Ricerca…


Osservazioni

Assembly è un nome generico utilizzato per molte forme di codice macchina leggibili dall'uomo. Differisce naturalmente molto tra diverse CPU (Central Processing Unit), ma anche sulla singola CPU possono esistere diversi dialetti incompatibili di Assembly, ciascuno compilato da un diverso assemblatore, nello stesso codice macchina definito dal creatore della CPU.

Se si desidera porre una domanda sul proprio problema di assemblaggio, indicare sempre cosa HW e quale assemblatore si sta utilizzando, altrimenti sarà difficile rispondere alla tua domanda in dettaglio.

L'apprendimento dell'Assemblaggio di una singola CPU particolare aiuterà a imparare le basi su diverse CPU, ma ogni architettura HW può avere notevoli differenze nei dettagli, quindi imparare ASM per una nuova piattaforma può essere vicino ad apprenderla da zero.

link:

X86 Assembly Wikibook

introduzione

Il linguaggio assembly è una forma leggibile dall'uomo di linguaggio macchina o codice macchina che è la sequenza effettiva di bit e byte su cui opera la logica del processore. È generalmente più facile per gli umani leggere e programmare in mnemonica che binario, ottale o esadecimale, quindi gli esseri umani tipicamente scrivono il codice in linguaggio assembly e quindi usano uno o più programmi per convertirlo nel formato della lingua macchina compreso dal processore.

ESEMPIO:

mov eax, 4
cmp eax, 5
je point

Un assemblatore è un programma che legge il programma in linguaggio assembly, lo analizza e produce il linguaggio macchina corrispondente. È importante capire che, a differenza di un linguaggio come C ++ che è una singola lingua definita nel documento standard, ci sono molti linguaggi di assemblaggio diversi. Ogni architettura del processore, ARM, MIPS, x86, ecc. Ha un codice macchina diverso e quindi un linguaggio di assemblaggio diverso. Inoltre, a volte esistono diversi linguaggi di assemblaggio per la stessa architettura del processore. In particolare, la famiglia di processori x86 ha due formati popolari che vengono spesso chiamati sintassi del gas ( gas è il nome dell'eseguibile per GNU Assembler) e sintassi Intel (dal nome del creatore della famiglia di processori x86). Sono diversi ma equivalenti in quanto si può scrivere in genere qualsiasi programma specificato in entrambe le sintassi.

Generalmente, l'inventore del processore documenta il processore e il relativo codice macchina e crea un linguaggio assembly. È comune che quel particolare linguaggio assembly sia l'unico utilizzato, ma a differenza dei compilatori che tentano di conformarsi a uno standard di linguaggio, il linguaggio assembly definito dall'inventore del processore è solitamente ma non sempre la versione utilizzata dalle persone che scrivono assemblatori .

Esistono due tipi generali di processori:

  • CISC (Computer set di istruzioni complesse): contiene molte e diverse istruzioni di linguaggio macchina complesse

  • RISC (Computer con set di istruzioni ridotto): al contrario, ha istruzioni meno numerose e più semplici

Per un programmatore di linguaggio assembly, la differenza è che un processore CISC può avere moltissime istruzioni da imparare, ma ci sono spesso istruzioni adatte per un particolare compito, mentre i processori RISC hanno meno istruzioni e più semplici ma qualsiasi operazione può richiedere il programmatore linguaggio assembly scrivere più istruzioni per ottenere lo stesso risultato.

Altri compilatori di linguaggi di programmazione a volte producono prima assembler, che viene quindi compilato in codice macchina chiamando un assemblatore. Ad esempio, gcc utilizza il proprio assemblatore di gas nella fase finale della compilazione. Il codice macchina prodotto è spesso memorizzato in file oggetto , che possono essere collegati in un eseguibile dal programma linker.

Una "toolchain" completa è spesso composta da un compilatore, un assemblatore e un linker. Si può quindi usare quell'assemblatore e il linker direttamente per scrivere programmi in linguaggio assembly. Nel mondo GNU il pacchetto binutils contiene l'assemblatore e il linker e gli strumenti correlati; coloro che sono interessati unicamente alla programmazione del linguaggio assembly non hanno bisogno di gcc o di altri pacchetti di compilatori.

Piccoli microcontrollori sono spesso programmati esclusivamente in linguaggio assembly o in una combinazione di linguaggio assembly e uno o più linguaggi di livello superiore come C o C ++. Ciò avviene perché spesso è possibile utilizzare gli aspetti particolari dell'architettura dell'insieme di istruzioni per tali dispositivi per scrivere un codice più compatto ed efficiente di quanto sarebbe possibile in un linguaggio di livello superiore e tali dispositivi spesso hanno memoria e registri limitati. Molti microprocessori sono utilizzati in sistemi embedded che sono dispositivi diversi dai computer di uso generale che hanno all'interno un microprocessore. Esempi di tali sistemi incorporati sono televisori, forni a microonde e l'unità di controllo del motore di un'automobile moderna. Molti di questi dispositivi non hanno tastiera o schermo, quindi un programmatore generalmente scrive il programma su un computer di uso generico, esegue un cross-assembler (così chiamato perché questo tipo di assemblatore produce codice per un diverso tipo di processore rispetto a quello su cui gira ) e / o un cross-compiler e cross linker per produrre codice macchina.

Esistono molti fornitori per tali strumenti, che sono tanto diversi quanto i processori per i quali producono codice. Molti, ma non tutti i processori hanno anche una soluzione open source come GNU, sdcc, llvm o altro.

Codice macchina

Il codice macchina è un termine per i dati in particolare formato macchina nativo, che vengono elaborati direttamente dalla macchina, solitamente dal processore chiamato CPU (Central Processing Unit).

L'architettura di computer comune (architettura di von Neumann ) è costituita da un processore per scopi generici (CPU), una memoria di uso generale, che memorizza sia il programma (ROM / RAM) sia i dati elaborati e i dispositivi di input e output (dispositivi I / O).

Il vantaggio principale di questa architettura è la relativa semplicità e universalità di ciascuno dei componenti - rispetto alle macchine informatiche precedenti (con un programma cablato nella costruzione della macchina), o architetture concorrenti (ad esempio l' architettura di Harvard che separa la memoria del programma dalla memoria di dati). Lo svantaggio è un po 'peggiore delle prestazioni generali. Nel lungo periodo l'universalità consentiva un utilizzo flessibile, che di solito superava il costo delle prestazioni.

In che modo questo si riferisce al codice macchina?

Programma e dati sono memorizzati in questi computer come numeri, nella memoria. Non esiste un modo genuino per distinguere il codice dai dati, quindi i sistemi operativi e gli operatori di macchina forniscono i suggerimenti della CPU, in base al quale il punto di ingresso della memoria avvia il programma, dopo aver caricato tutti i numeri nella memoria. La CPU legge quindi l'istruzione (numero) memorizzata al punto di ingresso e la elabora in modo rigoroso, leggendo sequenzialmente i numeri successivi come ulteriori istruzioni, a meno che il programma stesso non indichi alla CPU di continuare a eseguire altrove.

Ad esempio due numeri a 8 bit (8 bit raggruppati insieme sono uguali a 1 byte, ovvero un numero intero senza segno compreso nell'intervallo 0-255): 60 201 , quando eseguito come codice su Zilog Z80 CPU verrà elaborato come due istruzioni: INC a (valore incrementale nel registro a a a uno) e RET (di ritorno da sotto-routine, puntando la CPU per eseguire istruzioni da diverse parti della memoria).

Per definire questo programma, un essere umano può inserire tali numeri da qualche editor di memoria / file, ad esempio in hex-editor come due byte: 3C C9 (numeri decimali 60 e 201 scritti in codifica base 16). Sarebbe una programmazione in codice macchina .

Per rendere il compito della programmazione della CPU più facile per gli esseri umani, sono stati creati programmi di Assembler in grado di leggere file di testo contenenti qualcosa come:

subroutineIncrementA:
    INC   a
    RET

dataValueDefinedInAssemblerSource:
    DB    60          ; define byte with value 60 right after the ret

uscita di numeri esadecimali byte sequenza 3C C9 3C , avvolta con numeri aggiuntivi opzionali specifici per piattaforma di destinazione: contrassegnare quale parte di tale binario è codice eseguibile, dove è il punto di ingresso per il programma (la prima istruzione di esso), quali parti sono codificate dati (non eseguibili), ecc.

Si noti come il programmatore abbia specificato l'ultimo byte con il valore 60 come "dati", ma dal punto di vista della CPU non differisce in alcun modo da INC a byte. Spetta al programma in esecuzione passare correttamente la CPU sui byte preparati come istruzioni e elaborare i byte dei dati solo come dati per le istruzioni.

Tale output viene solitamente archiviato in un file sul dispositivo di archiviazione, caricato successivamente dal sistema operativo ( Sistema operativo - un codice macchina già in esecuzione sul computer, che aiuta a manipolare il computer ) in memoria prima dell'esecuzione, e infine puntando la CPU sul punto di ingresso del programma.

La CPU può elaborare ed eseguire solo il codice macchina, ma qualsiasi contenuto di memoria, anche casuale, può essere elaborato come tale, anche se il risultato può essere casuale, variando da " crash " rilevato e gestito dal sistema operativo fino alla cancellazione accidentale dei dati da I / O dispositivi o danni alle apparecchiature sensibili collegate al computer (non è un caso comune per i computer di casa :)).

Il processo simile è seguito da molti altri linguaggi di programmazione di alto livello, compilando il codice sorgente (forma di testo leggibile del programma) in numeri, o rappresentando il codice macchina (istruzioni native della CPU), o in caso di lingue interpretate / ibride in qualche generale codice macchina virtuale specifico della lingua, che viene ulteriormente decodificato in codice macchina nativo durante l'esecuzione da interprete o macchina virtuale.

Alcuni compilatori usano l'Assembler come fase intermedia della compilazione, traducendo l'origine prima in forma Assembler, quindi eseguendo lo strumento assembler per estrarre il codice macchina finale da esso (esempio GCC: eseguire gcc -S helloworld.c per ottenere una versione assembler del programma C helloworld.c ).

Ciao mondo per Linux x86_64 (Intel 64 bit)

section .data
    msg db "Hello world!",10      ; 10 is the ASCII code for a new line (LF)

section .text
    global _start

_start:
    mov rax, 1
    mov rdi, 1
    mov rsi, msg
    mov rdx, 13
    syscall
    
    mov rax, 60
    mov rdi, 0
    syscall

Se si desidera eseguire questo programma, è necessario prima Netwide Assembler , nasm , poiché questo codice utilizza la sua sintassi. Quindi utilizzare i seguenti comandi (supponendo che il codice sia nel file helloworld.asm ). Sono necessari per l'assemblaggio, il collegamento e l'esecuzione, rispettivamente.

  • nasm -felf64 helloworld.asm
  • ld helloworld.o -o helloworld
  • ./helloworld

Il codice fa uso di sys_write syscall di Linux. Qui puoi vedere un elenco di tutte le syscall per l'architettura x86_64. Quando prendi in considerazione anche le pagine man di write e exit , puoi tradurre il programma sopra in un C che fa lo stesso ed è molto più leggibile:

#include <unistd.h>

#define STDOUT 1

int main()
{
    write(STDOUT, "Hello world!\n", 13);
    _exit(0);
}

Qui sono necessari solo due comandi per la compilazione e il collegamento (il primo) e l'esecuzione:

  • gcc helloworld_c.c -o helloworld_c .
  • ./helloworld_c

Hello World per OS X (x86_64, Intel syntax gas)

.intel_syntax noprefix

.data

.align 16
hello_msg:
    .asciz "Hello, World!"

.text

.global _main
_main:
    push rbp
    mov rbp, rsp

    lea rdi, [rip+hello_msg]
    call _puts

    xor rax, rax
    leave
    ret

montare:

clang main.s -o hello
./hello

Gli appunti:

Esecuzione dell'assembly x86 in Visual Studio 2015

Passaggio 1 : creare un progetto vuoto tramite File -> Nuovo progetto .

inserisci la descrizione dell'immagine qui

Passaggio 2 : fare clic con il pulsante destro del mouse sulla soluzione del progetto e selezionare Crea dipendenze-> Crea personalizzazioni .

Passaggio 3 : selezionare la casella di controllo ".masm" .

inserisci la descrizione dell'immagine qui

Passaggio 4 : premere il pulsante "ok" .

Passaggio 5 : crea il file assembly e digita in questo:

.386
    .model small
        .code

            public main
                main proc

                    ; Ends program normally

                    ret
                main endp
            end main

Passaggio 6 : compilazione!

inserisci la descrizione dell'immagine qui



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow