在C代码中,是否有一种方法可以将ASM指令的文本表示形式(如cmpwi r3, 0x20
)转换为二进制表示形式(0x2c030020
)?
我正在编写将在运行时嵌入到另一个应用程序中的代码。该代码应该更改正在运行的程序的行为/代码。这意味着有一堆这样的代码行:
*((volatile int *)(0x80001234)) = 0x2c030020;
该代码将ASM指令cmpwi r3, 0x20
写入0x80001234,从而覆盖该地址上的当前指令。现在,在我的C代码中拥有常量“ 0x2c030020”,而又不知道该怎么做对维护代码不利。因此,我通常会在上面的代码中添加注释,说明ASM指令:// 2c 03 00 20 = cmpwi r3, 0x20
但是,这些有时会不同步。我可能会快速更改整数值而忘了更新评论,或者我可能只是在评论中打错了打字,引起混乱。
有什么办法可以代替我吗? (伪代码)*((volatile int *)(0x80001234)) = asm("cmpwi r3, 0x20");
,然后将导致0x2c030020被写入80001234?还是我需要一个在我的C源文件上运行自定义预处理器的骇人解决方案,用其字节码替换ASM指令?
我知道使用asm()
函数的内联汇编代码具有C语法,但是它将执行给定的ASM指令,而不是给我它们的二进制表示形式。
答案 0 :(得分:1)
听起来这很疯狂,但是我想您有充分的理由。没有一点疯狂,生活就没有乐趣。
您可以使用的一种方法是在构建过程中使用汇编器来生成编译时常量。
第一步是制作一个包含每条汇编指令的文件,每行一条。
例如:
cmpwi 3,0x20
addi 3,3,0
blr
将该文件命名为input.def。然后,使用以下shell脚本:
#!/usr/bin/env bash
(cat << HEADER
.global main
.text
main:
HEADER
cat input.def) > asm.s
powerpc-linux-gnu-as asm.s -o asm.o
powerpc-linux-gnu-objdump -d asm.o | \
sed '1,/<main>/ d' | \
paste -d'\t' - input.def | \
awk -F'\t' '{
bytes=$2
asm=$4
disasm=$3
gsub(/ /, "", bytes);
gsub(/[, ]+/, "_", asm);
printf("#define ASM_%-20s 0x%s // disassembly: %s\n", asm, bytes, disasm)
}'
# Clean temporaries
rm asm.s asm.o
(我在这里使用GNU汇编器和objdump。如果不使用这些工具,则可能需要更改此部分。这里将objdump用作美化的hexdump实用程序。)
此shell脚本:
这是很多工作,但是您可以在编译时完成所有工作。
这将产生一个名为asm.h的头文件:
#define ASM_cmpwi_3_0x20 0x2c030020 // disassembly: cmpwi r3,32
#define ASM_addi_3_3_0 0x38630000 // disassembly: addi r3,r3,0
#define ASM_blr 0x4e800020 // disassembly: blr
您可以这样使用asm.h文件:
#include "asm.h"
*((volatile int *)(0x80001234)) = ASM_cmpwi_3_0x20;
如果需要新的asm常量,请编辑input.def并重新运行Shell脚本。