Approfondimenti sull’ Assembly

Nell’ assembly per il DOS, la maggior parte delle azioni sono fatte chiamando l’ int 21h dei servizi del DOS, oppure chiamando gli analoghi del BIOS come ad esempio int 10h e int 16h.

Con Linux, tutte queste funzioni sono gestite dal kernel tramite kernel system calls, e il kernel viene chiamato con int 80.

Linux è un sistema operativo protetto a 32 bit: non bisogna preoccuparsi dei segmenti di memoria, le cose sono di molto semplificate.

Le parti di un programma

  • Sezione .data: contiene le dichiarazioni di inizializzazione dei dati, i quali non potranno essere modificati successivamente, cosicchè non potranno essere considerati delle vere e proprie variabili.
    Esempio:

    section .data
    	message:    db 'Hello world!'     ; dichiara un dato che contiene bytes (caratteri ASCII)
    	msglength:  equ 12                ; dichiara una costante
    	buffersize: dw 1024               ; dichiara un dato di tipo word
    
  • Sezione .text: è la sezione in cui scrivere le istruzioni; deve iniziare obbligatoriamente con global _start, che è l’ analogo del main() in C: il kernel cercherà questo punto di inizio.
    section .text
    	global _start
    
    _start:
    	pop    ebx
            ...
    
  • Sezione .bss: vi si possono dichiarare le variabili, riservando uno spazio non inizializzato di memoria per ciascuna di esse.
    section .bss
    	filename:   resb    255           ; 255 bytes
    	number:     resb    1             ; 1 byte
    	bignum:     resw    1             ; 1 word (1 word = 2 bytes)
    	realarray:  resq    10            ; array of 10 reals
    

Linux System Calls

Per effettuare una chiamata, di norma si pone il numero della chiamata in EAX e gli argomenti nei restanti registri (nell’ ordine di utilizzo: EBX, ECX, EDX, ESI, EDI, EBP), si chiama l’ interrupt del kernel 80h. Il risultato è generalmente ritornato in EAX.
Ecco una tabella con le system calls: http://www.cin.ufpe.br/~if817/arquivos/asmtut/syscalls.html.

Concetti avanzati

Calcolo della lunghezza di una stringa:

section .data
	hello:     db 'Hello world!',10    ; 'Hello world!' plus a linefeed character
	helloLen:  equ $-hello             ; Length of the 'Hello world!' string

la costante $-hello si legge in questo modo: NASM (o YASM) sostituisce al simbolo $ la posizione dell’ assembly all’ inizio della riga che lo contiene, il che equivale alla fine della riga precedente. Sottraendogli la posizione iniziale di una variabile, si ottiene la lunghezza della variabile stessa.
La documentazione di NASM contiene altri trucchi simili.

Argomenti sulla linea di comando

Passando degli argomenti ad un programma assemblato e linkato, li ritroviamo nello stack, quindi per ottenerli basta un semplice pop: ad esempio

# supponiamo di avere ./mioprogramma foo bar 42
section .text
	global _start

_start:
	pop	eax		; Get the number of arguments
	pop	ebx		; Get the program name....lo sovrascrivo con la seguente
	pop	ebx		; Get the first actual argument ("foo")
	pop	ecx		; "bar"
	pop	edx		; "42"....attenzione: è una stringa, non un intero !

	mov	eax,1
	mov	ebx,0
	int	80h		; Exit

Label e jump

In assembly non esistono “procedure”, ma si usano etichette e salti.
Con i test condizionali si può “saltare” ad un’ etichetta.
Invece con il comando call si può “chiamare” un’ etichetta.

Pretare molta attenzione a questa differenza: se si salta ad un’ etichetta che contiene ret si avrà un segmentation fault (con Linux).
Viceversa, se dopo un’ etichetta c’è ret, allora bisogna chiamarla con call.

Per chiarire, vediamo come si scrive un banale if-then-else in assembly:

/*
 * Si vuole scrivere in assembly il seguente test:
 *
 * if (AX == 'w') {
 * 	   writeFile();
 * 	} else {
 * 	   doSomethingElse();
 * 	}
 */
cmp	AX,'w'		; Does AX contain 'w'?
jne	skipWrite	; If not, skip writing by jumping to another label, and doSomethingElse there...
call	writeFile	; ...else call the writeFile procedure...
jmp	outOfThisMess	; ...and jump past all of this spaghetti

skipWrite:
	call	doSomethingElse
outOfThisMess:
	...			; The rest of the program goes on here

; proc fileWrite - write a string to a file
fileWrite:
   mov eax,4               ; write system call
   mov ebx,[filedesc]      ; File descriptor
   mov ecx,stuffToWrite
   mov edx,[stuffLen]
   int 80h
   ret
; endp fileWrite

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...