OpenBSD x64 Assembly
This past week I've been learning x86 assembly language on an old laptop, purely because I couldn't get anything running on my x64 OpenBSD machine. My 64 bit helloworld.s was as follows:
section .data
msg db "Hello world!", 10
len equ $-msg
;syscalls
%define SYS_exit 1
%define SYS_write 4
section .text
global _start
_start:
mov rax, SYS_write
mov rdi, 1 ;stdout
mov rsi, msg
mov rdx, len
syscall
mov rax, SYS_exit
xor rdi, rdi
syscall
Giving the errors:
jon@OpenBsD:~/dev/asm;$ nasm -f elf64 -o helloworld.o helloworld.s
jon@OpenBsD:~/dev/asm;$ ld -o helloworld helloworld.o
ld: warning: creating a DT_TEXTREL in a shared object.
jon@OpenBsD:~/dev/asm;$ yasm -f elf64 -o helloworld.o helloworld.s
jon@OpenBsD:~/dev/asm;$ ld -o helloworld helloworld.o
ld: helloworld.o: relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC
helloworld.o: could not read symbols: Bad value
I did search /usr/src for any assembly files I could straight up copy and test, but I didn't find anything suitable, however the code looks fine and as the assembler didn't throw out any errors I'm thinking this to be an issue with the linker.
Running ld with the verbose flag we are shown the options for available architectures:
jon@OpenBsD:~>$ ld -V
GNU ld version 2.17
Supported emulations:
elf_x86_64_obsd
elf_i386_obsd
elf_i386
But even specifying the architecture gives the same error, so I then searched for -fpic as the yasm compiled program error suggested and found in man 1 gcc the option -fpic/-fpie. I don't know much about position independent code but I found that the ld flag -nopie disables it.
jon@OpenBsD:~/dev/asm>$ nasm -f elf64 -o helloworld.o helloworld.s
jon@OpenBsD:~/dev/asm>$ ld -m elf_x86_64_obsd -o helloworld -nopie helloworld.o
jon@OpenBsD:~/dev/asm>$ ./helloworld
./helloworld[1]: ELF: not found
./helloworld[3]: no closing quote
Progress! After digging into this new error I found in man 5 elf "that OpenBSD native executables contain a .note.openbsd.ident section to identify themselves, for the kernel to bypass any compatibility ELF binary emulation tests when loading the file." Looking online for this note section I found multiple examples which where all the same so I copied that into my program:
section .note.openbsd.ident
align 2
dd 8, 4, 1
db 'OpenBSD',0
dd 0
align 2
section .data
msg db "Hello world!", 10
len equ $-msg
;syscalls
%define SYS_exit 1
%define SYS_write 4
section .text
global _start
_start:
mov rax, SYS_write
mov rdi, 1; stdout
mov rsi, msg
mov rdx, len
syscall
mov rax, SYS_exit
xor rdi, rdi
syscall
and compiled with:
jon@OpenBsD:~/dev/asm>$ nasm -f elf64 -o helloworld.o helloworld.s
jon@OpenBsD:~/dev/asm>$ ld -m elf_x86_64_obsd -o helloworld -nopie helloworld.o
jon@OpenBsD:~/dev/asm>$ ./helloworld
Hello world!
Success!
2020-07-03 Update
The default ld in OpenBSD has recently changed from GNU LD(ld(1)) to LLVM LD(ld.lld(1)), the above still works if you replace the ld command with ld.bfd.
Alternatively to make the change to ld.lld(1) you will need to upgrade to nasm-2.15 which is currently in ports and then run:
sed -i 's/.note.openbsd.ident/.note.openbsd.ident note/' helloworld.s
nasm -f elf64 -o helloworld.o helloworld.s
ld -m elf_x86_64 -o helloworld -no-pie helloworld.o
Also the notes alignment is automatically set to 4 bytes instead of 2 so the alignment no longer needs to be specified in nasm 2.15.
src.