linking functions in shared object - ld - linux

I'm trying to write a library (shared object) in assembly. I'm compiling with nasm and linking with ld. I've got 2 ASM files containing differents symbols. I'm trying to call a symbol contained in the first file from the second one, but ld keep throwing an error : relocation R_X86_64_PC32 against symbol 'strchr' can not be used when making a shared object; recompile with -fPIC.
The first file contains :
BITS 64
section .text
global strchr
strchr:
push rbp
mov rbp, rsp
xor rax, rax
looper:
cmp sil, byte [rdi]
je saveptr
cmp byte [rdi], 0x0
je endloop
inc rdi
jmp looper
saveptr:
mov rax, rdi
endloop:
mov rsp, rbp
pop rbp
ret
The second file contains :
BITS 64
section .text
extern strchr
global strspn
strspn:
push rbp
mov rbp, rsp
xor rax, rax
xor r11, r11
mov rax, rdi
looper:
cmp byte [rsi], 0x0
je endloop
push rax
mov sil, byte [rsi]
call strchr
cmp rax, 0x0
jne increase
inc rsi
mov rax, rdi
jmp looper
increase:
inc r11
inc rax
jmp looper
endloop:
mov rax, r11
mov rsp, rbp
pop rbp
ret
I'm compiling the library through this process:
nasm -f elf64 first_file.asm -o first_file.o
nasm -f elf64 second_file.asm -o second_file.o
ld -shared first_file.o second_file.o -o mylib.so
How can I link the first (compiled) ASM file so that I can call the symbol from the second one ?

Related

dlsym crash when called from assembler

I have a small program in assembler that loads an .so file using dlopen, and then tries to load a function pointer using dlsym. Calling dlopen seems to be fine but it crashes when I call dlsym.
SECTION .text
;default rel
EXTERN dlopen ; loads a dynamic library
EXTERN dlsym ; retrieves the address for a symbol in the dynamic library
; inputs:
; rdi: rdi the pointer to print
printHex:
sub rsp, 19 ; allocate space for the string 0x0123456789ABCDEF\n
mov BYTE [rsp + 0], '0'
mov BYTE [rsp + 1], 'x'
xor rcx, rcx ; int loop variable to 0
.LOOP1:
lea rsi, [rsp + rcx] ; rsi will we the offset where we will store the next hex charcter
mov rax, rdi
and rax, 0xf
sar rdi, 4 ; shift right 4 bits (divide by 16)
lea rdx, [hexLookUp + rax]
mov bl, [rdx]
mov BYTE [rsi +18], bl
dec rcx ; rcx--
cmp rcx, -16 ; while rcx > -16
jne .LOOP1
mov BYTE [rsp + 18], 10
; print
mov rax, 1 ; syscall: write
mov rdi, 1 ; stdout
mov rsi, rsp
mov rdx, 19
syscall
; release stack memory
add rsp, 19
ret
global _start ; "global" means that the symbol can be accessed in other modules. In order to refer to a global symbol from another module, you must use the "extern" keyboard
_start:
; load the library
mov rdi, str_libX11so
mov rsi, 2; RTLD_NOW=2
call dlopen wrt ..plt
; PLT stands for Procedure Linkage Table:
; used to call external library functions whose address is not know at link time,
; so it must be resolved by the dynamic linker at run time
; more info: https://reverseengineering.stackexchange.com/questions/1992/what-is-plt-got
mov [ptr_libX11so], rax ; the previous function call returned the value in rax
mov rdi, rax
call printHex
; load the function
mov rdi, [str_libX11so]
mov rsi, fstr_XOpenDisplay
call dlsym wrt ..plt
mov [fptr_XOpenDisplay], rax
mov rdi, rax
call printHex
mov rax, 60 ; syscal: exit
mov rdi, 0 ; return code
syscall
hexLookUp: db "0123456789ABCDEF"
str_libX11so: db "libX11.so", 0
; X11 function names
fstr_XOpenDisplay: db "XOpenDisplay", 0
SECTION .data
ptr_libX11so: dq 0 ; ptr to the X11 library
; X11 function ptrs
fptr_XOpenDisplay: dq 0
I have tried to make the same program in C and it seems to work. So I must be doing something wrong.
extern void* dlopen(const char* name, int);
extern void* dlsym(void* restrict handle, const char* restrict name);
int main()
{
void* libX11so = dlopen("libX11.so", 2);
void (*XOpenDisplay)() = dlsym(libX11so, "XOpenDisplay");
}
I tried to disassemble the C version and compare, but I can't still figure out what is the problem.
An interesting thing I noticed is that the pointer returned by dlopen (which is different in each execution), in the asm version is quite small compared to the C version (e.g 0x0000000001A932D vs 0x5555555592d0). But maybe that could be because I'm using the -no-pie flag for linking:
nasm -f elf64 -g -F dwarf minimal.asm && gcc -nostartfiles -no-pie minimal.o -ldl -o minimal && ./minimal
I just noticed my mistake:
; load the function
mov rdi, [str_libX11so]
should be:
; load the function
mov rdi, [ptr_libX11so]

How to compile shared file with .bss section using nasm

I am trying to compile shared file from nasm I am using these commands:
nasm -f elf64 -o asm/asm.o asm/asm.asm
ld -shared -o asm/asm.so asm/asm.o -I/lib64/ld-linux-x86-64.so.2
after second one i got an error:
ld: asm/asm.o: relocation R_X86_64_32S against `.bss' can not be used when making a shared object; recompile with -fPIC
ld: final link failed: Nonrepresentable section on output
I cant use nasm -fPIC instead -f elf64 because it's invalid command. What should I do if I need .bss section maybe I can compile it in different way?
Here is my assembly code:
DEFAULT rel
%include "asm/python.inc"
GLOBAL PyInit_asm:function
SECTION .rodata
l_dubois_name db "dubois", 0
l_module_name db "asm", 0
SECTION .bss
digitSpace resb 100
digitSpacePos resb 8
SECTION .data
l_asm_methods:
ISTRUC PyMethodDef
at PyMethodDef.ml_name , dq l_dubois_name
at PyMethodDef.ml_meth , dq asm_dubois
at PyMethodDef.ml_flags , dq METH_NOARGS
at PyMethodDef.ml_doc , dq l_sayit_doc
IEND
NullMethodDef
l_asm_module: ;; struct PyModuleDef *
ISTRUC PyModuleDef
at PyModuleDef.m_base , PyModuleDef_HEAD_INIT
at PyModuleDef.m_name , dq l_module_name
at PyModuleDef.m_doc , dq NULL
at PyModuleDef.m_size , dq -1
at PyModuleDef.m_methods , dq l_asm_methods
at PyModuleDef.m_slots , dq NULL
at PyModuleDef.m_traverse , dq NULL
at PyModuleDef.m_clear , dq 0
at PyModuleDef.m_free , dq NULL
IEND
SECTION .text
asm_dubois:
push rbp
mov rbp, rsp
mov rax, [rbp+62]
mov rsp, rbp
pop rbp
call _printRAX
mov rax, 60
mov rdi, 0
syscall
ret
_printRAX:
mov rcx, digitSpace
mov rbx, 10
mov [rcx], rbx
inc rcx
mov [digitSpacePos], rcx
_printRAXLoop:
mov rdx, 0
mov rbx, 10
div rbx
push rax
add rdx, 48
mov rcx, [digitSpacePos]
mov [rcx], dl
inc rcx
mov [digitSpacePos], rcx
pop rax
cmp rax, 0
jne _printRAXLoop
_printRAXLoop2:
mov rcx, [digitSpacePos]
mov rax, 1
mov rdi, 1
mov rsi, rcx
mov rdx, 1
syscall
mov rcx, [digitSpacePos]
dec rcx
mov [digitSpacePos], rcx
cmp rcx, digitSpace
jge _printRAXLoop2
ret
Some random text for stackOverflow to accept mine code
The recompile with -fPIC error message is assuming that the asm / object file was created by a compiler. With hand-written asm you are the compiler and have to write position-independent code. (Or at least code that inefficiently uses 64-bit absolute addresses like your mov rcx, digitSpace; runtime fixups are supported for those relocations on GNU/Linux.)
Use lea r8, [digitSpace] (or any convenient reg, preferably outside the loop) and compare against that.
cmp rcx, digitSpace uses a static address as a 32-bit immediate sign-extended to 64-bit. This will require a R_X86_64_32S relocation: 64-bit address encoded as a 32-bit signed value. (Same as you'd get for [digitSpace + rdx] for example, that's another thing you can't do in PIC/PIE code)
Only mov allows a 64-bit immediate (which NASM uses by default when you write mov r64, symbol). Of course it would be better to use a RIP-relative LEA like lea rcx, [digitSpace]. You used default rel so that will be RIP-relative).
Almost exact duplicate of Assembler Error: Mach-O 64 bit does not support absolute 32 bit addresses (MacOS never allows using symbol addresses as 32-bit immediates so it's an assemble-time error, vs. on Linux only an error when you try to link into an ELF shared object instead of a non-PIE executable.)
Also related:
How to load address of function or label into register in GNU Assembler - RIP-relative LEA is the best if you can't use mov r32, imm32
Mach-O 64-bit format does not support 32-bit absolute addresses. NASM Accessing Array various general stuff about using symbol addresses when disp32 and imm32 aren't allowed.
32-bit absolute addresses no longer allowed in x86-64 Linux? - Linux PIE executables have the same restrictions as shared objects.

Get end of data segment in assembly in Linux

I am trying to build a malloc function in assembly. My plan is to use the brk syscall, however in order to do this, I need to be able to know where the end of the current segment is. In c I could use sbrk(0) however this isn't available in assembly. Is there anyway to get the end of the data segment, aside from just putting a label at the bottom.
I am using Ubuntu, nasm, and ld if it helps.
I am assembling and linking with:
nasm -f elf64 mem.s -o mem.o
ld -m elf_x86_64 -o mem mem.o -e _start
mem.asm
global _start
%include "stdasm.s"
section .text
_start:
mov rax, 1
mov rbx, str
call print
mov rax, 0x0123456789ABCDEF
call regPrint
mov rax, end
call regPrint
mov rax, _end
call regPrint
call exit
section .data
str: db 'Hello, world!',0x0A,0
end:
stdasm.s
section .text
exit:
mov rax, 1
mov rbx, 0
int 0x80
print:;rax = fd, rbx = string
push rdx
push rcx
mov rcx, rbx
mov rbx, rax
.loop:
cmp byte [rcx], 0
je .exit
mov rdx, 1
mov rax, 4
int 0x80
inc rcx
jmp .loop
.exit:
pop rcx
pop rdx
ret
regPrint:
push rbx
push rcx
push rdx
xor rcx, rcx
mov rbx, regPrintBuf
.loop:
rol rax, 4
mov dl, al
and rdx, 0x0F
add rdx, hexStr
mov dl, byte [rdx]
mov byte [rbx], dl
inc rcx
inc rbx
cmp rcx, 16
jl .loop
mov rbx, regPrintBuf
mov rax, 1
call print
pop rdx
pop rcx
pop rbx
ret
section .data
hexStr: db '0123456789ABCDEF'
regPrintBuf: db '0000000000000000', 0x0A,0
The linker creates the symbol _end pointing to the end of the data segment at link time. You can use this symbol to find the end of the data segment.
The area allocated by brk is not continuous with the data segment of the executable unless address space layout randomisation is disabled.
To find the current end of this area call brk with an argument of 0. At program start the size is zero so the end address is the same as the start address.

Search for and replace characters in a string in assembly nasm issues

I've got this working to where it copies a string into another. I'm trying to make it search for a term and swap it. For some reason, if the replace function isn't commented, it somehow manages to delete the output in the console (literally goes backwards!). If I comment the replace function out, I just get an exact copy. Trying to change cat to dog.
bits 64
global main
extern printf
section .text
main:
; function setup
push rbp
mov rbp, rsp
sub rsp, 32
;
lea rdi, [rel message]
mov al, 0
call printf
;print source message
lea rdi, [rel source]
mov al, 0
call printf
;print target message
lea rdi, [rel target]
mov al, 0
call printf
lea rdi, [rel target]
lea rsi, [rel source]
cld
jmp Loop
Loop:
lodsb ;Load byte at address RSI into AL
stosb ;Store AL at address RDI
;push [rdi]
cmp byte RDI, 'c'
je replace
;pop [rdi]
test al,al ;code will jump only if al is not equ 0
jnz Loop
replace:
;lea rdi, [rel success]
mov byte [rdi], 'd'
;call printf
ret
;print new version of target
lea rdi, [rel target]
mov al, 0
call printf
; function return
mov eax, 0
add rsp, 32
pop rbp
ret
section .data
message: db 'Project:',0x0D,0x0a,'Author:',0x0D,0x0a,0x0D,0x0a,0
source: db "The cat chased the bird.",0x0a,0x0D,0
target: db '0000000000000000000000000000000000000000000',0x0D,0x0a,0
success: db "Success",0
This is what you want. I tested it in Ubuntu 64 with:
(assumed this file is a.asm)
nasm -f elf64 -l a.lst a.asm &
gcc -m64 -o a a.o
bits 64
global main
extern printf
section .text
main:
; function setup
push rbp
mov rbp, rsp
sub rsp, 32
;
lea rdi, [rel message]
mov al, 0
call printf
;print source message
lea rdi, [rel source]
mov al, 0
call printf
;print target message
lea rdi, [rel target]
mov al, 0
call printf
lea rdi, [rel target]
lea rsi, [rel source]
cld
Loop:
lodsb ;Load byte at address RSI into AL
stosb ;Store AL at address RDI
cmp al, 'c'
jne LoopBack
lodsb ;Load byte at address RSI into AL
stosb ;Store AL at address RDI
cmp al, 'a'
jne LoopBack
lodsb ;Load byte at address RSI into AL
stosb ;Store AL at address RDI
cmp al, 't'
jne LoopBack
sub rdi, 3
mov byte [rdi], 'd'
inc rdi
mov byte [rdi], 'o'
inc rdi
mov byte [rdi], 'g'
inc rdi
LoopBack:
cmp al, 0
jne Loop
;print new version of target
lea rdi, [rel target]
mov al, 0
call printf
; function return
mov eax, 0
add rsp, 32
pop rbp
ret
section .data
message: db 'Project:',0x0D,0x0a,'Author:',0x0D,0x0a,0x0D,0x0a,0
source: db "The cat chased the bird.",0x0a,0x0D,0
target: db '0000000000000000000000000000000000000000000',0x0D,0x0a,0
success: db "Success",0
The output is this:
Project:
Author:
The cat chased the bird.
0000000000000000000000000000000000000000000
The dog chased the bird.

Uncorrect work equal assembly code (x86_64 linux)

I'm trying to write a simple compiler. My language can calculate an arithmetic expression using float numbers, save a variable and print a variable. In the first version of my compiler all my calculations only using a push and pop. Then I make calculate with call absolute stack address. I have not allocated memory with sub rsp, but rather I used [rsp-8*x], where x is number of value on the stack, like a push and pop. But the issue is that it does not work with pow function from libc. I can't understand, what I'm doing wrong.
I refactored the code a bit, for your convenience.
My first version in assembly (nasm syntax):
[bits 64]
global _start
extern printf
extern pow
section .data
printf_format db '%lf', 10, 0
section .text
_start:
mov rbp, rsp
sub rsp, 0x20
mov rax, 0x4000000000000000
push rax
mov rax, 0x4000000000000000
push rax
mov rax, 0x4008000000000000
push rax
movsd xmm0, qword [rsp+8]
movsd xmm1, qword [rsp]
call pow
movsd qword [rsp+8], xmm0
add rsp, 8
movsd xmm0, qword [rsp+8]
movsd xmm1, qword [rsp]
call pow
mov rdi, printf_format
mov rax, 1
call printf
mov rax, 60
mov rdi, 0
syscall
My second version:
[bits 64]
global _start
extern printf
extern pow
section .data
printf_format db '%lf', 10, 0
section .text
_start:
mov rbp, rsp
sub rsp, 0x20
mov rax, 0x4000000000000000
mov qword [rsp-8*1], rax
mov rax, 0x4000000000000000
mov qword [rsp-8*2], rax
mov rax, 0x4008000000000000
mov qword [rsp-8*3], rax
movsd xmm0, qword [rsp-8*2]
movsd xmm1, qword [rsp-8*3]
call pow
movsd qword [rsp-8*2], xmm0
movsd xmm0, qword [rsp-8*1]
movsd xmm1, qword [rsp-8*2]
call pow
mov rdi, printf_format
mov rax, 1
call printf
mov rax, 60
mov rdi, 0
syscall
I compile and link this with:
nasm -f elf64 ex.asm
ld -lc -lm -m elf_x86_64 -I/lib/ld-linux-x86-64.so.2 ex.o -o ex
In the last version of my compiler, I wrote the call with [rsp+8*x] and allocated with sub rsp, and the problem was solved.
My question is: Why that change I made solved this problem?

Resources