gpt4 book ai didi

c - 理解汇编语言

转载 作者:太空狗 更新时间:2023-10-29 17:13:35 26 4
gpt4 key购买 nike

我试图理解与上述 C 代码相关的汇编代码。我不确定我是否走在正确的轨道上,所以也许有人可以帮助我更好地理解这一点。

int silly(int n, int *p)
{
int val, val2;
if (n > 0)
val2 = silly(n << 1, &val);
else
val = val2 = 0;
*p = val + val2 + n;
return val + val2;
}

这会产生以下机器码:

silly:
pushl %ebp // Here I am making space for the function on the stack
movl %esp,%ebp // Moving the stack pointer where the base pointer is
subl $20,%esp // Subtracting 20 from the stack pointer to allocate more space
pushl %ebx // Pushing the %ebx register on top of the stack
movl 8(%ebp),%ebx // Getting the first argument(which is n) and store it in register %ebx
testl %ebx,%ebx // The first if-statement which compares if n > 0
jle .L3 // Jump if less or equal - meaning if n < 0 then jump to .L3
addl $-8,%esp // Add -8 to %esp to allocate more space
leal -4(%ebp),%eax // Storing the first local variable (which is val) in %eax
pushl %eax // Pushing the register %eax on top of the stack
leal (%ebx,%ebx),%eax // n + n and stores it as 2n in %eax
pushl %eax // Pushing register %eax on top of the stack (Which I find strange
// considering that I've just pushed %eax onto the stack above
call silly // Call the function silly
jmp .L4 // Jump to .L4 (Unconditionally)
.p2align 4,,7 // Don't know what this means.
.L3: // .L3 is the else-statement
xorl %eax,%eax // Basically making %eax = 0
movl %eax,-4(%ebp) // Moving the value in %eax which is 0 to the first local variable
// meaning val = 0
.L4: // .L4 is the section after the else-statement
movl -4(%ebp),%edx // Getting val again and now storing it in %edx
addl %eax,%edx // Adding what is in %eax (which is 0) to %edx
movl 12(%ebp),%eax // Getting the second parameter (*p) and storing it in %eax
addl %edx,%ebx // Adding value from %edx to %ebx - meaning val + n
movl %ebx,(%eax) // Moving what is in %ebx and storing it in memory location of %eax
movl -24(%ebp),%ebx // Getting the second local variable (val2) and moving it to %ebx
movl %edx,%eax // Move val to %eax - and the return value will be in %eax
movl %ebp,%esp
popl %ebp
ret

我正在努力解决这个问题,我刚刚开始考虑组装,所以关于这个主题的指针会非常好。关于这段汇编代码,我有几个问题需要询问,这有助于我理解堆栈:

  • (a) 变量val是否存储在栈中?
    (b) 如果是,它存储在哪个字节 oset(相对于 %ebp)?
    (c) 为什么要存入栈?

  • (a) 变量val2是否存储在栈中?
    (b) 如果是,它存储在哪个字节 oset(相对于 %ebp)?
    (c) 为什么要存入栈?

  • (a) -24(%ebp) 存储了什么(如果有的话)?
    (b) 如果有东西存储在那里,为什么要存储它?

  • (a) -8(%ebp) 存储了什么(如果有的话)?
    (b) 如果有东西存储在那里,为什么要存储它?

提前致谢:)

最佳答案

在回答您的问题之前。我不是注释代码在做什么,而是注释所有值在寄存器或堆栈中的位置。

参数在栈上,返回值在%eax中。

寄存器 %eax%ecx%edx 是调用者保存的。所有其他寄存器,包括 %ebx%ebp%esp,都是被调用者保存的(%edi%esi 未使用)。

我对堆栈的表示法是一次 4 个字节,如果已知,我使用 ; 表示 ebp 指向的位置。

silly:                     ; eax: ?, ebx: ebx0, edx: ?, stack: [eip0, n, p]
pushl %ebp ; eax: ?, ebx: ebx0, edx: ?, stack: [ebp0, eip0, n, p]
movl %esp,%ebp ; eax: ?, ebx: ebx0, edx: ?, stack: [; ebp0, eip0, n, p]
subl $20,%esp ; eax: ?, ebx: ebx0, edx: ?, stack: [?, ?, ?, ?, ?; ebp0, eip0, n, p]
pushl %ebx ; eax: ?, ebx: ebx0, edx: ?, stack: [ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p]
movl 8(%ebp),%ebx ; eax: ?, ebx: n, edx: ?, stack: [ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p]
testl %ebx,%ebx ; set flags from n
jle .L3 ; if flags indicates <= 0, goto .L3, else fallthrough

; set up for calling the function
addl $-8,%esp ; eax: ?, ebx: n, edx: ?, stack: [?, ?, ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p]
leal -4(%ebp),%eax ; eax: &val, ebx: n, edx: ?, stack: [?, ?, ebx0, ?, ?, ?, ?, (stackeax); ebp0, eip0, n, p]
pushl %eax ; eax: &val, ebx: n, edx: ?, stack: [&val, ?, ?, ebx0, ?, ?, ?, ?, val=?; ebp0, eip0, n, p]
leal (%ebx,%ebx),%eax ; eax: 2*n, ebx: n, edx: ?, stack: [&val, ?, ?, ebx0, ?, ?, ?, ?, val=?; ebp0, eip0, n, p]
pushl %eax ; eax: 2*n, ebx: n, edx: ?, stack: [2*n, &val, ?, ?, ebx0, ?, ?, ?, ?, val=?; ebp0, eip0, n, p]
call silly ; pushes eip; args: (2*n, &val); val will be initialized on return
jmp .L4 ;
;
.p2align 4,,7 ; request alignment (there should be one before `silly:` too)
.L3: ;
xorl %eax,%eax ; eax: val=0, ebx: n, edx: ?, stack: [ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p]
movl %eax,-4(%ebp) ; eax: val=0, ebx: n, edx: ?, stack: [ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p]
;
.L4: ; eax: val2=φ(function result, 0), ebx: n, edx: ?, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p]
movl -4(%ebp),%edx ; eax: val2, ebx: n, edx: val, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p]
addl %eax,%edx ; eax: val2, ebx: n, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p]
movl 12(%ebp),%eax ; eax: p, ebx: n, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p]
addl %edx,%ebx ; eax: p, ebx: n+val+val2, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p]
movl %ebx,(%eax) ; *p = n+val+val2
movl -24(%ebp),%ebx ; eax: p, ebx: ebx0, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p]
movl %edx,%eax ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p]
movl %ebp,%esp ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [; ebp0, eip0, n, p]
popl %ebp ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [eip0, n, p]
ret ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [n, p]

停止

返回并重新阅读代码。如果您不自己找出答案,您只会伤害自己。我写的那种评论应该很容易。

但是无论如何...


  1. 一个。 val 通常在堆栈上,位于 -4(%ebp)。唯一一次不是在行 xorl %eax,%eax
    b.它存储在 -4(%ebp),如 leal -4(%ebp),%eax, movl %eax,-4 行所示(%ebp)movl -4(%ebp),%edx。此外,前一帧的 val*p
    C。 val 必须在堆栈上,以便可以获取其地址并将其传递给递归调用。
  2. 一个。 val2 永远不会存储在堆栈中,尽管其中一些 ? 很可能是为它保留的空间。
    b.它存储在.L4处的regixter eax中,在phi函数的第一个分支上是递归调用的返回值,在第二个分支上是值0,也存储在val中。
    C。 val2 永远不需要在堆栈上,因为它的地址未被获取,它在递归调用之前不存在,因此不需要保存,并且使用的寄存器很少无需溢出。
  3. 一个。 -24(%ebp)%ebx 的保存值,来自行 pushl %ebx
    b. %ebx 是一个被调用者保存的寄存器,所以它的值必须被保留。
  4. 一个。不,那里什么都没有。
    b.如果有必要溢出,它很可能是 val2。我最好的猜测是其他三个 ? 是为递归调用调用者保存的未使用寄存器保留的:%eax %ecx%edx

关于c - 理解汇编语言,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26288227/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com