[successivo] [precedente] [inizio] [fine] [indice generale] [indice ridotto] [indice analitico] [home] [volume] [parte]


Capitolo 552.   Primo approccio al linguaggio assemblatore per x86

Per scrivere programmi con il linguaggio assemblatore in un sistema GNU/Linux, è necessario disporre del compilatore: serve GNU AS(1) (GAS) per la sintassi AT&T oppure NASM(2) per quella Intel.

552.1   Il primo programma

Viene mostrato il listato di un programma molto semplice, il cui scopo è unicamente quello di concludere il proprio funzionamento restituendo un valore, attraverso una funzione del sistema operativo. Ne vengono preparate due versioni: una adatta a GNU AS e l'altra per NASM.

Listato 552.1. File fine-gas.s, adatto per GNU AS.

      1 #
      2 # fine-gas.s
      3 #
      4 .section .data
      5 #
      6 .section .text
      7 .globl _start
      8 #
      9 _start:
     10     mov  $1, %eax
     11     mov  $7, %ebx
     12     int  $0x80

Listato 552.2. File fine-nasm.s, adatto per NASM.

      1 ;
      2 ; fine-nasm.s
      3 ;
      4 section .data
      5 ;
      6 section .text
      7 global _start
      8 ;
      9 _start:
     10     mov eax, 1
     11     mov ebx, 7
     12     int 0x80

Per compilare il file si genera prima un file oggetto, quindi si passa per il linker (il «collegatore»), ovvero il programma che collega i file oggetto che devono comporre il file eseguibile finale. Si comincia con il sorgente per GNU AS:

as -o fine-gas.o fine-gas.s[Invio]

ld -o fine-gas fine-gas.o[Invio]

Per quanto riguarda il sorgente per NASM:

nasm -f elf -o fine-nasm.o fine-nasm.s[Invio]

ld -o fine-nasm fine-nasm.o[Invio]

In entrambi gli esempi, viene generato un file oggetto in formato ELF (Executable and linkable format), cosa che deve essere richiesta esplicitamente nel secondo caso, mentre nel primo è implicita. Pertanto, come si vede, il programma ld viene usato sempre nello stesso modo.

Il programma generato (fine-gas o fine-nasm) si limita a chiamare una funzione del sistema operativo, con la quale conclude il suo lavoro restituendo il valore numerico sette. Lo si può verificare ispezionando il parametro $? della shell:

./fine-gas[Invio]

echo $?[Invio]

7

I due programmi sono perfettamente uguali nel modo di disporsi nelle righe del file sorgente, pertanto vengono descritti senza fare distinzioni.

Le prime tre righe sono commenti, ignorati dal compilatore; la quarta riga contiene una direttiva per il compilatore che lo avverte dell'inizio della zona usata per descrivere l'uso della memoria (che in questo caso non viene usata affatto); la quinta riga è un altro commento; la sesta riga avverte il compilatore dell'inizio del codice del programma.

La settima riga serve ad avvisare il compilatore che l'etichetta denominata _start individua l'indirizzo dell'istruzione iniziale da rendere pubblica, pertanto deve rimanere rintracciabile nel file oggetto generato dalla compilazione. L'ottava riga è un altro commento e la nona riga dichiara l'etichetta _start già nominata.

Per il compilatore, l'etichetta _start rappresenta convenzionalmente il punto di inizio del programma e il simbolo corrispondente deve essere reso pubblico, perché ld deve sapere da che parte si comincia (soprattutto quando più file oggetto si collegano assieme in un solo eseguibile).

Nella decima riga si assegna il valore uno al registro EAX e nell'undicesima si assegna il valore sette al registro EBX; infine, nell'ultima riga, si esegue un'interruzione all'indirizzo 8016. In pratica, le ultime tre righe servono a eseguire la chiamata di una funzione del sistema operativo. La funzione è individuata dal numero uno che deve essere collocato nel registro EAX e il parametro, rappresentato dal valore di uscita, da collocare nel registro EBX. La chiamata effettiva avviene con l'interruzione all'indirizzo 8016.

Dopo aver compilato il programma e ottenuto il file eseguibile, si può dare un'occhiata al suo contenuto con l'aiuto di Objdump:(3)

objdump --disassemble fine-gas[Invio]

fine-gas:     file format elf32-i386

Disassembly of section .text:

08048074 <_start>:
 8048074:       b8 01 00 00 00          mov    $0x1,%eax
 8048079:       bb 07 00 00 00          mov    $0x7,%ebx
 804807e:       cd 80                   int    $0x80

Usato in questo modo, Objdump disassembla il programma e mostra anche le istruzioni nel linguaggio macchina vero e proprio, con gli indirizzi di memoria virtuale che verrebbero utilizzati durante il funzionamento. Eventualmente si può richiedere espressamente di disassemblare utilizzare una notazione Intel:

objdump --disassemble -M intel fine-gas[Invio]

fine-gas:     file format elf32-i386

Disassembly of section .text:

08048074 <_start>:
 8048074:       b8 01 00 00 00          mov    eax,0x1
 8048079:       bb 07 00 00 00          mov    ebx,0x7
 804807e:       cd 80                   int    0x80

552.2   Utilizzo di GDB

Per poter iniziare lo studio di un linguaggio assemblatore è praticamente indispensabile saper utilizzare un debugger, ovvero uno strumento che permetta di eseguire passo per passo il proprio programma, consentendo di verificare lo stato dei registri ed eventualmente della memoria. Infatti, con un linguaggio assemblatore, operazioni «semplici» come l'emissione di informazioni attraverso lo schermo diventano invece molto complicate.

Nei sistemi GNU è disponibile GDB (GNU debugger)(4). Per capire come utilizzarlo, si prenda nuovamente l'esempio di programma introduttivo, aggiungendo qualche piccola modifica:

      1 #
      2 # fine-gas.s
      3 #
      4 .section .data
      5 #
      6 .section .text
      7 .globl _start
      8 #
      9 _start:
     10     mov  $1, %eax
     11 bp1:
     12     mov  $7, %ebx
     13 bp2:
     14     int  $0x80
      1 ;
      2 ; fine-nasm.s
      3 ;
      4 segment .data
      5 ;
      6 segment .text
      7 global _start
      8 ;
      9 _start:
     10     mov eax, 1
     11 bp1:
     12     mov ebx, 7
     13 bp2:
     14     int 0x80

Rispetto al file originale sono state aggiunge due etichette, bp1 e bp2 (il cui nome è stato scelto arbitrariamente, ma in questo caso ricorda il termine breakpoint), collocate tra le istruzioni che si traducono in codici del linguaggio macchina. Naturalmente, il file va ricompilato nel modo già descritto; poi, una volta ottenuto il file eseguibile, lo si avvia all'interno di GDB:

gdb fine-gas[Invio]

GNU gdb 6.5-debian
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...(no debugging symbols found)
Using host libthread_db library "/lib/tls/libthread_db.so.1".

A questo punto GDB presenta un invito, dal quale è possibile inserire dei comandi in modo interattivo.

(gdb) 

Di solito, la prima cosa da fare consiste nel definire degli «stop» (breakpoint), dove il programma deve essere fermato automaticamente. È per questa ragione che sono state aggiunte delle etichette nel sorgente: per poter associare a quelle dei punti di sospensione dell'esecuzione.

(gdb) break bp1[Invio]

Breakpoint 1 at 0x8048079

(gdb) break bp2[Invio]

Breakpoint 2 at 0x804807e

Una volta fissati gli stop, si può «avviare» il programma, che viene così sospeso in corrispondenza del primo di questi punti:

(gdb) run[Invio]

Starting program: /home/tizio/fine-gas
(no debugging symbols found)

Breakpoint 1, 0x08048079 in bp1 ()

Si ispezionano i registri:

(gdb) info registers[Invio]

eax            0x1      1
ecx            0x0      0
edx            0x0      0
ebx            0x0      0
esp            0xbff50080       0xbff50080
ebp            0x0      0x0
esi            0x0      0
edi            0x0      0
eip            0x8048079        0x8048079 <bp1>
eflags         0x292    [ AF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x0      0

Si può verificare che il registro EAX contiene il valore uno, come dovrebbe effettivamente in questa posizione. Per far proseguire il programma fino al prossimo stop si usa il comando continue:

(gdb) continue[Invio]

Breakpoint 2, 0x0804807e in bp2 ()

Si ispezionano nuovamente i registri:

(gdb) info registers[Invio]

eax            0x1      1
ecx            0x0      0
edx            0x0      0
ebx            0x7      7
esp            0xbfcefe20       0xbfcefe20
ebp            0x0      0x0
esi            0x0      0
edi            0x0      0
eip            0x804807e        0x804807e <bp2>
eflags         0x292    [ AF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x0      0

Si può vedere che a questo punto il registro EBX risulta impostato con il valore previsto. Si lascia concludere il programma e si termina l'attività con GDB:

(gdb) continue[Invio]

Continuing.

Program exited with code 07.

(gdb) quit[Invio]

Il procedimento descritto vale per il programma compilato nel modo «normale», sia attraverso GNU AS, sia attraverso NASM. Ma per avere una visione più chiara di ciò che si fa, occorre abbinare il sorgente originale. Questo può essere fatto con GNU AS, utilizzando l'opzione --gstabs, oppure con NASM mettendo l'opzione -g. Qui si mostra solo il caso di GNU AS:

as --gstabs -o fine-gas.o fine-gas.s[Invio]

ld -o fine-gas fine-gas.o[Invio]

gdb fine-gas[Invio]

GNU gdb 6.5-debian
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...(no debugging symbols found)
Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) break bp1[Invio]

Breakpoint 1 at 0x8048079: file fine-gas.s, line 12.

(gdb) break bp2[Invio]

Breakpoint 2 at 0x804807e: file fine-gas.s, line 14.

(gdb) run[Invio]

Starting program: /home/tizio/fine-gas

Breakpoint 1, bp1 () at fine-gas.s:12
12          mov  $7, %ebx
Current language:  auto; currently asm

Come si vede dall'esempio, si ottengono più informazioni collegate al sorgente originale; in particolare si può sapere qual è la prossima istruzione che verrebbe eseguita. Questa volta si decide di procedere eseguendo un'istruzione alla volta, con il comando stepi:

(gdb) stepi[Invio]

bp2 () at fine-gas.s:14
14          int  $0x80

Dato che il programma è molto breve, con la prossima istruzione si va a concluderne il funzionamento:

(gdb) stepi[Invio]

Program exited with code 07.

(gdb) quit[Invio]

Tabella 552.22. Alcuni comandi interattivi per GDB.

Comando Descrizione
set args argomento...
Definisce gli argomenti della riga di comando del programma.
r [argomento]...
run [argomento]...
Avvia l'esecuzione del programma, eventualmente con gli argomenti indicati.
b funzione
break funzione
Definisce uno stop all'esecuzione del programma in corrispondenza dell'etichetta indicata. Questa etichetta viene definita precisamente «funzione» in quanto riguarda la zona che descrive le istruzioni del programma e non quelle dei dati.
b riga
break riga
Definisce uno stop all'esecuzione del programma in corrispondenza della riga indicata, riferita al file sorgente. Per poter usare questo comando occorre compilare il programma con i riferimenti al file sorgente.
cl [funzione]
clear [funzione]
Elimina uno stop associato a una certa etichetta, oppure, se c'è, elimina quello della posizione corrente.
cl riga
clear riga
Elimina uno stop associato alla riga indicata.
d [n]...
disable [n]...
Disabilita gli stop indicati per numero, o tutti se non ne viene indicato alcuno.
enable [n]...
Riabilita gli stop indicati per numero, o tutti se non ne viene indicato alcuno.
d [n]...
delete [n]...
Elimina gli stop indicati per numero, o tutti se non ne viene indicato alcuno.
si
stepi
Esegue la prossima istruzione-macchina e poi si ferma nuovamente. Se l'istruzione è una chiamata di funzione, passa all'inizio della stessa.
ni
nexti
Esegue la prossima istruzione-macchina e poi si ferma nuovamente. Se l'istruzione è una chiamata di funzione, questa viene saltata.
c
continue
Riprende l'esecuzione di un programma dopo uno stop (che può poi fermarsi nuovamente allo stop successivo, se c'è).
kill
Interrompe definitivamente l'esecuzione del programma.
i r
info registers
Mostra lo stato dei registri.
bt
backtrace
Mostra lo stato della pila, precisamente mostra gli elementi che compongono lo stack frame.
p [/f] [(tipo)]variabile
print [/f] [(tipo)]variabile
Mostra il valore contenuto in memoria, in corrispondenza dell'etichetta specificata (variabile). Se non si tratta di una variabile scalare di dimensione «standard», occorre specificarne il formato, tra parentesi tonde, esattamente prima del nome; se si vuole visualizzare il valore contenuto nella variabile in modo diverso da quello predefinito, occorre aggiungere l'opzione /f, dove la lettera f specifica il tipo di rappresentazione.
p /f (tipo[n])variabile
print /f (tipo[n])variabile
Se nella definizione del formato si mette un valore numerico tra parentesi quadre, si intende visualizzare n valori di quel tipo a partire dalla posizione indicata dal nome della variabile. Ciò consente di visualizzare il contenuto di un array.

552.3   Modalità «TUI»

GDB, se è stato compilato per includere tale funzionalità, può essere usato con l'opzione -tui, con la quale si ottiene una suddivisione dello schermo in finestre:

gdb -tui fine-gas[Invio]

   +--fine-gas.s---------------------------------------------------------------+
   |10          mov  $1, %eax                                                  |
   |11      bp1:                                                               |
   |12          mov  $7, %ebx                                                  |
   |13      bp2:                                                               |
   |14          int  $0x80                                                     |
   |15                                                                         |
   |16                                                                         |
   |17                                                                         |
   |18                                                                         |
   |19                                                                         |
   |20                                                                         |
   |21                                                                         |
   |22                                                                         |
   |23                                                                         |
   +---------------------------------------------------------------------------+
exec No process In:                                          Line: ??   PC: 0x0
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...Using host libthread_db library "/
lib/tls/libthread_db.so.1".

(gdb) break bp1[Invio]

(gdb) break bp2[Invio]

   +--fine-gas.s---------------------------------------------------------------+
   |10          mov  $1, %eax                                                  |
   |11      bp1:                                                               |
b+ |12          mov  $7, %ebx                                                  |
   |13      bp2:                                                               |
b+ |14          int  $0x80                                                     |
   |15                                                                         |
   |16                                                                         |
   |17                                                                         |
   |18                                                                         |
   |19                                                                         |
   |20                                                                         |
   |21                                                                         |
   |22                                                                         |
   |23                                                                         |
   +---------------------------------------------------------------------------+
exec No process In:                                          Line: ??   PC: 0x0
This GDB was configured as "i486-linux-gnu"...Using host libthread_db library "/
lib/tls/libthread_db.so.1".

(gdb) break bp1
Breakpoint 1 at 0x8048079: file fine-gas.s, line 12.
(gdb) break bp2
Breakpoint 2 at 0x804807e: file fine-gas.s, line 14.

(gdb) run[Invio]

   +--fine-gas.s---------------------------------------------------------------+
   |10          mov  $1, %eax                                                  |
   |11      bp1:                                                               |
B+>|12          mov  $7, %ebx                                                  |
   |13      bp2:                                                               |
b+ |14          int  $0x80                                                     |
   |15                                                                         |
   |16                                                                         |
   |17                                                                         |
   |18                                                                         |
   |19                                                                         |
   |20                                                                         |
   |21                                                                         |
   |22                                                                         |
   |23                                                                         |
   +---------------------------------------------------------------------------+
child process 9699 In: bp1                             Line: 12   PC: 0x8048079
(gdb) break bp2
Breakpoint 2 at 0x804807e: file fine-gas.s, line 14.
(gdb) run
Starting program: /home/tizio/fine-gas

Breakpoint 1, bp1 () at fine-gas.s:12
Current language:  auto; currently asm

Durante il funzionamento si può anche attivare una finestra con lo stato dei registri, attraverso il comando layout reg:

(gdb) layout reg[Invio]

+--Register group: general-----------------------------------------------------+
|eax            0x1      1                                                     |
|ecx            0x0      0                                                     |
|edx            0x0      0                                                     |
|ebx            0x0      0                                                     |
|esp            0xbfa77b90       0xbfa77b90                                    |
|ebp            0x0      0x0                                                   |
+------------------------------------------------------------------------------+
   |10          mov  $1, %eax                                                  |
   |11      bp1:                                                               |
B+>|12          mov  $7, %ebx                                                  |
   |13      bp2:                                                               |
b+ |14          int  $0x80                                                     |
   |15                                                                         |
   |16                                                                         |
   +---------------------------------------------------------------------------+
child process 9699 In: bp1                             Line: 12   PC: 0x8048079
Breakpoint 2 at 0x804807e: file fine-gas.s, line 14.
(gdb) run
Starting program: /home/tizio/fine-gas

Breakpoint 1, bp1 () at fine-gas.s:12
Current language:  auto; currently asm
(gdb) layout reg

(gdb) quit[Invio]

Durante il funzionamento normale di GDB, se è prevista tale modalità di funzionamento, questa può essere attivata anche con la combinazione di tasti [Ctrl x][a].

552.4   Utilizzo di DDD

GDB è lo strumento fondamentale per il controllo del funzionamento di un programma, ma al suo fianco se ne possono aggiungere altri che consentono di avere una visione più «semplice». Per esempio, DDD,(5) ovvero Data display debugger è un programma frontale che si avvale di GDB, ma lo fa attraverso un'interfaccia grafica che consente di tenere sotto controllo più cose, simultaneamente.

ddd fine-gas[Invio]

Prendendo lo stesso esempio di programma già usato nella sezione precedente, compilato in modo da avere i riferimenti al sorgente, ecco come si può presentare DDD dopo che sono stati fissati gli stop e dopo che il programma è stato avviato, in modo che si arresti al primo di questi:

ddd durante il funzionamento

Ecco la situazione al livello del secondo stop:

ddd durante il funzionamento

552.5   Alcune istruzioni comuni

Le istruzioni del linguaggio assemblatore che si traducono direttamente in istruzioni del linguaggio macchina hanno una forma uniforme: un nome mnemonico seguito dagli operandi.

mnemonico operando[, operando]...

Per esempio, l'istruzione seguente sottrae il valore contenuto nel registro EAX da quello di EBX, mettendo il risultato nel registro EBX (EBX=EBX-EAX):

GNU AS sub %eax, %ebx

NASM sub ebx, eax

In questo caso il nome mnemonico è SUB, mentre i nomi dei registri sono gli operandi (eventualmente, il codice corrispondente in linguaggio macchina sarebbe 29C316). Nelle sezioni successive si descrivono alcune istruzioni comuni.

552.5.1   MOV

L'istruzione MOV serve a copiare il contenuto dell'origine nella destinazione. Gli operandi possono essere registri, aree di memoria e costanti numeriche, tenendo conto che le costanti numeriche possono figurare solo nell'origine e che si può fare riferimento ad aree di memoria in una sola posizione (nell'origine o nella destinazione).

GNU AS mov origine, destinazione

NASM mov destinazione, origine

L'esempio seguente copia il contenuto del registro EAX all'interno di EBX:

GNU AS mov %eax, %ebx

NASM mov ebx, eax

552.5.2   ADD

L'istruzione ADD serve a eseguire la somma di valori interi, con o senza segno. Gli operandi possono essere registri, aree di memoria e costanti numeriche, tenendo conto che le costanti numeriche possono figurare solo nell'origine e che si può fare riferimento ad aree di memoria in una sola posizione: nell'origine o nella destinazione.

GNU AS add origine, destinazione

NASM add destinazione, origine

L'esempio seguente aggiunge al registro EAX una unità:

GNU AS add $1, %eax

NASM add eax, 1

552.5.3   SUB

L'istruzione SUB serve a eseguire la sottrazione di valori interi, con o senza segno. Gli operandi possono essere registri, aree di memoria e costanti numeriche, tenendo conto che le costanti numeriche possono figurare solo nell'origine e che si può fare riferimento ad aree di memoria in una sola posizione: nell'origine o nella destinazione.

GNU AS sub origine, destinazione

NASM sub destinazione, origine

L'esempio seguente sottrae il valore del registro EAX da quello di EBX, mettendo il risultato in EBX:

GNU AS sub %eax, %ebx

NASM sub ebx, eax

552.5.4   INC e DEC

Le istruzioni INC e DEC servono, rispettivamente, a incrementare e a decrementare di una unità il valore dell'operando, che può essere un registro o un'area di memoria. Dal momento che c'è un solo operando, non c'è differenza tra la sintassi di GNU AS e di NASM per quanto riguarda l'ordine degli stessi:

inc destinazione

dec destinazione

I due esempi seguenti, rispettivamente, incrementano e decrementano di una unità il valore del registro EAX:

552.6   Dimensione dei dati nelle istruzioni

Di norma, nelle istruzioni che elaborano dati, come quelle descritte nelle sezioni precedenti, se un registro si trova a essere origine o destinazione di qualcosa, implicitamente si intende che i dati debbano essere della sua dimensione. Per esempio, scrivendo mov $1, %eax si intende che la costante numerica sia precisamente 0000 000116 (ovvero 0000 0000 0000 0000 0000 0000 0000 00012), perché la destinazione è da 32 bit.

Quando il contesto non è sufficiente a stabilire di quanti bit deve essere fatto il valore che si elabora, l'istruzione va precisata. Nel caso di GNU AS si aggiunge un suffisso al nome mnemonico che distingue l'operazione, suffisso che è composto da una sola lettera. Per esempio, mov diventa movl per chiarire che si tratta di dati da 32 bit. Nel caso di NASM si aggiunge una parola chiave dopo il nome mnemonico.

Tabella 552.29. Suffissi per precisare la quantità di bit coinvolti nelle istruzioni, secondo la sintassi di GNU AS. Negli esempi, mem è un'etichetta che rappresenta un indirizzo di memoria.

Suffisso Significato Dimensione in bit Esempi
b
byte 8 bit

mov $1 %al

movb $1 mem

pushb mem

w
word 16 bit

mov $1 %ax

movw $1 mem

pushw mem

l
long 32 bit

mov $1 %eax

movl $1 mem

pushl mem

Tabella 552.30. Parole chiave per precisare la quantità di bit coinvolti nelle istruzioni, secondo la sintassi di NASM. Negli esempi, mem è un'etichetta che rappresenta un indirizzo di memoria.

Parola chiave Dimensione in bit Esempi
byte
8 bit

mov al, 1

mov byte [mem], 1

push byte [mem]

word
16 bit

mov ax, 1

mov word ax, 1

mov word [mem], 1

push word [mem]

long
32 bit

mov eax, 1

mov long [mem], 1

push long [mem]

552.7   Direttive per il compilatore

Nel sorgente in linguaggio assemblatore è possibile inserire delle direttive (o pseudoistruzioni) che il compilatore può interpretare per la costruzione corretta del file oggetto. Si usano queste direttive in particolare per definire delle costanti e delle aree di memoria.

552.7.1   Commenti

Le righe vuote e quelle bianche vengono ignorate dal compilatore; inoltre, è possibile inserire dei commenti preceduti da un carattere che viene riconosciuto come prefisso, con il quale si annulla il significato di ciò che appare da quel punto fino alla fine della riga:

GNU AS #commento

NASM ;commento

552.7.2   Direttiva «equ»

La direttiva equ viene usata per definire delle costanti simboliche (attraverso un nome, ovvero un'etichetta) da utilizzare poi nelle istruzioni, al posto del dato corrispondente. In linea di principio non dovrebbe essere possibile ridefinire le costanti.

GNU AS .equ nome, valore

NASM nome equ valore

Nell'esempio seguente si associa al simbolo ADDRESS il numero otto:

GNU AS .equ ADDRESS, 8

NASM ADDRESS equ 8

552.7.3   Direttive di dichiarazione dei dati

Attraverso delle direttive del compilatore si definiscono delle aree di memoria, a cui si fa riferimento nelle istruzioni attraverso dei nomi simbolici (etichette). In questo modo il compilatore attribuisce il loro indirizzo e lo sostituisce nella fase di assemblaggio. Si distingue tra dati che devono essere inizializzati preventivamente con un certo valore e dati il cui valore iniziale è indifferente. Quando si tratta di dati privi di valore iniziale, le informazioni necessarie consistono solo nel nome e nella dimensione dell'area di memoria:

GNU AS .lcomm nome, dimensione_in_byte

NASM nome resb dimensione_in_byte

NASM nome resw dimensione_in_multipli_di_16_bit

NASM nome resd dimensione_in_multipli_di_32_bit

Segue la descrizione di alcuni esempi.

Quando si tratta di dati da inizializzare, le informazioni necessarie alla dichiarazione consistono nel nome e nel contenuto, mentre la dimensione deriva dalla pseudoistruzione scelta:

GNU AS nome: .ascii stringa[, stringa]...

GNU AS nome: .byte byte[, byte]...

GNU AS nome: .int intero[, intero]...

NASM nome db byte[, byte]

NASM nome dd intero[, intero]

Segue la descrizione di alcuni esempi.

552.8   Sezioni del sorgente

Il sorgente si suddivide in sezioni, le quali descrivono la struttura del file-oggetto che si deve andare a produrre. Per quanto riguarda il formato ELF di un sistema GNU/Linux, si distingue l'area del codice, da quella dei dati; inoltre, nell'ambito dei dati si distingue la parte di quelli preinizializzati e di quelli che non lo sono.(6)

.section .data
    dichiarazione_dati_inizializzati
.section .bss
    dichiarazione_dati_non_definiti
.section .text
    istruzioni_del_programma
section .data
    dichiarazione_dati_inizializzati
section .bss
    dichiarazione_dati_non_definiti
section .text
    istruzioni_del_programma

I due modelli sintattici si riferiscono rispettivamente a GNU AS e a NASM.

552.9   Usare GNU AS con la notazione Intel

È possibile chiedere al compilatore GNU AS di interpretare il sorgente secondo la sintassi «Intel». Per questo si usa la direttiva .intel_syntax noprefix (l'opzione noprefix serve a consentire di annotare i nomi dei registri senza il prefisso %). L'esempio visto all'inizio del capitolo potrebbe essere modificato nel modo seguente:

#
.section .data
#
.section .text
.globl _start
#
.intel_syntax noprefix
_start:
    mov  eax, 1
    mov  ebx, 7
    int  0x80

La direttiva fa sì che il sorgente venga interpretato secondo la sintassi Intel a partire dal punto in cui si trova. Dal momento che l'effetto riguarda solo l'interpretazione delle istruzioni di codice che si traduce in linguaggio macchina (pertanto il modo di dare le altre direttive continua a essere quello normale di GNU AS), è conveniente piazzare la direttiva .intel_syntax noprefix all'inizio della sezione .text, come si vede nell'esempio.

Naturalmente è possibile tornare alla sintassi AT&T con una direttiva analoga: .att_syntax. Lo si può vedere nell'esempio successivo:

#
.section .data
#
.section .text
.globl _start
#
.intel_syntax noprefix
_start:
    mov  eax, 1
.att_syntax
    mov  $7, %ebx
    int  $0x80

552.10   Riferimenti


1) GNU Binutils   GNU GPL

2) NASM   GNU LGPL

3) GNU Binutils   GNU GPL

4) GDB   GNU GPL

5) DDD   GNU GPL

6) Il formato ELF prevede altri tipi di sezione, ma quelle di uso più frequente sono rappresentate nel modello sintattico.


Appunti di informatica libera 2008 --- Copyright © 2000-2008 Daniele Giacomini -- <appunti2 (ad) gmail·com>


Dovrebbe essere possibile fare riferimento a questa pagina anche con il nome primo_approccio_al_linguaggio_assemblatore_per_x86.htm

[successivo] [precedente] [inizio] [fine] [indice generale] [indice ridotto] [indice analitico] [home]

Valid ISO-HTML!

CSS validator!

Gjlg Metamotore e Web Directory