diff --git a/Cargo.lock b/Cargo.lock
index a2fb748e0bfe5cc63893067e1c89be47c44a4e01..30ba0798f5d77366ffe6aa666778a6c9b2709a3d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -725,7 +725,6 @@ dependencies = [
  "errno",
  "futures",
  "libc",
- "linkme",
  "nix 0.23.2",
  "pretty_assertions",
  "protobuf",
diff --git a/Cargo.toml b/Cargo.toml
index 616c9b795fea936f92d0f46e0e065abc64f891f1..fdca57bef9558a84347f9841ce82dd2b3a11a058 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,7 +20,6 @@ tempfile = "3"
 thiserror = "1.0"
 nix = "0.23.1"
 uuid = {version = "1.0", features = ["v3"]}
-linkme = "0.2.10"
 futures = "0.3.25"
 
 [dependencies.protobuf]
diff --git a/src/discovery.rs b/src/discovery.rs
index d187af67a02e3ef7488c218a30b6a07c0ba5ecde..27f62cd322453c7ff4dd936c6906663936985704 100644
--- a/src/discovery.rs
+++ b/src/discovery.rs
@@ -192,7 +192,6 @@ pub fn wait_global() -> Role {
     }
 }
 
-crate::collect_proc!(proc_discover);
 #[proc]
 fn proc_discover<'a>(request: Request, request_to: Address) -> Result<Response, Box<dyn StdError>> {
     crate::tarantool::fiber_name("proc_discover");
diff --git a/src/lib.rs b/src/lib.rs
index da42b060d0e5d9b97fe2ba2cad1df5a2db8ae4ce..fef857ef821c2f9f4cbe31a96be1535e8565a7ea 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -37,7 +37,6 @@ pub mod kvcell;
 pub mod r#loop;
 pub mod mailbox;
 pub mod on_shutdown;
-pub mod proc;
 pub mod replicaset;
 pub mod storage;
 pub mod tarantool;
@@ -527,12 +526,12 @@ fn init_handlers() -> traft::Result<()> {
     .unwrap();
 
     let lua = ::tarantool::lua_state();
-    for name in proc::AllProcs::names() {
+    for proc in ::tarantool::proc::all_procs().iter() {
         lua.exec_with(
-            "box.schema.func.create(...,
+            "box.schema.func.create('.' .. ...,
                 { language = 'C', if_not_exists = true }
             );",
-            name,
+            proc.name(),
         )
         .map_err(::tarantool::tlua::LuaError::from)?;
     }
diff --git a/src/proc.rs b/src/proc.rs
deleted file mode 100644
index b15b18eb85f9b54fb257e54694ed9a3f6aec5a8f..0000000000000000000000000000000000000000
--- a/src/proc.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-//! A collection of tarantool stored procedures used in picodata.
-//!
-
-use ::tarantool::tuple::FunctionArgs;
-use ::tarantool::tuple::FunctionCtx;
-use std::os::raw::c_int;
-
-// TODO: move this into [`tarantool::ffi::tarantool`]
-/// Tarantool stored procedure signature.
-pub type TarantoolProc = unsafe extern "C" fn(FunctionCtx, FunctionArgs) -> c_int;
-
-/// All stored procedures collected by
-/// [`collect_proc!`](crate::collect_proc) macro.
-pub struct AllProcs;
-
-#[doc(hidden)]
-#[::linkme::distributed_slice]
-pub static ALL_PROCS: [(&'static str, TarantoolProc)] = [..];
-
-impl AllProcs {
-    /// Returns an iterator over all procs names.
-    pub(crate) fn names() -> impl Iterator<Item = &'static str> {
-        ALL_PROCS.iter().map(|v| v.0)
-    }
-}
-
-#[macro_export]
-/// Collects a function to be used as a tarantool stored procedure.
-///
-/// The objective of this macro is to simplify creating stored
-/// procedures (`box.schema.func.create` invoked during the instance
-/// initialization). And, since those functions aren't invoked directly,
-/// to prevent symbols removal due to the link-time optimization.
-///
-/// For retrieving collected items refer to `AllProcs`.
-///
-macro_rules! collect_proc {
-    ($proc:ident) => {
-        impl $crate::proc::AllProcs {
-            #[allow(dead_code)]
-            #[doc(hidden)]
-            fn $proc() {
-                // Enclosing static variable in a function allows to avoid name clash.
-                #[::linkme::distributed_slice($crate::proc::ALL_PROCS)]
-                pub static PROC: (&str, $crate::proc::TarantoolProc) =
-                    ($crate::stringify_cfunc!($proc), $proc);
-            }
-        }
-    };
-}
diff --git a/src/traft/node.rs b/src/traft/node.rs
index 58c70871d578e8599a4a910f04bb5a2d87693502..9d0e3523ec5f185f52e6d62aec7c145ab328fdf8 100644
--- a/src/traft/node.rs
+++ b/src/traft/node.rs
@@ -1069,7 +1069,6 @@ pub fn global() -> traft::Result<&'static Node> {
     unsafe { RAFT_NODE.as_deref() }.ok_or(Error::Uninitialized)
 }
 
-crate::collect_proc!(proc_raft_interact);
 #[proc(packed_args)]
 fn proc_raft_interact(pbs: Vec<traft::MessagePb>) -> traft::Result<()> {
     crate::tarantool::fiber_name("proc_raft_interact");
diff --git a/src/traft/rpc/mod.rs b/src/traft/rpc/mod.rs
index afbaefe0018c792c89d9bee4b3bd462d230b9f4c..345d398932234425dbae29a400e82c91e3181cc3 100644
--- a/src/traft/rpc/mod.rs
+++ b/src/traft/rpc/mod.rs
@@ -70,7 +70,6 @@ macro_rules! define_rpc_request {
         $({ $($res_named_fields:tt)* })?
         $(( $($res_unnamed_fields:tt)* );)?
     ) => {
-        $crate::collect_proc!($proc);
         $(#[$proc_meta])*
         #[::tarantool::proc(packed_args)]
         fn $proc($_r: $_request) -> $result {