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 Answer
Reset to default 2CALL 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
版权声明:本文标题:x86 - Problem with Reading Sector Number in Assembly - Output is Always the Same - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736645441a1946092.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
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 agoread_decimal
andwrite_block
so we can't determine how those functions work. I find this suspiciousXOR 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 theLEA DX, block
to display the data you just loaded. – Michael Petch Commented 2 days ago