Skip to content

Commit

Permalink
fixed invoke dir: if cpu was 8086 and constants were to be pushed, th…
Browse files Browse the repository at this point in the history
…e values might have been wrong
  • Loading branch information
Baron-von-Riedesel committed May 27, 2024
1 parent eb83cf3 commit a14cc13
Show file tree
Hide file tree
Showing 11 changed files with 224 additions and 12 deletions.
10 changes: 10 additions & 0 deletions History.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
5 changes: 3 additions & 2 deletions Html/Readme.html
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
131 changes: 131 additions & 0 deletions OWDOS32.mak
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions OWWin32.mak
Original file line number Diff line number Diff line change
Expand Up @@ -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
#########

Expand Down
2 changes: 1 addition & 1 deletion src/H/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
39 changes: 38 additions & 1 deletion src/extern.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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 );
Expand Down Expand Up @@ -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 )
/************************************/
{
Expand Down
2 changes: 1 addition & 1 deletion src/fixup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/invoke.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down
5 changes: 4 additions & 1 deletion src/omf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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 )
/**************************************/
Expand Down Expand Up @@ -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;
Expand All @@ -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 );
}
}
Expand Down
26 changes: 24 additions & 2 deletions src/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 );

Expand Down
11 changes: 9 additions & 2 deletions src/segment.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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 )
Expand Down Expand Up @@ -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 */
Expand All @@ -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 ) );

Expand Down Expand Up @@ -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 )
Expand Down

3 comments on commit a14cc13

@nidud
Copy link

@nidud nidud commented on a14cc13 Jun 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think something is off there: proc.c(1087)

        /* 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;

seg_ofssize is not defined by PROC so newofssize should probably be set to ModuleInfo.Ofssize.

@Baron-von-Riedesel
Copy link
Owner Author

@Baron-von-Riedesel Baron-von-Riedesel commented on a14cc13 Jun 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think something is off there: proc.c(1087)

You're right - although using ModuleInfo.Ofssize almost certainly would also be wrong. My change is:

//newofssize = proc->sym.seg_ofssize; /* CreateProc() sets seg_ofssize for PROTO, but probably wasn't called */
newofssize = GetSymOfssize( &proc->sym ); /* just get the PROC's ofssize, so the check can't fail */

@nidud
Copy link

@nidud nidud commented on a14cc13 Jun 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up doing the following:

//        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;
//        }
...
    } else {
        proc->sym.mem_type = newmemtype;
//        if ( IsPROC == FALSE )
            proc->sym.seg_ofssize = newofssize;

CreateProc():

    if ( sym == NULL ) {
        sym = ( *name ? SymCreate( name ) : SymAlloc( name ) );
	if ( sym != NULL ) /* added */
            sym->seg_ofssize = ModuleInfo.Ofssize;
    } else
...
    if ( sym ) {
        struct proc_info *info;
        sym->state = state;
//        if ( state != SYM_INTERNAL ) {
//            sym->seg_ofssize = ModuleInfo.Ofssize;
//        }

Please sign in to comment.