我正在尝试学习汇编程序,并且我对osx使用nasm macho32用于将参数传递给函数的方法感到困惑。
我正在关注Jeff Duntemann撰写的“汇编语言一步一步”一书,并广泛使用互联网将其改为在32位和64位osx上运行。
首先从书中的linux版本开始
section .data ; Section containing initialised data
EatMsg db "Eat at Joe's!",10
EatLen equ $-EatMsg
section .bss ; Section containing uninitialised data
section .text ; Section containing code
global start ; Linker needs this to find the entry point!
start:
nop
mov eax, 4 ; Specify sys_write syscall
mov ebx, 1 ; Specify File Descriptor 1: Standard Output
mov ecx, EatMsg ; Pass offset of the message
mov edx, EatLen ; Pass the length of the message
int 0x80 ; Make syscall to output the text to stdout
mov eax, 1 ; Specify Exit syscall
mov ebx, 0 ; Return a code of zero
int 0x80 ; Make syscall to terminate the program
section .data ; Section containing initialised data
EatMsg db "Eat at Joe's!", 0x0a
EatLen equ $-EatMsg
section .bss ; Section containing uninitialised data
section .text ; Section containing code
global start ; Linker needs this to find the entry point!
然后非常类似于osx的64位版本,除了更改寄存器名称,替换int 80H(我理解有点过时)并将0x2000000添加到移动到eax的值(暂时不明白这一点)没有太大的改变。
section .data ; Section containing initialised data
EatMsg db "Eat at Joe's!", 0x0a
EatLen equ $-EatMsg
section .bss ; Section containing uninitialised data
section .text ; Section containing code
global start ; Linker needs this to find the entry point!
start:
mov rax, 0x2000004 ; Specify sys_write syscall
mov rdi, 1 ; Specify File Descriptor 1: Standard Output
mov rsi, EatMsg ; Pass offset of the message
mov rdx, EatLen ; Pass the length of the message
syscall ; Make syscall to output the text to stdout
mov rax, 0x2000001 ; Specify Exit syscall
mov rdi, 0 ; Return a code of zero
syscall ; Make syscall to terminate the program
另一方面,32位mac版本是完全不同的。我可以看到我们正在将参数推送到堆栈dword,所以我的问题是(并且对于长序言很抱歉)eax被推送到的堆栈和dword之间的区别是什么,为什么我们只使用寄存器而不是64位版本(和linux)中的堆栈?
section .data ; Section containing initialised data
EatMsg db "Eat at Joe's!", 0x0a
EatLen equ $-EatMsg
section .bss ; Section containing uninitialised data
section .text ; Section containing code
global start ; Linker needs this to find the entry point!
start:
mov eax, 0x4 ; Specify sys_write syscall
push dword EatLen ; Pass the length of the message
push dword EatMsg ; Pass offset of the message
push dword 1 ; Specify File Descriptor 1: Standard Output
push eax
int 0x80 ; Make syscall to output the text to stdout
add esp, 16 ; Move back the stack pointer
mov eax, 0x1 ; Specify Exit syscall
push dword 0 ; Return a code of zero
push eax
int 0x80 ; Make syscall to terminate the program
答案 0 :(得分:1)
嗯,你不太明白什么是dword
。说到HLL,它不是变量,而是一种类型。所以push doword 1
意味着你将双字常量1
推入堆栈。只有一个堆栈,并且一个和寄存器eax都被推入其中。
寄存器在linux中使用,因为它们更快,特别是在旧处理器上。 Linux ABI(据我所知,系统V ABI的下降)是很久以前开发的,并且经常用于性能至关重要的系统,而差异非常显着。 OSX intel abi更年轻,更远,使用堆栈的简单性在桌面OSX中比在可忽略的减速中更重要。在64位处理器中,添加了更多寄存器,因此更有效地使用它们。