通过修改 LLVM Backend 来 Clobber X86 注册
Clobber X86 register by modifying LLVM Backend
我正在尝试稍微改变 X86 目标的 LLVM 后端,以产生一些所需的行为。
更具体地说,我想模拟一个标志,如 gcc 的 fcall-used-reg option,它指示编译器将被调用者保存的寄存器转换为一个被破坏的寄存器(意味着它可能在函数调用期间被改变)。
让我们关注r14。我手动破坏了寄存器,比如 this answer:
#include <inttypes.h>
uint64_t inc(uint64_t i) {
__asm__ __volatile__(
""
: "+m" (i)
:
: "r14"
);
return i + 1;
}
int main(int argc, char **argv) {
(void)argv;
return inc(argc);
}
编译反汇编:
gcc -std=gnu99 -O3 -ggdb3 -Wall -Wextra -pedantic -o main.out main.c
objdump -d main.out
反汇编包含:
0000000000001150 <inc>:
1150: 41 56 push %r14
1152: 48 89 7c 24 f8 mov %rdi,-0x8(%rsp)
1157: 48 8b 44 24 f8 mov -0x8(%rsp),%rax
115c: 41 5e pop %r14
115e: 48 83 c0 01 add [=12=]x1,%rax
1162: c3 retq
1163: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
116a: 00 00 00
116d: 0f 1f 00 nopl (%rax)
这里我们可以看到r14,因为被篡改,被压入栈中,然后出栈恢复原来的值。
现在,重复 -fcall-used-r14 标志:
gcc -std=gnu99 -O3 -ggdb3 -fcall-used-r14 -Wall -Wextra -pedantic -o main.out main.c
objdump -d main.out
反汇编包含:
0000000000001150 <inc>:
1150: 48 89 7c 24 f8 mov %rdi,-0x8(%rsp)
1155: 48 8b 44 24 f8 mov -0x8(%rsp),%rax
115a: 48 83 c0 01 add [=14=]x1,%rax
115e: c3 retq
115f: 90 nop
没有 push/pop 发生。
现在,我已经修改了一些 LLVM 目标文件,编译了源代码,并将此功能添加(?)到 llc 工具中:
clang-11 -emit-llvm -S -c main.c -o main.ll
llc-11 main.ll -o main.s
现在,main.s
包含:
# %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
pushq %r14
.cfi_offset %r14, -24
movq %rdi, -16(%rbp)
#APP
#NO_APP
movq -16(%rbp), %rax
addq , %rax
popq %r14
popq %rbp
.cfi_def_cfa %rsp, 8
retq
显然,r14 仍然是 callee-saved。
在 llvm/lib/Target/X86/X86CallingConv.td
中,我修改了以下几行(删除了 R14),因为它们似乎与我感兴趣的 Linux 和 C 调用约定的 System V ABI 唯一相关:
def CSR_64 : CalleeSavedRegs<(add R12, R13, R15, RBP)>;
...
def CSR_64_MostRegs : CalleeSavedRegs<(add RBX, RCX, RDX, RSI, RDI, R8, R9, R10,
R11, R12, R13, R15, RBP,
...
def CSR_64_AllRegs_NoSSE : CalleeSavedRegs<(add RAX, RBX, RCX, RDX, RSI, RDI, R8, R9,
R10, R11, R12, R13, R15, RBP)>;
我的问题是:
X86CallingConv.td
是我应该修改的唯一文件吗?我想是的,但也许我错了。
- 我关注的是正确的台词吗?也许这更难回答,但至少一个方向可能会有所帮助。
我是 运行 Debian 10.5 中的 LLVM 11。
编辑:
更改行,从“隐藏”定义中删除 R14:
def CSR_SysV64_RegCall_NoSSE : CalleeSavedRegs<(add RBX, RBP, RSP,
(sequence "R%u", 12, 13), R15)>;
正如玛格丽特正确指出的那样,也没有帮助。
原来,最小的修改是行:
def CSR_64 : CalleeSavedRegs<(add RBX, R12, R13, R15, RBP)>;
问题出在我构建源代码的方式上。
通过 运行 cmake --build .
再次在原始安装后, llc 工具没有被全局修改(我认为它会因为我正在构建默认架构 - X86 - 但这无关紧要)。所以,我调用了一个未修改的 llc-11 工具。因此,当我 运行:
/path/to/llvm-project/build/bin/lcc main.ll -o main.s
main.s
包含:
# %bb.0:
movq %rdi, -8(%rsp)
#APP
#NO_APP
movq -8(%rsp), %rax
addq , %rax
retq
这正是我想要的。
我正在尝试稍微改变 X86 目标的 LLVM 后端,以产生一些所需的行为。
更具体地说,我想模拟一个标志,如 gcc 的 fcall-used-reg option,它指示编译器将被调用者保存的寄存器转换为一个被破坏的寄存器(意味着它可能在函数调用期间被改变)。
让我们关注r14。我手动破坏了寄存器,比如 this answer:
#include <inttypes.h>
uint64_t inc(uint64_t i) {
__asm__ __volatile__(
""
: "+m" (i)
:
: "r14"
);
return i + 1;
}
int main(int argc, char **argv) {
(void)argv;
return inc(argc);
}
编译反汇编:
gcc -std=gnu99 -O3 -ggdb3 -Wall -Wextra -pedantic -o main.out main.c
objdump -d main.out
反汇编包含:
0000000000001150 <inc>:
1150: 41 56 push %r14
1152: 48 89 7c 24 f8 mov %rdi,-0x8(%rsp)
1157: 48 8b 44 24 f8 mov -0x8(%rsp),%rax
115c: 41 5e pop %r14
115e: 48 83 c0 01 add [=12=]x1,%rax
1162: c3 retq
1163: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
116a: 00 00 00
116d: 0f 1f 00 nopl (%rax)
这里我们可以看到r14,因为被篡改,被压入栈中,然后出栈恢复原来的值。 现在,重复 -fcall-used-r14 标志:
gcc -std=gnu99 -O3 -ggdb3 -fcall-used-r14 -Wall -Wextra -pedantic -o main.out main.c
objdump -d main.out
反汇编包含:
0000000000001150 <inc>:
1150: 48 89 7c 24 f8 mov %rdi,-0x8(%rsp)
1155: 48 8b 44 24 f8 mov -0x8(%rsp),%rax
115a: 48 83 c0 01 add [=14=]x1,%rax
115e: c3 retq
115f: 90 nop
没有 push/pop 发生。
现在,我已经修改了一些 LLVM 目标文件,编译了源代码,并将此功能添加(?)到 llc 工具中:
clang-11 -emit-llvm -S -c main.c -o main.ll
llc-11 main.ll -o main.s
现在,main.s
包含:
# %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
pushq %r14
.cfi_offset %r14, -24
movq %rdi, -16(%rbp)
#APP
#NO_APP
movq -16(%rbp), %rax
addq , %rax
popq %r14
popq %rbp
.cfi_def_cfa %rsp, 8
retq
显然,r14 仍然是 callee-saved。
在 llvm/lib/Target/X86/X86CallingConv.td
中,我修改了以下几行(删除了 R14),因为它们似乎与我感兴趣的 Linux 和 C 调用约定的 System V ABI 唯一相关:
def CSR_64 : CalleeSavedRegs<(add R12, R13, R15, RBP)>;
...
def CSR_64_MostRegs : CalleeSavedRegs<(add RBX, RCX, RDX, RSI, RDI, R8, R9, R10,
R11, R12, R13, R15, RBP,
...
def CSR_64_AllRegs_NoSSE : CalleeSavedRegs<(add RAX, RBX, RCX, RDX, RSI, RDI, R8, R9,
R10, R11, R12, R13, R15, RBP)>;
我的问题是:
X86CallingConv.td
是我应该修改的唯一文件吗?我想是的,但也许我错了。- 我关注的是正确的台词吗?也许这更难回答,但至少一个方向可能会有所帮助。
我是 运行 Debian 10.5 中的 LLVM 11。
编辑:
更改行,从“隐藏”定义中删除 R14:
def CSR_SysV64_RegCall_NoSSE : CalleeSavedRegs<(add RBX, RBP, RSP,
(sequence "R%u", 12, 13), R15)>;
正如玛格丽特正确指出的那样,也没有帮助。
原来,最小的修改是行:
def CSR_64 : CalleeSavedRegs<(add RBX, R12, R13, R15, RBP)>;
问题出在我构建源代码的方式上。
通过 运行 cmake --build .
再次在原始安装后, llc 工具没有被全局修改(我认为它会因为我正在构建默认架构 - X86 - 但这无关紧要)。所以,我调用了一个未修改的 llc-11 工具。因此,当我 运行:
/path/to/llvm-project/build/bin/lcc main.ll -o main.s
main.s
包含:
# %bb.0:
movq %rdi, -8(%rsp)
#APP
#NO_APP
movq -8(%rsp), %rax
addq , %rax
retq
这正是我想要的。