Tuesday, December 17, 2013

Passing double to printf in XMM register

As last time all this happens on Linux and processor is 64 bit AMD. We want to call C function printf and to print float. Last time we used up to six registers to pass integers and %rdi for format string to printf and now we are going to use XMM registers and %rax to specify how many XMM registers we want printed. Compiling and linking is described in previous blog entry. I will actually use double which is 64 bit float. Here is the code:

.section .data
whatever:
    .int 3
double1:
    .double -1.234, 5.6789
double2:
    .double 123.456789
double3:
    .double 9.876, 5.4321
format:
    .asciz "have %d doubles %lf, %g, %g\n"
.section .text
.globl _start
_start:   
    nop
    movupd double3, %xmm2
    movdqu double1, %xmm1
    movsd double2, %xmm0
    movq whatever, %rsi
    movq $format, %rdi
    movq $3, %rax
    call printf
    call exit


Different MOV commands are used to load data into different XMM registers. One can use gdb to see what is loaded and where. Some will load single double into low half of register and some will load both doubles into register. Function printf will print only low half of register. XMM registers are in this call behaving as stack so the first float param is in %xmm0, the second one is in %xmm1 and so on.

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.