print · rss · source

< Implémenter les signaux | TutoOS | Annexe B - Arithmétique en base 16 >


Compilation séparée en assembleur sous Unix

Le programme principal

Le fichier suivant contient le code principal. Il incrémente la variable mavar avec la fonction incr définie dans un autre fichier. Cette fonction externe doit être déclarée au début du fichier avec la directive extern.
Le linker a besoin qu'un point d'entrée soit défini pour déterminer où débute le programme. Par défaut, ce point d'entrée correspond au label _start et il doit être déclaré de façon globale (sans quoi il ne serait pas vu par le linker) :

extern incr
global _start

_start:
    push dword mavar
    call incr

mavar: dw 0x01

La fonction

La fonction incr incrémente un entier sur 4 octets passé en argument (passage par pointeur). Pour que cette fonction soit visible au linkage, on la déclare au début du fichier grâce à la directive global :

global incr

incr:
    push eax  ; sauvegarde du registre
    push ebx  ; sauvegarde du registre

    push ebp
    mov ebp, esp

    mov ebx, [ebp+16] ; copie de l'adresse de la variable
    mov eax, [ebx]    ; copie de la valeur
    add eax, 1        ; incrementation la valeur
    mov [ebx], eax    ; modification de la variable pointee

    mov esp, ebp
    pop ebp

    pop ebx
    pop eax
    ret

Compilation et linkage

On produit à partir de chaque fichier source un fichier objet au format ELF grâce à la commande suivante :

$ nasm -f elf incr.asm -o incr.o
$ nasm -f elf main.asm -o main.o

Le linkage est fait avec la commande ld. L'argument --oformat binary permet d'obtenir un binaire pur :

$ ld --oformat binary -Ttext 0 main.o incr.o

En désassemblant le binaire a.out obtenu, on voit très clairement l'assemblage des deux fichiers objets en un seul :

$ ndisasm -u a.out
00000000  680A000000        push dword 0xa
00000005  E806000000        call dword 0x10
0000000A  0100              add [eax],eax
0000000C  90                nop
0000000D  90                nop
0000000E  90                nop
0000000F  90                nop
00000010  50                push eax
00000011  53                push ebx
00000012  55                push ebp
00000013  89E5              mov ebp,esp
00000015  8B5D08            mov ebx,[ebp+0x8]
00000018  8B03              mov eax,[ebx]
0000001A  0501000000        add eax,0x1
0000001F  8903              mov [ebx],eax
00000021  89EC              mov esp,ebp
00000023  5D                pop ebp
00000024  5B                pop ebx
00000025  58                pop eax
00000026  C3                ret

Création d'exécutables sous Unix

Un programme principal en assembleur

extern  printf
global  main
main:
    push eax
    push dword msg
    call printf
    pop eax
    pop eax
    ret

msg db "Hello world", 13, 10, 0

Ce programme est l'équivalent de :

#include <stdio.h>

void main()
{
    printf("Hello world\n");
}

On le compile de la façon suivante :

$ nasm -f elf main.asm -o main.o
$ gcc main.o

Un programme principal en C et une fonction en assembleur

Le programme principal

#include <stdio.h>

extern void incr(int*);

void main()
{
    int a = 1;

    incr(&a);

    printf("%d\n", a);
    return;
}

Compilation et linkage

Pour compiler le fichier principal et le lier au fichier objet :

$ gcc main.c incr.o

< Implémenter les signaux | TutoOS | Annexe B - Arithmétique en base 16 >

print · rss · source
Page last modified on November 27, 2008, at 10:56 AM