【问题标题】:Assembly - store the result of a comparison (1 if true, 0 if false)?汇编 - 存储比较的结果(如果为真,则为 0,如果为假,则为 0)?
【发布时间】:2021-02-26 13:53:48
【问题描述】:

我正在为 uni 赋值编写编译器,我目前正在从内部表示中发出 asm。我对for (a = 1; a < 10; a++) do print a 有以下表示:

COPY a, 1                    // Copy 1 to a
LABEL label0                 // 
LT tmp0, a, 10               // Store in tmp0 the result of the expression a < 10
JUMP_FALSE label1, tmp0      // Jump to label1 if tmp0 is false
PRINT a                      //
ADD a, a, 1                  // Store in a the result of the expression a + 1
JUMP label0                  //
LABEL label1                 //

我为此发出以下 asm,其中常量和变量都作为正交性的全局变量发出:

#a := 1
movl var_1(%rip), %eax
movl %eax, var_a(%rip)
.label0:
#EXPR_START tmp0 = a < 10
movl var_a(%rip), %eax
movl var_10(%rip), %edx
cmpl %eax, %edx
setl %al
movzbl %al, %eax
movl %eax, var_tmp0(%rip)
#EXPR_END
#jmpf label1, tmp0
movl var_tmp0(%rip), %eax
testl %eax, %eax
jne .label1
#Print a
movl var_a(%rip), %eax
movl %eax, %esi
leaq printf_int(%rip), %rdi
movl $0, %eax
call printf@PLT
movl $0, %eax
#EXPR_START a = a + 1
movl var_a(%rip), %eax
movl var_1(%rip), %edx
addl %edx, %eax
movl %eax, var_a(%rip)
#EXPR_END
#jmp label0
jmp .label0
.label1:

这似乎是在比较a &lt;= 10,但我不明白为什么。 cmplsetl 组合不是将 %al 的值设置为 1,如果比较的结果是“小于”?那么testl %eax, %eax 不应该是1a &lt; 10jne 发生在a == 10 时?如果我的理解有误,如何将比较结果存储在寄存器中(如果比较成立则为 1,否则为 0)?

下面是可以用gcc asm.s 编译的完整asm。预期输出为1 2 3 4 5 6 7 8 9,实际输出为1 2 3 4 5 6 7 8 9 10

main:
pushq %rbp
movq %rsp, %rbp
#a := 1
movl var_1(%rip), %eax
movl %eax, var_a(%rip)
.label0:
#EXPR_START
movl var_a(%rip), %eax
movl var_10(%rip), %edx
cmpl %eax, %edx
setl %al
movzbl %al, %eax
movl %eax, var_tmp0(%rip)
#EXPR_END
#jmpf label1, tmp0
movl var_tmp0(%rip), %eax
movl $1, %edx
cmpl %eax, %edx
je .label1
#Print a
movl var_a(%rip), %eax
movl %eax, %esi
leaq _printf_int(%rip), %rdi
movl $0, %eax
call printf@PLT
movl $0, %eax
#EXPR_START
movl var_a(%rip), %eax
movl var_1(%rip), %edx
addl %edx, %eax
movl %eax, var_a(%rip)
#EXPR_END
#jmp label0
jmp .label0
.label1:
popq %rbp
ret
.text
.globl var_tmp1
.data
.size var_tmp1, 4
var_tmp1:
.long 0
.text
.globl main
.text
.globl var_1
.data
.size var_1, 4
var_1:
.long 1
.text
.globl var_a
.data
.size var_a, 4
var_a:
.long 0
.text
.globl var_10
.data
.size var_10, 4
var_10:
.long 10
.text
.globl var_tmp0
.data
.size var_tmp0, 4
var_tmp0:
.long 0
_printf_int:
.string "%d "

【问题讨论】:

  • 您已编码if (10 &lt; a) goto label1。您已经交换了cmp 中的操作数顺序,并且您使用了if (tmp0 == 1),这意味着JUMP_TRUE 而不是JUMP_FALSE

标签: assembly x86-64 att


【解决方案1】:
movl var_a(%rip), %eax
movl var_10(%rip), %edx
cmpl %eax, %edx
setl %al

如果%edx 小于%eax,即如果10 小于a,这会将%al 设置为1。这似乎与您想要的相反,因此要么交换 cmpl 的操作数,要么反转您的测试 (setge %al)。

混淆的部分原因可能是汇编程序助记符最初是为 Intel 语法发明的,其中双操作数指令的源和目标是另一个顺序:mov dest, src 而不是 AT&T 的 movl %src, %dest。所以在 Intel 语法中,如果rx 小于rycmp rx, ry ; setl rz 将设置rz,这与代数符号rx &lt; ry 匹配。但是对于 AT&T 语法,这变成了cmpl %ry, %rx ; setl %rz,这可能会向后看。将第二个“目标”操作数视为谓词“关于”的操作数可能会有所帮助:“如果%rx 小于%ry 则设置”。

【讨论】:

猜你喜欢
  • 2012-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-19
  • 2021-01-07
  • 2016-07-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多