0

I need to write an assembler module with a function definition and link it with my program in C++ where is a declaration of the function implemented in assembly. I don't know how to write a C++ file and an Assembler module to properly compile it all.

I have written a C++ file

#include <iostream>
using namespace std;

void copy(unsigned int * source, unsigned int * dest, int n);

int main() {
    unsigned int source[] = {1, 2, 3, 4};
    unsigned int dest[4];
    copy(source, dest, 4);
    return 0;
}

Then I checkout the assembly name of that function by command:

g++ -masm=intel -S main.cpp -o file.asm

and I inserted the found result to the assembly module

segment .text
global _Z4copyPjS_i@PLT
_Z4copyPjS_i@PLT:
ret

I would like to compile cpp file with an assembly module (where will be an implementation for function copy) but I don't know how to do it? I tried:

nasm -felf64 -o copy.o copy.asm
g++ main.cpp -o main.o
g++ -o main copy.o main.o 

But during the second command, I get an error:

/usr/bin/ld: tmp/ccWFOX8p.o: in function 'main':
main.cpp:(.text+0x4b): undefined reference to 'copy(unsigned int*, unsigned int*, int)'
collect2: error: ld returned 1 exit status
Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
lapwingg
  • 112
  • 9
  • 6
    It would be better to declare the function as `extern "C"` in your C++ code. Then you won't have to deal with name mangling. – Paul Sanders Dec 05 '20 at 12:37
  • 1
    @Nesrine Hadj Khelil - please don't use `code formatting` for names of things like C++. Only for text you'd actually find in C++ source code, like "a `return` statement". Your edit should not have been approved; I assume you meant well but it's not actually an improvement. Quote instead of code-block for the error message is also not better. (It's not wrong, but not something that's worth changing in an edit, especially not if there's nothing else that needs fixing.) – Peter Cordes Dec 06 '20 at 02:06

3 Answers3

4

@PLT isn't part of the mangled asm symbol name. call symbol@plt means the call should be indirected through the PLT (Procedure Linking Table), in case the function is only defined in a shared library.

Your asm file should define _Z4copyPjS_i. (Or use extern "C" in the prototype if you don't need overloading or a member-function, then you can just define copy).


gcc -fPIE (which is the default on most current distros) calls through the PLT for functions that aren't defined in the current compilation unit, otherwise linking would fail if the functions is only defined in a shared library. But if the linker does find the symbol in another .o, it relaxes to just call copy directly, not going through a PLT stub. So you don't need to use __attribute__((visibility("hidden"))) to make function calls between parts of the same executable efficient. (https://gcc.gnu.org/wiki/Visibility).

https://godbolt.org/z/qrMK8P. If you omit -fPIE (or use -fno-pie explicitly), you'll see GCC emits just call _Z4copyPjS_i

If you compiled with gcc -fno-plt (https://godbolt.org/z/7s756d), "relaxing" call [QWORD PTR _Z4copyPjS_i@GOTPCREL[rip]] into call _Z4copyPjS_i still happens. But it would be 1 byte shorter, and at link time it's too late to change other offsets that don't have relocation info (like possible relative branches over the call). So the linker pads with a 67 address-size prefix, making it addr32 call rel32 if you check with objdump -drwC -Mintel after building gcc -fPIE -fno-plt foo.cpp asm.o or whatever.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
1
g++ main.cpp -o main.o

Compiles main.cpp and attempts to link it into an executable called main.o, but fails as no file containing an implementation of copy is provided. To just compile use the -c option:

g++ -c main.cpp -o main.o

You can compile and link in one command:

g++ -o main copy.o main.cpp
Timothy Baldwin
  • 3,551
  • 1
  • 14
  • 23
1

Thank you @Peter Cordes and @Timothy Baldwin!

To sum up: I should discard @PLT in the function name that g++ produces

I should compile with option -c

Function name is _Z4copyPjS_i To compile:

nasm -felf64 -o copy.o copy.asm
g++ -c main.cpp -o main.o
g++ -o main copy.o main.o
lapwingg
  • 112
  • 9
  • Or you could simplify the two `g++` commands into one, as Timothy showed: `g++ -o main copy.o main.cpp` will compile to a temporary `.o` and link that. That's part of the point of GCC's "front-end". But yes, you do want to avoid using an already-linked executable as an input to another linking command. For some reason it doesn't just error, I guess because gcc-created executables still have ELF section metadata, not just segments in the program header. – Peter Cordes Dec 06 '20 at 13:45