O exemplo de código que é apresentado abaixo está escrito na linguagem Assembly 386 e corre em qualquer processador compatÃvel com o Intel 80386 ou superior (Pentium, xCore, etc.). Tem que ser compilado com o NASM em ambiente Linux.
É uma programa simples que define uma variável (msg) com conteúdo de texto (string) e uma constante (len). Depois invoca o sistema operativo (int 0x80) para mandar imprimir a string e termina invocando a função EXIT.
A label _start tem que ser declarada pública (global _start) e aponta para a primeira instrução de código do programa.
len    equ    $ – msg                ;length of our dear string
section .text                          ;section declaration
;we must export the entry point to the ELF linker or
global _start      ;loader. They conventionally recognize _start as their
;entry point. Use ld -e foo to override the default.
_start:
;write our string to stdout
mov    edx,len ;third argument: message length
mov    ecx,msg ;second argument: pointer to message to write
mov    ebx,1  ;first argument: file handle (stdout)
mov    eax,4  ;system call number (sys_write)
int    0x80   ;call kernel
;and exit
mov    ebx,0  ;first syscall argument: exit code
mov    eax,1  ;system call number (sys_exit)
int    0x80   ;call kernel
Na secção .data são declaradas as variáveis inicializadas. Neste caso, é declarada a variável msg do tipo vetor de bytes. A diretiva db significa define byte e indica que se pretende definir uma variável do tipo byte (ou seja com um tamanho de 8 bits) ou uma sequência de bytes, que é o caso da variável msg, que contém a string “Olá Mundo” seguida do caráter 0xA, ou seja, o caráter 10 (da codificação ASCII, que representa o caráter newline, de mudança de linha). [Nota: o prefixo “0x” indica que o número seguinte está no formato hexadecimal, logo 0xA = 10]
Logo abaixo da variável msg define-se a constante len. As constantes são definidas à custa da diretiva equ (equal, ou seja, igual). Neste caso, o valor da constante len é definido de forma dinâmica. O sÃmbolo $ significa o endereço da posição onde o $ aparece. Por outro lado, uma vez que os nomes das variáveis em Assembly são todos apontadores, o nome msg contém o endereço da string “Olá Mundo”, ou seja, o endereço da letra ‘O’. Assim, a diferença $-msg contém o tamanho da string “Olá Mundo”,0xA, ou seja 10 carateres.
A secção .text é a secção de código. Como foi dito atrás, este programa executa apenas duas ações: imprime uma string no ecrã e termina a execução do programa.
Qualquer dessas ações deve ser executada pelo sistema operativo, uma vez que o processador apenas sabe efetuar cálculos e comunicar com a memória central. O processador também pode comunicar com os dispositivos periféricos, mas apenas em baixo nÃvel: não conhece os protocolos que permitam fazer um uso útil desses periféricos (esse é o objetivo dos drivers).
Estas duas ações estão codificadas considerando o sistema operativo Linux. Para efetuá-las é necessário invocar duas funções de sistema: a função WRITE e a função EXIT.
A sintaxe de chamada destas funções pode ser representada pelo pseudocódigo seguinte:
// write - writes data via a file handle. procedure linux.write( fd:dword; var buf:var; count:linux.size_t ); begin write; linux.pushregs; mov( linux.sys_write, eax ); mov( fd, ebx ); mov( buf, ecx ); mov( count, edx ); int( $80 ); linux.popregs; end write; procedure linux._exit( status:int32 ); begin _exit; mov( [esp+4], ebx ); // Get the status value mov( linux.sys_exit, eax ); // exit opcode. int( $80 ); // Does not return! end _exit;
A instrução int 0x80 invoca o sistema operativo. O sistema operativo consulta o registo eax para saber que função de sistema foi invocada. No primeiro caso é invocada a função número 4, ou seja, a função WRITE; no segundo caso é invicada a função número 1, ou seja, a função EXIT. Nos outros registos (ebx, ecx, e edx) são passados (caso seja necessário) os restantes parâmetros necessários à execução da função.
Na função WRITE, é passado o valor 1 no registo ebx, indicando que se pretende escrever no ficheiro número 1, ou seja, no stdout (o ecrã). No registo ecx coloca-se o endereço da string a escrever, e no registo edx, o tamanho dessa string.
Na função EXIT, é passado o valor 0 (código de erro ou código de retorno) no registo ebx, indicando que o programa terminou corretamente.