NASM - The Netwide Assembler
NASM Forum => Programming with NASM => Topic started by: mmk213 on October 14, 2019, 11:52:23 AM
-
This is my minimal code example.
I am trying to basically print one string from array of strings.
And I think relocation destroys me here.
This is my example, sorry about formatting, I am typing this by hand:
global start
sys_exit equ 0x01
sys_write equ 0x04
stdout equ 0x01
%define sys syscall
section .text
start:
; ok lets print one message, it works of course
lea rdi, [rel message_one]
call print_c
; ok, now lets print message from array
; lets use rax as an index of array
mov rax, 0
shl rax, 3 ; pointers are 8 bytes long
lea rdi, [rel message_array]
add rdi, rax
mov rdi, [rdi]
call print_c
mov rax, sys_exit
sub rdi, rdi
sys
print_c:
push rax
push rcx
push rdx
push rdi
push rsi
push r11
cld
sub ecx, ecx
push rdi
dec rcx
sub eax, eax
repnz scasb
pop rsi
mov rdx, rcx
add al, sys_write
not rdx
sub edi, edi
dec rdx
inc edi
sys
pop r11
pop rsi
pop rdi
pop rdx
pop rcx
pop rax
ret
section .data
message_one:
db 'This is the first message.', 0x0a, 0x00
message_two:
db 'This is the second message.', 0x0a, 0x00
message_three:
db 'This is the third message.', 0x0a, 0x00
message_array:
dq message_one
dq message_two
dq message_three
section .note.openbsd.ident
align 2
dd 8, 4, 1
db 'OpenBSD', 0
dd 0
align 2
build
nasm -o example.o -f elf64 example.s
ld.bfd -e example -e start -static example.o
This segfaults of course, the wrong address is put in rdi at the end of second print example.
How to do this correctly? What am I missing?
Sorry about typos if there are some, I typed it by hand, but the example is simple enough.
Thanks.
-
oh, I should mention that this above example works of course in linux 64 bit no problem.
-
; ok, now lets print message from array
; lets use rax as an index of array
mov rax, 0
shl rax, 3 ; pointers are 8 bytes long
Surely you want 1 in rax. If that's not a "posto", it's your problem.
Best,
Frank
-
"Surely you want 1 in rax. If that's not a "posto", it's your problem."
oh dear god.
it is an example.
a minimal working example.
i put zero just to show that rax is an index to an array.
of course it is not a mistake.
that is not my problem. i already wrote what the problem is but reading is hard, i guess.
i know how to solve my problem - i can do some sort of "manual relocation" on that array so the code would work.
but i'm guessing there is a more straighforward way to do it via linker or something.
-
Nevermind. I'll do the manual thing so that it works.. thanks.
-
Just to illustrate what was my problem. It was this:
rax = 0000027574101000 rbx = 0000000000000000
rcx = 0000000000000000 rdx = 0000000000000000
rdi = 0000000000000000 rsi = 0000000000000000
rsp = 00007f7ffffd79a0 rbp = 0000000000000000
r8 = 000002757410101c r9 = 000000000020101c
r10 = 000002757410102e r11 = 000000000020102e
r12 = 000002757410103d r13 = 000000000020103d
r14 = 000002757410105d r15 = 000000000020105d
So in this regdump, r8 is address of message_one, which I obtained by:
lea r8, [rel message_one]
and r9 is the value of first quad in message_array:
message_array:
dq message_one
dq message_two
dq message_three
So, those two values are NOT the same.
But the same code (with different syscall numbers of course) on linux gives the "right" result: r8 and r9 are the same.
It is like that value of message_one in message_array did not get "relocated". I dont know.
I know how to manually solve it - but I think surely this is a linker problem or something.
-
Didn't test it with FreeBSD:
; test.asm
bits 64
default rel
%define NULL 0
section .rodata
msg1: db `Message1\n\0`
msg2: db `Message2\n\0`
msg3: db `Message3\n\0`
msgs: dq msg1, msg2, msg3, NULL
section .text
global _start
_start:
lea rbx,[msgs] ; RBX is preserved between syscalls (SysV ABI).
.loop:
mov rdi,[rbx] ; Get a pointer in msgs table.
test rdi,rdi ; If it is NULL...
jz .exit_loop ; ... exit loop.
call strlen ; Return the string length in RDX.
mov rsi,[rbx] ; Get the pointer again...
mov eax,1 ; write_syscall
mov edi,eax ; to STDOUT
syscall
add rbx,8 ; Next pointer in msgs table.
jmp .loop
.exit_loop:
xor edi,edi ; Return value is 0 (EXIT_SUCCESS).
mov eax,60 ; exit_syscall
syscall
; Obs: We won't use strings greater than 4 GiB, so it is safe to use EDX.
strlen:
xor edx,edx
.loop:
cmp byte [rdi+rdx],0
jz .exit_loop
add edx,1
jmp .loop
.exit_loop:
ret
# Makefile
test: test.o
ld -o $@ $^
test.o: test.asm
nasm -felf64 -o $@ $<