;--------------------------------------------------; ; file callret.asm ; ; programma di esempio per CALL e RET ; ;--------------------------------------------------; ; nasm -f obj callret.asm -l callret.lst ; ; tlink callret.obj + exelib.obj ; ; (oppure link /map callret.obj + exelib.obj) ; ;--------------------------------------------------; ;########### direttive per l'assembler ############ CPU 386 ; set di istruzioni a 32 bit %include "exelib.inc" ; inclusione libreria di I/O ;######### dichiarazione tipi e costanti ########## %assign STACK_SIZE 0400h ; 1024 byte per lo stack ;################ segmento dati ################### SEGMENT DATASEGM ALIGN=16 PUBLIC USE16 CLASS=DATA ;----- inizio definizione variabili statiche ------ row_counter dw 0600h ; contatore riga di output near_addr dw 0 ; indirizzo NEAR strCodesegm db 'CODESEGM = ', 0 stringa1 db 'Chiamata diretta intrasegmento (Rel16)', 0 stringa2 db 'Chiamata indiretta intrasegmento (Reg16)', 0 stringa3 db 'Chiamata indiretta intrasegmento (Mem16)', 0 ;------- fine definizione variabili statiche ------ ;################ segmento dati 2 ################# SEGMENT DATASEGM2 ALIGN=16 PUBLIC USE16 CLASS=DATA ;----- inizio definizione variabili statiche ------ far_addr dd 0 ; indirizzo FAR stringa4 db 'Chiamata diretta intersegmento (Ptr16:Ptr16)', 0 stringa5 db 'Chiamata indiretta intersegmento (Mem16:Mem16)', 0 ;------- fine definizione variabili statiche ------ ;############### segmento codice ################## SEGMENT CODESEGM ALIGN=16 PUBLIC USE16 CLASS=CODE ..start: ; entry point mov ax, DATASEGM ; trasferisce DATASEGM mov ds, ax ; in DS attraverso AX ;------- inizio blocco principale istruzioni ------ call far set80x50 ; modo video 80 righe, 50 colonne call far clearScreen ; pulisce lo schermo mov ax, DATASEGM2 ; trasferisce DATASEGM2 mov fs, ax ; in FS attraverso AX push ds ; copia DS pop es ; in ES (per writeString) ; ATTENZIONE! Se si ha la necessita' di modificare ES, bisogna preservarne ; il vecchio contenuto; la procedura writeString presuppone, infatti, che ; ES contenga la componente Seg dell'indirizzo della stringa da visualizzare! ; mostra il valore assegnato dal SO a CODESEGM mov di, strCodesegm ; di = offset strCodesegm mov dx, 0400h ; riga 4, colonna 0 call far writeString ; mostra la stringa mov ax, CODESEGM ; ax = CODESEGM mov dx, 040Bh ; riga 4, colonna 11 call far writeHex16 ; mostra ax ; chiamata diretta intrasegmento di start_maiuscole1 (Rel16) mov bx, stringa1 ; ds:bx punta a stringa1 call start_maiuscole1 ; conversione di stringa1 mov dx, [row_counter] ; dx = coordinate di output mov di, stringa1 ; es:di punta a stringa1 call far writeString ; stampa la stringa add word [row_counter], 0100h ; incremento riga ; chiamata indiretta intrasegmento di start_maiuscole1 (Reg16) mov bx, stringa2 ; ds:bx punta a stringa2 mov ax, start_maiuscole1 ; cs:ax punta alla procedura call ax ; conversione di stringa2 mov dx, [row_counter] ; dx = coordinate di output mov di, stringa2 ; es:di punta a stringa2 call far writeString ; stampa la stringa add word [row_counter], 0100h ; incremento riga ; chiamata indiretta intrasegmento di start_maiuscole1 (Mem16) mov bx, stringa3 ; ds:bx punta a stringa3 mov word [near_addr], start_maiuscole1 ; cs:near_addr punta alla proc. call [near_addr] ; conversione di stringa3 mov dx, [row_counter] ; dx = coordinate di output mov di, stringa3 ; es:di punta a stringa3 call far writeString ; stampa la stringa add word [row_counter], 0100h ; incremento riga ;-------------------------------------------------- push fs ; copia FS pop es ; in ES (per writeString) ; ATTENZIONE! Se si ha la necessita' di modificare ES, bisogna preservarne ; il vecchio contenuto; la procedura writeString presuppone, infatti, che ; ES contenga la componente Seg dell'indirizzo della stringa da visualizzare! ; chiamata diretta intersegmento di start_maiuscole2 (Ptr16:Ptr16) mov bx, stringa4 ; fs:bx punta a stringa4 call far start_maiuscole2 ; conversione di stringa4 mov dx, [row_counter] ; dx = coordinate di output mov di, stringa4 ; es:di punta a stringa4 call far writeString ; stampa la stringa add word [row_counter], 0100h ; incremento riga ; chiamata indiretta intersegmento di start_maiuscole2 (Mem16:Mem16) mov bx, stringa5 ; fs:bx punta a stringa5 mov ax, start_maiuscole2 ; ax = Offset destinazione mov word [fs:far_addr+0], ax ; salva nella WORD bassa di far_addr mov ax, seg start_maiuscole2 ; ax = Seg destinazione mov word [fs:far_addr+2], ax ; salva nella WORD alta di far_addr call far [fs:far_addr] ; conversione di stringa5 mov dx, [row_counter] ; dx = coordinate di output mov di, stringa5 ; es:di punta a stringa4 call far writeString ; stampa la stringa add word [row_counter], 0100h ; incremento riga ;-------- fine blocco principale istruzioni ------- mov ah, 4ch ; servizio Terminate Program mov al, 00h ; exit code = 0 int 21h ; chiama i servizi DOS ;------------ inizio blocco procedure ------------- ; La procedura start_maiuscole1 converte una stringa in maiuscolo; ; la stringa deve essere puntata da DS:BX. ; Prima di effettuare la conversione, start_maiuscole1 visualizza ; l'indirizzo di ritorno NEAR; tale indirizzo si trova, ovviamente, ; in cima allo stack e cioe', in SS:SP start_maiuscole1: ; start procedura mov bp, sp ; ss:bp = ss:sp mov dx, [row_counter] ; dx = contatore riga mov ax, [bp] ; ax = return Offset call far writeHex16 ; stampa ax add word [row_counter], 0100h ; incremento riga strconvert_loop: ; WHILE ([ds:bx] != 0) mov al, [bx] ; al = codice ASCII da esaminare test al, al ; (al == 0) ? jz exit_loop ; if (al == 0) jump exit_loop cmp al, 'a' ; confronta al con 'a' jb next_char ; non e' una minuscola cmp al, 'z' ; confronta al con 'z' ja next_char ; non e' una minuscola sub al, 32 ; converte in maiuscolo mov [bx], al ; salva nella stringa next_char: inc bx ; prossimo elemento della stringa jmp short strconvert_loop ; DO exit_loop: ret ; NEAR return = C3h ;-------------- fine blocco procedure ------------- ;############## segmento codice 2 ################# SEGMENT LIBCODE ALIGN=16 PUBLIC USE16 CLASS=CODE ; La procedura start_maiuscole2 converte una stringa in maiuscolo; ; la stringa deve essere puntata da FS:BX. ; Prima di effettuare la conversione, start_maiuscole2 visualizza ; l'indirizzo di ritorno FAR; tale indirizzo si trova, ovviamente, ; in cima allo stack e cioe', in SS:SP start_maiuscole2: ; start procedura mov bp, sp ; ss:bp = ss:sp mov dx, [row_counter] ; dx = contatore riga mov ax, [bp] ; ax = return Offset call far writeHex16 ; stampa ax add word [row_counter], 0100h ; incremento riga mov dx, [row_counter] ; dx = contatore riga mov ax, [bp+2] ; ax = return Seg call far writeHex16 ; stampa ax add word [row_counter], 0100h ; incremento riga strconvert_loop2: ; WHILE ([fs:bx] != 0) mov al, [fs:bx] ; al = codice ASCII da esaminare test al, al ; (al == 0) ? jz exit_loop2 ; if (al == 0) jump exit_loop cmp al, 'a' ; confronta al con 'a' jb next_char2 ; non e' una minuscola cmp al, 'z' ; confronta al con 'z' ja next_char2 ; non e' una minuscola sub al, 32 ; converte in maiuscolo mov [fs:bx], al ; salva nella stringa next_char2: inc bx ; prossimo elemento della stringa jmp short strconvert_loop2 ; DO exit_loop2: retf ; FAR return = CBh ; al posto di RETF possiamo anche scrivere: db 0CBh ;################# segmento stack ################# SEGMENT STACKSEGM ALIGN=16 STACK USE16 CLASS=STACK resb STACK_SIZE ; 1024 byte per lo stack ;##################################################