2012-01-29 3 views
0

저수준 프로그래밍에 대한 기술을 새로 고침하기 위해 현재 x86 어셈블러를 사용 중입니다. 테스트 목적으로 주어진 문자열을 출력하는 함수를 작성하려고했습니다. 인쇄 기능 자체가 잘 작동합니다. 추가 단계에서 디스크에서 두 번째 어셈블러 프로그램을로드하여 텍스트를 인쇄하려고했습니다. 주소로 점프 할 때 디스크에서로드하는 것이 좋습니다.인쇄 기능을위한 x86 어셈블러 (nasm)의 데이터 세그먼트 문제

[... loading from disk etc ... program is loaded to 0x7e0:0001] 

jmp 0x7e0:0001 

[... context of other asm ...] 

jmp Start 
;data fields 
msg db "Hello World!",0 

Start: 
    xor si, si  ; clear SI register 
    mov si, msg ; load message to SI register 

    call Print 

    cli 
    hlt   ; halt the system 

Print: 
    .PrintLoop: 
     lodsb    ; load byte from SI register 
     or al, al   ; check if 0 byte 
     jz short .PrintDone ; if so - stop 
     mov ah, 0Ah   ; function - print text to cursor 
     int 0x10    ; BIOS interrupt 

     jmp .PrintLoop  ; continue with next char 
    .PrintDone: 
     ret 

이 프로그램은 모두 잘 작동 : 여기

은 주어진 시나리오입니다. 내가 직면하는 유일한 문제는 텍스트가 인쇄되지 않는다는 것입니다. 디버깅하는 동안 인쇄 기능을 즉시 .PrintDone 레이블을 점프 SI에서 아무런 데이터도 보이지 않으므로 lodsb는 널 바이트 이외에 아무 것도로드하지 않기 때문에 봤습니다.

데이터 세그먼트에 문제가있을 수 있다는 사실을 생각하고있었습니다.

xor ax, ax ; clear ax register 
mov ax, cs  
mov ds, ax ; set data segment pointer 

을하지만이 프로그램의 행동에 대해 아무 것도 변경하지 :

따라서, 나는 시작 루틴의 시작 부분에 다음 줄을 추가했다. 아무것도 인쇄되지 않습니다.

EAX=00000a00 EBX=00000000 ECX=00000002 EDX=00000000 
ESI=00000026 EDI=00000000 EBP=00000000 ESP=0000ffff 
EIP=00000036 EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=1 
ES =07e0 00007e00 0000ffff 00009300 
CS =07e0 00007e00 0000ffff 00009b00 
SS =9000 00090000 0000ffff 00009300 
DS =07e0 00007e00 0000ffff 00009300 

당신이 여기 무엇을 어떤 실마리이야가 있습니까 :

실행이 정지 명령에 도달하면, 다음주는 CPU 레지스터를 검사?

mov ah, 0Ah -> mov ah, 0xE 

수정 문제 -

교체 [EDIT 문제가 해결]!

최저 세바스찬

+0

'ds'를 설정 한 상태에서'.PrintDone'으로 곧바로 이동합니까, 아니면 그냥 아무것도 인쇄하지 않습니까? (나는 당신이 방해하기 바로 전에'아 '를 원한다고 생각합니다, 도끼가 아닙니다.) – ughoavgfhw

+0

안녕하세요, 도끼의 고전적인 오타가 다시 아에게 고정되었습니다. 이제이 프로그램은 뭔가 이상한 숯을 인쇄하고 있습니다. 레지스터를 검사 할 때 실행에 도달 시스템이 정지들이 다음과 같은 항목이있을 때 : ES = 07e0 00007e00 0000ffff 00009300 CS는 = 07e0는 00007e00 0000ffff 00009b00 SS = 9000 00090000 0000ffff 00009300 DS = 07e0은 00007e00 0000ffff 00009300 –

+0

나는 생각하지 않습니다 인터럽트는 커서를 움직입니다. 이는 두 개 이상의 문자가 인쇄되면 마지막 문자 만 볼 수 있음을 의미합니다. 또한 'si'가 끝 부분의 올바른 지점을 가리키고 있는지 확인하십시오. 내가 옳은 것으로 계산되면 "데이터 필드"에 24 바이트의 데이터가 있어야합니다. 코드는 괜찮아 보입니다. – ughoavgfhw

답변

2

은 몇 가지 문제가 있습니다.

먼저 함수 0Ah의 레지스터를 올바르게 설정하지 않았습니다. bh을 페이지 번호 (0)로 설정하고 cx을 반복 횟수 (1)로 설정해야합니다.

둘째,이 BIOS 기능은 커서 위치를 앞으로 이동하지 않으며 모든 문자가 화면의 동일한 위치에 인쇄되어 서로 겹쳐 쓰므로 '!' 마지막 문자이므로 표시됩니다.

대신 0Eh 기능을 사용하는 것이 좋습니다.

셋째, lodsb이 의존하는 방향 플래그 (flags.df)를 초기화하지 않습니다. df을 재설정하려면 cld을 사용해야합니다.

넷째, 모든 코드가 표시되지 않지만 적절한 org 지시문을 사용하여 지침과 데이터에 대한 올바른 오프셋을 생성해야합니다.

또한 NMIsSMIshlt으로 끝나고 그 다음 코드가 실행됩니다 (다음은 사용자의 Print입니다). 루프에서 hlt을 실행하려고합니다. 우리가 도착 이러한 수정으로

:

bits 16 
org 1 

jmp Start 
;data fields 
msg db "Hello World!",0 

Start: 
    mov ax, cs  
    mov ds, ax ; set data segment pointer 
    cld 

    mov si, msg ; load message to SI register 

    call Print 

    cli 
.halt: 
    hlt   ; halt the system 
    jmp .halt 

Print: 
    .PrintLoop: 
     lodsb    ; load byte from SI register 
     or al, al   ; check if 0 byte 
     jz short .PrintDone ; if so - stop 
;   mov ah, 0Ah   ; function - print text to cursor 
;   xor bh, bh 
;   mov cx, 1 
     mov ah, 0Eh   ; function - print text tty 

     int 0x10    ; BIOS interrupt 

     jmp .PrintLoop  ; continue with next char 
    .PrintDone: 
     ret 

당신이 nasm blah.asm -f bin -o blah.bin과 위를 컴파일하여 얻을 진 다음 0x7e0:0001로드와 jmp 0x7e0:0001로 뛰어 올랐다해야합니다.

+0

게시물 주셔서 감사합니다! 하지만 'org 0'이되어서는 안됩니까? 프로그램이 offset 0001로 기본 주소 0x7e0에로드되기 때문에 org 1은 1 바이트를 더 잘 잘라 낼 수 있습니까? 이 프로그램은 'ello World!'를 인쇄 할 수 있습니다. –

+0

'org n'은 맨 처음 명령 또는 데이터 항목의 오프셋을 'n'으로 설정합니다. 당신이'org 0', 0에서로드하지만 0x7e0 : 1로 점프한다면, 당신은 시작 대신에'jmp Start' 중간으로 뛰어갑니다. 당신이'org 0'이고, 0에서로드하고, 0x7e0 : 0으로 점프한다면, 모든 것이 OK입니다. 마찬가지로'org 1'이라면 모든 것이 OK이고, 1에서로드되고, 0x7e0 : 1로 점프합니다. –

+0

모두 지우기 - 감사합니다 :) –