GCC linking / symbol name mangling with C++ and as

2020-04-21 05:55发布

问题:

I'm having some trouble compiling and linking a library that's written in assembler with my program code which is in C++. In my case it's for an AVR microcontroller using the avr-gcc suite, but I imagine this problem would apply to GCC generally.

I can get .o files built from the C++ source and assembly, but linking them gives the error:

> avr-gcc -mmcu=attiny84 -lm -o obj\AvrTest.elf obj\Main.o obj\i2cmaster.o
obj\Main.o: In function `main':
Main.cpp:(.text+0x0): undefined reference to `i2c_init()'

Here's the uber-simple Main.cpp code:

#include "i2cmaster.h"
void main() { 
    i2c_init();
    while ( true ) {
    }
}

i2cmaster.h defines the function prototype like this:

extern void i2c_init(void);

And in the assembler file, i2cmaster.S, that function is:

.global i2c_init
.func i2c_init
i2c_init:
cbi SDA_DDR,SDA     ;release SDA
cbi SCL_DDR,SCL     ;release SCL
cbi SDA_OUT,SDA
cbi SCL_OUT,SCL
ret
.endfunc

The linking would seem like a no-brainer - but I get that reference error. I noticed the assembler code generated for Main.cpp comes out like this:

.global main
.type   main, @function
main:
rcall _Z8i2c_initv
.L2:
rjmp .L2
.size   main, .-main

I suspect the problem is that i2c_init is becoming _Z8i2c_initv through some name mangling process I don't understand, and that _Z8i2c_initv can no longer be matched with the non-mangled i2c_init symbol in the i2cmaster.o object file.

Does anyone understand the mangling process, and how to suppress it during compilation/assembly so that these modules can talk to each other? Or anything else I might be doing wrong?

回答1:

OK, solved it. Apparently the symbol mangling is a C++ thing, and the i2c library isn't set up to work with C++ correctly. Was able to fix it by using the following:

extern "C" {
    #include "i2cmaster.h"
};
void main() { 
    i2c_init();
    while ( true ) {
    }
}