open-watcom / open-watcom-v2

Open Watcom V2.0 - Source code repository, Wiki, Latest Binary build, Archived builds including all installers for download.
Other
972 stars 159 forks source link

Question: How to produce a binary with exact layout? #674

Closed LowLevelMahn closed 3 years ago

LowLevelMahn commented 3 years ago

i've got some sort of loadable driver/plugin that is used by an old 16Bit DOS program

i disassembled the plugin and im able to build a 100% binary equal version of the driver based on my assembler code

now i want to port that thing over to C code - but i have no idea how to fullfill the exact code location constraints

contraints: -jump table needs to be at offset 0 -each table entry needs to be far callable and at a descent offset -all variables needs to adressed by cs-Register

problems: -how to locate the jump table -how to get my vars cs-register addresseable -how to prevent runtime linking

thanks for any ideas

;----------------------------------------
; Realmode, 16Bit
; some sort of loadable library binary image with no entry point 
; but a 2 functions jump-table starting at offset 0
;
; this drv file gets dynamically loaded into its own segment
;
; all data is addressed by the CS-Register
;
; how to build:
;
; assembler: current ML (for example from VS2019) or UASM (http://www.terraspace.co.uk/uasm.html)
; linker: UniLinker (ftp://ftp.styx.cabel.net/pub/UniLink/ulnb1155.zip) (or later)
;
; assemble:
;   ml.exe /c /omf drv.asm
;   or
;   uasm64.exe drv.asm
; link:
;   ulink.exe -T16 -Tbi drv.obj, drv.drv
;----------------------------------------

seg000    segment byte public 'CODE' USE16
    org 0
    assume cs:seg000
    assume es:nothing, ss:nothing, ds:nothing

;----------------------------------------
; no entry point:
; there is no fixed first code to run and no (exe or whatever) header to put in the entry point address

; needed for UniLinker
; i can't find an option that allows to create an no-entry-point binary image (-e- does not work with DOS applications)
dummy_entry_point:
;----------------------------------------

;----------------------------------------
; jump table with 2 functions (far called by the drv loading program)
; "interface" of the driver
;----------------------------------------
    jmp near ptr tsub0
; ---------------------------------------------------------------------------
    jmp near ptr tsub1
; ---------------------------------------------------------------------------

; data

value1    db 0
value2    dw 0

; internal functions

isub0   proc near
    mov cs:value1, 123
    retn
isub0   endp

isub1   proc near
    mov cs:value2, 321
    retn
isub1   endp

; interface implementation

tsub0   proc far
    call isub0
    retf
tsub0   endp

tsub1   proc far
    call isub1
    retf
tsub1   endp

seg000    ends

end dummy_entry_point
jmalak commented 3 years ago

I am not sure if it is good idea. OW C code relate to C run-time library (for some support routines as minimum). The references to C run-time library depend on code if it call something what need it. Generaly it relates to C run-time initial code, you can remove such references by -zl and -zls compiler options.

Below is sample how you can declare variables in code. extern unsigned __based( __segname("_CODE") ) __OVLFILEPREV__; Or you can define it by unsigned __based( __segname("_CODE") ) __OVLFILEPREV__;

If you need something on begining of code than you can use something as following as first in source file. const char __based( __segname( "_CODE" ) ) Signature[4] = "DIP";

jmalak commented 3 years ago

You can link it as binary file which start on offset 0.

LowLevelMahn commented 3 years ago

Thanks for the tips - the Variables in CODE-Segment is perfect, and i don't need anything from the Standardlibs so skipping is ok

LowLevelMahn commented 3 years ago

Got working - thanks for your help - now i've got a small asm stub for the jump table and a little bit C/C++ with "based( segname( "_CODE" ) )" - perfect solution, your watcom tools are just briliant for reverse engineering/porting old stuff

jmalak commented 3 years ago

You are lucky, probably you use only int/unsigned int types or narrow types that you don't need wider 32/64-bit arithmetic. Anyway you could be able define jump tables in C. You need to put it in some module and ensure that linker put it on the beginning of binary image. It can be achieved by order of linked modules or by using multiple segments and their order. OW linker can group segment together even if they use different segment name. There are -n... compilers options which can define segment names for each module. OW linker can also organized segments by their explicit offset in output image.

LowLevelMahn commented 3 years ago

You are lucky, probably you use only int/unsigned int types or narrow types that you don't need wider 32/64-bit arithmetic.

im reversing 186 code - so years away from 32bit and eons away from 64bit

Anyway you could be able define jump tables in C.

im going with the asm stub because the jump-table needs to contain near jumps of 3 bytes size per entry - that could be hard to archive with C

jmalak commented 3 years ago

you can use array of jmp near structures with instruction byte and relative offset. You can simplify it by some macro.