Search code examples
cgccarm

Undefined reference to _write, which is implemented in a library


I'm getting undefined reference to _write, required by a printf statement, in my embedded project. Using arm-none-eabi-gcc 9.3.1.

uart.c implements _write, as shown below:

int _write(int file, char* ptr, int len) __atribute__ ((used));
int _write(int file, char* ptr, int len)
{
   ...
}
void foo()
{
   nop();
}

uart.c is compiled into a static library, which is linked while compiling the executable.

Here is main.c:

int main()
{
   //foo();
   printf("Hello world!");
}

With foo(); commented out, I get undefined reference to '_write'. With foo(); uncommented, the project builds as expected. How can I get it to build without including a dummy function?

Build steps:

arm-none-eabi-gcc -c uart.c
ar rvs uart.a uart.o
arm-none-eabi-gcc main.c uart.a

Solution

  • The problem is that the standard library is linked after your library:

    arm-none-eabi-gcc -v main.c uart.a
    ...
    /usr/lib/gcc/arm-none-eabi/11.1.0/collect2 ....
            uart.a
            --start-group -lgcc -lc --end-group
            /usr/lib/gcc/arm-none-eabi/11.1.0/crtend.o /usr/lib/gcc/arm-none-eabi/11.1.0/crtn.o
    

    which makes sense, but then -lc can't find stuff from uart.a. You can:

    1. include -lc yourself first before uart.a
    2. or use --whole-archive and include uart.a.

    Tested with:

    // main.c
    #include <stdio.h>
    int main() {
        printf("Hello wolrd\n");
    }
    
    // uart.c
    #define nop()  __asm__("nop")
    void _exit(int a) { for(;;); }
    int _sbrk() { return -1; }
    int _close() { return -1; }
    int _read() { return -1; }
    int _fstat() { return -1; }
    int _isatty() { return -1; }
    int _lseek() { return -1; }
    
    int _write(int file, char* ptr, int len)
    {
       nop();
    }
    void foo()
    {
       nop();
    }
    
    // Makefile
    all:
        arm-none-eabi-gcc -c uart.c
        ar rvs uart.a uart.o
        arm-none-eabi-gcc main.c -lc uart.a
        arm-none-eabi-gcc main.c -Wl,--whole-archive uart.a -Wl,--no-whole-archive