#include <ctype.h>
#include <time.h>
#include "globals.h"
#include "memalloc.h"
#include "parser.h"
#include "mangle.h"
#include "fixup.h"
#include "segment.h"
#include "extern.h"
#include "elf.h"
#include "elfspec.h"
#include "myassert.h"
#if ELF_SUPPORT
#define ELFALIAS 0
#define ADDSTARTLABEL 0
#define OWELFIMPORT 0
#define GNURELOCS 1
#define MANGLE_BYTES 8
#define IsWeak( x ) ( x.iscomm == FALSE && x.altname )
struct localname {
void *next;
struct asym *sym;
};
enum internal_sections {
SHSTRTAB_IDX,
SYMTAB_IDX,
STRTAB_IDX,
NUM_INTSEGS
};
struct intsegparm {
const char *name;
unsigned type;
};
static const struct intsegparm internal_segparms[] = {
{ ".shstrtab", SHT_STRTAB },
{ ".symtab", SHT_SYMTAB },
{ ".strtab", SHT_STRTAB },
};
struct intseg {
uint_32 size;
uint_32 fileoffset;
void *data;
};
struct elfmod {
uint_32 symindex;
uint_32 start_globals;
char *srcname;
#if GNURELOCS
bool extused;
#endif
struct intseg internal_segs[NUM_INTSEGS];
union {
Elf32_Ehdr ehdr32;
#if AMD64_SUPPORT
Elf64_Ehdr ehdr64;
#endif
};
};
struct conv_section {
uint_8 len;
uint_8 flags;
const char *src;
const char *dst;
};
enum cvs_flags {
CSF_GRPCHK = 1
};
static const struct conv_section cst[] = {
{ 5, CSF_GRPCHK, "_TEXT", ".text" },
{ 5, CSF_GRPCHK, "_DATA", ".data" },
{ 5, CSF_GRPCHK, "CONST", ".rodata" },
{ 4, 0, "_BSS", ".bss" }
};
static char *ElfConvertSectionName( const struct asym *sym, char *buffer )
{
int i;
for ( i = 0; i < sizeof( cst ) / sizeof( cst[0] ); i++ ) {
if ( memcmp( sym->name, cst[i].src, cst[i].len ) == 0 ) {
if ( sym->name[cst[i].len] == NULLC )
return( (char *)cst[i].dst );
else if ( ( cst[i].flags & CSF_GRPCHK ) && sym->name[cst[i].len] == '$' ) {
strcpy( buffer, cst[i].dst );
strcat( buffer, sym->name+cst[i].len );
return( buffer );
}
}
}
return( sym->name );
}
static int get_num_reloc_sections( void )
{
struct dsym *curr;
int num = 0;
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
if ( curr->e.seginfo->FixupList.head )
num++;
}
return( num );
}
static uint_32 set_symtab32( struct elfmod *em, uint_32 entries, struct localname *localshead )
{
uint_32 strsize = 1;
uint_32 len;
uint_8 stt;
struct dsym *curr;
struct asym *sym;
struct localname *localscurr;
struct qnode *q;
Elf32_Sym *p32;
char buffer[MAX_ID_LEN + MANGLE_BYTES + 1];
em->internal_segs[SYMTAB_IDX].size = entries * sizeof( Elf32_Sym );
em->internal_segs[SYMTAB_IDX].data = LclAlloc( em->internal_segs[SYMTAB_IDX].size );
memset( em->internal_segs[SYMTAB_IDX].data, 0, em->internal_segs[SYMTAB_IDX].size );
p32 = (Elf32_Sym *)em->internal_segs[SYMTAB_IDX].data;
p32++;
p32->st_name = strsize;
strsize += strlen( em->srcname ) + 1;
p32->st_value = 0;
p32->st_size = 0;
p32->st_info = ELF32_ST_INFO( STB_LOCAL, STT_FILE );
p32->st_shndx = SHN_ABS;
p32++;
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
p32->st_info = ELF32_ST_INFO( STB_LOCAL, STT_SECTION );
p32->st_shndx = GetSegIdx( curr->sym.segment );
p32++;
}
for ( localscurr = localshead ; localscurr ; localscurr = localscurr->next ) {
len = Mangle( localscurr->sym, buffer );
p32->st_name = strsize;
curr = (struct dsym *)localscurr->sym->segment;
if ( curr && curr->e.seginfo->segtype != SEGTYPE_CODE )
stt = STT_OBJECT;
else
stt = STT_FUNC;
p32->st_info = ELF32_ST_INFO( STB_LOCAL, stt );
p32->st_value = localscurr->sym->offset;
#if 1
if ( curr )
p32->st_shndx = GetSegIdx( &curr->sym );
else
p32->st_shndx = SHN_ABS;
#else#endif
strsize += len + 1;
DebugMsg(("set_symtab32, LOCAL: symbol %s, value=%X\n", buffer, p32->st_value));
p32++;
}
for( curr = SymTables[TAB_EXT].head ; curr != NULL ;curr = curr->next ) {
if ( curr->sym.iscomm == FALSE && curr->sym.weak == TRUE )
continue;
len = Mangle( &curr->sym, buffer );
p32->st_name = strsize;
if ( curr->sym.iscomm == TRUE ) {
p32->st_info = ELF32_ST_INFO( STB_GLOBAL, STT_COMMON );
p32->st_value = curr->sym.total_size;
p32->st_shndx = SHN_COMMON;
} else {
#if OWELFIMPORT
p32->st_info = ( IsWeak( curr->sym ) ? ELF32_ST_INFO( STB_WEAK, STT_IMPORT ) : ELF32_ST_INFO( STB_GLOBAL, STT_IMPORT ) );
#else
p32->st_info = ( IsWeak( curr->sym ) ? ELF32_ST_INFO( STB_WEAK, STT_NOTYPE ) : ELF32_ST_INFO( STB_GLOBAL, STT_NOTYPE ) );
#endif
p32->st_value = curr->sym.offset;
p32->st_shndx = SHN_UNDEF;
}
strsize += len + 1;
DebugMsg(("set_symtab32, EXTERNAL: symbol %s, info=%X, shndx=%X, value=%X\n", buffer, p32->st_info, p32->st_shndx, p32->st_value));
p32++;
}
#if ELFALIAS
for( curr = SymTables[TAB_ALIAS].head ; curr != NULL ;curr = curr->next ) {
len = Mangle( &curr->sym, buffer );
p32->st_name = strsize;
#if OWELFIMPORT
p32->st_info = ELF32_ST_INFO( STB_WEAK, STT_IMPORT );
#else
p32->st_info = ELF32_ST_INFO( STB_WEAK, STT_NOTYPE );
#endif
p32->st_value = 0;
p32->st_shndx = SHN_UNDEF;
strsize += len + 1;
DebugMsg(("set_symtab32, ALIAS: symbol %s, value=%X\n", buffer, p32->st_value));
p32++;
}
#endif
for ( q = ModuleInfo.g.PubQueue.head; q; q = q->next ) {
sym = q->sym;
len = Mangle( sym, buffer );
curr = (struct dsym *)sym->segment;
if ( curr && curr->e.seginfo->segtype != SEGTYPE_CODE )
stt = STT_OBJECT;
else
stt = STT_FUNC;
p32->st_name = strsize;
p32->st_info = ELF32_ST_INFO( STB_GLOBAL, stt );
p32->st_value = sym->offset;
#if 1
if ( sym->state == SYM_INTERNAL )
if ( curr )
p32->st_shndx = GetSegIdx( &curr->sym );
else
p32->st_shndx = SHN_ABS;
else
p32->st_shndx = SHN_UNDEF;
#else#endif
strsize += len + 1;
DebugMsg(("set_symtab32, PUBLIC+LOCAL: symbol %s, value=%X\n", buffer, p32->st_value));
p32++;
}
#if ADDSTARTLABEL
if ( ModuleInfo.g.start_label ) {
len = Mangle( ModuleInfo.g.start_label, buffer );
p32->st_name = strsize;
p32->st_info = ELF32_ST_INFO( STB_ENTRY, STT_FUNC );
p32->st_value = ModuleInfo.g.start_label->offset;
p32->st_shndx = GetSegIdx( ModuleInfo.g.start_label->segment );
strsize += len + 1;
DebugMsg(("set_symtab32, ENTRY: symbol %s, value=%X\n", buffer, p32->st_value));
p32++;
}
#endif
return( strsize );
}
#if AMD64_SUPPORT
static uint_32 set_symtab64( struct elfmod *em, uint_32 entries, struct localname *localshead )
{
uint_32 strsize = 1;
uint_32 len;
uint_8 stt;
struct dsym *curr;
struct asym *sym;
struct localname *localscurr;
struct qnode *q;
Elf64_Sym *p64;
char buffer[MAX_ID_LEN + MANGLE_BYTES + 1];
em->internal_segs[SYMTAB_IDX].size = entries * sizeof( Elf64_Sym );
em->internal_segs[SYMTAB_IDX].data = LclAlloc( em->internal_segs[SYMTAB_IDX].size );
memset( em->internal_segs[SYMTAB_IDX].data, 0, em->internal_segs[SYMTAB_IDX].size );
p64 = (Elf64_Sym *)em->internal_segs[SYMTAB_IDX].data;
p64++;
p64->st_name = strsize;
strsize += strlen( em->srcname ) + 1;
p64->st_value = 0;
p64->st_size = 0;
p64->st_info = ELF64_ST_INFO( STB_LOCAL, STT_FILE );
p64->st_shndx = SHN_ABS;
p64++;
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
p64->st_info = ELF64_ST_INFO( STB_LOCAL, STT_SECTION );
p64->st_shndx = GetSegIdx( curr->sym.segment );
p64++;
}
for ( localscurr = localshead ; localscurr ; localscurr = localscurr->next ) {
len = Mangle( localscurr->sym, buffer );
p64->st_name = strsize;
curr = (struct dsym *)localscurr->sym->segment;
if ( curr && curr->e.seginfo->segtype != SEGTYPE_CODE )
stt = STT_OBJECT;
else
stt = STT_FUNC;
p64->st_info = ELF64_ST_INFO( STB_LOCAL, stt );
p64->st_value = localscurr->sym->offset;
#if 1
if ( curr )
p64->st_shndx = GetSegIdx( &curr->sym );
else
p64->st_shndx = SHN_ABS;
#else#endif
strsize += len + 1;
DebugMsg(("set_symtab64, LOCAL: symbol %s, value=%" I64_SPEC "X\n", buffer, p64->st_value));
p64++;
}
for( curr = SymTables[TAB_EXT].head ; curr != NULL ;curr = curr->next ) {
if ( curr->sym.iscomm == FALSE && curr->sym.weak == TRUE )
continue;
len = Mangle( &curr->sym, buffer );
p64->st_name = strsize;
if ( curr->sym.iscomm == TRUE ) {
p64->st_info = ELF64_ST_INFO( STB_GLOBAL, STT_COMMON );
p64->st_value = curr->sym.total_size;
p64->st_shndx = SHN_COMMON;
} else {
#if OWELFIMPORT
p64->st_info = ( IsWeak( curr->sym ) ? ELF64_ST_INFO( STB_WEAK, STT_IMPORT ) : ELF64_ST_INFO( STB_GLOBAL, STT_IMPORT ) );
#else
p64->st_info = ( IsWeak( curr->sym ) ? ELF64_ST_INFO( STB_WEAK, STT_NOTYPE ) : ELF64_ST_INFO( STB_GLOBAL, STT_NOTYPE ) );
#endif
p64->st_value = curr->sym.offset;
p64->st_shndx = SHN_UNDEF;
}
strsize += len + 1;
DebugMsg(("set_symtab64, EXTERNAL: symbol %s, info=%X, shndx=%X, value=%" I64_SPEC "X\n", buffer, p64->st_info, p64->st_shndx, p64->st_value));
p64++;
}
#if ELFALIAS
for( curr = SymTables[TAB_ALIAS].head ; curr != NULL ;curr = curr->next ) {
len = Mangle( &curr->sym, buffer );
p64->st_name = strsize;
#if OWELFIMPORT
p64->st_info = ELF64_ST_INFO( STB_WEAK, STT_IMPORT );
#else
p64->st_info = ELF64_ST_INFO( STB_WEAK, STT_NOTYPE );
#endif
p64->st_value = 0;
p64->st_shndx = SHN_UNDEF;
strsize += len + 1;
DebugMsg(("set_symtab64, ALIASES: symbol %s, value=%" I64_SPEC "X\n", buffer, p64->st_value));
p64++;
}
#endif
for ( q = ModuleInfo.g.PubQueue.head; q; q = q->next ) {
sym = q->sym;
len = Mangle( sym, buffer );
curr = (struct dsym *)sym->segment;
if ( curr && curr->e.seginfo->segtype != SEGTYPE_CODE )
stt = STT_OBJECT;
else
stt = STT_FUNC;
p64->st_name = strsize;
p64->st_info = ELF64_ST_INFO( STB_GLOBAL, stt );
p64->st_value = sym->offset;
#if 1
if ( sym->state == SYM_INTERNAL )
if ( curr )
p64->st_shndx = GetSegIdx( &curr->sym );
else
p64->st_shndx = SHN_ABS;
else
p64->st_shndx = SHN_UNDEF;
#else#endif
strsize += len + 1;
DebugMsg(("set_symtab64, PUBLIC+LOCAL: symbol %s, info=%X, shndx=%X, value=%" I64_SPEC "X\n", buffer, p64->st_info, p64->st_shndx, p64->st_value));
p64++;
}
#if ADDSTARTLABEL
if ( ModuleInfo.g.start_label ) {
len = Mangle( ModuleInfo.g.start_label, buffer );
p64->st_name = strsize;
p64->st_info = ELF64_ST_INFO( STB_ENTRY, STT_FUNC );
p64->st_value = ModuleInfo.g.start_label->offset;
p64->st_shndx = GetSegIdx( ModuleInfo.g.start_label->segment );
strsize += len + 1;
DebugMsg(("set_symtab64, ENTRY: symbol %s, value=%" I64_SPEC "X\n", buffer, p64->st_value));
p64++;
}
#endif
return( strsize );
}
#endif
static void set_symtab_values( struct elfmod *em )
{
uint_32 strsize;
uint_32 entries;
struct dsym *curr;
struct qnode *q;
char *p2;
struct {
struct localname *head;
struct localname *tail;
} locals = { NULL, NULL };
struct localname *localscurr;
em->symindex = 1 + 1;
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next )
curr->sym.ext_idx = em->symindex++;
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
if ( curr->e.seginfo->num_relocs ) {
struct fixup *fix = curr->e.seginfo->FixupList.head;
for ( ; fix; fix = fix->nextrlc ) {
if ( fix->sym->variable ) {
fix->sym = fix->segment_var;
} else if ( ( fix->sym->state == SYM_INTERNAL ) &&
fix->sym->included == FALSE &&
fix->sym->ispublic == FALSE ) {
fix->sym->included = TRUE;
localscurr = LclAlloc( sizeof( struct localname ) );
localscurr->next = NULL;
localscurr->sym = fix->sym;
if (locals.tail) {
locals.tail->next = localscurr;
locals.tail = localscurr;
} else {
locals.head = locals.tail = localscurr;
}
fix->sym->ext_idx = em->symindex++;
}
}
}
}
DebugMsg(("set_symtab_values: index after sections: %u\n", em->symindex));
em->start_globals = em->symindex;
for( curr = SymTables[TAB_EXT].head ; curr != NULL ;curr = curr->next ) {
if ( curr->sym.iscomm == FALSE && curr->sym.weak == TRUE )
continue;
curr->sym.ext_idx = em->symindex++;
}
DebugMsg(("set_symtab_values: index after EXTERNALs: %u\n", em->symindex));
#if ELFALIAS
for( curr = SymTables[TAB_ALIAS].head ; curr != NULL ;curr = curr->next ) {
curr->sym.idx = em->symindex++;
}
DebugMsg(("set_symtab_values: index after ALIASES: %u\n", em->symindex));
#endif
for ( q = ModuleInfo.g.PubQueue.head; q; q = q->next ) {
q->sym->ext_idx = em->symindex++;
}
DebugMsg(("set_symtab_values: index after PUBLICs: %u\n", em->symindex));
entries = em->symindex;
#if ADDSTARTLABEL
if ( ModuleInfo.g.start_label )
entries++;
#endif
#if AMD64_SUPPORT
if ( ModuleInfo.defOfssize == USE64 )
strsize = set_symtab64( em, entries, locals.head );
else
#endif
strsize = set_symtab32( em, entries, locals.head );
DebugMsg(("set_symtab_values: creating string table, size=%X\n", strsize));
em->internal_segs[STRTAB_IDX].size = strsize;
em->internal_segs[STRTAB_IDX].data = LclAlloc( strsize );
memset( em->internal_segs[STRTAB_IDX].data, 0, strsize );
p2 = em->internal_segs[STRTAB_IDX].data;
*p2++ = NULLC;
strcpy( p2, em->srcname );
p2 += strlen( p2 ) + 1;
for ( localscurr = locals.head ; localscurr ; localscurr = localscurr->next ) {
p2 += Mangle( localscurr->sym, p2 ) + 1;
}
for( curr = SymTables[TAB_EXT].head ; curr != NULL ;curr = curr->next ) {
if ( curr->sym.iscomm == FALSE && curr->sym.weak == TRUE )
continue;
p2 += Mangle( &curr->sym, p2 ) + 1;
}
#if ELFALIAS
for( curr = SymTables[TAB_ALIAS].head ; curr != NULL ;curr = curr->next ) {
p2 += Mangle( &curr->sym, p2 ) + 1;
}
#endif
for ( q = ModuleInfo.g.PubQueue.head; q; q = q->next ) {
p2 += Mangle( q->sym, p2 ) + 1;
}
#if ADDSTARTLABEL
if ( ModuleInfo.g.start_label ) {
Mangle( ModuleInfo.g.start_label, p2 );
}
#endif
DebugMsg(("set_symtab_values: exit, symindex=%u\n", em->symindex ));
return;
}
static void set_shstrtab_values( struct elfmod *em )
{
int i;
struct dsym *curr;
char *p;
unsigned int size = 1;
char buffer[MAX_ID_LEN+1];
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
p = ( curr->e.seginfo->aliasname ? curr->e.seginfo->aliasname : ElfConvertSectionName( &curr->sym, buffer ) );
size += strlen( p ) + 1;
if ( curr->e.seginfo->FixupList.head )
size += strlen( p ) +
#if AMD64_SUPPORT
(( ModuleInfo.defOfssize == USE64 ) ? sizeof(".rela") : sizeof(".rel"));
#else
sizeof(".rel");
#endif
}
for ( i = 0; i < NUM_INTSEGS; i++ ) {
size += strlen( internal_segparms[i].name ) + 1;
}
em->internal_segs[SHSTRTAB_IDX].size = size;
em->internal_segs[SHSTRTAB_IDX].data = LclAlloc( size );
p = (char *)em->internal_segs[SHSTRTAB_IDX].data;
*p++ = NULLC;
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
strcpy( p, curr->e.seginfo->aliasname ? curr->e.seginfo->aliasname : ElfConvertSectionName( &curr->sym, buffer ) );
p += strlen( p ) + 1;
}
for ( i = 0; i < NUM_INTSEGS; i++ ) {
strcpy( p, internal_segparms[i].name );
p += strlen( p ) + 1;
}
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
if ( curr->e.seginfo->FixupList.head ) {
#if AMD64_SUPPORT
strcpy( p, (( ModuleInfo.defOfssize == USE64 ) ? ".rela": ".rel") );
#else
strcpy( p, ".rel" );
#endif
p += strlen( p );
strcpy( p, curr->e.seginfo->aliasname ? curr->e.seginfo->aliasname : ElfConvertSectionName( &curr->sym, buffer ) );
p += strlen( p ) + 1;
}
}
myassert( size == p - (char *)em->internal_segs[SHSTRTAB_IDX].data );
DebugMsg(("set_shstrtab_values: size=%X\n", size));
return;
}
static unsigned int get_relocation_count( struct dsym *curr )
{
unsigned relocs;
struct fixup *fix;
for ( relocs = 0, fix = curr->e.seginfo->FixupList.head; fix ; fix = fix->nextrlc, relocs++ );
return( relocs );
}
static unsigned int Get_Alignment( struct dsym *curr )
{
if ( curr->e.seginfo->alignment == MAX_SEGALIGNMENT )
return( 0 );
return( 1 << curr->e.seginfo->alignment );
}
static int elf_write_section_table32( struct module_info *modinfo, struct elfmod *em, uint_32 fileoffset )
{
int i;
struct dsym *curr;
uint_8 *p;
Elf32_Shdr shdr32;
DebugMsg(("elf_write_section_table32( fileofs=%X ): enter\n", fileoffset ));
fileoffset = (fileoffset + 0xF) & ~0xF;
set_shstrtab_values( em );
memset( &shdr32, 0, sizeof( shdr32) );
if ( fwrite( &shdr32, 1, sizeof(shdr32), CurrFile[OBJ] ) != sizeof(shdr32) )
WriteError();
p = (uint_8 *)em->internal_segs[SHSTRTAB_IDX].data;
p++;
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
memset( &shdr32, 0, sizeof(shdr32) );
shdr32.sh_name = p - (uint_8 *)em->internal_segs[SHSTRTAB_IDX].data;
p += strlen( (char *)p ) + 1;
if ( curr->e.seginfo->info == TRUE ) {
shdr32.sh_type = SHT_NOTE;
shdr32.sh_flags = 0;
} else {
shdr32.sh_type = ( curr->e.seginfo->segtype != SEGTYPE_BSS ? SHT_PROGBITS : SHT_NOBITS );
if ( curr->e.seginfo->segtype == SEGTYPE_CODE ) {
shdr32.sh_flags = SHF_EXECINSTR | SHF_ALLOC;
} else if ( curr->e.seginfo->readonly == TRUE ) {
shdr32.sh_flags = SHF_ALLOC;
} else if ( curr->e.seginfo->clsym && strcmp( curr->e.seginfo->clsym->name, "CONST" ) == 0 ) {
shdr32.sh_flags = SHF_ALLOC;
} else {
shdr32.sh_flags = SHF_WRITE | SHF_ALLOC;
}
}
#if 0#endif
shdr32.sh_addr = 0;
shdr32.sh_offset = fileoffset;
curr->e.seginfo->fileoffset = fileoffset;
shdr32.sh_size = curr->sym.max_offset;
shdr32.sh_link = 0;
shdr32.sh_info = 0;
shdr32.sh_addralign = Get_Alignment( curr );
shdr32.sh_entsize = 0;
if ( fwrite( &shdr32, 1, sizeof(shdr32), CurrFile[OBJ] ) != sizeof(shdr32) )
WriteError();
curr->e.seginfo->num_relocs = get_relocation_count( curr );
if ( shdr32.sh_type != SHT_NOBITS ) {
fileoffset += shdr32.sh_size;
fileoffset = (fileoffset + 0xF) & ~0xF;
}
DebugMsg(("elf_write_section_table32(%s): ofs=%X size=%X numrelocs=%u\n", curr->sym.name, shdr32.sh_offset, shdr32.sh_size, curr->e.seginfo->num_relocs));
}
set_symtab_values( em );
for ( i = 0; i < NUM_INTSEGS; i++ ) {
shdr32.sh_name = p - (uint_8 *)em->internal_segs[SHSTRTAB_IDX].data;
p += strlen( (char *)p ) + 1;
shdr32.sh_type = internal_segparms[i].type;
shdr32.sh_flags = 0;
shdr32.sh_offset = fileoffset;
em->internal_segs[i].fileoffset = fileoffset;
shdr32.sh_size = em->internal_segs[i].size;
if ( i == SYMTAB_IDX ) {
shdr32.sh_link = 1 + modinfo->g.num_segs + STRTAB_IDX;
shdr32.sh_info = em->start_globals;
shdr32.sh_addralign = 4;
shdr32.sh_entsize = sizeof( Elf32_Sym );
} else {
shdr32.sh_link = 0;
shdr32.sh_info = 0;
shdr32.sh_addralign = 1;
shdr32.sh_entsize = 0;
}
if ( fwrite( &shdr32, 1, sizeof( shdr32 ), CurrFile[OBJ] ) != sizeof( shdr32 ) )
WriteError();
fileoffset += shdr32.sh_size;
fileoffset = (fileoffset + 0xF) & ~0xF;
DebugMsg(("elf_write_section_table32(%s): ofs=%X size=%X\n", internal_segparms[i].name, shdr32.sh_offset, shdr32.sh_size));
}
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
if ( curr->e.seginfo->FixupList.head == NULL )
continue;
memset( &shdr32, 0, sizeof( shdr32 ) );
shdr32.sh_name = p - (uint_8 *)em->internal_segs[SHSTRTAB_IDX].data;
p += strlen( (char *)p ) + 1;
shdr32.sh_type = SHT_REL;
shdr32.sh_flags = 0;
shdr32.sh_addr = 0;
shdr32.sh_offset = fileoffset;
curr->e.seginfo->reloc_offset = fileoffset;
shdr32.sh_size = curr->e.seginfo->num_relocs * sizeof( Elf32_Rel );
shdr32.sh_link = 1 + modinfo->g.num_segs + SYMTAB_IDX;
shdr32.sh_info = GetSegIdx( curr->sym.segment );
shdr32.sh_addralign = 4;
shdr32.sh_entsize = sizeof( Elf32_Rel );
if ( fwrite( &shdr32, 1, sizeof( shdr32 ), CurrFile[OBJ] ) != sizeof( shdr32 ) )
WriteError();
fileoffset += shdr32.sh_size;
fileoffset = (fileoffset + 0xF) & ~0xF;
DebugMsg(("elf_write_section_table32(%s): relocs, ofs=%X size=%X\n", curr->sym.name, shdr32.sh_offset, shdr32.sh_size));
}
DebugMsg(("elf_write_section_table32: exit, final fileofs=%X\n", fileoffset ));
return( NOT_ERROR );
}
#if AMD64_SUPPORT
static int elf_write_section_table64( struct module_info *modinfo, struct elfmod *em, uint_32 fileoffset )
{
int i;
struct dsym *curr;
uint_8 *p;
Elf64_Shdr shdr64;
DebugMsg(("elf_write_section_table64( fileofs=%X ): enter\n", fileoffset ));
fileoffset = (fileoffset + 0xF) & ~0xF;
set_shstrtab_values( em );
memset( &shdr64, 0, sizeof( shdr64) );
if ( fwrite( &shdr64, 1, sizeof(shdr64), CurrFile[OBJ] ) != sizeof(shdr64) )
WriteError();
p = (uint_8 *)em->internal_segs[SHSTRTAB_IDX].data;
p++;
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
memset( &shdr64, 0, sizeof(shdr64) );
shdr64.sh_name = p - (uint_8 *)em->internal_segs[SHSTRTAB_IDX].data;
p += strlen( (char *)p ) + 1;
if ( curr->e.seginfo->info == TRUE ) {
shdr64.sh_type = SHT_NOTE;
shdr64.sh_flags = 0;
} else {
shdr64.sh_type = ( curr->e.seginfo->segtype != SEGTYPE_BSS ? SHT_PROGBITS : SHT_NOBITS );
if ( curr->e.seginfo->segtype == SEGTYPE_CODE ) {
shdr64.sh_flags = SHF_EXECINSTR | SHF_ALLOC;
} else if ( curr->e.seginfo->readonly == TRUE ) {
shdr64.sh_flags = SHF_ALLOC;
} else if ( curr->e.seginfo->clsym && strcmp( curr->e.seginfo->clsym->name, "CONST" ) == 0 ) {
shdr64.sh_flags = SHF_ALLOC;
} else {
shdr64.sh_flags = SHF_WRITE | SHF_ALLOC;
}
}
#if 0#endif
shdr64.sh_addr = 0;
shdr64.sh_offset = fileoffset;
curr->e.seginfo->fileoffset = fileoffset;
shdr64.sh_size = curr->sym.max_offset;
shdr64.sh_link = 0;
shdr64.sh_info = 0;
shdr64.sh_addralign = Get_Alignment( curr );
shdr64.sh_entsize = 0;
if ( fwrite( &shdr64, 1, sizeof(shdr64), CurrFile[OBJ] ) != sizeof(shdr64) )
WriteError();
curr->e.seginfo->num_relocs = get_relocation_count( curr );
if ( shdr64.sh_type != SHT_NOBITS ) {
fileoffset += shdr64.sh_size;
fileoffset = (fileoffset + 0xF) & ~0xF;
}
DebugMsg(("elf_write_section_table64(%s): ofs=%" I64_SPEC "X size=%" I64_SPEC "X numrelocs=%u\n", curr->sym.name, shdr64.sh_offset, shdr64.sh_size, curr->e.seginfo->num_relocs));
}
set_symtab_values( em );
for ( i = 0; i < NUM_INTSEGS; i++ ) {
shdr64.sh_name = p - (uint_8 *)em->internal_segs[SHSTRTAB_IDX].data;
p += strlen( (char *)p ) + 1;
shdr64.sh_type = internal_segparms[i].type;
shdr64.sh_flags = 0;
shdr64.sh_offset = fileoffset;
em->internal_segs[i].fileoffset = fileoffset;
shdr64.sh_size = em->internal_segs[i].size;
if ( i == SYMTAB_IDX ) {
shdr64.sh_link = 1 + modinfo->g.num_segs + STRTAB_IDX;
shdr64.sh_info = em->start_globals;
shdr64.sh_addralign = 4;
shdr64.sh_entsize = sizeof( Elf64_Sym );
} else {
shdr64.sh_link = 0;
shdr64.sh_info = 0;
shdr64.sh_addralign = 1;
shdr64.sh_entsize = 0;
}
if ( fwrite( &shdr64, 1, sizeof( shdr64 ), CurrFile[OBJ] ) != sizeof( shdr64 ) )
WriteError();
fileoffset += shdr64.sh_size;
fileoffset = (fileoffset + 0xF) & ~0xF;
DebugMsg(("elf_write_section_table64(%s): ofs=%" I64_SPEC "X size=%" I64_SPEC "X\n", internal_segparms[i].name, shdr64.sh_offset, shdr64.sh_size));
}
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
if ( curr->e.seginfo->FixupList.head == NULL )
continue;
memset( &shdr64, 0, sizeof(shdr64) );
shdr64.sh_name = p - (uint_8 *)em->internal_segs[SHSTRTAB_IDX].data;
p += strlen( (char *)p ) + 1;
shdr64.sh_type = SHT_RELA;
shdr64.sh_flags = 0;
shdr64.sh_addr = 0;
shdr64.sh_offset = fileoffset;
curr->e.seginfo->reloc_offset = fileoffset;
shdr64.sh_size = curr->e.seginfo->num_relocs * sizeof( Elf64_Rela );
shdr64.sh_link = 1 + modinfo->g.num_segs + SYMTAB_IDX;
shdr64.sh_info = GetSegIdx( curr->sym.segment );
shdr64.sh_addralign = 4;
shdr64.sh_entsize = sizeof( Elf64_Rela );
if ( fwrite( &shdr64, 1, sizeof( shdr64 ), CurrFile[OBJ] ) != sizeof( shdr64 ) )
WriteError();
fileoffset += shdr64.sh_size;
fileoffset = (fileoffset + 0xF) & ~0xF;
DebugMsg(("elf_write_section_table64(%s): relocs, ofs=%" I64_SPEC "X size=%" I64_SPEC "X\n", curr->sym.name, shdr64.sh_offset, shdr64.sh_size));
}
DebugMsg(("elf_write_section_table64: exit, final fileofs=%X\n", fileoffset ));
return( NOT_ERROR );
}
#endif
static void write_relocs32( struct elfmod *em, struct dsym *curr )
{
uint_8 elftype;
struct fixup *fixup;
Elf32_Rel reloc32;
DebugMsg(("write_relocs32: enter\n"));
for ( fixup = curr->e.seginfo->FixupList.head; fixup; fixup = fixup->nextrlc ) {
reloc32.r_offset = fixup->locofs;
switch ( fixup->type ) {
case FIX_OFF32: elftype = R_386_32; break;
case FIX_RELOFF32: elftype = R_386_PC32; break;
case FIX_OFF32_IMGREL: elftype = R_386_RELATIVE; break;
#if GNURELOCS
case FIX_OFF16: em->extused = TRUE; elftype = R_386_16; break;
case FIX_RELOFF16: em->extused = TRUE; elftype = R_386_PC16; break;
case FIX_OFF8: em->extused = TRUE; elftype = R_386_8; break;
case FIX_RELOFF8: em->extused = TRUE; elftype = R_386_PC8; break;
#endif
default:
DebugMsg(("write_relocs32(): unhandled reloc loc=%X type=%u idx=%u sym=%s\n",
fixup->locofs, fixup->type, fixup->sym->ext_idx, fixup->sym->name));
elftype = R_386_NONE;
if ( fixup->type < FIX_LAST ) {
EmitErr( INVALID_FIXUP_TYPE, ModuleInfo.fmtopt->formatname, fixup->type, curr->sym.name, fixup->locofs );
} else
EmitErr( UNKNOWN_FIXUP_TYPE, fixup->type, curr->sym.name, fixup->locofs );
}
reloc32.r_info = ELF32_R_INFO( fixup->sym->ext_idx, elftype );
if ( fwrite( &reloc32, 1, sizeof(reloc32), CurrFile[OBJ] ) != sizeof(reloc32) )
WriteError();
}
DebugMsg(("write_relocs32: exit\n"));
return;
}
#if AMD64_SUPPORT
static void write_relocs64( struct dsym *curr )
{
uint_8 elftype;
struct fixup *fixup;
Elf64_Rela reloc64;
DebugMsg(("write_relocs64: enter\n"));
for ( fixup = curr->e.seginfo->FixupList.head; fixup; fixup = fixup->nextrlc ) {
unsigned symidx = fixup->sym->ext_idx;
reloc64.r_offset = fixup->locofs;
reloc64.r_addend = - fixup->addbytes;
DebugMsg(("write_relocs64(): reloc loc=%X type=%u idx=%u sym=%s ofs=%X addbyt=%u\n",
fixup->locofs, fixup->type, fixup->sym->ext_idx, fixup->sym->name, fixup->offset, fixup->addbytes ));
switch ( fixup->type ) {
case FIX_RELOFF32:
#if 0#endif
reloc64.r_addend += *(int_32*)(curr->e.seginfo->CodeBuffer + fixup->locofs);
elftype = R_X86_64_PC32;
break;
case FIX_OFF64: elftype = R_X86_64_64; break;
case FIX_GOT64: elftype = R_X86_64_GLOB_DAT; break;
case FIX_PLT64: elftype = R_X86_64_JUMP_SLOT; break;
case FIX_OFF32_IMGREL: elftype = R_X86_64_RELATIVE; break;
case FIX_GOTPCREL64: elftype = R_X86_64_GOTPCREL; break;
case FIX_OFF32: elftype = R_X86_64_32; break;
case FIX_OFF16: elftype = R_X86_64_16; break;
case FIX_RELOFF16: elftype = R_X86_64_PC16; break;
case FIX_OFF8: elftype = R_X86_64_8; break;
case FIX_RELOFF8: elftype = R_X86_64_PC8; break;
default:
DebugMsg(("write_relocs64(): unhandled reloc loc=%X type=%u idx=%u sym=%s\n",
fixup->locofs, fixup->type, fixup->sym->ext_idx, fixup->sym->name));
elftype = R_X86_64_NONE;
if ( fixup->type < FIX_LAST ) {
EmitErr( INVALID_FIXUP_TYPE, ModuleInfo.fmtopt->formatname, fixup->type, curr->sym.name, fixup->locofs );
} else
EmitErr( UNKNOWN_FIXUP_TYPE, fixup->type, curr->sym.name, fixup->locofs );
}
reloc64.r_info = ELF64_R_INFO( symidx, elftype );
if ( fwrite( &reloc64, 1, sizeof( reloc64 ), CurrFile[OBJ] ) != sizeof(reloc64) )
WriteError();
}
DebugMsg(("write_relocs64: exit\n"));
return;
}
#endif
static ret_code elf_write_data( struct module_info *modinfo, struct elfmod *em )
{
struct dsym *curr;
uint_32 size;
int i;
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
size = curr->sym.max_offset - curr->e.seginfo->start_loc;
if ( curr->e.seginfo->segtype != SEGTYPE_BSS && size != 0 ) {
fseek( CurrFile[OBJ], curr->e.seginfo->fileoffset + curr->e.seginfo->start_loc, SEEK_SET );
if ( fwrite( curr->e.seginfo->CodeBuffer, 1, size, CurrFile[OBJ] ) != size )
WriteError();
}
}
for ( i = 0; i < NUM_INTSEGS; i++ ) {
if ( em->internal_segs[i].data ) {
fseek( CurrFile[OBJ], em->internal_segs[i].fileoffset, SEEK_SET );
if ( fwrite( em->internal_segs[i].data, 1, em->internal_segs[i].size, CurrFile[OBJ] ) != em->internal_segs[i].size )
WriteError();
}
}
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
if ( curr->e.seginfo->num_relocs ) {
fseek( CurrFile[OBJ], curr->e.seginfo->reloc_offset, SEEK_SET );
#if AMD64_SUPPORT
if ( modinfo->defOfssize == USE64 )
write_relocs64( curr );
else
#endif
write_relocs32( em, curr );
}
}
#if GNURELOCS
if ( em->extused ) {
EmitWarn( 2, ELF_GNU_EXTENSIONS_USED );
}
#endif
return( NOT_ERROR );
}
static ret_code elf_write_module( struct module_info *modinfo )
{
struct elfmod em;
DebugMsg(("elf_write_module: enter\n"));
memset( &em, 0, sizeof( em ) );
em.srcname = CurrFName[ASM];
#if 1
em.srcname += strlen( em.srcname );
while ( em.srcname > CurrFName[ASM] &&
*(em.srcname-1) != '/' &&
*(em.srcname-1) != '\\') em.srcname--;
#endif
fseek( CurrFile[OBJ], 0, SEEK_SET );
switch ( modinfo->defOfssize ) {
#if AMD64_SUPPORT
case USE64:
memcpy( &em.ehdr64.e_ident, ELF_SIGNATURE, ELF_SIGNATURE_LEN );
em.ehdr64.e_ident[EI_CLASS] = ELFCLASS64;
em.ehdr64.e_ident[EI_DATA] = ELFDATA2LSB;
em.ehdr64.e_ident[EI_VERSION] = EV_CURRENT;
em.ehdr64.e_ident[EI_OSABI] = modinfo->elf_osabi;
em.ehdr64.e_ident[EI_ABIVERSION] = 0;
em.ehdr64.e_type = ET_REL;
em.ehdr64.e_machine = EM_X86_64;
em.ehdr64.e_version = EV_CURRENT;
em.ehdr64.e_entry = 0;
em.ehdr64.e_phoff = 0;
em.ehdr64.e_shoff = sizeof( em.ehdr64 );
em.ehdr64.e_flags = 0;
em.ehdr64.e_ehsize = sizeof( em.ehdr64 );
em.ehdr64.e_phentsize = 0;
em.ehdr64.e_phnum = 0;
em.ehdr64.e_shentsize = sizeof( Elf64_Shdr );
em.ehdr64.e_shnum = 1 + modinfo->g.num_segs + 3 + get_num_reloc_sections();
em.ehdr64.e_shstrndx = 1 + modinfo->g.num_segs + SHSTRTAB_IDX;
if ( fwrite( &em.ehdr64, 1, sizeof( em.ehdr64 ), CurrFile[OBJ] ) != sizeof( em.ehdr64 ) )
WriteError();
elf_write_section_table64( modinfo, &em,
sizeof( Elf64_Ehdr ) + em.ehdr64.e_shnum * em.ehdr64.e_shentsize );
break;
#endif
default:
memcpy( &em.ehdr32.e_ident, ELF_SIGNATURE, ELF_SIGNATURE_LEN );
em.ehdr32.e_ident[EI_CLASS] = ELFCLASS32;
em.ehdr32.e_ident[EI_DATA] = ELFDATA2LSB;
em.ehdr32.e_ident[EI_VERSION] = EV_CURRENT;
em.ehdr32.e_ident[EI_OSABI] = modinfo->elf_osabi;
em.ehdr32.e_ident[EI_ABIVERSION] = 0;
em.ehdr32.e_type = ET_REL;
em.ehdr32.e_machine = EM_386;
em.ehdr32.e_version = EV_CURRENT;
em.ehdr32.e_entry = 0;
em.ehdr32.e_phoff = 0;
em.ehdr32.e_shoff = sizeof( em.ehdr32 );
em.ehdr32.e_flags = 0;
em.ehdr32.e_ehsize = sizeof( em.ehdr32 );
em.ehdr32.e_phentsize = 0;
em.ehdr32.e_phnum = 0;
em.ehdr32.e_shentsize = sizeof( Elf32_Shdr );
em.ehdr32.e_shnum = 1 + modinfo->g.num_segs + 3 + get_num_reloc_sections();
em.ehdr32.e_shstrndx = 1 + modinfo->g.num_segs + SHSTRTAB_IDX;
if ( fwrite( &em.ehdr32, 1, sizeof( em.ehdr32 ), CurrFile[OBJ] ) != sizeof( em.ehdr32 ) )
WriteError();
elf_write_section_table32( modinfo, &em,
sizeof( Elf32_Ehdr ) + em.ehdr32.e_shnum * em.ehdr32.e_shentsize );
};
elf_write_data( modinfo, &em );
DebugMsg(("elf_write_module: exit\n"));
return( NOT_ERROR );
}
void elf_init( struct module_info *modinfo )
{
modinfo->elf_osabi = ELFOSABI_NONE;
modinfo->g.WriteModule = elf_write_module;
#if 0#endif
return;
}
#endif