2

I installed FreeBSD 13.0 on a Raspberry Pi 4B, and tried to assemble and link a "Hello World" assembly program on it. Assembler (as) and linker (ld) produced output files without any error messages, but when I tried to run the program, I got the following error message:

ELF binary type "0" not known. Exec format error. Binary file not executable.

I used the following commands to assemble and link,

as hello.asm -o hello.o
ld hello.o -o hello

and here is the source code of my "Hello World" program hello.asm:

.global _start
.align 4

_start:
    mov X0, #1
    adr X1, helloworld
    mov X2, #16
    mov X16, #4
    svc #0x80

    mov X0, #0
    mov X16, #1
    svc #0x80

helloworld:    .ascii "Hello Pi-World!\n"

My assembler and linker versions are:

as -v
GNU assembler version 2.37 (aarch64-portbld-freebsd13.0) using BFD version (GNU Binutils) 2.37

ld -v
LLD 11.0.1 (FreeBSD llvmorg-11.0.1-0-g43ff75f2c3fe-1300007) (compatible with GNU linkers)

and the file command gives

file hello
hello: ELF 64-bit LSB relocatable, ARM aarch64, version 1 (SYSV), not stripped

and my system details are

uname -a
FreeBSD BSD 13.0-RELEASE FreeBSD 13.0-RELEASE #0 releng/13.0-n244733-ea31abc261f: Fri Apr  9 06:06:55 UTC 2021     root@releng1.nyi.freebsd.org:/usr/obj/usr/src/arm64.aarch64/sys/GENERIC  arm64

Could anyone explain to me what the problem is, and how to fix it? Thanks.

EDIT: Posted a follow-up question on how to use system calls in FreeBSD on ARM64 architectures, see here.

  • 1
    Try `brandelf -t freebsd hello`. It is weird that this step is needed. – fuz Mar 06 '22 at 14:30
  • Now as for the code itself, `svc #0x80` is not how you do system calls on FreeBSD. And the syscall numbers and calling convention seem wrong, too. Where did you get this example code from? – fuz Mar 06 '22 at 14:33
  • 1
    You can avoid the `brandelf` command by assembling with `cc` instead. I.e. `cc -c hello.s`. – fuz Mar 06 '22 at 14:36
  • @fuz Thanks a lot for the quick reply! Both methods you suggested work (at least now the file is recognised as a binary, I still have to fix the registers to make it run properly). – Wolfgang Globke Mar 06 '22 at 15:34
  • @fuz This is an example I wrote myself for macOS, I wanted to see what it takes to make it run on FreeBSD. The syscalls numbers are from /usr/include/sys/syscall.h and appear to be the same as on macOS (not surprising, given that macOS uses BSD syscalls). I assumed using svc for syscalls was universal to ARM-based systems, can you tell me how this works on FreeBSD? – Wolfgang Globke Mar 06 '22 at 15:40
  • Syscall numbers differ between systems and so do calling conventions. I see that perhaps you meant for `x16` to hold the system call numbers in which case the numbers are indeed the same. However, I don't know the calling convention and it could be different. Also the `svc` instruction you have to use likely differs (hence the `SIGILL` when you execute this code). – fuz Mar 06 '22 at 16:09
  • @fuz Ok, thanks again. I found some slides online saying that for FreeBSD, X8 is the proper register to hold the syscall number (like on ARM64 Linux). I assumed the calling conventions were required by the ARM architecture (passing arguments in X0, X1, X2,..., argument for svc ignored). But it's really hard to find anything on FreeBSD ARM64 online. Btw if you summarise your reply(s) in an answer to this question, I can give you an upvote. I might post the question about the BSD ARM64 syscalls separately. – Wolfgang Globke Mar 06 '22 at 16:27
  • 1
    The ABI/calling convention is just a recommendation. FreeBSD follows it for user code but apparently not the system call interface. – fuz Mar 06 '22 at 17:18
  • [FreeBSD x86 Assembly Language Programming](https://docs.freebsd.org/en/books/developers-handbook/x86/) if you haven't seen it. – Rob Mar 06 '22 at 22:44
  • @Ron Thanks, but the system calls on x86 and ARM64 work quite differently, and I couldn't find a comparable document for ARM64. – Wolfgang Globke Mar 07 '22 at 06:52
  • Update on the syscall issue: One has to use `svc #0` in FreeBSD (on Linux ARM64 or macOS the number does not matter). Arguments are still passed in X0, X1, X2... and the syscall number goes into X8. – Wolfgang Globke Mar 07 '22 at 16:19

0 Answers0