Tuesday, December 10, 2013

Linux assembler, 64 bit, for beginners

Huge majority of literature about programming in assembly is written for 32 bit architecture. So beginner will have difficulties translating and linking examples on 64 bit machine. To be more precise the first major hurdle is calling C function printf. That goes from notorious error message “Accessing a corrupted shared library” to different calling convention. To solve linking problem we need to link using 64 bit version of ld-linux.so.2. For example Richard Bloom gives following solution:

ld --dynamic-linker /lib/ld-linux.so.2 -o [name] -lc [name].o

When we apply it we have “Accessing a corrupted shared library”. I am using Linux Mint 13, based on Ubuntu 12.04, and /lib/ld-linux.so.2 is symlink to 32 bit library:

$ ls -l /lib/ld-linux.so.2
lrwxrwxrwx 1 root root 25 Sep 30 16:38 /lib/ld-linux.so.2 -> i386-linux-gnu/ld-2.15.so


Since we are on 64 bit architecture we need to modify linking to use appropriate architecture:

ld --dynamic-linker /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -o [name] -lc [name].o

That should eliminate “Accessing a corrupted shared library” problem. Now we have calling printf problem. On 32 bit architecture we simply push on the stack parameters and on 64 bit machine that just doesn’t work. Calling convention for 64 bit architecture is the following: result will end up in %rax, parameters, in order of appearance, will go into %rdi, %rsi, %rdx, %rcx and so on. There is quite good article about it GNU x86_64 assembler - Calling printf by Aleksandar Mitrevski. Now we can try some Hello World examples.

.section .data
hws: 
    .asciz "Hello World!\n"
.section .text
.globl _start
_start:
    mov $hws, %rdi
    call printf 
    call exit


We place our zero terminated string into register %rdi and call printf. To compile, link and execute we execute the following from terminal:

$ as -o helloworld.o helloworld.s
$ ld --dynamic-linker /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 -o helloworld -lc helloworld.o
$ ./helloworld


Now slightly more complicated example:

.section .data
whatever:
    .int 1234
format:
    .asciz "Our integer is %d\n"
.section .text
.globl _start
_start:
    movq whatever, %rsi
    movq $format, %rdi
    movq $0, %rax
    call printf
    movl $1, %eax
    movl $0, %ebx
    int $0x80


The last three lines can be replaced with call exit, but this is more like examples from book Professional assembly language by Richard Blum. Final example with even more parameters and some addition:

.section .data
a:
    .int 1234
b:
    .int 766
format:
    .asciz "%d + %d = %d\n"
.section .text
.globl _start
_start:
    movq a, %rsi
    movq b, %rdx
    movq $format, %rdi
    movq %rsi, %rcx
    addq %rdx, %rcx
    movq $0, %rax
    call printf
    call exit


If you managed to build and execute all three examples, quickly go and update your CV with freshly acquired assembly on Linux experience.

No comments:

Post a Comment