2. TP 2
Squelette de programme
Dans ce TP nous allons créer un squelette de programme et nous intéresser, par la suite, à la traduction
d'un if then else.
Le cheminement et les explications sont disponibles dans cette
vidéo.
Commencez par créer un sous-répertoire qui contiendra l'ensemble des codes sources et
appelez le par exemple assembleur.
2.1. Squelette de programme
Nous allons traduire le programme suivant, le fameux Hello World :
// ===================================================================
// Program: hello_world.c
// Date: July 2020
// Author: Jean-Michel Richer
// Email: jean-michel.richer@univ-angers.fr
// ===================================================================
// Description:
// This program is the classical 'Hello World" program.
//
// It is intended to be translated in 32 bits x86 assembly
// language.
// ===================================================================
#include <stdio.h>
#include <stdlib.h>
/**
* main function
*/
int main(int argc, char *argv[]) {
return EXIT_SUCCESS;
}
Le code correspondant en nasm est le suivant :
; ===================================================================
; Program: hello_word_nasm.asm
; Date: July 2020
; Author: Jean-Michel Richer
; Email: jean-michel.richer@univ-angers.fr
; ===================================================================
; Description:
; This program is an assembly translation of the C Hello World
; program.
; ===================================================================
global main
extern printf
; ===================================================================
; ##### ## ##### ##
; # # # # # # #
; # # # # # # #
; # # ###### # ######
; # # # # # # #
; ##### # # # # #
; ===================================================================
section .data
message: db "Hello World!", 10, 0
; ===================================================================
; #### #### ##### ######
; # # # # # # #
; # # # # # #####
; # # # # # #
; # # # # # # #
; #### #### ##### ######
; ===================================================================
section .text
; -------------------------------------------------------------------
; SUBPROGRAM
;
; int main(int argc, char *argv[])
;
; DESCRIPTION
;
; Main subprogram that prints the string 'message' on standard
; output
;
; PARAMETERS
;
; argc int number of arguments of the program
; argv char *[] array of arguments as strings
;
; RETURN VALUE
;
; 0 if everything is ok,
; >0 if error
;
; -------------------------------------------------------------------
main:
push ebp
mov ebp, esp
;
; Code of subprogram
;
push dword message
call printf
add esp, 4
xor eax, eax ; 0 of return 0
mov esp, ebp
pop ebp
ret
La compilation et la génération de l'exécutable en architecture 32 bits (sous un système 64 bits) sont réalisées grâce aux commandes suivantes :
richer@zentopia:\$ nasm -f elf hello_world_nasm.asm
richer@zentopia:\$ g++ -o hello_world_nasm.exe hello_world_nasm.o -m32
Attention : sous les dernières versions de Debian ou Ubuntu, il est parfois nécessaire d'ajouter un flag supplémentaire à gcc/g++ lors de la compilation : -no-pie. Vous devez donc compiler avec :
richer@zentopia:\$ g++ -o hello_world_nasm.exe hello_world_nasm.o -m32 -no-pie
2.2. Automatisation de la compilation
Etant donné que nous aurons plusieurs programmes à compiler nous allons créer un
makefile afin d'automatiser la compilation des programmes assembleur :
Vous pouvez récupérer le fichier suivant et l'enregistrer sous le nom
makefile :
# ===================================================================
# Makefile for assembly programming
# ===================================================================
NASM_FLAGS= -f elf -g -F dwarf
CXX_FLAGS= -Wall -m32 -ggdb
OPT_FLAGS= -m32 -ggdb -O3 -mavx2 -ftree-vectorize -funroll-loops
.PRECIOUS: obj/%.o
.SECONDARY: obj/%.o
all: setup_directories \
bin/hello_world.exe bin/hello_world_nasm.exe
setup_directories:
mkdir -p bin obj
# rules
bin/%.exe: obj/%.o
gcc -o $@ $< $(OPT_FLAGS)
obj/%.o: %.asm
nasm $(NASM_FLAGS) $< -o $@
obj/%.o: %.c
gcc -c -o $@ $< $(OPT_FLAGS) $(CXX_FLAGS)
obj/%.o: %.cpp
g++ -c -o $@ $< $(OPT_FLAGS) $(CXX_FLAGS)
# clean
clean:
rm -rf bin/*.exe obj/*.o
2.3. If then else
2.3.1. Version basique
Traduire le programme suivant en assembleur 32 bits. On dispose de deux valeurs entières
$a$ et $b$ et on veut afficher un message qui indique si $a$ est inférieur à $b$ ou si
$a$ est supérieur ou égal à $b$ :
// ===================================================================
// Program: if_then_else_v1.c
// Date: July 2020
// Author: Jean-Michel Richer
// Email: jean-michel.richer@univ-angers.fr
// ===================================================================
// Description:
// This program shows how to code a if then else statement in C.
// It is intended to be translated in 32 bits x86 assembly
// language.
// ===================================================================
#include <stdio.h>
#include <stdlib.h>
// global integer variables
int a = 1;
int b = 2;
/**
* main function
*/
int main(int argc, char *argv[]) {
// compare 'a' to 'b' and print message
if (a < b) {
} else {
}
return EXIT_SUCCESS;
}
Voici la traduction :
; ===================================================================
; Program: if_then_else_v1_nasm.asm
; Date: July 2020
; Author: Jean-Michel Richer
; Email: jean-michel.richer@univ-angers.fr
; ===================================================================
; Description:
; This program shows how to code a if-then-else statement
;
; ===================================================================
global main
extern printf
; ===================================================================
; ##### ## ##### ##
; # # # # # # #
; # # # # # # #
; # # ###### # ######
; # # # # # # #
; ##### # # # # #
; ===================================================================
section .data
a: dd 1
b: dd 2
msg_inf: db "a < b", 10, 0
msg_supe: db "a >= b", 10, 0
; ===================================================================
; #### #### ##### ######
; # # # # # # #
; # # # # # #####
; # # # # # #
; # # # # # # #
; #### #### ##### ######
; ===================================================================
section .text
; -------------------------------------------------------------------
; SUBPROGRAM
;
; int main(int argc, char *argv[])
;
; DESCRIPTION
;
; Main subprogram that compares variables 'a' and 'b'
;
; PARAMETERS
;
; argc int number of arguments of the program
; argv char *[] array of arguments as strings
;
; RETURN VALUE
;
; 0 if everything is ok,
; >0 if error
;
; VARIABLES / REGISTERS
;
; a int first operand eax
; b int second operand ebx
;
; -------------------------------------------------------------------
main:
push ebp
mov ebp, esp
push ebx
mov eax, [a]
mov ebx, [b]
.if:
cmp eax, ebx
jge .else
.then:
push dword msg_inf
call printf
add esp, 4
jmp .endif
.else:
push dword msg_supe
call printf
add esp, 4
.endif:
pop ebx
xor eax, eax ; 0 of return 0
mov esp, ebp
pop ebp
ret
2.3.2. Version avec affichage des valeurs
On reprend le programme précédent mais en affichant les valeurs de $a$ et $b$ :
// ===================================================================
// Program: if_then_else_v2.c
// Date: July 2020
// Author: Jean-Michel Richer
// Email: jean-michel.richer@univ-angers.fr
// ===================================================================
// Description:
// This program shows how to code a if-then-else statement in C
// and print the values of 'a' and 'b'.
// It is intended to be translated in 32 bits x86 assembly
// language.
// ===================================================================
#include <stdio.h>
#include <stdlib.h>
// global integer variables
int a = 1;
int b = 2;
/**
* main function
*/
int main(int argc, char *argv[]) {
if (a < b) {
} else {
}
return EXIT_SUCCESS;
}
Dont la traduction en assembleur en 32 bits est :
; ===================================================================
; Program: if_then_else_v2_nasm.asm
; Date: July 2020
; Author: Jean-Michel Richer
; Email: jean-michel.richer@univ-angers.fr
; ===================================================================
; Description:
; This program shows how to code a if then else statement.
; This second version prints the values of variables 'a' and 'b'
; ===================================================================
global main
extern printf
; ===================================================================
; ##### ## ##### ##
; # # # # # # #
; # # # # # # #
; # # ###### # ######
; # # # # # # #
; ##### # # # # #
; ===================================================================
section .data
a: dd 1
b: dd 2
msg_inf: db "%d < %d", 10, 0
msg_supe: db "%d >= %d", 10, 0
; ===================================================================
; #### #### ##### ######
; # # # # # # #
; # # # # # #####
; # # # # # #
; # # # # # # #
; #### #### ##### ######
; ===================================================================
section .text
; -------------------------------------------------------------------
; SUBPROGRAM
;
; int main(int argc, char *argv[])
;
; DESCRIPTION
;
; Main subprogram that compares variables 'a' and 'b'
;
; PARAMETERS
;
; argc int number of arguments of the program
; argv char *[] array of arguments as strings
;
; RETURN VALUE
;
; 0 if everything is ok,
; >0 if error
;
; VARIABLES / REGISTERS
;
; a int first operand eax
; b int second operand ebx
;
; -------------------------------------------------------------------
main:
push ebp
mov ebp, esp
push ebx
mov eax, [a]
mov ebx, [b]
.if:
cmp eax, ebx
jge .else
.then:
push ebx
push eax
push dword msg_inf
call printf
add esp, 12
jmp .endif
.else:
push dword [b] ; equivalent to push ebx
push dword [a] ; equivalent to push eax
push dword msg_supe
call printf
add esp, 12
.endif:
pop ebx
xor eax, eax ; 0 of return 0
mov esp, ebp
pop ebp
ret
2.3.3. Version avec saisie et affichage des valeurs
Traduire le programme suivant qui demande à l'utilisateur de saisir les valeurs
des variables entières $a$ et $b$ et affiche un message en fonction du fait que
$a < b$ :
// ===================================================================
// Program: if_then_else_v3.c
// Date: July 2020
// Author: Jean-Michel Richer
// Email: jean-michel.richer@univ-angers.fr
// ===================================================================
// Description:
// This program shows how to code a if-then-else statement in C.
// and print the values of 'a' and 'b'. First, the user is asked
// to provide the values of 'a' and 'b'.
// It is intended to be translated in 32 bits x86 assembly
// language.
// ===================================================================
#include <stdio.h>
#include <stdlib.h>
// global integer variables
int a = 0;
int b = 0;
/**
* main function
*/
int main(int argc, char *argv[]) {
if (a < b) {
} else {
}
return EXIT_SUCCESS;
}
Dont la traduction en assembleur en 32 bits est :
; ===================================================================
; Program: if_then_else_v3_nasm.asm
; Date: July 2020
; Author: Jean-Michel Richer
; Email: jean-michel.richer@univ-angers.fr
; ===================================================================
; Description:
; This program shows how to code a if then else statement.
; This third version asks the values of 'a' and 'b' and
; then prints them
; ===================================================================
global main
extern printf
extern scanf
; ===================================================================
; ##### ## ##### ##
; # # # # # # #
; # # # # # # #
; # # ###### # ######
; # # # # # # #
; ##### # # # # #
; ===================================================================
section .data
a: dd 1
b: dd 2
msg_inf: db "%d < %d", 10, 0
msg_supe: db "%d >= %d", 10, 0
msg_ask: db "a, b ? ", 0
msg_scanf: db "%d%d", 0
; ===================================================================
; #### #### ##### ######
; # # # # # # #
; # # # # # #####
; # # # # # #
; # # # # # # #
; #### #### ##### ######
; ===================================================================
section .text
; -------------------------------------------------------------------
; SUBPROGRAM
;
; int main(int argc, char *argv[])
;
; DESCRIPTION
;
; Main subprogram that compares variables 'a' and 'b'
;
; PARAMETERS
;
; argc int number of arguments of the program
; argv char *[] array of arguments as strings
;
; RETURN VALUE
;
; 0 if everything is ok,
; >0 if error
;
; VARIABLES / REGISTERS
;
; a int first operand eax
; b int second operand ebx
;
; -------------------------------------------------------------------
main:
push ebp
mov ebp, esp
push dword msg_ask
call printf
add esp, 4
push dword b
push dword a
push dword msg_scanf
call scanf
add esp, 4
push ebx
mov eax, [a]
mov ebx, [b]
.if:
cmp eax, ebx
jge .else
.then:
push ebx
push eax
push dword msg_inf
call printf
add esp, 12
jmp .endif
.else:
push dword [b] ; equivalent to push ebx
push dword [a] ; equivalent to push eax
push dword msg_supe
call printf
add esp, 12
.endif:
pop ebx
xor eax, eax ; 0 of return 0
mov esp, ebp
pop ebp
ret
2.4. Que retenir
Dans le cas d'un if avec une seule condition, on utilise la négation de la condition pour faire le saut conditionnel au niveau du label .endif ou du .else.
x < y |
jge |
Jump Greater or Equal |
x <= y |
jg |
Jump Greater |
x > y |
jle |
Jump Less or Equal |
x >= y |
jl |
Jump Less |
x == y |
jne |
Jump Not Equal |
x != y |
je |
Jump Equal |
Saut conditionnel complémentaire