在Windows 10下,使用linaro
提供的交叉编译工具链,其全名gcc-linaro-7.2.1-2017.11-i686-mingw32_aarch64-elf
(可通过互联网搜索),编译以下代码段:
// file test.cpp
// ASM_DEFINE_LOCAL_SYM and ASM_DEFINE_GLOBAL_SYM defines assembler symbol,
// one is local and the other is global, as their name indicated
#define ASM_DEFINE_LOCAL_SYM(sym) __asm__ __volatile__(#sym ":\n\t")
#define ASM_DEFINE_GLOBAL_SYM(sym) __asm__ __volatile__(".global " #sym " \n\t;" #sym ":\n\t")
void testIfLocalSymWrongs()
{
kout << "func address = " <<reinterpret_cast<uint64_t>(testIfLocalSymWrongs) << "\n";
extern char local[];
extern char global[];
ASM_DEFINE_LOCAL_SYM(local);
ASM_DEFINE_GLOBAL_SYM(global);
kout << "local = " << reinterpret_cast<uint64_t>(local) << "\n";
kout << "global = " << reinterpret_cast<uint64_t>(global) << "\n";
}
代码不完整,因为我在裸机环境中测试迷你内核。在上面的代码中,kout
只是将字符写入串口(当使用raspberry pi 3
等硬件时)或者控制台(当使用QEMU
等模拟器时),但我认为它不需要完整。
无论如何,编译命令为aarch64-elf-g++ -fPIC test.cpp .... -o test
,并使用aarch64-elf-objcopy
生成kernel.test.img
,其中只包含二进制代码,其他数据如elf标头被剥离。
在QEMU上运行:qemu-system-aarch64 -machine virt,gic-version=3 -cpu cortex-a53 -smp 1 -m 1G -nographic -serial stdio -bios kernel.test.img
给出以下输出:
func address = 3c64
local = 3c64
global = 3cc0
但您可以看到func address
与local
相同,而local
与global
不同,这与我们的预期完全不同。
核心问题是当您使用-fPIC
进行编译时,本地符号和全局符号在它们应该相同时具有不同的值。
可能aarch64-elf-g++
生成了错误的.got
部分?但我不确定,有人能解释一下吗?
答案 0 :(得分:0)
一天后解决了这个问题,抱歉这么晚回答。
编译选项-fPIC
和-pie
之间的区别在于,当您使用后者替换前者时,程序将给出正确的(如预期的)输出。
因此,在使用aarch64-elf-g++
等交叉工具链进行编译时,要生成position independent code
,您更喜欢-pie
而不是-fPIC
。
请自行测试,如果可能,请回复此答案。