首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过修改LLVM后端关闭X86寄存器

通过修改LLVM后端关闭X86寄存器
EN

Stack Overflow用户
提问于 2020-10-30 01:08:40
回答 1查看 242关注 0票数 2

我试图稍微修改一下X86目标的LLVM后端,以产生一些想要的行为。

更具体地说,我想模仿gcc的fcall 选项这样的标志,它指示编译器将一个调用保存的寄存器转换为一个失败的寄存器(这意味着它可能在函数调用期间被更改)。

让我们关注r14。我手动关闭寄存器,如在应答中:

代码语言:javascript
复制
#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);
}

编译和拆卸:

代码语言:javascript
复制
 gcc -std=gnu99 -O3 -ggdb3 -Wall -Wextra -pedantic -o main.out main.c
 objdump -d main.out

反汇编包括:

代码语言:javascript
复制
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    $0x1,%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 r14标志:

代码语言:javascript
复制
 gcc -std=gnu99 -O3 -ggdb3 -fcall-used-r14 -Wall -Wextra -pedantic -o main.out main.c
 objdump -d main.out

反汇编包括:

代码语言:javascript
复制
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    $0x1,%rax
    115e:       c3                      retq
    115f:       90                      nop

在没有推/弹的地方。

现在,我修改了一些LLVM目标文件,编译了源代码,并添加了(?)llc工具的这一功能:

代码语言:javascript
复制
clang-11 -emit-llvm -S -c main.c -o main.ll
llc-11 main.ll -o main.s

现在,main.s包含:

代码语言:javascript
复制
# %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    $1, %rax
        popq    %r14
        popq    %rbp
        .cfi_def_cfa %rsp, 8
        retq

很明显,r14还在被称为拯救者。

llvm/lib/Target/X86/X86CallingConv.td内部,我修改了以下行(删除R14),因为它们似乎是我感兴趣的系统V和C调用约定的唯一相关内容:

代码语言:javascript
复制
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是我应该修改的唯一文件吗?我想是的,但也许我错了。
  • 我的注意力集中在正确的线条上吗?也许这更难回答,但至少一个方向是有帮助的。

我正在Debian10.5中运行LLVM 11。

编辑:

更改行,从“隐藏”定义中删除R14:

代码语言:javascript
复制
def CSR_SysV64_RegCall_NoSSE : CalleeSavedRegs<(add RBX, RBP, RSP,
                                               (sequence "R%u", 12, 13), R15)>;

正如玛格丽特正确地指出的那样,这也没有帮助。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-10-30 15:35:29

事实证明,最低限度的修改是这样的:

代码语言:javascript
复制
def CSR_64 : CalleeSavedRegs<(add RBX, R12, R13, R15, RBP)>;

问题在于我是如何建立源头的。

通过在最初安装之后再次运行cmake --build .,llc工具没有进行全局修改(我认为它会被修改,因为我正在构建默认的体系结构-- X86 --但这与此无关)。所以,我打电话给一个未经修改的llc-11工具。因此,当我跑:

代码语言:javascript
复制
/path/to/llvm-project/build/bin/lcc main.ll -o main.s

main.s包含:

代码语言:javascript
复制
# %bb.0:
        movq    %rdi, -8(%rsp)
        #APP
        #NO_APP
        movq    -8(%rsp), %rax
        addq    $1, %rax
        retq

这是我一开始就想要的。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64601393

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档