Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 31 Jul 2017 22:36:24 +0200
From:      Polytropon <>
To:        Makketron <>
Subject:   Re: FreeBSD System Calls in Assembly
Message-ID:  <>
In-Reply-To: <>
References:  <>

Next in thread | Previous in thread | Raw E-Mail | Index | Archive | Help
On Mon, 31 Jul 2017 15:59:58 -0400, Makketron wrote:
> Hello,
> It seems that the  documentation here doesn't apply for 64-bits.

Yes, the URL states "x86", which usually means "32 bit" (or "i386"),
whereas "x86-64" indicates "64 bit" (or "amd64").

> I asked a question on stackoverflow. I thought I should ask it here too
> I am running FreeBSD 11.0.

And I therefore assume you're talking about 64 bit assembly here.

> global _start
> _start:
>     push dword hbytes
>     push dword hello
>     push dword 1   ; stdout
>     mov rax, 4    ; write syscall
>     call _syscall
>     add rsp, byte 24 ; restore stack
>     push word 0      ; return 0
>     mov rax, 1       ; exit call
>     call _syscall

If I remember correctly, you need to use the registers for the
parameters you want to pass to the system call. (My assembly
knwoledge is quite dusty, so check the documentation!)

> But this works:
> section .text
> hello db 'Hello, World!, 0Ah
> hbytes equ $-hello
> _syscall:
>     int 80h
>     ret
> global _start
> _start:
>     mov rdi, 1
>     mov rsi, hello  ; appears to be magic
>     mov rdx, hbytes ; appears to be magic
>     mov rax, 4    ; write syscall
>     call _syscall
>     push word 0      ; return 0
>     mov rax, 1       ; exit call
>     call _syscall
> This raises couple questions:
> 1) Why doesn't the first approach work?

The example program in "11.6. Our First Program" is a little bit
different: It uses and sys.write so you don't have to
manually code the syscall.

How (using which tools) do you assemble, link, and maybe brandelf?

> The UNIX calling convention is push data on the stack. Program does not
> crash. I just don't get any output, and the program terminates. I am
> compiling and linking fine.

Did you check with e. g. "truss <progname>" if the write syscall has
actually been executed? And if yes, with which parameters?

> 2) How are we supposed to know about what registers to load, and with what
> values?

You can see that from the documentation, for example regarding write,
you check "man 2 write" and see:

	ssize_t write(int d, const void *buf, size_t nbytes);

So the 1st parameter is an integer, the second a pointer, the third
a size_t integer. The registers to use are... let's see if I get it
right without further checking... AX is the syscall number, DI gets
the destination descriptor, SI gets the address of the source buffer,
DX gets the length of the buffer... I really hope this is right...
I'm not sure, it could also be that you use AX, BX, CX, DX... you
see I didn't do much assembly programming recently, especially not
on FreeBSD. ;-)

(NB: When I say "DI", I mean "edi" or "rdi" depending on architecture.)

FreeBSD does support this calling convention.

However, I think there is a difference between 32 bit and 64 bit.
Stack-based parameter lists are possible in 32 bit, but for 64 bit,
you have to use the registers. And you can use the 64 bit instruction
"syscall" instead of "int 80h".

> If I was pushing on the stack, it is easy. I look up the C functions and
> then I know how to push data.

Exactly. The order or parameters in the function prototype will
tell you in which order to push the parameters on the stack.

> In this case, it works like magic.

It's just the right registers on 64 bit. :-)

> 3) Where is the documentation for FreeBSD for similar system calls (not
> utilizing stack)??!

I think this is "11.3.2. Alternate Calling Convention":

In worst case, ask on the freebsd-hackers@ mailing list. :-)

Magdeburg, Germany
Happy FreeBSD user since 4.0
Andra moi ennepe, Mousa, ...

Want to link to this message? Use this URL: <>