Showing posts with label C. Show all posts
Showing posts with label C. Show all posts

Friday, May 18, 2012

Using the stack to pass parameters between assembly functions

For a new assignment in AETC I have to pass parameters between assembly functions using the stack instead of registers.

I've made a simple test using again the power example (like in previuos posts: [1] and [2]).
In this case, an assembly function called pow_caller, which in turn calls the p_pow function, is being called from C.

This is the calling C code:
#include "stdlib.h"
#include "stdio.h"
#include "assert.h"

extern int pow_caller(int, int);

int main(void) 
{   
  assert(1 == pow_caller(3, 0)); 
  assert(9 == pow_caller(3, 2));
  assert(25 == pow_caller(5, 2));   
  assert(36 == pow_caller(6, 2));   
  assert(27 == pow_caller(3, 3));      
  printf("All tests passed!\n");
  return EXIT_SUCCESS;
}
This code is calling the pow_caller function:
pow_caller:             
  push rbp      ; Store stack initial state
  mov  rbp, rsp   

  sub rsp, 8    ; We make space for p_pow result by
                ; subtracting 8 bytes to the stack 
                ; pointer (RSP)
  push rdi      ; We push the base (b) to the stack
  push rsi      ; We push the exponent (e) to the stack
  
  call p_pow    ; Now we call p_pow
  
  add rsp, 16   ; We make RSP point to the 
                ; position were the result is.
  pop rax       ; And move the result to rax so 
                ; that it's returned to the C program
  
  mov rsp, rbp  ; Restore stack initial state
  pop rbp

  ret
As you can see, pow_caller is passing the parameters (base and exponent) to p_pow using the stack.
Before passing the parameters it's also reserving some space (8 bytes) for the result of p_pow to be returned. That's what sub rsp, 8 is doing, (remember that the stack grows towards decreasing addresses).

Once p_pow finishes, we have to get the result from the stack. To do it we go to the place where the result is by moving the stack pointer RSP (add rsp, 16) and, once there, get the result from the stack moving it to the RAX register (pop rax), so that it's returned to the C program when pow_caller ends.
Before executing add rsp, 16, the result of p_pow was in memory at address rbp+16, but after executing add rsp, 16 it was at address rbp, so it can be reached just using pop.

It's very important to remark that the state of the stack (RSP and RBP) must be the same before and after the function to avoid funny bugs when you go back to the caller.

In pow_caller we've pushed the content of 3 registers (RBP, RDI and RSI) to the stack (24 bytes) and subtracted 8 bytes to store the result of p_pow, that's 32 bytes, so that, $rsp' = $rsp - 32, where $rsp is the content of RSP when entering p_pow_caller and $rsp' is its current value.
After p_pow finished, we added 16 bytes to RSP and then made two pops (another 16 bytes), so at the end $rsp' = $rsp again.
That last pop made also that $rbp' = $rbp again.

It only remains to see how p_pow accesses the stack to get the parameters and store the result.

This is the code of p_pow:
p_pow:
  push rbp
  mov  rbp, rsp    ; Store stack initial state
  push rax                   
  push rbx 
  push rcx
  push rdx  
  
  mov eax, 1       ; Initialize rax  

  ; We move the base (b) from the stack to ebx
  mov ebx, dword[rbp+24]  

  ; We move the exponent (e) from the stack to ecx
  mov ecx, dword[rbp+16]  

  cmp ecx, 0       ; if e==0 -> b^0=1, and we are done
  jle p_pow_end             
  
  p_pow_loop:              
    mul ebx        ; eax*ebx=edx:eax
    dec ecx        ; ecx = ecx - 1
    jg  p_pow_loop ; If ecx > 0 it iterates again
  p_pow_end:

  ; Move the result to the space reserved for it in the stack
  mov [rbp+32], rax      
  
  pop rdx          ; Restore stack initial state
  pop rcx
  pop rbx
  pop rax
  mov rsp, rbp
  pop rbp
  
  ret
Ok, so again the first thing we do is pushing the initial value of RBP (the value in p_pow_caller), so that we can get it back once the function has finished.

Then we copy in RBP the initial content of RSP+8 (because we did a pop). We do this because we want to be able to go on using the stack doing push and pop (which changes RSP), but we also want to be able to reach the parameters that are at certain distance in memory of the original RSP.
This explains why to get a parameter from the stack we use [rbp+distance].
In p_pow_caller we pushed the base first and then the exponent. Since the stack is a LIFO data structure, the exponent is closer to RBP than the base.
How far is it? Well, before pushing p_pow initial RBP content, the exponent was at a distance of 8 bytes from the caller's RSP and the base at a distance of 16. After pushing RBP, the distance is 8 bytes more: base at 28 and exponent at 16 bytes distance.
In that moment we stored the content of RSP inside RBP, so that later changes to RSP cannot change the distance to the parameters. That's the reason why we are able to grab the base and exponent by doing mov ebx, dword[rbp+24] and mov ecx, dword[rbp+16], respectively.

When we've computed the power, we store it in the place that we reserved for it before pushing the parameters (which is 8 bytes farther than the base) doing mov [rbp+32], rax

At the end of p_pow we restore the initial state of the stack (RBP and RSP) again before returning to p_pow_caller.

Saturday, April 28, 2012

Calling an assembly function from C passing parameters by reference

In a recent post I showed how to call an assembly function from C. In that example we passed the exponent and base parameters by value to an assembly function, p_pow.
In this example, we'll see how to pass parameters by reference.

This time, instead of using the RAX register to return the result of the p_pow function, we pass a third parameter by reference that will hold the result.
This is the calling C code:
#include "stdlib.h"
#include "stdio.h"
#include "assert.h"

// Assembly function declaration
extern void p_pow(int, int, int *);

int main(void) 
{  
  int result;

  p_pow(2, 2, &result);
  assert(4 == result);
  
  p_pow(3, 2, &result);
  assert(9 == result);
  
  p_pow(5, 2, &result);
  assert(25 == result);   
  
  p_pow(6, 2, &result);
  assert(36 == result);   
  
  p_pow(3, 3, &result);
  assert(27 == result);      
  
  p_pow(3, 0, &result);
  assert(1 == result);
  
  p_pow(1, 5, &result);
  assert(1 == result);
  
  p_pow(-2, 2, &result);
  assert(4 == result);
  
  p_pow(-2, 3, &result);
  assert(-8 == result);

  printf("All tests passed!\n");
  return EXIT_SUCCESS;
}
Look at the prototype of the p_pow function.
extern void p_pow(int, int, int *);
We want to pass result by reference. Since in C everything is passed by default, to pass a parameter by reference what we actually do is passing by value the memory address where result is stored. That's why we've used a pointer.
This is the assembly code:
section .data          
  
section .text                

  ; Make the function name global so it can be seen from the C code
  global p_pow              

p_pow:
  push rbp
  mov rbp, rsp ; Stack initial state is stored
  
  push rdx     ; Store initial value of RDX 
               ; (memory address where the result will be stored)
               ; because RDX can be modified by MUL operation
  
  ; The base (b) is being passed in RDI register
  ; and the exponent (e) is being passed in RCX register
  
  mov eax, 1   ; Register RAX will hold the result temporarily
  
  cmp esi, 0   ; if (e == 0) -> b^0 = 1, and we're done
  jle pow_end   
  
  mul_loop:
   mul edi     ; eax*ebx = edx:eax (when operating 
               ; with ints, edx is not used).
   dec esi     ; esi = esi - 1
   jg mul_loop ; If esi > 0, it continues iterating
  
  pow_end:
  
  pop rdx      ; Restore initial value of RDX
               ; (memory address where the result will be stored)
  
  mov [RDX], dword eax ; Copy final result in memory
  
  mov rsp, rbp ; Stack initial state is restored
  pop rbp                     
  ret           
Now we compile, link and execute the program and we get:
$ yasm -f elf64 -g dwarf2 pow.asm 
$ gcc -g -o pow pow.o pow_c.c
$ ./pow
All tests passed!
Note that in the assembly code, the RDX register is holding the memory address where result is stored. That's how the assembly program is able to change its value. As I explained in a previous post, in the calling convention of the System V AMD64 ABI the registers RDI, RSI, RDX, RCX, R8 and R9 are used for integer and pointer arguments.
To see it better, we'll use gdb.
This is the content of the registers in the first call to p_pow right after executing mov [RDX], dword eax:
(gdb) info register
rax            0x4 4
rbx            0x0 0
rcx            0x0 0
rdx            0x7fffffffe0fc 140737488347388
rsi            0x0 0
rdi            0x2 2
rbp            0x7fffffffe0e0 0x7fffffffe0e0
rsp            0x7fffffffe0e0 0x7fffffffe0e0
r8             0x7ffff7dd7300 140737351873280
r9             0x7ffff7deb5f0 140737351955952
r10            0x7fffffffdf50 140737488346960
r11            0x7ffff7a76c90 140737348332688
r12            0x400460 4195424
r13            0x7fffffffe1e0 140737488347616
r14            0x0 0
r15            0x0 0
rip            0x400568 0x400568 <pow_end+3>
eflags         0x246 [ PF ZF IF ]
cs             0x33 51
ss             0x2b 43
ds             0x0 0
es             0x0 0
fs             0x0 0
gs             0x0 0
The RDX register contains the memory address of result and the content of that memory address is 4:
(gdb) x/d $rdx
0x7fffffffe0fc: 4

We've seen how by passing its memory address by value, we were able to change the content of a variable from inside an assembly function, as though we were passing the variable by reference.

Sunday, April 22, 2012

Calling an assembly function from C: simple example

This semester I'm studying AETC in ETIS in the UOC.
For one of the course assignments I had to use some C mixed with assembly.
To make things simpler in this first assignment, we were asked to use only global variables to pass information between the main C programs and the assembly subroutines.
Since I wanted to know how to do it without global variables, I started to explore a bit.

After some googling and reading several blog posts I found out that, first of all, I needed to identify which calling convention to use. There are many different calling conventions, which one you use depends on your architecture, language or even operative system.
I was using a x86-64 architecture in a 64 Bit Linux, so checking this Wikipedia list of different x86 calling conventions I finally found out that the one I needed to use was: the System V AMD64 ABI convention.
From Wikipedia:
System V AMD64 ABI convention
The calling convention of the System V AMD64 application binary interface is followed on Linux and other non-Microsoft operating systems. The registers RDI, RSI, RDX, RCX, R8 and R9 are used for integer and pointer arguments while XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 and XMM7 are used for floating point arguments. For system calls, R10 is used instead of RCX.[9] As in the Microsoft x64 calling convention, additional arguments are pushed onto the stack and the return value is stored in RAX.
Once I knew how to pass parameters to an assembly function from C, I coded a simple integer power computation to test it.
This is the calling C code (pow_c.c):
#include "stdlib.h"
#include "stdio.h"
#include "assert.h"

// Assembly function declaration
extern p_pow(int, int);

int main(void) {  
  assert(4 == p_pow(2, 2));
  assert(9 == p_pow(3, 2));
  assert(25 == p_pow(5, 2));   
  assert(36 == p_pow(6, 2));   
  assert(27 == p_pow(3, 3));      
  assert(1 == p_pow(3, 0));
  assert(1 == p_pow(1, 5));
  assert(4 == p_pow(-2, 2));
  assert(-8 == p_pow(-2, 3));
  printf("All tests passed!\n");
  return EXIT_SUCCESS;
}
And this is the assembly code (pow.asm):
section .data          
  
section .text                

; Make the function name global so it can be 
; seen from the C code
global p_pow              

; Function that computes the power of an integer.
; The base (b) is being passed in RDI register
; and the exponent (e) is being passed in RSI register
; The result is returned in the RAX register
p_pow:
 push rbp
 mov rbp, rsp ; Stack initial state is stored
    
 mov eax, 1   ; Register RAX will hold the result
 cmp esi, 0   ; if (e == 0) -> b^0 = 1, and we're done
 jle pow_end   
  
 mul_loop:
  mul edi     ; eax*ebx = edx:eax (when operating 
              ; with ints, edx is not used).
  dec esi     ; esi = esi - 1
  jg mul_loop ; If esi > 0, it continues iterating
 pow_end:
  
 mov rsp, rbp ; Stack initial state is restored
 pop rbp                      
 ret
To compile the assembly code I used Yasm which is a rewrite of the NASM assembler under the “new” BSD License. If you have it already installed, you just need to open a console and write this:
$ yasm -f elf64 -g dwarf2 pow.asm
Doing this you'll get an object file: pow.o
Actually only yasm -f elf64 pow.asm is needed to get an object file, but I added -g dwarf2 to obtain debug information so I could use gdb to debug the program.
The elf64 object format is the 64-bit version of the Executable and Linkable Object Format. DWARF is a debugging format used on most modern Unix systems.

To compile the C code and link it with pow.o:
$ gcc -g -o pow pow.o pow_c.c
which produces the executable pow, that when executed yields the following output:
$ ./pow
All tests passed!

Saturday, December 31, 2011

Example of using variadic functions in C

This is the translation into English of an old post.

In my master's thesis I used variadic functions (functions that can accept a variable number of arguments) to be able to pass different differential equations systems to the function in charge of computing Lyapunov exponents.

Since that code is too big to fit in here, I'll post the tiny tests that I did to understand how C variadic functions work.

You can find a great explanation of C variadic functions in a section of apendix A of The GNU C Library manual. In this manual there is an example in which an undetermined number of integers is passed to a function that adds them.

This is the example where I've highlighted and commented the most important lines:
#include 
#include 

int sum (int count,...){
    va_list ap; // List of arguments
    int i, sum;

    /* Initializes the list of arguments */
    va_start (ap, count);         

    sum = 0;
    for (i = 0; i < count; i++){
        /* Obtains the next argument */
        sum += va_arg (ap, int);    
    }
    
    /* Frees the list */
    va_end (ap);       
    
    return sum;
}

int main(void){
    /* This prints 16. */
    printf ("%d\n", sum (3, 5, 5, 6));

    /* This prints 19. */
    printf ("%d\n", sum (10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
    
    return (0);
}

Several important things regarding this example must be remarked:
  • To work with an undetermined number of arguments we must include the header stdarg.h of the C Standard Library.
  • In the function's list of arguments three dots are used to signal the start of the undetermined arguments.
  • A variable of type va_list must be declared. This variable will contain the arguments list.
  • The macro va_start is used to initialize the arguments list. We must tell the macro which is the last determined argument.
  • The macro va_arg is used tp extract the arguments from the list. We must tell the macro the type of the extracted argument. 
  • The macro va_end is used to free the memory.  
This is the result of executing the previous example:
$ ./test1 
16
55

In the next example, I used the same procedure to pass an undetermined number of arguments. In this case, though, the type of the argument is a user defined type:
#include <stdarg.h> 
#include <stdio.h>

typedef struct s_Date{
    unsigned int year;
    unsigned int month;
    unsigned int day;
}t_Date;

void setDate(unsigned int day, unsigned int month, unsigned int year, 
             t_Date *date);
void printDate(t_Date date);

/* Prints several dates */
void printDates(unsigned int numberOfDates, ...){
    va_list ap;
    int i;

    /* Initializes the list of arguments */
    va_start(ap, numberOfDates);         

    for(i = 0; i < numberOfDates; i++){
        // Extracts next argument from the list
        printDate(va_arg (ap, t_Date));
    }
    
    printf("\n");
    
    // Frees the memory
    va_end(ap);          
    
    return;
}

int main(void){
    t_Date date1, date2, date3;
    
    setDate(1,1,2009, &date1);
    setDate(2,2,2009, &date2);
    setDate(3,3,2009, &date3);
    
    /* This prints 1/1/2009 */
    printDates(1, date1);

    /* This prints  1/1/2009 2/2/2009*/
    printDates(2, date1, date2);
    
    /* This prints 1/1/2009 2/2/2009 3/3/2009*/
    printDates(3, date1, date2, date3);

    return (0);
}

/* Initializes a t_Date variable*/
void setDate(unsigned int day, unsigned int month, unsigned int year, 
             t_Date *date){
    date->day = day;
    date->month = month;
    date->year = year;
}

/*Prints a date*/
void printDate(t_Date date){
    printf("%d/%d/%d ", date.day, date.month, date.year);
    return;
}
This is the output:
$ ./test2 
1/1/2009 
1/1/2009 2/2/2009 
1/1/2009 2/2/2009 3/3/2009 

Saturday, March 27, 2010

Usando dSFMT

Antes de empezar el Master de Física Computacional y Aplicada sólo había usado generadores de números aleatorios escritos en Fortran.
En la asignatura Simulación con Dinámica Molecular y Monte Carlo tuve que hacer una simulación del modelo de Ising para la que necesitaba un buen generador escrito en C.
Googleando un poco acabé encontrando el Mersenne Twister desarrollado en 1997 por Makoto Matsumoto y Takuji Nishimura, que, según Wikipedia:
... provides for fast generation of very high-quality pseudorandom numbers, having been designed specifically to rectify many of the flaws found in older algorithms.
Ahora para el proyecto final del máster estoy utilizando la versión 2.1 en C del Double precision SIMD-oriented Fast Mersenne Twister (dSFMT) que es una variante del Mersenne Twister que introdujeron Mutsuo Saito y Makoto Matsumoto en el 2006. La librería se puede descargar de la página web de los inventores.

Esta variante es mucho más rápida que el MT en la mayoría de las plataformas. Además cuenta con la ventaja de que proporciona directamente numeros reales de doble precisión.

Existen implementaciones de SFMT en otros lenguajes (aún no de dSFMT) que han sido realizadas por voluntarios.

Lo último que han hecho ha sido una versión del MT para GPUs.

Funciones con un número indeterminado de argumentos en C

En el proyecto de fin de master utilicé listas de argumentos variables para poder pasar diferentes sistemas de ecuaciones diferenciales a la función con la que calculo exponentes de Lyapunov.

Como ese código es demasiado largo para ponerlo aquí, pondré las pequeñas pruebas que hice para aprender.

Se puede encontrar una explicación muy buena de las funciones variádicas (funciones que pueden aceptar un número indeterminado de argumentos) en un apartado del apéndice A del manual de The GNU C Library.
En este manual hay un ejemplo en el que se le pasa a una función un número indeterminado de enteros para que esta devuelva su suma.
Este es el ejemplo del manual con los comentarios traducidos y resaltando las líneas más importantes:
#include 
#include 

int suma (int count,...)
{
    va_list ap; //Lista de parámetros
    int i, sum;

    /* Inicializa la lista de argumentos */
    va_start (ap, count);         

    sum = 0;
    for (i = 0; i < count; i++)
    {
        /* Obtiene el siguiente argumento. */
        sum += va_arg (ap, int);    
    }
    
    /* Limpia la lista */
    va_end (ap);       
    
    return sum;
}

int main(void)
{
    /* Esta llamada imprime 16. */
    printf ("%d\n", suma (3, 5, 5, 6));

    /* Esta llamada imprime 19. */
    printf ("%d\n", suma (10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
    
    return (0);
}
En este ejemplo se debe destacar lo siguiente:
  • Para poder pasar un número indeterminado de argumentos se debe incluir la cabecera stdarg.h de la librería estándar de C.
  • En la lista de argumentos se usan tres puntos para indicar el comienzo de los argumentos variables.
  • Se debe declarar una variable de tipo va_list que se encargará de contener la lista de argumentos.
  • Se utiliza la macro va_start para inicializar la lista indicándole cuál es el último argumento fijo.
  • Se utiliza la macro va_arg para extraer los argumentos de la lista indicándole cuál es su tipo de datos. 
  • Se utiliza la macro va_end para limpiar la memoria.  
Este es el resultado de ejecutar el ejemplo anterior:
$ ./test1 
16
55
En este otro ejemplo usé el mismo procedimiento para pasar un número indeterminado de argumentos variables con tipos de datos definidos por el usuario:
#include  
#include 

typedef struct s_Fecha
{
    unsigned int anyo;
    unsigned int mes;
    unsigned int dia;
}t_Fecha;

t_Fecha setFecha(unsigned short dia, unsigned short mes,unsigned short anyo);
void imprimeFecha(t_Fecha fecha);

/* Imprime varias fechas */
void imprimeFechas(unsigned int numFechas, ...)
{
    va_list ap;
    int i;

    /* Se inicializa la lista de argumentos */
    va_start (ap, numFechas);         

    for (i = 0; i < numFechas; i++)
    {
        // Se saca el siguiente argumento de la lista
        imprimeFecha(va_arg (ap, t_Fecha));
    }
    
    printf("\n");
    
    //Se limpia la memoria
    va_end (ap);          
    
    return;
}

int main(void)
{
    t_Fecha fecha1, fecha2, fecha3;
    
    fecha1=setFecha(1,1,2009);
    fecha2=setFecha(2,2,2009);
    fecha3=setFecha(3,3,2009);
    
    /* Esta llamada imprime 1/1/2009 */
    imprimeFechas(1, fecha1);

    /* Esta llamada imprime 1/1/2009 2/2/2009*/
    imprimeFechas(2, fecha1, fecha2);
    
    /* Esta llamada imprime 1/1/2009 2/2/2009 3/3/2009*/
    imprimeFechas(3, fecha1, fecha2, fecha3);

    return (0);
}

/* Devuelve una variable de tipo t_Fecha */
t_Fecha setFecha(unsigned short dia, unsigned short mes,unsigned short anyo)
{
    t_Fecha fecha;
    
    fecha.dia=dia;
    fecha.mes=mes;
    fecha.anyo=anyo;
    
    return fecha;
}

/*Imprime una fecha*/
void imprimeFecha(t_Fecha fecha)
{
    printf("%d/%d/%d ",fecha.dia,fecha.mes,fecha.anyo);
    return;
}
Este es el resultado:
$ ./test2 
1/1/2009 
1/1/2009 2/2/2009 
1/1/2009 2/2/2009 3/3/2009 

Thursday, October 22, 2009

Ejemplos de programación avanzada en C sobre Linux

Ejemplos sencillos de C/C++ para Linux avanzado
Esta web contiene ejemplos muy bien explicados de técnicas de programación avanzadas en C y C++.
Los temas avanzados de C son:
  • Comunicaciones en red entre procesos.
  • IPCs (Recursos compartidos).
    • Varios programas en el mismo ordenador pueden compartir información por medio de recursos compartidos, como memoria compartida, semáforos, colas de mensajes o señales y alarmas. Cómo hacer que un programa ejecute algo cada cierto tiempo sin necesidad de "dormirlo".
  • Procesos y Threads.
  • Gráficos con X11.

Programación en Linux

Programación en Linux
Como dice su autor:
Esta página intenta acumular links, información y toda clase de cosas útiles a los que se embarcan en la programación para Linux.
Es muy interesante.

Ejemplos de Java y C/Linux

Tiene muchos ejemplos en ambos lenguajes y algunos tutoriales.
Lo mejor es que tiene mucho ejemplos muy bien explicados de C y C++ en Linux.
Estos me gustaron tanto que les dedicaré una entrada aparte.

Wednesday, October 21, 2009

The GNU C Library

Documentación de The GNU C Library.
Muy útil para no reinventar la rueda, pero parece que no trae muchos ejemplos.

Thursday, October 15, 2009

Cursos de C

Este curso de C de la web El rincón del C puede complementar los dos primeros temas del curso de Introducción al desarrollo de software del Master de Software Libre de la UOC. El rincón del C contiene un montón de ejemplos, noticias y tutoriales.

En el curso de la Cardiff School of Computer Sciences:
Programming in C. UNIX System Calls and Subroutines using C. se puede encontrar mucha información sobre el uso de threads en C, comunicación entre procesos, señales, interrupciones y otros aspectos avanzados del lenguaje C. La verdad es que tiene muy buena pinta y contiene abundantes ejemplos y código fuente.