admin管理员组

文章数量:1124653

I'm working on an assembly program that reads the drive number and sector number from the user and then attempts to read a block of data from the specified sector. The program works correctly when I only ask for the drive number, but when I try to read the sector number, the output is always the same, regardless of the input. I've tried multiple inputs, but the output never changes, and there are no error codes from Visual Studio Code. The read_decimal subroutine, which reads the decimal input, has worked fine in previous projects.

Here is the source code:

.MODEL SMALL
Space EQU " " ; Space character
.STACK
.DATA
    msg1 DB "Enter the drive number (0=A, 1=B, 2=C, etc.): $"
    msg2 DB "Enter the sector number to read: $"
    newline DB 13, 10, "$" ; Newline
.DATA?
    drive_num DB ?         ; Drive number storage
    sector_num DW ?        ; Sector number storage
    block DB 512 DUP (?)   ; Memory allocation for one block
.CODE

main proc
    MOV AX, Dgroup         ; Set DS (Data Segment)
    MOV DS, AX

    ; Prompt the user to enter the drive number
    LEA DX, msg1
    MOV AH, 09h            ; Print string function
    INT 21h                ; DOS interrupt for string output
    MOV AH, 01h            ; Input character function
    INT 21h                ; Read a character
    SUB AL, '0'            ; Convert ASCII digit to integer
    MOV drive_num, AL      ; Store the drive number

    ; Output a newline
    LEA DX, newline
    MOV AH, 09h
    INT 21h

    ; Prompt the user to enter the sector number
    LEA DX, msg2
    MOV AH, 09h
    INT 21h
    CALL read_decimal      ; Read the entered decimal number
    MOV sector_num, AX     ; Store the sector number

    ; Output a newline
    LEA DX, newline
    MOV AH, 09h
    INT 21h

    ; Read the specified block from the disk
    LEA BX, block          ; Set DS:BX to point to the memory block
    MOV AL, drive_num      ; Specify the drive number (A=0, B=1, etc.)
    MOV CX, 1              ; Number of blocks to read
    MOV DX, sector_num     ; Starting sector number
    INT 25h                ; Perform direct disk read
    POPF                   ; Restore flags from the stack
    XOR DX, DX             ; Reset DX
    CALL write_block       ; Display the read block
    MOV AH, 4Ch            ; Terminate the program
    INT 21h
main endp

write_block proc
    PUSH CX                ; Save CX
    PUSH DX                ; Save DX
    MOV CX, 32             ; Number of lines to print (512 bytes / 16 bytes per line)
write_block_new:
    CALL out_line          ; Print one line
    CALL cr_lf             ; Move to the next line
    ADD DX, 16             ; Move to the next line's data
    LOOP write_block_new   ; Repeat for the next line
    POP DX                 ; Restore DX
    POP CX                 ; Restore CX
    RET
write_block endp

out_line proc
    PUSH BX                ; Save BX
    PUSH CX                ; Save CX
    PUSH DX                ; Save DX
    MOV BX, DX             ; Load the address of the current line's data
    PUSH BX                ; Save BX for ASCII output
    MOV CX, 16             ; Number of bytes per line
hexa_out:
    MOV DL, block[BX]      ; Load one byte
    CALL write_hexa        ; Display the byte in hexadecimal format
    MOV DL, Space          ; Print a space between hexadecimal values
    CALL write_char
    INC BX                 ; Move to the next byte
    LOOP hexa_out          ; Repeat for all bytes in the line
    MOV DL, Space          ; Print a space before ASCII output
    CALL write_char
    MOV CX, 16             ; Reset counter for ASCII output
    POP BX                 ; Restore BX for ASCII processing
ascii_out:
    MOV DL, block[BX]      ; Load one byte
    CMP DL, Space          ; Check if it's a visible character
    JA visible             ; If so, jump to visible
    MOV DL, Space          ; Replace non-visible characters with a space
visible:
    CALL write_char        ; Print the character
    INC BX                 ; Move to the next byte
    LOOP ascii_out         ; Repeat for all bytes in the line
    POP DX                 ; Restore DX
    POP CX                 ; Restore CX
    POP BX                 ; Restore BX
    RET
out_line endp

write_char proc
    PUSH AX                ; Save AX
    MOV AH, 2              ; Function code for printing a character
    INT 21h                ; Print the character in DL
    POP AX                 ; Restore AX
    RET
write_char endp

write_hexa proc
    PUSH CX                ; Save CX
    PUSH DX                ; Save DX
    MOV DH, DL             ; Save the original byte
    MOV CL, 4              ; Number of bits to shift
    SHR DL, CL             ; Shift the upper nibble to the lower nibble
    CALL write_hexa_digit  ; Print the upper nibble
    MOV DL, DH             ; Restore the original byte
    AND DL, 0Fh            ; Mask out the upper nibble
    CALL write_hexa_digit  ; Print the lower nibble
    POP DX                 ; Restore DX
    POP CX                 ; Restore CX
    RET
write_hexa endp

write_hexa_digit proc
    PUSH DX                ; Save DX
    CMP DL, 10             ; Check if the digit is less than 10
    JB non_hexa_letter      ; If so, jump to non_hexa_letter
    ADD DL, "A"-"0"-10     ; Convert to a letter (A-F)
non_hexa_letter:
    ADD DL, "0"            ; Convert to ASCII
    CALL write_char        ; Print the character
    POP DX                 ; Restore DX
    RET
write_hexa_digit endp

CR EQU 13                ; Carriage return
LF EQU 10                ; Line feed

cr_lf proc
    PUSH DX                ; Save DX
    MOV DL, CR
    CALL write_char        ; Move cursor to the beginning of the line
    MOV DL, LF
    CALL write_char        ; Move cursor to the next line
    POP DX                 ; Restore DX
    RET
cr_lf endp

read_decimal proc
    PUSH AX                ; Save AX
    PUSH BX                ; Save BX
    MOV BL, 10             ; Decimal base
    XOR AX, AX             ; Clear AX
read_decimal_new:
    CALL read_char         ; Read a character
    CMP DL, CR             ; Check for Enter key
    JE read_decimal_end    ; If Enter, end input
    SUB DL, "0"            ; Convert ASCII to integer
    MUL BL                 ; Multiply by 10
    ADD AL, DL             ; Add the next digit
    JMP read_decimal_new   ; Continue reading
read_decimal_end:
    MOV DL, AL             ; Store the result in DL
    POP BX                 ; Restore BX
    POP AX                 ; Restore AX
    RET
read_decimal endp

read_char proc
    PUSH AX                ; Save AX
    MOV AH, 1              ; Function code for reading a character
    INT 21h                ; Read one character into AL
    CMP AL, 27             ; Check for ESC key (ASCII 27)
    JE escape              ; Exit if ESC is pressed
    MOV DL, AL             ; Store the character in DL
    POP AX                 ; Restore AX
    RET
escape:
    MOV AH, 4Ch            ; Exit program
    INT 21h
read_char endp

END main

The issue I am encountering is that when I try to read the sector number, it always results in the same output. I’ve tested with different inputs, but the result doesn't change. The program does not give any error codes, but I’m not sure what’s causing this behavior.

I suspect there may be an issue with how the sector number is being stored or passed around, but I can’t seem to figure it out. Any help or insight would be greatly appreciated!

I'm working on an assembly program that reads the drive number and sector number from the user and then attempts to read a block of data from the specified sector. The program works correctly when I only ask for the drive number, but when I try to read the sector number, the output is always the same, regardless of the input. I've tried multiple inputs, but the output never changes, and there are no error codes from Visual Studio Code. The read_decimal subroutine, which reads the decimal input, has worked fine in previous projects.

Here is the source code:

.MODEL SMALL
Space EQU " " ; Space character
.STACK
.DATA
    msg1 DB "Enter the drive number (0=A, 1=B, 2=C, etc.): $"
    msg2 DB "Enter the sector number to read: $"
    newline DB 13, 10, "$" ; Newline
.DATA?
    drive_num DB ?         ; Drive number storage
    sector_num DW ?        ; Sector number storage
    block DB 512 DUP (?)   ; Memory allocation for one block
.CODE

main proc
    MOV AX, Dgroup         ; Set DS (Data Segment)
    MOV DS, AX

    ; Prompt the user to enter the drive number
    LEA DX, msg1
    MOV AH, 09h            ; Print string function
    INT 21h                ; DOS interrupt for string output
    MOV AH, 01h            ; Input character function
    INT 21h                ; Read a character
    SUB AL, '0'            ; Convert ASCII digit to integer
    MOV drive_num, AL      ; Store the drive number

    ; Output a newline
    LEA DX, newline
    MOV AH, 09h
    INT 21h

    ; Prompt the user to enter the sector number
    LEA DX, msg2
    MOV AH, 09h
    INT 21h
    CALL read_decimal      ; Read the entered decimal number
    MOV sector_num, AX     ; Store the sector number

    ; Output a newline
    LEA DX, newline
    MOV AH, 09h
    INT 21h

    ; Read the specified block from the disk
    LEA BX, block          ; Set DS:BX to point to the memory block
    MOV AL, drive_num      ; Specify the drive number (A=0, B=1, etc.)
    MOV CX, 1              ; Number of blocks to read
    MOV DX, sector_num     ; Starting sector number
    INT 25h                ; Perform direct disk read
    POPF                   ; Restore flags from the stack
    XOR DX, DX             ; Reset DX
    CALL write_block       ; Display the read block
    MOV AH, 4Ch            ; Terminate the program
    INT 21h
main endp

write_block proc
    PUSH CX                ; Save CX
    PUSH DX                ; Save DX
    MOV CX, 32             ; Number of lines to print (512 bytes / 16 bytes per line)
write_block_new:
    CALL out_line          ; Print one line
    CALL cr_lf             ; Move to the next line
    ADD DX, 16             ; Move to the next line's data
    LOOP write_block_new   ; Repeat for the next line
    POP DX                 ; Restore DX
    POP CX                 ; Restore CX
    RET
write_block endp

out_line proc
    PUSH BX                ; Save BX
    PUSH CX                ; Save CX
    PUSH DX                ; Save DX
    MOV BX, DX             ; Load the address of the current line's data
    PUSH BX                ; Save BX for ASCII output
    MOV CX, 16             ; Number of bytes per line
hexa_out:
    MOV DL, block[BX]      ; Load one byte
    CALL write_hexa        ; Display the byte in hexadecimal format
    MOV DL, Space          ; Print a space between hexadecimal values
    CALL write_char
    INC BX                 ; Move to the next byte
    LOOP hexa_out          ; Repeat for all bytes in the line
    MOV DL, Space          ; Print a space before ASCII output
    CALL write_char
    MOV CX, 16             ; Reset counter for ASCII output
    POP BX                 ; Restore BX for ASCII processing
ascii_out:
    MOV DL, block[BX]      ; Load one byte
    CMP DL, Space          ; Check if it's a visible character
    JA visible             ; If so, jump to visible
    MOV DL, Space          ; Replace non-visible characters with a space
visible:
    CALL write_char        ; Print the character
    INC BX                 ; Move to the next byte
    LOOP ascii_out         ; Repeat for all bytes in the line
    POP DX                 ; Restore DX
    POP CX                 ; Restore CX
    POP BX                 ; Restore BX
    RET
out_line endp

write_char proc
    PUSH AX                ; Save AX
    MOV AH, 2              ; Function code for printing a character
    INT 21h                ; Print the character in DL
    POP AX                 ; Restore AX
    RET
write_char endp

write_hexa proc
    PUSH CX                ; Save CX
    PUSH DX                ; Save DX
    MOV DH, DL             ; Save the original byte
    MOV CL, 4              ; Number of bits to shift
    SHR DL, CL             ; Shift the upper nibble to the lower nibble
    CALL write_hexa_digit  ; Print the upper nibble
    MOV DL, DH             ; Restore the original byte
    AND DL, 0Fh            ; Mask out the upper nibble
    CALL write_hexa_digit  ; Print the lower nibble
    POP DX                 ; Restore DX
    POP CX                 ; Restore CX
    RET
write_hexa endp

write_hexa_digit proc
    PUSH DX                ; Save DX
    CMP DL, 10             ; Check if the digit is less than 10
    JB non_hexa_letter      ; If so, jump to non_hexa_letter
    ADD DL, "A"-"0"-10     ; Convert to a letter (A-F)
non_hexa_letter:
    ADD DL, "0"            ; Convert to ASCII
    CALL write_char        ; Print the character
    POP DX                 ; Restore DX
    RET
write_hexa_digit endp

CR EQU 13                ; Carriage return
LF EQU 10                ; Line feed

cr_lf proc
    PUSH DX                ; Save DX
    MOV DL, CR
    CALL write_char        ; Move cursor to the beginning of the line
    MOV DL, LF
    CALL write_char        ; Move cursor to the next line
    POP DX                 ; Restore DX
    RET
cr_lf endp

read_decimal proc
    PUSH AX                ; Save AX
    PUSH BX                ; Save BX
    MOV BL, 10             ; Decimal base
    XOR AX, AX             ; Clear AX
read_decimal_new:
    CALL read_char         ; Read a character
    CMP DL, CR             ; Check for Enter key
    JE read_decimal_end    ; If Enter, end input
    SUB DL, "0"            ; Convert ASCII to integer
    MUL BL                 ; Multiply by 10
    ADD AL, DL             ; Add the next digit
    JMP read_decimal_new   ; Continue reading
read_decimal_end:
    MOV DL, AL             ; Store the result in DL
    POP BX                 ; Restore BX
    POP AX                 ; Restore AX
    RET
read_decimal endp

read_char proc
    PUSH AX                ; Save AX
    MOV AH, 1              ; Function code for reading a character
    INT 21h                ; Read one character into AL
    CMP AL, 27             ; Check for ESC key (ASCII 27)
    JE escape              ; Exit if ESC is pressed
    MOV DL, AL             ; Store the character in DL
    POP AX                 ; Restore AX
    RET
escape:
    MOV AH, 4Ch            ; Exit program
    INT 21h
read_char endp

END main

The issue I am encountering is that when I try to read the sector number, it always results in the same output. I’ve tested with different inputs, but the result doesn't change. The program does not give any error codes, but I’m not sure what’s causing this behavior.

I suspect there may be an issue with how the sector number is being stored or passed around, but I can’t seem to figure it out. Any help or insight would be greatly appreciated!

Share Improve this question edited 2 days ago Martin Máté Hajc asked 2 days ago Martin Máté HajcMartin Máté Hajc 133 bronze badges 2
  • 1 This is not a minimal reproducible example. Please provide all the code. Since you tagged tasm I assume you also have the excellent turbo debugger. Use that to single step the program and see where it goes wrong. – Jester Commented 2 days ago
  • 2 As Jester points out this isn't complete since we don't have the code for read_decimal and write_block so we can't determine how those functions work. I find this suspicious XOR DX, DX ;Set DS:DX to point to data to be displayed. If DS:DX is the data to be displayed it seems wrong to me you'd choose DS:0. You'd think you'd want to load DX with the LEA DX, block to display the data you just loaded. – Michael Petch Commented 2 days ago
Add a comment  | 

1 Answer 1

Reset to default 2
CALL read_decimal      ; Read the entered decimal number
MOV sector_num, AX     ; Store the sector number

The issue is that read_decimal does not return the result in AX. You preserved both AX and BX, and return the result in DL.
Because your program expects a word-sized sector_num, you could write:

CALL read_decimal      ; Read the entered decimal number -> DL
MOV  dh, 0
MOV  sector_num, dx    ; Store the sector number

Alternatively, adapt your read_decimal procedure to return the 16-bit DX by using the word-size multiplication:

    ...
    CALL read_decimal      ; Read the entered decimal number -> DX
    MOV  sector_num, dx    ; Store the sector number
    ...

    ...
    XOR CX, CX
    MOV BX, 10             ; Decimal base
    XOR AX, AX             ; Clear AX
read_decimal_new:
    CALL read_char         ; Read a character -> DL
    MOV  CL, DL            ; CH=0
    CMP  CL, CR            ; Check for Enter key
    JE   read_decimal_end  ; If Enter, end input
    SUB  CL, "0"           ; Convert ASCII to integer
    MUL  BX                ; Multiply by 10 -> DX:AX
    ADD  AX, CX            ; Add the next digit
    JMP  read_decimal_new  ; Continue reading
read_decimal_end:
    MOV  DX, AX            ; Store the result in DX
    ...

本文标签: x86Problem with Reading Sector Number in AssemblyOutput is Always the SameStack Overflow