2013-01-09 22 views
5

Ich versuche zu lernen, DOS.EXE-Dateien mit Assembly (NASM) zu erstellen, den Header manuell erstellen und die Datei zusammenstellen als binär. Ich habe ein Problem mit den Seitenoptionen (sowohl die Gesamtzahl der Seiten als auch die Byteanzahl auf der letzten Seite). Egal wie klein ich die Anfangswerte festlege, das Programm wird funktionieren.Bedeutung der Anzahl der Seiten und der letzten Seite in einem MZ (DOS, 16 Bit) .EXE-Header

Als Extremfall der folgenden Programmfunktionen, auch wenn 1 Seite von 1 Byte Einstellung:

; 
; the smallest possible "Hello, World!" .EXE (DOS MZ) file 
; assemble with: 
; nasm -f bin -w+all -O0 smallest_hello_exe.asm -o ASM.EXE 
; 

bits 16 
cpu 8086 

; 
; by setting cs:ip=-10h:100h instead of 0h:0h inside the .EXE header 
; (identical assignments), we achieve the following two advantages: 
; 1) ds==cs, so no "push cs pop ds" is needed in order for ds:dx 
; to point to the message string 
; 2) we can exit by int 20h instead of int 21h, thus omitting the 
; ah=4ch assignment 
; (int 20h requires that cs points to the PSP segment) 
; 

; 
; we do not the address calculations to take the .EXE header into account 
; so we must subtract its length (20h) by an "org -20h" 
; but, since ip will be 100h, we must also issue an "org 100h" 
; and, since 0x100-0x20=0xE0... 

org 0xE0  ; 100h for ip value - 20h for header 



section .text align=1 
; 
; the MZ .EXE header structure 
; 28 bytes long 
; 1 pararaph equals 16 bytes 
; 1 page equals 512 bytes 
; suggested reading: int 21h,ah=4bh procedure 
; 
host_exe_header: 
.signature: dw 'MZ'  ; the 'MZ' characters 
.last_page_size: dw 1 ; number of used bytes in the final file page, 0 for all 
.page_count: dw 1  ; number of file pages including any last partial page 
.reloc: dw 0   ; number of relocation entries after the header 
.paragraphs: dw 2  ; size of header + relocation table, in paragraphs 
.minalloc: dw 0   ; minimum required additional memory, in paragraphs 
.maxalloc: dw 0xFFFF ; maximum memory to be allocated, in paragraphs 
.in_ss: dw 0   ; initial relative value of the stack segment 
.in_sp: dw 0xF000  ; initial sp value 
.checksum: dw 0   ; checksum: 1's complement of sum of all words 
.in_ip: dw 100h   ; initial ip value 
.in_cs: dw -10h   ; initial relative value of the text segment 
.offset: dw 0   ; offset of the relocation table from start of header 
.overlay: dw 0   ; overlay value (0h = main program) 

; pad header (its size in bytes must be a multiple of 16) 
times (32-$+$$) db 0 

mov dx,message 
mov ah,09h    ; write string ds:dx to stdout 
int 21h 
int 20h 

section .data align=1 
message: db 'Hello, World!$' 

section .bss align=1 

Experimentieren mit verschiedenen Programmgrößen, ich bin zu dem Schluss gekommen, dass Dos alle 512 Bytes jeder Seite lädt in Erinnerung. Wenn ja, was ist der Zweck der Anzahl der Bytes auf der letzten Seite?

Kann es mit .bss, Stapeldaten und/oder dynamischen Speicherzuordnungen interferieren?

Antwort

3

Die Gesamtzahl der Seiten wird definitiv nicht ignoriert, sie wird sogar von Programmen verwendet, die nicht wollen, dass ihre gesamte Datei anfänglich geladen wird. Sie werden die notwendigen Fragmente später selbst lesen. Das bytes in the last page Feld kann oder kann nicht ignoriert werden, abhängig von der Betriebssystemversion. Es könnte auch auf einen Absatz oder eine Plattensektorgrenze aufgerundet werden. Sie sollten sich nicht auf ein bestimmtes Verhalten verlassen und es richtig ausfüllen.

Ihr Testcode funktioniert, weil er klein ist und Ihr spezielles Betriebssystem sich dafür entschieden hat, genug davon in den Speicher zu laden. Wenn Sie Ihr Programm größer als eine einzelne Seite machen, aber immer noch 1 im Feld page count angeben, wird Ihr Code wahrscheinlich nicht vollständig geladen und funktioniert nicht. Ich habe versucht:

times (32-$+$$) db 0 
times (512) nop 
mov dx,message 
mov ah,09h    ; write string ds:dx to stdout 
int 21h 
int 20h 

Dies schlägt fehl, wenn page count 1 ist, aber funktioniert, wenn page count 2 (dosbox zum Testen verwendet).

0

Das Seitenzahlfeld wird von DOS verwendet, nicht von Windows NT.

Die einzigen beiden Bereichen IMAGE_DOS_HEADER von NT verwendet werden, sind e_magic (was sein IMAGE_DOS_SIGNATURE muss) und e_lfanew, die eine weniger als 4 MB von Anfang des IMAGE_DOS_HEADER zu einer IMAGE_NT_HEADERS Struktur versetzt ist, die alle Informationen für den NT-Loader enthält .