【问题标题】:Y86 code doesn't handle ret instruction as expectedY86 代码未按预期处理 ret 指令
【发布时间】:2023-04-05 15:28:01
【问题描述】:

以下是一门汇编语言课的作业题。我们将通过在 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:

感谢您的帮助!

【问题讨论】:

    标签: assembly x86 y86


    【解决方案1】:

    这可能是也可能不是错误的原因,但我认为您错误地拆除了sum_list 的堆栈帧。你设置如下:

    pushl   %ebp  
    rrmovl  %esp, %ebp
    

    然后你像这样拆掉它:

    rrmovl  %esp, %ebp
    popl    %ebp
    

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

    rrmovl  %ebp, %esp
    popl    %ebp
    

    或者干脆

    leave
    

    做同样的事情。

    【讨论】:

    • 谢谢!就是这样。我的困惑源于 Y86 没有请假指令。我查看了该指令的工作原理,并且一定是错误地复制了它。我进行了更改,效果很好!
    • @user373374:太棒了!顺便说一句,我以前没有听说过Y86——它似乎是一种基于X86的教学语言?看起来很有趣;你有什么好的资源吗?
    • 是的,它是一种用于教学的简化汇编语言。 wrt 资源,主要是我们的教科书,计算机系统:程序员的观点,作者 Bryant 和 O'Hallaron,课程幻灯片,当然还有 Google :) 它几乎与 X86 相同,只是指令集更小。例如,movl 分为 rrmovl、rmmovl、mrmovl 和 irmovl(分别为 reg->reg、reg->mem、mem->reg 和 const->reg)。您还必须分解离开和离开等指令。
    【解决方案2】:
    mrmovl  -4(%ebp), %edx
    

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

    【讨论】:

    • 返回地址不应该是ebp+4吗?栈不是向低地址的方向增长(即栈顶真的是栈底)吗?所以在这种情况下,在调用时,返回地址在 esp。下一条指令,旧的 ebp 被推送(意味着 %esp 被 dec'd 4),然后 ebp 被移动到该值,这意味着 ebp 也被 dec'd 4。所以ebp应该是4低于返回地址。
    【解决方案3】:

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2010-11-04
      • 1970-01-01
      • 2021-11-21
      • 1970-01-01
      • 2018-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多