diff --git a/History.txt b/History.txt index 4c725ce..2613dfa 100644 --- a/History.txt +++ b/History.txt @@ -12,10 +12,20 @@ model is flat; see tiny3.asm. - default fastcall for 32-bit (MS style) caused a GPF for non-proc symbols; see fastcms.asm. + - listing: when segment directive created a list entry, the offset size + may have been wrong. + - omf format: externdef may have caused a PUBDEF record to be written + in pass 2, resulting in an invalid object module. + - invoke directive: if cpu was 8086, and the argument was a constant 0, + a wrong value may have been pushed; see invoke56.asm. + Other changes: - output format -djgpp: support added for 16-bit offset fixups. - in listings, for directives, offset of 16-bit segments displayed with width 4. + - OWDOS32.mak added. Creates a 32-bit version that uses the native Open + Watcom runtime for extended DOS. Open Watcom 2.0 is recommended to + create this variant. 25.03.2023, v2.17: diff --git a/Html/Readme.html b/Html/Readme.html index f774317..b7240e6 100644 --- a/Html/Readme.html +++ b/Html/Readme.html @@ -26,7 +26,7 @@ PE -pe Win32/Win64 PE binary format ELF32 -elf Linux 32-bit object format ELF64 -elf64 Linux 64-bit object format - DJGPP -djgpp Djgpp's 32-bit COFF variant (optional). + DJGPP -djgpp Djgpp's 32-bit COFF variant JWasm is distributed in several packages. Besides the source package there are some which contain precompiled binaries for Windows, DOS and @@ -122,7 +122,8 @@ name tool chain used creates binary for --------------------------------------------------------------- - OWWin32.mak Open Watcom v1.8-v1.9 Win32 [, DOS (32-bit)] + OWWin32.mak Open Watcom v1.8-v2.0 Win32 [, DOS (32-bit)] + OWDOS32.mak Open Watcom v2.0 DOS (32-bit) OWDOS16.mak Open Watcom v1.8-v1.9 DOS (16-bit) OWOS2.mak Open Watcom v1.8-v1.9 OS/2 (32-bit) OWLinux.mak Open Watcom v1.8-v1.9 Linux diff --git a/OWDOS32.mak b/OWDOS32.mak new file mode 100644 index 0000000..262b268 --- /dev/null +++ b/OWDOS32.mak @@ -0,0 +1,131 @@ + +# this makefile in OW WMake style creates JWasmd.EXE (DOS32). +# unlike the DOS version created with OWWin32.mak, which uses +# a statically linked Win32 emulation layer, this creates +# a DOS version that uses the native OW DOS32 support. Besides +# a noticeable size reduction there isn't much gained, though. +# Tools used: +# - Open Watcom v2.0 +# - jwlink ( OW's wlink might also be used ) +# - HXDev ( for modules cstrtdhr.obj and loadpe.bin ) +# +# "WMake debug=1" - creates a debug version. +# +# Note that OW 1.9 has severe bugs concerning its LFN support! + +name = JWasm + +# Open Watcom root directory +!ifndef WATCOM +WATCOM = \ow20 +!endif +# HXDIR must contain the HX root directory +!ifndef HXDIR +HXDIR = \HX +!endif + +NOGBL = 1 + +!ifndef DEBUG +DEBUG=0 +!endif +!ifndef DJGPP +DJGPP=1 +!endif + +# to track memory leaks, the Open Watcom TRMEM module can be included. +# it's useful only if FASTMEM=0 is set, though, otherwise most allocs +# won't use the C heap. +!ifndef TRMEM +TRMEM=0 +!endif + +!ifndef OUTD +!if $(DEBUG) +OUTD=Build\OWDOS32D +!else +OUTD=Build\OWDOS32R +!endif +!endif + +inc_dirs = -Isrc\H -I$(WATCOM)\H +c_flags = -q -bc -bt=dos -3r -fpi87 -wcd=115 -D__WATCOM_LFN__ + +LINK = jwlink.exe + +#cflags stuff +######### +extra_c_flags = +!if $(DEBUG) +extra_c_flags += -od -d2 -w3 -hc -DDEBUG_OUT +!else +#extra_c_flags += -obmilrt -s -DNDEBUG +extra_c_flags += -oxa -s -DNDEBUG +!endif + +!if $(TRMEM) +extra_c_flags += -of -DTRMEM -DFASTMEM=0 +!endif +!if !$(DJGPP) +extra_c_flags += -DDJGPP_SUPPORT=0 +!endif +######### + +!if $(DEBUG) +LOPTD = debug c op cvp, symfile +!else +LOPTD = +!endif + +CC=$(WATCOM)\binnt\wcc386 $(c_flags) $(inc_dirs) $(extra_c_flags) -fo$@ +LIB=$(WATCOM)\binnt\wlib + +{src}.c{$(OUTD)}.obj: + $(CC) $< + +proj_obj = & +!include owmod.inc + +!if $(TRMEM) +proj_obj += $(OUTD)/trmem.obj +!endif + +TARGET1=$(OUTD)/$(name)d.exe + +ALL: $(OUTD) $(TARGET1) + +$(OUTD): + @if not exist $(OUTD) mkdir $(OUTD) + +$(OUTD)/$(name)d.exe: $(OUTD)/main.obj $(proj_obj) + $(LINK) @<< +$(LOPTD) +format windows pe hx runtime console +file { $(OUTD)/main.obj $(proj_obj) } +name $@ +Libpath $(WATCOM)\lib386\dos;$(WATCOM)\lib386 +Libfile cstrtdhr.obj, inirmlfn.obj +op quiet, stack=0x10000, heapsize=0x1000, map=$^*, stub=loadpero.bin +disable 171 +!ifndef NOGBL +sort global +!endif +op statics +!ifndef WLINK +segment CONST readonly +segment CONST2 readonly +!endif +<< + +$(OUTD)/msgtext.obj: src/msgtext.c src/H/msgdef.h src/H/globals.h + $(CC) src\msgtext.c + +$(OUTD)/reswords.obj: src/reswords.c src/H/instruct.h src/H/special.h src/H/directve.h src/H/opndcls.h src/H/instravx.h + $(CC) src\reswords.c + +###### + +clean: .SYMBOLIC + @if exist $(OUTD)\$(name).exe erase $(OUTD)\$(name).exe + @if exist $(OUTD)\$(name).map erase $(OUTD)\$(name).map + @if exist $(OUTD)\*.obj erase $(OUTD)\*.obj diff --git a/OWWin32.mak b/OWWin32.mak index e4e6c27..4d65aa8 100644 --- a/OWWin32.mak +++ b/OWWin32.mak @@ -77,8 +77,8 @@ extra_c_flags += -oxa -s -DNDEBUG !if $(TRMEM) extra_c_flags += -of -DTRMEM -DFASTMEM=0 !endif -!if $(DJGPP) -extra_c_flags += -DDJGPP_SUPPORT=1 +!if !$(DJGPP) +extra_c_flags += -DDJGPP_SUPPORT=0 !endif ######### diff --git a/src/H/globals.h b/src/H/globals.h index 046554d..5910f3a 100644 --- a/src/H/globals.h +++ b/src/H/globals.h @@ -103,7 +103,7 @@ char *strupr(char *); #define COFF_SUPPORT 1 /* support COFF output format */ #endif #ifndef DJGPP_SUPPORT -#define DJGPP_SUPPORT 0 /* support for Djgpp COFF variant */ +#define DJGPP_SUPPORT 1 /* support for Djgpp COFF variant; NOP if COFF isn't active */ #endif #ifndef ELF_SUPPORT #define ELF_SUPPORT 1 /* support ELF output format */ diff --git a/src/extern.c b/src/extern.c index 54cdb44..5622add 100644 --- a/src/extern.c +++ b/src/extern.c @@ -352,6 +352,21 @@ ret_code ExterndefDirective( int i, struct asm_tok tokenarray[] ) */ if ( langtype != LANG_NONE && sym->langtype != langtype ) EmitWarn( 3, LANGUAGE_ATTRIBUTE_CONFLICT, sym->name ); + +#if 1 + /* v2.18: code moved from below to this place + * this covers the case where the externdef is located BEHIND + * the label that is to become public. + * It's still a bit doubtful for PROCs, because the PROC directive + * should know better about the visibility status of the procedure. + * So if the PROC has been explicitely marked as private, the + * externdef doesn't care. But that's what masm (6/8) does... + */ + if ( sym->state == SYM_INTERNAL && sym->ispublic == FALSE ) { + sym->ispublic = TRUE; + AddPublicData( sym ); + } +#endif } sym->isdefined = TRUE; @@ -364,7 +379,19 @@ ret_code ExterndefDirective( int i, struct asm_tok tokenarray[] ) DebugMsg1(("ExterndefDirective(%s): writing a global entry\n", sym->name)); QAddItem( &ModuleInfo.g.GlobalQueue, sym ); } -#else +#endif +#if 0 + /* v2.18: removed, because it's a bug. + * 1. adding a public after pass one is something that should NOT be done. + * If output format is OMF, the publics are written after pass one and then + * again when all is finished. If the number of publics differ for the second + * write, the object module may become invalid! + * 2. if FASTPASS is on, there's a good chance that the EXTERNDEF directive + * code won't run after pass one - if the FASTPASS's line store feature hasn't + * been triggered yet ( that is, no code or data definition BEFORE the EXTERNDEF ). + * 3. the EXTERNDEF directive running in pass 2 surely cannot know better than + * the PROC directive what the visibility status of the procedure is supposed to be. + */ if ( sym->state == SYM_INTERNAL && sym->ispublic == FALSE ) { sym->ispublic = TRUE; AddPublicData( sym ); @@ -846,6 +873,16 @@ ret_code CommDirective( int i, struct asm_tok tokenarray[] ) return( NOT_ERROR ); } +/* add a symbol into the Publics queue. + * called by: + * - EXTERNDEF (if symbol is internal and public=0) - this cannot happen in pass 1 + * ( and it's a very questionable thing!) + * - PUBLIC ( this usually happens in pass 1 ) + * - END ( if the label hasn't been marked as public ) + * - PROC + * - sym_ext2int() in parser.c, for public data, constants, labels ( not PROCs ) + */ + void AddPublicData( struct asym *sym ) /************************************/ { diff --git a/src/fixup.c b/src/fixup.c index f51f908..4512b27 100644 --- a/src/fixup.c +++ b/src/fixup.c @@ -289,7 +289,7 @@ void store_fixup( struct fixup *fixup, struct dsym *seg, int_32 *pdata ) #endif } #endif -#if DJGPP_SUPPORT +#if COFF_SUPPORT && DJGPP_SUPPORT /* Djgpp's COFF variant needs special handling for * - at least - relative and direct 32-bit offsets. * v2.18: support for 16-bit offsets (FIX_OFF16) added diff --git a/src/invoke.c b/src/invoke.c index e082b44..52e36f6 100644 --- a/src/invoke.c +++ b/src/invoke.c @@ -1450,6 +1450,7 @@ static int PushInvokeParam( int i, struct asm_tok tokenarray[], struct dsym *pro case 2: if ( opnd.value != 0 || opnd.kind == EXPR_ADDR ) { AddLineQueueX( " mov %r, %s", T_AX, fullparam ); + *r0flags &= ~(R0_H_CLEARED | R0_X_CLEARED); /* 2.18: added; see invoke56.asm */ } else { if ( !(*r0flags & R0_X_CLEARED ) ) { AddLineQueueX( " xor %r, %r", T_AX, T_AX ); diff --git a/src/omf.c b/src/omf.c index 5bdc373..7744442 100644 --- a/src/omf.c +++ b/src/omf.c @@ -153,7 +153,7 @@ static void omf_InitRec( struct omf_rec *obj, uint_8 command ) obj->data = NULL; obj->command = command; obj->is_32 = 0; - DebugMsg1(("omf_InitRec(%p, %X)\n", obj, command )); + DebugMsg1(("omf_InitRec(%X)\n", command )); return; } @@ -1370,6 +1370,7 @@ static void omf_write_alias( void ) * - name[] * - offset ( 2/4 bytes ) * - type ( index field, here always 0 ) + * PUBDEFs are written after pass 1 and finally ( when the offsets are known ). */ static ret_code omf_write_pubdef( void ) /**************************************/ @@ -1461,6 +1462,7 @@ static ret_code omf_write_pubdef( void ) } *data++ = 0; /* type field */ size = (char *)data - StringBufferEnd; + DebugMsg1(("omf_write_pub(%s)\n", sym->name )); } if ( size ) { struct omf_rec obj; @@ -1475,6 +1477,7 @@ static ret_code omf_write_pubdef( void ) obj.d.pubdef.base.grp_idx = omf_GetGrpIdx( GetGroup( curr_seg ) ); } obj.d.pubdef.base.frame = 0; + DebugMsg1(("omf_write_pub: is_32=%u, size=%u\n", obj.is_32, size)); omf_write_record( &obj ); } } diff --git a/src/proc.c b/src/proc.c index a7339bf..fdb66e7 100644 --- a/src/proc.c +++ b/src/proc.c @@ -1079,8 +1079,16 @@ ret_code ParseProc( struct dsym *proc, int i, struct asm_tok tokenarray[], bool newofssize = (( Ofssize != USE_EMPTY ) ? Ofssize : ModuleInfo.Ofssize ); i++; } else { - newmemtype = ( ( SIZE_CODEPTR & ( 1 << ModuleInfo.model ) ) ? MT_FAR : MT_NEAR ); - newofssize = ModuleInfo.Ofssize; + /* v2.18: if PROTO/EXTERNDEF is behind the PROC directive, + * ignore module's ofssize or distance. + */ + if (IsPROC == FALSE && proc->sym.state == SYM_INTERNAL && proc->sym.isproc == TRUE ) { + newmemtype = proc->sym.mem_type; + newofssize = proc->sym.seg_ofssize; + } else { + newmemtype = ( ( SIZE_CODEPTR & ( 1 << ModuleInfo.model ) ) ? MT_FAR : MT_NEAR ); + newofssize = ModuleInfo.Ofssize; + } } /* v2.11: GetSymOfssize() cannot handle SYM_TYPE correctly */ @@ -1532,6 +1540,20 @@ ret_code ProcDir( int i, struct asm_tok tokenarray[] ) if ( CurrProc->e.procinfo->paralist && GetRegNo( CurrProc->e.procinfo->basereg ) == 4 ) CurrProc->e.procinfo->fpo = TRUE; #endif + /* add item to the PUBLIC queue. + * this is done when + * a) OPTION PROC:PRIVATE is set: + * Masm6: PROC must be marked as PUBLIC, EXTERNDEF or PROTO won't have any effect + * Masm8: EXTERNDEF or PROTO will change visibility to public! + * JWasm: default is Masm6, option -Zv8 switches to Masm8 + * b) OPTION PROC:PRIVATE is NOT set: + * Masm: + * - PROC will be public unless it's marked as private; + * In that case it depends if an EXTERNDEF/PROTO is also found + * JWasm: + * - if PROC is marked as private, EXTERNDEF/PROTO will change that + * only if option -Zv8 is set! + */ if( sym->ispublic == TRUE && oldpubstate == FALSE ) AddPublicData( sym ); diff --git a/src/segment.c b/src/segment.c index a94c998..6afd0bd 100644 --- a/src/segment.c +++ b/src/segment.c @@ -896,6 +896,7 @@ static ret_code SetCurrSeg( int i, struct asm_tok tokenarray[] ) /**************************************************************/ { struct asym *sym; + ret_code rc; sym = SymSearch( tokenarray[0].string_ptr ); DebugMsg1(("SetCurrSeg(%s) sym=%p\n", tokenarray[0].string_ptr, sym)); @@ -911,10 +912,12 @@ static ret_code SetCurrSeg( int i, struct asm_tok tokenarray[] ) } push_seg( (struct dsym *)sym ); + rc = SetOfssize(); /* v2.18: set offset size BEFORE listing, so it shows correctly */ + if ( ModuleInfo.list ) LstWrite( LSTTYPE_LABEL, 0, NULL ); - return( SetOfssize() ); + return( rc ); } static void UnlinkSeg( struct dsym *dir ) @@ -944,6 +947,7 @@ ret_code SegmentDir( int i, struct asm_tok tokenarray[] ) /*******************************************************/ { char is_old = FALSE; + ret_code rc; char *token; int typeidx; const struct typeinfo *type; /* type of option */ @@ -962,6 +966,7 @@ ret_code SegmentDir( int i, struct asm_tok tokenarray[] ) struct asym *sym; struct expr opndx; + if ( Parse_Pass != PASS_1 ) return( SetCurrSeg( i, tokenarray ) ); @@ -1408,10 +1413,12 @@ ret_code SegmentDir( int i, struct asm_tok tokenarray[] ) push_seg( dir ); /* set CurrSeg */ + rc = SetOfssize(); /* 2.18: call SetOfssize BEFORE LstWrite() */ + if ( ModuleInfo.list ) LstWrite( LSTTYPE_LABEL, 0, NULL ); - return( SetOfssize() ); + return( rc ); } /* sort segments ( a simple bubble sort )