clang/LLVM ARM ABI,non-volatile 寄存器被销毁
clang/LLVM ARM ABI, non-volatile registers being destroyed
我正在尝试使用 clang/llvm 作为 ARM cortex-m 的交叉编译器。
基于 an/some 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,而且它没有为 return 保留 link 寄存器来自这个函数(虽然我猜它认为这是一个无限循环而不是 return(请不要告诉我我又陷入了 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,所以
How To Cross-Compile Clang/LLVM using 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,但我确实有一个问题。一两个地方它起作用了,一个地方不起作用,并且必须一次又一次地 运行 或最终串行。因此最终的结果就是这样。
对于 Release 版本,二进制文件明显更小而不是数十 GB,对于整个安装来说就像 1.somethingGB。
我不认为构建速度更快。持续时间仍然与 1990 年代构建 gcc 相当。
答案很简单:您的函数从不 returns。因此,保存/恢复被调用者保存的寄存器没有任何意义。
如果您更改源代码以允许函数终止,如下所示:
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:您当然希望在 Release 模式下编译 llvm/clang – 二进制文件会更小并且链接时间会显着减少。
我正在尝试使用 clang/llvm 作为 ARM cortex-m 的交叉编译器。
基于 an/some 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,而且它没有为 return 保留 link 寄存器来自这个函数(虽然我猜它认为这是一个无限循环而不是 return(请不要告诉我我又陷入了 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,所以
How To Cross-Compile Clang/LLVM using 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,但我确实有一个问题。一两个地方它起作用了,一个地方不起作用,并且必须一次又一次地 运行 或最终串行。因此最终的结果就是这样。
对于 Release 版本,二进制文件明显更小而不是数十 GB,对于整个安装来说就像 1.somethingGB。
我不认为构建速度更快。持续时间仍然与 1990 年代构建 gcc 相当。
答案很简单:您的函数从不 returns。因此,保存/恢复被调用者保存的寄存器没有任何意义。
如果您更改源代码以允许函数终止,如下所示:
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:您当然希望在 Release 模式下编译 llvm/clang – 二进制文件会更小并且链接时间会显着减少。