Assembly Y86代码不';t按预期处理ret指令

Assembly Y86代码不';t按预期处理ret指令,assembly,x86,y86,Assembly,X86,Y86,下面是一个汇编语言类的家庭作业问题。我们将通过读取gdb中C生成的X86代码来创建Y86代码。函数的目的是对链表的元素求和 正如功能当前所示,它可以工作!当程序终止时,%eax寄存器中包含正确的值。不幸的是,由于黑客攻击,它才是正确的。我在函数末尾添加了一条halt指令,就在ret指令之前。如果我取消注释,似乎发生的是,当执行ret指令时,PC被设置为0x0。换句话说,它似乎从一开始就重新开始,当它应该做的是回到它被调用的地方。它进入一个无限循环 代码如下。如果安装了Y86模拟器,则它是独立的

下面是一个汇编语言类的家庭作业问题。我们将通过读取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:
谢谢你的帮助

mrmovl  -4(%ebp), %edx

问题就在这里。在ebp-4中有返回地址,因此您正在覆盖它。使用不同的位置,一切都会好起来:)

这可能是错误的原因,也可能不是,但我认为您正在错误地拆除
总和列表的堆栈框架。您可以按如下方式进行设置:

pushl   %ebp  
rrmovl  %esp, %ebp
然后你就这样把它拆掉:

rrmovl  %esp, %ebp
popl    %ebp
请注意,在这两种情况下,您都从
%esp
复制到
%ebp
,这是不正确的,因为拆卸应该撤消安装程序所做的操作。相反,试试看

rrmovl  %ebp, %esp
popl    %ebp
或者干脆

leave
这与堆栈操作有两个(半)问题:

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

尝试访问前一帧(即调用方的帧)中存储的参数失败。堆栈自上而下运行,堆栈上存储的最后一个元素是返回地址和旧的帧指针,因此一旦更改了ebp寄存器,被调用方可以通过从8(%ebp)开始的递增偏移量直接引用调用函数的参数

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


在我的Y86博客上讨论了呼叫者-被呼叫者约定

回复地址不应该在ebp+4吗?堆栈不是沿着较低地址的方向增长吗(即堆栈的顶部实际上是底部)?所以在这种情况下,在调用时,返回地址在esp。下一条指令,旧的ebp被按下(表示%esp被4删除),然后ebp被移动到该值,表示ebp也被4删除。所以ebp应该比回信地址低4。谢谢!就这样。我的困惑源于Y86没有请假指示。我查了一下那个指令是如何工作的,一定是抄错了。我做了改变,效果很好@用户373374:太棒了!顺便说一下,我以前从未听说过Y86——它似乎是一种基于X86的教学语言?看起来很有趣;你有关于它的好资源吗?是的,它是一种用于教学的简化汇编语言。wrt参考资料,它主要是我们的教科书,《计算机系统:程序员的视角》,作者Bryant&O'Hallaron,课堂幻灯片,当然还有Google:)它几乎与X86相同,只是指令集更小。例如,movl分为rrmovl、rmmovl、mrmovl和irmovl(分别为reg->reg、reg->mem、mem->reg和const->reg)。你还必须分解像leave和lea这样的指令。