2017-12-22 44 views
1

내 코드가 8086 & 80286 프로세서에 비해 너무 느립니다. 따라서 실제 모드 코드에 32 비트 레지스터와 명령어를 사용하기로 결정했습니다.기본 세그먼트 정의 크기를 변경하지 않고 MASM에서 32 비트 레지스터 사용

내가 할 수 있어야 할 필요가있는 것은 66h로 접두어로되어 있지만, 어셈블리 파일의 맨 위에 .386 지시문을 포함시키지 않으면 386 개의 레지스터가 MASM에서 허용되지 않는다는 것을 알고 있습니다. .

이렇게하면 386 개의 레지스터를 사용하지 않아도 프로그램이 더 이상 작동하지 않는 것으로 나타났습니다. 그것은 검은 화면에서 중단 후 DOSBox 충돌합니다. 이는 일반적으로 프로그램에서 스택 크래시 및 메모리 손상을 나타내는 동작입니다.

MASM 5.10 (내가 사용하는 버전)에 대한 설명서에서이 정보를 발견했습니다. ".MODEL 지시문 앞에 .386 지시문을 사용하면 세그먼트 정의는 32 비트 세그먼트를 정의합니다. 16 비트 세그먼트를 가진 80386 프로세서라면, .MODEL 지시문 뒤에 .386 지시문을 주어야합니다. "

저는 여기에 제 문제가 있다고 확신합니다. 세그먼트가 16 비트로 유지되도록 .MODEL 지시문을 포함해야합니다. .386 지시문을 사용하기 전에 나열된 .MODEL 지시문 (설명서가 가장 일반적인 모델로 참조 됨)을 주 어셈블리 파일에 포함하여 시도했습니다. 그들은 모두 내 프로그램을 구성하는 다른 12 개의 어셈블리 파일 중 하나에 .MODEL 지시문을 포함하지 않는다는 사실로 인해 발생할 수있는 오류를 생성합니다. 그냥 기본 .MODEL을 계속 사용하고 싶습니다.

.MODEL 지시문을 지금까지 사용할 필요가 없었습니다. 설명서에 기본적으로 사용되는 언급이 없거나 .386을 사용하면 16 비트 세그먼트가 그대로 유지됩니다.

.MODEL SMALL, .MODEL MEDIUM과 같이 많은 링커 오류 발생 모든 .MODEL COMPACT : 오류 L2002을 : 세그먼트 코드의 POS에서 0016에서 픽스 오버 플로우 : 1FA 기록 유형 : LARGE 48A8

.MODEL .MODEL HUGE는 잘 어셈블하고 연결하지만 비디오 메모리에 덤프 된 일부 쓰레기와 함께 나중에 몇 프레임짜리 프로그램이 충돌합니다. 아마도 스택 충돌입니다. 또 다른 12 개의 어셈블리 파일에 .MODEL 지시문을 포함시키지 않습니다.

가끔 내가 원하는 것은 386 개의 레지스터와 명령어를 사용할 수 있지만, 그렇지 않으면 프로그램이 항상 똑같은 동작을하기를 원합니다. 16 비트와 같은 모든 세그먼트를 처리합니다.

여기 내 메인 어셈블리 파일입니다. 어떤 모델인지 확실하지 않습니다. 아마, 아마도? 64k보다 큰 단일 세그먼트는 없으므로 그렇지 않을 수도 있습니다. 단일 스택 세그먼트와 단일 코드 세그먼트가 있지만 여러 개의 데이터 세그먼트가 있습니다. 이 모든 것은 공개되어 있으며 프로그램을 구성하는 어셈블리 파일 전체에서 공유됩니다.

theStack SEGMENT STACK              

db 64 dup ('THESTACK') ;512 byte stack 

theStack ENDS                





varData SEGMENT PUBLIC                     

INCLUDE const.inc  ;global constants 

PUBLIC fCntr 

fCntr db 0   ;A frame counter used to delay animations. 

varData ENDS                






frame SEGMENT PUBLIC              

db scrArea dup (247d) ;64,000 byte frame buffer 

frame ENDS                 






field SEGMENT PUBLIC              

db 65535 dup ('F')  ;64k buffer that holds up to 32,768 tile indexes 

field ENDS                 







sprites SEGMENT PUBLIC              

db 65535 dup ('S')  ;64k buffer for animated spites 

sprites ENDS                               






code SEGMENT PUBLIC 

EXTRN SET_VGA_256:PROC,INIT_DISK_VARS:PROC,INIT_AREA:PROC,CALC_DELAY:PROC 
EXTRN HANDLE_INPUT:PROC,UPDATE_SPRITES:PROC,DRAW_SPRITES:PROC 
EXTRN DRAW_FIELD:PROC,WRITE_FRAME:PROC,FRAME_DELAY:PROC,EXIT2DOS:PROC 
EXTRN DBG:PROC      

assume cs:code,ds:varData            

main PROC                 

start:                  

    mov ax, varData        
    mov ds, ax    ;Load the variable segment into ds            
    cld      ;ensure that string operations auto-increment 



    call SET_VGA_256   ;Set the video mode to 320x200 256 colors. 
    call INIT_DISK_VARS  ;Setup hard drive access variables 
    call INIT_AREA   ;Build the area into memory from data files 
    call CALC_DELAY   ;calculate the frame delay using the RTC 



LOOP_TILL_ESC: 
    call HANDLE_INPUT  ;Handle user input. 
    call UPDATE_SPRITES  ;bounds check then move the sprites 
    call DRAW_FIELD   ;draw the tiles that make up the play field 
    call DRAW_SPRITES  ;draw all currently visible sprites 
    call WRITE_FRAME   ;Write the frame buffer to video memory. 
    inc fCntr    ;increment the frame counter 
    call FRAME_DELAY   ;delay for the specified number of milliseconds 
    cmp bp, 1    ;Was the Esc key pressed? 
    jne LOOP_TILL_ESC  ;If not, loop back through the main program. 
    call EXIT2DOS   ;If so, return to DOS. 



main ENDP                 

code ENDS                 

END start    

다음은 .386이 사용되면 중단되는 간단한 프로그램입니다. 그것은 분홍색 픽셀로 화면을 채우기로되어 있지만 대신 그것은 검은 화면에서 멈추고 도스 박스를 충돌시킵니다.

.MODEL SMALL 
.386 

theStack SEGMENT STACK              

db 64 dup ('THESTACK') 

theStack ENDS                




code SEGMENT PUBLIC 

assume cs:code,ds:varData            

main PROC                 

start:                  

    mov ax, varData        
    mov ds, ax     ;Load the variable segment into ds            
    cld       ;ensure that string ops auto-increment 



    xor ah, ah     ;select set video mode function 
    mov al, 13h     ;320x200 256 colors 
    int 10h      ;video mode set 

    mov di, 0a000h    
    mov es, di 
    xor di, di     ;es:di -> vga pixel buffer 
    mov ah, 64d 
    mov al, ah     ;ah & al -> pink color index byte 
    mov cx, 32000d    ;writing 32,000 words 
    rep stosw     ;fill the screen with pink pixels 

ESC_LOOP: 
    in al, 60h 
    cmp al, 1 
    jne ESC_LOOP     ;delay till escape key is pressed 

    mov ax, 40h 
    mov es, ax     ;access keyboard data area via segment 40h 
    mov WORD PTR es:[1ah], 1eh ;set the kbd buff head to start of buff 
    mov WORD PTR es:[1ch], 1eh ;set the kbd buff tail to same as buff head 
           ;now the keyboard buffer is cleared. 
    xor ah, ah     ;select video mode function 
    mov al, 3     ;select 80x25 16 colors 
    int 10h      ;restore VIDEO back to text mode 




mov ah, 4ch      ;Terminate process DOS service 
xor al, al      ;Pass 0 to ERRORLEVEL 
int 21h       ;Control returns to DOS 

main ENDP                 

code ENDS                 

END start        
+0

이전에 사용한 프로그래밍 모델은 무엇입니까? 코드를 볼 수 있습니까? L2002 오류는 너무 멀리있는 기호를 참조하려고 시도했음을 나타내지 만 코드를 보지 않고는 정확히 틀린 것을 말하기 어렵습니다. – fuz

+0

좋아요, 주 어셈블리 파일에서 수정하겠습니다. 나는 모델을 사용한 적이 없다. 그것은 무엇이든을 사용하고 있었다 디폴트. –

+0

'.model '없이 세그먼트를 어떻게 정의합니까? '.code'와 다른 단축키를 피하고 세그먼트를 완전히 정의 할 수 있습니까? 그렇다면 16b 코드 세그먼트 안에'.386 '을 포함하는 것은 아마도'.model'없이도 작동 할 수 있습니다. 그러나 이것은 실제 MASM 지식/경험과 관련이없는 논리적 의미에 기반한 것입니다. 그리고 목표 아키텍처는 무엇입니까, 얼마나 많은 코드/데이터가 있습니까? 당신은 "작은"모델에 들어 맞습니까? (하나의 데이터 세그먼트 + 하나의 코드 세그먼트) – Ped7g

답변

3

문제 설명이 100 % 정확하지는 않지만 문제의 "분홍색"샘플 소스는 완전히 설명하는 좋은 예입니다.

.MODEL.CODE, .CONST, .DATA, .DATA?, .FARDATA, .FARDATA?, .STACK 지시자와 함께 상기 "간략화 세그먼트 지시자" 속한다. 작업 패션과 16B DOS 실행 파일에서 다음을 사용

그래서 한 가지 방법은 다음과 같이이다 :

.MODEL SMALL 
.386 

.STACK 100h 

.DATA 
x DB 1 

.CODE 
start: 
    mov  ax,@DATA 
    mov  ds,ax 
    movzx eax,BYTE PTR [x] 

    mov  ah,4Ch 
    int  21h 
END start 

독점적으로 만 단순화 된 지시어를 사용하여 .CODE는 16B 리얼 모드 코드가 _TEXT라는 이름의 코드 세그먼트를 정의합니다 (.MODEL SMALL 지시문 이후 에 붙는 .386 지시문 덕분에).

"분홍색"예제는 단순화 된 세그먼트 지시문을 사용하지 않지만 완전한 세그먼트 지시문은 사용하지 않습니다. 그런 다음 코드 세그먼트 정의에 다음 고정 소스에서와 같이 리얼 모드 용으로 지정해야합니다. (16b 레지스터 사용), 시안 색 (시 리얼 모드에서 32b 레지스터 사용)의 키를 사용한 후.

code SEGMENT 지시문에 USE16을 추가하여 올바르게 설정해야합니다. 그런 다음 생성 된 32b 명령어는 16b 리얼 모드 (즉, 32b 보호 모드 이외의 다른 방법)에 올바른 방법으로 접두사가 붙습니다.

내가 더 당신이 단순화 .CODE 지시문이 명시 적 코드 세그먼트 정의를 혼합하고, 놀라 울 (나에게) 때 최종 .EXE도 .MODEL SMALL 모델이 개 코드 세그먼트를 가지고 일이 ... 그래서 시험 절차가 무슨 테스트 않았다

"dotCode"세그먼트에서 FAR 호출을 통해서만 접근 할 수 있습니다. 적어도 .CODE 세그먼트는 16b 세그먼트로 올바르게 지정되므로 생성 된 어셈블리가 예상대로 작동합니다.

고정 예 (TASM 4.1 + TLINK 테스트, 단지 파일의 이름과 옵션없이 실행, ASM은 -> OBJ -> EXE 파일이 생성되어야한다) :

.MODEL SMALL 
.386 

theStack SEGMENT USE16 STACK 

db 64 dup ('THESTACK') 

theStack ENDS 

; test of simplified code segment directive 
.CODE 
testDotCode PROC 
    mov  eax,12345678h 
    retf 
testDotCode ENDP 
ENDS 

code SEGMENT USE16 PUBLIC 

assume cs:code, ss:theStack 

main PROC 
    call FAR PTR testDotCode ; test code inside simplified code segment definition 
    ; with experiment I find out, that even with ".MODEL SMALL" the TASM+TLINK will 
    ; put the testDotCode subroutine into new "_TEXT" code segment! 
    ; So only FAR call + retf works to access it. 

    cld       ; ensure that string ops auto-increment 
    mov  ax, 13h    ; select set video mode function: 13h 320x200 256 colors 
    int  10h     ; video mode set 

    mov  di, 0a000h 
    mov  es, di    ; es = VRAM segment 

    ; original 16b test code - fill screen with pink 
    xor di, di     ;es:di -> vga pixel buffer 
    mov ah, 64d 
    mov al, ah     ;ah & al -> pink color index byte 
    mov cx, 32000d    ;writing 32,000 words 
    rep stosw     ;fill the screen with pink pixels 

    ; wait for any key 
    xor  ah,ah 
    int  16h 

    ; 32b test code to validate ".386" setup success in real mode 
    xor  di, di    ; es:edi -> vga pixel buffer 
    mov  eax, 34343434h  ; eax = 4x cyan color 
    mov  ecx, 320*200/4  ; full screen fill 
    rep stosd     ; fill the screen with pink pixels 

    ; wait for any key 
    xor  ah,ah 
    int  16h 

    ; restore text mode (3) 
    mov  ax,3    ; select video mode: text 80x25 16 colors 
    int  10h 

    mov  ax,4C00h   ; terminate DOS process with 0 ERRORLEVEL 
    int  21h 
main ENDP 

code ENDS 

END main 

나는 대부분이 웹 페이지를 사용 http://www.c-jump.com/CIS77/ASM/Directives/lecture.html#D77_0070_code_directive

그리고이 대답은 적절한 TASM/MASM 문서를 철저히 대체하는 것이 아니라 불행히도 문제의 원인을 설명하는 것입니다.

0

.386 지시문이 어셈블리 파일 맨 위에 속한다고 잘못 생각했습니다. 사실 그것은 코드 세그먼트 정의 안에 속합니다. 스택 정의 위에 .386을 포함 시키면 스택에 WORD가 아닌 DWORD 정렬 유형이 지정되어 push ax과 같은 스택 작업이 push eax으로 처리되고 있음을 의미합니다.이로 인해 16 비트 스택을 예상하는 코드와의 호환성이 깨져서 내 프로그램이 중단되었습니다.

.386을 사용한 후에 다른 세그먼트가 정의되기 전에 .8086 지시문을 사용해야합니다.

+2

더 많은 경우,'.386'은 32 비트 모드로 동작해야하는 기계어를 만들기 위해 어셈블러를 얻었습니다. 16 비트 모드에서 피연산자 크기 접두사가 필요하지만 'push eax'는 16 비트 모드에서 해당 기계 코드를 실행하는 경우 반대가됩니다. 비트 모드는 피연산자 크기를 32 비트로 만들었으므로'push eax '를 얻을 수 있습니다.'push axs '를 의도적으로 push eax로 조합하는 것보다 더 가능성이 높습니다. 그러나'add axx, 0x1234'로 확인할 수 있습니다. 그 문제는 잘못된 위치에 지시문을 사용하여'add eax, imm32' (여분의 바이트를 소비)로 변합니다. –

+0

결코 놀랄 일이 아닙니다. 문제는 32 비트 명령어를 사용하는 DOS 응용 프로그램의 맨 위에 .386을 항상 넣을 것이라고 생각했습니다. 그래도 충분하지만 여전히 돌아 다니는 소스 코드를 검사 할 때마다 항상 모델과 코드 이후였습니다 ... 바보 같은 행운이 나를 다시 보호 해 준 것 같습니다. :-) –

+1

@BrianKnoblauch 나는 최근에 다른 질문에'SEGMENT' 지시어로 답을 추가했는데, 재미를 위해서 문서에서 보았을 때 즉시'USE16'을 추가 했으므로 첫 번째 시도에서 작동했습니다 행운을 빕니다. 그리고 나는 전체 세그먼트 정의가 기본적으로 32b이고 보호 모드에 대한 opcode를 생성하고 16b 리얼 모드 코드를 깨는이 트랩이 있는지 전혀 몰랐습니다. OP가 샘플 소스 코드를 추가하기 전에는 디버거에서 직접 보았을 때까지 오히려 opcodes 자체가 틀렸다는 것을 믿을 수는 없었습니다. :디 – Ped7g