【问题标题】:x86 assembly jl doesn't workx86 程序集 jl 不起作用
【发布时间】:2018-05-24 23:45:09
【问题描述】:

我在 64 位 Ubuntu 上使用 x86 程序集(AT&T 语法)进行编码(所以我使用的是 as --32ld -melf_i386,到目前为止,它在其他练习中运行良好)。

jl 指令的工作方式与我的预期相反。我实际上可以让代码与jg 一起正常工作,这基本上可以解决我的问题,但我想在这里找出根本问题。

代码sn-p如下:

   # Open file for reading
   movl $SYS_OPEN, %eax         # prepare syscall 5 
   movl $input_file_name, %ebx      # move input file name into %ebx
   movl $0, %ecx                    # open in read-only mode
   movl $0666, %edx     
   int $LINUX_SYSCALL               # execute system call,
                                   # sys_open returns file descriptor in %eax

   movl %eax, ST_INPUT_DESCRIPTOR(%ebp) # store the input file descriptor away

   # This will test and see if %eax is negative. 
   # If it is not negative, it will jump to continue_processing.
   # Otherwise it will handle the error condition that the negative number represents.
   cmpl $0, %eax
   jl continue_processing

   pushl $no_open_file_msg
   pushl $no_open_file_code
   call error_exit

continue_processing:

   # Open file for writing
   movl $SYS_OPEN, %eax         # prepare syscall 5 

...程序继续进行,尽管其余部分与此问题无关。

使用 gdbgui 进行调试,我看到 open sys 调用返回输入文件描述符 (eax = 3) 没有问题。 然后你比较 0 和 3。如果我不是白痴,0 jl 指令should take you to continue_processing,但it does not

但是,如果我改用jg,它就可以工作。打开系统调用returns 3 in eaxjg properly jumpscontinue_processing

我读过跳转操作数的顺序可能取决于汇编程序。这里会是这样吗?使用gcc -m32 -nostdlib 编译具有相同的行为。我还尝试将订单交换为cmpl %eax, $0,但出现错误:'cmp' 的操作数类型不匹配。

或者这只是这个 32 位代码在 64 位 Ubuntu 上运行这一事实的怪癖?

我正在看书Programming From the Ground Up。在第 125 页上,本书的示例在 jl continue_processing 之后插入了 .section .data,插入了一些标签和 .ascii 命令,然后在 pushl $no_open_file_msg 之前使用 .section .text 恢复代码。为了清理代码,我将.section .data 合并到顶部,因此不需要第二个.section .text。它似乎不会影响jl 问题,但我想我会提到它,以防问题确实存在。

【问题讨论】:

  • 您正在阅读的书是从头开始编程(我在您的问题中添加了参考)。有问题的代码在第 125 页。这实际上是书中的一个错误,它应该是 JGE 而不是 JL。该错误已在本书的错误跟踪系统中报告。该错误报告在这里:savannah.nongnu.org/bugs/?17654。不幸的是,这本书已经十年没有更新了。您可以在此处找到所有已报告问题的列表:savannah.nongnu.org/bugs/?group=pgubook
  • 是的,就是这本书。另外,很好的链接,谢谢

标签: ubuntu assembly x86 32-bit att


【解决方案1】:

在 AT&T 语法中,操作数的顺序与 Intel 语法相比是交换的。为此,

cmpl $0, %eax

实际上计算 eax - 0 并设置标志,而不是像您预期的那样计算 0 - eax。因此,所有标志的设置方式都与您最初预期的相反,从而导致您观察到的问题。没有真正的方法可以解决这个问题,因为它并没有真正的错误。我建议你习惯这个怪癖。

一般来说,使用testl 指令而不是将值与零进行比较通常是个好主意。 testl %eax,%eax 在机器代码中比 cmp $0,%eax 更紧凑,在某些微架构上也更快。 testl 根据位和其操作数设置标志,因此如果 eax 为负数,SF 设置在 testl %eax,%eax 之后,您可以像这样检查:

testl %eax,%eax
jns continue_processing

【讨论】:

  • CF=0 在and 总是之后。但是他可以测试顺丰js negative_eax_detected。 ... 补救措施是使用 Intel 语法。
  • @Ped7g:使用 JL 代替 JS 效率更高。测试(和对零的 cmp)也总是清除 OF,因此它相当于直接测试 SF,但可以在更多 CPU 上进行宏融合。即test %eax,%eax/jl negative_eax_detectedTEST same,same and CMP-with-zero set all flags identically,AF 除外。
  • 感谢您的确认,这很奇怪,因为这本书全是 x86 AT&T 汇编,而作者在我猜他的意思是 jg 时使用了 jl。但这已经足够了,我习惯了这个怪癖没有问题。
  • @JaimeSalazar 啊,这本书是从头开始编程第 125 页
  • @Ped7g 谢谢,我把 CF 和 SF 搞混了。
猜你喜欢
  • 2015-09-22
  • 1970-01-01
  • 1970-01-01
  • 2015-01-21
  • 2019-02-26
  • 2012-03-11
  • 2011-05-26
  • 2016-03-30
相关资源
最近更新 更多