lapwingg
lapwingg

Reputation: 112

How to write and compile c++ program which declares a function which has its definition in the assembly module?

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

Upvotes: 0

Views: 263

Answers (3)

lapwingg
lapwingg

Reputation: 112

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

Upvotes: 1

Timothy Baldwin
Timothy Baldwin

Reputation: 3675

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

Upvotes: 1

Peter Cordes
Peter Cordes

Reputation: 364458

@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.

Upvotes: 4

Related Questions