# i386 assembly example does not work



## user0 (Apr 16, 2016)

Took a sample program from https://www.freebsd.org/doc/en_US.ISO8859-1/books/developers-handbook/x86-first-program.html and put the code into these files.

This into hello.asm:

```
%include   'system.inc'
section   .data
hello   db   'Hello, World!', 0Ah
hbytes   equ   $-hello

section   .text
global   _start
_start:
push   dword hbytes
push   dword hello
push   dword stdout
sys.write

push   dword 0
sys.exit
```
And this into system.inc

```
%define   stdin   0
%define   stdout   1
%define   stderr   2
%define   SYS_nosys   0
%define   SYS_exit   1
%define   SYS_fork   2
%define   SYS_read   3
%define   SYS_write   4
section   .text
align 4
access.the.bsd.kernel:
   int   80h
   ret
%macro   system   1
   mov   eax, %1
   call   access.the.bsd.kernel
%endmacro
%macro   sys.exit   0
   system   SYS_exit
%endmacro

%macro   sys.fork   0
   system   SYS_fork
%endmacro

%macro   sys.read   0
   system   SYS_read
%endmacro

%macro   sys.write   0
   system   SYS_write
%endmacro
```
Compiled (changing format to elf64 as that would match the system's architecture):

```
% nasm -f elf64 hello.asm
% ld -s -o hello hello.o
```
That does not print Hello World. What am I doing wrong?


----------



## zirias@ (Apr 16, 2016)

I assume syscalls on amd64 don't use `int 80h` but the `syscall` instruction


----------



## tobik@ (Apr 16, 2016)

user0 said:


> What am I doing wrong?


The example is for x86 only. Compile it like this:

```
% nasm -f elf hello.asm
% ld -m elf_i386_fbsd -s -o hello hello.o
```
Or use `syscall` as Zirias suggested. Also see the following links:

https://thebrownnotebook.wordpress.com/2009/10/27/native-64-bit-hello-world-with-nasm-on-freebsd/
https://github.com/EhevuTov/asm-fbsd64-hello-world


----------



## zirias@ (Apr 16, 2016)

nitpick: "compile" is not the correct wording here  It's assembly language and a key property of assembly is that it *isn't* platform-independent like e.g. C. That's the nature of it, with assembly, you literally write down what the CPU should execute (well, with the help of mnemonics instead of the binary codes, but that's just syntactic sugar). I wrote my earlier reply on the phone, just wanted to make sure this wasn't overlooked. Thanks tobik for elaborating on it and giving a helpful answer!

On a side note, this thread should be in "userland scripting & programming".


----------



## kpa (Apr 17, 2016)

To expand what is said above, the assembler never does any optimization on the code it's given. It literally takes a sequence of assembly language instructions and turns that sequence into executable code in 1:1 correspondence with the assembly language mnemonics and the machine instructions. It is really 1:1 mapping because you can use a disassembler on the executable object and you will get back the original assembly language program minus the macros that were used.


----------



## user0 (Apr 17, 2016)

Zirias said:


> I assume syscalls on amd64 don't use `int 80h` but the `syscall` instruction


Where is that documented?
I could only find this so far https://www.freebsd.org/doc/en_US.ISO8859-1/books/developers-handbook/x86-first-program.html


----------



## zirias@ (Apr 17, 2016)

user0 said:


> Where is that documented?
> I could only find this so far https://www.freebsd.org/doc/en_US.ISO8859-1/books/developers-handbook/x86-first-program.html


Well this only describes x86 -- amd64 is missing. But a very reliable "documentation" is always having a look in the source  See the KERNCALL macro here for how libc issues a syscall on FreeBSD amd64 -- as opposed to the i386 version using `int 80h`.

In fact, as amd64 provides a dedicated `syscall` instruction, it would be silly for an OS not to use it.


----------



## Juha Nurmela (Apr 18, 2016)

It used to be LCALL on i386, long time ago. Anyone remember why this was changed?

Juha


----------



## zirias@ (Apr 18, 2016)

Are you sure? I thought `lcall` was for protected mode / segmented addressing only? Anyhow, you need an instruction that enters ring-0


----------



## Juha Nurmela (Apr 18, 2016)

The descriptors were set so that lcall 7 did all the right things. It's still visible in the i386 link you gave, wouldn't have remembered otherwise.

Juha


----------



## asteriskRoss (Apr 18, 2016)

I love programming in assembler though it's often difficult to justify the additional time it needs over a compiled language and the lack of portability.

As a chatty introduction to assembly language I enjoyed Assembly Language Step-by-Step: Programming with Linux (ISBN 978-0-470-49702-9). It really is only an introduction to i386 assembly so don't expect to be selling yourself as a seasoned professional after you finish it.  Ignore that it uses GNU/Linux and the i386 instruction set as a teaching base rather than FreeBSD and amd64 -- it doesn't matter.  Once you understand the concepts you can start ploughing into more terse books and reference material on the ins and outs of the amd64 instruction set and FreeBSD system calls or indeed coding for microcontrollers like the PIC or AVR ranges.http://eu.wiley.com/WileyCDA/WileyTitle/productCd-0470497025.html


----------



## user0 (Apr 18, 2016)

Thank you for all the comments, but I am not learning assembly. I am learning assembly for a 64 bit FreeBSD to be exact.


----------



## asteriskRoss (Apr 18, 2016)

Developer guides for their respective x86-64 chips are available from AMD for AMD64 and Intel for Intel 64 (previously known as EM64T).  Note the instruction sets are almost but not quite the same, though the differences likely won't matter to you.  For your code that interacts with the operating system, the source code (syscalls.c) will show you FreeBSD system calls, which are described in section 2 of the man pages (for example write(2)).  System calls use the System V calling convention.  Alternatively you could call functions in the C standard library, which are described in section 3 of the man pages (for example fputs(3)), which will then make the relevant system call.


----------



## jrigg (May 12, 2016)

Be aware that register names are different in amd64, eg. eax becomes rax etc. You can still use the 32-bit names but only if the data will fit in 32 bits. Addresses in amd64 are 64 bit (strictly speaking only the lowest 48 bits are used, but you still need 64-bit registers to store them).


----------

