Main & Allocator
These two macros are explained together because they are both global settings that must be run before _start
. In practice, they are usually used together (typically auto-generated by ckb-script-template
).
In the previous chapter, a Script does not rely on an OS, so both no_std
and no_main
must be enabled:
no_std
: Disables the standard library.no_main
: Since the standard library’s entry point is unavailable, the_start
function must be defined manually.
At the same time, common Rust types like String
and Vec
depend on alloc
, but in no_std
, there is no default memory allocator. Therefore, developers must configure it manually.
Here’s a minimal example:
#![no_std]
#![no_main]
extern crate alloc;
ckb_std::default_alloc!(16384, 1258306, 64);
ckb_std::entry!(program_entry);
pub fn program_entry() -> i8 {
ckb_std::debug!("Hello World!");
0
}
(See rust-script-examples/hello-world
for reference.)
entry!
Define program entry point (_start
function) and lang items (panic handler, etc.).
Syntax
macro_rules! entry {
($main:path) => { ... }
}
Parameters
main
: Name of the main function. It must be defined as:pub fn FunctionName() -> i8
.
Return
None
Remarks
The Script must explicitly define the _start
function. A typical implementation:
#![no_std]
#![no_main]
core::arch::global_asm!(
".global _start",
"_start:",
// Argc.
"lw a0, 0(sp)",
// Argv.
"addi a1, sp, 8",
// Envp.
"li a2, 0",
"call __ckb_std_main",
// Exit.
"li a7, 93",
"ecall",
);
#[no_mangle]
unsafe extern "C" fn __ckb_std_main(
_argc: core::ffi::c_int,
_argv: *const core::ffi::c_void,
) -> i8 {
0
}
Explanation:
- Embeds asm code with global_asm!.
.global _start
set_start
as the program entry.- Loads arguments from the stack into registers a0 and a1 (mainly for subprocesses created via exec/spawn, usually unnecessary for Scripts).
- Clears register a2.
- Calls
__ckb_std_main
.
__ckb_std_main
must use C style (extern "C"
).- It must be marked with
#[no_mangle]
to prevent the compiler from altering the symbol.
Internally, the entry!
macro calls __ckb_std_main
and then executes the provided main function (e.g., program_entry
).
default_alloc!
Defines global allocator.
Syntax
macro_rules! default_alloc {
() => {
$crate::default_alloc!({ 4 * 1024 }, { 516 * 1024 }, 64);
};
($fixed_block_heap_size:expr, $heap_size:expr, $min_block_size:expr) => {
...
}
Parameters
If None parameters: defaults to: default_alloc!({ 4 * 1024 }, { 516 * 1024 }, 64)
.
Else:
fixed_block_heap_size
: Size of the fixed block heap.heap_size
: Size of the heap.min_block_size
: The min size to allocate.
We recommend: the following heap configuration is used: 16KB fixed heap, 1.2MB(rounded up to be 16-byte aligned) dynamic heap. Minimal memory block in dynamic heap is 64 bytes.
ckb_std::default_alloc!(16384, 1258306, 64);
Return
None
Remarks
In the example above, ckb_std::debug!
relies on alloc::string
, so you need:
extern crate alloc;
ckb_std::default_alloc!();
Here’s a simple example of how default_alloc
could be implemented:
#[global_allocator]
static ALLOC: buddy_alloc::NonThreadsafeAlloc = unsafe {
#[repr(align(64))]
struct _AlignedHeap<const N: usize>([u8; N]);
const FIXED_BLOCK_HEAP_SIZE: usize = 4 * 1024;
const HEAP_SIZE: usize = 516 * 1024;
const MIN_BLOCK_SIZE: usize = 64;
static mut _BUDDY_HEAP: _AlignedHeap<HEAP_SIZE> = _AlignedHeap([0u8; HEAP_SIZE]);
static mut _FIXED_BLOCK_HEAP: _AlignedHeap<FIXED_BLOCK_HEAP_SIZE> =
_AlignedHeap([0u8; FIXED_BLOCK_HEAP_SIZE]);
use buddy_alloc::{BuddyAllocParam, FastAllocParam, NonThreadsafeAlloc};
#[allow(static_mut_refs)]
NonThreadsafeAlloc::new(
FastAllocParam::new(_FIXED_BLOCK_HEAP.0.as_ptr(), FIXED_BLOCK_HEAP_SIZE),
BuddyAllocParam::new_with_zero_filled(
_BUDDY_HEAP.0.as_ptr(),
HEAP_SIZE,
MIN_BLOCK_SIZE,
),
)
};
Explanation:
#[global_allocator]
declares the global allocator.- Uses
buddy_alloc
as the memory allocation (the same allocator used internally byckb-std
).
example
In rust-script-examples/empty
, implement a basic Rust Script following the structure described above. This example uses the allocator
feature to create a heap allocator, enabling the use of types like String
through alloc
.