So I’ve recently switched to my first non-(usb live) Linux using Ubuntu. I wiped my whole unresizable Vista partition for this. Using assembly in Linux quite different but for the better. It already has a built-in GNU toolchain which also includes the GNU Assembler. The AT&T syntax is more readable than Intel and there’s also an interrupt you can use for kernel calls (unlike Windows where you must call DLLs).
So this is what I’ve learned so far…
The interrupt for the kernel calls in Linux is 0x80. To view the functions in this interrupt, look at /usr/include/asm/unistd_32.h (I think it’s unistd_64.h for 64-bit computers). You’ll see a list of #define’s that look like this in the beginning of the file:
#ifndef _ASM_X86_UNISTD_32_H #define _ASM_X86_UNISTD_32_H /* * This file contains the system call numbers. */ #define __NR_restart_syscall 0 #define __NR_exit 1 #define __NR_fork 2 #define __NR_read 3 #define __NR_write 4 #define __NR_open 5 #define __NR_close 6 #define __NR_waitpid 7 #define __NR_creat 8 #define __NR_link 9 #define __NR_unlink 10 #define __NR_execve 11 #define __NR_chdir 12
The function number goes into eax and the parameters start at ebx, then to ecx, edx, esi and edi. To know the parameters for each syscall, look at the man pages in section 2. For example, to see the arguments for the write function run this command:
man 2 write
So this should be the synopsis:
#include <unistd.h> ssize_t write(int fd, const void *buf, size_t count);
This function writes out up to [u]count[/u] bytes from [u]buf[/u] into file referenced by file descriptor [u]fd[/u]. Using this function, you can print to the console since Linux also provides these 3 global file descriptors:
- 0 = stdin
- 1 = stdout
- 2 = stderr
So here’s my first hello world assembly program:
.text .globl _start _start: movl $4,%eax # ssize_t write movl $1,%ebx # int fd movl $msg,%ecx # const void *buf movl $13,%edx # size_t count int $0x80 movl $1,%eax # exit movl $0,%ebx # int status int $0x80 .data msg: .ascii "Hello world!\n"
Assuming this is hello.asm; to assemble and link, run the following commands:
as -o hello.o hello.asm ld -o hello hello.o
Then to run it:
So we have some assembler directives used here. .text defines our text section of our program where we put our executable code. Like C programs that start at main, programs assembled with gas start at the address labeled “_start”. So before we define our _start label, we declare it as globl, which I’m not entirely sure, but I think it makes this symbol visible to other programs that are linked with it. Comments start with # or /* & */ for multiline comments. GAS uses AT&T syntax asm so instead of “instruction dest,src” we have “instruction src,dest”. Literal values prefixed with $ and registers prefixed with %. .ascii lets me define string literals in quotes, I may also use common escape sequences found in C.