2017-01-24 13 views
3

boot.img 파일의 섹터 37에있는 코드 세그먼트가 있고 마스터 부트 레코드에이 코드를 메모리 0x5678에로드했습니다 : 0x1234, 여기에 내 ASM 코드 :이시에 제출 넣으면8086 어셈블리 : 코드 세그먼트의 시작 부분에 변수 영역 넣기

[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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 

내 에뮬레이터는 도스 박스, 운영 체제 오라클 VM 가상 상자에서 실행 루 분투되고, 내 자신의 운영 체제, 파일의 끝에 win8 64에게 통지 변수 필드입니다 상단, 바로 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) 
+2

표시하지 않은 로더는 컨트롤을 실행 코드가 아닌 데이터를 포함하는'0x5678 : 0x1234'로 전송합니다. '30'은'PUSH DS'에 대한 opcode로 사용되며 코드가 제대로 실행될 수 있습니다. 추신 : 디버거를 사용하는 법을 배워보십시오. – Jester

+0

, 다시 한번 감사드립니다! – paradox

+1

당신은 DOSBox를 Windows에서 직접 실행할 수 있다는 것을 알고 있습니다. –

답변

5

내가보기 엔 디버거를 사용하는 것이 좋습니다 :

여기 내 로더입니다. 그 코멘트는 다음과 같습니다 :

디버깅 부트 로더에는 BOCHS을 권하고 싶습니다. 그것은 리얼 모드 주소 지정하고이 중단 점을 설정, 디스플레이 레지스터 실행될 때 검사 등 메모리 지침을 볼 수 있습니다 이해하는 명령 줄 디버거를 가지고

당신이 center: db 25을 배치 할 때 무슨 일이 있었는지보고 싶은 경우 코드 상단에서 NDISASM을 사용하여 인코딩 된 명령어를 덤프 할 수 있습니다.

ndisasm -b16 dt.bin 

이 명령은 16 비트 명령어한다는 가정하에 dt.bin를 분해 : 두 번째 단계를 가정하면 바이너리의 디스 어셈블 된 출력을 얻기 위해이 명령을 사용할 수 있습니다 dt.bin 아직도있다. 당신은 dt.asm의 맨 위에있는 코드 앞에 center: db 25를 배치했고 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 

당신이했던 코드가 아니다 기대하고있어! 그 값은 어디에 있습니까? 출력은 16 진수입니다. 25 진수는 0x19입니다. 첫 번째 명령어 디코딩 198CC88E을 살펴보면 19이 첫 번째 바이트임을 알 수 있습니다. 그 1 바이트는 명령 디코딩을 완전한 난센스로 바 꾸었습니다.

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입니다. 그 1 바이트 명령어는 쓸데없는 일을하지만 이후의 모든 명령어는 예상대로입니다. 이와 같이 바이너리 파일에 출력 할 때 코드 위에 데이터를두면 을 으로, NASM을 사용하면 비정상적인 문제가 발생할 수 있습니다.이러한 이유 때문에 명령 디코딩을 방해하지 않는 코드 뒤에 데이터를 배치하는 것이 가장 좋습니다.