我在Ubuntu(arm-linux-gnueabi-gcc)中有一个ARM交叉编译器,默认的架构是ARMv7。但是,我想编译一个ARMv5二进制文件。我这样做是通过给编译器-march=armv5te
选项。
到目前为止,这么好。由于我的ARM系统使用BusyBox,我必须编译静态链接的二进制文件。所以我给gcc -static
选项。
但是,我遇到了 libc.a 的问题,链接器链接到我的ARMv5二进制文件。此文件使用ARMv7体系结构选项进行编译。所以,即使我用ARMv5交叉编译我的ARM二进制文件,我也无法在基于BusyBox的ARMv5盒子上运行它。
提前谢谢。
答案 0 :(得分:1)
您有两个选择,
让编译器与您的系统匹配,始终最安全。这适用于x86 Linux和各种发行版。如果不同的编译器工作,你很幸运。交叉编译时更加困难,因为编译器不会自动同步。尝试在2014 Ubuntu系统上编译的1999 x86 Mandrake Linux上运行程序。
除了指令兼容性(已经确定)之外,还有ABI和OS依赖性。具体来说, armv7 很可能是 hardfloat (具有浮点FPU 和注册调用约定),你需要一个 softfloat (模拟FPU)。特定的 glibc (或 ucLibc )具有Linux操作系统的特定调用和期望。例如, threads 的工作方式随着时间的推移而发生了变化。
您始终可以使用-fno-builtin
和-ffreestanding
以及-static
。然后你不能使用任何 libc 函数,但你可以program them your self。
有外部来源,例如Mark Martinec's snprintf和像write()
这样易于实施的构建模块,
#define _SYS_IOCTL_H 1
#include <linux/unistd.h>
#include <linux/ioctl.h>
static inline int write(int fd, void *buf, int len)
{
int rval;
asm volatile ("mov r0, %1\n\t"
"mov r1, %2\n\t"
"mov r2, %3\n\t"
"mov r7, %4\n\t"
"swi #7\n\t"
"mov %0, r0\n\t"
: "=r" (rval)
: "r" (fd),
"r" (buf),
"r" (len),
"Ir" (__NR_write)
: "r0", "r1", "r2", "r7");
return rval;
}
static inline void exit(int status)
{
asm volatile ("mov r0, %0\n\t"
"mov r7, %1\n\t"
"swi #7\n\t"
: : "r" (status),
"Ir" (__NR_exit)
: "r0", "r7");
}
您必须添加自己的启动机器,由C&#39; C&#39;库,
/* Called from assembler startup. */
int main (int argc, char*argv[])
{
write(STDOUT, "Hello world\n", sizeof("Hello world\n"));
return 0;
}
/* Wrapper for main return code. */
void __attribute__ ((unused)) estart (int argc, char*argv[])
{
int rval = main(argc,argv);
exit(rval);
}
/* Setup arguments for estart [like main()]. */
void __attribute__ ((naked)) _start (void)
{
asm(" sub lr, lr, lr\n" /* Clear the link register. */
" ldr r0, [sp]\n" /* Get argc... */
" add r1, sp, #4\n" /* ... and argv ... */
" b estart\n" /* Let's go! */
);
}
如果这太令人生畏,因为您需要实现许多功能,那么您可以尝试获取各种库源并使用-fno-builtin
重建它们,并确保库不与Ubuntu链接库是不兼容的。
像crosstool-ng这样的项目可以让你构建一个正确适合 armv5 系统的正确编译器(可能有更高级的代码生成)。这可能看起来很痛苦,但上述替代方案也不容易。