STATIC void id32Block( obj_rec *objr, OBJ_WFILE *out, int_16 *delta, uint_16 first_block_offset ) { /* Since LIDATAs are different under PharLap and MicroSoft 386 formats, we have to do some magic. */ uint_16 rpt_count; uint_16 blk_count; uint_8 data_count; uint_8 *ptr; rpt_count = ObjGet16( objr ); ObjWrite32( out, rpt_count ); *delta += 2; /* ok, everything from here on will be at +2 offset */ LifixAdd( &lifList, ObjRTell( objr ) - first_block_offset, *delta ); blk_count = ObjGet16( objr ); ObjWrite16( out, blk_count ); if( blk_count == 0 ) { data_count = ObjGet8( objr ); ObjWrite8( out, data_count ); ptr = ObjGet( objr, data_count ); ObjWrite( out, ptr, data_count ); } else { for( ; blk_count != 0; --blk_count ) { id32Block( objr, out, delta, first_block_offset ); } } }
STATIC int writeLedata( obj_rec *objr, pobj_state *state ) { OBJ_WFILE *out; uint_16 save; uint_8 *ptr; uint_16 len; int is32; /**/myassert( objr != NULL ); /**/myassert( objr->command == CMD_LEDATA ); /**/myassert( state != NULL ); /**/myassert( state->pass == POBJ_WRITE_PASS ); #if ( _WOMP_OPT & _WOMP_WATFOR ) == 0 LifixDestroy( &lifList ); LifixInit( &lifList ); #endif out = state->file_out; is32 = objr->is_32 || objr->is_phar; ObjWBegRec( out, is32 ? CMD_LEDA32 : CMD_LEDATA ); ObjWriteIndex( out, objr->d.ledata.idx ); if( is32 ) { ObjWrite32( out, objr->d.ledata.offset ); } else { ObjWrite16( out, (uint_16)objr->d.ledata.offset ); } save = ObjRTell( objr ); len = ObjRemain( objr ); ptr = ObjGet( objr, len ); /**/myassert( len <= 1024 ); ObjWrite( out, ptr, len ); ObjWEndRec( out ); ObjRSeek( objr, save ); return( 0 ); }
STATIC int writeFixup( obj_rec *objr, pobj_state *state ) { OBJ_WFILE *out; int is32; fixup *walk; uint_8 buf[ FIX_GEN_MAX ]; uint_16 len; uint_16 len_written; uint_8 cmd1; uint_8 cmd2; /**/myassert( objr != NULL ); /**/myassert( objr->command == CMD_FIXUP ); /**/myassert( state != NULL ); /**/myassert( state->pass == POBJ_WRITE_PASS ); walk = objr->d.fixup.fixup; if( walk == NULL ) { /* huh? this shouldn't really happen... */ return( 0 ); } out = state->file_out; is32 = objr->is_32 || objr->is_phar; cmd1 = is32 ? CMD_FIXU32 : CMD_FIXUP; cmd2 = is32 ? FIX_GEN_MS386 : FIX_GEN_INTEL; /* we don't want to write FIXUP records that are too large, so we limit our records to approximately 1024 bytes */ do { len_written = 0; ObjWBegRec( out, cmd1 ); while( walk != NULL && len_written < 1024 - FIX_GEN_MAX ) { walk->loc_offset += LifixDelta( &lifList, (uint_16)walk->loc_offset ); #if _WOMP_OPT & _WOMP_WOMP if( Can2MsOS2Flat() && ( walk->loc_method == FIX_OFFSET386 || walk->loc_method == FIX_POINTER386 ) ) { /* zap FIXUPs for OS/2 2.0 linker 21-mar-91 AFS */ switch( walk->lr.frame ) { case FRAME_SEG: case FRAME_GRP: case FRAME_TARG: walk->lr.frame = FRAME_GRP; walk->lr.frame_datum = ObjFLATIndex; break; } } #endif len = FixGenFix( walk, buf, cmd2 ); ObjWrite( out, buf, len ); walk = walk->next; len_written += len; } ObjWEndRec( out ); } while( walk != NULL ); return( 0 ); }
STATIC int writeComdat( obj_rec *objr, pobj_state *state ) { OBJ_WFILE *out; uint_8 *ptr; uint_16 len; uint_16 save; int is32; /**/myassert( objr != NULL ); /**/myassert( objr->command == CMD_COMDAT ); /**/myassert( state != NULL ); /**/myassert( state->pass == POBJ_WRITE_PASS ); save = ObjRTell( objr ); is32 = objr->is_32 || objr->is_phar; if( is32 ) { objr->command |= 1; } out = state->file_out; ObjWBegRec( out, objr->command ); ObjWrite8( out, objr->d.comdat.flags ); ObjWrite8( out, objr->d.comdat.attributes ); ObjWrite8( out, objr->d.comdat.align ); if( is32 ) { ObjWrite32( out, objr->d.comdat.offset ); } else { ObjWrite16( out, (uint_16)objr->d.comdat.offset ); } ObjWriteIndex( out, objr->d.comdat.type_idx ); if( ( objr->d.comdat.attributes & COMDAT_ALLOC_MASK ) == COMDAT_EXPLICIT ) { writeBase( objr, out ); } ObjWriteIndex( out, objr->d.comdat.public_name_idx ); if( ( objr->d.comdat.flags & COMDAT_ITERATED ) == 0 || objr->is_phar == 0 ) { /* record is already in ms omf format */ len = ObjRemain( objr ); ptr = ObjGet( objr, len ); /**/ myassert( len <= 1024 ); ObjWrite( out, ptr, len ); } else { int_16 delta; uint_16 first_block_offset; delta = 0; /* id32Block needs to play with this */ first_block_offset = ObjRTell( objr ); while( !ObjEOR( objr ) ) { id32Block( objr, out, &delta, first_block_offset ); } } ObjWEndRec( out ); ObjRSeek( objr, save ); return( 0 ); }
STATIC int writeLidata( obj_rec *objr, pobj_state *state ) { OBJ_WFILE *out; uint_16 save; uint_8 *ptr; uint_16 len; int is32; /**/myassert( objr != NULL ); /**/myassert( objr->command == CMD_LIDATA ); /**/myassert( state != NULL ); /**/myassert( state->pass == POBJ_WRITE_PASS ); LifixDestroy( &lifList ); LifixInit( &lifList ); out = state->file_out; save = ObjRTell( objr ); is32 = objr->is_32 || objr->is_phar; ObjWBegRec( out, is32 ? CMD_LIDA32 : CMD_LIDATA ); ObjWriteIndex( out, objr->d.lidata.idx ); if( is32 ) { ObjWrite32( out, objr->d.lidata.offset ); } else { ObjWrite16( out, (uint_16)objr->d.lidata.offset ); } if( objr->is_phar == 0 ) { /* ok, already in our format */ len = ObjRemain( objr ); ptr = ObjGet( objr, len ); ObjWrite( out, ptr, len ); } else { int_16 delta; uint_16 first_block_offset; delta = 0; /* id32Block needs to play with this */ first_block_offset = ObjRTell( objr ); while( !ObjEOR( objr ) ) { id32Block( objr, out, &delta, first_block_offset ); } } ObjWEndRec( out ); ObjRSeek( objr, save ); return( 0 ); }
STATIC int writePubdef( obj_rec *objr, pobj_state *state ) { int is32; OBJ_WFILE *out; const char *name; size_t name_len; pubdef_data *pubdata; pubdef_data *pubstop; /**/myassert( objr != NULL ); /**/myassert( objr->command == CMD_PUBDEF || objr->command == CMD_STATIC_PUBDEF ); /**/myassert( state != NULL ); /**/myassert( state->pass == POBJ_WRITE_PASS ); is32 = objr->is_32 || objr->is_phar; if( is32 ) { objr->command |= 1; } out = state->file_out; ObjWBegRec( out, objr->command ); writeBase( objr, out ); pubdata = objr->d.pubdef.pubs; if( pubdata != NULL ) { pubstop = pubdata + objr->d.pubdef.num_pubs; while( pubdata < pubstop ) { name = NameGet( pubdata->name ); name_len = strlen( name ); if( name_len > 255 ) name_len = 255; ObjWrite8( out, (uint_8)name_len ); ObjWrite( out, (uint_8 *)name, (uint_16)name_len ); if( is32 ) { ObjWrite32( out, pubdata->offset ); } else { ObjWrite16( out, (uint_16)pubdata->offset ); } ObjWriteIndex( out, pubdata->type.idx ); ++pubdata; } } ObjWEndRec( out ); return( 0 ); }
STATIC int writeComent( obj_rec *objr, pobj_state *state ) { uint_8 *ptr; uint_16 len; uint_16 save; OBJ_WFILE *out; /**/myassert( objr != NULL ); /**/myassert( objr->data != NULL ); /**/myassert( state != NULL ); /**/myassert( state->pass == POBJ_WRITE_PASS ); out = state->file_out; ObjWBegRec( out, CMD_COMENT ); ObjWrite8( out, objr->d.coment.attr ); ObjWrite8( out, objr->d.coment.class ); save = ObjRTell( objr ); len = ObjRemain( objr ); ptr = ObjGet( objr, len ); ObjWrite( out, ptr, len ); ObjRSeek( objr, save ); ObjWEndRec( out ); return( 0 ); }
void Pass2(Instruction *instr, int pc) { Expression *expr = instr->optexpr; int opcode = instr->opcode; int result = 0; if (instr->combine == 0) { /* no post processesing required */ /* pass opcode straight to the object formatter */ WriteCodeWord(opcode); return; } switch (instr->combine) { /* diadic combine commands */ /* All these commands will only use combine, NOT combine2 */ /* Register addressing doesn't need to be checked */ case COM_DIA_REG: /* do nothing */ break; /* Check signed immediate <= 16 bits and insert int bits 0-15 */ case COM_DIA_IMM: result = Eval(expr, pc); if (!fits_in_16_bits(result)) { char Err[80]; sprintf(Err, "signed immediate value (%d) will not fit in 16 bits", result); Error(Err); } opcode |= result & 0xffff; break; /* Check UNsigned immediate <= 16 bits and insert int bits 0-15 */ case COM_DIA_IMM_UNSIGNED: result = Eval(expr, pc); if (!fits_in_16_bits_unsigned(result)) { char Err[80]; sprintf(Err, "unsigned immediate value (%#x) will not fit in 16 bits", result); Error(Err); } opcode |= result; break; /* Shift immediate >> 16 and insert int bits 0-15 */ case COM_DIA_IMM_LDP: opcode |= (Eval(expr, pc) >> 16) & 0xffff; break; /* Check unsigned disp <= 8 bits and insert into bits 0-7 */ case COM_DIA_IND: result = Eval(expr, pc); if (!fits_in_8_bits_unsigned(result)) { char Err[80]; sprintf(Err, "unsigned indirect displacement (%d) is too large to be held in 8 bits", result); Error(Err); } opcode |= result; break; /* Check direct unsigned offset <= 16 bits and insert into bits 0-15 */ case COM_DIA_DIR: result = Eval(expr, pc); if (!fits_in_16_bits_unsigned(result)) { char Err[80]; sprintf(Err, "unsigned direct offset of (%d) cannot be held in 16 bits", result); Error(Err); } opcode |= result; break; /* Check signed immediate is <= 5 bits and insert into bits 16-20 */ case COM_STIK_IMM: result = Eval(expr, pc); if (!fits_in_5_bits(result)) { char Err[80]; sprintf(Err, "STIK signed immediate value (%d) cannot be held in 5 bits", result); Error(Err); } opcode |= (result & B_11111) << 16; break; /* triadic combine commands */ /* Notes arg position by: _A1 = bits 0-7, _A2 = bits 8-15 */ /* Triadic type 1 indirect addressing, args 1 and 2 */ /* If instr->optexpr is NULL then there is no need to check the */ /* displacement as it will be an index reg. */ /* Check displacement is only 1 or 0. */ /* If displacement is 0, then convert mod to 0b11000: */ /* (*+ARn(0) -> *ARn) */ case COM_TRI_IND1_A1: /* mod = bits 3-7 */ if (expr != NULL) { if((result = Eval(expr, pc)) > 1 || result < 0) Error("indirect displacement value should only be 1 or 0"); if (result == 0) /* convert to a *ARn type indirection preserving ARn */ opcode = (opcode & ~B_11111000) | B_11000000; } break; case COM_TRI_IND1_A2: /* mod = bits 11-15 */ if (expr != NULL) { if((result = Eval(expr, pc)) > 1 || result < 0) Error("indirect displacement value should only be 1 or 0"); if (result == 0) /* convert to a *ARn type indirection preserving ARn */ opcode = (opcode & ~(B_11111000 << 8)) | (B_11000000 << 8); } break; /* Triadic type 2 indirect addressing, args 1 and 2 */ /* Check unsigned displacement is <= 5 bits and insert disp. */ /* into bits 11-15 or 3-7 */ case COM_TRI_IND2_A1: /* bits 3-7 */ if (expr != NULL) { result = Eval(expr, pc); if (!fits_in_5_bits_unsigned(result)) { char Err[80]; sprintf(Err, "indirect displacement value (%d) cannot be held in 5 bits", result); Error(Err); } #if 0 /* @@@ opt syntax #4 - would also have to convert T field */ if (result == 0) { /* convert to a type 1, *ARn type indirection */ /* preserving ARn - opt syntax #4 */ opcode = ((opcode & ~TRI_TYPE_2) & ~B_11111000) | B_11000000; } else #endif /* insert 5bit displacement into mod field */ opcode = (opcode & ~B_11111000) | (result << 3); } else FatalNullExpr(); break; case COM_TRI_IND2_A2: /* bits 11-15 */ if (expr != NULL) { result = Eval(expr, pc); if (!fits_in_5_bits_unsigned(result)) { char Err[80]; sprintf(Err, "unsigned indirect displacement value (%d) cannot be held in 5 bits", result); Error(Err); } #if 0 /* @@@ opt syntax #4 - would also have to convert T field */ if (result == 0) { /* convert to a type 1, *ARn type indirection */ /* preserving ARn - opt syntax #4 */ opcode = ((opcode & ~TRI_TYPE_2) & ~(B_11111000 << 8)) | (B_11000000 << 8); } else #endif opcode = (opcode & ~(B_11111000 << 8)) | (result << 11); } else FatalNullExpr(); break; /* Triadic type 2 immediate addressing, arg 1 only */ /* Check immediate <= eight bits and insert into bits 0-7 of */ /* instruction. */ case COM_TRI_IMM_A1: if (expr != NULL) { result = Eval(expr, pc); if (!fits_in_8_bits(result)) { char Err[80]; sprintf(Err, "signed immediate value (%d) cannot be held in 8 bits", result); Error(Err); } opcode |= (result & 0xff); } break; case COM_TRI_IMM_A1_UNSIGNED: if (expr != NULL) { result = Eval(expr, pc); if (!fits_in_8_bits_unsigned(result)) { char Err[80]; sprintf(Err, "unsigned immediate value (%d) cannot be held in 8 bits", result); Error(Err); } opcode |= result; } break; /* parallel store combine commands */ /* Check displacement is only 1 or 0, If displacement is 0, */ /* then convert mod to 0b11000 (*+ARn(0) -> *ARn) */ case COM_PST_IND_S1: /* 1st src operand: mod = bits 3-7 */ if (expr != NULL) { if((result = Eval(expr, pc)) > 1 || result < 0) Error("indirect displacement value should only be 1 or 0"); if (result == 0) /* convert to a *ARn type indirection preserving ARn */ opcode = (opcode & ~B_11111000) | B_11000000; } break; case COM_PST_IND_D2: /* Store dest operand: mod = bits 11-15 */ if (expr != NULL) { if((result = Eval(expr, pc)) > 1 || result < 0) Error("indirect displacement value should only be 1 or 0"); if (result == 0) /* convert to a *ARn type indirection preserving ARn */ opcode = (opcode & ~(B_11111000 << 8)) | (B_11000000 << 8); } break; /* parallel multiply add/sub combine commands */ /* Check displacement is only 1 or 0, If displacement is 0, */ /* then convert mod to 0b11000 (*+ARn(0) -> *ARn) */ case COM_PMPY_IND1: /* mod bits 11-15 */ if (expr != NULL) { if((result = Eval(expr, pc)) > 1 || result < 0) Error("indirect displacement value should only be 1 or 0"); if (result == 0) /* convert to a *ARn type indirection preserving ARn */ opcode = (opcode & ~(B_11111000 << 8)) | (B_11000000 << 8); } break; case COM_PMPY_IND2: /* mod bits 3-7 */ if (expr != NULL) { if((result = Eval(expr, pc)) > 1 || result < 0) Error("indirect displacement value should only be 1 or 0"); if (result == 0) /* convert to a *ARn type indirection preserving ARn */ opcode = (opcode & ~B_11111000) | B_11000000; } break; /* branch combine commands */ /* If operation is a delayed branch then subtract 3 from the */ /* offset before inserting it into the instruction, otherwise */ /* subtract 1. These combine commands will only ever occur in */ /* the first ->combine */ /* Check PC relative offset <= 16 bits and insert into */ /* bits 0-15. Used in conditional branch instructions. */ /* Bit 21 specifies if it is a delayed branch. */ case COM_CBR_PCREL: /* default for pcrel mode */ /* pipeline adjustment for normal or delayed branch */ if ( opcode & (1 << 21)) result = -3; else result = -1; if (expr->what == E_Str) { /* possible imported label ? */ Symbol *s = FindSymb(expr->type.name); if (s != NULL && s->what == HT_IMPORT) { /* output instruction with codestub patch */ FlushCodeBuffer(); /* assume word sized instruction */ GHOFEncode(GHOF_WORD); /* output the machine specific patch */ GHOFEncode(PATCH_C40MASK16ADD); /* output the assembled instruction as the */ /* patches data */ opcode |= result & 0xffff; GHOFEncode(opcode); /* For the C40 we have to shift the labelref */ /* value to a word pointer */ GHOFEncode(PATCH_SHIFT); GHOFEncode(-2); /* Other machines may use labelrefs if they */ /* have not implemented linker codestubs */ GHOFEncode(GHOF_CODESTUB); ObjWrite(s->name, strlen(s->name)+1); return; } } result += Eval(expr, pc); if (!fits_in_16_bits(result)) { char Err[80]; sprintf(Err,"pc relative offset (%#x) is larger than can be held in 16 bits", result); Error(Err); } opcode |= result & 0xffff; break; /* Check PC relative offset < 24 bits and insert into bits 0-23 */ /* Used in UNconditional branch instructions and RPTB(D) */ /* Bit 24 specifies if it is a delayed branch */ case COM_BR_PCREL: if ( opcode & (1 << 24)) result = -3; else result = -1; if (expr->what == E_Str) { /* possible imported label ? */ /* pipeline adjustment for normal or delayed branch */ Symbol *s = FindSymb(expr->type.name); if (s != NULL && s->what == HT_IMPORT) { /* output instruction with codestub patch */ FlushCodeBuffer(); /* assume word sized instruction */ GHOFEncode(GHOF_WORD); /* output the machine specific patch */ GHOFEncode(PATCH_C40MASK24ADD); /* output the assembled instruction as the */ /* patches data */ opcode |= result & 0xffffff; GHOFEncode(opcode); /* For the C40 we have to shift the labelref */ /* value to a word pointer */ GHOFEncode(PATCH_SHIFT); GHOFEncode(-2); /* Other machines may use labelrefs if they */ /* have not implemented linker codestubs */ GHOFEncode(GHOF_CODESTUB); ObjWrite(s->name, strlen(s->name)+1); return; } } result += Eval(expr, pc); if (!fits_in_24_bits(result)) { char Err[80]; sprintf(Err, "pc relative offset (%#x) is larger than can be held in 24 bits", result); Error(Err); } opcode |= result & 0x00ffffff; break; /* Check immediate value is <= 9 bits and insert into bits 0-8 */ case COM_TRAP: if ((result = Eval(expr, pc)) & ~(B_111111111)) Error("cannot have a trap vector higher than 511"); opcode |= result; break; default: { char Err[80]; sprintf(Err, "Unknown combine 1 command (%d) in second pass", \ instr->combine); Fatal(Err); break; } } if (instr->combine2 == 0) { /* no second operand to post process */ /* pass opcode on to the object formatter */ WriteCodeWord(opcode); return; } /* now check for combine commands on a second operand */ expr = instr->optexpr2; switch (instr->combine2) { /* triadic combine commands */ /* Notes arg position by: _A1 = bits 0-7, _A2 = bits 8-15 */ /* Triadic type 1 indirect addressing, args 1 and 2 */ /* Check displacement is only 1 or 0. */ /* If displacement is 0, then convert mod to 0b11000: */ /* (*+ARn(0) -> *ARn) */ case COM_TRI_IND1_A1: /* mod = bits 3-7 */ if (expr != NULL) { if((result = Eval(expr, pc)) > 1 || result < 0) Error("indirect displacement value should only be 1 or 0"); if (result == 0) /* convert to a *ARn type indirection preserving ARn */ opcode = (opcode & ~B_11111000) | B_11000000; } break; case COM_TRI_IND1_A2: /* mod = bits 11-15 */ if (expr != NULL) { if ((result = Eval(expr, pc)) > 1 || result < 0) Error("indirect displacement value should only be 1 or 0"); if (result == 0) /* convert to a *ARn type indirection preserving ARn */ opcode = (opcode & ~(B_11111000 << 8)) | (B_11000000 << 8); } break; /* Triadic type 2 indirect addressing, args 1 and 2 */ /* Check displacement is <= 5 bits and insert disp. into */ /* bits 11-15 or 3-7 */ case COM_TRI_IND2_A1: /* bits 3-7 */ if (expr != NULL) { result = Eval(expr, pc); if (!fits_in_5_bits_unsigned(result)) { char Err[80]; sprintf(Err, "indirect displacement value (%d) cannot be held in 5 bits", result); Error(Err); } #if 0 /* would also have to convert T field */ if (result == 0) { /* convert to a type 1, *ARn type indirection */ /* preserving ARn - opt syntax #4 */ opcode = ((opcode & ~TRI_TYPE_2) & ~B_11111000) | B_11000000; } else #endif opcode = (opcode & ~B_11111000) | (result << 3); } else FatalNullExpr(); break; case COM_TRI_IND2_A2: /* bits 11-15 */ if (expr != NULL) { result = Eval(expr, pc); if (!fits_in_5_bits_unsigned(result)) { char Err[80]; sprintf(Err, "indirect displacement value (%d) will not fit into 5 bits", result); Error(Err); } #if 0 /* would also have to convert T field */ if (result == 0) { /* convert to a type 1, *ARn type indirection */ /* preserving ARn - opt syntax #4 */ opcode = ((opcode & ~TRI_TYPE_2) & ~(B_11111000 << 8)) | (B_11000000 << 8); } else #endif opcode = (opcode & ~(B_11111000 << 8)) | (result << 11); } else FatalNullExpr(); break; /* parallel store combine commands */ /* Check displacement is only 1 or 0, If displacement is 0, */ /* then convert mod to 0b11000 (*+ARn(0) -> *ARn) */ case COM_PST_IND_S1: /* 1st src operand: mod = bits 3-7 */ if (expr != NULL) { if((result = Eval(expr, pc)) > 1 || result < 0) Error("indirect displacement value should only be 1 or 0"); if (result == 0) /* convert to a *ARn type indirection preserving ARn */ opcode = (opcode & ~B_11111000) | B_11000000; } break; case COM_PST_IND_D2: /* Store dest operand: mod = bits 11-15 */ if (expr != NULL) { if((result = Eval(expr, pc)) > 1 || result < 0) Error("indirect displacement value should only be 1 or 0"); if (result == 0) /* convert to a *ARn type indirection preserving ARn */ opcode = (opcode & ~(B_11111000 << 8)) | (B_11000000 << 8); } break; /* parallel multiply add/sub combine commands */ /* Check displacement is only 1 or 0, If displacement is 0, */ /* then convert mod to 0b11000 (*+ARn(0) -> *ARn) */ case COM_PMPY_IND1: /* mod bits 11-15 */ if (expr != NULL) { if((result = Eval(expr, pc)) > 1 || result < 0) Error("indirect displacement value should only be 1 or 0"); if (result == 0) /* convert to a *ARn type indirection preserving ARn */ opcode = (opcode & ~B_11111000) | B_11000000; } break; case COM_PMPY_IND2: /* mod bits 3-7 */ if (expr != NULL) { if((result = Eval(expr, pc)) > 1 || result < 0) Error("indirect displacement value should only be 1 or 0"); if (result == 0) /* convert to a *ARn type indirection preserving ARn */ opcode = (opcode & ~(B_11111000 << 8)) | (B_11000000 << 8); } break; /* Following two commands should only get into second combine */ /* if used with a STIK instruction */ /* Check unsigned disp <= 8 bits and insert into bits 0-7 */ case COM_DIA_IND: result = Eval(expr, pc); if (!fits_in_8_bits_unsigned(result)) { char Err[80]; sprintf(Err, "indirect displacement of (%d) will not fit into 8 bits", result); Error(Err); } opcode |= result; break; /* Check direct unsigned offset <= 16 bits and insert into bits 0-15 */ case COM_DIA_DIR: result = Eval(expr, pc); if (!fits_in_16_bits_unsigned(result)) { char Err[128]; sprintf(Err, "direct offset of (%d) cannot be held in 16 bits", result); Error(Err); } opcode |= result; break; default: { char Err[80]; sprintf(Err, "Unknown combine 2 command (%d) in second pass", \ instr->combine2); Fatal(Err); break; } } /* pass opcode on to the object formatter */ WriteCodeWord(opcode); }