Reputation: 112
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
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
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
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