Assembler step-mode interrupt handler

I am writing a step-mode interrupt handler in x86 architecture assembler and can’t figure out how to find and print out mov byte ptr [bx] and bx registers.

So far i have this and in theory it should work but it doesn’t. The output should look something like this: 0000:0128 C60723 mov byte ptr [bx], 23h ; bx= 0001, [bx]=12


.model small
.stack 100h
.data
    senasIP dw ?
    senasCS dw ?
    
    regAX dw ?
    regBX dw ?
    regCX dw ?
    regDX dw ?
    regSP dw ?
    regBP dw ?
    regSI dw ?
    regDI dw ?
    
    baitas1 db ?
    baitas2 db ?
    baitas3 db ?
    baitas4 db ?
    baitas5 db ?
    baitas6 db ?
    
    zingsn_pranesimas db "Zingsninis pertraukimas: $"
    mov_bx_kabl       db "MOV bx, $"
    bx_lygu db "bx=$"
    enteris db 13,10,"$"
.code
    mov ax, @data
    mov ds, ax
    
    mov ax, 0
    mov es, ax ;Extra segmentas prasides ten pat kur vektoriu lentele
                ;To reikia, kad galetume prieiti prie vektoriu lenteles baitu reiksmiu
    
    mov ax, es:[4]
    mov bx, es:[6]
    mov senasCS, bx
    mov senasIP, ax ;neisikeliam tiesiai, nes nera perdavimo is atminties i atminti (butina panaudoti registrus, isimtis eilutines komandos, bet jas panaudoti butu sudetingiau)

;===================PERIMAME PERTRAUKIMA==========================
    mov ax, cs
    mov bx, offset pertraukimas
    
    mov es:[4], bx
    mov es:[6], ax

;=================AKTYVUOJAME ZINGSNINI REZIMA===================
    pushf ;PUSH SF
    pop ax
    or ax, 100h ;0000 0001 0000 0000 (TF=1, kiti lieka kokie buvo)
    push ax
    popf  ;POP SF ;>Zingsninis rezimas ijungiamas po sios komandos ivykdymo - ivykdzius kiekviena sekancia komanda ivyks zingsninis pertraukimas

;==================BELEKOKIOS KOMANDOS====================
    mov byte ptr [bx],23h
    mov bx,001h
;==================ISJUNGIAME ZINGSNINI REZIMA======================
    pushf
    pop  ax
    and  ax, 0FEFFh ;1111 1110 1111 1111 (nuliukas priekyj F, nes skaiciai privalo prasideti skaitmeniu, ne raide) - TF=0, visi kiti liks nepakeisti
    push ax
    popf ;
    
    mov ax, senasIP
    mov bx, senasCS
    mov es:[4], ax
    mov es:[6], bx
    
uzdaryti_programa:
    mov ah, 4Ch
    int 21h
    
    
    
    
    
;==================================================================
;Pertraukimo apdorojimo procedura
;==================================================================
pertraukimas:   
    ; Save register values
    mov regAX, ax               
    mov regBX, bx
    mov regCX, cx
    mov regDX, dx
    mov regSP, sp
    mov regBP, bp
    mov regSI, si
    mov regDI, di
    
    ; Retrieve instruction bytes at CS:IP
    pop si ; Get IP value
    pop di ; Get CS value
    push di ; Restore CS
    push si ; Restore IP

    ; Copy bytes into local storage
    mov al, cs:[si]       ; First byte of instruction
    mov ah, cs:[si+1]     ; Second byte of instruction
    mov baitas1, al
    mov baitas2, ah

    cmp al, 0C6h          ; Check for opcode `C6`
    jne grizti_is_pertraukimo
    cmp ah, 07h           ; Check for ModRM byte `07` (BX addressing mode)
    jne grizti_is_pertraukimo
    
    ; Print the recognized instruction
    mov ah, 9
    mov dx, offset zingsn_pranesimas
    int 21h
    
    ; Print CS:IP
    mov ax, di
    call printAX
    mov ah, 2
    mov dl, ":"
    int 21h
    mov ax, si
    call printAX
    call printSpace
    
    ; Print machine code bytes
    mov ah, baitas1
    call printAL
    mov al, baitas2
    call printAL
    mov al, cs:[si+2]     ; Immediate byte
    call printAL
    call printSpace
    call printSpace
    
    ; Print assembly mnemonic
    mov ah, 9
    mov dx, offset mov_bx_kabl ; Text: `MOV byte ptr [BX],`
    int 21h
    
    mov al, cs:[si+2]     ; Immediate value
    call printAL
    
    mov ah, 2
    mov dl, "h"           ; Append `h` for hexadecimal notation
    int 21h
    
    call printSpace
    call printSpace
    
    ; Print the value of BX register before execution
    mov ah, 9
    mov dx, offset bx_lygu ; Text: `bx=`
    int 21h
    mov ax, regBX
    call printAX
    
    ; Print newline
    mov ah, 9
    mov dx, offset enteris
    int 21h
    
grizti_is_pertraukimo:
    mov ax, regAX
    mov bx, regBX
    mov cx, regCX
    mov dx, regDX
    mov sp, regSP
    mov bp, regBP
    mov si, regSI
    mov di, regDI
IRET ; Return from interrupt handler

;===================PAGALBINES pertraukime naudojamos proceduros================

;>>>Spausdinti AX reiksme
printAX:
    push ax
    mov al, ah
    call printAL
    pop ax
    call printAL
RET

;>>>>Spausdink tarpa
printSpace:
    push ax
    push dx
        mov ah, 2
        mov dl, " "
        int 21h
    pop dx
    pop ax
RET

;>>>Spausdinti AL reiksme
printAL:
    push ax
    push cx
        push ax
        mov cl, 4
        shr al, cl
        call printHexSkaitmuo
        pop ax
        call printHexSkaitmuo
    pop cx
    pop ax
RET

;>>>Spausdina hex skaitmeni pagal AL jaunesniji pusbaiti (4 jaunesnieji bitai - > AL=72, tai 0010)
printHexSkaitmuo:
    push ax
    push dx
    
    and al, 0Fh ;nunulinam vyresniji pusbaiti AND al, 00001111b
    cmp al, 9
    jbe PrintHexSkaitmuo_0_9
    jmp PrintHexSkaitmuo_A_F
    
    PrintHexSkaitmuo_A_F: 
    sub al, 10 ;10-15 ===> 0-5
    add al, 41h
    mov dl, al
    mov ah, 2; spausdiname simboli (A-F) is DL'o
    int 21h
    jmp PrintHexSkaitmuo_grizti
    
    
    PrintHexSkaitmuo_0_9: ;0-9
    mov dl, al
    add dl, 30h
    mov ah, 2 ;spausdiname simboli (0-9) is DL'o
    int 21h
    jmp printHexSkaitmuo_grizti
    
    printHexSkaitmuo_grizti:
    pop dx
    pop ax
RET

END

3

mov ax, cs
mov bx, offset pertraukimas

mov es:[4], bx
mov es:[6], ax

It is always better if you modify an interrupt vector with interrupts disabled. This will avoid any risk of using an incomplete vector. That’s why I wrote:

cli
mov word [es:4], pertraukimas
mov [es:6], cs
sti

popf
mov byte ptr [bx],23h
mov bx,001h

Once your popf instruction has set the single-step flag TF, the CPU will automatically generate an exception after the execution of following instructions. It is important to note that the exception is not generated for the instruction that actually sets TF. So, directly after your popf there’s no invokation of your special handler, but there is after the execution of mov byte ptr [bx],23h. In my program I solved it with an inserted nop:

popf                           ; This sets TF=1
nop
; Here happens the very first trap and CS:IP point at
mov byte [bx], 23h             ; ... this instruction
mov bx, 0001h

The CS:IP value that the processor places on the stack does not represent the address of the instruction that just ran, but rather the one that follows.

The demo program that I wrote is a .COM executable where all of the segment registers start off equal to each other. The single-step handler works as indicated in the question. I tested it in the DOSBox 0.74 environment.

The output I got is close to what you have showed:

Zingsninis pertraukimas: 0192:012A C60723  MOV bx, 23h  bx=0070
  ORG 256

  xor ax, ax
  mov es, ax
  mov ax, [es:4]
  mov bx, [es:6]
  mov [senasIP], ax
  mov [senasCS], bx
  cli
  mov word [es:4], pertraukimas
  mov [es:6], cs
  sti

  pushf : pop ax : or ax, 0100h : push ax : popf
;===============================================
  nop
  mov byte [bx], 23h
  mov bx, 0001h
;=================================================
  pushf : pop ax : and ax, 0FEFFh : push ax : popf
    
  cli
  mov ax, [senasIP]
  mov [es:4], ax
  mov ax, [senasCS]
  mov [es:6], ax
  sti
  mov ax, 4C00h
  int 21h

;==================================================================
;Pertraukimo apdorojimo procedura
;==================================================================

pertraukimas:   
  push es ax bx cx dx si di bp
  mov  bp, sp
  les  si, [bp+16]

  mov  ax, [es:si]
  cmp  ax, 07C6h ; Check for opcode `C6` and ModRM byte `07` (BX addressing mode)
  jne  grizti_is_pertraukimo

  mov  ah, 9
  mov  dx, zingsn_pranesimas
  int  21h

  mov  ax, es
  call printAX
  mov  ah, 2
  mov  dl, ":"
  int  21h
  mov  ax, si
  call printAX
  call printSpace
    
  mov  al, 0C7h
  call printAL
  mov  al, 07h
  call printAL
  mov  al, [es:si+2]     ; Immediate byte
  call printAL
  call printSpace
  call printSpace
    
  mov  ah, 9
  mov  dx, mov_bx_kabl   ; Text: `MOV byte ptr [BX],`
  int  21h
    
  mov  al, [es:si+2]     ; Immediate value
  call printAL

  mov  ah, 2
  mov  dl, "h"           ; Append `h` for hexadecimal notation
  int  21h

  call printSpace
  call printSpace
    
  ; Print the value of BX register before execution
  mov  ah, 9
  mov  dx, bx_lygu       ; Text: `bx=`
  int  21h
  mov  ax, [bp+10]       ; Pushed BX
  call printAX
  mov ah, 9
  mov dx, enteris
  int 21h
    
grizti_is_pertraukimo:
  pop  bp di si dx cx bx ax es
  iret

;===================PAGALBINES pertraukime naudojamos proceduros================

printSpace:
  push ax dx
  mov  ah, 2
  mov  dl, " "
  int  21h
  pop  dx ax
  ret

printAX:
  push ax
  mov  al, ah
  call printAL
  pop  ax
printAL:
  push ax cx
  push ax
  mov  cl, 4
  shr  al, cl
  call printHexSkaitmuo
  pop  ax
  call printHexSkaitmuo
  pop  cx ax
  ret

printHexSkaitmuo:
  push ax dx
  and  al, 15
  cmp  al, 10
  jb   .num
  add  al, 65-10-48
.num:
  add  al, 48
  mov  dl, al
  mov  ah, 2
  int  21h
  pop  dx ax
  ret
; ------------------------------------
senasIP:           dw ?
senasCS:           dw ?
    
zingsn_pranesimas: db "Zingsninis pertraukimas: $"
mov_bx_kabl:       db "MOV bx, $"
bx_lygu:           db "bx=$"
enteris:           db 13,10,"$"

I used a private assembler (similar to FASM) for this. Do modify anything that your assembler might not allow.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa

Assembler step-mode interrupt handler

I am writing a step-mode interrupt handler in x86 architecture assembler and can’t figure out how to find and print out mov byte ptr [bx] and bx registers.

So far i have this and in theory it should work but it doesn’t. The output should look something like this: 0000:0128 C60723 mov byte ptr [bx], 23h ; bx= 0001, [bx]=12


.model small
.stack 100h
.data
    senasIP dw ?
    senasCS dw ?
    
    regAX dw ?
    regBX dw ?
    regCX dw ?
    regDX dw ?
    regSP dw ?
    regBP dw ?
    regSI dw ?
    regDI dw ?
    
    baitas1 db ?
    baitas2 db ?
    baitas3 db ?
    baitas4 db ?
    baitas5 db ?
    baitas6 db ?
    
    zingsn_pranesimas db "Zingsninis pertraukimas: $"
    mov_bx_kabl       db "MOV bx, $"
    bx_lygu db "bx=$"
    enteris db 13,10,"$"
.code
    mov ax, @data
    mov ds, ax
    
    mov ax, 0
    mov es, ax ;Extra segmentas prasides ten pat kur vektoriu lentele
                ;To reikia, kad galetume prieiti prie vektoriu lenteles baitu reiksmiu
    
    mov ax, es:[4]
    mov bx, es:[6]
    mov senasCS, bx
    mov senasIP, ax ;neisikeliam tiesiai, nes nera perdavimo is atminties i atminti (butina panaudoti registrus, isimtis eilutines komandos, bet jas panaudoti butu sudetingiau)

;===================PERIMAME PERTRAUKIMA==========================
    mov ax, cs
    mov bx, offset pertraukimas
    
    mov es:[4], bx
    mov es:[6], ax

;=================AKTYVUOJAME ZINGSNINI REZIMA===================
    pushf ;PUSH SF
    pop ax
    or ax, 100h ;0000 0001 0000 0000 (TF=1, kiti lieka kokie buvo)
    push ax
    popf  ;POP SF ;>Zingsninis rezimas ijungiamas po sios komandos ivykdymo - ivykdzius kiekviena sekancia komanda ivyks zingsninis pertraukimas

;==================BELEKOKIOS KOMANDOS====================
    mov byte ptr [bx],23h
    mov bx,001h
;==================ISJUNGIAME ZINGSNINI REZIMA======================
    pushf
    pop  ax
    and  ax, 0FEFFh ;1111 1110 1111 1111 (nuliukas priekyj F, nes skaiciai privalo prasideti skaitmeniu, ne raide) - TF=0, visi kiti liks nepakeisti
    push ax
    popf ;
    
    mov ax, senasIP
    mov bx, senasCS
    mov es:[4], ax
    mov es:[6], bx
    
uzdaryti_programa:
    mov ah, 4Ch
    int 21h
    
    
    
    
    
;==================================================================
;Pertraukimo apdorojimo procedura
;==================================================================
pertraukimas:   
    ; Save register values
    mov regAX, ax               
    mov regBX, bx
    mov regCX, cx
    mov regDX, dx
    mov regSP, sp
    mov regBP, bp
    mov regSI, si
    mov regDI, di
    
    ; Retrieve instruction bytes at CS:IP
    pop si ; Get IP value
    pop di ; Get CS value
    push di ; Restore CS
    push si ; Restore IP

    ; Copy bytes into local storage
    mov al, cs:[si]       ; First byte of instruction
    mov ah, cs:[si+1]     ; Second byte of instruction
    mov baitas1, al
    mov baitas2, ah

    cmp al, 0C6h          ; Check for opcode `C6`
    jne grizti_is_pertraukimo
    cmp ah, 07h           ; Check for ModRM byte `07` (BX addressing mode)
    jne grizti_is_pertraukimo
    
    ; Print the recognized instruction
    mov ah, 9
    mov dx, offset zingsn_pranesimas
    int 21h
    
    ; Print CS:IP
    mov ax, di
    call printAX
    mov ah, 2
    mov dl, ":"
    int 21h
    mov ax, si
    call printAX
    call printSpace
    
    ; Print machine code bytes
    mov ah, baitas1
    call printAL
    mov al, baitas2
    call printAL
    mov al, cs:[si+2]     ; Immediate byte
    call printAL
    call printSpace
    call printSpace
    
    ; Print assembly mnemonic
    mov ah, 9
    mov dx, offset mov_bx_kabl ; Text: `MOV byte ptr [BX],`
    int 21h
    
    mov al, cs:[si+2]     ; Immediate value
    call printAL
    
    mov ah, 2
    mov dl, "h"           ; Append `h` for hexadecimal notation
    int 21h
    
    call printSpace
    call printSpace
    
    ; Print the value of BX register before execution
    mov ah, 9
    mov dx, offset bx_lygu ; Text: `bx=`
    int 21h
    mov ax, regBX
    call printAX
    
    ; Print newline
    mov ah, 9
    mov dx, offset enteris
    int 21h
    
grizti_is_pertraukimo:
    mov ax, regAX
    mov bx, regBX
    mov cx, regCX
    mov dx, regDX
    mov sp, regSP
    mov bp, regBP
    mov si, regSI
    mov di, regDI
IRET ; Return from interrupt handler

;===================PAGALBINES pertraukime naudojamos proceduros================

;>>>Spausdinti AX reiksme
printAX:
    push ax
    mov al, ah
    call printAL
    pop ax
    call printAL
RET

;>>>>Spausdink tarpa
printSpace:
    push ax
    push dx
        mov ah, 2
        mov dl, " "
        int 21h
    pop dx
    pop ax
RET

;>>>Spausdinti AL reiksme
printAL:
    push ax
    push cx
        push ax
        mov cl, 4
        shr al, cl
        call printHexSkaitmuo
        pop ax
        call printHexSkaitmuo
    pop cx
    pop ax
RET

;>>>Spausdina hex skaitmeni pagal AL jaunesniji pusbaiti (4 jaunesnieji bitai - > AL=72, tai 0010)
printHexSkaitmuo:
    push ax
    push dx
    
    and al, 0Fh ;nunulinam vyresniji pusbaiti AND al, 00001111b
    cmp al, 9
    jbe PrintHexSkaitmuo_0_9
    jmp PrintHexSkaitmuo_A_F
    
    PrintHexSkaitmuo_A_F: 
    sub al, 10 ;10-15 ===> 0-5
    add al, 41h
    mov dl, al
    mov ah, 2; spausdiname simboli (A-F) is DL'o
    int 21h
    jmp PrintHexSkaitmuo_grizti
    
    
    PrintHexSkaitmuo_0_9: ;0-9
    mov dl, al
    add dl, 30h
    mov ah, 2 ;spausdiname simboli (0-9) is DL'o
    int 21h
    jmp printHexSkaitmuo_grizti
    
    printHexSkaitmuo_grizti:
    pop dx
    pop ax
RET

END

3

mov ax, cs
mov bx, offset pertraukimas

mov es:[4], bx
mov es:[6], ax

It is always better if you modify an interrupt vector with interrupts disabled. This will avoid any risk of using an incomplete vector. That’s why I wrote:

cli
mov word [es:4], pertraukimas
mov [es:6], cs
sti

popf
mov byte ptr [bx],23h
mov bx,001h

Once your popf instruction has set the single-step flag TF, the CPU will automatically generate an exception after the execution of following instructions. It is important to note that the exception is not generated for the instruction that actually sets TF. So, directly after your popf there’s no invokation of your special handler, but there is after the execution of mov byte ptr [bx],23h. In my program I solved it with an inserted nop:

popf                           ; This sets TF=1
nop
; Here happens the very first trap and CS:IP point at
mov byte [bx], 23h             ; ... this instruction
mov bx, 0001h

The CS:IP value that the processor places on the stack does not represent the address of the instruction that just ran, but rather the one that follows.

The demo program that I wrote is a .COM executable where all of the segment registers start off equal to each other. The single-step handler works as indicated in the question. I tested it in the DOSBox 0.74 environment.

The output I got is close to what you have showed:

Zingsninis pertraukimas: 0192:012A C60723  MOV bx, 23h  bx=0070
  ORG 256

  xor ax, ax
  mov es, ax
  mov ax, [es:4]
  mov bx, [es:6]
  mov [senasIP], ax
  mov [senasCS], bx
  cli
  mov word [es:4], pertraukimas
  mov [es:6], cs
  sti

  pushf : pop ax : or ax, 0100h : push ax : popf
;===============================================
  nop
  mov byte [bx], 23h
  mov bx, 0001h
;=================================================
  pushf : pop ax : and ax, 0FEFFh : push ax : popf
    
  cli
  mov ax, [senasIP]
  mov [es:4], ax
  mov ax, [senasCS]
  mov [es:6], ax
  sti
  mov ax, 4C00h
  int 21h

;==================================================================
;Pertraukimo apdorojimo procedura
;==================================================================

pertraukimas:   
  push es ax bx cx dx si di bp
  mov  bp, sp
  les  si, [bp+16]

  mov  ax, [es:si]
  cmp  ax, 07C6h ; Check for opcode `C6` and ModRM byte `07` (BX addressing mode)
  jne  grizti_is_pertraukimo

  mov  ah, 9
  mov  dx, zingsn_pranesimas
  int  21h

  mov  ax, es
  call printAX
  mov  ah, 2
  mov  dl, ":"
  int  21h
  mov  ax, si
  call printAX
  call printSpace
    
  mov  al, 0C7h
  call printAL
  mov  al, 07h
  call printAL
  mov  al, [es:si+2]     ; Immediate byte
  call printAL
  call printSpace
  call printSpace
    
  mov  ah, 9
  mov  dx, mov_bx_kabl   ; Text: `MOV byte ptr [BX],`
  int  21h
    
  mov  al, [es:si+2]     ; Immediate value
  call printAL

  mov  ah, 2
  mov  dl, "h"           ; Append `h` for hexadecimal notation
  int  21h

  call printSpace
  call printSpace
    
  ; Print the value of BX register before execution
  mov  ah, 9
  mov  dx, bx_lygu       ; Text: `bx=`
  int  21h
  mov  ax, [bp+10]       ; Pushed BX
  call printAX
  mov ah, 9
  mov dx, enteris
  int 21h
    
grizti_is_pertraukimo:
  pop  bp di si dx cx bx ax es
  iret

;===================PAGALBINES pertraukime naudojamos proceduros================

printSpace:
  push ax dx
  mov  ah, 2
  mov  dl, " "
  int  21h
  pop  dx ax
  ret

printAX:
  push ax
  mov  al, ah
  call printAL
  pop  ax
printAL:
  push ax cx
  push ax
  mov  cl, 4
  shr  al, cl
  call printHexSkaitmuo
  pop  ax
  call printHexSkaitmuo
  pop  cx ax
  ret

printHexSkaitmuo:
  push ax dx
  and  al, 15
  cmp  al, 10
  jb   .num
  add  al, 65-10-48
.num:
  add  al, 48
  mov  dl, al
  mov  ah, 2
  int  21h
  pop  dx ax
  ret
; ------------------------------------
senasIP:           dw ?
senasCS:           dw ?
    
zingsn_pranesimas: db "Zingsninis pertraukimas: $"
mov_bx_kabl:       db "MOV bx, $"
bx_lygu:           db "bx=$"
enteris:           db 13,10,"$"

I used a private assembler (similar to FASM) for this. Do modify anything that your assembler might not allow.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật