Home > Back-end >  Display an Array of Strings using 8086 MS-DOS Assembly
Display an Array of Strings using 8086 MS-DOS Assembly

Time:11-06

I'm trying to display an array using Borland Turbo Assembler 5 (similar to MASM syntax as far as I know) for MS-DOS, the first string prints but remaining ones don't. Any advice on best way to accomplish this with 8086 compatible MS-DOS assembly?

    ; TEST.COM:    
    
    stdin   equ     0   ; standard input handle
stdout  equ     1   ; standard output handle
stderr  equ     2   ; standard error handle

cr      equ     0dh ; ASCII carriage return
lf      equ     0ah ; ASCII linefeed
escape  equ     1Bh ; escape
fg_black equ    escape,'[30m'
fg_red   equ    escape,'[31m'

_TEXT   segment word public 'CODE'

    org     100h

    assume  cs:_TEXT,ds:_TEXT,es:_TEXT,ss:_TEXT

main    proc near   
        mov     bx,dir_array
        mov     ah,9
dirloop:
        lea     dx,[bx]
        int     21h
        add     bx,2
        cmp     bx,offset dir_array dir_array_size
        jl      dirloop

        mov     ax,4C00h
        int     21h

main    endp

msg1    db  cr,lf
        db  'DOS FindFirst API Test',cr,lf

dir_array       dw dos_dir,int21_3E_dir,test_dir1,test_dir2,test_dir3
end1 db '$'
dir_array_size  equ $-dir_array
end2 db '$'
dos_dir    db 'C:\DOS',cr,lf,'$'
int21_3E_dir db "C:\DOS\INT21_3E",cr,lf,'$'
test_dir1   db "C:\DOS\INT21_3E\TEST1",cr,lf,'$'
test_dir2   db "C:\DOS\INT21_3E\TEST2",cr,lf,'$'
test_dir3   db "C:\DOS\INT21_3E\TEST3",cr,lf,'$'
test_file1   db "C:\DOS\INT21_3E\ARC.TXT",0
test_file2   db "C:\DOS\INT21_3E\RONLY.TXT",0
test_file3   db "C:\DOS\INT21_3E\SYSTEM.TXT",0
test_file4   db "C:\DOS\INT21_3E\HIDDEN.TXT",0
msg1_len equ $-msg1
_TEXT   ends

end main

Checking with turbo debugger I can see "bx" is being assigned the value dos_dir but I was hoping it would specify the address of dir_array.

enter image description here

The first string is at 13E:

enter image description here

Output:

enter image description here

CodePudding user response:

Fixed code, using lea instruction to load array, and an 'end1' to mark the end of array.

stdin   equ     0   ; standard input handle
stdout  equ     1   ; standard output handle
stderr  equ     2   ; standard error handle

cr      equ     0dh ; ASCII carriage return
lf      equ     0ah ; ASCII linefeed
escape  equ     1Bh ; escape
fg_black equ    escape,'[30m'
fg_red   equ    escape,'[31m'

_TEXT   segment word public 'CODE'

    org     100h

    assume  cs:_TEXT,ds:_TEXT,es:_TEXT,ss:_TEXT

main    proc near   
        lea     bx,dir_array
        mov     ah,9
dirloop:
        mov     dx,[bx]
        int     21h
        add     bx,2
        cmp     bx,offset end1
        jl      dirloop

        mov     ax,4C00h
        int     21h

main    endp

msg1    db  cr,lf
        db  'DOS FindFirst API Test',cr,lf

dir_array       dw dos_dir,int21_3E_dir,test_dir1,test_dir2,test_dir3
end1 db '$'
dir_array_size  equ $-dir_array
end2 db '$'
dos_dir    db 'C:\DOS',cr,lf,'$'
int21_3E_dir db "C:\DOS\INT21_3E",cr,lf,'$'
test_dir1   db "C:\DOS\INT21_3E\TEST1",cr,lf,'$'
test_dir2   db "C:\DOS\INT21_3E\TEST2",cr,lf,'$'
test_dir3   db "C:\DOS\INT21_3E\TEST3",cr,lf,'$'
test_file1   db "C:\DOS\INT21_3E\ARC.TXT",0
test_file2   db "C:\DOS\INT21_3E\RONLY.TXT",0
test_file3   db "C:\DOS\INT21_3E\SYSTEM.TXT",0
test_file4   db "C:\DOS\INT21_3E\HIDDEN.TXT",0
msg1_len equ $-msg1
_TEXT   ends

end main

CodePudding user response:

I can see bx is being assigned the value dos_dir but I was hoping it would specify the address of dir_array.

TASM follows MASM-style where writing mov bx, dir_array will fetch a word from memory and store it in BX, but mov bx, offset dir_array will store the effective address in BX. You can also obtain the effective address via lea bx, dir_array, but that would waste a byte. mov - offset use 3 bytes vs lea using 4 bytes.

Because the dir_array contains 5 words and you appended a further byte to it, the dir_array_size equ $-dir_array equate will set dir_array_size equal to 11. This means that the loop will run too long! Just drop the extra byte and also treat the conditional as unsigned, after all it's a count.

A solution

  mov  si, offset dir_array
dirloop:
  lodsw
  mov  dx, ax
  mov  ah, 09h   ; DOS.PrintString
  int  21h
  cmp  si, offset dir_array   dir_array_size
  jb   dirloop

  ...

dir_array       dw dos_dir, int21_3E_dir, test_dir1, test_dir2, test_dir3
dir_array_size  equ $-dir_array

An alternative solution

  xor  bx, bx
dirloop:
  mov  dx, dir_array[bx]
  mov  ah, 09h   ; DOS.PrintString
  int  21h
  add  bx, 2
  cmp  bx, dir_array_size
  jb   dirloop

  ...

dir_array       dw dos_dir, int21_3E_dir, test_dir1, test_dir2, test_dir3
dir_array_size  equ $-dir_array
  • Related