当前位置:  开发笔记 > 编程语言 > 正文

8086汇编:将变量区域放在代码段的开头

如何解决《8086汇编:将变量区域放在代码段的开头》经验,为你挑选了1个好方法。

我有一个代码段位于boot.img文件的扇区37,在我的主启动记录中,我将此代码加载到内存0x5678:0x1234,这是我的asm代码:

[BITS 16]               ;Set code generation to 16 bit mode

ORG 0x1234      ;set addressing to begin at 0x5678:0x1234
mov ax, cs
mov ds, ax
mov es, ax



  call cls  ;call routine to clear screen
  call dspmsg   ;call routine to display message

startdt:
  call date
  call cvtmo
  call cvtday
  call cvtcent
  call cvtyear
  call dspdate

  call time
  call cvthrs
  call cvtmin
  call cvtsec
  call dsptime

  jmp startdt   ;use infinite loop to halt?

cls:             
  mov ah,06h    ;function 06h (Scroll Screen)
  mov al, 0 ;scroll all lines
  mov bh,0x0a   ;Attribute (light green on black)
  mov ch,0  ;Upper left row is zero
  mov cl,0  ;Upper left column is zero
  mov dh,24 ;Lower left row is 24
  mov dl,79 ;Lower left column is 79
  int 10H   ;BIOS Interrupt 10h (video services)
  ret

dspmsg: 
  mov ah,13h    ;function 13h (Display String)
  mov al,0  ;Write mode is zero
  mov bh,0  ;Use video page of zero
  mov bl,0x0c   ;Attribute (light red on black)
  mov cx,msglen ;Character string is 25 long
  mov dh,3  ;position on row 3
  mov dl,[center]   ;and column 28
  lea bp,[msg]  ;load the offset address of string into BP
  int 10H
  ret
  msg:  db 'Pradox V 0.1 Jiansong He',10,13
  msglen: equ $-msg

  int 10H
  ret

date:
;Get date from the system
mov ah,04h   ;function 04h (get RTC date)
int 1Ah     ;BIOS Interrupt 1Ah (Read Real Time Clock)
ret

;CH - Century
;CL - Year
;DH - Month
;DL - Day

cvtmo:
;Converts the system date from BCD to ASCII
mov bh,dh ;copy contents of month (dh) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [dtfld],bh
mov bh,dh
and bh,0fh
add bh,30h
mov [dtfld + 1],bh
ret

cvtday:
mov bh,dl ;copy contents of day (dl) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [dtfld + 3],bh
mov bh,dl
and bh,0fh
add bh,30h
mov [dtfld + 4],bh
ret

cvtcent:
mov bh,ch ;copy contents of century (ch) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [dtfld + 6],bh
mov bh,ch
and bh,0fh
add bh,30h
mov [dtfld + 7],bh
ret

cvtyear:
mov bh,cl ;copy contents of year (cl) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [dtfld + 8],bh
mov bh,cl
and bh,0fh
add bh,30h
mov [dtfld + 9],bh
ret

dtfld: db '00/00/0000'

dspdate:
;Display the system date
mov ah,13h ;function 13h (Display String)
mov al,0 ;Write mode is zero
mov bh,0 ;Use video page of zero
mov bl,0x0a;Attribute
mov cx,10 ;Character string is 10 long
mov dh,4 ;position on row 4
mov dl,[center] ;and column 28
push ds ;put ds register on stack
pop es ;pop it into es register
lea bp,[dtfld] ;load the offset address of string into BP
int 10H
ret

time:
;Get time from the system
mov ah,02h
int 1Ah
ret

;CH - Hours
;CL - Minutes
;DH - Seconds

cvthrs:
;Converts the system time from BCD to ASCII
mov bh,ch ;copy contents of hours (ch) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [tmfld],bh
mov bh,ch
and bh,0fh
add bh,30h
mov [tmfld + 1],bh
ret

cvtmin:
mov bh,cl ;copy contents of minutes (cl) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [tmfld + 3],bh
mov bh,cl
and bh,0fh
add bh,30h
mov [tmfld + 4],bh
ret

cvtsec:
mov bh,dh ;copy contents of seconds (dh) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [tmfld + 6],bh
mov bh,dh
and bh,0fh
add bh,30h
mov [tmfld + 7],bh
ret

tmfld: db '00:00:00'

dsptime:
;Display the system time
mov ah,13h ;function 13h (Display String)
mov al,1 ;Write mode is zero
mov bh,0 ;Use video page of zero
mov bl,0x0a;Attribute
mov cx,8 ;Character string is 8 long
mov dh,5 ;position on row 5
mov dl,[center];and column 0
push ds ;put ds register on stack
pop es ;pop it into es register
lea bp,[tmfld] ;load the offset address of string into BP
int 10H
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;variables;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
center: db 25

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;end variables;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

我的模拟器是dosbox,操作系统是运行在Oracle VM虚拟盒上的lubuntu,我自己的操作系统是win8 x64注意文件末尾的变量字段,如果我把这个文件放在顶部,我更新了我的DS和ES之后注册,我遇到了一个问题:cls和dspmsg子例程将无法工作,但如果我将值更改为center: db 30或只是将此字段放在我的代码的末尾,它将工作.有人可以解释为什么将变量字段放在我的代码之上并更改标签的值会影响程序的性能吗?这与我的段寄存器有关吗?

这是我的装载机:

;bit16                  ; 16bit by default
    org 0x7c00
    jmp short start
    nop
bsOEM   db "OS423 v.0.1"               ; OEM String

start:

;;load sector into memory & 5678h:1234h
    mov bx, 0x5678  ;segmented address
    mov es, bx      ;move segemented address to es
    mov bx,0x1234       ;base address to bx

    mov ah, 02      ;function read sectors
    mov al, 01      ;# of sectors to load
    mov ch, 00      ;track to read
    mov cl, 02      ;sector to read
    mov dh, 00      ;head to read
    mov dl, 00          ;drive number

    int 0x13            ;call interrupt 13 

    jmp 0x5678:0x1234       ;jump to memory address 


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;variables;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

msg:  db 'Welcome to Pradox OS 0.1! Authored by Jiansong he', 10, 13, '$' 
mlen equ $-msg

padding times 510-($-$$) db 0       ;to make MBR 512 bytes
bootSig db 0x55, 0xaa       ;signature (optional)

Michael Petc.. 5

正如Jester(以及我在上一个问题中)所提到的,我强烈建议使用调试器.该评论是:

我建议使用BOCHS来调试bootloaders.它有一个命令行调试器,可以理解实模式寻址,可用于在执行时查看指令,设置断点,显示寄存器,检查内存等.

如果您希望查看放置center: db 25在代码顶部时发生的情况,可以使用NDISASM转储已编码的指令.假设您的第二阶段仍然是dt.bin您可以使用此命令来获取该二进制文件的反汇编输出:

ndisasm -b16 dt.bin

该命令dt.bin在假设它是16位指令的情况下被反汇编.如果你要放在center: db 25顶部的代码之前dt.asm并组装dt.bin并运行上面的命令,你会得到类似这样的输出:

00000000  198CC88E          sbb [si-0x7138],cx
00000004  D88EC0E8          fmul dword [bp-0x1740]
00000008  2600E8            es add al,ch
0000000B  3400              xor al,0x0
0000000D  E86600            call word 0x76

那不是你期待的代码!那个值25在哪里?输出为十六进制.那个25十进制是0x19.如果你检查第一个指令解码,198CC88E你会看到19第一个字节.该单个字节将指令解码变为完全无意义.

如果换center: db 25center: db 30?会发生什么?如果您尝试组装它并再次使用上面的NDISASM命令,您应该看到:

00000000  1E                push ds
00000001  8CC8              mov ax,cs
00000003  8ED8              mov ds,ax
00000005  8EC0              mov es,ax
00000007  E82600            call word 0x30

30十进制是0x1e.正如Jester所指出的,0x1e本身就是一个指令push ds.那个单字节指令做了一些无用的事情,但之后的所有指令都是你所期望的.输出到像这样使用二进制文件时将上述代码数据-f binNASM会引起异常的问题.因此,最好将数据放在代码之后,它不会干扰指令解码.



1> Michael Petc..:

正如Jester(以及我在上一个问题中)所提到的,我强烈建议使用调试器.该评论是:

我建议使用BOCHS来调试bootloaders.它有一个命令行调试器,可以理解实模式寻址,可用于在执行时查看指令,设置断点,显示寄存器,检查内存等.

如果您希望查看放置center: db 25在代码顶部时发生的情况,可以使用NDISASM转储已编码的指令.假设您的第二阶段仍然是dt.bin您可以使用此命令来获取该二进制文件的反汇编输出:

ndisasm -b16 dt.bin

该命令dt.bin在假设它是16位指令的情况下被反汇编.如果你要放在center: db 25顶部的代码之前dt.asm并组装dt.bin并运行上面的命令,你会得到类似这样的输出:

00000000  198CC88E          sbb [si-0x7138],cx
00000004  D88EC0E8          fmul dword [bp-0x1740]
00000008  2600E8            es add al,ch
0000000B  3400              xor al,0x0
0000000D  E86600            call word 0x76

那不是你期待的代码!那个值25在哪里?输出为十六进制.那个25十进制是0x19.如果你检查第一个指令解码,198CC88E你会看到19第一个字节.该单个字节将指令解码变为完全无意义.

如果换center: db 25center: db 30?会发生什么?如果您尝试组装它并再次使用上面的NDISASM命令,您应该看到:

00000000  1E                push ds
00000001  8CC8              mov ax,cs
00000003  8ED8              mov ds,ax
00000005  8EC0              mov es,ax
00000007  E82600            call word 0x30

30十进制是0x1e.正如Jester所指出的,0x1e本身就是一个指令push ds.那个单字节指令做了一些无用的事情,但之后的所有指令都是你所期望的.输出到像这样使用二进制文件时将上述代码数据-f binNASM会引起异常的问题.因此,最好将数据放在代码之后,它不会干扰指令解码.

推荐阅读
我我檬檬我我186
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有