diff -uNr a/dos32a/MANIFEST b/dos32a/MANIFEST --- a/dos32a/MANIFEST 02d632e991f6d9f98083a9464c5078faa330d6ae45c483c27cd04ae9ac752237a9409dfa59ce131f61c824521d877fd551a6eb2c7924fb0ef22ebf6b31648ebe +++ b/dos32a/MANIFEST 11f7691abf2c048f7d7b4678687c3588ff369c73b90621c0a16840c4d7d3abf518d3ce2bc06dd51c145f3b551bf02113f384076d8c1372e8dc5ac4a0397d41f1 @@ -1 +1,2 @@ 828710 dos32a-src "DOS/32 Advanced DOS Extender, version 9.1.2." + 828717 dos32a-pecoff "PE/COFF object file format support." diff -uNr a/dos32a/src/dos32a/loadpe.asm b/dos32a/src/dos32a/loadpe.asm --- a/dos32a/src/dos32a/loadpe.asm bf2d8275ddac10274d45bd45de2ffb7afb22062c51c20f70d3952ad0f1338b7b4e1369938fd82914559d224d250f17f985fab9c8dacade68b95bcd5414b3cd50 +++ b/dos32a/src/dos32a/loadpe.asm fd5806e4594bd151b3f7c1e51000e4ea5325c54eea9683cabc76138dd495ee1f728765b4856667ddc83c5eb380777507b88a92d22aa9f2e7b81e145330ab511f @@ -1,5 +1,5 @@ ; -; Copyright (C) 1996-2006 by Narech K. All rights reserved. +; Copyright (C) 2024 by David Gregory. All rights reserved. ; ; Redistribution and use in source and binary forms, with or without ; modification, are permitted provided that the following conditions are @@ -37,19 +37,276 @@ ; ; +;***************************************************************************** +; DOS/32A 32-bit application loader (PE style file format) +; +;***************************************************************************** + PushState .386p ;============================================================================= load_pe_app: - mov _app_type,3 -; -; Insert PE loader implementation here -; - mov ax,3004h ; "exec format not supported" - jmp file_error + mov _app_type,3 + call load_pe_header + call verbose_showloadhdr + mov ecx,1 +@@1: call load_pe_object + call create_selector + call verbose_showloadobj + push dword 0 ; padding + push edi ; save address of the loaded object + push ebp ; save size of the loaded object + push esi ; save the virtual address + inc cx + cmp cx,word ptr _app_num_objects + jbe @@1 + + call create_stack_object + call create_selector + call verbose_showloadobj + + mov ebp,esp ; point to objects + mov ebx,_app_num_objects + dec bx + shl bx,4 ; times 16 (the size of our record) + + call fix_reloc_offset + +@@4: call relocate_pe_object + sub bx,10h ; get next object + jnc @@4 + + call close_exec + mov esp,_sel_esp + call verbose_showstartup + jmp enter_32bit_code + + + +;----------------------------------------------------------------------------- +load_pe_header: + mov ecx,0F8h ; size of a full 32-bit PE header + mov edx,04h + mov _err_code,3002h ; "error in app file" + + call load_fs_block + mov edx,_exec_start + + mov ax,fs:[0016h] ; load characteristics + and ax,0103h ; check for: + cmp ax,0102h ; EXECUTABLE_IMAGE and 32BIT_MACHINE + mov ax,3005h ; and not RELOCS_STRIPPED + jne file_error + + mov ax,fs:[0006h] ; get number of sections + mov cx,ax + cmp ax,APP_MAXOBJECTS + mov ax,4001h ; "too many objects" + ja file_error + mov _app_num_objects,ecx + + mov eax,0F8h ; size of the optional header + add eax,edx + mov _app_off_objects,eax + + mov eax,fs:[0034h] ; image base + mov _app_tmp_addr1,eax + + mov eax,fs:[0060h] ; stack size + mov _app_tmp_addr2,eax + + mov eax,fs:[00A0h] ; base relocation table virtual address + mov _app_off_fixrectab,eax + + mov eax,fs:[00A4h] ; base relocation table size + mov _app_siz_fixrecstab,eax + + mov _app_eip_object,0 ; 0 = have not found it yet + + mov eax,fs:[0028h] ; entry point address + mov _app_eip,eax + ret + + + +;----------------------------------------------------------------------------- +load_pe_object: + push ecx + + mov _err_code,3002h + mov edx,_app_off_objects + call seek_from_start + mov ecx,28h ; size of a section entry + xor edx,edx + call load_fs_block + add _app_off_objects,eax + + mov eax,fs:[0008h] ; virtual size + mov esi,fs:[000Ch] ; virtual address + mov edx,fs:[0014h] ; pointer to raw data + mov ecx,fs:[0024h] ; characteristics + call seek_from_start ; head to section data + + mov edx,2040h ; 32-bit and preloaded + test ecx,40000000h ; readable-p + jz @@nr + or edx,0001h ; set readable +@@nr: test ecx,80000000h ; writable-p + jz @@nw + or edx,0002h ; set writable +@@nw: test ecx,20000000h ; executable-p + jz @@ne + or edx,0004h ; set executable +@@ne: push edx ; save our characteristics + + ;; This is how we get the proper EIP. + test ecx,00000020h ; check if section contains code + jz @@skip + cmp _app_eip_object,0 ; not 0 = already found it + jnz @@skip + cmp _app_eip,esi ; EIP >= virtual address + jb @@skip + mov ecx,eax + add ecx,esi + cmp _app_eip,ecx ; EIP < virtual address + virtual size + jae @@skip + mov ecx,[esp+4] + mov _app_eip_object,ecx + sub _app_eip,esi + +@@skip: mov ebx,eax ; get physical size + shr ebx,12 ; number of pages + test eax,0FFFh ; check for a tail + jz @@1 + inc ebx ; add one more page + +@@1: call alloc_block ; allocate EAX memory block to EDI + mov ecx,eax ; ECX = bytes to read + mov ebp,eax ; EBP = preserve virtual size + mov edx,edi ; EDX = addres to read to + call fill_zero_pages ; fill allocated memory with zeroes + + mov _err_code,3002h + call load_gs_block ; load object data + + pop edx ; leave our characteristics on EDX + pop ecx + ret + + + +;----------------------------------------------------------------------------- +create_stack_object: + push ecx + mov eax,_app_tmp_addr2 + mov ebx,eax + shr ebx,12 + test eax,0FFFh + jz @@1 + inc ebx + +@@1: mov _app_esp_object,ecx + mov _app_esp,eax + + call alloc_block + mov ecx,eax + mov ebp,eax + mov edx,edi + call fill_zero_pages + + mov edx,2103h ; 32-bit, zeroed, rw + pop ecx + ret + + + + +;============================================================================= +relocate_pe_object: + mov _err_code,4005h ; "unrecognized fixup data" + mov edx,_app_off_fixrectab ; first base relocation block + mov ecx,_app_siz_fixrecstab ; size of all blocks +@@1: test ecx,ecx ; check if zero + jz @@done ; if zero, we're done + + ;; here we assume consistent object ordering, ascending and we also + ;; assume there are no blocks starting before our first object + mov eax,[ebp+ebx+0] ; virtual address of our loaded object + cmp eax,gs:[edx] ; skip blocks below us + ja @@next + add eax,[ebp+ebx+4] ; add size of our loaded object + cmp eax,gs:[edx] ; skip blocks above us + jbe @@next + + lea esi,[edx+8] ; ESI = address of first relocation + mov edi,edx ; EDI = address of current block + add edi,gs:[edx+4] ; EDI = address of next block + +@@2: cmp esi,edi ; finish the block if at the end + je @@next + + mov ax,gs:[esi] ; get relocation + and eax,0000F000h ; relocation type mask + jz @@skip ; skip if base relocation type = 0 + cmp eax,00003000h + jne file_errorm ; eggog if base relocation type /= 3 + mov ax,gs:[esi] ; get relocation (again) + and eax,00000FFFh ; clear relocation type + add eax,gs:[edx] ; add page address + sub eax,[ebp+ebx+0] ; sub virtual address of our object + add eax,[ebp+ebx+8] ; add actual address of our object + + push esi ecx edx ebx ; save the registers + + mov esi,gs:[eax] ; load the address to relocate + sub esi,_app_tmp_addr1 ; sub image base + + xor ebx,ebx + mov edx,_app_num_objects ; for our all remote objects + shl edx,4 ; times 16 (size of object structure) +@@3: cmp ebx,edx ; leave loop if we did all objects + je @@oo + + ;; here we assume consistent remote object ordering, descending + cmp esi,[ebp+ebx+0] ; address equal or lower our page + jae @@mm + add ebx,10h ; next object + jmp @@3 + +@@mm: mov ecx,_app_tmp_addr1 ; get image base + sub gs:[eax],ecx ; sub it from the address + mov ecx,[ebp+ebx+0] ; get virtual address of our object + sub gs:[eax],ecx ; sub it from the address + mov ecx,[ebp+ebx+8] ; get actual address of our object + add gs:[eax],ecx ; add it to the address + +@@oo: pop ebx edx ecx esi ; restore the registers + +@@skip: add esi,2 ; records are two octets long + jmp @@2 ; next reloc + +@@next: mov eax,gs:[edx+4] ; get size of our block + add edx,eax ; move block pointer to next block + sub ecx,eax ; shrink size of all blocks + jmp @@1 ; next block +@@done: ret + + +;----------------------------------------------------------------------------- +fix_reloc_offset: + push ebx ; save object pointer + mov eax,_app_off_fixrectab ; reloc section virtual address +@@1: cmp eax,[ebp+ebx+0] ; compare with object's virtual address + je @@done + sub bx,10h ; next object + jmp @@1 +@@done: mov eax,[ebp+ebx+8] ; get object's actual address + mov _app_off_fixrectab,eax + pop ebx ; restore object pointer + ret PopState