int xreloc_relocate( xreloc xr ) { table *t = (table *) xr; int loc; int word; int mask; int err = 0; symbol *sym; symbol *rel = NULL; reloc *r; rel = findsym( t, REL_NAME ); rel->flags = FLAG_RELOCAT | FLAG_GLOBAL; rel->loc = 0; for( sym = t->syms; sym; sym = sym->next ) { if( sym->flags & FLAG_GLOBAL ) { /* symbols to be written to symbol table */ continue; } else if( sym->flags & FLAG_RELOCAT ) { /* symbols need to be relocated */ sym->flags |= FLAG_WRITTEN; for( r = sym->relocs; r; r = r->next ) { add_reloc( t, rel, r->loc, r->size, XRELOC_ABSOLUTE ); word = GETWORD( t->mem, r->loc ); mask = ( 1 << r->size ) - 1; loc = ( word & mask ) + sym->loc; if( loc & ~mask ) { fprintf( t->err, "error: relocation out of range for symbol '%s'\n", sym->name ); err = 1; } word = ( word & ~mask ) | ( loc & mask ); t->mem[r->loc] = word >> 8; t->mem[r->loc + 1] = word; } } else if( sym->loc != INV_ADDR ) { /* symbol is defined */
int xreloc_reloc( xreloc xr, int loc, int size, char *name, unsigned char flags ) { table *t = (table *) xr; symbol *sym; assert( t ); assert( name ); if( loc == INV_ADDR ) { fprintf( stderr, "error: invalid address '%x', object may be too big\n", INV_ADDR ); return 0; } sym = findsym( t, name ); assert( sym ); add_reloc( t, sym, loc, size, flags ); return 1; }
void write_elf(FILE *outfile, Elf *elf) { add_symtab(elf); add_reloc(elf); add_shstrtab(elf); // Section header String *sh = make_string(); for (int i = 0; i < 64; i++) o1(sh, 0); // NULL section header // Body String *content = make_string(); for (int i = 0; i < LIST_LEN(elf->sections); i++) { write_section(sh, content, LIST_REF(elf->sections, i), 64); } align(content, 16); // ELF header String *eh = make_string(); int numsect = LIST_LEN(elf->sections) + 1; out(eh, elf_ident, sizeof(elf_ident)); o2(eh, 1); // e_type = ET_REL o2(eh, 62); // e_machine = EM_X86_64 o4(eh, 1); // e_version = EV_CURRENT o8(eh, 0); // e_entry o8(eh, 0); // e_phoff o8(eh, STRING_LEN(content) + 64); // e_shoff; o4(eh, 0); // e_flags o2(eh, 64); // e_ehsize o2(eh, 0); // e_phentsize o2(eh, 0); // e_phnum o2(eh, 64); // e_shentsize o2(eh, numsect); // e_shnum o2(eh, elf->shnum); // e_shstrndx fwrite(STRING_BODY(eh), STRING_LEN(eh), 1, outfile); fwrite(STRING_BODY(content), STRING_LEN(content), 1, outfile); fwrite(STRING_BODY(sh), STRING_LEN(sh), 1, outfile); fclose(outfile); }
int xreloc_load_table( xreloc xr, int size, int base ) { table *t = (table *) xr; int i, ent, loc; short chksum = 0; int code_size = 0; symbol *sym; char buf[10]; assert( t ); assert( size >= 0 ); assert( base >= 0 ); assert( ( base + size ) <= XIS_MEM_SIZE ); if( size & 1 ) { /* Cannot have a valid table because size is odd */ return -1; } for( i = 0; i < size; i += 2 ) { chksum += GETWORD( t->mem, i + base ); } if( chksum ) { /* chksum failed, no table */ return -1; } i = GETWORD( t->mem, size + base - 4 ); if( i != XIS_VERSION ) { fprintf( t->err, "error: unknown version %x\n", i ); return 0; } ent = GETWORD( t->mem, size + base - 6 ) + base + 1; /* 1 is the padding */ code_size = GETWORD( t->mem, size + base - 6 ); while( t->mem[ent] && ( ent < ( base + size ) ) ) { if( !strcmp( REL_NAME, (char *)&t->mem[ent] ) ) { sprintf( buf, "%s%x", REL_NAME, t->rel_cnt ); t->rel_cnt++; sym = findsym( t, buf ); sym->flags = FLAG_RELOCAT; } else { sym = findsym( t, (char *) &t->mem[ent] ); } ent += strlen( (char *) &t->mem[ent] ) + 1; loc = GETWORD( t->mem, ent ); ent += 2; if( loc != INV_ADDR ) { if( sym->loc == INV_ADDR ) { sym->loc = loc + base; } else { fprintf( t->err, "error: Multiple instances of symbol '%s'\n", sym->name ); code_size = 0; } } for( loc = GETWORD( t->mem, ent ); loc != INV_ADDR; loc = GETWORD( t->mem, ent ) ) { ent += 2; i = t->mem[ent++] & 0xff; add_reloc( t, sym, loc + base, i, t->mem[ent++] ); } ent += 2; } return code_size; }