How can I select a static library to be linked while ARM cross compiling?

You have two choices,

  1. Get the right compiler.
  2. Write your own ‘C’ Library.

Get the right compiler.

You are always safest to have a compiler match your system. This applies to x86 Linux and various distributions. You are lucky if different compilers work. It is more difficult when you cross-compile as often the compiler will not be automatically synced. Try to run a program on a 1999 x86 Mandrake Linux compiled on your 2014 Ubuntu system.

As well as instruction compatibility (which you have identified), there are ABI and OS dependencies. Specifically, the armv7 is most likely hardfloat (has floating point FPU and register call convention) and you need a softfloat (emulated FPU). The specific glibc (or ucLibc) has specific calls and expectations of the Linux OS. For instance, the way threads works has changed over time.

Write your own

You can always use -fno-builtin and -ffreestanding as well as -static. Then you can not use any libc functions, but you can program them your self.

There are external source, like Mark Martinec’s snprintf and building blocks like write() which is easy to implement,

#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    #0\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    #0\n\t"
                : : "r" (status),
                  "Ir" (__NR_exit)
                : "r0", "r7");
}

You have to add your own start-up machinery taken care of by the ‘C’ library,

/* 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! */
        );
}

If this is too daunting, because you need to implement a lot of functionality, then you can try and get various library source and rebuild them with -fno-builtin and make sure that the libraries do not get linked with the Ubuntu libraries, which are incompatible.

Projects like crosstool-ng can allow you to build a correct compiler (maybe with more advanced code generation) that suits the armv5 system exactly. This may seem like a pain, but the alternatives above aren’t easy either.

Leave a Comment