我正在尝试使用clang/llvm作为ARM Cortex-M的交叉编译器。
根据LLVM的一些页面,我正在按照以下步骤构建工具链。
构建工具链以用于
"没让情况变得更好"
"但如果我使用通用的apt-gotten clang/llvm"
问题已经消失。
现在,在撰写本文的时候,构建的版本为 v10,而 apt-get 获取的版本为 v6(构建 v10 版本需要很长时间,二进制文件为什么这么大呢?)。
使用相同的命令行针对构建好的版本,ABI 问题没有任何变化。
现在,如果不进行优化,也许只是运气好罢了。
链接在SO上不好,所以:
“如何使用Clang/LLVM交叉编译Clang/LLVM”
这是页面的标题,它包含以下信息。
我最初使用了页面上提到的GNU三倍体,但后来发现LLVM有子架构,因此将其添加进去。一开始看起来一切都很好,直到我编写了一个超过几行的程序。
我是不是在错误地构建LLVM?还是这只是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的输出要好得多)
问题在于arms 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-get 获取的版本为 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”应该允许并行可构建的makefiles,但我在其中有一个问题。有一两个地方可以工作,一个地方不行,必须一遍又一遍地运行,或者最终串行运行。因此,最后的构建方式就是这样。
使用发布版本构建后,二进制文件明显较小,而不是数十GB,整个安装只有1.x GB。
我认为构建速度并没有更快。持续时间与1990年代构建gcc相当。