How to communicate with Linux kernel   " The power of assembly programming "

  1. Identity of the "bloated software"
  2. Independence from GLIBC
  3. Requirement of exit function
  4. How to communicate with system calls in assembly?
  5. Brief anatomy of Executable and Linking Format (ELF)
  6. Library independent "Hello World"

Last updated 2001-07-30 5:36 pm


Library independent "Hello World"

Most of all programmers use printf() or fprintf() to output strings. Of course, they are standard library functions provided by GNU libc. To support output routine in assembly, I created xputchar() function.

xputchar.asm
     
; ; N A M E : x p u t c h a r . a s m ; ; D E S C : putchar() by assembly ; ; A U T H : Wataru Nishida, M.D., Ph.D. ; wnishida@skyfree.org ; http://www.skyfree.org ; ; M A K E : nasm -f elf xputchar.asm ; ; V E R S : 1.0 ; ; D A T E : Dec. 17, 2000 ; bits 32 ; Use 32bit mode. ; [ NOTE ] Code starts from here. section .text ; Code must resides in the ".text" in GCC. global xputchar ; Declare xputchar() as a public function. ; ; x p u t c h a r ; ; int xputchar (unsigned int ch) ; ; --- return one (success) or -1 (error) ; ; Dec. 17, 2000 xputchar: push ebp ; Remember EBP. mov ebp, esp ; Prepare my stack frame. ; Now, [ ebp ] points saved EBP, ; and [ ebp+4 ] points return address. ; [ NOTE ] We must preserve registers except EAX, ECX, and EDX. push ebx ; Save EBX. ; [ NOTE ] 1st argument appears in [ ebp+8 ], and 2nd [ ebp+12 ]... mov eax, [ ebp + 8 ]; Get character code. mov [ msgbuf ], al ; And save it. mov edx, 1 ; Set character count. mov ecx, msgbuf ; Set buffer pointer. mov ebx, 1 ; Set STDOUT. mov eax, 4 ; Call sys_write(). int 0x80 pop ebx ; Recover EBX. leave ; Perform ESP=EBP and EBP=pop(). ret ; [ NOTE ] Storage area for the variables starts from here. section .data ; Variables must reside in the ".data" in GCC. msgbuf db 0 ; Message buffer.

xputchar() executes "write" system call (Function number is 4) with three arguments. First is file descriptor, second is string buffer pointer, and last is string length. In this program, we use standard output (STDOUT) and specify one as file descriptor. For temporary buffer, I declared a static variable "msgbuf" in .data section. If you want to output a string, you have to create original "strlen()" function.

hello.c
     
extern int xputchar(unsigned int); extern int xexit(int); main(){ char msg[]="Hello World!\n"; char *ptr; int res; ptr = msg; while (*ptr) res = xputchar(*ptr++); xexit(128); }

Here is the body of assembly "HelloWorld". It is a simple C language program. Let's create the program.

     
$ nasm -f elf xputchar.asm $ gcc -c hello.c $ ld -s -e main -o hello hello.o xputchar.o xexit.o $ strip --remove-section=.comment --remove-section=.note hello $ ldd hello statically linked (ELF) $ ls -l total 25 drwxr-sr-x 2 root src 208 Jan 6 22:03 . drwxr-sr-x 4 root src 96 Jan 6 21:57 .. -rwxr-xr-x 1 root src 676 Jan 6 22:03 hello -rw------- 1 root src 196 Jan 6 22:02 hello.c -rw-r--r-- 1 root src 1040 Jan 6 22:02 hello.o -rw-r--r-- 1 root src 512 Jan 6 21:31 xexit.o -rw------- 1 root src 1360 Jan 5 18:49 xputchar.asm -rw-r--r-- 1 root src 704 Jan 5 18:49 xputchar.o $ ./hello ; echo $? Hello World! 128

When -s option is specified, ld automatically removes symbol table sections. Completed program is independent of library, and its size is 676 bytes. Finally, we comletely controled Linux kernel without a help of standard environment! Congratulation, but this is the beginning.