【问题标题】:Assembly x86_64 displays residual values汇编 x86_64 显示残值
【发布时间】:2019-09-19 22:25:05
【问题描述】:

我想从控制台获取一个数字并以 1 为增量显示它。但结果不是我想要显示的。你能向我解释我做错了什么吗? (我在组装方面一点都不先进)

.data
number: .long 0
numberformat: .asciz "%ld"
assig: .asciz "text \n \n"
enternumber: .asciz "Enter the number: \n"
numberformat1: .asciz "The input number+1 = %d \n"

.text
.global main
main:           # main
    call print1
    call print2
    call inout
    call exit

inout:
    movq $0, %rax    # clear rax
    movq $numberformat, %rdi    # load format string
    movq $number, %rsi    # set storage to address of number
    call scanf
    pop %rbp
    movq $number, %rbx
    add $1, %rbx
    movq $0, %rax
    movq %rbx, %rsi
    movq $numberformat1, %rdi
    call printf    
    # call printnewnumber
    ret

print1:
    movq $0, %rax
    movq $assig, %rdi
    call printf
    ret

print2:
    movq $0, %rax
    movq $enternumber, %rdi
    call printf
    ret

printnewnumber:
    movq $0, %rax
    movq %rdx, %rsi
    movq $numberformat1, %rdi
    call printf    
    ret

【问题讨论】:

  • “但结果不是我想要显示的” - 那么程序实际打印的是什么?
  • 程序显示(我认为)剩余值,正如我在标题中所说。如果我运行该程序,我将始终在控制台中得到相同的数字(这不是我写的加 1 的数字)
  • 不要将 Javascript sn-p 标签用于汇编代码。这行不通。
  • 我正在使用带有 AT&T 语法(x86_64 程序集)的 Debian,并使用 gcc 进行编译
  • pop %rbp 在那里很奇怪。您正在从堆栈中弹出您的返回地址,所以当inout 底部的ret 返回时,它实际上是返回到main 的返回地址。 call exit 永远无法到达。

标签: assembly x86-64


【解决方案1】:

movq $number, %rbx 行不复制输入数字本身,而只是复制它的地址。如果你取消引用指针,你会得到想要的输出:

将上述行改为

movq number(%rip), %rbx   # Dereference pointer and store input number in RBX

产量

Assignment 1b: inout

Enter the number:
123
The input number+1 = 124

【讨论】:

  • 不是我们应得的英雄,而是我们需要的英雄。非常感谢!
  • 为什么要在单独的指令中将地址用作 32 位绝对立即数(符号扩展为 64 位:movq 而不是 movabs)?像编译器一样使用mov number(%rip), %rbx。或者,如果您真的想要 32 位绝对值,请使用 mov number, %rbx,就像在 32 位代码中一样(没有 RIP 相对寻址)。这也适用于非 PIE 可执行文件,但效率低下。处理静态数据的常规方法是相对于 RIP。
  • 我不完全明白。为什么movq $number, %rbx 会移动 32 位立即数?这不是一个明确的qword动作吗?无论如何,感谢您指出正确的语法,我仍在努力学习 AT&T 语法,显然无法弄清楚如何完全正确地做到这一点 - 我通常使用 NASM,mov rbx, qword [rel number] 本来是要走的路。我没有想到在这里使用显式的rip-relative 寻址,我在编写 NASM 程序集时从来不需要它(好吧,现在我知道,rel 实际上是相同的;))。我已经编辑了答案。
  • @JanWichelmann:看看movqmovabs 的反汇编。最后我检查了一下,只有movabs 使用 64 位绝对立即数作为地址 IIRC。但是,如果您想要寄存器中的地址,那么这两者当然都比 RIP 相关的 LEA 不好。当然,没有理由这样做。 Intel 语法 mov 包括 movq(32 位立即符号扩展,或具有正常寻址模式的 64 位 mov)和 movabsq(64 位立即或 64 位绝对加载/存储)。你不想要绝对地址; RIP + rel32 寻址方式是最紧凑的静态数据寻址方式。
  • 哦,是的,我不久前写了一个关于这个的答案。请参阅Difference between movq and movabsq in x86-64 比较 AT&T 与 NASM 的反汇编。还有How do RIP-relative variable references like "[RIP + _a]" in x86-64 GAS Intel-syntax work? 用于 NASM 与 GAS 的 AT&T 和 Intel 语法
猜你喜欢
  • 1970-01-01
  • 2015-09-11
  • 2015-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-24
相关资源
最近更新 更多