How to solve this linker error I get when trying t

2020-04-08 14:18发布

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!

1条回答
Emotional °昔
2楼-- · 2020-04-08 14:44

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.

查看更多
登录 后发表回答