1

下面是一门汇编语言课的作业题。我们将通过在 gdb 中读取从 C 生成的 X86 代码来创建 Y86 代码。该函数的目的是对链表的元素求和。

就目前的功能而言,它可以工作!当程序终止时,正确的值包含在 %eax 寄存器中。不幸的是,这只是由于黑客攻击而正确的。我halt在函数末尾添加了一条指令,就在ret指令之前。如果我取消注释,似乎发生的是当它执行ret指令时,PC 设置为 0x0。换句话说,它似乎从头开始,当它应该做的就是回到它被调用的地方。它进入一个无限循环。

代码如下。如果您安装了 Y86 模拟器,它是独立的。

.pos    0
init:    irmovl Stack, %esp  
irmovl    Stack, %ebp  
jmp     Main  

Main:  
    irmovl  ele1, %eax  
    pushl   %eax  
    call    sum_list  
    halt  

sum_list:  
    pushl   %ebp  
    rrmovl  %esp, %ebp  
    irmovl  $16, %edx  
    subl    %edx, %esp  
    irmovl  $0, %edx  
    rmmovl  %edx, -4(%ebp)  
    jmp     L2  

L3:
    mrmovl  8(%ebp), %eax
    mrmovl  (%eax), %eax
    mrmovl  -4(%ebp), %edx
    addl    %eax, %edx
    rmmovl  %edx, -4(%ebp)
    mrmovl  8(%ebp), %eax
    mrmovl  4(%eax), %eax
    rmmovl  %eax, 8(%ebp)

L2:
    irmovl  $0, %ecx
    mrmovl  8(%ebp), %edx
    subl    %ecx, %edx
    jne     L3
    mrmovl  -4(%ebp), %eax
    rrmovl  %esp, %ebp
    popl    %ebp
    halt #THIS DOESN'T BELONG. COMMENT OUT TO SEE BAD BEHAVIOR.
    ret

#linked list
.align  4
    ele1:
            .long   0x00a
            .long   ele2
    ele2:
            .long   0x0b0
            .long   ele3
    ele3:
            .long   0xc00
            .long   0


    .pos    0x300
    Stack:

谢谢你的帮助!

4

3 回答 3

4

这可能是也可能不是错误的原因,但我认为您正在错误地拆除堆栈框架sum_list。您进行如下设置:

pushl   %ebp  
rrmovl  %esp, %ebp

但是然后你像这样拆掉它:

rrmovl  %esp, %ebp
popl    %ebp

%esp请注意,您在这两种情况下都从to复制%ebp,这是不正确的,因为拆解应该撤消设置所做的操作。相反,尝试

rrmovl  %ebp, %esp
popl    %ebp

或者干脆

leave

它做同样的事情。

于 2011-05-13T16:56:48.323 回答
0
mrmovl  -4(%ebp), %edx

这就是问题所在。在 ebp - 4 有返回地址,所以你要覆盖它。使用不同的位置,一切都会好起来的:)

于 2011-05-13T16:49:28.037 回答
-1

有两个(半)与堆栈操作相关的问题:

框架设置正确,但解构块失败(程序执行 rrmovl %esp, %ebp 而不是 rrmovl %ebp, %esp)

尝试访问存储在前一帧(即调用者的帧)中的参数失败。堆栈从上往下运行,最后存储在堆栈中的元素是返回地址和旧帧指针,因此一旦 ebp 寄存器发生更改,被调用者可以通过渐进式偏移直接引用调用函数的参数8(%ebp)。

有一半的错误是主函数在终止之前没有弹出堆栈的存储参数。

调用者-被调用者约定在我的 Y86 博客http://y86tutoring.wordpress.com/2012/10/31/functioning-stacks/上进行了讨论

于 2012-11-08T14:41:21.063 回答