# Questo programmino legge un carattere da tastiera, # lo stampa a video, stampa la stringa "->" e poi stampa # il carattere successivo. # # Esempio: # Se come input si inserisce 'm', stampera' la stringa # "m->n" .data .text _main: call inchar call outchar push %eax mov $'-', %al call outchar mov $'>', %al call outchar pop %eax inc %al # incremento il carattere call outchar call newline call exit # .INCLUDE C:\amb_GAS\utility # questa riga non serve ed # e' pertanto commentata ############################################################# # Libreria "utility", per Linux a 32 bit # Universita' di Pisa, Scuola di Ingegneria ############################################################# .global output output: push %eax # Salvo lo stato dei registri prima della chiamata push %ebx push %ecx push %edx mov %al, _msg_ # muovo il byte contenuto nel registro al nella posizione di memoria _msg_, passaggio neccesario per # poterlo mettere in output, in quanto l'indirizzo deve essere nel registro ecx xor %eax,%eax # pulisco i registro Setto a zero il valore xor %ecx, %ecx movl $SYS_WRITE, %eax # Chiamo la system_call int write ( int fd, const void * buffer, size_t size) movl $STDOUT, %ebx # file di uscita standard 1 movl $_msg_ , %ecx # Muovo dall'indirizzo _msg_ nel registro ecx movl $1, %edx # Grandezza stringa da mettere in output int $SYSTEM_CALL_LINUX #ripristino lo stato dei registri aalo stadio precedente pop %edx pop %ecx pop %ebx pop %eax ret #RITORNO AL PROGRAMMA PRINCIPALE #----------------------------------------------------------------------------------------------------------------------------------------------------------- ####################################################################################################### # INPUT : # # Legge una codifica ascii dalla tastiera e la mette nel registro al, questa versione # # della funzione input richiede la pressione del tasto INVIO dopo l'inserimento del # # carattere # ####################################################################################################### eoi_errmsg: .asciz "*** Il programma ha cercato di accedere oltre la fine del file di ingresso ***\n" eoi_error: pushl $eoi_errmsg call printf addl $4, %esp pushl stdout call fflush addl $4, %esp ret .global input input : pushl %ebx pushl %ecx pushl %edx pushl %eax xor %eax, %eax call getchar cmp $-1, %eax jne 1f call eoi_error call abort 1: mov %al , _var_b popl %eax mov _var_b , %al popl %edx popl %ecx popl %ebx ret # # push %eax # Salvo lo stato dei registri prima della chiamata # push %ebx # push %ecx ## push %edx # # # xor %eax,%eax # pulisco i registro Setto a zero il valore # xor %ecx, %ecx # # # # movl $SYS_READ, %eax # Chiamo la system_call int read (int fd, void * buffer, size_t size) # movl $STDIN, %ebx #stdin # inserisco il descitore del file di input 0 # movl $vettore_2byte, %ecx # metto l'indirizzo delle variabli sulle quali verra memmorizato il carattere # movl $2, %edx # grandezza dell 'input, 2 perchè si aspetta la pressione del tasto invio # int $SYSTEM_CALL_LINUX # # # # # # # cmp $0xa, (vettore_2byte +1) # controllo che il tasto premetu dopo sia realmente \n # je ok # # devo svuotare il buffer #ciclo_svuota_buffer: # movl $SYS_READ, %eax # Chiamo la system_call int read (int fd, void * buffer, size_t size) # movl $STDIN, %ebx #stdin # inserisco il descitore del file di input 0 # movl $_var_b, %ecx # metto l'indirizzo delle variabli sulle quali verra memmorizato il carattere # movl $1, %edx # grandezza dell 'input # int $SYSTEM_CALL_LINUX # # cmp $0xa, _var_b # jne ciclo_svuota_buffer # #ok: # pop %edx # pop %ecx # pop %ebx # pop %eax # # mov vettore_2byte, %al # Trasferisco il valore messo in input nel registro al # # movl $0, vettore_2byte # Azzero le posizioni in memmoria # movl $0, (vettore_2byte+1) # # # ret # #----------------------------------------------------------------------------------------------------------------------------------------------------------- ####################################################################################################### # EXIT : # # System_call che serve ad uscire dal programma, in questa maniera si puo mettere un valore # # di ritorno all'uscita, semplicemente mettendolo nel registro ebx, per default 0, che # # rapresenta l'uscita senza errori # ####################################################################################################### .global exit exit: movl $SYS_EXIT, %eax # Chiamo la system_Call void_exit(int value) movl $0, %ebx # Valore di Uscita int $SYSTEM_CALL_LINUX #----------------------------------------------------------------------------------------------------------------------------------------------------------- ####################################################################################################### # NEWLINE : # # Stampa una nuova riga # ####################################################################################################### .global newline newline: PUSH %EAX MOV $0x0D,%AL CALL output MOV $0x0A,%AL CALL output POP %EAX RET #----------------------------------------------------------------------------------------------------------------------------------------------------------- ####################################################################################################### # PAUSE n : # # CheckPoint mette in attesa il programma principale stampando un messaggio è attendendo la # # pressione del Tasto INVIO # ####################################################################################################### .global pause, pause0, pause1, pause2, pause3, pause4, pause5, pause6, pause7, pause8, pause9 pause : pause0 : pause1 : pause2 : pause3 : pause4 : pause5 : pause6 : pause7 : pause8 : pause9 : ret #---------------------------------------------------------------------------------------------------------------------------------------------------------- ####################################################################################################### # INLINE_ECO : # # preleva un numero x (passato tramite il registro cx ) di caratteri mettendoli nel - # # l'indirizzo che si trova in ebx # # -se il numero di dati inseriti è maggiore della grandezza del buffer -2 questi # # verranno ignorati # ####################################################################################################### .global inline_eco inline_eco : push %eax push %ebx push %ecx push %edx subw $2, %cx #Sottrago due alla grandezza del buffer perchè mi devo riservare due celle di memmoria per # salvare i caratteri di ritorno carrello e di nuova linea and $0x0000FFFF, %ecx #Metto il valore di cx in ecx perchè lavoro sui i registri a 32 bit movl %ecx , _n_carat_l #Salvo il numero di caratteri di cui devo fare l'input movl %ebx, _buffer_l #Salvo l'indirrizzo del buffer #Sono obbligato a fare questi salvataggi in quanto quei registri sono riservati per le system_call movl $SYS_READ, %eax # System_call si input della stringa movl $STDIN, %ebx movl _buffer_l, %ecx movl _n_carat_l, %edx int $SYSTEM_CALL_LINUX #Quando la system_call ritorna mette il numero dei caratteri letti in eax cmpl $0, %eax # Se in eax c'è un valore negativo (solitamente -1) si è verificato un errore e chiudo il jb errore # programma con un _exit con valore di ritorno -1 cmpl _n_carat_l, %eax #Confronto il numero di byte letti con quello passato alla funzione, perchè si possono # verificare tre casi diversi da gestire jb decrementa # 1 caso) Se il numero di caratteri letti è inferiore al numero passato alla funzione # si va a sistemare il buffer ed è finito #2 caso) Caso peggiore, che si verifica quando si inserscono n-1 caratteri, bisogna rettrocedere # il puntatore del buffer a causa della presenza del carattere newline '\n' movl _buffer_l , %ebx # traferisco l'indirizzo del buffer in ebx addl %eax, %ebx # aggiorno il puntatore decl %ebx cmpb $0xa, (%ebx) #confronto il contenuto dell'indirizzo con 0xa, che corrisponde alla codifica esadecimale di newline je decrementa # una volta fatto questo ci riconducciamo al caso 1 #caso 3) Se la condizioni precedente sono false ci sono byte in piu e bisogna pulire il buffer di input _loop_: push %eax # mi devo salvare eax perchè ho l'offset del buffer in memoria movl $SYS_READ, %eax # Faccio un input di un carattere finchè non trovo '\n', e cosi faccendo aggiorno il file stdin movl $STDIN, %ebx movl $_msg_ , %ecx movl $1, %edx int $SYSTEM_CALL_LINUX and $0x00000000, %ebx mov _msg_, %bl cmp $0xa , %bl pop %eax je fine_buffer #Una volta giunto al carattere di nuova linea vado ad aggiornare il buffer in memoria jmp _loop_ decrementa: dec %eax #decremento perchè l'offset della memoria parte da zero fine_buffer: movl _buffer_l, %ebx #Sistemo il buffer aggiungendo i caratteri 0x0A nuova linea, 0x0D ritorno carrello addl %eax, %ebx movb $0x0A, (%ebx) incl %ebx movb $0x0D, (%ebx) pop %edx pop %ecx pop %ebx pop %eax ret errore : movl $SYS_WRITE, %eax # Chiamo la system_call int write ( int fd, const void * buffer, size_t size) movl $STDERR, %ebx # Srivo la stringa relativa all'errore sul file STDERR movl $string_error , %ecx movl $(end_string_error -string_error), %edx int $SYSTEM_CALL_LINUX movl $SYS_EXIT, %eax movl $-1, %ebx int $SYSTEM_CALL_LINUX #----------------------------------------------------------------------------------------------------------------------------------------------------------- ####################################################################################################### # OUTLINE : # # mette in output la stringa contenuta nel registro ebx # # Scritta dal professore # ####################################################################################################### .global outline outline: PUSH %AX PUSH %EBX L4001B: MOV (%EBX),%AL CALL output CMP $0x0D,%AL JZ L4002A INC %EBX JMP L4001B L4002A: POP %EBX POP %AX RET #----------------------------------------------------------------------------------------------------------------------------------------------------------- ####################################################################################################### # OUTMESS : # # mette in output la stringa contenuta nel registro ebx # ####################################################################################################### .global outmess outmess: push %eax push %ebx push %ecx push %edx and $0x0000FFFF, %ecx movl %ecx, %edx movl %ebx, %ecx movl $SYS_WRITE, %eax movl $STDOUT, %ebx int $SYSTEM_CALL_LINUX pop %edx pop %ecx pop %ebx pop %eax ret #---------------------------------------------------------------------------------------------------------------------------------------------------------- ####################################################################################################### # inDA1_eco : # # Attende che dalla tastiera che arrivi una cifra decimale, e mette il contenuto in al. # # Uguale a quella del prof tranne per l'eliminazione della chiamata di output # ####################################################################################################### .global inDA1_eco inDA1_eco: CALL input #chiamo l'input CMP $'0',%AL JB inDA1_eco # Controllo che il valore inserito sia nel range 0 <= x <= 9 CMP $'9',%AL JA inDA1_eco call output RET #------------------------------------------------------------------------------------------------------------------------------------------- ####################################################################################################### # inHA1_eco : # # Attende che dalla tastiera che arrivi una cifra esadecimale, e mette il contenuto in al # # Uguale a quella del prof tranne per l'eliminazione della chiamata di output # ####################################################################################################### .global inHA1_eco inHA1_eco: CALL input CMP $'0',%AL JB inHA1_eco CMP $'F',%AL #Controllo che il valore inserito nel input stia nel range 0 <= x <= 9 o A <= x <= F JA inHA1_eco CMP $'9',%AL JBE L3A89B3 CMP $'A',%AL JB inHA1_eco L3A89B3: call output RET #---------------------------------------------------------------------------------------------------------------------------------------------------------- ####################################################################################################### # B4HA1 : # # Trasforma i 4 bit meno significativi nella sua codifica compata esadecimale # # Identica a quella del proffessore # ####################################################################################################### .global B4HA1 B4HA1: AND $0x0F,%AL # azzera la parte meno significativa del registro CMP $9,%AL JA L3ACD37 L3ACD30: ADD $0x30,%AL # codifca esadecimale di 48 RET L3ACD37: ADD $0x37,%AL # codifica esadecimale di 55 RET #----------------------------------------------------------------------------------------------------------------------------------------------------------- ####################################################################################################### # B8HA2 : # # Trasforma gli 8 bit contenuti in al nella loro rapresentazione esadecimale, mettendo il # # risultato in al (parte meno significativa) e in ah # # Identica a quella del proffessore # ####################################################################################################### .global B8HA2 B8HA2: PUSH %CX MOV %AL,%CH SHR $4,%AL CALL B4HA1 MOV %AL,%AH MOV %CH,%AL CALL B4HA1 POP %CX RET #------------------------------------------------------------------------------ .global outbyte outbyte: PUSH %AX CALL B8HA2 PUSH %AX MOV %AH,%AL CALL output POP %AX CALL output POP %AX RET #------------------------------------------------------------------------------ .global outchar outchar: call video ret #------------------------------------------------------------------------------ .global inchar inchar: call tastiera ret #------------------------------------------------------------------------------ .global HA1B4 HA1B4: CMP $'9',%AL JA L3KCD37 sub_0x30: SUB $0x30,%AL RET L3KCD37: SUB $0x37,%AL RET #------------------------------------------------------------------------------ .global HA2B8 HA2B8: PUSH %CX MOV %AL,%CH MOV %AH,%AL CALL HA1B4 MOV %AL,%AH ROL $4,%AH MOV %CH,%AL CALL HA1B4 OR %AH,%AL POP %CX RET #------------------------------------------------------------------------------ #----------------------------------------------------------------- .global inbyte inbyte: PUSH %EBX MOV %AH,%BH CALL inHA1_eco MOV %AL,%AH CALL inHA1_eco CALL pause1 CALL HA2B8 CALL pause2 MOV %BH,%AH POP %EBX RET #------------------------------------------------------------------------------ .global B16DAN_out B16DAN_out: PUSH %AX PUSH %CX PUSH %DX PUSH %SI MOV $5,%CL CMP $9999,%AX JA L4013K DEC %CL CMP $999,%AX JA L4013K DEC %CL CMP $99,%AX JA L4013K DEC %CL CMP $9,%AX JA L4013K DEC %CL L4013K: MOV %CL,%CH MOV $0x000A,%SI L4013D: MOV $0x0000,%DX DIV %SI ADD $0x30,%DL PUSH %DX DEC %CL JNZ L4013D L401C6: POP %AX CALL output DEC %CH JNZ L401C6 POP %SI POP %DX POP %CX POP %AX L401C2: RET #------------------------------------------------------------------------------ .global inDANB16_eco inDANB16_eco: NOP inDANB16_eco1: CMP $0,%CX JE L40130 CMP $5,%CX JA L40130 PUSH %CX PUSH %DX PUSH %SI MOV $0x000A,%SI MOV $0x0000,%AX L40119: MUL %SI PUSH %AX CALL inDA1_eco MOV %AL,%DL POP %AX AND $0x000F,%DX ADD %DX,%AX DEC %CX JNZ L40119 POP %SI POP %DX POP %CX L40130: RET #------------------------------------------------------------------------------ .global inDANB16_eco2 inDANB16_eco2: PUSH %CX PUSH %DX PUSH %SI MOV $0x000A,%SI MOV $0x0000,%AX MOV $5,%CH L71119: CMP $0,%CH JE L71130 DEC %CH PUSH %AX L7158A: CALL input CMP $0x0D,%AL JE L71579 CMP $'0',%AL JB L7158A CMP $'9',%AL JA L7158A L71579: CALL output MOV %AL,%CL POP %AX CMP $0x0D,%CL JE L71130 MUL %SI MOV %CL,%DL AND $0x000F,%DX ADD %DX,%AX JMP L71119 L71130: POP %SI POP %DX POP %CX RET .data ############################### # # # DEDINIZIONE COSTANTI # # # ############################### .set SYS_EXIT, 1 .set SYS_READ, 3 .set SYS_WRITE, 4 .set STDIN, 0 .set STDOUT, 1 .set STDERR, 2 .set SYSTEM_CALL_LINUX,0x80 ############################### # # # DEDINIZIONE DELLE VARIABILI # # # ############################### new_line : .ascii "\n" # Carattere di nuova linea Check_point : .ascii "Checkpoint number : x\nPress any KEY to continue" #stringa per la funzione pausa End_check_point: string_error : .ascii "Errore nella chiamata di system_call\n" # Stringa per quando si presentano errori end_string_error: _msg_ : # Variabile che mi serve per memmorizare il contenuto del registro al .ascii "0" # mandare il valore in output _var_b : .byte 0 # var generica byte che uso in varie occasioni _var_w : .word 0 # var generica word che uso in varie occasioni _var_l : .long 0 # var generica long che uso in varie occasioni # variabili che uso nella funzione inline_eco _n_carat_l : .long 0 # numero caratteri presi in input _buffer_l : .long 0 # inidirizzo buffer .global main .text FMTFLOAT: .ASCIZ "%g" FMTDOUBLE: .ASCIZ "%lg" .global f_input f_input: PUSHAL LEA FMTFLOAT, %ECX CALL generic_input POPAL RET .global d_input d_input: PUSHAL LEA FMTDOUBLE, %ECX CALL generic_input POPAL RET .global f_output f_output: PUSHAL CALL float_output POPAL RET .global d_output d_output: PUSHAL CALL double_output POPAL RET ## EAX = puntatore a 32bit per il float generic_input: pushl %ebp movl %esp, %ebp subl $256, %esp pushl %edi pushl %esi movl %eax, %edi # ind. dest movl %ecx, %esi # ind. format pushl stdin pushl $256 leal -256(%ebp), %eax pushl %eax call fgets addl $12, %esp cmpl $0, %eax # in caso di errore o EOF abort jne 1f call eoi_error call abort 1: pushl %edi pushl %esi leal -256(%ebp), %eax pushl %eax call sscanf addl $12, %esp pushl $0 # se stdin non e' un terminale, echo call isatty addl $8, %esp cmpl $1, %eax je 1f pushl stdout leal -256(%ebp), %eax pushl %eax call fputs addl $8, %eax pushl stdout call fflush addl $4, %esp 1: popl %esi popl %edi leave ret # EAX = puntatore a 32bit per il float float_output: pushl %ebp movl %esp, %ebp subl $8, %esp flds (%eax) subl $4, %esp leal -8(%esp), %esp fstpl (%esp) pushl $FMTFLOAT call printf addl $16, %esp pushl stdout call fflush addl $4, %esp leave ret # EAX = puntatore a 32bit per il float double_output: pushl %ebp movl %esp, %ebp subl $8, %esp fldl (%eax) subl $4, %esp leal -8(%esp), %esp fstpl (%esp) pushl $FMTDOUBLE call printf addl $16, %esp pushl stdout call fflush addl $4, %esp leave ret ################################################### # file "servizio.s" per sistemi Un*x/i386 # testato su # Linux Mandrake 8.0, gcc 2.96 # Gentoo Linux 1.4, gcc 3.2.3 # Slackware 9.1, gcc 3.2.3 # ################################################### .data .balign 4 .type ttysavefd,@object .size ttysavefd,4 ttysavefd: .long -1 .balign 4 .type ttystate,@object .size ttystate,4 ttystate: .long 0 save_termios: .balign 32 .fill 60,1,0 a_capo: .asciz "\n" .previous .balign 16 ################################################### # tty_raw: # configura il terminale per la modalita' raw # (un carattere alla volta, senza eco) # (da: W. Stevens, "Advanced Programming in the Unix(R) # environment") ################################################### tty_raw: pushl %ebp movl %esp, %ebp pushl %edi pushl %esi pushl %ebx subl $84, %esp movl 8(%ebp), %ebx pushl $save_termios pushl %ebx call tcgetattr addl $16, %esp testl %eax, %eax js .L20 cld leal -88(%ebp), %edi movl $save_termios, %esi movl $15, %ecx rep movsl movl -80(%ebp), %eax movl -76(%ebp), %esi andl $-305, %eax movl -88(%ebp), %ecx orl $48, %eax movl -84(%ebp), %edx movl %eax, -80(%ebp) pushl %eax leal -88(%ebp), %eax pushl %eax andl $-1331, %ecx andl $-2, %edx pushl $2 andl $-32780, %esi pushl %ebx movl %esi, -76(%ebp) movl %ecx, -88(%ebp) movl %edx, -84(%ebp) movb $1, -65(%ebp) movb $0, -66(%ebp) call tcsetattr addl $16, %esp testl %eax, %eax jns .L19 .L20: orl $-1, %eax jmp .L17 .p2align 4,,7 .L19: movl $1, ttystate movl %ebx, ttysavefd xorl %eax, %eax .L17: leal -12(%ebp), %esp popl %ebx popl %esi popl %edi popl %ebp ret .balign 16 ########################################################## # tty_reset: # riconfigura il terminale per la modalita' canonica # (una linea alla volta, con eco) # (da: W. Stevens, "Advanced Programming in the Unix(R) # environment") ########################################################## tty_reset: pushl %ebp movl %esp, %ebp pushl %ecx pushl %ecx cmpl $1, ttystate jne .L24 pushl %edx pushl $save_termios pushl $2 movl 8(%ebp), %eax pushl %eax call tcsetattr addl $16, %esp testl %eax, %eax jns .L23 orl $-1, %eax jmp .L21 .p2align 4,,7 .L23: movl $0, ttystate .L24: xorl %eax, %eax .L21: movl %ebp, %esp popl %ebp ret .balign 16 ########################################################### # tty_atexit: # chiama la tty_reset all'uscita dal programma # se il terminale era stato configurato per la # modalita' raw # (da: W. Stevens, "Advanced Programming in the Unix(R) # environment") ########################################################### tty_atexit: pushl %ebp movl %esp, %ebp pushl %eax pushl %eax movl ttysavefd, %eax testl %eax, %eax js .L26 subl $12, %esp pushl %eax call tty_reset movl $1, (%esp) call isatty addl $16, %esp testl %eax, %eax je .L26 subl $12, %esp pushl $a_capo call printf addl $16, %esp .L26: movl %ebp, %esp popl %ebp ret .balign 16 .globl main ########################################################### # main: # trucco: questo e' il vero main, che prima chiama # tty_raw sul'input standard e poi chiama _main ########################################################### main: pushl %ebp movl %esp, %ebp pushl $0 call isatty addl $4, %esp testl %eax, %eax je .L13 pushl $0 call tty_raw addl $4, %esp pushl $tty_atexit call atexit addl $4, %esp .L13: pushl %ebx pushl %ecx pushl %edx pushl %esi pushl %edi call _main popl %edi popl %esi popl %edx popl %ecx popl %ebx movl %ebp, %esp popl %ebp ret .balign 16 .globl tastiera ############################################################## # tastiera: # legge un singolo carattere dallo standard input e # lascia il suo codice ascii in %al ############################################################## tastiera: pushl %ebp movl %esp, %ebp subl $4, %esp pushl %eax pushl %ebx pushl %ecx pushl %edx leal -1(%ebp), %eax pushl $1 pushl %eax pushl $0 call read addl $12, %esp popl %edx popl %ecx popl %ebx popl %eax movb -1(%ebp),%al movl %ebp, %esp popl %ebp ret .balign 16 .globl video ############################################################### # video: # si aspetta in %al il codice ascii di un carattere e # lo stampa sullo standard output ############################################################### video: pushl %ebp movl %esp, %ebp subl $4, %esp pushl %eax pushl %ebx pushl %ecx pushl %edx movb %al, -1(%ebp) leal -1(%ebp), %eax pushl $1 pushl %eax pushl $1 call write addl $12, %esp popl %edx popl %ecx popl %ebx popl %eax movl %ebp, %esp popl %ebp ret