使用arg时的nasm分段错误

时间:2016-11-16 10:14:22

标签: linux gcc assembly nasm x86-64

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代码。然而,分段错误最后发生。我无法理解为什么会出现分段错误。

2 个答案:

答案 0 :(得分:1)

rax不保证在函数调用中保留,因为它用于从函数返回整数结果(在puts &#34的情况下;成功时为非负数,或错误的EOF" )您需要在调用rax之前保存puts的值,就像您使用rsi一样,并将其恢复之后。

答案 1 :(得分:0)

显然,您希望在64位Linux上的GCC环境中获取命令行参数,根据遵循Linux调用约定“System V AMD64 ABI”的GCC调用约定传递命令行参数。

让我们将程序逻辑转换为C:

#include <stdio.h>

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

asm程序不返回退出代码。当函数返回时,退出代码应该在RAX中。顺便说一句:argc始终> 0,因为argv的第一个字符串包含程序名称。

main函数既是“调用者”(调用puts)又是“被调用者”(返回GCC环境)。作为来电者,它必须在调用RAX之前保留RSIputs,并在需要时恢复它们。不使用被调用者保存的寄存器。不要忘记将堆栈对齐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