Ars*_*ble 79 x86 assembly stack terminology
在阅读有关汇编程序的文章时,我经常遇到人们在写文件时他们推送处理器的某个寄存器并稍后再次弹出它以恢复它之前的状态.
Lin*_*een 129
推送值(不一定存储在寄存器中)意味着将其写入堆栈.
弹出意味着将堆栈顶部的任何内容恢复到寄存器中.这些是基本的指示:
push 0xdeadbeef ; push a value to the stack
pop eax ; eax is now 0xdeadbeef
; swap contents of registers
push eax
mov eax, ebx
pop ebx
Run Code Online (Sandbox Code Playgroud)
Mad*_*uja 39
这是你如何推送一个寄存器.我假设我们正在谈论x86.
push ebx
push eax
Run Code Online (Sandbox Code Playgroud)
它被推到堆栈上.ESP随着堆栈在x86系统中向下增长,寄存器的值减小到推送值的大小.
需要保留这些值.一般用法是
push eax ; preserve the value of eax
call some_method ; some method is called which will put return value in eax
mov edx, eax ; move the return value to edx
pop eax ; restore original eax
Run Code Online (Sandbox Code Playgroud)
A push是x86中的单个指令,它在内部执行两项操作.
ESP寄存器的当前地址.ESP寄存器减小到推动值的大小.Cir*_*四事件 34
它在哪里推?
esp - 4.更确切地说:
esp 被减去4esppop 扭转这一点.
System V ABI告诉Linux rsp在程序开始运行时指向一个合理的堆栈位置:程序启动时的默认寄存器状态是什么(asm,linux)?这是你应该经常使用的.
怎么能推一个寄存器?
最小的GNU GAS示例:
.data
/* .long takes 4 bytes each. */
val1:
/* Store bytes 0x 01 00 00 00 here. */
.long 1
val2:
/* 0x 02 00 00 00 */
.long 2
.text
/* Make esp point to the address of val2.
* Unusual, but totally possible. */
mov $val2, %esp
/* eax = 3 */
mov $3, %ea
push %eax
/*
Outcome:
- esp == val1
- val1 == 3
esp was changed to point to val1,
and then val1 was modified.
*/
pop %ebx
/*
Outcome:
- esp == &val2
- ebx == 3
Inverses push: ebx gets the value of val1 (first)
and then esp is increased back to point to val2.
*/
Run Code Online (Sandbox Code Playgroud)
为什么需要这个?
这是事实,这些指令可以通过轻松实现mov,add并sub.
他们之所以存在,那些指令组合是如此频繁,以至于英特尔决定为我们提供它们.
这些组合如此频繁的原因是它们可以很容易地将寄存器的值保存并暂时恢复到存储器中,这样它们就不会被覆盖.
要了解问题,请尝试手动编译一些C代码.
一个主要的困难是决定每个变量的存储位置.
理想情况下,所有变量都适合寄存器,这是访问速度最快的存储器(目前比RAM 快约100倍).
但是,当然,我们可以轻松地拥有比寄存器更多的变量,特别是嵌套函数的参数,因此唯一的解决方案是写入内存.
我们可以写入任何内存地址,但由于函数调用和返回的局部变量和参数适合一个很好的堆栈模式,这可以防止内存碎片,这是处理它的最佳方法.将其与编写堆分配器的精神错误进行比较.
然后我们让编译器为我们优化寄存器分配,因为这是NP完成的,也是编写编译器最困难的部分之一.这个问题称为寄存器分配,它与图着色同构.
当编译器的分配器被迫将内容存储在内存而不仅仅是寄存器时,这就是所谓的溢出.
这可归结为单处理器指令还是更复杂?
我们所知道的只是英特尔记录了push一条pop指令,因此它们就是这方面的一条指令.
在内部,它可以扩展到多个微码,一个用于修改esp,一个用于执行内存IO,并且可以进行多个循环.
但是单个也可能push比其他指令的等效组合更快,因为它更具体.
这主要是未记录的:
push并pop采取一次微操作. gow*_*ath 17
推送和弹出寄存器在幕后等效于此:
push reg <= same as => sub $8,%rsp # subtract 8 from rsp
mov reg,(%rsp) # store, using rsp as the address
pop reg <= same as=> mov (%rsp),reg # load, using rsp as the address
add $8,%rsp # add 8 to the rsp
Run Code Online (Sandbox Code Playgroud)
注意这是x86-64 At&t语法.
作为一对使用,您可以将堆栈中的寄存器保存并稍后恢复.还有其他用途.
| 归档时间: |
|
| 查看次数: |
257720 次 |
| 最近记录: |