flat assembler
Message board for the users of flat assembler.
Index
> Windows > [solved]:playing with 16bit winincludes Goto page 1, 2, 3 Next |
Author |
|
Tomasz Grysztar 24 Jan 2020, 09:52
Amazing! I never thought that I would see an NE framework done in fasm 1 before fasmg. Although with fasmg you could probably make it more maintainable (and relocations are really hard to do well with fasm 1).
As someone that would like to test it on my Windows 3.11, I might suggest using 8.3 filenames for all the headers. |
|||
24 Jan 2020, 09:52 |
|
ProMiNick 30 Jan 2020, 22:03
I am stuck for a days...
before I add stub.relocations_offset my exe was never identified as NE. And even after I got "bad relocation chain". In my donor exe I searched everywhere for import ordinals or for relocation implementation - it is too trickery hidden. Moreover every call to import is "call 0:-1" fixes: esp macro rudiments replaced to sp: Code: ; Macroinstructions for defining and calling procedures macro x16 statement& { match =stdcall sttmnt,statement \{ stdcall16 sttmnt \} match =farcall sttmnt,statement \{ farcall16 sttmnt \} match =far =stdcall sttmnt,statement \{ farcall16 sttmnt \} match =invoke sttmnt,statement \{ invoke16 sttmnt \} match =far =invoke sttmnt,statement \{ farinvk16 sttmnt \} match =ccall sttmnt,statement \{ ccall16 sttmnt \} match =far =ccall sttmnt,statement \{ farccall16 sttmnt \} match =cinvoke sttmnt,statement \{ cinvoke16 sttmnt \} match =far =cinvoke sttmnt,statement \{ farcinvoke16 sttmnt \} } macro stdcall16 proc,[arg] ; directly call STDCALL procedure { common if ~ arg eq reverse pushw arg common end if call proc } macro farcall16 proc,[arg] ; directly call STDCALL procedure { common if ~ arg eq reverse pushw arg common end if push cs call proc } macro invoke16 proc,[arg] ; indirectly call STDCALL procedure { common if ~ arg eq reverse pushw arg common end if call [proc] } macro farinvk16 proc,[arg] ; indirectly call STDCALL procedure { common if ~ arg eq reverse pushw arg common end if push cs call [proc] } macro ccall16 proc,[arg] ; directly call CDECL procedure { common size@ccall = 0 if ~ arg eq reverse pushw arg size@ccall = size@ccall+2 common end if call proc if size@ccall add sp,size@ccall end if } macro farccall16 proc,[arg] ; directly call CDECL procedure { common size@ccall = 0 if ~ arg eq reverse pushw arg size@ccall = size@ccall+2 common end if push cs call proc if size@ccall add sp,size@ccall end if } macro cinvoke16 proc,[arg] ; indirectly call CDECL procedure { common size@ccall = 0 if ~ arg eq reverse pushw arg size@ccall = size@ccall+2 common end if call [proc] if size@ccall add sp,size@ccall end if } macro farcinvoke16 proc,[arg] ; indirectly call CDECL procedure { common size@ccall = 0 if ~ arg eq reverse pushw arg size@ccall = size@ccall+2 common end if push cs call [proc] if size@ccall add sp,size@ccall end if } macro proc16 [args] ; define procedure { common match name params, args> \{ define@proc16 name,<params \} } prologue@proc16 equ prologuedef16 macro prologuedef16 procname,flag,parmbytes,localbytes,reglist { local loc loc = (localbytes+1) and (not 1) parmbase@proc16 equ bp+4 localbase@proc16 equ bp-loc if parmbytes | localbytes push bp mov bp,sp if localbytes sub sp,loc end if end if irps reg, reglist \{ push reg \} } epilogue@proc16 equ epiloguedef16 macro epiloguedef16 procname,flag,parmbytes,localbytes,reglist { irps reg, reglist \{ reverse pop reg \} if parmbytes | localbytes leave end if if flag and 100000b if flag and 10000b retf else retf parmbytes end if else if flag and 10000b retn else retn parmbytes end if end if } close@proc16 equ macro define@proc16 name,statement { local params,flag,regs,parmbytes,localbytes,current if used name name: flag = 0 params equ statement: match =far args, params \{ flag = 100000b params equ args \} match =farcall args, params \{ flag = 100011b params equ args \} match =stdcall args, params \{ flag = flag or 11b params equ args \} match =c args, params \{ flag = flag or 10001b params equ args \} match =uses reglist=,args, params \{ regs equ reglist params equ args \} match =regs =uses reglist:, regs params \{ regs equ reglist params equ \} match =regs, regs \{ regs equ \} match args:, params \{ params equ args \} match :, params \{ params equ \} match prologue:reglist, prologue@proc16:<regs> \{ prologue name,flag,parmbytes,localbytes,reglist \} virtual at parmbase@proc16 match =,args, params \{ defargs@proc16 args \} match =args@proc16 args, args@proc16 params \{ defargs@proc16 args \} parmbytes = $-(parmbase@proc16) end virtual name # % = parmbytes/2 all@vars equ current = 0 macro locals \{ virtual at localbase@proc16+current macro label def \\{ match . type,def> \\\{ deflocal@proc .,label,<type \\\} \\} struc db [val] \\{ \common deflocal@proc .,db,val \\} struc du [val] \\{ \common deflocal@proc .,du,val \\} struc dw [val] \\{ \common deflocal@proc .,dw,val \\} struc dp [val] \\{ \common deflocal@proc .,dp,val \\} struc dd [val] \\{ \common deflocal@proc .,dd,val \\} struc dt [val] \\{ \common deflocal@proc .,dt,val \\} struc dq [val] \\{ \common deflocal@proc .,dq,val \\} struc rb cnt \\{ deflocal@proc .,rb cnt, \\} struc rw cnt \\{ deflocal@proc .,rw cnt, \\} struc rp cnt \\{ deflocal@proc .,rp cnt, \\} struc rd cnt \\{ deflocal@proc .,rd cnt, \\} struc rt cnt \\{ deflocal@proc .,rt cnt, \\} struc rq cnt \\{ deflocal@proc .,rq cnt, \\} \} macro endl \{ purge label restruc db,du,dw,dp,dd,dt,dq restruc rb,rw,rp,rd,rt,rq current = $-(localbase@proc16) end virtual \} macro ret operand \{ match any, operand \\{ retn operand \\} match , operand \\{ match epilogue:reglist, epilogue@proc16:<regs> \\\{ epilogue name,flag,parmbytes,localbytes,reglist \\\} \\} \} macro finish@proc16 \{ localbytes = current match close:reglist, close@proc16:<regs> \\{ close name,flag,parmbytes,localbytes,reglist \\} end if \} } macro defargs@proc16 [arg] { common if ~ arg eq forward local ..arg,current@arg match argname:type, arg \{ current@arg equ argname label ..arg type argname equ ..arg if qqword eq type dw ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,? else if dqword eq type dw ?,?,?,?,?,?,?,? else if tbyte eq type dw ?,?,?,?,?,? else if qword eq type | pword eq type dw ?,?,?,? else if dword eq type dw ?,? else dw ? end if \} match =current@arg,current@arg \{ current@arg equ arg arg equ ..arg ..arg dw ? \} common args@proc16 equ current@arg forward restore current@arg common end if } macro deflocal@proc name,def,[val] { name def val } macro deflocal@proc name,def,[val] { common match vars, all@vars \{ all@vars equ all@vars, \} all@vars equ all@vars name forward local ..var,..tmp ..var def val match =?, val \{ ..tmp equ \} match any =?, val \{ ..tmp equ \} match any (=?), val \{ ..tmp equ \} match =label, def \{ ..tmp equ \} match tmp : value, ..tmp : val \{ tmp: end virtual initlocal@proc ..var,def value virtual at tmp\} common match first rest, ..var, \{ name equ first \} } struc label type { label . type } macro initlocal@proc name,def { virtual at name def size@initlocal = $ - name end virtual position@initlocal = 0 while size@initlocal > position@initlocal virtual at name def if size@initlocal - position@initlocal < 2 current@initlocal = 1 load byte@initlocal byte from name+position@initlocal else if size@initlocal - position@initlocal < 4 current@initlocal = 2 load word@initlocal word from name+position@initlocal else current@initlocal = 4 load dword@initlocal dword from name+position@initlocal end if end virtual if current@initlocal = 1 mov byte [name+position@initlocal],byte@initlocal else if current@initlocal = 2 mov word [name+position@initlocal],word@initlocal else mov dword [name+position@initlocal],dword@initlocal end if position@initlocal = position@initlocal + current@initlocal end while } macro endp { purge ret,locals,endl finish@proc16 purge finish@proc16 restore regs@proc match all,args@proc16 \{ restore all \} restore args@proc16 match all,all@vars \{ restore all \} } macro local [var] { common locals forward done@local equ match varname[count]:vartype, var \{ match =BYTE, vartype \\{ varname rb count restore done@local \\} match =WORD, vartype \\{ varname rw count restore done@local \\} match =DWORD, vartype \\{ varname rd count restore done@local \\} match =PWORD, vartype \\{ varname rp count restore done@local \\} match =QWORD, vartype \\{ varname rq count restore done@local \\} match =TBYTE, vartype \\{ varname rt count restore done@local \\} match =DQWORD, vartype \\{ label varname dqword rq count*2 restore done@local \\} match =QQWORD, vartype \\{ label varname qqword rq count*4 restore done@local \\} match =XWORD, vartype \\{ label varname xword rq count*2 restore done@local \\} match =YWORD, vartype \\{ label varname yword rq count*4 restore done@local \\} match , done@local \\{ virtual varname vartype end virtual rb count*sizeof.\#vartype restore done@local \\} \} match :varname:vartype, done@local:var \{ match =BYTE, vartype \\{ varname db ? restore done@local \\} match =WORD, vartype \\{ varname dw ? restore done@local \\} match =DWORD, vartype \\{ varname dd ? restore done@local \\} match =PWORD, vartype \\{ varname dp ? restore done@local \\} match =QWORD, vartype \\{ varname dq ? restore done@local \\} match =TBYTE, vartype \\{ varname dt ? restore done@local \\} match =DQWORD, vartype \\{ label varname dqword dq ?,? restore done@local \\} match =QQWORD, vartype \\{ label varname qqword dq ?,?,?,? restore done@local \\} match =XWORD, vartype \\{ label varname xword dq ?,? restore done@local \\} match =YWORD, vartype \\{ label varname yword dq ?,?,?,? restore done@local \\} match , done@local \\{ varname vartype restore done@local \\} \} match ,done@local \{ var restore done@local \} common endl } I dont understand what Gangload is, but I locate where it is And some minor fixes in fields calculations And now I primary reffer to file conrent (not image conent as before) so some calls became "call 0:-1". Code: format binary as 'exe' include 'win16a.inc' include 'file formats\ne\equates\flags.inc' macro align boundary,value:? { db (boundary-1)-($+boundary-1) mod boundary dup value } FILE_ALIGNMENT_SHIFT = 4 RSRC_ALIGNMENT_SHIFT = 4 FILE_ALIGNMENT = 1 shl FILE_ALIGNMENT_SHIFT stub: .Signature dw 'MZ' .BytesInLastSector dw SIZE_OF_STUB mod 512 .NumberOfSectors dw (SIZE_OF_STUB-1)/512 + 1 .NumberOfRelocations dw 0 .NumberOfHeaderParagraphs dw SIZE_OF_STUB_HEADER / 16 db 0x18 - ($-stub) dup 0 .relocations_offset dw SIZE_OF_STUB_HEADER db 0x3C - ($-stub) dup 0 .NewHeaderOffset dd Header;-IMAGE_BASE align 16 SIZE_OF_STUB_HEADER = $ - stub ; The code of a DOS program would go here. org 0 push cs pop ds mov dx, noDOS mov ah,9 int $21 mov ax,$4C01 int $21 noDOS db 'This program requires Microsoft Windows',$2E,13,10,'$',0 org SIZE_OF_STUB_HEADER+$ SIZE_OF_STUB = $ - stub align 8 Header: assert Header=$80 .Signature dw "NE" .MajorLinkerVersion db 0 .MinorLinkerVersion db 0 .EntryTable dw EntryTable-Header .SizeOfEntryTable dw EntryTable.End-EntryTable .CheckSum dd 0 .ProgramFlags db NE_INST .Applicationflags db NE_WINAPI .AutoDataSegIndex dw 2 .InitHeapSize dw $800 .InitStackSize dw $2400 .EntryPoint dd 1:start .InitialStackPointer dd 2:0 .SegCount dw 2 .ModRefs dw 6 .SizeOfNonResNamesTable dw NonResNamesTable.End-NonResNamesTable .SegTableOffset dw SegmentTable-Header .ResTableOffset dw ResourceTable-Header .ResNamesTable dw ResidentNamesTable-Header .ModRefTable dw ModRefTable-Header .ImportNamesTable dw ImportNamesTable-Header .OffStartNonResNamesTable dd NonResNamesTable .MovEntryCount dw 2 .FileAlnSzShftCnt dw FILE_ALIGNMENT_SHIFT .nResTableEntries dw 6 .TargetOS db NE_WINDOWS .OS2EXEFlags db NE_GANGL .RetThunksOffset: .GangloadStart dw GangloadStart shr FILE_ALIGNMENT_SHIFT .SegRefThunksOffset: .GangloadSize dw (GangloadEnd-GangloadStart) shr FILE_ALIGNMENT_SHIFT .MinCodeSwap dw 0 .MinorOperatingSystemVersion db 10 .MajorOperatingSystemVersion db 3 SegmentTable: assert SegmentTable=$C0 .1.Offset dw Segment.1 shr 4 .1.Length dw Segment.1.End - Segment.1 .1.Flags dw NE_NSCODE or NE_NSMOVE or NE_NSPRELOAD or NE_NSRELOC or (NE_NSDPL and (3 shl 10)) .1.MinAlloc dw Segment.1.End - Segment.1 .2.Offset dw Segment.2 shr 4 .2.Length dw Segment.2.End - Segment.2 .2.Flags dw NE_NSDATA or NE_NSMOVE or NE_NSPRELOAD or NE_NSRELOC or (NE_NSDPL and (3 shl 10)) .2.MinAlloc dw Segment.2.End - Segment.2 ResourceTable: assert ResourceTable=$D0 .RsrcAlnSzShftCnt dw RSRC_ALIGNMENT_SHIFT .RsrcTypes: .1.TypeID dw $8000 or RT_GROUP_ICON .1.Count dw 1 .1.Reserved dd 0 .1.NameInfo: .1.NameInfo.1.rnOffset dw rsrc.1 shr RSRC_ALIGNMENT_SHIFT .1.NameInfo.1.rnLength dw (rsrc.1.End - rsrc.1) shr RSRC_ALIGNMENT_SHIFT .1.NameInfo.1.rnFlags dw NE_NSMOVE or NE_NSPRELOAD or (NE_NSDPL and (3 shl 10)) or NE_NSDISCARD .1.NameInfo.1.rnID dw $8000 or $93 .1.NameInfo.1.rnHandle dw 0 .1.NameInfo.1.rnUsage dw 0 .2.TypeID dw $8000 or RT_STRING .2.Count dw 2 .2.Reserved dd 0 .2.NameInfo: .2.NameInfo.1.rnOffset dw rsrc.2 shr RSRC_ALIGNMENT_SHIFT .2.NameInfo.1.rnLength dw (rsrc.2.End - rsrc.2) shr RSRC_ALIGNMENT_SHIFT .2.NameInfo.1.rnFlags dw NE_NSMOVE or NE_NSSHARED or (NE_NSDPL and (3 shl 10)) or NE_NSDISCARD .2.NameInfo.1.rnID dw $8000 or 1 .2.NameInfo.1.rnHandle dw 0 .2.NameInfo.1.rnUsage dw 0 .2.NameInfo.2.rnOffset dw rsrc.3 shr RSRC_ALIGNMENT_SHIFT .2.NameInfo.2.rnLength dw (rsrc.3.End - rsrc.3) shr RSRC_ALIGNMENT_SHIFT .2.NameInfo.2.rnFlags dw NE_NSMOVE or NE_NSSHARED or (NE_NSDPL and (3 shl 10)) or NE_NSDISCARD .2.NameInfo.2.rnID dw $8000 or 2 .2.NameInfo.2.rnHandle dw 0 .2.NameInfo.2.rnUsage dw 0 .3.TypeID dw $8000 or RT_VERSION .3.Count dw 1 .3.Reserved dd 0 .3.NameInfo: .3.NameInfo.1.rnOffset dw rsrc.4 shr RSRC_ALIGNMENT_SHIFT .3.NameInfo.1.rnLength dw (rsrc.4.End - rsrc.4) shr RSRC_ALIGNMENT_SHIFT .3.NameInfo.1.rnFlags dw NE_NSMOVE or NE_NSSHARED or (NE_NSDPL and (3 shl 10)) .3.NameInfo.1.rnID dw $8000 or 1 .3.NameInfo.1.rnHandle dw 0 .3.NameInfo.1.rnUsage dw 0 .4.TypeID dw $8000 or RT_ICON .4.Count dw 2 .4.Reserved dd 0 .4.NameInfo: .4.NameInfo.1.rnOffset dw rsrc.5 shr RSRC_ALIGNMENT_SHIFT .4.NameInfo.1.rnLength dw (rsrc.5.End - rsrc.5) shr RSRC_ALIGNMENT_SHIFT .4.NameInfo.1.rnFlags dw NE_NSMOVE or NE_NSPRELOAD or (NE_NSDPL and (3 shl 10)) or NE_NSDISCARD .4.NameInfo.1.rnID dw $8000 or 1 .4.NameInfo.1.rnHandle dw 0 .4.NameInfo.1.rnUsage dw 0 .4.NameInfo.2.rnOffset dw rsrc.6 shr RSRC_ALIGNMENT_SHIFT .4.NameInfo.2.rnLength dw (rsrc.6.End - rsrc.6) shr RSRC_ALIGNMENT_SHIFT .4.NameInfo.2.rnFlags dw NE_NSMOVE or NE_NSPRELOAD or (NE_NSDPL and (3 shl 10)) or NE_NSDISCARD .4.NameInfo.2.rnID dw $8000 or 2 .4.NameInfo.2.rnHandle dw 0 .4.NameInfo.2.rnUsage dw 0 .RsrcTypes.End: ; dw 0 .RsrcNames db 0 .RsrcNames.End db 0 ResidentNamesTable: assert ResidentNamesTable=$13C .Export.1.Str db 8,'BOOTSTRP' .Export.1.Ord dw 0 .Export.2.Str db 15,'___EXPORTEDSTUB' .Export.2.Ord dw 2 db 0 ModRefTable: assert ModRefTable=$15A .1.Offset dw ImportNamesTable.1.Lib-ImportNamesTable .2.Offset dw ImportNamesTable.2.Lib-ImportNamesTable .3.Offset dw ImportNamesTable.3.Lib-ImportNamesTable .4.Offset dw ImportNamesTable.4.Lib-ImportNamesTable .5.Offset dw ImportNamesTable.5.Lib-ImportNamesTable .6.Offset dw ImportNamesTable.6.Lib-ImportNamesTable ImportNamesTable: assert ImportNamesTable=$166 db 0 .1.Lib db 6,'KERNEL' .1.Imports: .1.Imports.1 db 16,'LOADLIBRARYEX32W' .1.Imports.2 db 14,'FREELIBRARY32W' .1.Imports.3 db 17,'GETPROCADDRESS32W' .1.Imports.4 db 16,'GETVDMPOINTER32W' .1.Imports.5 db 11,'CALLPROC32W' .2.Lib db 3,'GDI' .3.Lib db 4,'USER' .4.Lib db 8,'KEYBOARD' .5.Lib db 8,'LZEXPAND' .6.Lib db 5,'SHELL' EntryTable: assert EntryTable=$1DE .1.Count db 2 .1.SegNDX db NE_SEGNDX_MOVABLE .1.Movables: .1.Movable.1.flags db NE_ET_EXPORTED .1.Movable.1.int3f db $CD,$3F .1.Movable.1.SegNum db 1 .1.Movable.1.SegOffset dw $A3F6 .1.Movable.2.flags db NE_ET_EXPORTED .1.Movable.2.int3f db $CD,$3F .1.Movable.2.SegNum db 1 .1.Movable.2.SegOffset dw $3178 db 0 .End: NonResNamesTable: assert NonResNamesTable=$1ED .1.Str db 15,'MS-Setup Loader' .1.Ord dw 0 .2.Str db 11,'BOOTWNDPROC' .2.Ord dw 1 db 0 .End: STACKSLOP = 256 ; amount of stack slop space required align $20 GangloadStart: align $40 Segment.1: assert Segment.1=$240; CODE MOVEABLE PRELOADED RELOCATED DPL:3 org 0 db $10 dup (0) off_10 dw -1 error: mov al,-1 x16 stdcall 0:__exit,ax start: xor bp, bp push bp x16 stdcall 0:-1;INITTASK or ax, ax jz error mov [word_CA58], es add cx, STACKSLOP jb error mov [StackSize], cx mov [hPrev], si mov [hInst], di mov word [lpszCmd], bx mov word [lpszCmd+2], es mov [cmdShow], dx mov ax, -1 x16 stdcall 0:-1,ax ; LOCKSEGMENT x16 stdcall 0:GETVERSION xchg al, ah mov [word_CA5A], ax mov ah, $30 test [cs:off_10], 1 jz short .loc_6D call 0:-1 ; DOS3CALL jmp short .loc_6F .loc_6D: int $21 .loc_6F: mov [word_CA5E], ax xchg al, ah mov [word_CA5C], ax test [cs:off_10], 1 jnz short .loc_85 mov al, 0 mov [byte_CA61], al .loc_85: xor ax, ax x16 stdcall 0:-1,ax ; WAITEVENT x16 stdcall 0:-1,[hInst] ; INITAPP or ax, ax jnz short .loc_9D jmp error .loc_9D: call $18:__cinit call $A0:__setargv call $A5:__setenvp nop nop nop x16 ccall $AA:__stubmain,[word_CA92],[word_CA94],[word_CA96],[word_CA98],[word_CA9A] x16 stdcall $C6:_exit,ax __nomain: mov ax, $15 jmp __amsg_exit nop proc16 fclose c, file.offs, file.seg endp __exit: __WINFLAGS: INITTASK: LOCKSEGMENT: GETVERSION: DOS3CALL: WAITEVENT: INITAPP: WINMAIN: __setargv: __setenvp: __wcinit: __GetDGROUP: __fptrap: rb $16F2-$ proc16 __stubmain farcall,arg0,arg1,arg2,arg3,arg4 mov ax, ds push ds x16 stdcall 0:WINMAIN,[cmdShow],word [lpszCmd],word [lpszCmd+2],[hPrev],[hInst] pop ds ret endp rb $171E-$ proc16 __cinit farcall mov ax, ds push ds mov ax, $3500 test [cs:off_10], 1 jz short .loc_173B call DOS3CALL jmp short .loc_173D .loc_173B: int $21 .loc_173D: mov word [dword_CA44], bx mov word [dword_CA44+2], es push cs pop ds ; ds - codeseg mov ax, $2500 mov dx, $1BBE test [cs:off_10], 1 jz short .loc_175D call DOS3CALL jmp short .loc_175F .loc_175D: int $21 .loc_175F: x16 farcall __GetDGROUP mov ds, ax ; ds - dataseg mov cx, [word_CD98] jcxz short .loc_1794 mov es, [word_CA58] ; es - nothing mov si, [es:$2C] mov ax, [word_CD9A] mov dx, [word_CD9C] xor bx, bx call dword [unk_CD96] jnb short .loc_1786 jmp __fptrap .loc_1786: mov ax, [word_CD9E] mov dx, [word_CDA0] mov bx, 3 call dword [unk_CD96] .loc_1794: mov es, [word_CA58] mov cx, [es:$2C] jcxz short .loc_17DD mov es, cx xor di, di .loc_17A3: cmp byte [es:di], 0 jz short .loc_17DD mov cx, $0D mov si, word_CA36 repe cmpsb jz short .loc_17BE mov cx, $7FFF xor ax, ax repne scasb jnz short .loc_17DD jmp short .loc_17A3 .loc_17BE: push es ds pop es ds ; es - dataseg mov si, di mov di, unk_CA6A mov cl, 4 .loc_17C9: lodsb sub al, 'A' jb short .loc_17DB shl al, cl xchg ax, dx lodsb sub al, 'A' jb short .loc_17DB or al, dl stosb jmp short .loc_17C9 .loc_17DB: push es pop ds .loc_17DD: ret endp rb $1801-$ proc16 _exit farcall exitcode endp rb $1BC8-$ __amsg_exit: rb $C473-$ org $+Segment.1 Segment.1.End: rb $C9C0-$ align $10 Segment.2: assert Segment.2=$C9C0 org 0 dd ? dd 5 dw 0,0,0,0 db 'LST',0 db 'Params',0 align 2 db 'Files',0 db 'Win3.x Params',0 db 'Win3.x Files',0 align 2 db 'Windows 95 Params',0 db 'Windows 95 Files',0 align 2 db 'NT Alpha Params',0 db 'NT Alpha Files',0 align 2 db 'NT Mips Params',0 align 2 db 'NT Mips Files',0 db 'NT PPC Params',0 db 'NT PPC Files',0 align 2 db 'NT Intel Params',0 db 'NT Intel Files',0 align 2 db 'NT3.51 Intel Params',0 db 'NT3.51 Intel Files',0 align 2 dw 0,0,0,0 db 'PROCESSOR_ARCHITECTURE',0 align 2 db 'X86',0 db 'ALPHA',0 db 'MIPS',0 align 2 db 'PPC',0 db 'STUFF-BOOT',0 align 2 dw 9,0,0,0 dw 0,0,0,0 rb 260 rb 260 rb 260 db 'Source Directory',9,0 dd ? StackSize dw ? hPrev dw ? hInst dw ? lpszCmd dd ? cmdShow dw ? word_CA36: dword_CA44: word_CA58: word_CA5A:;OSVERSION word_CA5E: word_CA5C: byte_CA61: unk_CA6A: word_CA92: word_CA94: word_CA96: word_CA98: word_CA9A: unk_CD96: word_CD98: word_CD9A: word_CD9C: word_CD9E: word_CDA0: rb $B14-$ db '<<NMSG>>' dw 0 db 'R6000',13,10,'- stack overflow',13,10,0 dw 3 db 'R6003',13,10,'- integer divide by 0',13,10,0 dw 9 db 'R6009',13,10,'- not enough space for environment',13,10,0 dw 18 db 'R6018',13,10,'- unexpected heap error',13,10,0 dw 20 db 'R6020',13,10,'- unexpected QuickWin error',13,10,0 dw 8 db 'R6008',13,10,'- not enough space for arguments',13,10,0 dw 21 db 'R6021',13,10,'- no main procedure',13,10,0 dw 252 db 13,10,0 dw 255 db 'run-time error ',0 dw 2 db 'R6002',13,10,'- floating-point support not loaded',13,10,0 rb $4AF8-$ org Segment.2+$ Segment.2.End: dw 2,2,$928,1,0,2,$6B8,2,0,0,0,0 align $20 rsrc.1: assert rsrc.1 = $114E0 MainIcon: .idReserved dw 0 .idType dw 1 .idCount dw 2 .1.bWidth db 32 .1.bHeight db 32 .1.bColorCount db 16 .1.bReserved db 0 .1.wPlanes dw 1 .1.wBitCount dw 4 .1.dwBytesInRes dd Icon_1.End-Icon_1 .1.nId dw 1 .2.bWidth db 16 .2.bHeight db 16 .2.bColorCount db 16 .2.bReserved db 0 .2.wPlanes dw 1 .2.wBitCount dw 4 .2.dwBytesInRes dd Icon_2.End-Icon_2 .2.nId dw 2 align $10 rsrc.1.End: align $20 rsrc.5: assert rsrc.5 = $11520 Icon_1: rb $2E8 .End: rb 8 rsrc.5.End: align $20 rsrc.6: assert rsrc.6 = $11820 Icon_2: rb $128 .End: rb 8 rsrc.6.End: rb $30 GangloadEnd: rsrc.2: assert rsrc.2 = $11980 db 26,'Setup Initialization Error' db 35,'The application has been corrupted.' db 149,'Another copy of Setup is already running.',$A,$A,'Finish installing the other copy of the Setup program or restart Windows, then restart this copy of Setup.' db 58,'Setup cannot access the required initialization file ',$27,'%s',$27,'.' db 118,'There is insufficient memory or disk space to run Setup. The Setup program requires about %1ldkb of free disk space.',$A,$A db 47,'A Setup initialization file has been corrupted.' db 100,'There is insufficient memory to run Setup.',$A,$A,'Try closing any open applications or restarting Windows.' db 146,'There is insufficient disk space to run Setup. The Setup program requires about %1ldkb of free disk space.',$A,$A,'Free up some disk space and try again.' db 82,'Try closing any open applications, restarting Windows, or freeing some disk space.' db 21,'Please insert disk %s' db 54,'Setup cannot find the file %s.',$A,$A,'Please insert disk %s.' db 75,'This Setup program is not intended to be used with your version of Windows.' db 95,'Setup is unable to create a temporary file of size %s K for decompressing installation files.',$A,$A db 60,'Setup has encountered an error in the Registration Database.' db 0 db 34,'Setup cannot find the file %s.',$A,$A,'%s' rb 4 rsrc.2.End: rsrc.3: assert rsrc.3 = $11DE0 db 50,'Setup cannot run without your program',$27,'s diskettes.' db 2,'%s' db 86,'Setup cannot find the files on ',$27,'%s',$27,' from which you originally installed the product.',$A,$A db 207,'To add/remove programs or options, run the Setup program from the CD or floppy Disk 1. If you installed from a network location, run Setup from the network location that currently contains the Setup program.' db 116,'The Setup configuration file ',$27,'%s',$27,' is missing or corrupted. Try running Setup again from where you originally ran it.' db 0 db 20,'Insufficient memory.' db 26,'Setup initialization error' db 5,'Setup' rb 7 rsrc.3.End: rsrc.4: assert rsrc.4 = $11FF0 db $280 dup (0) rsrc.4.End: May be someone have smaller NE than 75kb (I have only 1 donor), or literature where NE relocation mechanic described(I understand mechanic, but where it hided? overlapped with DosStubProc?) Or I should explore IDA PRO loader NE.ldw - where it gets data to resolve relocations. |
|||
30 Jan 2020, 22:03 |
|
Tomasz Grysztar 31 Jan 2020, 07:17
ProMiNick wrote: May be someone have smaller NE than 75kb (I have only 1 donor), or literature where NE relocation mechanic described(I understand mechanic, but where it hided? overlapped with DosStubProc?) |
|||
31 Jan 2020, 07:17 |
|
ProMiNick 31 Jan 2020, 08:41
Thanks, looks helpful.
|
|||
31 Jan 2020, 08:41 |
|
ProMiNick 06 Feb 2020, 01:27
Code: NE_REL_TYPE_IMPORT_ORDINAL = 1 NE_REL_TYPE_IMPORT_NAME = 2 NE_REL_FARPTR = 3 macro library [name,string] { common module.references: forward if defined name#.%used & name#.%used name#.%libidx = 1 + ($- module.references) shr 1 dw name end if common import.names: db 0 forward local ..end if defined name#.%libidx label name byte at $-import.names db ..end-$-1,string ..end: end if } macro import name,[labl,ord,fname] { common local %used if ~definite import.names .err library must precede to import end if %used = 0 forward if used labl %used = %used + 1 labl#.%libidx = name#.%libidx if fname eq labl#.%type = NE_REL_TYPE_IMPORT_ORDINAL label labl byte at ord else labl#.%type = NE_REL_TYPE_IMPORT_NAME local ..end label labl byte at $-import.names db ..end-$-1,fname ..end: end if end if common name#.%used = %used } macro reloc statement& { match =call name,statement \{ call name-name:-1 relocs equ relocs,NE_REL_FARPTR,name#.%type,$-4,name#.%libidx,name \} } macro fixup dummy,[reladdr,reltype,offs,data1,data2] { common local ..relstart,..relcount dw ..relcount ..relstart: forward db reladdr,reltype dw offs,data1,data2 common ..relcount = ($-..relstart) shr 3 } relocs equ Segment.code: reloc call InitTask Segment.code.end: fixup relocs relocs equ library krnl386,'KERNEL' import krnl386,\ InitTask,91,'INITTASK' fixup macro dosn`t works as expected If I comment line "fixup relocs" produced output Code: Segment.code: $9A $FFFF $0000 ; call 0:-1 module.references: $0001 ; import.names+1 import.names: $00 $06 'KERNEL' ; import.names+1 $08 'INITTASK' ; import.names+8 what wanted with fixup Code: Segment.code: $9A $FFFF $0000 ; call 0:-1 $0001 ; reloc count $03 ; reloc address = NE_REL_FARPTR $02 ; reloc type = NE_REL_TYPE_IMPORT_NAME $0001 ; Segment.code +1 (addr of opnd in call seg:offset) $0001 ; Lib Index $0008 ; Offset of funcname in import.names (import.names+8) module.references: $0001 ; import.names+1 import.names: $00 $06 'KERNEL' ; import.names+1 $08 'INITTASK' ; import.names+8 |
|||
06 Feb 2020, 01:27 |
|
ProMiNick 15 Feb 2020, 11:54
I minimized context: macros below build valid imports, 2 segments code & data with correct relocations - not flexible but all as expected:
Code: NE_RELFL_INTERNALREF = 0 NE_RELFL_IMPORT_ORDINAL = 1 NE_RELFL_IMPORT_NAME = 2 NE_REL_FARPTR = 3 NE_REL_OFFSET16 = 5 END_RELOC_CHAIN = -1 DOS_QUIT_WITH_EXIT_CODE = $4C MB_OK=0 RETURN_ERROR1 = 1 macro reloc instruction& { instruction match instr +++ opnd,instruction \{ relocs equ relocs,NE_REL_OFFSET16,NE_RELFL_INTERNALREF,$-2,2,opnd \} } macro library [name,string] { common module.references: forward if defined name#.%used & name#.%used name#.%libidx = 1 + ($- module.references) shr 1 dw name end if common import.names: db 0 forward local ..end if defined name#.%libidx label name byte at $-import.names db ..end-$-1,string ..end: end if } macro import name,[labl,ord,fname] { common local %used if ~definite import.names .err library must precede to import end if %used = 0 forward define labl#.@imported if used labl %used = %used + 1 labl#.%libidx = name#.%libidx if fname eq labl#.%type = NE_RELFL_IMPORT_ORDINAL label labl byte at ord else labl#.%type = NE_RELFL_IMPORT_NAME local ..end label labl byte at $-import.names db ..end-$-1,fname ..end: end if end if common name#.%used = %used } macro pushw value { match =addr var,value \{ if +var relativeto 0 | +var relativeto $ reloc push +++var else lea dx,[var] push dx end if pushw equ \} match pushw =far seg:offs,pushw value \{ push seg if +offs relativeto 0 | +offs relativeto $ reloc push +++offs else lea dx,[offs] push dx end if pushw equ \} match pushw =qword [var],pushw value \{ push word [var+6] push word [var+4] push word [var+2] push word [var] pushw equ \} match pushw =dword [var],pushw value \{ push word [var+2] push word [var] pushw equ \} match pushw,pushw \{ push value pushw equ \} restore pushw } macro doscall toAH*,toAL,toDX { if ~toAL eq mov ax,toAH shl 8 + toAL else mov ah,toAH end if if ~toDX eq mov dx,toDX end if if defined REAL_MODE int $21 else invoke Dos3Call end if } macro invoke proc,[arg] { ; indirectly call PASCAL procedure common local s$n1 if ~ arg eq forward pushw arg common end if s$n1 = $+1 match ++any,proc#.@current \{ store word (s$n1-proc#.@current) at proc#.@current \} proc#.@current equ ++s$n1 match :no,proc#.@imported:proc#.@used \{ relocs equ relocs,NE_REL_FARPTR,proc#.%type,proc#.@current,proc#.%libidx,proc \} define proc#.@used call proc-proc:END_RELOC_CHAIN } macro fixup dummy,[reladdr,reltype,offs,data1,data2] { common local ..relstart,..relcount dw ..relcount ..relstart: if ~reladdr eq forward db reladdr,reltype dw offs,data1,data2 common end if ..relcount = ($-..relstart) shr 3 } library krnl386,'KERNEL',\ user,'USER' import krnl386,\ WaitEvent,30,'WAITEVENT',\ InitTask,91,'INITTASK',\ Dos3Call,102,'DOS3CALL' import user,\ MessageBox,1,'MESSAGEBOX',\ InitApp,5,'INITAPP' ;segment code movable preloaded relocated DPL(3) org 0 start: invoke InitTask ; test relocation chain passed invoke InitTask ; invoke InitTask ; or ax, ax jz .err ;push di ; hInstance ;push si ; hPrevInstance ;pushw far es:bx ; lpCmdLine ;push dx ; nCmdShow invoke WaitEvent, 0 invoke InitApp, di or ax, ax jz .err invoke MessageBox,0,far ds:_message,far ds:_caption,MB_OK jmp .exit .err: mov al,RETURN_ERROR1 jmp .exit .exit: doscall DOS_QUIT_WITH_EXIT_CODE match dummy=,relinfo,relocs { fixup ,relinfo } relocs equ () ;segment data movable preloaded DPL(3) org 0 _caption db 'Win16 assembly program',0 _message db 'Hello World!',0 |
|||
15 Feb 2020, 11:54 |
|
ProMiNick 24 Feb 2020, 21:57
alexfru, examples\win16\nedemo\nedemo.asm
sections, their content & their relocations are now calculated OK (files produced w/o errors), but IDAPro thoughts its a truncated file w95 informs that it is in invalid format https://yadi.sk/d/f3kzyjRlFrocHQ thanks for ideas what wrong. I guess I have to play nasm & thour example to explore its output for comparing with mine. Tomasz, thou were right about relocations, they will be hard to be realize in fasm1, but not impossible: in examples\win16\template\template.asm I realize every form of relocations needed for win16. alexfru, (a bit offtopic from fasm assembly: nasm) Code: @echo off if not '%2'=='' "%~0" "%*" if not '%1'=='' goto :Start start "" "C:\fasmw17322COMFRIENDLY\fasmw.exe" "%~0" &exit :Start "C:\nasm-2.15rc0-20191023\nasm.exe" "%~1" -o hw.exe pause :exit output is: Code: C:\KNOWLEDGEBASE\NE\Win16asm\hw.asm:3: fatal: unable to open include file `ne.inc' Press any key to continue . . . hw.asm, ne.inc, win16api.inc, helpers.inc - are all in same directory when I combine them in 1 file error is: Code: panic: C:\KNOWLEDGEBASE\NE\Win16asm\hw2.asm:546: assertion next == tok failed at asm/prepr oc.c:4543 Press any key to continue . . . |
|||
24 Feb 2020, 21:57 |
|
alexfru 25 Feb 2020, 10:00
ProMiNick wrote: alexfru, examples\win16\nedemo\nedemo.asm Does my hw.exe work for you at all? It worked for me on either 32-bit Win7 or XP. I never tried anything as old as Win9x. I'm not 100% my implementation is clean. But like I said, my hw.exe did work at least on one 32-bit Windows. ProMiNick wrote:
I don't see that one. ProMiNick wrote:
But I too see that one with the latest build. 2.14.02 stable and 2.14.03 RC2 seem to work fine. You should've tried them before asking. Latest ≠ best. I've been happily using 2.10 for many years. |
|||
25 Feb 2020, 10:00 |
|
ProMiNick 25 Feb 2020, 12:50
Sources for members that has no access to yadi.sk:
nedemo.asm (itself): Code: format binary as 'exe' include 'win16.inc' macro align boundary,value:? { db (boundary-1)-($+boundary-1) mod boundary dup value } NEFORMAT entry cseg1:start ;entry start include 'os specific\dos\equates\syscalls.inc' END_RELOC_CHAIN = -1 RETURN_ERROR1 = 1 STACKSLOP = 256 FILE_ALIGNMENT_SHIFT = 4 RSRC_ALIGNMENT_SHIFT = 4 FILE_ALIGNMENT = 1 shl FILE_ALIGNMENT_SHIFT ;=============================================================================== SegmentTable: repeat segment@count dw 4 dup(0) end repeat ResourceTable: ResidentNamesTable: .Export.1.Str db 6,'module' .Export.1.Ord dw 0 db 0 library krnl386,'KERNEL',\ user,'USER' include 'os specific\windows\api\win16\krnl386.inc' include 'os specific\windows\api\win16\user.inc' EntryTable: .Count db 0 db 0 .End: NonResNamesTable: .1.Str db 4,'none' .1.Ord dw 0 db 0 .End: align 16 FastloadAreaStart: ;align $40 segment cseg1 code movable preloaded relocatable DPL(3) db $10 dup (0) ; 0Ch dword is maybe trashed by OS ;off_10 dw -1 start: invoke InitTask ; or ax, ax jz .err invoke WaitEvent, 0 invoke InitApp, di or ax, ax jz .err invoke MessageBox,0,far ds:dseg1&_message,far ds:dseg1&_caption,MB_OK jmp .exit .err: mov al,RETURN_ERROR1 jmp .exit .exit: doscall DOS_QUIT_WITH_EXIT_CODE endsegment segment dseg1 data movable preloaded DPL(3) db $10 dup (0) ; 0Ch dword is trashed by OS _caption db 'Win16 assembly program',0 _message db 'Hello World!',0 endsegment FastloadAreaEnd: in win16.inc listed includes "struct.inc", "pushw.inc", "proc16.inc" , "ne/macro/segmentation.inc", "ne/macro/headers.inc", "ne/macro/import.inc", "ne/macro/relocs.inc", "ne/equates/flags.inc", "resource.inc" equates (same as for 32 bit but without struct definitions) own 16bit struct definitions "structures/x16/winuser.inc" pushw.inc: Code: ;variants: ;pushw dword [segN&var] ;pushw dword [bp+local] ;pushw ds:dx ;pushw ds:[segN&var] ;pushw ds:[bp+local] ;pushw imm:[segN&var] ;pushw imm:[bp+local] ;pushw far segN&var ;pushw far ds:segN&var ;pushw far ds:bp+local ;pushw far imm:segN&var ;pushw far imm:bp+local ;pushw [segN&var] ;pushw [bp+local] ;pushw ax ;pushw imm ;pushw addr segN&var ;pushw addr bp+local ;pushw ds macro relpush [value] { match [segN&var],value \{ push word [var-var+END_RELOC_CHAIN] reloc offs16 idxof@\#segN:var \} match =offset segN&var,value \{ push word var-var+END_RELOC_CHAIN reloc offs16 idxof@\#segN:var \} } macro pushmem size:word,arg { match segN&offs,arg \{ match =qword,size \\{ relpush [arg+6],[arg+4],[arg+2],[arg] \\} match =dword,size \\{ relpush [arg+2],[arg] \\} match =word,size \\{ relpush [arg] \\} pushw equ \} match =pushw,pushw \{ match =qword,size \\{ push word[arg+6] push word[arg+4] push word[arg+2] push word[arg] \\} match =dword,size \\{ push word[arg+2] push word[arg] \\} match =word,size \\{ push word[arg] \\} pushw equ \} } macro pushfar segN,offs { push END_RELOC_CHAIN reloc segment idxof@#segN:offs push word offs-offs+END_RELOC_CHAIN reloc offs16 idxof@#segN:offs pushw equ } macro pushadr addr { match segN&offs,addr \{ push word offs-offs+END_RELOC_CHAIN reloc offs16 idxof@\#segN:offs pushw equ \} match =pushw,pushw \{ lea dx, word[addr] push dx pushw equ \} } macro simplepushw value { match size[addr],value \{ pushmem size,addr \} match [addr],value \{ pushmem ,addr \} match =far segN&offs,value \{ pushfar segN,offs \} match =addr offs,value \{ pushadr offs \} match =pushw,pushw \{ push value pushw equ \} } macro complexpushw seg,offs { match =far rest,seg \{ push rest pushadr offs \} match =pushw,pushw \{ push seg match [addr],value \\{ pushmem ,addr \\} match =pushw,pushw \\{ push offs pushw equ \\} \}} macro pushw value { match pre:post,value \{ match |,post \\{ simplepushw value \\} match rest,post \\{ complexpushw pre,rest \\} \} restore pushw } proc16.inc: Code: ; Macroinstructions for defining and calling procedures ; far imm16:imm16 ; far seg:segN&var ; far segN&var ; off segN&var ; seg segN&var ; addr var ; addr imm16:imm16 macro pascal proc,[arg] { ; directly call PASCAL procedure common if ~ arg eq forward pushw arg common end if call proc } macro invoke proc,[arg] { ; indirectly call PASCAL procedure common local s$n1 match any,arg \{ forward pushw arg common \} s$n1 = $+1 match ++any,proc#.@current \{ store word (s$n1-proc#.@current) at :proc#.@current \} proc#.@current equ ++s$n1 match :no,proc#.@imported:proc#.@used \{ relocs equ relocs,NE_REL_FARPTR,proc#.%type,proc#.@current,proc#.%libidx,proc \} define proc#.@used call proc-proc:END_RELOC_CHAIN } macro doscall toAH*,toAL,toDX { if ~toAL eq mov ax,toAH shl 8 + toAL else mov ah,toAH end if if ~toDX eq mov dx,toDX end if match any =1 rest,:REAL_MODE:1: \{ match :,rest \\{ invoke Dos3Call \\} match :1:,rest \\{ int $21 \\} \} } macro proc16 [args] ; define procedure { common match name params, args> \{ define@proc16 name,<params \} } prologue@proc16 equ prologuedef16 macro prologuedef16 procname,flag,parmbytes,localbytes,reglist { local loc loc = (localbytes+1) and (not 1) parmbase@proc16 equ bp+4 localbase@proc16 equ bp-loc if parmbytes | localbytes push bp mov bp,sp if localbytes sub sp,loc end if end if irps reg, reglist \{ push reg \} } epilogue@proc16 equ epiloguedef16 macro epiloguedef16 procname,flag,parmbytes,localbytes,reglist { irps reg, reglist \{ reverse pop reg \} if parmbytes | localbytes leave end if if flag and 100000b if flag and 10000b retf else retf parmbytes end if else if flag and 10000b retn else retn parmbytes end if end if } close@proc16 equ macro define@proc16 name,statement { local params,flag,regs,parmbytes,localbytes,current if used name name: flag = 0 params equ statement: match =far args, params \{ flag = 100000b params equ args \} match =farcall args, params \{ flag = 100011b params equ args \} match =stdcall args, params \{ flag = flag or 11b params equ args \} match =c args, params \{ flag = flag or 10001b params equ args \} match =uses reglist=,args, params \{ regs equ reglist params equ args \} match =regs =uses reglist:, regs params \{ regs equ reglist params equ \} match =regs, regs \{ regs equ \} match args:, params \{ params equ args \} match :, params \{ params equ \} match prologue:reglist, prologue@proc16:<regs> \{ prologue name,flag,parmbytes,localbytes,reglist \} virtual at parmbase@proc16 match =,args, params \{ defargs@proc16 args \} match =args@proc16 args, args@proc16 params \{ defargs@proc16 args \} parmbytes = $-(parmbase@proc16) end virtual name # % = parmbytes/2 all@vars equ current = 0 macro locals \{ virtual at localbase@proc16+current macro label def \\{ match . type,def> \\\{ deflocal@proc .,label,<type \\\} \\} struc db [val] \\{ \common deflocal@proc .,db,val \\} struc du [val] \\{ \common deflocal@proc .,du,val \\} struc dw [val] \\{ \common deflocal@proc .,dw,val \\} struc dp [val] \\{ \common deflocal@proc .,dp,val \\} struc dd [val] \\{ \common deflocal@proc .,dd,val \\} struc dt [val] \\{ \common deflocal@proc .,dt,val \\} struc dq [val] \\{ \common deflocal@proc .,dq,val \\} struc rb cnt \\{ deflocal@proc .,rb cnt, \\} struc rw cnt \\{ deflocal@proc .,rw cnt, \\} struc rp cnt \\{ deflocal@proc .,rp cnt, \\} struc rd cnt \\{ deflocal@proc .,rd cnt, \\} struc rt cnt \\{ deflocal@proc .,rt cnt, \\} struc rq cnt \\{ deflocal@proc .,rq cnt, \\} \} macro endl \{ purge label restruc db,du,dw,dp,dd,dt,dq restruc rb,rw,rp,rd,rt,rq current = $-(localbase@proc16) end virtual \} macro ret operand \{ match any, operand \\{ retn operand \\} match , operand \\{ match epilogue:reglist, epilogue@proc16:<regs> \\\{ epilogue name,flag,parmbytes,localbytes,reglist \\\} \\} \} macro finish@proc16 \{ localbytes = current match close:reglist, close@proc16:<regs> \\{ close name,flag,parmbytes,localbytes,reglist \\} end if \} } macro defargs@proc16 [arg] { common if ~ arg eq forward local ..arg,current@arg match argname:type, arg \{ current@arg equ argname label ..arg type argname equ ..arg if qqword eq type dw ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,? else if dqword eq type dw ?,?,?,?,?,?,?,? else if tbyte eq type dw ?,?,?,?,?,? else if qword eq type | pword eq type dw ?,?,?,? else if dword eq type dw ?,? else dw ? end if \} match =current@arg,current@arg \{ current@arg equ arg arg equ ..arg ..arg dw ? \} common args@proc16 equ current@arg forward restore current@arg common end if } macro deflocal@proc name,def,[val] { name def val } macro deflocal@proc name,def,[val] { common match vars, all@vars \{ all@vars equ all@vars, \} all@vars equ all@vars name forward local ..var,..tmp ..var def val match =?, val \{ ..tmp equ \} match any =?, val \{ ..tmp equ \} match any (=?), val \{ ..tmp equ \} match =label, def \{ ..tmp equ \} match tmp : value, ..tmp : val \{ tmp: end virtual initlocal@proc ..var,def value virtual at tmp\} common match first rest, ..var, \{ name equ first \} } struc label type { label . type } macro initlocal@proc name,def { virtual at name def size@initlocal = $ - name end virtual position@initlocal = 0 while size@initlocal > position@initlocal virtual at name def if size@initlocal - position@initlocal < 2 current@initlocal = 1 load byte@initlocal byte from name+position@initlocal else if size@initlocal - position@initlocal < 4 current@initlocal = 2 load word@initlocal word from name+position@initlocal else current@initlocal = 4 load dword@initlocal dword from name+position@initlocal end if end virtual if current@initlocal = 1 mov byte [name+position@initlocal],byte@initlocal else if current@initlocal = 2 mov word [name+position@initlocal],word@initlocal else mov dword [name+position@initlocal],dword@initlocal end if position@initlocal = position@initlocal + current@initlocal end while } macro endp { purge ret,locals,endl finish@proc16 purge finish@proc16 restore regs@proc match all,args@proc16 \{ restore all \} restore args@proc16 match all,all@vars \{ restore all \} } macro local [var] { common locals forward done@local equ match varname[count]:vartype, var \{ match =BYTE, vartype \\{ varname rb count restore done@local \\} match =WORD, vartype \\{ varname rw count restore done@local \\} match =DWORD, vartype \\{ varname rd count restore done@local \\} match =PWORD, vartype \\{ varname rp count restore done@local \\} match =QWORD, vartype \\{ varname rq count restore done@local \\} match =TBYTE, vartype \\{ varname rt count restore done@local \\} match =DQWORD, vartype \\{ label varname dqword rq count*2 restore done@local \\} match =QQWORD, vartype \\{ label varname qqword rq count*4 restore done@local \\} match =XWORD, vartype \\{ label varname xword rq count*2 restore done@local \\} match =YWORD, vartype \\{ label varname yword rq count*4 restore done@local \\} match , done@local \\{ virtual varname vartype end virtual rb count*sizeof.\#vartype restore done@local \\} \} match :varname:vartype, done@local:var \{ match =BYTE, vartype \\{ varname db ? restore done@local \\} match =WORD, vartype \\{ varname dw ? restore done@local \\} match =DWORD, vartype \\{ varname dd ? restore done@local \\} match =PWORD, vartype \\{ varname dp ? restore done@local \\} match =QWORD, vartype \\{ varname dq ? restore done@local \\} match =TBYTE, vartype \\{ varname dt ? restore done@local \\} match =DQWORD, vartype \\{ label varname dqword dq ?,? restore done@local \\} match =QQWORD, vartype \\{ label varname qqword dq ?,?,?,? restore done@local \\} match =XWORD, vartype \\{ label varname xword dq ?,? restore done@local \\} match =YWORD, vartype \\{ label varname yword dq ?,?,?,? restore done@local \\} match , done@local \\{ varname vartype restore done@local \\} \} match ,done@local \{ var restore done@local \} common endl } segmentation.inc: Code: ; Macroinstructions for making segments (16|32-bit) postpone {segment@count = segment@idx resource@count = resource@idx } segment@idx =0 resource@idx = 0 code@idx = 0 data@idx = 0 cseg1st = 0 macro end@alloc {} macro segment statement& { local flag, setmode flag = 0 match alias flags, statement \{ idxof@\#alias = segment@idx + 1 segment@idx = segment@idx + 1 match any =code rest,:flags: \\{ if ~code@idx cseg1st = segment@idx end if code@idx = code@idx + 1 \\} match any =data rest,:flags: \\{ data@idx = data@idx + 1 flag = flag or NE_NSDATA \\} match any =allocated rest,:flags: \\{ flag = flag or NE_NSALLOC \\} match any =loaded rest,:flags: \\{ flag = flag or NE_NSLOADED \\} match any =iterated rest,:flags: \\{ flag = flag or NE_NSITER \\} match any =movable rest,:flags: \\{ flag = flag or NE_NSMOVE \\} match any =shared rest,:flags: \\{ flag = flag or NE_NSSHARED \\} match any =preloaded rest,:flags: \\{ flag = flag or NE_NSPRELOAD \\} match any =unwriteable rest,:flags: \\{ flag = flag or NE_NSEXRD \\} match any =relocatable rest,:flags:relocatable: \\{ match rest1 =relocatable:,rest \\\{ flag = flag or NE_NSRELOC relocs equ () \\\} match :,rest \\\{ macro reloc [relinfo] \\\\{ \\\\} macro fixup dummy,[reladdr,reltype,offs,data1,data2] \\\\{ \\\\} \\\} \\} match any =conformed rest,:flags: \\{ flag = flag or NE_NSCONFORM \\} match any =DPL(val) rest,:flags: \\{ \\assert val>=0 \\assert val<4 flag = flag or (val shl 10) \\} match any =discarded rest,:flags: \\{ flag = flag or NE_NSDISCARD \\} match any =32bit rest,:flags:32bit: \\{ match rest1 =32bit:,rest \\\{ flag = flag or NE_NS32BIT setmode equ use32 \\\} match :,rest \\\{ setmode equ use16 \\\} \\} match any =huge rest,:flags: \\{ flag = flag or NE_NSHUGE \\} macro end@alloc \\{ allocof@\#alias: virtual at $ purge end@alloc \\} macro unallocated \\{ end@alloc purge unallocated\\} macro endsegment \\{ sizeof@\#alias: end@alloc end virtual store word startof@\#alias shr FILE_ALIGNMENT_SHIFT at :SegmentTable+8*(segment@idx-1) store word sizeof@\#alias at :SegmentTable+8*(segment@idx-1)+2 store word flag at :SegmentTable+8*(segment@idx-1)+4 store word allocof@\#alias at :SegmentTable+8*(segment@idx-1)+6 \\use16 \\org startof@\#alias+sizeof@\#alias match any =relocatable rest,:flags:relocatable: \\\{ match rest1 =relocatable:,rest \\\\{ match dummy =,relinfo,relocs \\\\\{ fixup ,relinfo \\\\\} \\\\} match :,rest \\\\{ purge reloc,fixup \\\\} \\\} purge endsegment,unallocated \\} if (~cseg1st) & segment@idx>data@idx cseg1st = segment@idx end if align FILE_ALIGNMENT startof@\#alias: setmode org 0 \} } headers.inc: Code: macro entry address { match any:rest,address:: \{ match off::,rest \\{ store dword idxof@\#any shl 16 + off at :Header.EntryPoint \\} match :,rest \\{ store word any at :Header.EntryPoint \\} \} } macro NEFORMAT { stub: .e_magic dw 'MZ' .e_cblp dw SIZE_OF_STUB mod 512 .e_cp dw (SIZE_OF_STUB-1)/512 + 1 .e_crlc dw 0 .e_cparhdr dw SIZE_OF_STUB_HEADER / 16 db 0x18 - ($-stub) dup 0 .e_lfarlc dw SIZE_OF_STUB_HEADER db 0x3C - ($-stub) dup 0 .e_lfanew dd NE align 16 SIZE_OF_STUB_HEADER = $ - stub ; The code of a DOS program would go here. org 0 define REAL_MODE 1 push cs pop ds doscall DOS_WRITE_STRING,,noDOS doscall DOS_QUIT_WITH_EXIT_CODE,RETURN_ERROR1 noDOS db 'This program requires Microsoft Windows',$2E,13,10,'$' define REAL_MODE 0 org SIZE_OF_STUB_HEADER+$ SIZE_OF_STUB = $ - stub align 8 NE: Header: .Signature dw "NE" .MajorLinkerVersion db 5 .MinorLinkerVersion db 0 .EntryTable dw EntryTable-NE .SizeOfEntryTable dw EntryTable.End-EntryTable .CheckSum dd 0 .ProgramFlags db NE_INST .Applicationflags db NE_WINAPI .AutoDataSegIndex dw 2 .InitHeapSize dw 0;$800 .InitStackSize dw $2000 .EntryPoint dd cseg1st:start .InitialStackPointer dd idxof@dseg1:0 .SegCount dw segment@count .ModRefs dw (import.names-module.references) shr 1 .SizeOfNonResNamesTable dw NonResNamesTable.End-NonResNamesTable .SegTableOffset dw SegmentTable-NE .ResTableOffset dw ResourceTable-NE .ResNamesTable dw ResidentNamesTable-NE .ModRefTable dw module.references-NE .ImportNamesTable dw import.names-NE .OffStartNonResNamesTable dd NonResNamesTable .MovEntryCount dw 0;2 .FileAlnSzShftCnt dw FILE_ALIGNMENT_SHIFT .nResTableEntries dw resource@count .TargetOS db NE_WINDOWS .OS2EXEFlags db 0;NE_GANGL .RetThunksOffset: .FastLoadAreaStart dw FastloadAreaStart shr FILE_ALIGNMENT_SHIFT .SegRefThunksOffset: .FastLoadAreaSize dw (FastloadAreaEnd-FastloadAreaStart) shr FILE_ALIGNMENT_SHIFT .MinCodeSwap dw 0 .MinorOperatingSystemVersion db 10 .MajorOperatingSystemVersion db 3 } import.inc: Code: ; Macroinstructions for making imports (16-bit) macro library [name,string] { common module.references: forward if defined name#.%used & name#.%used name#.%libidx = 1 + ($- module.references) shr 1 dw name end if common import.names: db 0 forward local ..end if defined name#.%libidx label name byte at $-import.names db ..end-$-1,string ..end: end if } macro import name,[labl,ord,fname] { common local %used if ~definite import.names .err library must precede to import end if %used = 0 forward define labl#.@imported if used labl %used = %used + 1 labl#.%libidx = name#.%libidx if fname eq labl#.%type = NE_RELFL_IMPORT_ORDINAL label labl byte at ord else labl#.%type = NE_RELFL_IMPORT_NAME local ..end label labl byte at $-import.names db ..end-$-1,fname ..end: end if end if common name#.%used = %used } relocs.inc: Code: ; Macroinstructions for making relocations (16-bit) macro reloc [relinfo] { common local rbase rbase = $-2 reverse local current match =constimm8,relinfo \{ rbase = rbase-1 \} match =constimm16,relinfo \{ rbase = rbase-2 \} match =constimm32,relinfo \{ rbase = rbase-4 \} match =far dseg:name,relinfo \{ current = rbase relocs equ relocs,NE_REL_FARPTR,NE_RELFL_INTERNALREF,current-2,dseg,name rbase = rbase-4 \} match =far48 dseg:name,relinfo \{ current = rbase relocs equ relocs,NE_REL_FARPTR48,NE_RELFL_INTERNALREF,current-4,dseg,name rbase = rbase-6 \} match =offs16 dseg:name,relinfo \{ current = rbase relocs equ relocs,NE_REL_OFFSET16,NE_RELFL_INTERNALREF,current,dseg,name rbase = rbase-2 \} match =offset dseg:name,relinfo \{ current = rbase relocs equ relocs,NE_REL_OFFSET32,NE_RELFL_INTERNALREF,current-2,dseg,name rbase = rbase-4 \} match =segment dseg:name,relinfo \{ current = rbase relocs equ relocs,NE_REL_SEGMENT,NE_RELFL_INTERNALREF,current,dseg,name rbase = rbase-2 \} ;match =lobyte dseg:name,relinfo \{ ; current = rbase ; relocs equ relocs,NE_REL_LOBYTE,NE_RELFL_INTERNALREF,current,dseg,name ; rbase = rbase-1 \} } macro fixup dummy,[reladdr,reltype,offs,data1,data2] { common local ..relstart,..relcount dw ..relcount ..relstart: if ~reladdr eq forward db reladdr,reltype dw offs,data1,data2 common end if ..relcount = ($-..relstart) shr 3 } flags.inc: Code: ; Program flags NE_SOLO = $01 NE_INST = $02 NE_PPLI = $04 NE_PROT = $08 NE_I086 = $10 NE_I286 = $20 NE_I386 = $40 NE_FLTP = $80 ; Application flags NE_NOTWINCOMPAT = $01 ; fullscreen NE_WINCOMPAT = $02 NE_WINAPI = $03 NE_APPTYPEMASK = $07 NE_OS2APP = $08 ; reserved $10 NE_IERR = $20 NE_NONCOMFORM = $40 NE_DLL = $80 ; TargetOS NE_UNKNOWN = 0 NE_OS2 = 1 NE_WINDOWS = 2 ;Win16 NE_DOS4 = 3 NE_WIN386 = 4 ;Win32s NE_BOSS = 5 ; Additional flags NE_LONGFILENAMES = 1 NE_PMODE = 2 NE_PFONT = 4 NE_GANGL = 8 ; file contains a fast-load area ; Segment flags NE_NSCODE = $0000 NE_NSDATA = $0001 NE_NSALLOC = $0002 NE_NSLOADED = $0004 NE_NSITER = $0008 NE_NSMOVE = $0010 NE_NSSHARED = $0020 NE_NSPRELOAD = $0040 NE_NSEXRD = $0080 NE_NSRELOC = $0100 NE_NSCONFORM = $0200 NE_NSDPL = $0C00 NE_NSDISCARD = $1000 NE_NS32BIT = $2000 NE_NSHUGE = $4000 ; Segment predefined numbers for Entry Table NE_SEGNDX_MOVABLE = $FF NE_SEGNDX_REFCONST = $FE ; Entry table flags NE_ET_EXPORTED = 1 NE_ET_SHARED = 2 ; Relocation type NE_REL_LOBYTE = 0 ;NE_REL_OFFSET = 1 NE_REL_SEGMENT = 2 NE_REL_FARPTR = 3 NE_REL_OFFSET16 = 5 NE_REL_FARPTR48 = 8+NE_REL_FARPTR NE_REL_OFFSET32 = 8+NE_REL_OFFSET16 ; Relocation flags NE_RELFL_INTERNALREF = 0 NE_RELFL_IMPORT_ORDINAL = 1 NE_RELFL_IMPORT_NAME = 2 NE_RELFL_OSFIXUP = 3 NE_RELFL_ADDITIVE = 4 "structures/x16/winuser.inc" - described in 1st post, other includes can be made manualy from fasm ones by cutting structs definitions. Last edited by ProMiNick on 05 Mar 2020, 13:27; edited 1 time in total |
|||
25 Feb 2020, 12:50 |
|
ProMiNick 04 Mar 2020, 23:55
It is done first fasm compiled NE that works on 32bit OSes (tested in Win95, in WinXP, as administrator in Win7) named nedemo.exe
https://yadi.sk/d/f3kzyjRlFrocHQ _________________ I don`t like to refer by "you" to one person. My soul requires acronim "thou" instead. |
|||
04 Mar 2020, 23:55 |
|
ProMiNick 06 Mar 2020, 02:35
NE relocs analizing script:
Code: ; assumption&limitation: section size calculated properly for not huge sections format binary as 'txt' NE_NSRELOC = $0100 source equ 'TEMPLATE.exe' macro dbdec val* { local outv,divider if ~val db '0' else divider = 1 while val>divider divider = divider*10 end while if divider>val divider = divider/10 end if outv=val while outv>=divider & divider db outv/divider+'0' outv=outv mod divider divider = divider/10 end while end if } macro dbhex val*,size:2,prefix:'$' { local x,y db prefix if ~val db '0' else y=val repeat size shl 1 x=(y shr (4*(size shl 1-%))) and $F if x>9 x=x+'A'-'0'-10 end if x=x+'0' db x end repeat end if } ;DOS Header.lfaNEW virtual at 0 file source:$3C,4 load newhdr dword from 0 end virtual ; NE Header virtual at 0 file source:newhdr,$40 load SegCount word from $1C load ModRefCount word from $1E load SegTableOffset word from $22 load ModRefTableOffset word from $28 load ImportNamesTableOffset word from $2A load FileAlnSzShftCnt word from $32 end virtual ;module references virtual at 0 modrefs:: file source:newhdr+ModRefTableOffset,ModRefCount shl 1 end virtual ;import names virtual at 0 importnames:: file source:newhdr+ImportNamesTableOffset end virtual ;prepare relocs virtual at 0 relocs:: end virtual ;segment iteration repeat SegCount db 'segment ' dbdec % db 13,10 virtual at 0 file source:newhdr+SegTableOffset+(%-1)*8,8 ;segment load shiftedSegStart word from 0 load flags word from 4 load SegSize word from 6 end virtual if flags and NE_NSRELOC if ~FileAlnSzShftCnt FileAlnSzShftCnt = 9 end if RelocOffset = shiftedSegStart shl FileAlnSzShftCnt + SegSize ;RelocCount virtual at 0 file source:RelocOffset,2 load RelocCount word from 0 end virtual virtual relocs curOffs = $ file source:RelocOffset+2,RelocCount*8 end virtual repeat RelocCount load x byte from relocs:(%-1)*8+curOffs db 'addrType: ' if x = 1 db 'offset' else if x=2 db 'segment' else if x=3 db 'farptr' else if x=5 db 'deltaoffs' else db x+'0' end if db 13,10 load x byte from relocs:(%-1)*8+1+curOffs db 'Flags: ' U=x and 3 if U = 0 db 'INTERNALREF' else if U=1 db 'IMPORTORDINAL' else if U=2 db 'IMPORTNAME' else if U=3 db 'OSFIXUP' end if if x and 4 db ', ADDITIVE' end if db 13,10 load y word from relocs:(%-1)*8+2+curOffs db 'offset: ' dbhex y db 13,10 load o word from relocs:(%-1)*8+4+curOffs load z word from relocs:(%-1)*8+6+curOffs if U=3 db 'OS fixup type: ' if z=1 db 'FIARQQ, FJARQQ' else if z=2 db 'FISRQQ, FJSRQQ' else if z=3 db 'FICRQQ, FJCRQQ' else if z=4 db 'FIERQQ' else if z=5 db 'FIDRQQ' else if z=6 db 'FIWRQQ' end if else if U=0 if o=$FF db 'EntryTblIdx(Movable seg): ' else db '(SegmentNum:offset): ' dbhex o db ':' end if dbhex z else db 'Library: ' load a word from modrefs:(o-1)*2 load b byte from importnames:a repeat b load c byte from importnames:a+% db c end repeat db 13,10 if U=1 db 'Ordinal: ' dbhex z else db 'FuncName: ' load b byte from importnames:z repeat b load c byte from importnames:z+% db c end repeat end if end if end if db 13,10,13,10 end repeat else db 'not relocated',13,10 end if end repeat weaknest part of algorithm - imports has no size or endmark that makes neeedance to include rest of binary Code: virtual at 0 importnames:: file source:newhdr+ImportNamesTableOffset end virtual |
|||
06 Mar 2020, 02:35 |
|
ProMiNick 07 Mar 2020, 08:35
one more fix of relocs.inc(added forcing of END_RELOOC_CHAIN=-1 value to relocated place):
Code: ; Macroinstructions for making relocations (16-bit) macro reloc [relinfo] { common local rbase rbase = $-2 reverse local current match =constimm8,relinfo \{ rbase = rbase-1 \} match =constimm16,relinfo \{ rbase = rbase-2 \} match =constimm32,relinfo \{ rbase = rbase-4 \} match =far dseg:name,relinfo \{ current = rbase store word -1 at current-2 relocs equ relocs,NE_REL_FARPTR,NE_RELFL_INTERNALREF,current-2,dseg,name rbase = rbase-4 \} match =far48 dseg:name,relinfo \{ current = rbase store dword -1 at current-4 relocs equ relocs,NE_REL_FARPTR48,NE_RELFL_INTERNALREF,current-4,dseg,name rbase = rbase-6 \} match =offs16 dseg:name,relinfo \{ current = rbase store word -1 at current relocs equ relocs,NE_REL_OFFSET16,NE_RELFL_INTERNALREF,current,dseg,name rbase = rbase-2 \} match =offset dseg:name,relinfo \{ current = rbase store dword -1 at current-2 relocs equ relocs,NE_REL_OFFSET32,NE_RELFL_INTERNALREF,current-2,dseg,name rbase = rbase-4 \} match =segment dseg:name,relinfo \{ current = rbase store word -1 at current relocs equ relocs,NE_REL_SEGMENT,NE_RELFL_INTERNALREF,current,dseg,name rbase = rbase-2 \} ;match =lobyte dseg:name,relinfo \{ ; current = rbase ; store byte -1 at current ; relocs equ relocs,NE_REL_LOBYTE,NE_RELFL_INTERNALREF,current,dseg,name ; rbase = rbase-1 \} } macro fixup dummy,[reladdr,reltype,offs,data1,data2] { common local ..relstart,..relcount dw ..relcount ..relstart: if ~reladdr eq forward db reladdr,reltype dw offs,data1,data2 common end if ..relcount = ($-..relstart) shr 3 } second NE example named template functionaly similar to PE template: Code: format binary as 'exe' include 'win16.inc' NEFORMAT entry cseg1:start ;entry start include 'os specific\dos\equates\syscalls.inc' END_RELOC_CHAIN = -1 RETURN_ERROR1 = 1 STACKSLOP = 256 FILE_ALIGNMENT_SHIFT = 4 RSRC_ALIGNMENT_SHIFT = 4 FILE_ALIGNMENT = 1 shl FILE_ALIGNMENT_SHIFT macro align boundary,value:? { db (boundary-1)-($+boundary-1) mod boundary dup value } ;=============================================================================== SegmentTable: repeat segment@count dw 4 dup(0) end repeat ResourceTable: ResidentNamesTable: .Export.1.Str db 6,'module' .Export.1.Ord dw 0 db 0 library krnl386,'KERNEL',\ user,'USER' include 'os specific\windows\api\win16\krnl386.inc' include 'os specific\windows\api\win16\user.inc' EntryTable: .Count db 0 db 0 .End: NonResNamesTable: .1.Str db 4,'none' .1.Ord dw 0 db 0 .End: FastloadAreaStart: ;align $40 segment cseg1 code movable preloaded relocatable DPL(3) db $10 dup (0) ;off_10 dw -1 start: invoke InitTask ; or ax, ax jz .err push di ; hInstance push si ; hPrevInstance pushw es:bx ; lpCmdLine push dx ; nCmdShow mov [wc.hInstance],di reloc offs16 idxof@#dseg1:wc.hInstance invoke WaitEvent, 0 invoke InitApp, [dseg1&wc.hInstance] or ax, ax jz .err invoke LoadIcon,0,IDI_APPLICATION mov [wc.hIcon],ax reloc offs16 idxof@#dseg1:wc.hIcon invoke LoadCursor,0,IDC_ARROW mov [wc.hCursor],ax reloc offs16 idxof@#dseg1:wc.hCursor invoke RegisterClass,far ds:dseg1&wc or ax, ax jz .err invoke CreateWindow,far ds:dseg1&_class,far ds:dseg1&_title,WS_OVERLAPPEDWINDOW shr 16:WS_OVERLAPPEDWINDOW and $FFFF,128,128,256,192,NULL,NULL,[wc.hInstance],NULL:NULL or ax, ax jz .err mov [hwnd],ax reloc offs16 idxof@#dseg1:hwnd invoke ShowWindow,[dseg1&hwnd],dx invoke UpdateWindow,[dseg1&hwnd] .msg_loop: invoke GetMessage,far ds:dseg1&msg,NULL,0,0 cmp ax,1 jb .end_loop jne .msg_loop invoke TranslateMessage,far ds:dseg1&msg invoke DispatchMessage,far ds:dseg1&msg jmp .msg_loop .end_loop: mov al,byte[msg.wParam] reloc offs16 idxof@#dseg1:msg.wParam jmp .exit .err: invoke MessageBox,0,far ds:dseg1&_error,far 0:0,MB_OK mov al,RETURN_ERROR1 .exit: doscall DOS_QUIT_WITH_EXIT_CODE proc16 WindowProc far hwnd,wmsg,wparam,lparam:dword cmp [wmsg],WM_DESTROY je .wmdestroy .defwndproc: invoke DefWindowProc,[hwnd],[wmsg],[wparam],[lparam] jmp .finish .wmdestroy: invoke PostQuitMessage,0 xor ax,ax .finish: ret endp endsegment segment dseg1 data movable preloaded relocatable DPL(3) db $10 dup (0) ; 0Ch dword is trashed by OS _class db 'FASMWIN16',0 _title TCHAR 'Win16 program template',0 _error TCHAR 'Startup failed.',0 wc WNDCLASS 0,WindowProc,0,0,0,NULL,NULL,COLOR_BTNFACE+1,NULL,_class reloc constimm16,far idxof@#cseg1:WindowProc,constimm16,constimm16,constimm16,constimm16,constimm16,constimm16,constimm16,far idxof@#dseg1:_class hwnd dw ? msg MSG endsegment FastloadAreaEnd: It succesfuly recognized as NE and shows message with title "Error" and text "Startup failed." That is a part of template.asm logic that signals that some params passed to RegisterClass or passed to CreateWindow are wrong. [EDITED]: That kind of miracle that 1st NE runned w/o errors & 2nd fragmentary runned. When I tryed to catch where exacly bug happened - NE crashed. That what was initially worked (multiple invoking of the same import) now stoped to work as expected. Code: macro invoke proc,[arg] { ; indirectly call PASCAL procedure common local s$n1 match any,arg \{ forward pushw arg common \} s$n1 = $+1 ; I expect these 3 lines will build reloc chain match ++any,proc#.@current \{ store word (s$n1-proc#.@current) at proc#.@current \} ; it was worked when section wasn`t start new addres space by org, I replaced "at :proc#.@current" with "at proc#.@current" proc#.@current equ ++s$n1 ; but that isn`t helps match :no,proc#.@imported:proc#.@used \{ relocs equ relocs,NE_REL_FARPTR,proc#.%type,proc#.@current,proc#.%libidx,proc \} define proc#.@used call proc-proc:END_RELOC_CHAIN } [EDITED-FIX FOUND]: Code: macro invoke proc,[arg] { ; indirectly call PASCAL procedure common local s$n1 match any,arg \{ forward pushw arg common \} s$n1 = $+1 ; bug found address should be stored as section absolute s$n1, but not relative to address where it is stored (s$n1-proc#.@current) match ++any,proc#.@current \{ store word s$n1 at proc#.@current \} proc#.@current equ ++s$n1 match :no,proc#.@imported:proc#.@used \{ relocs equ relocs,NE_REL_FARPTR,proc#.%type,proc#.@current,proc#.%libidx,proc \} define proc#.@used call proc-proc:END_RELOC_CHAIN } so I catch where logic broken: error after RegisterClass. To be continued... Last edited by ProMiNick on 07 Mar 2020, 11:51; edited 1 time in total |
|||
07 Mar 2020, 08:35 |
|
Tomasz Grysztar 07 Mar 2020, 11:42
Do you think it would be worth it to try converting your framework to fasmg, to get the possibility of automatically generated relocations?
|
|||
07 Mar 2020, 11:42 |
|
ProMiNick 07 Mar 2020, 12:05
Tomasz I going to demonstrate to fasm community win16 subsystem (and NE format I used only as source of such demonstration, NE format itself not my target).
As thou see I making assumptions and testing them to find out NE format limitations & specs. When I finish I think porting NE from fasm to fasmg would be trivial and that could be one of thour video tutorials in real time. And NE is 16|32 format, I skip that it is 32bit too. At current state I even can`t consult anyone about NE format, some things I test, some still hidden from me. And moreover I wish to combine in one package examples with same functionality for different subsystems win16,win32,win64,wince,kol,me32,me64, lnxKDE32,lnxKDE64,lnxMATE32,lnxMATE64,lnxGNOME32,lnxGNOME64,lnxCINNAMON32,lnxCINNAMON64,lnxBUDGIE32,lnxBUDGIE64,lnxLXDE32,lnxLXDE64,lnxXFCE32,lnxXFCE64. in fasmg i will have to canceled of wince. I know no one of linuxes not presented in my package - but it is future target. Because of that realization not in fasmg. |
|||
07 Mar 2020, 12:05 |
|
ProMiNick 11 Mar 2020, 23:18
https://yadi.sk/d/f3kzyjRlFrocHQ updated again.
specific of win16: windows with style 0 are not displayed - I fix that (CS_HREDRAW or CS_VREDRAW)- that makes template demo working. Also I add singleinstance & multyinstance template variants with comment. In NT6+(maybe in all NTs) win16 RegisterClass succeed on already registered class But in win9x legacy behavior: win16 RegisterClass failed on already registered class also ShowWindow & UpdateWindow are optional in win32, but in win16 they must present before message loop. (If thou skip their call win16 process will become unterminatable in win32 environments that will require OS restart) MS can produce win16 NE that successfuly executed in win64! I amazed (this feature still not reproduced). |
|||
11 Mar 2020, 23:18 |
|
ProMiNick 21 Mar 2020, 00:00
fail. win16 NE never executed at win64 environment.
OS loader checks NE version indormation if it fit some conditions than launched application with next properties Path: C:\Windows\SysWOW64\setup16.exe Command line: doublequoted fullpath (with filename & extension) to NE executable than switch -m and than again doublequoted fullpath (with filename & extension) to NE executable Current directory: cloned from NE executable too. |
|||
21 Mar 2020, 00:00 |
|
ProMiNick 24 Mar 2020, 13:59
https://yadi.sk/d/f3kzyjRlFrocHQ updated again.
bugs in reloc chain fixed: Code: macro invoke proc,[arg] { ; indirectly call PASCAL procedure common local s$n1,s$_n1 match any,arg \{ forward pushw arg common \} s$_n1 = $%+1 s$n1 = $+1 ;previously stored relative addres to $+1 that was incorrect, now stored abs addr to $%+1 match ++any,proc#.@current \{ store word (s$n1) at :proc#.@current \} proc#.@current equ ++s$_n1 proc#.@chainstart equ ++s$n1 match :no,proc#.@imported:proc#.@used \{ relocs equ relocs,NE_REL_FARPTR,proc#.%type,proc#.@chainstart,proc#.%libidx,proc \} define proc#.@used call proc-proc:END_RELOC_CHAIN } pushw extended to handle one more case: dword with imm32 value Code: macro simplepushw value { match size[addr],value \{ pushmem size,addr \} match [addr],value \{ pushmem ,addr \} match =far segN&offs,value \{ pushfar segN,offs \} match =addr offs,value \{ pushadr offs \} match =pushw =dword imm32,pushw value \{ push (imm32) shr 16 push (imm32) and $FFFF pushw equ \} match =pushw,pushw \{ push value pushw equ \} } by analogy I am going to add minipad example: (for now w|o menu) Code: ; Simple text editor - fasm example program ; Win9x Single(WinNT Multy) instance example format binary as 'exe' include 'win16.inc' NEFORMAT entry cseg1:start ;entry start include 'os specific\dos\equates\syscalls.inc' END_RELOC_CHAIN = -1 RETURN_ERROR1 = 1 STACKSLOP = 256 FILE_ALIGNMENT_SHIFT = 4 RSRC_ALIGNMENT_SHIFT = 4 FILE_ALIGNMENT = 1 shl FILE_ALIGNMENT_SHIFT IDR_ICON = 17 IDR_MENU = 37 IDM_NEW = 101 IDM_EXIT = 102 IDM_ABOUT = 901 macro align boundary,value:? { db (boundary-1)-($+boundary-1) mod boundary dup value } ;=============================================================================== SegmentTable: repeat segment@count dw 4 dup(0) end repeat ResourceTable: ResidentNamesTable: .Export.1.Str db 6,'module' .Export.1.Ord dw 0 db 0 library krnl386,'KERNEL',\ user,'USER' include 'os specific\windows\api\win16\krnl386.inc' include 'os specific\windows\api\win16\user.inc' EntryTable: .Count db 0 db 0 .End: NonResNamesTable: .1.Str db 4,'none' .1.Ord dw 0 db 0 .End: FastloadAreaStart: ;align $40 segment cseg1 code movable preloaded relocatable DPL(3) db $10 dup (0) ;off_10 dw -1 start: invoke InitTask ; or ax, ax jz .err ;push di ; hInstance ;push si ; hPrevInstance ;pushw es:bx ; lpCmdLine ;push dx ; nCmdShow mov [cmdShow],dx reloc offs16 idxof@#dseg1:cmdShow mov [wc.hInstance],di reloc offs16 idxof@#dseg1:wc.hInstance invoke WaitEvent, 0 invoke InitApp, [dseg1&wc.hInstance] or ax, ax jz .err invoke LoadIcon,0,IDI_APPLICATION mov [wc.hIcon],ax reloc offs16 idxof@#dseg1:wc.hIcon invoke LoadCursor,0,IDC_ARROW mov [wc.hCursor],ax reloc offs16 idxof@#dseg1:wc.hCursor invoke RegisterClass,far ds:dseg1&wc or ax, ax jz .err invoke CreateWindow,far ds:dseg1&_class,far ds:dseg1&_title,dword WS_OVERLAPPEDWINDOW,144,128,256,256,NULL,NULL,[dseg1&wc.hInstance],NULL:NULL or ax, ax jz .err mov [hwnd],ax reloc offs16 idxof@#dseg1:hwnd invoke ShowWindow,[dseg1&hwnd],[dseg1&cmdShow] invoke UpdateWindow,[dseg1&hwnd] .msg_loop: invoke GetMessage,far ds:dseg1&msg,NULL,0,0 cmp ax,1 jb .end_loop jne .msg_loop invoke TranslateMessage,far ds:dseg1&msg invoke DispatchMessage,far ds:dseg1&msg jmp .msg_loop .end_loop: mov al,byte[msg.wParam] reloc offs16 idxof@#dseg1:msg.wParam jmp .exit .err: invoke MessageBox,0,far ds:dseg1&_error,far 0:0,MB_ICONERROR+MB_OK mov al,RETURN_ERROR1 .exit: doscall DOS_QUIT_WITH_EXIT_CODE ret proc16 WindowProc far hwnd,wmsg,wparam,lparam:dword mov ax,[wmsg] cmp ax,WM_CREATE je .wmcreate cmp ax,WM_SIZE je .wmsize cmp ax,WM_SETFOCUS je .wmsetfocus cmp ax,WM_COMMAND je .wmcommand cmp ax,WM_DESTROY je .wmdestroy .defwndproc: invoke DefWindowProc,[hwnd],[wmsg],[wparam],dword [lparam] jmp .finish .wmcreate: invoke GetClientRect,[hwnd],far ds:dseg1&client invoke CreateWindow,far ds:dseg1&_edit,far ds:dseg1&_null,dword WS_VISIBLE+WS_CHILD+WS_BORDER+WS_HSCROLL+WS_VSCROLL+ES_LEFT+ES_AUTOHSCROLL+ES_AUTOVSCROLL+ES_MULTILINE,[dseg1&client.left],[dseg1&client.top],[dseg1&client.right],[dseg1&client.bottom],[hwnd],NULL,[dseg1&wc.hInstance],NULL:NULL or ax,ax jz .failed mov [edithwnd],ax reloc offs16 idxof@#dseg1:edithwnd jmp .finish .failed: or ax,-1 jmp .finish .wmsize: invoke GetClientRect,[hwnd],far ds:dseg1&client invoke MoveWindow,[dseg1&edithwnd],[dseg1&client.left],[dseg1&client.top],[dseg1&client.right],[dseg1&client.bottom],TRUE xor ax,ax jmp .finish .wmsetfocus: ;invoke SetFocus,[dseg1&edithwnd] xor ax,ax jmp .finish .wmcommand: mov ax,[wparam] cmp ax,IDM_NEW je .new cmp ax,IDM_ABOUT je .about cmp ax,IDM_EXIT je .wmdestroy jmp .defwndproc .new: invoke SendMessage,[dseg1&edithwnd],WM_SETTEXT,0,0 jmp .finish .about: invoke MessageBox,[hwnd],far ds:dseg1&_about_text,far ds:dseg1&_about_title,MB_OK jmp .finish .wmdestroy: ;invoke DeleteObject,[dseg1&editfont] invoke PostQuitMessage,0 xor ax,ax .finish: ret endp endsegment segment dseg1 data movable preloaded relocatable DPL(3) db $10 dup (0) ; 0Ch dword is trashed by OS _title TCHAR 'MiniPad',0 _about_title TCHAR 'About MiniPad',0 _about_text TCHAR 'This is Win32 example program created with flat assembler.',0 _error TCHAR 'Startup failed.',0 _class db 'MINIPAD16',0 _edit TCHAR 'EDIT',0 ; BUTTON,LISTBOX,MDICLIENT,RICHEDIT,RICHEDIT_CLASS,SCROLLBAR,STATIC _null TCHAR 0 wc WNDCLASS CS_HREDRAW or CS_VREDRAW,WindowProc,0,0,0,NULL,NULL,COLOR_BTNFACE+1,NULL,_class reloc constimm16,far idxof@#cseg1:WindowProc,constimm16,constimm16,constimm16,constimm16,constimm16,constimm16,constimm16,constimm16,far idxof@#dseg1:_class hwnd dw ? edithwnd dw ? editfont dw ? cmdShow dw ? msg MSG client RECTS endsegment align 16,0 FastloadAreaEnd: If I replace _edit TCHAR 'EDIT' with one of commented values - all OK, but with edit I will got: Code: MODULE caused a General Protection Fault... Any ideas? |
|||
24 Mar 2020, 13:59 |
|
Tomasz Grysztar 24 Mar 2020, 15:24
ProMiNick wrote: If I replace _edit TCHAR 'EDIT' with one of commented values - all OK, but with edit I will got: Code: invoke CreateWindow,far ds:dseg1&_class,far ds:dseg1&_title,dword WS_OVERLAPPEDWINDOW,144,128,256,256,NULL,NULL,[dseg1&wc.hInstance],NULL:NULL or ax, ax jz .err mov [mainhwnd],ax reloc offs16 idxof@#dseg1:mainhwnd invoke GetClientRect,[dseg1&mainhwnd],far ds:dseg1&client invoke CreateWindow,far ds:dseg1&_button,far ds:dseg1&_button,dword WS_CHILD+WS_VISIBLE,[dseg1&client.left],[dseg1&client.top],[dseg1&client.right],[dseg1&client.bottom],[dseg1&mainhwnd],0,[dseg1&wc.hInstance],NULL:NULL or ax,ax jz .err mov [bttnhwnd],ax reloc offs16 idxof@#dseg1:bttnhwnd I'm attaching the screenshot of this tiny success. But, unfortunately, if I try to switch to 'edit' instead of 'button', I get the general protection error, same as you. Perhaps edit control requires more resources of some kind? BTW, I would suggest making these header sets with 8.3 filenames, with Windows 3 in mind. Also, I really think this deserves conversion to fasmg. Adding relocations manually is more error-prone.
|
||||||||||
24 Mar 2020, 15:24 |
|
Tomasz Grysztar 24 Mar 2020, 15:44
I have just realized that I have this old book on my shelf. It does not say anything helpful for this specific problem, but perhaps might be interesting here.
This function prologue has me scratching my head.
|
|||||||||||||||||||
24 Mar 2020, 15:44 |
|
Goto page 1, 2, 3 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.