Beispiel #1
0
static void WriteDOSSectRelocs( section *sect, bool repos )
/*********************************************************/
/* write all relocs associated with sect to the file */
{
    unsigned long       loc;
    OUTFILELIST         *out;

    if( sect->relocs != 0 ) {
        loc = sect->u.file_loc + MAKE_PARA( sect->size );
        out = sect->outfile;
        if( out->file_loc > loc ) {
            SeekLoad( loc );
        } else {
            if( repos ) {
                SeekLoad( out->file_loc );
            }
            if( out->file_loc < loc ) {
                PadLoad( loc - out->file_loc );
                out->file_loc = loc;
            }
        }
        loc += sect->relocs * sizeof( dos_addr );
        DumpRelocList( sect->reloclist );
        if( loc > out->file_loc ) {
            out->file_loc = loc;
        }
    }
}
Beispiel #2
0
void FiniRdosLoadFile16( void )
/* terminate writing of load file */
{
    if( Extension == E_RDV ) {
        HeaderSize = sizeof( rdos_dev16_header );
        SeekLoad( HeaderSize );
        Root->u.file_loc = HeaderSize;
        WriteRDOSCode();
        WriteRDOSData();
        DBIWrite();
        WriteHeader16();
    } else {
        if( FmtData.u.rdos.mboot ) {
            HeaderSize = sizeof( struct mb_header );
            SeekLoad( HeaderSize );
            Root->u.file_loc = HeaderSize;
        } else {
            Root->u.file_loc = 0;
            SeekLoad( 0 );
        }
        WriteBinData();
        DBIWrite();
        if( FmtData.u.rdos.mboot )
            WriteMbootHeader(); 
    }
}
Beispiel #3
0
WResFileOffset res_seek( WResFileID fid, WResFileOffset amount, int where )
{
    if( fid == hInstance.fid ) {
        if( where == SEEK_SET ) {
            return( lseek( WRES_FID2PH( fid ), amount + WResFileShift, where ) - WResFileShift );
        } else {
            return( lseek( WRES_FID2PH( fid ), amount, where ) );
        }
    }

    DbgAssert( where != SEEK_END );
    DbgAssert( !(where == SEEK_CUR && amount < 0) );

    if( WRES_FID2PH( fid ) == Root->outfile->handle ) {
        if( where == SEEK_CUR ) {
            unsigned long   old_pos;
            unsigned long   new_pos;

            old_pos = PosLoad();
            new_pos = old_pos + amount;
            if( new_pos > old_pos ) {
                PadLoad( (size_t)amount );
            } else {
                SeekLoad( new_pos );
            }
            return( new_pos );
        } else {
            SeekLoad( amount );
            return( amount );
        }
    } else {
        return( QLSeek( WRES_FID2PH( fid ), amount, where, "resource file" ) );
    }
}
Beispiel #4
0
static void WriteQNXRelocs( RELOC_INFO *head, unsigned lmf_type, unsigned_16 seg )
/********************************************************************************/
{
    lmf_record          record;
    unsigned_32         pos;
    unsigned_32         size;
    bool                islinear;
    unsigned            adjust;

    adjust = 0;
    record.reserved = record.spare = 0;
    record.rec_type = lmf_type;
    islinear = (lmf_type == LMF_LINEAR_FIXUP_REC);
    if( islinear ) {
        adjust = 2;
    }
    pos = PosLoad();    /* get current position */
    while( head != NULL ) {
        SeekLoad( pos + sizeof(lmf_record) );
        if( islinear ) {
            WriteLoad( &seg, sizeof(unsigned_16) );
        }
        size = DumpMaxRelocList( &head, QNX_MAX_FIXUPS - adjust ) + adjust;
        SeekLoad( pos );
        record.data_nbytes = size;
        WriteLoad( &record, sizeof( lmf_record ) );
        pos += size + sizeof( lmf_record );
    }
    SeekLoad( pos );
}
Beispiel #5
0
void FiniDOSLoadFile( void )
/*********************************/
/* terminate writing of load file */
{
    unsigned_32         hdr_size;
    unsigned_32         mz_hdr_size;
    unsigned_32         temp;
    unsigned_32         min_size;
    unsigned_32         root_size;
    dos_exe_header      exe_head;

    if( FmtData.type & MK_COM ) {
        WriteCOMFile();
        return;
    }
    if( FmtData.u.dos.full_mz_hdr ) {
        mz_hdr_size = 0x40;
    } else {
        mz_hdr_size = sizeof( dos_exe_header ) + sizeof( unsigned_32 );
    }
    SeekLoad( mz_hdr_size );
    root_size = WriteDOSData( mz_hdr_size );
    if( FmtData.type & MK_OVERLAYS ) {
        PadOvlFiles();
    }
    // output debug info into root main output file
    CurrSect = Root;
    DBIWrite();
    hdr_size = MAKE_PARA( (unsigned long)Root->relocs * sizeof( dos_addr )
                                                                 + mz_hdr_size );
    DEBUG((DBG_LOADDOS, "root size %l, hdr size %l", root_size, hdr_size ));
    SeekLoad( 0 );
    _HostU16toTarg( DOS_SIGNATURE, exe_head.signature );
    temp = hdr_size / 16U;
    _HostU16toTarg( temp, exe_head.hdr_size );
    _HostU16toTarg( root_size % 512U, exe_head.mod_size );
    temp = ( root_size + 511U ) / 512U;
    _HostU16toTarg( temp, exe_head.file_size );
    _HostU16toTarg( Root->relocs, exe_head.num_relocs );

    min_size = MemorySize() - ( root_size - hdr_size ) + FmtData.SegMask;
    min_size >>= FmtData.SegShift;
    _HostU16toTarg( min_size, exe_head.min_16 );
    _HostU16toTarg( 0xffff, exe_head.max_16 );
    _HostU16toTarg( StartInfo.addr.off, exe_head.IP );
    _HostU16toTarg( StartInfo.addr.seg, exe_head.CS_offset );
    _HostU16toTarg( StackAddr.seg, exe_head.SS_offset );
    _HostU16toTarg( StackAddr.off, exe_head.SP );
    _HostU16toTarg( 0, exe_head.chk_sum );
    _HostU16toTarg( mz_hdr_size, exe_head.reloc_offset );
    _HostU16toTarg( 0, exe_head.overlay_num );
    WriteLoad( &exe_head, sizeof( dos_exe_header ) );
    WriteLoad( &OvlTabOffset, sizeof( unsigned_32 ) );
}
Beispiel #6
0
static void WritePharSimple( unsigned_32 start )
/**********************************************/
{
    simple_header   header;
    unsigned_32     file_size;
    unsigned_32     header_size;
    unsigned_32     extra;
    unsigned_32     temp;

    if( FmtData.type & MK_PHAR_REX ) {
        SeekLoad( start + sizeof(simple_header) );
        extra = start + sizeof( simple_header ) + WritePharRelocs();
        header_size = MAKE_PARA( extra );
        PadLoad( header_size - extra );
    } else {
        SeekLoad( start + MAKE_PARA( sizeof(simple_header) ) );
        header_size = MAKE_PARA( sizeof(simple_header) );    // para align.
    }
    file_size = header_size + WritePharData( start + header_size );
    DBIWrite();
    if( FmtData.type & MK_PHAR_SIMPLE ) {
        _HostU16toTarg( SIMPLE_SIGNATURE, header.signature );
    } else {
        _HostU16toTarg( REX_SIGNATURE, header.signature );
    }
    _HostU16toTarg( file_size % 512U, header.mod_size );
    _HostU16toTarg( (file_size + 511U) / 512U, header.file_size );
    _HostU16toTarg( Root->relocs, header.num_relocs );
    _HostU16toTarg( header_size / 16, header.hdr_size );
    extra = MemorySize() - file_size + header_size + 0xfff;
    temp = FmtData.u.phar.mindata + extra;
    if( temp < FmtData.u.phar.mindata ) temp = 0xffffffff;
    _HostU16toTarg( temp >> 12, header.min_data );
    temp = FmtData.u.phar.maxdata + extra;
    if( temp < FmtData.u.phar.maxdata ) temp = 0xffffffff;
    _HostU16toTarg( temp >> 12, header.max_data );
    _HostU32toTarg( StackAddr.off, header.ESP );
    _HostU16toTarg( 0, header.checksum );
    _HostU32toTarg( StartInfo.addr.off, header.EIP );
    _HostU16toTarg( 0x1E, header.reloc_offset );
    _HostU16toTarg( 0, header.overlay_num );
    /* allow header size to exceed 1M */
    _HostU16toTarg( (header_size / (16*0x10000ul)) + 1, header.always_one );
    SeekLoad( start );
    WriteLoad( &header, sizeof( simple_header ) );
    if( FmtData.type & MK_PHAR_SIMPLE ) {
        PadLoad( 2 );                   // header occupies a full paragraph.
    }
}
Beispiel #7
0
static bool WriteCOMGroup( group_entry *group, soffset chop )
/***********************************************************/
/* write the data for group to the loadfile */
/* returns true if the file should be repositioned */
{
    unsigned long       file_loc;
    section             *sect;
    bool                repos;
    outfilelist         *finfo;

    repos = false;
    sect = group->section;
    CurrSect = sect;
    finfo = sect->outfile;
    file_loc = GROUP_FILE_LOC( group );
    if( file_loc > finfo->file_loc ) {
        PadLoad( file_loc - finfo->file_loc );
    } else if( file_loc < finfo->file_loc ) {
        SeekLoad( file_loc );
        repos = true;
    }
    DEBUG((DBG_LOADDOS, "group %a section %d to %l in %s",
            &group->grp_addr, sect->ovl_num, file_loc, finfo->fname ));
    COMAmountWritten = 0;
    Ring2Lookup( group->leaders, DoCOMGroup, &chop );
    file_loc += COMAmountWritten;
    if( file_loc > finfo->file_loc ) {
        finfo->file_loc = file_loc;
    }
    return( repos );
}
Beispiel #8
0
static bool WriteCOMGroup( group_entry *group, signed long chop )
/***************************************************************/
/* write the data for group to the loadfile */
/* returns TRUE if the file should be repositioned */
{
    unsigned long       loc;
    signed  long        diff;
    section             *sect;
    bool                repos;
    outfilelist         *finfo;

    repos = FALSE;
    sect = group->section;
    CurrSect = sect;
    finfo = sect->outfile;
    loc = SUB_ADDR( group->grp_addr, sect->sect_addr ) + sect->u.file_loc;
    diff = loc - finfo->file_loc;
    if( diff > 0 ) {
        PadLoad( diff );
    } else if( diff != 0 ) {
        SeekLoad( loc );
        repos = TRUE;
    }
    DEBUG((DBG_LOADDOS, "group %a section %d to %l in %s",
            &group->grp_addr, sect->ovl_num, loc, finfo->fname ));
    COMAmountWritten = 0;
    Ring2Lookup( group->leaders, DoCOMGroup, &chop );
    loc += COMAmountWritten;
    if( loc > finfo->file_loc ) {
        finfo->file_loc = loc;
    }
    return( repos );
}
Beispiel #9
0
void FiniELFLoadFile( void )
/*********************************/
{
    ElfHdr      hdr;

    SetHeaders( &hdr );
#if 0
    if( (LinkState & HAVE_PPC_CODE) && (FmtData.type & MK_OS2) ) {
        // Development temporarly on hold
        // BuildOS2Imports(); // Build .got section
    }
#endif

    WriteELFGroups( &hdr ); // Write out all groups
    WriteRelocsSections( &hdr );        // Relocations
    if( INJECT_DEBUG ) {                // Debug info
        hdr.curr_off = DwarfWriteElf( hdr.curr_off, &hdr.secstrtab,
                                hdr.sh+hdr.i.dbgbegin );
    }
    if( ElfSymTab != NULL ) {           // Symbol tables
        WriteElfSymTable( ElfSymTab, &hdr, hdr.i.symhash, hdr.i.symtab,
                          hdr.i.symstr);
        ZapElfSymTable( ElfSymTab );
    }
    if( hdr.i.symstr != 0 ) {           // String sections
        WriteSHStrings( &hdr, hdr.i.symstr, &SymStrTab );
    }
    WriteSHStrings( &hdr, hdr.i.secstr, &hdr.secstrtab );
    hdr.eh.e_shoff = hdr.curr_off;
    WriteLoad( hdr.sh, hdr.sh_size );
    hdr.curr_off += hdr.sh_size;
    if( !INJECT_DEBUG ) {
        DBIWrite();
    }
    SeekLoad( 0 );
    WriteLoad( &hdr.eh, sizeof(Elf32_Ehdr) );
    WriteLoad( hdr.ph, hdr.ph_size );
    _LnkFree( hdr.sh );
    _LnkFree( hdr.ph );
    FiniStringTable( &hdr.secstrtab );
    FiniStringTable( &SymStrTab );
    SeekLoad( hdr.curr_off );
}
Beispiel #10
0
void FiniRdosLoadFile32( void )
/* terminate writing of load file */
{
    if( Extension == E_RDV ) {
        HeaderSize = sizeof( rdos_dev32_header );
        SeekLoad( HeaderSize );
        Root->u.file_loc = HeaderSize;
        WriteRDOSCode();
        WriteRDOSData();
        DBIWrite();
        CodeSize += 0x10;           // this is a fix to make offsets into data segment correct
        WriteHeader32();
    } else {
        SeekLoad( 0 );
        Root->u.file_loc = 0;
        WriteBinData();
        DBIWrite();
    }
}
Beispiel #11
0
extern void FiniZdosLoadFile( void )
/*************************************/
{
    zdos_exe_header header;
    unsigned_32     position;
    unsigned_32     size;
    unsigned_32     checksum;

    for( position = 0; position < 4; position ++ )
        header.reserved[position] = 0;
    checksum = ZDOS_SIGNATURE;
    _HostU32toTarg( ZDOS_SIGNATURE, header.signature );
    _HostU32toTarg( StartInfo.addr.off, header.EIP );
    checksum += StackAddr.off;
    _HostU32toTarg( StackAddr.off, header.ESP );
    checksum += StackAddr.off;
    _HostU32toTarg( sizeof( zdos_exe_header ), header.hdr_size );
    checksum += sizeof( zdos_exe_header );
    _HostU32toTarg( Root->relocs, header.num_relocs );
    checksum += Root->relocs;
    _HostU32toTarg( sizeof( zdos_exe_header ), header.reloc_offset );
    checksum += sizeof( zdos_exe_header );
    _HostU32toTarg( FmtData.base, header.reloc_base );
    checksum += FmtData.base;
    SeekLoad( sizeof(zdos_exe_header) );
    position = sizeof( zdos_exe_header ) + WriteZdosRelocs();
    _HostU32toTarg( position, header.image_offset );
    checksum += position;
    size = WriteZdosData( position );
    _HostU32toTarg( size, header.image_size );
    checksum += size;
    position += size;
    _HostU32toTarg( position, header.debug_offset );
    checksum += position;
    size = ( StackAddr.off - FmtData.base ) - size;
    _HostU32toTarg( size, header.extra_size );
    checksum += size;
    _HostU32toTarg( size, header.chk_sum );
    DBIWrite();
    SeekLoad( 0 );
    WriteLoad( &header, sizeof( zdos_exe_header ) );
}
Beispiel #12
0
static void SetHeaders( ElfHdr *hdr )
/***********************************/
{
    memcpy( hdr->eh.e_ident, ELF_SIGNATURE, ELF_SIGNATURE_LEN );
    hdr->eh.e_ident[EI_CLASS] = ELFCLASS32;
#ifdef __BIG_ENDIAN__
    hdr->eh.e_ident[EI_DATA] = ELFDATA2MSB;
#else
    hdr->eh.e_ident[EI_DATA] = ELFDATA2LSB;
#endif
    hdr->eh.e_ident[EI_VERSION] = EV_CURRENT;
    hdr->eh.e_ident[EI_OSABI] = FmtData.u.elf.abitype;
    hdr->eh.e_ident[EI_ABIVERSION] = FmtData.u.elf.abiversion;
    memset( &hdr->eh.e_ident[EI_PAD], 0, EI_NIDENT - EI_PAD );
    hdr->eh.e_type = ET_EXEC;
    if( LinkState & HAVE_PPC_CODE ) {
        hdr->eh.e_machine = EM_PPC;
    } else if( LinkState & HAVE_MIPS_CODE ) {
        hdr->eh.e_machine = EM_MIPS;
    } else if( LinkState & HAVE_X64_CODE ) {
        hdr->eh.e_machine = EM_X86_64;
    } else {
        hdr->eh.e_machine = EM_386;
    }
    hdr->eh.e_version = EV_CURRENT;
    if( StartInfo.type == START_UNDEFED ) {
        hdr->eh.e_entry = 0;
    } else {
        hdr->eh.e_entry = FindLinearAddr2( &StartInfo.addr );
    }
    hdr->eh.e_flags = 0;
    hdr->eh.e_ehsize = sizeof(Elf32_Ehdr);
    hdr->eh.e_phentsize = sizeof(Elf32_Phdr);
    hdr->eh.e_shentsize = sizeof(Elf32_Shdr);
    hdr->eh.e_phnum = NumGroups + 1;
    hdr->eh.e_phoff = sizeof(Elf32_Ehdr);
    hdr->ph_size = sizeof(Elf32_Phdr) * hdr->eh.e_phnum;
    _ChkAlloc( hdr->ph, hdr->ph_size );
    hdr->ph->p_type = PT_PHDR;
    hdr->ph->p_offset = sizeof(Elf32_Ehdr);
    hdr->ph->p_vaddr = sizeof(Elf32_Ehdr) + FmtData.base;
    hdr->ph->p_paddr = 0;
    hdr->ph->p_filesz = hdr->ph_size;
    hdr->ph->p_memsz = hdr->ph_size;
    hdr->ph->p_flags = PF_R | PF_X;
    hdr->ph->p_align = 0;
    InitStringTable( &hdr->secstrtab, FALSE );
    AddCharStringTable( &hdr->secstrtab, '\0' );
    InitSections( hdr );
    hdr->curr_off = hdr->eh.e_ehsize + hdr->ph_size;
    hdr->curr_off = ROUND_UP( hdr->curr_off, 0x100 );
    SeekLoad( hdr->curr_off );
}
Beispiel #13
0
static unsigned long WriteDOSData( unsigned_32 mz_hdr_size )
/**********************************************************/
/* copy code from extra memory to loadfile */
{
    group_entry         *group;
    SECTION             *sect;
    unsigned long       header_size;
    outfilelist         *fnode;
    bool                repos;
    unsigned long       root_size;

    DEBUG(( DBG_BASE, "Writing data" ));
    OrderGroups( CompareDosSegments );
    CurrSect = Root;        // needed for WriteInfo.
    header_size = WriteDOSRootRelocs( mz_hdr_size );

    Root->u.file_loc = header_size;
    if( Root->areas != NULL ) {
        Root->outfile->file_loc = header_size + Root->size;
        WalkAllOvl( &AssignFileLocs );
        EmitOvlTable();
    }

// keep track of positions within the file.
    for( fnode = OutFiles; fnode != NULL; fnode = fnode->next ) {
        fnode->file_loc = 0;
    }
    Root->outfile->file_loc = Root->u.file_loc;
    Root->sect_addr = Groups->grp_addr;

/* write groups and relocations */
    root_size = 0;
    for( group = Groups; group != NULL; ) {
        sect = group->section;
        CurrSect = sect;
        fnode = sect->outfile;
        repos = WriteDOSGroup( group );
        group = group->next_group;
        if( ( group == NULL ) || ( sect != group->section ) ) {
            if( sect == Root ) {
                root_size = fnode->file_loc;
            } else {
                WriteDOSSectRelocs( sect, repos );
            }
        }
        if( repos ) {
            SeekLoad( fnode->file_loc );
        }
    }
    return( root_size );
}
Beispiel #14
0
static void WriteCOMFile( void )
/******************************/
// generate a DOS .COM file.
{
    outfilelist         *fnode;
    group_entry         *group;
    bool                repos;
    unsigned long       root_size;
    signed long         chop;

    if( StartInfo.addr.seg != 0 ) {
        LnkMsg( ERR+MSG_INV_COM_START_ADDR, NULL );
        return;
    }
    if( ( StackAddr.seg != 0 ) || ( StackAddr.off != 0 ) ) {
        LnkMsg( WRN+MSG_STACK_SEG_IGNORED, NULL );
    }
    OrderGroups( CompareDosSegments );
    CurrSect = Root;        // needed for WriteInfo.
    fnode = Root->outfile;
    fnode->file_loc = Root->u.file_loc = 0;
    Root->sect_addr = Groups->grp_addr;

    /* write groups */
    for( group = Groups; group != NULL; group = group->next_group ) {
        chop = SUB_ADDR( group->grp_addr, StartInfo.addr );
        if( chop > 0 ) {
            chop = 0;
        }
        if( (signed long)group->size + chop > 0 ) {
            repos = WriteCOMGroup( group, chop );
            if( repos ) {
                SeekLoad( fnode->file_loc );
            }
        }
#if 0
        if( loc < 0 ) {
            Root->u.file_loc += (unsigned long)loc;  // adjust for missing code
        }
#endif
    }
    root_size = fnode->file_loc;
    if( root_size > (64 * 1024L - 0x200) ) {
        LnkMsg( ERR+MSG_COM_TOO_LARGE, NULL );
    }
    DBIWrite();
}
Beispiel #15
0
static void WriteHeader16( void )
/* write 16-bit device header */
{
    rdos_dev16_header   exe_head;
    unsigned_16         temp16;

    SeekLoad( 0 );
    _HostU16toTarg( RDOS_SIGNATURE_16, exe_head.signature );
    _HostU16toTarg( StartInfo.addr.off, exe_head.IP );
    temp16 = (unsigned_16)CodeSize;
    _HostU16toTarg( temp16, exe_head.code_size );
    temp16 = (unsigned_16)FmtData.u.rdos.code_sel;
    _HostU16toTarg( temp16, exe_head.code_sel );
    temp16 = (unsigned_16)DataSize;
    _HostU16toTarg( temp16, exe_head.data_size );
    temp16 = (unsigned_16)FmtData.u.rdos.data_sel;
    _HostU16toTarg( temp16, exe_head.data_sel );
    WriteLoad( &exe_head, sizeof( rdos_dev16_header ) );
}
Beispiel #16
0
static void WriteMbootHeader( void )
/* write multiboot header */
{
    struct mb_header   mb_head;
    unsigned_32        temp32;
    unsigned_32        linear = MB_BASE;

    SeekLoad( 0 );
    _HostU32toTarg(0x1BADB002, mb_head.mb_magic );
    _HostU32toTarg(0x00010001, mb_head.mb_flags );
    _HostU32toTarg(0xE4514FFD, mb_head.mb_checksum );
    _HostU32toTarg(linear, mb_head.mb_header_addr );
    _HostU32toTarg(linear, mb_head.mb_load_addr );
    linear += CodeSize + sizeof( struct mb_header );
    _HostU32toTarg(linear, mb_head.mb_load_end_addr );
    _HostU32toTarg(linear, mb_head.mb_bss_end_addr );
    temp32 = MB_BASE + StartInfo.addr.off + sizeof( struct mb_header );
    _HostU32toTarg(temp32, mb_head.mb_entry_addr );
    WriteLoad( &mb_head, sizeof( struct mb_header ) );
}
Beispiel #17
0
static unsigned_32 WritePharData( unsigned file_pos )
/***************************************************/
{
    group_entry         *group;
    outfilelist *       fnode;
    bool                repos;

    DEBUG(( DBG_BASE, "Writing data" ));
    OrderGroups( CompareOffsets );
    CurrSect = Root;        // needed for WriteInfo.
    fnode = Root->outfile;
    fnode->file_loc = file_pos;
    Root->u.file_loc = file_pos;
    Root->sect_addr = Groups->grp_addr;
    for( group = Groups; group != NULL; group = group->next_group ) {
        repos = WriteDOSGroup( group );
        if( repos ) {
            SeekLoad( fnode->file_loc );
        }
    }
    return( fnode->file_loc - file_pos );
}
Beispiel #18
0
void FiniQNXLoadFile( void )
/*********************************/
{
    unsigned_32 *   segments;
    unsigned_16     nbytes;
    lmf_record      record;
    lmf_header      header;
    lmf_eof         trailer;
    unsigned        adseg;

    CurrSect = Root;
    if( FmtData.type & MK_QNX_FLAT ) {
        if( FmtData.base < StackSize ) {
            LnkMsg( WRN+MSG_QNX_BASE_LT_STACK, NULL );
        }
    }
    nbytes = NumGroups * sizeof( unsigned_32 );
    segments = (unsigned_32 *) alloca( nbytes );
    SeekLoad( sizeof(lmf_header) + nbytes + sizeof(lmf_record) );
    WriteQNXResource();
    WriteQNXData( segments );
    WriteQNXRelocs( Root->reloclist, LMF_FIXUP_REC, 0 );
    WriteQNXRelocs( FloatFixups, LMF_8087_FIXUP_REC, 0 );
    record.reserved = record.spare = 0;
    record.rec_type = LMF_IMAGE_END_REC;
    record.data_nbytes = sizeof( trailer );
    WriteLoad( &record, sizeof( lmf_record ) );
    memset( &trailer, 0, sizeof( trailer ) );
    WriteLoad( &trailer, sizeof( trailer ) );
    DBIWrite();

    SeekLoad( 0 );
    record.rec_type = LMF_HEADER_REC;
    record.data_nbytes = sizeof( lmf_header ) + nbytes;
    WriteLoad( &record, sizeof( lmf_record ) );
    memset( &header, 0, sizeof( header ) );
    header.version = QNX_VERSION;
    header.cflags = (FmtData.u.qnx.flags | (FmtData.u.qnx.priv_level << QNX_PRIV_SHIFT)) & QNX_FLAG_MASK;
    if( LinkState & FMT_SEEN_32_BIT ) {
        header.cflags |= _TCF_32BIT;
    }
    if( FmtData.type & MK_QNX_FLAT ) {
        header.cflags |= _TCF_FLAT;
    }
    header.fpu = 0;     //NYI: need to set 87, 287, 387
    if( FmtData.cpu_type == 0 ) {        // no model specified, so assume...
        if( LinkState & FMT_SEEN_32_BIT ) {
            header.cpu = 386;
        } else {
            header.cpu = 86;
        }
    } else {
        header.cpu = (FmtData.cpu_type * 100) + 86;
    }
    header.code_index = QNX_SEL_NUM( StartInfo.addr.seg );
    header.stack_index = QNX_SEL_NUM( StackAddr.seg );
    adseg = header.stack_index;
    if( DataGroup != NULL ) {
        adseg = QNX_SEL_NUM( DataGroup->grp_addr.seg );
    }
    header.heap_index = adseg;  // all in DGROUP.
    header.argv_index = adseg;
    header.code_offset = StartInfo.addr.off;
    header.stack_nbytes = StackSize;
    header.heap_nbytes = FmtData.u.qnx.heapsize;
    header.image_base = FmtData.base;
    WriteLoad( &header, sizeof( lmf_header ) );
    WriteLoad( segments, nbytes );
}