nasm 使用 arg 时出现分段错误

nasm segmentation fault while using arg

extern puts
global main

section .text
main:
    mov rax, rdi
label:
    test rax, rax
    je exit
    push rsi
    mov rdi, [rsi]
    call puts
    pop rsi
    dec rax
    add rsi, 8
    jmp label
exit:
    pop rsi
    ret

我写了 nasm 那样的代码。但是最后发生分段错误。我不明白为什么会出现段错误。

rax 不能保证在函数调用中保留,因为它用于 return 函数的整数结果(在 puts [ 的情况下) =19=]) 您需要在调用 puts 之前保存 rax 的值,就像您对 rsi 所做的那样,然后再恢复它。

显然您想在 64 位 Linux 的 GCC 环境中获取命令行参数,根据 Linux 调用约定之后的 GCC 调用约定传递它们" System V AMD64 ABI".

让我们把程序逻辑翻译成C:

#include <stdio.h>

int main ( int argc, char** argv )
{
    if (argc != 0)
    {
        do
        {
            puts (*argv);
            argc--;
            argv++;
        } while (argc);
    }
    return;
}

asm 程序没有 return 退出代码。当函数 returns 时,退出代码应该在 RAX 中。顺便说一句:argc 总是 >0,因为 argv 的第一个字符串包含程序名称。

main函数既是"caller"(调用puts)又是"callee"(return调用GCC环境)。作为调用者,它必须在调用 puts 之前保留 RAXRSI 并在需要时恢复它们。不使用被调用者保存的寄存器。不要忘记将堆栈对齐 16.

这个有效:

extern puts
global main

section .text
main:                       ; RDI: argc, RSI: argv, stack is unaligned by 8
    mov rax, rdi
label:
    test rax, rax
    je exit
    push rbx                ; Push 8 bytes to align the stack before the call
    push rax                ; Save it (caller-saved)
    push rsi                ; Save it (caller-saved)
    mov rdi, [rsi]          ; Argument for puts
    call puts
    pop rsi                 ; Restore it
    pop rax                 ; Restore it
    pop rbx                 ; "Unalign" the stack
    dec rax
    add rsi, 8
    jmp label
exit:
;    pop rsi                ; Once too much
    xor eax, eax            ; RAX = 0 (return 0)
    ret                     ; RAX: return value