告诉编译器以不同的方式翻译某条指令?
Tell the compiler to translate a certain instruction differently?
我正在使用 armcc 和 arm-gcc 为 ARM968 处理器编译我的项目。
函数调用返回时,返回指令如下:
Pop {ri-rj, pc}
所有压入的寄存器都在同一条指令中弹出。我想把上面的指令改成这样:
Pop {ri-rj}
Pop {pc}
我可以在使用 Pop
时指示汇编器或编译器在任何 ARM 工具链中遵守上述规则吗?
您可以告诉 gcc 在生成 assembler 后停止处理。您可以手动或使用 sed
编辑 assembler 文件。然后你将 assembler 文件从 binutils 传递到 as
到 assemble 到目标文件。
$ cat test.c
#include <stdio.h>
int main(int argc, char *argv[])
{
printf ("hello world\n");
return 0;
}
$ gcc test.c -o test.s -S
cat test.s
.file "test.c"
.section .rodata
.LC0:
.string "hello world"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq , %rsp
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
movl $.LC0, %edi
call puts
movl [=10=], %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4"
.section .note.GNU-stack,"",@progbits
$ as test.s -o test.o
根据问题的确切性质,以及您是否严重依赖一些较新的指令,另一种可能性可能是针对 ARMv4T 进行编译。在 ARMv5T 之前,进入 PC 的 ldm
无法互通,因此编译器不会为 v4T 目标发出那种形式的 return 指令。对于一些简单的测试代码,使用 -march=armv5t
编译会生成一个堆栈帧:
8: e92d4070 push {r4, r5, r6, lr}
...
4c: d8bd8070 pople {r4, r5, r6, pc}
而使用 -march=armv4t
编译相同的东西使用相同的序言但使用间接 return 序列(上面是循环内的条件 return,现在它也被移动到函数末尾):
48: da000006 ble 68 <func+0x68>
...
68: e8bd4070 pop {r4, r5, r6, lr}
6c: e12fff1e bx lr
当然,这是否与两个单独的 pop 具有相同的效果取决于系统中的潜在错误是什么 - 如果它类似于 ldm
和指令的数据获取之间的时间获取跳跃本身,那么这可能是足够等价的;可以想象它可能是完全不同的东西,比如一个损坏的内存系统截断了超过一定大小的 AHB 突发,所以它是在单个 ldm
中传输的寄存器数量这就是问题所在,但在那种情况下我也希望查看 memcpy
之类的问题,这些问题不太容易解决。
我正在使用 armcc 和 arm-gcc 为 ARM968 处理器编译我的项目。
函数调用返回时,返回指令如下:
Pop {ri-rj, pc}
所有压入的寄存器都在同一条指令中弹出。我想把上面的指令改成这样:
Pop {ri-rj}
Pop {pc}
我可以在使用 Pop
时指示汇编器或编译器在任何 ARM 工具链中遵守上述规则吗?
您可以告诉 gcc 在生成 assembler 后停止处理。您可以手动或使用 sed
编辑 assembler 文件。然后你将 assembler 文件从 binutils 传递到 as
到 assemble 到目标文件。
$ cat test.c
#include <stdio.h>
int main(int argc, char *argv[])
{
printf ("hello world\n");
return 0;
}
$ gcc test.c -o test.s -S
cat test.s
.file "test.c"
.section .rodata
.LC0:
.string "hello world"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq , %rsp
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
movl $.LC0, %edi
call puts
movl [=10=], %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4"
.section .note.GNU-stack,"",@progbits
$ as test.s -o test.o
根据问题的确切性质,以及您是否严重依赖一些较新的指令,另一种可能性可能是针对 ARMv4T 进行编译。在 ARMv5T 之前,进入 PC 的 ldm
无法互通,因此编译器不会为 v4T 目标发出那种形式的 return 指令。对于一些简单的测试代码,使用 -march=armv5t
编译会生成一个堆栈帧:
8: e92d4070 push {r4, r5, r6, lr}
...
4c: d8bd8070 pople {r4, r5, r6, pc}
而使用 -march=armv4t
编译相同的东西使用相同的序言但使用间接 return 序列(上面是循环内的条件 return,现在它也被移动到函数末尾):
48: da000006 ble 68 <func+0x68>
...
68: e8bd4070 pop {r4, r5, r6, lr}
6c: e12fff1e bx lr
当然,这是否与两个单独的 pop 具有相同的效果取决于系统中的潜在错误是什么 - 如果它类似于 ldm
和指令的数据获取之间的时间获取跳跃本身,那么这可能是足够等价的;可以想象它可能是完全不同的东西,比如一个损坏的内存系统截断了超过一定大小的 AHB 突发,所以它是在单个 ldm
中传输的寄存器数量这就是问题所在,但在那种情况下我也希望查看 memcpy
之类的问题,这些问题不太容易解决。