phiral.net
Home

|=-------------------------=[ NetBSD (x86) Assembly ]=------------------------=|
|=----------------------------------------------------------------------------=|

----[ Intro

This paper is going to be a bit light, as NetBSD assembly is very similar to
assembly on OpenBSD and Ive gone through that in "Writing Assembly on OpenBSD".
Mainly this will discuss the differences between the two hopefully without too
much overlap.

---[ NetBSD Note Section

A short and consise paper to read, if you wish to know all the details about
vendor-specific ELF note sections can be found at [1]. Here is a short summary:

Various operating system vendors are shipping ELF binaries and those binaries expect 
different system call interfaces. In order to help operating systems correctly 
determine whether or not they can run an ELF program, and how to run it (e.g. what 
OS emulation to use), some operating system vendors have begun marking their ELF binaries 
with vendor-specific note elements, and placing those notes in the binaries' PT_NOTE sections.

Format of an ELF Note Element
All ELF Note elements have the same basic structure:

	Name Size	4 bytes (integer)
	Desc Size	4 bytes (integer)
	Type		4 bytes (usually interpreted as an integer)
	Name		variable size, padded to a 4 byte boundary
	Desc		variable size, padded to a 4 byte boundary

The Name Size and Desc Size fields are integers (in the byte order specified by the 
binary's ELF header) which specify the size of the Name and Desc fields (excluding padding).

The Name field specifies the vendor who defined the format of the Note. Typically, 
vendors use names which are related to their project and/or company names. For instance, 
the GNU Project uses "GNU" as its name. No two vendors should use the same ELF Note Name, 
lest there be confusion when trying to interpret the meanings of notes.

The Type field is vendor specific, but it is usually treated as an integer which identifies 
the type of the note.

The Desc field is vendor specific, and usually contains data which depends on the note type.

The NetBSD Project
    There are two vendor-specific ELF Notes for NetBSD, an OS Version note and an Emulation 
Name note. The former is used to indicate what OS Version native binaries were built with, and 
can be used to identify native binaries. The latter is used to mark binaries (both native 
an non-native) with a name that indicates which set of binary emulation code is to be 
used when they are run.

    The format of the NetBSD OS Version note is:

    Name Size:          7
    Desc Size:          4
    Type:               4-byte integer containing the value 0x01
    Name:               "NetBSD\0" (padded to 8 bytes)
    Desc:               4-byte integer containing the NetBSD OS version
                        constant

---[ Hello, World!

From above we know that so far the note section must look like:

.section ".note.netbsd.ident", "a"
   .long   7                        <--- Name size
   .long   4                        <--- Desc Size
   .long   1                        <--- 4-byte integer containing the value 0x01
   .ascii "NetBSD\0"                <--- "NetBSD\0" (padded to 8 bytes)
   .p2align 2
   .long   ??????                   <--- 4-byte integer containing the NetBSD OS version
   .p2align 2

The OS version is stored in the define "__NetBSD_Version__" which is defined in the
file /usr/include/sys/param.h, so we can just grep for it.

entropy@netbsd {~/asm} grep "__NetBSD_Version__" /usr/include/sys/param.h

 *      #define __NetBSD_Version__ MMmmrrpp00
#define __NetBSD_Version__      200000200       /* NetBSD 2.0.2 */
    (m) * 1000000) + (p) * 100) >= __NetBSD_Version__)
 * New code must use __NetBSD_Version__ instead, and should not even
 
With this the note section is finalized and looks like:

.section ".note.netbsd.ident", "a"
   .long   7                        <--- Name size
   .long   4                        <--- Desc Size
   .long   1                        <--- 4-byte integer containing the value 0x01
   .ascii "NetBSD\0"                <--- "NetBSD\0" (padded to 8 bytes)
   .p2align 2
   .long   200000200                <--- 4-byte integer containing the NetBSD OS version
   .p2align 2

With this all we need is the syscall numbers and prototypes for write and exit which can be found in
the file /usr/include/sys/syscall.h or if you have the sources in /usr/src/sys/sys/syscall.h,
either way is fine as its the same file.

entropy@netbsd {~/asm} man 2 _exit

     void
     _exit(int status);

entropy@netbsd {~/asm} man 2 write

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

entropy@netbsd {~/asm} grep SYS_exit /usr/src/sys/sys/syscall.h

#define SYS_exit        1

entropy@netbsd {~/asm} grep SYS_write /usr/src/sys/sys/syscall.h

#define SYS_write       4

entropy@netbsd {~/asm}

We now have everything we need.

entropy@netbsd {~/asm} cat helloWorld.s
.section ".note.netbsd.ident", "a"
   .long   7                         # Name size
   .long   4                         # Desc Size
   .long   1                         # 4-byte integer containing the value 0x01
   .ascii "NetBSD\0"                 # "NetBSD\0" (padded to 8 bytes)
   .p2align 2
   .long   200000200                 # 4-byte integer containing the NetBSD OS version constant
   .p2align 2

.section .rodata
hello:
   .ascii "Hello, World!\n"          # our string

.section .text
.globl _start
_start:
   nop                               # so we can break at *_start+1 with gdb

   movl $4, %eax                     # move 4(SYS_write) into eax
   pushl $14                         # push the length of our string
   pushl $hello                      # push the address of our string
   pushl $1                          # push the file descriptor to write 1(STDOUT)
   pushl %eax                        # push extra long to compensate for C convention
   int $0x80                         # call the kernel

   movl $1, %eax                     # move 1(SYS_exit) into eax
   pushl $0                          # push the return value
   pushl %eax                        # push extra long to compensate for C convention
   int $0x80                         # call the kernel

Assemble, link and exectue.

entropy@netbsd {~/asm} as -gstabs helloWorld.s -o helloWorld.o

entropy@netbsd {~/asm} ld helloWorld.o -o helloWorld

entropy@netbsd {~/asm} ./helloWorld
Hello, World!

entropy@netbsd {~/asm} objdump -D helloWorld

helloWorld:     file format elf32-i386

Disassembly of section .text:

080480ac <_start>:
 80480ac:       90                      nop
 80480ad:       b8 04 00 00 00          mov    $0x4,%eax
 80480b2:       6a 0e                   push   $0xe
 80480b4:       68 c8 80 04 08          push   $0x80480c8
 80480b9:       6a 01                   push   $0x1
 80480bb:       50                      push   %eax
 80480bc:       cd 80                   int    $0x80
 80480be:       b8 01 00 00 00          mov    $0x1,%eax
 80480c3:       6a 00                   push   $0x0
 80480c5:       50                      push   %eax
 80480c6:       cd 80                   int    $0x80
Disassembly of section .rodata:

080480c8 <hello>:
 80480c8:       48                      dec    %eax
 80480c9:       65                      gs
 80480ca:       6c                      insb   (%dx),%es:(%edi)
 80480cb:       6c                      insb   (%dx),%es:(%edi)
 80480cc:       6f                      outsl  %ds:(%esi),(%dx)
 80480cd:       2c 20                   sub    $0x20,%al
 80480cf:       57                      push   %edi
 80480d0:       6f                      outsl  %ds:(%esi),(%dx)
 80480d1:       72 6c                   jb     804813f <hello+0x77>
 80480d3:       64 21 0a                and    %ecx,%fs:(%edx)
Disassembly of section .data:
Disassembly of section .note.netbsd.ident:

08048094 <.note.netbsd.ident>:
 8048094:       07                      pop    %es
 8048095:       00 00                   add    %al,(%eax)
 8048097:       00 04 00                add    %al,(%eax,%eax,1)
 804809a:       00 00                   add    %al,(%eax)
 804809c:       01 00                   add    %eax,(%eax)
 804809e:       00 00                   add    %al,(%eax)
 80480a0:       4e                      dec    %esi
 80480a1:       65                      gs
 80480a2:       74 42                   je     80480e6 <hello+0x1e>
 80480a4:       53                      push   %ebx
 80480a5:       44                      inc    %esp
 80480a6:       00 00                   add    %al,(%eax)
 80480a8:       c8 c2 eb 0b             enter  $0xebc2,$0xb

For a more in depth look check out "Writing Assembly on OpenBSD".

---[ References

- [1] NetBSD Documentation, http://netbsd.org/Documentation/kernel/elf-notes.html