程序的动态加载和执行

mbr.asm

;===============================================================================
;FileName:          mbr.asm
;Complie Method:    nasm mbr.asm -o mbr.bin
;Descriptor:        MBR
;Author:            by Taozai
;Date:                 2015/01/16
;===============================================================================
    
        core_base_address equ 0x00040000
        core_start_sector equ 0x00000001
    
        ;set stack.
        mov ax,cs
        mov ss,ax
        mov sp,0x7c00
    
        ;calc GDT segment address.
        mov eax,[cs:pgdt+0x7c00+0x02]
        xor edx,edx
        mov ebx,16
        div ebx
        
        mov ds,eax        ;GDT segment address.
        mov ebx,edx        ;GDT offset address.
        
        ;#0 default to set 0.
        mov dword [ebx+0x00],0x00000000
        mov dword [ebx+0x04],0x00000000
        
        ;#1 data segment.
        mov dword [ebx+0x08],0x0000ffff ;base address is 0x00000000, segment bound is 0xfffff
        mov dword [ebx+0x0c],0x00cf9200    ;Granularity is 4KB.
        ;bits[0000 0000 _1_1_0_0 _1111 _1_00_1 _0010 _0000 0000]
        
        ;#2 init code.
        mov dword [ebx+0x10],0x7c0001ff ;base address is 0x00007c00, segment bound is 0x001ff
        mov dword [ebx+0x14],0x00409800 ;Granularity is 1 bit.
        ;bits[0000 0000 _0_1_0_0 _0000 _1_00_1 _1000 _0000 0000]
        
        ;#3 stack segment
        mov dword [ebx+0x18],0x7c00fffe ;base address is 0x00007c00, segment bound is 0xffffe
        mov dword [ebx+0x1c],0x00cf9600 ;Granularity is 4KB.
        ;bits[0000 0000 _1_1_0_0 _1111 _1_00_1 _0110 _0000 0000]
        
        ;#4 According to the buffer.
        mov dword [ebx+0x20],0x80007fff ;base address is 0x000B8000, segment bound is 0x07fff
        mov dword [ebx+0x24],0x0040920b ;Granularity is 1 bit.
        ;bits[0000 0000 _0_1_0_0 _0000 _1_00_1 _0010 _0000 1011]
        
        ;set gdt bound.
        mov word [cs:pgdt+0x7c00],39
        
        ;load gdt.
        lgdt [cs:pgdt+0x7c00]
        
        ;Preparation for entry into the protected mode.
        in al,0x92
        or al,0000_0010B
        out 0x92,al
        
        ;disable interrupt.
        cli
        
        ;set PE
        mov eax,cr0
        or eax,1
        mov cr0,eax
        
        ;Enter the protected mode.
        jmp dword 0x0010:flush
        ;bits[0000 0000 0001  0_0_00]
        
        [bits 32]
    flush:
        mov eax,0x0008 ;bits[0000 0000 0000  1_0_00]
        mov ds,eax
        
        mov eax,0x0018 ;bits[0000 0000 0001  1_0_00]
        mov ss,eax
        xor esp,esp
        
        ;load core program.
        mov edi,core_base_address
        
        mov eax,core_start_sector
        mov ebx,edi
        call read_hard_disk_0
        
        ;calc core program size.
        mov eax,[edi]
        xor edx,edx
        mov ecx,512
        div ecx

        or edx,edx
        jnz @1
        dec eax
    @1:
        or eax,eax
        jz setup

        mov ecx,eax
        mov eax,core_start_sector
        inc eax
    @2:
        call read_hard_disk_0
        inc eax
        loop @2
    
    setup:    
        mov esi,[0x7c00+pgdt+0x02]
        
        ;#5 sys routine seg.
        mov eax,[edi+0x04]
        mov ebx,[edi+0x08]
        sub ebx,eax
        dec ebx            ;seg bound.
        add eax,edi        ;base address.
        mov ecx,0x00409800
        ;bits[0000 0000 _0_1_0_0 _0000 _1_00_1 _1000 _000 0000]
        call make_gdt_descriptor
        mov [esi+0x28],eax
        mov [esi+0x2c],edx
        
        ;#6 core data seg.
        mov eax,[edi+0x08]
        mov ebx,[edi+0x0c]
        sub ebx,eax
        dec ebx
        add eax,edi
        mov ecx,0x00409200
        ;bits[0000 0000 _0_1_0_0 _0000 _1_00_1 _0010 _0000 0000]
        call make_gdt_descriptor
        mov [esi+0x30],eax
        mov [esi+0x34],edx

        ;#7 core code seg.
        mov eax,[edi+0x0c]
        mov ebx,[edi+0x00]
        sub ebx,eax
        dec ebx
        add eax,edi
        mov ecx,0x00409800
        ;bits[0000 0000 _0_1_0_0 _0000 _1_00_1 _1000 _000 0000]
        call make_gdt_descriptor
        mov [esi+0x38],eax
        mov [esi+0x3c],edx
        
        mov word [0x7c00+pgdt],63
        
        lgdt [0x7c00+pgdt]
        
        jmp far [edi+0x10]
        
;-------------------------------------------------------------------
; read 1 sector
; params:
;    EAX= src sector id.
;   DS:EBX=dst address.
;
;return:
;    EBX=EBX+512
;    
read_hard_disk_0:
        
        push eax
        push ecx
        push edx
        
        push eax
        
        mov dx,0x1f2
        mov al,1
        out dx,al        ;read sector count.
        
        inc dx            ;0x1f3
        pop eax
        out dx,al        ;LBA(7~0)
        
        inc dx            ;0x1f4
        mov cl,8
        shr eax,cl
        out dx,al        ;LBA(15~8)
        
        inc dx            ;0x1f5
        shr eax,cl
        out dx,al        ;LBA(23~16)
        
        inc dx            ;0x1f6
        shr eax,cl
        or eax,0xe0        ;1 hard disk. LBA(27~24)
        out dx,al
        
        inc dx            ;0x1f7
        mov al,0x20        ;read command.
        out dx,al
    
    .waits:
        in al,dx
        and al,0x88
        cmp al,0x08
        jnz .waits
        
        mov ecx,256
        mov dx,0x1f0
    .readw:
        in ax,dx
        mov [ebx],ax
        add ebx,2
        loop .readw
    
        pop edx
        pop ecx
        pop eax
        
        ret
        
;-------------------------------------------------------------------
; buil gdt item.
; params:
;    EAX= base address.
;   EBX= segment bound.
;    ECX= properties.
;
;return:
;    EDX:EAX=gdt item.
;
make_gdt_descriptor:
        mov edx,eax
        shl eax,16
        or ax,bx
        
        and edx,0xffff0000
        rol edx,8
        bswap edx
        
        xor bx,bx
        or edx,ebx
        
        or edx,ecx
        
        ret
            
;-------------------------------------------------------------------
        pgdt                dw 0            ;bound.
                            dd 0x0007e00    ;GDT address.
;-------------------------------------------------------------------
        times 510-($-$$)     db 0
                            db 0x55,0xaa

core.asm

;===============================================================================
;FileName:          core.asm
;Complie Method:    nasm core.asm -o core.bin
;Descriptor:        CORE
;Author:            by Taozai
;Date:                 2015/02/03
;===============================================================================
        ;
        ;defines
        ;
        core_code_seg_sel        equ 0x38    ;core code segment selector.
                                ;bits[0000 0000 0011 1_0_00] #7
                                
        core_data_seg_sel        equ 0x30    ;core data segment selector.
                                ;bits[0000 0000 0011 0_0_00] #6
        
        sys_routine_seg_sel        equ 0x28    ;system routine segment selector.
                                ;bits[0000 0000 0010 1_0_00] #5
        
        video_ram_seg_sel        equ 0x20    ;video ram segment selector.
                                ;bits[0000 0000 0010 0_0_00] #4
                                
        core_stack_seg_sel        equ    0x18    ;core stack segment selector.                
                                ;bits[0000 0000 0001 1_0_00] #3
                                
        mem_0_4_gb_seg_sel        equ 0x08    ;(0~4GB) segment selector.
                                ;bits[0000 0000 0000 1_0_00] #1
                                
;-------------------------------------------------------------------------------
        ;
        ;core header.
        ;
        core_length            dd core_end                        ;#00    the total length of core program.
        sys_routine_seg        dd section.sys_routine.start    ;#04    system utility routines section position.
        core_data_seg        dd section.core_data.start        ;#08    the position of the core data.
        core_code_seg        dd section.core_code.start        ;#0c    the position of the core code.
        code_entry            dd start                        ;#10    the core code entry point.
                            dw core_code_seg_sel
        
        [bits 32]
;===============================================================================
SECTION sys_routine vstart=0    
;-------------------------------------------------------------------------------

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; public:
;     print string.
;
; parameters:
;   DS:EBX = string address.
;
; return:
;    
put_string:
        
        push ecx
        
    .getc:
        mov cl,[ebx]
        or cl,cl
        jz .exit
        call put_char
        inc ebx
        jmp .getc

    .exit:
        pop ecx
        
        retf

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; private:
;     print char.
;
; parameters:
;   CL = ANSCII.
;
; return:
;    
put_char:
                            ;pusha:  push ax,cx,dx,bx,sp,bp,si,di                16bits.
        pushad                ;pushad: push eax,ecx,edx,ebx,esp,ebp,esi,edi        32bits.

        mov dx,0x3d4
        mov al,0x0e
        out dx,al
        inc dx
        in al,dx
        mov ah,al
        
        dec dx
        mov al,0x0f
        out dx,al
        inc dx
        in al,dx
        mov bx,ax             ;BX=cursor position.
        
        cmp cl,0x0d            ;enter?
        jnz .put_0a
        mov ax,bx
        mov bl,80
        div bl
        mul bl                ;ax=al*bl
        mov bx,ax
        jmp .set_cursor
        
    .put_0a:
        cmp cl,0x0a            ;newline.
        jnz .put_other
        add bx,80
        jmp .roll_screen
        
    .put_other:
        push es
        mov eax,video_ram_seg_sel
        mov es,eax
        shl bx,1            ;BX=BX*2
        mov [es:bx],cl
        pop es
        
        shr bx,1
        inc bx
    
    .roll_screen:
        cmp bx,2000
        jl .set_cursor        ;<
        
        push ds
        push es
        mov eax,video_ram_seg_sel
        mov ds,eax
        mov es,eax
        cld                    ;CLear Direction flag.  esi++, edi++
        mov esi,0xa0
        mov edi,0x00
        mov ecx,1920
        rep movsd
        mov bx,3840
        mov ecx,80

    .cls:
        mov word[es:bx],0x0720
        add bx,2
        loop .cls
        
        pop es
        pop ds
        
        mov bx,1920
    
    .set_cursor:
        mov dx,0x3d4
        mov al,0x0e
        out dx,al            ;0x3d4
        
        inc dx
        mov al,bh
        out dx,al            ;0x3d5
        
        dec dx
        mov al,0x0f
        out dx,al            ;0x3d4
        
        inc dx
        mov al,bl
        out dx,al            ;0x3d5
        
        popad
        
        ret

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; public:
;     a logical sector read from the hard disk.
;
; parameters:
;   EAX = logical sector number.
;    DS:EBX = target buffer address.
;
; return:
;    EBX = EBX+512
;
read_hard_disk_0:
    
        push eax
        push ecx
        push edx
        
        push eax
        
        mov dx,0x1f2
        mov al,1            ;read sector count.
        out dx,al
        
        inc dx                ;0x1f3
        pop eax
        out dx,al            ;LBA(7~0)
        
        inc dx                ;0x1f4
        mov cl,8
        shr eax,cl
        out dx,al            ;LBA(15~8)
        
        inc dx                ;0x1f5
        shr eax,cl
        out dx,al            ;LBA(23~16)

        inc dx                ;0x1f6
        shr eax,cl
        or al,0xe0            ;0 hard disk, LBA(27~24)
        out dx,al
        
        inc dx                ;0x1f7
        mov al,0x20
        out dx,al            ;read command.
        
        
    .waits:
        in al,dx
        and al,0x88
        cmp al,0x08
        jnz .waits
        
        mov ecx,256
        mov dx,0x1f0
    .readw:
        in ax,dx
        mov [ebx],ax
        add ebx,2
        loop .readw
        
        pop edx
        pop ecx
        pop eax
        
        retf
        
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; public:
;     In the current cursor displayed in hexadecimal.
;
; parameters:
;   EDX = To transform and digital display.
;
; return:
;
put_hex_dword:
        
        pushad
        push ds
        
        mov ax,core_data_seg_sel
        mov ds,ax
        
        mov ebx,bin_hex            ;First address TABLE for a written form.
        mov ecx,8                ;8 bytes.
    .xlt:
        rol edx,4
        mov eax,edx
        and eax,0x0000000f
        xlat
        
        push ecx
        mov cl,al                ;ANSCII.
        call put_char
        pop ecx
        
        loop .xlt
        
        pop ds
        popad
        
        retf
        
        

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; public:
;     Allocate memory.
;
; parameters:
;   ECX = Distribution of the number of bytes of memory.
;
; return:
;    ECX = The start of the allocated memory linear addresses.
;
allocate_memory:
    
        push ds
        push eax
        push ebx
        
        mov eax,core_data_seg_sel
        mov ds,eax
        
        mov eax,[ram_alloc]
        add eax,ecx                ;The next time the starting address of the allocated memory.
        
        mov ecx,[ram_alloc]        ;Return to the starting address of the allocated memory.
        
        mov ebx,eax
        and ebx,0xfffffffc        ;4 byte alignment.
        add ebx,4
        test eax,0x00000003
        cmovnz eax,ebx
        mov [ram_alloc],eax
                
        pop ebx
        pop eax
        pop ds
        
        retf
        
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;public:
;     Install a new descriptor in the GDT.
;
; params:
;    EDX:EAX = The descriptor.
;
;return:
;    CX = The choice of the descriptor.
;
set_up_gdt_descriptor:
    
        push eax
        push ebx
        push edx
        
        push ds
        push es
        
        mov ebx,core_data_seg_sel
        mov ds,ebx
        
        sgdt [pgdt]                    ;Save the global descriptor.
        
        mov ebx,mem_0_4_gb_seg_sel
        mov es,ebx
        
        movzx ebx,word [pgdt]        ;GDT boundaries.
        inc bx                        ;GDT total number of bytes, is also a descriptor under deviation.
        add ebx,[pgdt+2]            ;Under a descriptor linear address.
            
        mov [es:ebx],eax            ;Under a descriptor linear address.
        mov [es:ebx+4],edx
        
        add word [pgdt],8            ;Increase the size of a descriptor.
        
        lgdt [pgdt]                    ;The GDT changes to take effect.
        
        mov ax,[pgdt]                ;Get the GDT threshold value.
        xor dx,dx
        mov bx,8
        div bx                        ;Divided by the number 8, remove the remainder.
        mov cx,ax
        shl cx,3                    ;Index number will be moved to the right place.
        
        pop es
        pop ds
        
        pop edx
        pop ebx
        pop eax
        
        retf
        
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;public:
;     To construct storage and segment descriptor systems.
;
; params:
;    EAX = base address.
;   EBX = segment bound.
;    ECX = properties.
;
;return:
;    EDX:EAX = gdt item.
;
make_seg_descriptor:
        mov edx,eax
        shl eax,16
        or ax,bx
        
        and edx,0xffff0000
        rol edx,8
        bswap edx                    ;(80486+)
        
        xor bx,bx
        or edx,ebx
        
        or edx,ecx
        
        retf        
        
;===============================================================================
SECTION core_data vstart=0
;-------------------------------------------------------------------------------
        pgdt            dw 0
                        dd 0
        
        ram_alloc       dd  0x00100000
        
        salt:
        salt_1            db  '@PrintString'
                        times 256-($-salt_1) db 0
                        dd put_string
                        dw sys_routine_seg_sel
                        
        salt_2            db  '@ReadDiskData'
                        times 256-($-salt_2) db 0
                        dd read_hard_disk_0
                        dw sys_routine_seg_sel
                        
        salt_3            db  '@PrintDwordAsHexString'
                        times 256-($-salt_3) db 0
                        dd put_hex_dword
                        dw sys_routine_seg_sel

        salt_4            db  '@TerminateProgram'
                        times 256-($-salt_4) db 0
                        dd return_point
                        dw core_code_seg_sel

        ;defines.
        salt_item_len    equ    $-salt_4
        salt_items        equ ($-salt)/salt_item_len    
                        
        
        message_1        db  '  If you seen this message,that means we '
                        db  'are now in protect mode,and the system '
                        db  'core is loaded,and the video display '
                        db  'routine works perfectly.',0x0d,0x0a,0
        
        message_5       db  '  Loading user program...',0
        
        do_status       db  'Done.',0x0d,0x0a,0
         
        message_6       db  0x0d,0x0a,0x0d,0x0a,0x0d,0x0a
                        db  '  User program terminated,control returned.',0
                        
        bin_hex         db '0123456789ABCDEF'                
        
        core_buf        times 2048 db 0
        
        esp_pointer        dd 0
        
        cpu_brnd0        db 0x0d,0x0a,'  ',0
        cpu_brand        times 52 db 0
        cpu_brnd1        db 0x0d,0x0a,0x0d,0x0a,0

;===============================================================================
SECTION core_code vstart=0
;-------------------------------------------------------------------------------

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; private:
;     loading and positioning the user program.
;
; parameters:
;    ESI = starting logical sector number.
;
; return:
;    AX = point to the user program head selector.
;
load_relocate_program:
        
        push ebx
        push ecx
        push edx
        push esi
        push edi
        
        push ds
        push es

        mov eax,core_data_seg_sel
        mov ds,eax
        
        mov eax,esi
        mov ebx,core_buf
        call sys_routine_seg_sel:read_hard_disk_0
        
        mov eax,[core_buf]
        mov ebx,eax
        and ebx,0xfffffe00                ;512 byte alignment.
        add ebx,512
        test eax,0x000001ff
        cmovnz eax,ebx
        
        mov ecx,eax
        call sys_routine_seg_sel:allocate_memory
        mov ebx,ecx
        push ebx
        xor edx,edx
        mov ecx,512
        div ecx
        mov ecx,eax                        ;sector count.
        
        mov eax,mem_0_4_gb_seg_sel
        mov ds,eax
        
        mov eax,esi                        ;Start sector number.
    .b1:
        call sys_routine_seg_sel:read_hard_disk_0
        inc eax
        loop .b1                        ;Loop reads the user program.
        
        ;#? head seg.
        pop edi                            ;push ebx, The user program first address.
        mov eax,edi                        ;The head start program linear address.
        mov ebx,[edi+0x04]                ;length.
        dec ebx                            ;segment boundaries.
        mov ecx,0x00409200                ;bits[00000 0000 _0_1_0_0 _0000 _1_00_1 _0010 _0000 0000]
        call sys_routine_seg_sel:make_seg_descriptor
        call sys_routine_seg_sel:set_up_gdt_descriptor
        mov [edi+0x04],cx
        
        ;#?+1 code seg.
        mov eax,edi
        add eax,[edi+0x14]                ;Initial linear address code
        mov ebx,[edi+0x18]                ;length.
        dec ebx                            ;segment boundaries.
        mov ecx,0x00409800                ;bits[0000 0000 _0_1_0_0 _0000 _100_1 _1000 _0000 0000]
        call sys_routine_seg_sel:make_seg_descriptor
        call sys_routine_seg_sel:set_up_gdt_descriptor
        mov [edi+0x14],cx
        
        ;#?+2 data seg.
        mov eax,edi
        add eax,[edi+0x1c]                ;Initial linear address code
        mov ebx,[edi+0x20]                ;length.
        dec ebx                            ;segment boundaries.
        mov ecx,0x00409200                ;bits[0000 0000 _0_1_0_0 _0000 _100_1 _0010 _0000 0000]
        call sys_routine_seg_sel:make_seg_descriptor
        call sys_routine_seg_sel:set_up_gdt_descriptor
        mov [edi+0x1c],cx
        
        ;#?+3 stack seg.
        mov ecx,[edi+0x0c]                ;Ratio of 4 KB.
        mov ebx,0x000fffff
        sub ebx,ecx                        ;Get segment boundaries.
        mov eax,4096
        mul dword [edi+0x0c]
        mov ecx,eax
        call sys_routine_seg_sel:allocate_memory
        add eax,ecx                        ;Get a stack of high-end physical address.
        mov ecx,0x00c09600                ;bits[0000 0000 _1_1_0_0 _0000 _100_1 _0110 _0000 0000]
        call sys_routine_seg_sel:make_seg_descriptor
        call sys_routine_seg_sel:set_up_gdt_descriptor
        mov [edi+0x08],cx
        
        mov eax,[edi+0x04]
        mov es,eax
        mov eax,core_data_seg_sel
        mov ds,eax
        
        cld                                ;cld; DF=0 (esi++, edi++)
        
        mov ecx,[es:0x24]                ;The user program SALT number entries.
        mov edi,0x28                    ;The SALT in the user program is 0 x28 place inside the head.
    .b2:
        push ecx
        push edi
        
        mov ecx,salt_items
        mov esi,salt
    .b3
        push edi
        push esi
        push ecx
            
        mov ecx,64                        ;
        repe cmpsd
        jnz .b4
        mov eax,[esi]
        mov [es:edi-256],eax
        mov ax,[esi+4]
        mov [es:edi-252],ax
    .b4:    
            
        pop ecx
        pop esi
        add esi,salt_item_len
        pop edi
        loop .b3                        ;end .b3
        
        pop edi
        add edi,256
        pop ecx
        loop .b2                        ;end .b2
        
        mov ax,[es:0x04]                ;Returns the user program head index number.

        pop es
        pop ds
        
        pop edi
        pop esi
        pop edx
        pop ecx
        pop ebx
        ret


;-------------------------------------------------------------------------------
;
;the core code entry point.
;
start:
        mov ecx,core_data_seg_sel
        mov ds,ecx
        
        mov ebx,message_1
        call sys_routine_seg_sel:put_string
        
        ;show .
        mov eax,0x80000002
        cpuid
        mov [cpu_brand + 0x00],eax
        mov [cpu_brand + 0x04],ebx
        mov [cpu_brand + 0x08],ecx
        mov [cpu_brand + 0x0c],edx
        
        mov eax,0x80000003
        cpuid
        mov [cpu_brand + 0x10],eax
        mov [cpu_brand + 0x14],ebx
        mov [cpu_brand + 0x18],ecx
        mov [cpu_brand + 0x1c],edx
        
        mov eax,0x80000004
        cpuid
        mov [cpu_brand + 0x20],eax
        mov [cpu_brand + 0x24],ebx
        mov [cpu_brand + 0x28],ecx
        mov [cpu_brand + 0x2c],edx
        
        mov ebx,cpu_brnd0
        call sys_routine_seg_sel:put_string
        mov ebx,cpu_brand
        call sys_routine_seg_sel:put_string
        mov ebx,cpu_brnd1
        call sys_routine_seg_sel:put_string
        
        ;loading and positioning the user program.
        mov ebx,message_5
        call sys_routine_seg_sel:put_string
        mov esi,50
        call load_relocate_program
        
        mov ebx,do_status
        call sys_routine_seg_sel:put_string
        
        mov [esp_pointer], esp            ;Temporary storage stack pointer.
        mov ds,ax                        ;User program head index number.
        jmp far [0x10]                    ;Control to the user program (entry point).
        
    return_point:
        mov eax,core_data_seg_sel        ;Switch back to the kernel data segment.
        mov ds,eax
        
        mov eax,core_stack_seg_sel        ;Switch back to the kernel stack.
        mov ss,eax
        mov esp,[esp_pointer]
        
        mov ebx,message_6
        call sys_routine_seg_sel:put_string
        
        hlt

;===============================================================================
SECTION core_trail
;-------------------------------------------------------------------------------
core_end:

user.asm

;===============================================================================
;FileName:          user.asm
;Complie Method:    nasm user.asm -o user.bin
;Descriptor:        USER
;Author:            by Taozai
;Date:                 2015/02/04
;===============================================================================

;===============================================================================
SECTION header vstart=0    
;-------------------------------------------------------------------------------
        ;
        ; head info.
        ;
        program_length        dd program_end                ;#0x00    program length.
        
        header_len            dd header_end                ;#0x04    program head length.
        
        stack_seg            dd 0                        ;#0x08    stack selector.
        stack_len            dd 1                        ;#0x0c  stack length. 4KB.
        
        prgentry            dd start                    ;#0x10 program entry pointer.
        code_seg            dd section.code.start        ;#0x14 code segment position.
        code_len            dd code_end                    ;#0x18 code segment length.
        
        data_seg            dd section.data.start        ;#0x1c data segment position.
        data_len            dd data_end                    ;#0x20 data segment length.
        
        ;
        ;
        ;
        salt_items            dd (header_end-salt)/256    ;#0x24 function counts.
        
        salt:                                            ;#0x28
        PrintString            db '@PrintString'
                            times 256-($-PrintString) db 0
        
        TerminateProgram    db '@TerminateProgram'
                            times 256-($-TerminateProgram) db 0
                            
        ReadDiskData        db '@ReadDiskData'
                            times 256-($-ReadDiskData) db 0                    
        
header_end:

;===============================================================================
SECTION data vstart=0    
;-------------------------------------------------------------------------------
         buffer times 1024 db  0

         message_1         db  0x0d,0x0a,0x0d,0x0a
                           db  '**********User program is runing**********'
                           db  0x0d,0x0a,0
         message_2         db  '  Disk data:',0x0d,0x0a,0

data_end:

;*******************************************************************************
        [bits 32]
;*******************************************************************************
;===============================================================================
SECTION code vstart=0    
;-------------------------------------------------------------------------------
start:
        mov eax,ds
        mov fs,eax
        
        mov eax,[stack_seg]
        mov ss,eax
        mov esp,0

        mov eax,[data_seg]
        mov ds,eax
        
        mov ebx,message_1
        call far [fs:PrintString]

        mov eax,100
        mov ebx,buffer
        call far [fs:ReadDiskData]
        
        mov ebx,message_2
        call far [fs:PrintString]
        
        mov ebx,buffer
        call far [fs:PrintString]
        
        jmp far [fs:TerminateProgram]
    
code_end:

;===============================================================================
SECTION trail
;-------------------------------------------------------------------------------
program_end:
原文地址:https://www.cnblogs.com/qintangtao/p/4279146.html