Cours du 10-12-19

int calc(int a, int b)
{
    int c;
    c = g + a + b;
    return c;
}
#if 0

// argument: a = %edi (car int, sinon %rdi), b = %esi
// return value: %eax
// stack:
//      -8(%rbp)    a
//      -16(%rbp)   b
//      -24(%rbp)   c

calc:
    push %rbp
    mov %rsp, %rbp
    sub $24, %rsp

    movl %rsp, -8(%rbp)
    movl %esi, -16(%rbp)
    movl g, -24(%rbp)

    //addl a, c
    addl -8(%rbp), %edi
    addl %edi, -24(%rbp)
    
    ==>False
    #addl -8(%rbp), -24(%rbp)
    //Fonctionne pas, 2 deref en meme temps
    //On doit passer par un registre intermediaire pour faire l'operation

    //addl b, c
    addl -16(%rbp), %edi
    addl %edi, -24(%rbp)

    movl -24(%rbp), %eax

    leave
    ret
#endif

Relocation : la localisation des fonctions se fait au link.
Il s’agit de la localisation (l’adresse) des differentes fonctions appelees.

Lea

Lea : Load Effective Address
Instruction sur x86
Elle permet de calculer l’adresse plutot que de la dereferencer.

mov -0x10(%rbp), %rdx   %rdx <- local;  //Met la valeur de (par deref)
lea -0x10(%rbp), %rdx   %rdx <- &local; //Met l'adresse de (juste l'adress)

lea (%rax, %rax, 2), %rdx   %rdx = %rax * 3

Cette operation est plus rapide qu’avec les instructions de multiplication

lea 0xeaf(%rip) //-> %rip = notre adresse courante du programme

Avant c’etait une @ en dure, maintenant on essaye d’avoir des programmes qui
puissent etre n’importe ou en memoire.

Format ELF

ELF : Extensible Loading Format, Format des binaire

2 utilisations de l’ELF

Header:
readelf -h <name>

Program header:
readelf -l <name>

Section:
readelf -S <name>

Table des symboles:
readelf -s <name>

Relocation section:
readelf -r <name>

2 tables:

Dans un .o, la partie dynamique est un peu vide -> on ne pas executer un .o

Type Load : Doit etre charge en memoire

Chargeur de programme : execve

|      |<-|
|      |<||
|------| ||
| Auxv | ||   Vecteur auxiliaire (le kernel place des infos supplementaire pour 
|      | ||   la libc et le chargeur de programme)
|------| ||
| Envp |-||
|------|  |
| Argv |--|
|------|
| Argc |<- RSP
|------|
|      |

De base il n’y a pas d’executable.

On veut du code PIC (Position independante Code) pour que le code puisse etre
charge a une adresse arbitraire.

Les PIE (Position independante Executable), ce sont des objets dynamiques.
La premiere adresse virtuel est a 0x0, ce qui signifie que cette adresse peut
etre n’importe ou. Les autres sont des offsets.

Section

Permet de donner du sens a chaque bout. Le linker met tout bout a bout. Tout
les .text de tous les .o sont mis bout a bout et formera le .text du
binaire finale.

STRTAB : Table de string
SYMTAB : Table de symbole (@ des fonctions pour le link que j’ai et que
j’aimerais avoir) il y en a au moins 2.

La table de symbole pointe sur la table de string. En effet, les strings sont
de taille variable. Donc la table de symbole stocke l’emplacement du nom du
symbole dans la table de string.

file.s : fichier assembleur (generes) -> Appel directement GCC
file.S : fichier assembleur avec directives preprocesseur (humain) -> Appel
avant le preprocesseur.

    .section .text //Maintenant nous sommes dans '.text'
    .global calc //La fonction est global, d'autre peuvent l'utiliser
    .type calc, @function //Calc est de type fonction

calc:
    xor %eax, %eax
    movl g, %eax
    addl %esi, %eax
    addl %edi, %eax
    ret

.Lend_calc:
    .size calc, .Lend_calc - calc //Utile pour le debugger, avec deux symbole
                                //On peut avoir facilement la taille

    //En prefixant un label par '.L', ce dernier n'auras pas de symbole associe
    // . - calc :  '.' represente l'adresse courante

    .section .data
    .type g, @object

g:
    .long 12 //Il ecrit 12 sur 4 bytes
    .size g, . - g

Fail compilation : recompile with -fPIE
Relocation Statique
Tentative de chargement de g comme @ absolue.
g -> g(%rip) Passage en adresse relative

Faire un syscall

build.sh

#!/bin/sh

gcc -c empty.S -o empty.o
ld -o empty empty.o

empty.S //.S -> Possibilite d’include

#include <asm/unistd.h>

    .global _start

_start:
    mov $1, %rdi
    call _exit

_exit:
    mov $__NR_exit, %rax
    syscall
    ret

man 2 syscall

instr : syscall
numero doit etre dans rax
valeur de retour : rax et rdx

strace <exe>

Trouver le numero de syscall
/usr/include/asm/unistd_64.h