最近写中断嵌套汇编的时候发现这么一个问题:我的汇编语句被arm-linux-gcc更改了。熟悉编译器的人获悉给个“哦”!以为编译器不管是翻译一些C/C++,还是更底层的汇编语句,一定会对其有所更改。
sub r14,r14,#4
str r14,[r13,#-0x4]
mrs r14,spsr
str r14,[r13,#-0x8]
str r0,[r13,#-0xc]
mov r0,r13
msr CPSR_c,#0xd3
ldr r14,[r0,#-0x4]
sub r13,r13,#4
str r14,[r13]
ldr r14,[r0,#-0x8]
sub r13,r13,#4
str r14,[r13]
ldr r0,[r0,#-0xc]
stmdb r13!,{r0-r12}
bl ext_irq_server
ldmia r13!,{r0-r12}
ldmia r13!,{r14}
msr spsr,r14
ldmia r13!,{pc}^ ;(这是最终正确版,欢迎使用)
在arm-linux-gcc-4.3.2上编译通过,但是程序只能执行中断处理程序,回不去中断之前的状态!毫无疑问在压栈出栈那块一定有问题。于是分析程序逻辑,压栈出栈、调整核心执行程序。最后在反汇编中找到了答案:
本来我使用的stmdb/ldmia等四字节压栈出栈指令被编译器转化为push/pop双字节压栈出栈。然后我修改Makefile 给arm-linux-gcc添加-O0选项,使其不优化我的语句,固执的编译器一如既往,于是它就被我无情换成了arm-linux-gcc-3.2.5版本。测试后在反汇编中就看到stmdb/ldmia等四字节压栈出栈指令!开心!
小结:编译有风险,多加小心。
2017/12/19
Carl
在我看来,任何编译器只是按照自己的一套规则去翻译用户的语言。只是当编译通过的时候,大多数时候我们能运行自己的程序。如果不能呢?BUG!!!(它认为你的语言没有错别字,但是可能他不太会断句,是吧)。
话说回来,为实现操作系统的嵌套中断处理,我编写了如下语句:
Handleirq:sub r14,r14,#4
str r14,[r13,#-0x4]
mrs r14,spsr
str r14,[r13,#-0x8]
str r0,[r13,#-0xc]
mov r0,r13
msr CPSR_c,#0xd3
ldr r14,[r0,#-0x4]
sub r13,r13,#4
str r14,[r13]
ldr r14,[r0,#-0x8]
sub r13,r13,#4
str r14,[r13]
ldr r0,[r0,#-0xc]
stmdb r13!,{r0-r12}
bl ext_irq_server
ldmia r13!,{r0-r12}
ldmia r13!,{r14}
msr spsr,r14
ldmia r13!,{pc}^ ;(这是最终正确版,欢迎使用)
在arm-linux-gcc-4.3.2上编译通过,但是程序只能执行中断处理程序,回不去中断之前的状态!毫无疑问在压栈出栈那块一定有问题。于是分析程序逻辑,压栈出栈、调整核心执行程序。最后在反汇编中找到了答案:
本来我使用的stmdb/ldmia等四字节压栈出栈指令被编译器转化为push/pop双字节压栈出栈。然后我修改Makefile 给arm-linux-gcc添加-O0选项,使其不优化我的语句,固执的编译器一如既往,于是它就被我无情换成了arm-linux-gcc-3.2.5版本。测试后在反汇编中就看到stmdb/ldmia等四字节压栈出栈指令!开心!
小结:编译有风险,多加小心。
2017/12/19
Carl