Rob*_*ert 5 x86 assembly machine-code
运行程序时,您可以传递参数,例如
$ myProgram par1 par2 par3
Run Code Online (Sandbox Code Playgroud)
在C中你可以通过查看来访问这些参数argv,
int main (int argc, char *argv[])
{
char* aParameter = argv[1]; // Not sure if this is 100% right but you get the idea...
}
Run Code Online (Sandbox Code Playgroud)
这将如何在assembly/x86机器代码中转换?你会如何访问给你的变量?系统如何为您提供这些变量?
我对组装非常新,它接缝只能访问寄存器和绝对地址.我很困惑你如何访问参数.系统是否会将参数预加载到特殊寄存器中?
参数通常在堆栈上传递,堆栈是指向的内存的一部分esp.操作系统负责为堆栈保留一些内存,然后esp在将控制权交给程序之前正确设置.
正常的函数调用可能如下所示:
main:
push 456
push 123
call MyFunction
add esp, 8
ret
MyFunction:
; [esp+0] will hold the return address
; [esp+4] will hold the first parameter (123)
; [esp+8] will hold the second parameter (456)
;
; To return from here, we usually execute a 'ret' instruction,
; which is actually equivalent to:
;
; add esp, 4
; jmp [esp-4]
ret
Run Code Online (Sandbox Code Playgroud)
在调用函数和被调用函数之间有不同的职责分离,关于它们如何保证寄存器.这些规则称为调用约定.
上面的示例使用cdecl调用约定,这意味着参数以相反的顺序被压入堆栈,并且调用函数负责在将esp这些参数推送到堆栈之前将其恢复回指向的位置.这是什么add esp, 8.
通常,您main在汇编中编写函数并将其组装到目标文件中.然后,将此目标文件传递给链接器以生成可执行文件.
链接器负责生成启动代码,在控制传递给main函数之前正确设置堆栈,这样您的函数就可以像使用两个参数(argc/argv)一样调用它.也就是说,您的main函数不是真正的入口点,但启动代码在设置了argc/argv参数后跳转到那里.
那么这个"启动代码"看起来如何?链接器会为我们生成它,但知道它是如何工作的总是很有趣.
这是特定于平台的,但我将描述Linux上的典型案例.这篇文章虽然已经过时,但它解释了i386程序启动时Linux上的堆栈布局.堆栈看起来像这样:
esp+00h: argc
esp+04h: argv[0]
esp+08h: argv[1]
esp+1Ch: argv[2]
...
Run Code Online (Sandbox Code Playgroud)
因此启动代码可以从堆栈中获取argc/argv值,然后main(...)使用两个参数调用:
; This is very incomplete startup code, but it illustrates the point
mov eax, [esp] ; eax = argc
lea edx, [esp+0x04] ; edx = argv
; push argv, and argc onto the stack (note the reverse order)
push edx
push eax
call main
;
; When main returns, use its return value (eax)
; to set an exit status
;
...
Run Code Online (Sandbox Code Playgroud)