<<<L3

Précisions sur l'assembleur sous Linux

1. Les sections

Différentes sections de données existent :

  1. .data : contient les données initialisées
  2. .bss : (Block Started by Symbol) données non initialisées globales et variables statiques
  3. .rdata : (read only) : contient constantes et littéraux

Pour rappel, la section .text contient le code du programme.

2. Obtenir le code assembleur d'un fichier .c

On prendra l'exemple de travail suivant :

#include <stdio.h>
#include <stdlib.h>

char *message = "coucou";
#define MAXIMUM 100
int tab[MAXIMUM];
int sum = -1;

int main() {
	int i;
	
	srand(1);
	for (i = 0; i < MAXIMUM; ++i) tab[i] = rand() % 10;
	sum = 0;
	for (i = 0; i < MAXIMUM; ++i) sum += tab[i];
	printf("sum = %d\n", sum);
	return 0;
}

Il existe deux méthodes :

Utiliser gcc -S

gcc génèrera un fichier d'extension .s : gcc -S -masm=intel example.c

	.file	"example.c"
	.intel_syntax noprefix
	.globl	message
	.section	.rodata
.LC0:
	.string	"coucou"
	.data
	.align 4
	.type	message, @object
	.size	message, 4
message:
	.long	.LC0
	.comm	tab,400,32
	.comm	sum,4,4
	.section	.rodata
.LC1:
	.string	"sum = %d\n"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	push	ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	mov	ebp, esp
	.cfi_def_cfa_register 5
	and	esp, -16
	sub	esp, 32
	mov	DWORD PTR [esp], 1
	call	srand
	mov	DWORD PTR [esp+28], 0
	jmp	.L2
.L3:
	call	rand
	mov	ecx, eax
	mov	edx, 1717986919
	mov	eax, ecx
	imul	edx
	sar	edx, 2
	mov	eax, ecx
	sar	eax, 31
	sub	edx, eax
	mov	eax, edx
	sal	eax, 2
	add	eax, edx
	add	eax, eax
	mov	edx, ecx
	sub	edx, eax
	mov	eax, DWORD PTR [esp+28]
	mov	DWORD PTR tab[0+eax*4], edx
	add	DWORD PTR [esp+28], 1
.L2:
	cmp	DWORD PTR [esp+28], 99
	jle	.L3
	mov	DWORD PTR sum, 0
	mov	DWORD PTR [esp+28], 0
	jmp	.L4
.L5:
	mov	eax, DWORD PTR [esp+28]
	mov	edx, DWORD PTR tab[0+eax*4]
	mov	eax, DWORD PTR sum
	add	eax, edx
	mov	DWORD PTR sum, eax
	add	DWORD PTR [esp+28], 1
.L4:
	cmp	DWORD PTR [esp+28], 99
	jle	.L5
	mov	eax, DWORD PTR sum
	mov	DWORD PTR [esp+4], eax
	mov	DWORD PTR [esp], OFFSET FLAT:.LC1
	call	printf
	mov	eax, 0
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu/Linaro 4.7.0-7ubuntu3) 4.7.0"
	.section	.note.GNU-stack,"",@progbits

utilisation de objdump

Ne pas oublier l'option -r pour la relocation des instructions:

gcc -c example.c 
objdump --disassemble -r -l -S -M intel example.o

example.o:     file format elf32-i386


Disassembly of section .text:

00000000 
: main(): 0: 55 push ebp 1: 89 e5 mov ebp,esp 3: 83 e4 f0 and esp,0xfffffff0 6: 83 ec 20 sub esp,0x20 9: c7 04 24 01 00 00 00 mov DWORD PTR [esp],0x1 10: e8 fc ff ff ff call 11 11: R_386_PC32 srand 15: c7 44 24 1c 00 00 00 mov DWORD PTR [esp+0x1c],0x0 1c: 00 1d: eb 37 jmp 56 1f: e8 fc ff ff ff call 20 20: R_386_PC32 rand 24: 89 c1 mov ecx,eax 26: ba 67 66 66 66 mov edx,0x66666667 2b: 89 c8 mov eax,ecx 2d: f7 ea imul edx 2f: c1 fa 02 sar edx,0x2 32: 89 c8 mov eax,ecx 34: c1 f8 1f sar eax,0x1f 37: 29 c2 sub edx,eax 39: 89 d0 mov eax,edx 3b: c1 e0 02 shl eax,0x2 3e: 01 d0 add eax,edx 40: 01 c0 add eax,eax 42: 89 ca mov edx,ecx 44: 29 c2 sub edx,eax 46: 8b 44 24 1c mov eax,DWORD PTR [esp+0x1c] 4a: 89 14 85 00 00 00 00 mov DWORD PTR [eax*4+0x0],edx 4d: R_386_32 tab 51: 83 44 24 1c 01 add DWORD PTR [esp+0x1c],0x1 56: 83 7c 24 1c 63 cmp DWORD PTR [esp+0x1c],0x63 5b: 7e c2 jle 1f 5d: c7 05 00 00 00 00 00 mov DWORD PTR ds:0x0,0x0 64: 00 00 00 5f: R_386_32 sum 67: c7 44 24 1c 00 00 00 mov DWORD PTR [esp+0x1c],0x0 6e: 00 6f: eb 1c jmp 8d 71: 8b 44 24 1c mov eax,DWORD PTR [esp+0x1c] 75: 8b 14 85 00 00 00 00 mov edx,DWORD PTR [eax*4+0x0] 78: R_386_32 tab 7c: a1 00 00 00 00 mov eax,ds:0x0 7d: R_386_32 sum 81: 01 d0 add eax,edx 83: a3 00 00 00 00 mov ds:0x0,eax 84: R_386_32 sum 88: 83 44 24 1c 01 add DWORD PTR [esp+0x1c],0x1 8d: 83 7c 24 1c 63 cmp DWORD PTR [esp+0x1c],0x63 92: 7e dd jle 71 94: a1 00 00 00 00 mov eax,ds:0x0 95: R_386_32 sum 99: 89 44 24 04 mov DWORD PTR [esp+0x4],eax 9d: c7 04 24 07 00 00 00 mov DWORD PTR [esp],0x7 a0: R_386_32 .rodata a4: e8 fc ff ff ff call a5 a5: R_386_PC32 printf a9: b8 00 00 00 00 mov eax,0x0 ae: c9 leave af: c3 ret

Pour visualiser les sections de données :

objdump -s -j .rodata example.o

example.o:     file format elf32-i386

Contents of section .rodata:
 0000 636f7563 6f750073 756d203d 2025640a  coucou.sum = %d.
 0010 00                                   .

Ici on peut voir sum initialisé à -1 :

objdump -s -j .data example.o

example.o:     file format elf32-i386

Contents of section .data:
 0000 00000000 ffffffff                    ........                                 

3. Compiler du code 32 bits dans un environnement 64 bits

Sous Ubuntu