Author Topic: how to print from array of strings? (openbsd)  (Read 181 times)

Offline mmk213

  • Jr. Member
  • *
  • Posts: 8
how to print from array of strings? (openbsd)
« 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:

Code: [Select]
  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
Code: [Select]
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.

Offline mmk213

  • Jr. Member
  • *
  • Posts: 8
Re: how to print from array of strings? (openbsd)
« Reply #1 on: October 14, 2019, 11:56:32 AM »
oh, I should mention that this above example works of course in linux 64 bit no problem.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2381
  • Country: us
Re: how to print from array of strings? (openbsd)
« Reply #2 on: October 14, 2019, 09:06:11 PM »
Code: [Select]
  ; 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


Offline mmk213

  • Jr. Member
  • *
  • Posts: 8
Re: how to print from array of strings? (openbsd)
« Reply #3 on: October 14, 2019, 09:16:17 PM »
"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.

Offline mmk213

  • Jr. Member
  • *
  • Posts: 8
Re: how to print from array of strings? (openbsd)
« Reply #4 on: October 14, 2019, 09:24:06 PM »
Nevermind. I'll do the manual thing so that it works.. thanks.
« Last Edit: October 14, 2019, 09:35:00 PM by mmk213 »

Offline mmk213

  • Jr. Member
  • *
  • Posts: 8
Re: how to print from array of strings? (openbsd)
« Reply #5 on: October 14, 2019, 09:44:33 PM »
Just to illustrate what was my problem. It was this:
Code: [Select]
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:
Code: [Select]
lea r8, [rel message_one]
and r9 is the value of first quad in message_array:
Code: [Select]
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.

Offline fredericopissarra

  • Jr. Member
  • *
  • Posts: 53
Re: how to print from array of strings? (openbsd)
« Reply #6 on: October 15, 2019, 12:41:02 AM »
Didn't test it with FreeBSD:
Code: [Select]
; 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

Code: [Select]
# Makefile

test: test.o
ld -o $@ $^

test.o: test.asm
nasm -felf64 -o $@ $<