汇编调用堆栈 - 术语问题
Assembly Call Stack - Terminology Questions
我是 Assembly 的新手,希望确认在以下陈述中我在哪里有误解,需要更正。
栈指针(ESP
)指向栈顶(最低内存地址)
base Pointer(EBP
)用于构建栈帧时临时存放各种内存地址。它通常保存当前堆栈帧的最高内存地址。
指令指针(EIP
)指的是一行代码在内存的文本(代码)段的内存地址
一旦将某些内容推入堆栈,就无法就地更改。 IE。如果我们 PUSH EBP
到堆栈,我们推的是 EBP
的当前值,而不是指向它的某种引用或指针。我们无法就地更改该值。
传递给函数的参数通常被移动到地址space,这是堆栈指针的偏移量。 IE。 [ESP-12]
.
调用函数时(使用CALL
),会发生以下情况:
- return地址被添加到堆栈(紧跟在当前
EIP
之后的地址的内存,所以我们知道在被调用函数完成后return到哪里
- 保存的帧指针入栈,一般为调用函数的栈帧的栈指针
- 然后我们将进入被调用函数的序言
谢谢。我正在努力解决这个问题。
Arguments being passed into a function are generally moved into an address space which is an offset of the stack pointer. ie. [ESP-12].
经常将参数压入堆栈,在调用之前。
push paramA ; ( some 32bit value, register, whatever )
push paramB
call myFunct
这导致以下堆栈内容:
---------------
| paramA |
---------------
| paramB |
---------------
| return addr | <-- ESP
---------------
由于 return 地址(由 call
推送)是 4 个字节,函数的参数在 [ESP+4]
和 [ESP+8]
.
如果您的函数添加堆栈帧,通常您会这样做
myFunct: push EBP
mov EBP, ESP
现在堆栈看起来像这样:
---------------
| paramA |
---------------
| paramB |
---------------
| return addr |
---------------
| saved EBP | <-- EBP, ESP
---------------
并且参数位于 [EBP+8]
和 [EBP+12]
,即使您推入更多值(或为局部变量添加一些位置),因为 EBP
不再更改:
myFunct: push EBP
mov EBP, ESP
sub ESP, 12 ; make room for 3 32bit local variables
mov eax, [EBP+8] ; access one of the parameters
mov [EBP-4], eax ; save it in local variable #1
rel | rel |
to | to |
ESP | EBP |
----|------|--------------
+24 | +12 | paramA |
| |--------------
+20 | +8 | paramB |
| |--------------
+16 | +4 | return addr |
| |--------------
+12 | | saved EBP | <-- EBP (is fixed here for now)
| |---------------
+8 | -4 | local#1 |
| |---------------
+4 | -8 | local#2 |
| | ---------------
0 | -12 | local#3 | <--- ESP (keeps growing, by pushing, calling etc)
---------------
局部变量位于[EBP-4]
、[EBP-8]
、[EBP-12]
等
return 地址位于 [EBP+4]
注意:如你所见,是可以的
- 通过
ESP
访问(然后你 不需要 需要一个帧指针,但是你需要跟踪你推送了多少数据,到 "find" 参数和变量 )
- 或
EBP
(这会增加一些开销)。在许多函数中,根本不需要帧指针,并且被编译器优化掉了。
Once something has been pushed to the stack, it can't be changed in-place. ie. If we PUSH EBP to the stack, we are pushing the current value of EBP, not some kind of reference or pointer to it. We can't then change that value in-place.
当然可以。栈就是普通的计算机内存,没什么特别的,除了99%的代码期望有效(读+写访问)内存地址在esp
和一些保留的space,所以它可以压入一些本地的东西根据需要添加。
push ebp ; store current value in ebp to stack
几乎等同于:
sub esp,4
mov [esp],ebp
(但第二个变体也会修改标志并且它的原子性稍差)
现在您可以用其他任何内容覆盖它,例如:
mov [esp],eax ; overwrite the old_ebp value with current_eax value
reference or pointer to it
嗯,没有办法对 ebp
寄存器有某种引用或指针,它是 CPU 中的一个寄存器,只有 32 位(32x 0 或 1 值)并且它有没有地址,您只能在指令中使用它的名称 ebp
,这允许在它们的编码中使用它。
在 push ebp
之后,这 32 位(没有其他信息)被复制到内存中(然后内存将这些 0/1 值复制到它自己的 32 位 = 4 字节中)。没有信息从哪里写入内存中的值,何时以及通过什么指令,只存储值位。
我是 Assembly 的新手,希望确认在以下陈述中我在哪里有误解,需要更正。
栈指针(ESP
)指向栈顶(最低内存地址)
base Pointer(EBP
)用于构建栈帧时临时存放各种内存地址。它通常保存当前堆栈帧的最高内存地址。
指令指针(EIP
)指的是一行代码在内存的文本(代码)段的内存地址
一旦将某些内容推入堆栈,就无法就地更改。 IE。如果我们 PUSH EBP
到堆栈,我们推的是 EBP
的当前值,而不是指向它的某种引用或指针。我们无法就地更改该值。
传递给函数的参数通常被移动到地址space,这是堆栈指针的偏移量。 IE。 [ESP-12]
.
调用函数时(使用CALL
),会发生以下情况:
- return地址被添加到堆栈(紧跟在当前
EIP
之后的地址的内存,所以我们知道在被调用函数完成后return到哪里 - 保存的帧指针入栈,一般为调用函数的栈帧的栈指针
- 然后我们将进入被调用函数的序言
谢谢。我正在努力解决这个问题。
Arguments being passed into a function are generally moved into an address space which is an offset of the stack pointer. ie. [ESP-12].
经常将参数压入堆栈,在调用之前。
push paramA ; ( some 32bit value, register, whatever )
push paramB
call myFunct
这导致以下堆栈内容:
---------------
| paramA |
---------------
| paramB |
---------------
| return addr | <-- ESP
---------------
由于 return 地址(由 call
推送)是 4 个字节,函数的参数在 [ESP+4]
和 [ESP+8]
.
如果您的函数添加堆栈帧,通常您会这样做
myFunct: push EBP
mov EBP, ESP
现在堆栈看起来像这样:
---------------
| paramA |
---------------
| paramB |
---------------
| return addr |
---------------
| saved EBP | <-- EBP, ESP
---------------
并且参数位于 [EBP+8]
和 [EBP+12]
,即使您推入更多值(或为局部变量添加一些位置),因为 EBP
不再更改:
myFunct: push EBP
mov EBP, ESP
sub ESP, 12 ; make room for 3 32bit local variables
mov eax, [EBP+8] ; access one of the parameters
mov [EBP-4], eax ; save it in local variable #1
rel | rel |
to | to |
ESP | EBP |
----|------|--------------
+24 | +12 | paramA |
| |--------------
+20 | +8 | paramB |
| |--------------
+16 | +4 | return addr |
| |--------------
+12 | | saved EBP | <-- EBP (is fixed here for now)
| |---------------
+8 | -4 | local#1 |
| |---------------
+4 | -8 | local#2 |
| | ---------------
0 | -12 | local#3 | <--- ESP (keeps growing, by pushing, calling etc)
---------------
局部变量位于[EBP-4]
、[EBP-8]
、[EBP-12]
等
return 地址位于 [EBP+4]
注意:如你所见,是可以的
- 通过
ESP
访问(然后你 不需要 需要一个帧指针,但是你需要跟踪你推送了多少数据,到 "find" 参数和变量 ) - 或
EBP
(这会增加一些开销)。在许多函数中,根本不需要帧指针,并且被编译器优化掉了。
Once something has been pushed to the stack, it can't be changed in-place. ie. If we PUSH EBP to the stack, we are pushing the current value of EBP, not some kind of reference or pointer to it. We can't then change that value in-place.
当然可以。栈就是普通的计算机内存,没什么特别的,除了99%的代码期望有效(读+写访问)内存地址在esp
和一些保留的space,所以它可以压入一些本地的东西根据需要添加。
push ebp ; store current value in ebp to stack
几乎等同于:
sub esp,4
mov [esp],ebp
(但第二个变体也会修改标志并且它的原子性稍差)
现在您可以用其他任何内容覆盖它,例如:
mov [esp],eax ; overwrite the old_ebp value with current_eax value
reference or pointer to it
嗯,没有办法对 ebp
寄存器有某种引用或指针,它是 CPU 中的一个寄存器,只有 32 位(32x 0 或 1 值)并且它有没有地址,您只能在指令中使用它的名称 ebp
,这允许在它们的编码中使用它。
在 push ebp
之后,这 32 位(没有其他信息)被复制到内存中(然后内存将这些 0/1 值复制到它自己的 32 位 = 4 字节中)。没有信息从哪里写入内存中的值,何时以及通过什么指令,只存储值位。