程序集 - 存储比较结果(如果为真,则为 1,如果为假,则为 0)?



我正在为 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 <= 10,但我不明白为什么。如果比较结果为"小于",cmplsetl组合不是将%al的值设置为 1 吗?那么testl %eax, %eax不应该在a < 101jne发生在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 "
movl var_a(%rip), %eax
movl var_10(%rip), %edx
cmpl %eax, %edx
setl %al

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

部分混淆可能来自这样一个事实,即汇编助记符最初是为英特尔语法发明的,其中双操作数指令的来源和目的地是另一个顺序:mov dest, src而不是AT&T的movl %src, %dest。 所以在英特尔语法中,如果rx小于rycmp rx, ry ; setl rz会设置rz,这与代数表示法rx < ry匹配。 但对于AT&T语法来说,这变得cmpl %ry, %rx ; setl %rz可能会向后看。 将第二个"目的地"操作数视为谓词"大约"的操作数可能会有所帮助:"如果%rx小于%ry则设置"。

相关内容

最新更新