flat assembler
Message board for the users of flat assembler.

Index > Windows > [solved]:playing with 16bit winincludes

Goto page 1, 2, 3  Next
Author
Thread Post new topic Reply to topic
ProMiNick



Joined: 24 Mar 2012
Posts: 798
Location: Russian Federation, Sochi
ProMiNick 24 Jan 2020, 07:05
by analogy to 32/64 winuser.inc(structures):
Code:
; USER.DLL structures

struct WNDCLASS
  style         dw ?
  lpfnWndProc   dd ?
  cbClsExtra    dw ?
  cbWndExtra    dw ?
  hInstance     dw ?
  hIcon         dw ?
  hCursor       dw ?
  hbrBackground dw ?
  lpszMenuName  dd ?
  lpszClassName dd ?
ends

struct CREATESTRUCT
  lpCreateParams dd ?
  hInstance      dw ?
  hMenu          dw ?
  hwndParent     dw ?
  cy             dw ?
  cx             dw ?
  y              dw ?
  x              dw ?
  style          dd ?
  lpszName       dd ?
  lpszClass      dd ?
  dwExStyle      dd ?
ends

struct CLIENTCREATESTRUCT
  hWindowMenu  dw ?
  idFirstChild dw ?
ends

struct MDICREATESTRUCT
  szClass dd ?
  szTitle dd ?
  hOwner  dw ?
  x       dw ?
  y       dw ?
  cx      dw ?
  cy      dw ?
  style   dd ?
  lParam  dd ?
ends

struct MSG
  hwnd    dw ?
  message dw ?
  wParam  dw ?
  lParam  dd ?
  time    dd ?
  pt      POINTS
ends

struct MINMAXINFO
  ptReserved     POINTS
  ptMaxSize      POINTS
  ptMaxPosition  POINTS
  ptMinTrackSize POINTS
  ptMaxTrackSize POINTS
ends

struct WINDOWPLACEMENT
  length           dw ?
  flags            dw ?
  showCmd          dw ?
  ptMinPosition    POINTS
  ptMaxPosition    POINTS
  rcNormalPosition RECTS
ends

struct WINDOWPOS
  hwnd            dw ?
  hwndInsertAfter dw ?
  x               dw ?
  y               dw ?
  cx              dw ?
  cy              dw ?
  flags           dw ?
ends

struct PAINTSTRUCT
  hdc         dw ?
  fErase      dw ?
  rcPaint     RECTS
  fRestore    dw ?
  fIncUpdate  dw ?
  rgbReserved db 16 dup (?)
ends

struct DRAWITEMSTRUCT
  CtlType    dw ?
  CtlID      dw ?
  itemID     dw ?
  itemAction dw ?
  itemState  dw ?
  hwndItem   dw ?
  hDC        dw ?
  rcItem     RECTS
  itemData   dd ?
ends

struct MEASUREITEMSTRUCT
  CtlType    dw ?
  CtlID      dw ?
  itemID     dw ?
  itemWidth  dw ?
  itemHeight dw ?
  itemData   dd ?
ends    


proc16.inc by analogy to proc32.inc/proc64.inc (it is still pretty raw, I suppose not everything convinient):
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 esp,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 esp,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 esp,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 esp,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 }    


win16w.inc by analogy to win32w.inc/win64w.inc:
Code:
; Win16 programming headers (WideChar)

datadef@directives equ db,dw,du,dd,dp,dq,dt
datarsv@directives equ rb,rw,rd,rp,rq,rt
algnmnt@directives equ
def.rb equ db
def.rw equ dw
def.rd equ dd
def.rp equ dp
def.rq equ dq
def.rt equ dt
db.align = 1
dw.align = 2
du.align = 2
dd.align = 4
dq.align = 8

sizeof.PTR =2
sizeof.FARPTR =2
struc PTR [value:?] { common . dw value }
struc FARPTR [value:?] { common . dd value }
macro PTR [value:?] { common dw value }
macro FARPTR [value:?] { common dd value }

;====== fundamental macros ======================
include 'generic/macro/struct.inc'
include 'generic/macro/interface.inc'
include 'generic/macro/guid.inc'
;====== OS specific macros ======================
include 'os specific/windows/macro/x86/proc16.inc'
;include 'os specific/windows/macro/x86/com32.inc'
;====== file format specific macros =============
;include 'file formats/pe coff/macro/import32.inc'
;include 'file formats/pe coff/macro/export.inc'
;include 'file formats/pe coff/macro/resource.inc'
;include 'file formats/pe coff/equates/imagebase.inc'
include 'file formats/pe coff/equates/resource.inc'

struc TCHAR [val:?] { common . du val }
sizeof.TCHAR = 2
struc ACHAR [val:?] { common . db val }
sizeof.ACHAR = 1
struc WCHAR [val:?] { common . du val }
sizeof.WCHAR = 2

;====== fundamental equates =====================
include 'generic/equates/fundamental.inc'
;====== OS specific equates =====================
include 'os specific/windows/equates/windef.inc'
include 'os specific/windows/equates/winver.inc'
include 'os specific/windows/equates/winbase.inc'
include 'os specific/windows/equates/wingdi.inc'
include 'os specific/windows/equates/winuser.inc' ; winuser - next level of abstraction after wingdi
include 'os specific/windows/equates/comctl.inc'
include 'os specific/windows/equates/comdlg.inc'
include 'os specific/windows/equates/shell.inc'
include 'os specific/windows/equates/winsock2.inc'
;====== Internet technology equates =============
include 'technologies/internet/equates/socket.inc'
include 'technologies/internet/equates/ipproto.inc'
;====== COM technology equates ==================
include 'os specific/windows/equates/com.inc'
include 'os specific/windows/equates/shobjidl_core.inc'

;====== fundamental structures ==================
include 'generic/structures/coordinates.inc'
;====== OS specific structures ==================
;include 'os specific/windows/structures/windef.inc'
;include 'os specific/windows/structures/x32/ntdef.inc'
;include 'os specific/windows/structures/x32/sysinfo.inc'
;include 'os specific/windows/structures/x32/processthreads.inc'
;include 'os specific/windows/structures/x32/synch.inc'
;include 'os specific/windows/structures/x32/winbase.inc'
;include 'os specific/windows/structures/x32/winternl.inc'
;include 'os specific/windows/structures/x32/wingdi.inc'
include 'os specific/windows/structures/x16/winuser.inc'
;include 'os specific/windows/structures/x32/comctl.inc'
;include 'os specific/windows/structures/x32/comdlg.inc'
;include 'os specific/windows/structures/x32/shell.inc'
;include 'os specific/windows/structures/x32/winsock2.inc'
;====== COM technology structures ===============
;include 'os specific/windows/structures/x32/objidl.inc'
;include 'os specific/windows/structures/x32/shobjidl_core.inc'

;====== COM technology interfaces ===============
;include 'os specific/windows/interfaces/iunknwn.inc'
;include 'os specific/windows/interfaces/objidl.inc'
;include 'os specific/windows/interfaces/shobjidl_core.inc'

;macro api [name] { if used name
;                    label name dword at name#W
;                   end if }
    


test itself (chosen format NE)
because of that:
Code:
include 'file formats\ne\equates\flags.inc'    
(InProcess - missed consts for making relocs) - it content here too:
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    


because fasm dont support NE natively build it in style as it done in file format tutorials but in fasm syntax, not fasmg
Code:
format binary as 'exe'

include 'win16a.inc'
include 'file formats\ne\equates\flags.inc'

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 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.

SIZE_OF_STUB = $ - stub

align 8
align $80

Header:
        .Signature                      dw "NE",0
        .MajorLinkerVersion             db 0
        .MinorLinkerVersion             db 0
        .EntryTable                     dw EntryTable-Header
        .SizeOfEntryTable               dw ?
        .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 ?
        .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 ?
        .FileAlnSzShftCnt               dw FILE_ALIGNMENT_SHIFT
        .nResTableEntries               dw 6
        .TargetOS                       db NE_WINDOWS
        .OS2EXEFlags                    db NE_GANGL
        .RetThunksOffset:
        .GangloadStart                  dw GangloadStart
        .SegRefThunksOffset:
        .GangloadSize                   dw ?
        .MinCodeSwap                    dw ?
        .MinorOperatingSystemVersion    db 10
        .MajorOperatingSystemVersion    db 3

SegmentTable:

        .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:

        .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 (1 shl RSRC_ALIGNMENT_SHIFT)
        .1.NameInfo.1.rnLength          dw (rsrc.1.End - rsrc.1) shr (1 shl 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 (1 shl RSRC_ALIGNMENT_SHIFT)
        .2.NameInfo.1.rnLength          dw (rsrc.2.End - rsrc.2) shr (1 shl 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 (1 shl RSRC_ALIGNMENT_SHIFT)
        .2.NameInfo.2.rnLength          dw (rsrc.3.End - rsrc.3) shr (1 shl 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 (1 shl RSRC_ALIGNMENT_SHIFT)
        .3.NameInfo.1.rnLength          dw (rsrc.4.End - rsrc.4) shr (1 shl RSRC_ALIGNMENT_SHIFT)
        .3.NameInfo.1.rnFlags           dw NE_NSMOVE or NE_NSPRELOAD 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_STRING
        .4.Count                        dw 2
        .4.Reserved                     dd 0
        .4.NameInfo:

        .4.NameInfo.1.rnOffset          dw rsrc.5 shr (1 shl RSRC_ALIGNMENT_SHIFT)
        .4.NameInfo.1.rnLength          dw (rsrc.5.End - rsrc.5) shr (1 shl 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 (1 shl RSRC_ALIGNMENT_SHIFT)
        .4.NameInfo.2.rnLength          dw (rsrc.6.End - rsrc.6) shr (1 shl 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:

        .Export.1.Str                   db 8,'BOOTSTRP'
        .Export.1.Ord                   dw 0

        .Export.2.Str                   db 8,'___EXPORTEDSTUB'
        .Export.2.Ord                   dw 2

                                        db 0

ModRefTable:
        .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:
                                        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:

        .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

NonResNamesTable:

        .1.Str                          db 15,'MS-Setup Loader'
        .1.Ord                          dw 0

        .2.Str                          db 11,'BOOTWNDPROC'
        .2.Ord                          dw 1

                                        db 0

align $40
Segment.1: ; CODE MOVEABLE PRELOADED RELOCATED DPL:3
org 0

                db $10 dup (0)
        off_10   dw __WINFLAGS
error:
        mov     al,-1
    x16 stdcall 0:__exit,ax

proc16 start
        xor     bp, bp
        push    bp
    x16 stdcall $11CC:INITTASK
        or      ax, ax
        jz      error
        mov     [word_CA58], es
        add     cx, $100
        jb      error
        mov     [word_C8F6], cx
        mov     [word_C8F8], si
        mov     [word_C8FA], di
        mov     [word_C8FC], bx
        mov     [word_C8FE], es
        mov     [word_C900], dx
        mov     ax, -1
    x16 stdcall $11CC:LOCKSEGMENT,ax
    x16 stdcall $11CC:GETVERSION
        xchg    al, ah
        mov     [word_CA5A], ax
        mov     ah, $30
        test    [cs:off_10], 1
        jz      short .loc_6D
        call    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 $11CC:WAITEVENT,ax
    x16 stdcall $11CC:INITAPP,[word_C8FA]
        or      ax, ax
        jnz     short .loc_9D
        jmp     error
  .loc_9D:
        call    0:__cinit
        call    0:__setargv
        call    0:__setenvp
        call    __wcinit
    x16 ccall   0:__stubmain,[word_CA92],[word_CA94],[word_CA96],[word_CA98],[word_CA9A]
    x16 stdcall 0:__exit,ax
endp
__exit:
__WINFLAGS:
INITTASK:
LOCKSEGMENT:
GETVERSION:
DOS3CALL:
WAITEVENT:
INITAPP:
WINMAIN:
__setargv:
__setenvp:
__wcinit:
proc16 __stubmain farcall,arg0,arg1,arg2,arg3,arg4
        mov     ax, ds
        push    ds
    x16 stdcall 0:WINMAIN,[word_C900],[word_C8FC],[word_C8FE],[word_C8F8],[word_C8FA]
        pop     ds
        ret
endp

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
        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:











endp

Segment.1.End:

Segment.2:
word_C8F6:
word_C8F8:
word_C8FA:
word_C8FC:
word_C8FE:
word_C900:
dword_CA44:
word_CA58:
word_CA5A:;OSVERSION
word_CA5E:
word_CA5C:
byte_CA61:
word_CA92:
word_CA94:
word_CA96:
word_CA98:
word_CA9A:
Segment.2.End:

GangloadStart:

rsrc.1:
rsrc.1.End:

rsrc.2:
rsrc.2.End:

rsrc.3:
rsrc.3.End:

rsrc.4:
rsrc.4.End:

rsrc.5:
rsrc.5.End:

rsrc.6:
rsrc.6.End:    


For now it is unworked dummy, I using NE format donor to reproduce aspects of NE in fasm syntax (donor payload I wish to replace with hello world window because register class & window creation in donor present but there are many other unneeded for example things).

Topic has no practical sense (NE is obsolete - I just tryed to make set of 16 bit includes in addition to 32/64bit ones).

_________________
I don`t like to refer by "you" to one person.
My soul requires acronim "thou" instead.


Last edited by ProMiNick on 05 Mar 2020, 13:06; edited 3 times in total
Post 24 Jan 2020, 07:05
View user's profile Send private message Send e-mail Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8351
Location: Kraków, Poland
Tomasz Grysztar 24 Jan 2020, 09:52
Amazing! I never thought that I would see an NE framework done in fasm 1 before fasmg. Smile 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. Wink
Post 24 Jan 2020, 09:52
View user's profile Send private message Visit poster's website Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 798
Location: Russian Federation, Sochi
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.
Post 30 Jan 2020, 22:03
View user's profile Send private message Send e-mail Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8351
Location: Kraków, Poland
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?)
Perhaps this might help?
Post 31 Jan 2020, 07:17
View user's profile Send private message Visit poster's website Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 798
Location: Russian Federation, Sochi
ProMiNick 31 Jan 2020, 08:41
Thanks, looks helpful.
Post 31 Jan 2020, 08:41
View user's profile Send private message Send e-mail Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 798
Location: Russian Federation, Sochi
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    
Post 06 Feb 2020, 01:27
View user's profile Send private message Send e-mail Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 798
Location: Russian Federation, Sochi
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     
Post 15 Feb 2020, 11:54
View user's profile Send private message Send e-mail Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 798
Location: Russian Federation, Sochi
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 . . .    
Post 24 Feb 2020, 21:57
View user's profile Send private message Send e-mail Reply with quote
alexfru



Joined: 23 Mar 2014
Posts: 80
alexfru 25 Feb 2020, 10:00
ProMiNick wrote:
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.

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:

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 . . .    


I don't see that one.

ProMiNick wrote:

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 . . .    

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.
Post 25 Feb 2020, 10:00
View user's profile Send private message Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 798
Location: Russian Federation, Sochi
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,valueNeutral \{
                match |,post \\{ simplepushw value \\}
                match restNeutral,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
Post 25 Feb 2020, 12:50
View user's profile Send private message Send e-mail Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 798
Location: Russian Federation, Sochi
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.
Post 04 Mar 2020, 23:55
View user's profile Send private message Send e-mail Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 798
Location: Russian Federation, Sochi
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    
Post 06 Mar 2020, 02:35
View user's profile Send private message Send e-mail Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 798
Location: Russian Federation, Sochi
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
Post 07 Mar 2020, 08:35
View user's profile Send private message Send e-mail Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8351
Location: Kraków, Poland
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?
Post 07 Mar 2020, 11:42
View user's profile Send private message Visit poster's website Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 798
Location: Russian Federation, Sochi
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.
Post 07 Mar 2020, 12:05
View user's profile Send private message Send e-mail Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 798
Location: Russian Federation, Sochi
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).
Post 11 Mar 2020, 23:18
View user's profile Send private message Send e-mail Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 798
Location: Russian Federation, Sochi
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.
Post 21 Mar 2020, 00:00
View user's profile Send private message Send e-mail Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 798
Location: Russian Federation, Sochi
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?
Post 24 Mar 2020, 13:59
View user's profile Send private message Send e-mail Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8351
Location: Kraków, Poland
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:
MODULE caused a General Protection Fault...    

Any ideas?
Interesting... I tried playing with it on my Windows 3.11, and I managed to create a button as a child, although only when I create it together with the main window:
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
    
When I try to use the same code to create child in WM_CREATE, it fails for some reason.
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.


Description: Button under 16-bit Windows
Filesize: 14.77 KB
Viewed: 21707 Time(s)

win16.png


Post 24 Mar 2020, 15:24
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8351
Location: Kraków, Poland
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.


Description:
Filesize: 308.31 KB
Viewed: 21700 Time(s)

winasm1.jpg


Description:
Filesize: 315.06 KB
Viewed: 21700 Time(s)

winasm2.jpg


Post 24 Mar 2020, 15:44
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2, 3  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.