#define YASM_WRITE_64Z_L(p, i) YASM_WRITE_64C_L(p, 0, i)
-typedef int(*func_accepts_reloc)(size_t val, yasm_symrec *wrt,
- yasm_symrec **ssyms);
+typedef int(*func_accepts_reloc)(size_t val, yasm_symrec *wrt);
typedef void(*func_write_symtab_entry)(unsigned char *bufp,
elf_symtab_entry *entry,
yasm_intnum *value_intn,
elf_section_index sindex);
typedef void(*func_handle_reloc_addend)(yasm_intnum *intn,
- elf_reloc_entry *reloc);
-typedef unsigned int(*func_map_reloc_info_to_type)(elf_reloc_entry *reloc,
- yasm_symrec **ssyms);
+ elf_reloc_entry *reloc,
+ unsigned long offset);
+typedef unsigned int(*func_map_reloc_info_to_type)(elf_reloc_entry *reloc);
typedef void(*func_write_reloc)(unsigned char *bufp,
elf_reloc_entry *reloc,
unsigned int r_type,
yasm_section *sect;
yasm_object *object;
unsigned long sindex;
+ yasm_symrec *GOT_sym;
} elf_objfmt_output_info;
typedef struct {
int retval;
reloc = elf_reloc_entry_create(sym, NULL,
- yasm_intnum_create_uint(bc->offset), 0, valsize);
+ yasm_intnum_create_uint(bc->offset), 0, valsize, 0);
if (reloc == NULL) {
yasm_error_set(YASM_ERROR_TYPE, N_("elf: invalid relocation size"));
return 1;
elf_secthead_append_reloc(info->sect, info->shead, reloc);
zero = yasm_intnum_create_uint(0);
- elf_handle_reloc_addend(zero, reloc);
+ elf_handle_reloc_addend(zero, reloc, 0);
retval = yasm_arch_intnum_tobytes(info->object->arch, zero, buf, destsize,
valsize, 0, bc, warn);
yasm_intnum_destroy(zero);
if (value->curpos_rel)
intn_val += offset;
+ /* Check for _GLOBAL_OFFSET_TABLE_ symbol reference */
reloc = elf_reloc_entry_create(sym, wrt,
yasm_intnum_create_uint(bc->offset + offset), value->curpos_rel,
- valsize);
+ valsize, sym == info->GOT_sym);
if (reloc == NULL) {
yasm_error_set(YASM_ERROR_TYPE,
N_("elf: invalid relocation (WRT or size)"));
}
if (reloc)
- elf_handle_reloc_addend(intn, reloc);
+ elf_handle_reloc_addend(intn, reloc, offset);
retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
valsize, 0, bc, warn);
yasm_intnum_destroy(intn);
info.objfmt_elf = objfmt_elf;
info.errwarns = errwarns;
info.f = f;
+ info.GOT_sym = yasm_symtab_get(object->symtab, "_GLOBAL_OFFSET_TABLE_");
/* Update filename strtab */
elf_strtab_entry_set_str(objfmt_elf->file_strtab_entry,
};
static int
-elf_x86_amd64_accepts_reloc(size_t val, yasm_symrec *wrt, yasm_symrec **ssyms)
+elf_x86_amd64_accepts_reloc(size_t val, yasm_symrec *wrt)
{
if (wrt) {
- size_t i;
- for (i=0; i<NELEMS(elf_x86_amd64_ssyms); i++) {
- if (wrt == ssyms[i] && val == elf_x86_amd64_ssyms[i].size)
- return 1;
- }
- return 0;
+ const elf_machine_ssym *ssym = (elf_machine_ssym *)
+ yasm_symrec_get_data(wrt, &elf_ssym_symrec_data);
+ if (!ssym || val != ssym->size)
+ return 0;
+ return 1;
}
return (val&(val-1)) ? 0 : ((val & (8|16|32|64)) != 0);
}
}
static void
-elf_x86_amd64_handle_reloc_addend(yasm_intnum *intn, elf_reloc_entry *reloc)
+elf_x86_amd64_handle_reloc_addend(yasm_intnum *intn,
+ elf_reloc_entry *reloc,
+ unsigned long offset)
{
/* .rela: copy value out as addend, replace original with 0 */
reloc->addend = yasm_intnum_copy(intn);
}
static unsigned int
-elf_x86_amd64_map_reloc_info_to_type(elf_reloc_entry *reloc,
- yasm_symrec **ssyms)
+elf_x86_amd64_map_reloc_info_to_type(elf_reloc_entry *reloc)
{
if (reloc->wrt) {
- size_t i;
- for (i=0; i<NELEMS(elf_x86_amd64_ssyms); i++) {
- if (reloc->wrt == ssyms[i] &&
- reloc->valsize == elf_x86_amd64_ssyms[i].size) {
- /* Force TLS type; this is required by the linker. */
- if (elf_x86_amd64_ssyms[i].sym_rel & ELF_SSYM_THREAD_LOCAL) {
- elf_symtab_entry *esym;
-
- esym = yasm_symrec_get_data(reloc->reloc.sym,
- &elf_symrec_data);
- if (esym)
- esym->type = STT_TLS;
- }
- /* Map PC-relative GOT to appropriate relocation */
- if (reloc->rtype_rel &&
- elf_x86_amd64_ssyms[i].reloc == R_X86_64_GOT32)
- return (unsigned char) R_X86_64_GOTPCREL;
- return (unsigned char) elf_x86_amd64_ssyms[i].reloc;
- }
+ const elf_machine_ssym *ssym = (elf_machine_ssym *)
+ yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data);
+ if (!ssym || reloc->valsize != ssym->size)
+ yasm_internal_error(N_("Unsupported WRT"));
+
+ /* Force TLS type; this is required by the linker. */
+ if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) {
+ elf_symtab_entry *esym;
+
+ esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data);
+ if (esym)
+ esym->type = STT_TLS;
}
- yasm_internal_error(N_("Unsupported WRT"));
+ /* Map PC-relative GOT to appropriate relocation */
+ if (reloc->rtype_rel && ssym->reloc == R_X86_64_GOT32)
+ return (unsigned char) R_X86_64_GOTPCREL;
+ return (unsigned char) ssym->reloc;
+ } else if (reloc->is_GOT_sym && reloc->valsize == 32) {
+ return (unsigned char) R_X86_64_GOTPC32;
+ } else if (reloc->is_GOT_sym && reloc->valsize == 64) {
+ return (unsigned char) R_X86_64_GOTPC64;
} else if (reloc->rtype_rel) {
switch (reloc->valsize) {
case 8: return (unsigned char) R_X86_64_PC8;
};
static int
-elf_x86_x86_accepts_reloc(size_t val, yasm_symrec *wrt, yasm_symrec **ssyms)
+elf_x86_x86_accepts_reloc(size_t val, yasm_symrec *wrt)
{
if (wrt) {
- size_t i;
- for (i=0; i<NELEMS(elf_x86_x86_ssyms); i++) {
- if (wrt == ssyms[i] && val == elf_x86_x86_ssyms[i].size)
- return 1;
- }
- return 0;
+ const elf_machine_ssym *ssym = (elf_machine_ssym *)
+ yasm_symrec_get_data(wrt, &elf_ssym_symrec_data);
+ if (!ssym || val != ssym->size)
+ return 0;
+ return 1;
}
return (val&(val-1)) ? 0 : ((val & (8|16|32)) != 0);
}
}
static void
-elf_x86_x86_handle_reloc_addend(yasm_intnum *intn, elf_reloc_entry *reloc)
+elf_x86_x86_handle_reloc_addend(yasm_intnum *intn,
+ elf_reloc_entry *reloc,
+ unsigned long offset)
{
+ int is_GOT = reloc->is_GOT_sym;
+
+ if (reloc->wrt) {
+ const elf_machine_ssym *ssym = (elf_machine_ssym *)
+ yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data);
+ if (!ssym || reloc->valsize != ssym->size)
+ yasm_internal_error(N_("Unsupported WRT"));
+ if (ssym->reloc == R_386_GOTPC)
+ is_GOT = 1;
+ }
+
+ if (is_GOT && reloc->valsize == 32 && offset != 0)
+ {
+ yasm_intnum *off_intn = yasm_intnum_create_uint(offset);
+ yasm_intnum_calc(intn, YASM_EXPR_ADD, off_intn);
+ yasm_intnum_destroy(off_intn);
+ }
return; /* .rel: Leave addend in intn */
}
static unsigned int
-elf_x86_x86_map_reloc_info_to_type(elf_reloc_entry *reloc,
- yasm_symrec **ssyms)
+elf_x86_x86_map_reloc_info_to_type(elf_reloc_entry *reloc)
{
if (reloc->wrt) {
- size_t i;
- for (i=0; i<NELEMS(elf_x86_x86_ssyms); i++) {
- if (reloc->wrt == ssyms[i] &&
- reloc->valsize == elf_x86_x86_ssyms[i].size) {
- /* Force TLS type; this is required by the linker. */
- if (elf_x86_x86_ssyms[i].sym_rel & ELF_SSYM_THREAD_LOCAL) {
- elf_symtab_entry *esym;
-
- esym = yasm_symrec_get_data(reloc->reloc.sym,
- &elf_symrec_data);
- if (esym)
- esym->type = STT_TLS;
- }
- return (unsigned char) elf_x86_x86_ssyms[i].reloc;
- }
+ const elf_machine_ssym *ssym = (elf_machine_ssym *)
+ yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data);
+ if (!ssym || reloc->valsize != ssym->size)
+ yasm_internal_error(N_("Unsupported WRT"));
+
+ /* Force TLS type; this is required by the linker. */
+ if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) {
+ elf_symtab_entry *esym;
+
+ esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data);
+ if (esym)
+ esym->type = STT_TLS;
}
- yasm_internal_error(N_("Unsupported WRT"));
+ return (unsigned char) ssym->reloc;
+ } else if (reloc->is_GOT_sym && reloc->valsize == 32) {
+ return (unsigned char) R_386_GOTPC;
} else if (reloc->rtype_rel) {
switch (reloc->valsize) {
case 8: return (unsigned char) R_386_PC8;
static void elf_symrec_data_destroy(/*@only@*/ void *d);
static void elf_symtab_entry_print(void *data, FILE *f, int indent_level);
+static void elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level);
const yasm_assoc_data_callback elf_symrec_data = {
elf_symrec_data_destroy,
elf_symtab_entry_print
};
+const yasm_assoc_data_callback elf_ssym_symrec_data = {
+ elf_symrec_data_destroy,
+ elf_ssym_symtab_entry_print
+};
+
extern elf_machine_handler
elf_machine_handler_x86_x86,
elf_machine_handler_x86_amd64;
elf_ssyms[i] = yasm_symtab_define_label(symtab,
elf_march->ssyms[i].name,
NULL, 0, 0);
+ yasm_symrec_add_data(elf_ssyms[i], &elf_ssym_symrec_data,
+ &elf_march->ssyms[i]);
}
}
yasm_symrec *wrt,
yasm_intnum *addr,
int rel,
- size_t valsize)
+ size_t valsize,
+ int is_GOT_sym)
{
elf_reloc_entry *entry;
if (!elf_march->accepts_reloc)
yasm_internal_error(N_("Unsupported machine for ELF output"));
- if (!elf_march->accepts_reloc(valsize, wrt, elf_ssyms))
+ if (!elf_march->accepts_reloc(valsize, wrt))
{
if (addr)
yasm_intnum_destroy(addr);
entry->valsize = valsize;
entry->addend = NULL;
entry->wrt = wrt;
+ entry->is_GOT_sym = is_GOT_sym;
return entry;
}
fprintf(f, "\n");
}
+static void
+elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level)
+{
+ /* TODO */
+}
+
elf_symtab_head *
elf_symtab_create()
{
}
void
-elf_handle_reloc_addend(yasm_intnum *intn, elf_reloc_entry *reloc)
+elf_handle_reloc_addend(yasm_intnum *intn,
+ elf_reloc_entry *reloc,
+ unsigned long offset)
{
if (!elf_march->handle_reloc_addend)
yasm_internal_error(N_("Unsupported machine for ELF output"));
- elf_march->handle_reloc_addend(intn, reloc);
+ elf_march->handle_reloc_addend(intn, reloc, offset);
}
unsigned long
vis = yasm_symrec_get_visibility(reloc->reloc.sym);
if (!elf_march->map_reloc_info_to_type)
yasm_internal_error(N_("Unsupported arch/machine for elf output"));
- r_type = elf_march->map_reloc_info_to_type(reloc, elf_ssyms);
+ r_type = elf_march->map_reloc_info_to_type(reloc);
bufp = buf;
if (!elf_march->write_reloc || !elf_march->reloc_entry_size)
R_X86_64_TLSLD = 20, /* word32, PC-rel offset to LD GOT block */
R_X86_64_DTPOFF32 = 21, /* word32, offset to TLS block */
R_X86_64_GOTTPOFF = 22, /* word32, PC-rel offset to IE GOT entry */
- R_X86_64_TPOFF32 = 23 /* word32, offset in initial TLS block */
+ R_X86_64_TPOFF32 = 23, /* word32, offset in initial TLS block */
+ R_X86_64_PC64 = 24, /* word64, PC relative */
+ R_X86_64_GOTOFF64 = 25, /* word64, offset to GOT */
+ R_X86_64_GOTPC32 = 26, /* word32, signed pc relative to GOT */
+ R_X86_64_GOT64 = 27, /* word64, GOT entry offset */
+ R_X86_64_GOTPCREL64 = 28, /* word64, signed pc relative to GOT entry */
+ R_X86_64_GOTPC64 = 29, /* word64, signed pc relative to GOT */
+ R_X86_64_GOTPLT64 = 30, /* like GOT64, but indicates PLT entry needed */
+ R_X86_64_PLTOFF64 = 31, /* word64, GOT relative offset to PLT entry */
+ R_X86_64_GOTPC32_TLSDESC = 34, /* GOT offset for TLS descriptor */
+ R_X86_64_TLSDESC_CALL = 35, /* Marker for call through TLS descriptor */
+ R_X86_64_TLSDESC = 36 /* TLS descriptor */
} elf_x86_64_relocation_type;
struct elf_secthead {
size_t valsize;
yasm_intnum *addend;
/*@null@*/ yasm_symrec *wrt;
+ int is_GOT_sym;
};
STAILQ_HEAD(elf_strtab_head, elf_strtab_entry);
extern const yasm_assoc_data_callback elf_section_data;
extern const yasm_assoc_data_callback elf_symrec_data;
+extern const yasm_assoc_data_callback elf_ssym_symrec_data;
const elf_machine_handler *elf_set_arch(struct yasm_arch *arch,
/*@null@*/ yasm_symrec *wrt,
yasm_intnum *addr,
int rel,
- size_t valsize);
+ size_t valsize,
+ int is_GOT_sym);
void elf_reloc_entry_destroy(void *entry);
/* strtab functions */
struct yasm_symrec *sym);
void elf_secthead_add_size(elf_secthead *shead, yasm_intnum *size);
char *elf_secthead_name_reloc_section(const char *basesect);
-void elf_handle_reloc_addend(yasm_intnum *intn, elf_reloc_entry *reloc);
+void elf_handle_reloc_addend(yasm_intnum *intn,
+ elf_reloc_entry *reloc,
+ unsigned long offset);
unsigned long elf_secthead_write_rel_to_file(FILE *f, elf_section_index symtab,
yasm_section *sect,
elf_secthead *esd,
EXTRA_DIST += modules/objfmts/elf/tests/gas32/elf_gas32_test.sh
EXTRA_DIST += modules/objfmts/elf/tests/gas32/elf_gas32_ssym.asm
EXTRA_DIST += modules/objfmts/elf/tests/gas32/elf_gas32_ssym.hex
+EXTRA_DIST += modules/objfmts/elf/tests/gas32/elf_gas32_got.asm
+EXTRA_DIST += modules/objfmts/elf/tests/gas32/elf_gas32_got.hex
--- /dev/null
+.text
+
+.extern a
+
+.globl tst
+tst:
+ call L1
+L1:
+ pop %eax
+ add $_GLOBAL_OFFSET_TABLE_+(.-L1), %eax
+ mov (a@GOT)(%eax), %eax
+ movl $5, (%eax)
+ ret
--- /dev/null
+7f
+45
+4c
+46
+01
+01
+01
+00
+00
+00
+00
+00
+00
+00
+00
+00
+01
+00
+03
+00
+01
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+30
+01
+00
+00
+00
+00
+00
+00
+34
+00
+00
+00
+00
+00
+28
+00
+06
+00
+01
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+e8
+00
+00
+00
+00
+58
+05
+02
+00
+00
+00
+8b
+80
+00
+00
+00
+00
+c7
+00
+05
+00
+00
+00
+c3
+07
+00
+00
+00
+0a
+06
+00
+00
+0d
+00
+00
+00
+03
+04
+00
+00
+00
+2e
+74
+65
+78
+74
+00
+2e
+72
+65
+6c
+2e
+74
+65
+78
+74
+00
+2e
+73
+74
+72
+74
+61
+62
+00
+2e
+73
+79
+6d
+74
+61
+62
+00
+2e
+73
+68
+73
+74
+72
+74
+61
+62
+00
+00
+00
+2d
+00
+61
+00
+74
+73
+74
+00
+5f
+47
+4c
+4f
+42
+41
+4c
+5f
+4f
+46
+46
+53
+45
+54
+5f
+54
+41
+42
+4c
+45
+5f
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+01
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+04
+00
+f1
+ff
+00
+00
+00
+00
+05
+00
+00
+00
+00
+00
+00
+00
+00
+00
+04
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+03
+00
+04
+00
+03
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+10
+00
+00
+00
+05
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+10
+00
+04
+00
+09
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+10
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+21
+00
+00
+00
+03
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+68
+00
+00
+00
+2b
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+11
+00
+00
+00
+03
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+94
+00
+00
+00
+1f
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+19
+00
+00
+00
+02
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+b4
+00
+00
+00
+70
+00
+00
+00
+02
+00
+00
+00
+04
+00
+00
+00
+04
+00
+00
+00
+10
+00
+00
+00
+01
+00
+00
+00
+01
+00
+00
+00
+06
+00
+00
+00
+00
+00
+00
+00
+40
+00
+00
+00
+18
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+10
+00
+00
+00
+00
+00
+00
+00
+07
+00
+00
+00
+09
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+58
+00
+00
+00
+10
+00
+00
+00
+03
+00
+00
+00
+04
+00
+00
+00
+04
+00
+00
+00
+08
+00
+00
+00