owelf.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 481 行 · 第 1/2 页

C
481
字号

    switch( section->align ) {
    case  1:
    case  2:
    case  4:
    case  8:
    case 16:
    case 32:
    case 64:
        alignment = section->align;
        break;
    default:
        assert( 0 );    // must be power of two
        break;
    }
    return( alignment );
}

static owl_offset sectionPadding( owl_section_handle section, owl_offset offset )
//*******************************************************************************
{
    owl_offset          mod;
    owl_offset          padding;

    padding = 0;
    if( section->align != 0 ) {
        mod = offset % section->align;
        if( mod != 0 ) {
            padding = section->align - mod;
        }
    }
    section->x.elf.pad_amount = padding;
    return( padding );
}

static void doSectionHeader( owl_section_handle section, Elf32_Shdr *header )
//***************************************************************************
{
    initSectionHeader( header, sectionTypes( section->type ), sectionFlags( section->type ) );
    header->sh_name = OWLStringOffset( section->name );
    header->sh_addralign = sectionAlignment( section );
    header->sh_size = section->size + sectionPadding( section, section->size );
    if( !( section->type & OWL_SEC_ATTR_BSS ) ) {
        header->sh_offset = section->file->x.elf.next_section;
        section->file->x.elf.next_section += header->sh_size;
    }
}

static void doSectionRelocsHeader( owl_section_handle section, Elf32_Shdr *header ) {
//***********************************************************************************

    size_t      reloc_entry_size;

    reloc_entry_size = useRela ? sizeof( Elf32_Rela ) : sizeof( Elf32_Rel );
    initSectionHeader( header, (useRela ? SHT_RELA : SHT_REL), sectionFlags( section->type ) & SHF_ALLOC );
    header->sh_name = OWLStringOffset( section->x.elf.relocs_name );
    header->sh_link = ELF_SYMBOL_INDEX;
    header->sh_info = _OWLIndexToELFIndex( section->index );
    header->sh_size = reloc_entry_size * section->num_relocs;
    header->sh_entsize = reloc_entry_size;
    header->sh_offset = section->file->x.elf.next_section;
    section->file->x.elf.next_section += header->sh_size;
}

static void formatUserSectionHeaders( owl_file_handle file, Elf32_Shdr *headers ) {
//*********************************************************************************

    owl_section_handle  curr;

    for( curr = file->sections; curr != NULL; curr = curr->next ) {
        doSectionHeader( curr, &headers[ _OWLIndexToELFIndex( curr->index ) ] );
        if( curr->first_reloc != NULL ) {
            doSectionRelocsHeader( curr, &headers[ _OWLIndexToELFIndex( curr->x.elf.relocs_index ) ] );
        }
    }
}

static void emitSectionHeaders( owl_file_handle file ) {
//******************************************************

    Elf32_Shdr          *headers;
    Elf32_Word          section_header_table_size;

    section_header_table_size = numSections( file ) * sizeof( Elf32_Shdr );
    file->x.elf.next_section = sizeof( Elf32_Ehdr ) + section_header_table_size;
    headers = _ClientAlloc( file, section_header_table_size );
    formatBogusUndefHeader( file, &headers[ ELF_UNDEF_INDEX ] );
    formatStringTableHeader( file, &headers[ ELF_STRING_INDEX ] );
    formatSymbolTableHeader( file, &headers[ ELF_SYMBOL_INDEX ] );
    formatUserSectionHeaders( file, headers );
    _ClientWrite( file, (const char *)headers, section_header_table_size );
    _ClientFree( file, headers );
}

static void emitSpecialSection( owl_file_handle file, elf_special_section *section ) {
//************************************************************************************

    _ClientWrite( file, section->buffer, section->length );
    _ClientFree( file, section->buffer );
}

static void emitReloc( owl_section_handle sec, owl_reloc_info *reloc, Elf32_Rela *elf_reloc ) {
//*********************************************************************************************

    owl_offset          old_loc;
    unsigned_32         data;
    unsigned_32         bit_mask;
    size_t              data_size;

    elf_reloc->r_offset = reloc->location;
    elf_reloc->r_info = ELF32_R_INFO( reloc->symbol->index, ElfRelocType( reloc->type, sec->file->info->cpu ) );
    bit_mask = OWLRelocBitMask( sec->file, reloc );
#ifdef __BIG_ENDIAN__ //TODO check target, not host
    // When targeting big endian machines, halfword relocs do not start
    // where the instruction starts because high bits are stored first and
    // reloc is in the low bits. Adjust the location of the reloc for those.
    // Bit of a hack really, but this is the easiest place to do it.
    if( !(bit_mask & 0xffff0000) )
        elf_reloc->r_offset += 2;
#endif
    if( useRela ) {
        // dig up the embedded addend within the object and put it here
        old_loc = OWLBufferTell( sec->buffer );
        OWLBufferSeek( sec->buffer, reloc->location );
        data = 0;
        data_size = min( 4, OWLBufferSize( sec->buffer ) - reloc->location );
        OWLBufferRead( sec->buffer, reloc->location, (char *)&data, data_size );
        elf_reloc->r_addend = ( data & bit_mask );
        data &= ~bit_mask;
        OWLBufferWrite( sec->buffer, (char *)&data, data_size );
        OWLBufferSeek( sec->buffer, old_loc );
    }
}

static void emitSectionPadding( owl_section_info *curr )
//******************************************************
{
    char                *buffer;
    owl_offset          padding;

    padding = curr->x.elf.pad_amount;
    if( padding != 0 ) {
        buffer = _ClientAlloc( curr->file, padding );
        memset( buffer, 0, padding );
        _ClientWrite( curr->file, buffer, padding );
        _ClientFree( curr->file, buffer );
    }
}

static void emitSectionData( owl_file_handle file ) {
//***************************************************

    owl_section_handle  curr;
    owl_reloc_info      *reloc;
    owl_offset          relocs_size;
    Elf32_Rela          *reloc_buffer;
    Elf32_Rela          *next_reloc;
    size_t              reloc_entry_size;

    // Depending on useRela, the last field of Elf32_Rela might be unused.
    // We pass rela ptr around because it works for rel case also.
    // So be careful: don't do a ++next_reloc etc and expect it to be correct.
    reloc_entry_size = useRela ? sizeof( Elf32_Rela ) : sizeof( Elf32_Rel );
    for( curr = file->sections; curr != NULL; curr = curr->next ) {
        // We need to prepare the reloc data before emitting its corresponding
        // section because we might need to modify the buffer content.
        // (see emitReloc)
        if( curr->first_reloc != NULL ) {
            relocs_size = reloc_entry_size * curr->num_relocs;
            reloc_buffer = _ClientAlloc( file, relocs_size );
            next_reloc = reloc_buffer;
            for( reloc = curr->first_reloc; reloc != NULL; reloc = reloc->next ) {
                emitReloc( curr, reloc, next_reloc );
                next_reloc = (Elf32_Rela *)((unsigned)next_reloc + reloc_entry_size);
            }
        } else {
            reloc_buffer = NULL;
        }
        if( !_OwlSectionBSS( curr ) ) {
            OWLBufferEmit( curr->buffer );
            emitSectionPadding( curr );
        }
        if( reloc_buffer ) {
            // Now write out the prepared reloc_buffer
            _ClientWrite( file, (const char *)reloc_buffer, relocs_size );
            _ClientFree( file, reloc_buffer );
        }
    }
}

static void prepareRelocSections( owl_file_handle file ) {
//********************************************************
// Run through the user-defined sections noting which ones have
// relocs and allocate a section index for the section which will
// hold those relocs - also, alloc names for them in the string table

    owl_section_handle  curr;
    char                buffer[ MAX_SECTION_NAME + 5 ];

    switch( file->info->cpu ) {
    case OWL_CPU_INTEL:
    case OWL_CPU_MIPS:    // MIPS SysV ABI supplement says so
        useRela = FALSE;
        break;
    default:
        useRela = TRUE; // This seems to be the common case
        break;
    }
    for( curr = file->sections; curr != NULL; curr = curr->next ) {
        curr->x.elf.pad_amount = 0;
        if( curr->first_reloc != NULL ) {
            strcpy( buffer, (useRela ? ".rela" : ".rel") );
            strcat( buffer, OWLStringText( curr->name ) );
            curr->x.elf.relocs_name = OWLStringAdd( file->string_table, buffer );
            curr->x.elf.relocs_index = file->next_index++;
        }
    }
}

static void addSpecialStrings( owl_file_handle file ) {
//*****************************************************

    file->x.elf.string_table.name = OWLStringAdd( file->string_table, ".strtab" );
    file->x.elf.symbol_table.name = OWLStringAdd( file->string_table, ".symtab" );
}

void ELFFileEmit( owl_file_handle file ) {
//****************************************

    prepareRelocSections( file );
    writeFileHeader( file );
    addSpecialStrings( file );
    prepareStringTable( file, &file->x.elf.string_table );
    prepareSymbolTable( file, &file->x.elf.symbol_table );
    emitSectionHeaders( file );
    emitSpecialSection( file, &file->x.elf.string_table );
    emitSpecialSection( file, &file->x.elf.symbol_table );
    emitSectionData( file );
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?