【问题标题】:clang/LLVM ARM ABI, non-volatile registers being destroyedclang/LLVM ARM ABI,非易失性寄存器被破坏
【发布时间】:2020-04-08 03:32:26
【问题描述】:

我正在尝试使用 clang/llvm 作为 ARM cortex-m 的交叉编译器。

基于一个/一些 LLVM 页面,这就是我构建工具链的方式

rm -rf /opt/llvm/llvm10armv6m
rm -rf llvm-project
git clone https://github.com/llvm/llvm-project.git
cd llvm-project
git checkout llvmorg-10.0.0
mkdir build
cd build
cmake -DLLVM_ENABLE_PROJECTS='clang;lld' -DCMAKE_CROSSCOMPILING=True -DCMAKE_INSTALL_PREFIX=/opt/llvm/llvm10armv6m -DLLVM_DEFAULT_TARGET_TRIPLE=armv6m-none-eabi -DLLVM_TARGET_ARCH=ARM -DLLVM_TARGETS_TO_BUILD=ARM -G "Unix Makefiles" ../llvm
make -j 8
make -j 4
make
sudo make install

test.c

void fun ( unsigned int, unsigned int );
int test ( void )
{
    unsigned int ra;
    unsigned int rx;

    for(rx=0;;rx++)
    {
        ra=rx;
        ra|=((~rx)&0xFF)<<16;
        fun(0x12345678,ra);
    }
    return(0);
}

clang -Wall -O2 -nostdlib -ffreestanding -fomit-frame-pointer -c test.c -o test.o
arm-none-eabi-objdump -D test.o


Disassembly of section .text:

00000000 <test>:
   0:   20ff        movs    r0, #255    ; 0xff
   2:   0405        lsls    r5, r0, #16
   4:   2600        movs    r6, #0
   6:   4c06        ldr r4, [pc, #24]   ; (20 <test+0x20>)
   8:   4637        mov r7, r6
   a:   4629        mov r1, r5
   c:   43b1        bics    r1, r6
   e:   4339        orrs    r1, r7
  10:   4620        mov r0, r4
  12:   f7ff fffe   bl  0 <fun>
  16:   2001        movs    r0, #1
  18:   0400        lsls    r0, r0, #16
  1a:   1836        adds    r6, r6, r0
  1c:   1c7f        adds    r7, r7, #1
  1e:   e7f4        b.n a <test+0xa>
  20:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

(gnu的输出要好很多)

这里的问题是 arm abi 说不要破坏 r4 及以上,当然不是像这里那样破坏 r4 和 r7,它也没有保留链接寄存器以从这个函数返回(虽然我猜它看到了这个是一个无限循环并且不会返回(请不要告诉我我又陷入了 llvm 无限循环错误)。

帧指针也好不到哪里去

00000000 <test>:
   0:   b580        push    {r7, lr}
   2:   af00        add r7, sp, #0
   4:   20ff        movs    r0, #255    ; 0xff
   6:   0405        lsls    r5, r0, #16
   8:   2400        movs    r4, #0
   a:   4626        mov r6, r4
   c:   4629        mov r1, r5
   e:   43a1        bics    r1, r4
  10:   4331        orrs    r1, r6
  12:   4804        ldr r0, [pc, #16]   ; (24 <test+0x24>)
  14:   f7ff fffe   bl  0 <fun>
  18:   2001        movs    r0, #1
  1a:   0400        lsls    r0, r0, #16
  1c:   1824        adds    r4, r4, r0
  1e:   1c76        adds    r6, r6, #1
  20:   e7f4        b.n c <test+0xc>
  22:   46c0        nop         ; (mov r8, r8)
  24:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

并为

构建工具链
armv6m-none-gnueabi

并没有变得更好

但如果我采用通用的 apt-gotten clang/llvm

clang -Wall -O2 -nostdlib -ffreestanding -fomit-frame-pointer -target armv6m-none-gnueabi -mthumb -mcpu=cortex-m0 -c test.c -o test.o
arm-none-eabi-objdump -D test.o

Disassembly of section .text:

00000000 <test>:
   0:   b5f0        push    {r4, r5, r6, r7, lr}
   2:   b081        sub sp, #4
   4:   20ff        movs    r0, #255    ; 0xff
   6:   0405        lsls    r5, r0, #16
   8:   2600        movs    r6, #0
   a:   4c06        ldr r4, [pc, #24]   ; (24 <test+0x24>)
   c:   4637        mov r7, r6
   e:   4629        mov r1, r5
  10:   43b1        bics    r1, r6
  12:   4339        orrs    r1, r7
  14:   4620        mov r0, r4
  16:   f7ff fffe   bl  0 <fun>
  1a:   2001        movs    r0, #1
  1c:   0400        lsls    r0, r0, #16
  1e:   1836        adds    r6, r6, r0
  20:   1c7f        adds    r7, r7, #1
  22:   e7f4        b.n e <test+0xe>
  24:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

问题消失了。

现在是的,在撰写本文时,已构建的版本是 v10,而 apt-gotten 的版本是 v6(构建 v10 版本,为什么要花很长时间才能构建?为什么二进制文件如此庞大?)

对内置的使用相同的命令行没有变化有abi问题。

现在如果我不优化也许只是运气不好:

00000000 <test>:
   0:   b580        push    {r7, lr}
   2:   b082        sub sp, #8
   4:   2000        movs    r0, #0
   6:   9000        str r0, [sp, #0]
   8:   e7ff        b.n a <test+0xa>
   a:   9800        ldr r0, [sp, #0]
   c:   9001        str r0, [sp, #4]
   e:   4668        mov r0, sp
  10:   7800        ldrb    r0, [r0, #0]
  12:   21ff        movs    r1, #255    ; 0xff
  14:   4048        eors    r0, r1
  16:   0400        lsls    r0, r0, #16
  18:   9901        ldr r1, [sp, #4]
  1a:   4301        orrs    r1, r0
  1c:   9101        str r1, [sp, #4]
  1e:   9901        ldr r1, [sp, #4]
  20:   4803        ldr r0, [pc, #12]   ; (30 <test+0x30>)
  22:   f7ff fffe   bl  0 <fun>
  26:   e7ff        b.n 28 <test+0x28>
  28:   9800        ldr r0, [sp, #0]
  2a:   1c40        adds    r0, r0, #1
  2c:   9000        str r0, [sp, #0]
  2e:   e7ec        b.n a <test+0xa>
  30:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

链接不擅长 SO,所以

如何使用 Clang/LLVM 交叉编译 Clang/LLVM

页面的标题是否包含这样的信息

The CMake options you need to add are:

-DCMAKE_CROSSCOMPILING=True
-DCMAKE_INSTALL_PREFIX=<install-dir>
-DLLVM_TABLEGEN=<path-to-host-bin>/llvm-tblgen
-DCLANG_TABLEGEN=<path-to-host-bin>/clang-tblgen
-DLLVM_DEFAULT_TARGET_TRIPLE=arm-linux-gnueabihf
-DLLVM_TARGET_ARCH=ARM
-DLLVM_TARGETS_TO_BUILD=ARM

我从页面提到的 gnu 三元组开始,但后来看到 llvm 具有子架构,因此添加了它,最初看起来一切都很好,直到我制作了一个包含几行以上的程序。

我是否错误地构建了 llvm?或者这只是 llvm 无限循环的事情? (或其他...)

编辑

更新的构建脚本:

export THEPLACE=/opt/llvm/llvm10armv6m
export THETARGET=armv6m-none-eabi

rm -rf $THEPLACE
rm -rf llvm-project
git clone https://github.com/llvm/llvm-project.git
cd llvm-project
git checkout llvmorg-10.0.0
mkdir build
cd build
cmake \
-DLLVM_ENABLE_PROJECTS='clang;lld' \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CROSSCOMPILING=True \
-DCMAKE_INSTALL_PREFIX=$THEPLACE \
-DLLVM_DEFAULT_TARGET_TRIPLE=$THETARGET \
-DLLVM_TARGET_ARCH=ARM \
-DLLVM_TARGETS_TO_BUILD=ARM \
-G "Unix Makefiles" \
../llvm

make -j 8
make -j 4
make
sudo make install

显然不需要 tbl-gen 的东西。从理论上讲,-G Unix Makefiles 应该允许并行构建的 makefile,但我确实有一个问题。一两个地方它工作了一个它没有,并且将不得不一次又一次地运行或最终连续运行。因此最终的品牌就是这样。

在发布版本中,二进制文件明显更小,而不是几十 GB,整个安装就像 1.somethingGB。

我不认为构建速度更快。仍然与 1990 年代构建 gcc 相提并论。

【问题讨论】:

    标签: optimization arm clang llvm abi


    【解决方案1】:

    答案很简单:你的函数永远不会返回。因此,保存/恢复被调用者保存的寄存器没有任何意义。

    如果您更改源以允许函数终止,如下所示:

    void fun ( unsigned int, unsigned int );
    unsigned bar();
    int test ( void )
    {
        unsigned int ra;
        unsigned int rx;
    
        for(rx=0;rx<bar();rx++)
        {
            ra=rx;
            ra|=((~rx)&0xFF)<<16;
            fun(0x12345678,ra);
        }
        return(0);
    }
    

    一切都将按您的预期保存/恢复。

    PS:我不会评论无限循环是否是UB

    PPS:您当然希望在发布模式下编译 llvm/clang - 二进制文件会更小,链接时间会大大减少。

    【讨论】:

    • DOH 太有趣了,多年来我都数不清了就检测到这一点并抱怨返回是无法访问的代码。谢谢,我可能会删除它,它是如此微不足道,我错过了...
    • 将尝试发布模式,谢谢,这是我要研究的东西
    • 还解释了为什么 llvm 二进制文件比 gnu 小
    • Unix Makefiles — 用于生成兼容 make 的并行 makefile .....嗯,我在一台机器上失败了。因此多次运行...
    • 有趣的是交叉编译确实推送了寄存器,所以也许这是一个不应该出现的问题。
    猜你喜欢
    • 2013-04-19
    • 2015-11-07
    • 1970-01-01
    • 2011-02-23
    • 2013-07-04
    • 2015-05-13
    • 2021-05-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多