Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Assembly Guidelines

Define sections

To define built-in sections, such as the text section, it is preferable to use the short directive, e.g., .text. For other sections, the section directive with the desired flags and type should be used, e.g., .section ".bsp_boot", "awx", @progbits.

To ensure consistency and clarity, a blank line should follow each section definition, creating a separate code block for each definition.

.section ".bsp_boot.stack", "aw", @nobits

boot_stack_bottom:
    .align 4096
    .skip 0x40000  # 256 KiB
boot_stack_top:

In x86-64, if an executable section contains only 64-bit code, the .code64 directive should be placed directly after the section definition. The same applies to the .code32 directive for 32-bit code.

.text
.code64

.global foo
foo:
   mov rax, 1
   ret

Define functions

Function attributes, such as .global and .align, should be placed directly before the function. These function attributes should not be indented.

.align 4
.global foo
foo:
   mov rax, 1
   ret

The assembler treats the directives .global and .globl as the same. For clarity, however, .global is preferred.

Note that a Rust crate is a single translation unit, so global_asm! labels in different modules within the same crate share the same global namespace. In RISC-V, we have experienced that defining two labels with the same name in different modules can nondeterministically cause duplicate symbol error. The .L prefix does not help. Therefore, add custom prefixes to your labels to avoid name clashes. Nevertheless, use .global to export symbols that need to be visible within the same crate.

In x86-64, if an executable section contains a mix of 32-bit and 64-bit code, the .code64 and .code32 directives are treated as function attributes.

.code32
.global foo32
foo32:
    mov eax, 1
    ret

.code64
.global foo64
foo64:
    mov rax, 1
    ret

Functions that can be called from Rust code should also include the .type and .size directives. This will give debuggers a better understanding of the function. For example:

.global bar
.type bar, @function
bar:
    mov rax, 2
    ret
.size bar, .-bar

Note that this rule explicitly limits the functions to those that can be called from Rust code. Therefore, it does not apply to boot entry points, exception trampolines, or interrupt trampolines. They may not fit into the typical definition of "function", and their sizes may be ill-defined.