I'm trying to link a C++ file and an Assembly file. The Assembly file defines a C++ function called add
. I'm using a 64 bit Mac OS. I get the following error when I try to compile the program:
Undefined symbols for architecture x86_64:
"_add", referenced from:
_main in main-d71cab.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [main.o] Error 1
Makefile
hello: main.o hello.o
g++ main.o hello.o -o hello
hello.o: hello.asm
nasm -f macho64 hello.asm -o hello.o
main.o: main.cpp
g++ main.cpp -o main.o
hello.asm
global add
segment .text
add:
mov rax, rdi
add rax, rsi
ret
main.cpp
#include <iostream>
extern "C" int add(int a, int b);
int main(int argc, char* argv[]) {
int a, b;
std::cout << "Enter two numbers\n";
std::cin >> a;
std::cin >> b;
std::cout << "Sum of a and b is " << add(a, b) << std::endl;
return 0;
}
I'd really appreciate any help. Thanks!
On OS/X, the C calling convention is that functions must have an underscore on them (unless it is overridden) when exported from an object in order to be visible to C. You are saying that add is using C calling convention when you put
extern "C"
on this prototype:This is in fact correct, but in order for your assembler code to conform you also need to make sure your assembler functions that are going to be global and visible to C/C++ code have a leading underscore on them. Your assembler code would start like this:
The other problem you have is in your
Makefile
and the way you generatemain.o
frommain.cpp
.This tells
g++
to compilemain.cpp
to an executable calledmain.o
. What you really want to do is tellg++
to skip the linking to an executable part, and that the output filemain.o
will actually be an object. To do that change the line to be:The
-c
option says to skip the linking stage (that generates an executable and simply output an object that will be linked later).Without this change when it tries to make
main.o
, it thinks you want an executable, and can't find the function_add
because it is isn't in a file it knows about. It is inhello.o
but the commandg++ main.cpp -o main.o
doesn't know that.