Reputation: 287
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!
Upvotes: 4
Views: 1133
Reputation: 47623
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:
extern "C" int add(int a, int b);
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:
global _add
segment .text
_add:
The other problem you have is in your Makefile
and the way you generate main.o
from main.cpp
.
main.o: main.cpp
g++ main.cpp -o main.o
This tells g++
to compile main.cpp
to an executable called main.o
. What you really want to do is tell g++
to skip the linking to an executable part, and that the output file main.o
will actually be an object. To do that change the line to be:
main.o: main.cpp
g++ -c main.cpp -o main.o
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 in hello.o
but the command g++ main.cpp -o main.o
doesn't know that.
Upvotes: 5