我正在为一个简单的语言规范编写一个编译器,并使用给我的参考编译器,我一直在关注生成的程序集并将其定制到我自己的编译器。
然而,在检查参考编译器生成的程序集的过程中,我很难理解为什么我更改的程序集导致第二个打印不生成任何内容:
.data
msg_0:
.word 50
.ascii "NullReferenceError: dereference a null reference\n\0"
msg_1:
.word 5
.ascii "%.*s\0"
msg_2:
.word 3
.ascii "%d\0"
msg_3:
.word 1
.ascii "\0"
.global main
.text
main:
PUSH {lr}
SUB sp, sp, #8
LDR r0, =8
BL malloc
MOV r4, r0
LDR r5, =10
LDR r0, =4
BL malloc
STR r5, [r0]
STR r0, [r4]
MOV r5, #'a'
LDR r0, =1
BL malloc
STRB r5, [r0]
STR r0, [r4, #4]
STR r4, [sp, #4]
LDR r4, [sp, #4]
MOV r0, r4
BL p_check_null_pointer
LDR r4, [r4]
LDR r4, [r4]
STR r4, [sp, #0]
LDR r4, [sp, #0]
MOV r0, r4
BL p_print_int
BL p_print_ln
LDR r4, =42
LDR r5, [sp, #4]
MOV r0, r5
BL p_check_null_pointer
LDR r5, [r5]
STR r4, [r5]
LDR r4, [sp, #4]
MOV r0, r4
BL p_check_null_pointer
LDR r4, [r4]
LDR r4, [r4]
STR r4, [sp, #0]
LDR r4, [sp, #0]
MOV r0, r4
BL p_print_int
BL p_print_ln
ADD sp, sp, #8
LDR r0, =0
POP {pc}
.ltorg
p_check_null_pointer:
PUSH {lr}
CMP r0, #0
LDREQ r0, =msg_0
BLEQ p_throw_runtime_error
POP {pc}
p_throw_runtime_error:
BL p_print_string
MOV r0, #-1
BL exit
p_print_string:
PUSH {lr}
LDR r1, [r0]
ADD r2, r0, #4
LDR r0, =msg_1
ADD r0, r0, #4
BL printf
MOV r0, #0
BL fflush
POP {pc}
p_print_int:
PUSH {lr}
MOV r1, r0
LDR r0, =msg_2
ADD r0, r0, #4
BL printf
MOV r0, #0
BL fflush
POP {pc}
p_print_ln:
PUSH {lr}
LDR r0, =msg_3
ADD r0, r0, #4
BL puts
MOV r0, #0
BL fflush
POP {pc}
此处的程序集由以下代码段
生成begin
pair(int, char) p = newpair(10, 'a');
int f = fst p;
println f;
fst p = 42;
f = fst p;
println f
end
作为编译器的扩展,我决定进行编译器优化(强度降低/死代码消除/窥孔优化等)。所以我发现以下汇编指令,我认为我将其简化为一条指令:
LDR r4, [sp, #4]
MOV r0, r4
要
LDR r0, [sp, #4]
所以在主要中,我对上面的说明进行了更改
LDR r4, [sp, #4]
MOV r0, r4
LDR r4, [sp, #0]
MOV r0, r4
LDR r5, [sp, #4]
MOV r0, r5
LDR r4, [sp, #4]
MOV r0, r4
LDR r4, [sp, #0]
MOV r0, r4
当我进行这些修改时,只有第一条打印指令打印10.它还应该打印42.所以我期待
10
42
但实际上在改变后它是
10
我阅读了手册,发现MOV用于字节值,我们应该将LDR用于大小超过一个字节的任何内容。但为什么这不起作用?
我不明白我在这里做错了什么。