Risposta breve: allo stesso modo di qualsiasi altro compilatore.
Risposta lunga: un programma che prende l'input del codice di programmazione in una lingua e lo trasforma in output in una lingua diversa è chiamato compiler . (Un assemblatore è un tipo speciale di compilatore la cui lingua di input è la lingua assembly e la cui lingua di output è il codice macchina.)
Il lavoro di un compilatore può essere descritto in generale come composto da tre fasi: analisi (lettura del codice e costruzione di una struttura dati interna che descrive ciò che dice), analisi semantica (assicurandosi che i dati analizzati siano effettivamente validi e determinanti cosa significhi) e generazione del codice (trasformando i dati analizzati nella lingua di output).
Per un assemblatore, la fase di analisi semantica probabilmente implicherebbe la ricerca di ogni nome di istruzione in una tabella, quindi chiamando un metodo con gli argomenti di quella istruzione per capire se corrisponde a uno qualsiasi degli insiemi di argomenti validi per quell'istruzione. Questo determina quale codice esadecimale userà. (Ad esempio, l'opcode esadecimale per MOV (register, register)
è diverso dall'opcode esadecimale per MOV (register, memory address)
anche se l'assembly mnemonico è lo stesso.)
Una volta che i dati di analisi sono stati annotati con dati semantici, il generatore di codice può esaminarli e leggere gli opcode hex e codificarli in output di codice macchina secondo le regole del linguaggio macchina del processore, sotto forma di flusso di numeri.
Non esiste un software che "lo converti in 1 e 0". Il software funziona a un livello di astrazione più alto; abbattere i numeri più grandi con cui lavora in bit avviene al livello hardware , dove è effettivamente implementato come "voltaggio più alto" e "voltaggio più basso". I numeri 1 e 0 sono solo per comodità, ma non hanno molto significato (a qualsiasi livello) in questi giorni.