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代码。然而,分段错误最后发生。我无法理解为什么会出现分段错误。
答案 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
之前保留RSI
和puts
,并在需要时恢复它们。不使用被调用者保存的寄存器。不要忘记将堆栈对齐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