|=-------------------------=[ 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
|