summaryrefslogtreecommitdiff
path: root/src/i386_ld.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/i386_ld.c')
-rw-r--r--src/i386_ld.c462
1 files changed, 321 insertions, 141 deletions
diff --git a/src/i386_ld.c b/src/i386_ld.c
index c79804cd..2702ef85 100644
--- a/src/i386_ld.c
+++ b/src/i386_ld.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2001.
@@ -214,8 +214,9 @@ elf_i386_initialize_plt (struct ld_state *statep, Elf_Scn *scn)
relocation routines) and one for each function we call in a DSO. */
data->d_size = (1 + statep->nplt) * PLT_ENTRY_SIZE;
data->d_buf = xcalloc (1, data->d_size);
- data->d_align = 8;
+ assert (data->d_type == ELF_T_BYTE);
data->d_off = 0;
+ data->d_align = 8;
statep->nplt_used = 1;
}
@@ -232,9 +233,10 @@ elf_i386_initialize_pltrel (struct ld_state *statep, Elf_Scn *scn)
elf_errmsg (-1));
/* One relocation per PLT entry. */
- data->d_size = statep->nplt * sizeof (Elf32_Rel);
- data->d_buf = xcalloc (1, data->d_size);
+ size_t size = statep->nplt * sizeof (Elf32_Rel);
+ data->d_buf = xcalloc (1, size);
data->d_type = ELF_T_REL;
+ data->d_size = size;
data->d_align = 4;
data->d_off = 0;
}
@@ -243,26 +245,45 @@ elf_i386_initialize_pltrel (struct ld_state *statep, Elf_Scn *scn)
static void
elf_i386_initialize_got (struct ld_state *statep, Elf_Scn *scn)
{
- Elf_Data *data;
-
- /* If we have no .plt we don't need the special entries we normally
- create for it. The other contents is created later. */
- if (statep->ngot + statep->nplt == 0)
- return;
+ /* If we come here we better need a GOT. */
+ assert (statep->ngot != 0);
- data = elf_newdata (scn);
+ Elf_Data *data = elf_newdata (scn);
if (data == NULL)
error (EXIT_FAILURE, 0, gettext ("cannot allocate GOT section: %s"),
elf_errmsg (-1));
- /* We construct the .got section in pieces. Here we only add the data
+ /* Just a single word per GOT entry is needed. */
+ size_t size = statep->ngot * sizeof (Elf32_Addr);
+ data->d_buf = xcalloc (1, size);
+ data->d_size = size;
+ data->d_type = ELF_T_WORD;
+ data->d_off = 0;
+ data->d_align = sizeof (Elf32_Addr);
+}
+
+
+static void
+elf_i386_initialize_gotplt (struct ld_state *statep, Elf_Scn *scn)
+{
+ /* If we come here we better need a PLT. */
+ assert (statep->nplt != 0);
+
+ Elf_Data *data = elf_newdata (scn);
+ if (data == NULL)
+ error (EXIT_FAILURE, 0, gettext ("cannot allocate GOTPLT section: %s"),
+ elf_errmsg (-1));
+
+ /* We construct the .got.plt section in pieces. Here we only add the data
structures which are used by the PLT. This includes three reserved
entries at the beginning (the first will contain a pointer to the
.dynamic section), and one word for each PLT entry. */
- data->d_size = (3 + statep->ngot + statep->nplt) * sizeof (Elf32_Addr);
- data->d_buf = xcalloc (1, data->d_size);
- data->d_align = sizeof (Elf32_Addr);
+ size_t size = (3 + statep->nplt) * sizeof (Elf32_Addr);
+ data->d_buf = xcalloc (1, size);
+ data->d_type = ELF_T_WORD;
+ data->d_size = size;
data->d_off = 0;
+ data->d_align = sizeof (Elf32_Addr);
}
@@ -274,7 +295,8 @@ static const unsigned char elf_i386_plt0_entry[PLT_ENTRY_SIZE] =
0, 0, 0, 0, /* replaced with address of .got + 4. */
0xff, 0x25, /* jmp indirect */
0, 0, 0, 0, /* replaced with address of .got + 8. */
- 0, 0, 0, 0 /* pad out to 16 bytes. */
+ 0x0f, 0x0b, /* ud2a, to prevent further decoding. */
+ 0, 0 /* pad out to 16 bytes. */
};
/* Type describing the first PLT entry in non-PIC. */
@@ -295,7 +317,8 @@ static const unsigned char elf_i386_pic_plt0_entry[PLT_ENTRY_SIZE] =
{
0xff, 0xb3, 4, 0, 0, 0, /* pushl 4(%ebx) */
0xff, 0xa3, 8, 0, 0, 0, /* jmp *8(%ebx) */
- 0, 0, 0, 0 /* pad out to 16 bytes. */
+ 0x0f, 0x0b, /* ud2a, to prevent further decoding. */
+ 0, 0 /* pad out to 16 bytes. */
};
/* Contents of all but the first PLT entry in executable. */
@@ -337,46 +360,47 @@ struct plt_entry
static void
elf_i386_finalize_plt (struct ld_state *statep, size_t nsym,
- size_t nsym_dyn __attribute__ ((unused)))
+ size_t nsym_local, struct symbol **ndxtosym)
{
+ if (unlikely (statep->nplt + statep->ngot == 0))
+ /* Nothing to be done. */
+ return;
+
Elf_Scn *scn;
XElf_Shdr_vardef (shdr);
Elf_Data *data;
- Elf_Data *symdata = NULL;
- Elf_Data *dynsymdata;
- size_t cnt;
const bool build_dso = statep->file_type == dso_file_type;
- if (unlikely (statep->nplt + statep->ngot == 0))
- /* Nothing to be done. */
- return;
-
- /* Get the address of the got section. */
- scn = elf_getscn (statep->outelf, statep->gotscnidx);
+ /* Get the address of the .got.plt section. */
+ scn = elf_getscn (statep->outelf, statep->gotpltscnidx);
xelf_getshdr (scn, shdr);
data = elf_getdata (scn, NULL);
assert (shdr != NULL && data != NULL);
+ /* The address points to the .got.plt section, not the .got section. */
Elf32_Addr gotaddr = shdr->sh_addr;
- /* Now create the initial values for the .got section. The first
- word contains the address of the .dynamic section. */
+ /* Now create the initial values for the .got.plt section. The
+ first word contains the address of the .dynamic section. The
+ second and third entry are left empty for use by the dynamic
+ linker. The following entries are pointers to the instructions
+ following the initial jmp instruction in the corresponding PLT
+ entry. */
xelf_getshdr (elf_getscn (statep->outelf, statep->dynamicscnidx), shdr);
assert (shdr != NULL);
((Elf32_Word *) data->d_buf)[0] = shdr->sh_addr;
- /* The second and third entry are left empty for use by the dynamic
- linker. The following entries are pointers to the instructions
- following the initial jmp instruction in the corresponding PLT
- entry. Since the first PLT entry is special the first used one
- has the index 1. */
+ /* The PLT contains code which a user of a function jumps to. The first
+ PLT entry is special, so the first used one has the index 1. */
scn = elf_getscn (statep->outelf, statep->pltscnidx);
- xelf_getshdr (scn, shdr);
- assert (shdr != NULL);
+ XElf_Shdr_vardef (pltshdr);
+ xelf_getshdr (scn, pltshdr);
+ assert (pltshdr != NULL);
- dynsymdata = elf_getdata (elf_getscn (statep->outelf, statep->dynsymscnidx),
- NULL);
+ Elf_Data *dynsymdata = elf_getdata (elf_getscn (statep->outelf,
+ statep->dynsymscnidx), NULL);
assert (dynsymdata != NULL);
+ Elf_Data *symdata = NULL;
if (statep->symscnidx != 0)
{
symdata = elf_getdata (elf_getscn (statep->outelf, statep->symscnidx),
@@ -384,48 +408,40 @@ elf_i386_finalize_plt (struct ld_state *statep, size_t nsym,
assert (symdata != NULL);
}
- for (cnt = 0; cnt < statep->nplt; ++cnt)
- {
- assert ((4 + cnt) * sizeof (Elf32_Word) <= data->d_size);
-
- /* Address in the PLT. */
- Elf32_Addr pltentryaddr = shdr->sh_addr + (1 + cnt) * PLT_ENTRY_SIZE;
-
- /* Point the GOT entry at the PLT entry, after the initial jmp. */
- ((Elf32_Word *) data->d_buf)[3 + cnt] = pltentryaddr + 6;
-
-
- /* If the symbol is defined, adjust the address. */
- if (((Elf32_Sym *) dynsymdata->d_buf)[1 + cnt].st_shndx != SHN_UNDEF)
- {
- /* The value of the symbol is the address of the corresponding PLT
- entry. Store the address, also for the normal symbol table if
- this is necessary. */
- ((Elf32_Sym *) dynsymdata->d_buf)[1 + cnt].st_value = pltentryaddr;
-
- if (symdata != NULL)
- ((Elf32_Sym *) symdata->d_buf)[nsym - statep->nplt + cnt].st_value
- = pltentryaddr;
- }
- }
-
/* Create the .plt section. */
scn = elf_getscn (statep->outelf, statep->pltscnidx);
- data = elf_getdata (scn, NULL);
- assert (data != NULL);
+ Elf_Data *pltdata = elf_getdata (scn, NULL);
+ assert (pltdata != NULL);
+
+ /* Also create the .rel.plt section data. It simply means relocations
+ addressing the corresponding entry in the .got.plt section. The
+ section name is misleading. */
+ scn = elf_getscn (statep->outelf, statep->pltrelscnidx);
+ xelf_getshdr (scn, shdr);
+ Elf_Data *reldata = elf_getdata (scn, NULL);
+ assert (shdr != NULL && reldata != NULL);
+
+ /* Update the sh_link to point to the section being modified. We
+ point it here (correctly) to the .got.plt section. Some linkers
+ (e.g., the GNU binutils linker) point to the .plt section. This
+ is wrong since the .plt section isn't modified even though the
+ name .rel.plt suggests that this is correct. */
+ shdr->sh_link = statep->dynsymscnidx;
+ shdr->sh_info = statep->gotpltscnidx;
+ (void) xelf_update_shdr (scn, shdr);
- /* Create the first entry. */
- assert (data->d_size >= PLT_ENTRY_SIZE);
+ /* Create the first entry of the .plt section. */
+ assert (pltdata->d_size >= PLT_ENTRY_SIZE);
if (build_dso)
/* Copy the entry. It's complete, no relocation needed. */
- memcpy (data->d_buf, elf_i386_pic_plt0_entry, PLT_ENTRY_SIZE);
+ memcpy (pltdata->d_buf, elf_i386_pic_plt0_entry, PLT_ENTRY_SIZE);
else
{
/* Copy the skeleton. */
- memcpy (data->d_buf, elf_i386_plt0_entry, PLT_ENTRY_SIZE);
+ memcpy (pltdata->d_buf, elf_i386_plt0_entry, PLT_ENTRY_SIZE);
/* And fill in the addresses. */
- struct plt0_entry *addr = (struct plt0_entry *) data->d_buf;
+ struct plt0_entry *addr = (struct plt0_entry *) pltdata->d_buf;
addr->gotp4_addr = target_bswap_32 (gotaddr + 4);
addr->gotp8_addr = target_bswap_32 (gotaddr + 8);
}
@@ -437,54 +453,68 @@ elf_i386_finalize_plt (struct ld_state *statep, size_t nsym,
const unsigned char *plt_template
= build_dso ? elf_i386_pic_plt_entry : elf_i386_plt_entry;
- for (cnt = 0; cnt < statep->nplt; ++cnt)
+ for (size_t idx = nsym_local; idx < nsym; ++idx)
{
- struct plt_entry *addr;
+ struct symbol *symbol = ndxtosym[idx];
+ if (symbol == NULL || symbol->type != STT_FUNC
+ || ndxtosym[idx]->outdynsymidx == 0
+ // XXX is the following test correct?
+ || ! ndxtosym[idx]->in_dso)
+ continue;
+
+ size_t pltidx = symbol->merge.value;
+
+ assert (pltidx > 0);
+ assert ((3 + pltidx) * sizeof (Elf32_Word) <= data->d_size);
+
+ /* Address in the PLT. */
+ Elf32_Addr pltentryaddr = (pltshdr->sh_addr + pltidx * PLT_ENTRY_SIZE);
+
+ /* Point the GOT entry at the PLT entry, after the initial jmp. */
+ ((Elf32_Word *) data->d_buf)[2 + pltidx] = pltentryaddr + 6;
+
+ /* If the symbol is defined, adjust the address. */
+ if (((Elf32_Sym *) dynsymdata->d_buf)[ndxtosym[idx]->outdynsymidx].st_shndx != SHN_UNDEF)
+ {
+ /* The value of the symbol is the address of the corresponding PLT
+ entry. Store the address, also for the normal symbol table if
+ this is necessary. */
+ ((Elf32_Sym *) dynsymdata->d_buf)[pltidx].st_value = pltentryaddr;
- /* Copy the template. */
- assert (data->d_size >= (2 + cnt) * PLT_ENTRY_SIZE);
- addr = (struct plt_entry *) ((char *) data->d_buf
- + (1 + cnt) * PLT_ENTRY_SIZE);
+ if (symdata != NULL)
+ {
+ assert(nsym - statep->nplt + (pltidx - 1) == idx);
+ ((Elf32_Sym *) symdata->d_buf)[nsym - statep->nplt
+ + (pltidx - 1)].st_value
+ = pltentryaddr;
+ }
+ }
+
+ /* Copy the PLT entry template. */
+ assert (pltdata->d_size >= (1 + pltidx) * PLT_ENTRY_SIZE);
+ struct plt_entry *addr = (struct plt_entry *) ((char *) pltdata->d_buf
+ + (pltidx
+ * PLT_ENTRY_SIZE));
memcpy (addr, plt_template, PLT_ENTRY_SIZE);
/* And once more, fill in the addresses. First the address of
this symbol in .got. */
addr->offset_got = target_bswap_32 (gotaddr_off
- + (3 + cnt) * sizeof (Elf32_Addr));
+ + (2 + pltidx) * sizeof (Elf32_Addr));
/* Offset into relocation table. */
- addr->push_imm = target_bswap_32 (cnt * sizeof (Elf32_Rel));
+ addr->push_imm = target_bswap_32 ((pltidx - 1) * sizeof (Elf32_Rel));
/* Offset to start of .plt. */
- addr->plt0_offset = target_bswap_32 (-(2 + cnt) * PLT_ENTRY_SIZE);
- }
+ addr->plt0_offset = target_bswap_32 (-(1 + pltidx) * PLT_ENTRY_SIZE);
- /* Create the .rel.plt section data. It simply means relocations
- addressing the corresponding entry in the .got section. The
- section name is misleading. */
- scn = elf_getscn (statep->outelf, statep->pltrelscnidx);
- xelf_getshdr (scn, shdr);
- data = elf_getdata (scn, NULL);
- assert (shdr != NULL && data != NULL);
- /* Update the sh_link to point to the section being modified. We
- point it here (correctly) to the .got section. Some linkers
- (e.g., the GNU binutils linker) point to the .plt section. This
- is wrong since the .plt section isn't modified even though the
- name .rel.plt suggests that this is correct. */
- shdr->sh_link = statep->dynsymscnidx;
- shdr->sh_info = statep->gotscnidx;
- (void) xelf_update_shdr (scn, shdr);
-
- for (cnt = 0; cnt < statep->nplt; ++cnt)
- {
XElf_Rel_vardef (rel);
-
- assert ((1 + cnt) * sizeof (Elf32_Rel) <= data->d_size);
- xelf_getrel_ptr (data, cnt, rel);
- rel->r_offset = gotaddr + (3 + cnt) * sizeof (Elf32_Addr);
+ assert (pltidx * sizeof (Elf32_Rel) <= reldata->d_size);
+ xelf_getrel_ptr (reldata, pltidx - 1, rel);
+ rel->r_offset = gotaddr + (2 + pltidx) * sizeof (Elf32_Addr);
/* The symbol table entries for the functions from DSOs are at
- the end of the symbol table. */
- rel->r_info = XELF_R_INFO (1 + cnt, R_386_JMP_SLOT);
- (void) xelf_update_rel (data, cnt, rel);
+ the beginning of the symbol table. */
+ rel->r_info = XELF_R_INFO (ndxtosym[idx]->outdynsymidx, R_386_JMP_SLOT);
+ (void) xelf_update_rel (reldata, pltidx - 1, rel);
}
}
@@ -533,13 +563,16 @@ elf_i386_count_relocations (struct ld_state *statep, struct scninfo *scninfo)
{
case R_386_GOT32:
if (! scninfo->fileinfo->symref[r_sym]->defined
- || scninfo->fileinfo->symref[r_sym]->in_dso)
- relsize += sizeof (Elf32_Rel);
+ || scninfo->fileinfo->symref[r_sym]->in_dso
+ || statep->file_type == dso_file_type)
+ {
+ relsize += sizeof (Elf32_Rel);
+ ++statep->nrel_got;
+ }
- /* This relocation is not emitted in the output file but
- requires a GOT entry. */
+ /* Even if this relocation is not emitted in the output
+ file it requires a GOT entry. */
++statep->ngot;
- ++statep->nrel_got;
/* FALLTHROUGH */
@@ -592,10 +625,9 @@ elf_i386_count_relocations (struct ld_state *statep, struct scninfo *scninfo)
If the symbol is not defined and we are not creating
a statically linked binary, then we need in any case
a PLT entry. */
- if (! scninfo->fileinfo->symref[r_sym]->defined)
+ if (! scninfo->fileinfo->symref[r_sym]->defined
+ && !statep->statically)
{
- assert (!statep->statically);
-
sym = scninfo->fileinfo->symref[r_sym];
sym->type = STT_FUNC;
sym->in_dso = 1;
@@ -614,7 +646,36 @@ elf_i386_count_relocations (struct ld_state *statep, struct scninfo *scninfo)
}
break;
+ case R_386_TLS_LDO_32:
+ if (statep->file_type != executable_file_type)
+ abort ();
+ /* We do not need a relocation in the output file. */
+ break;
+
+ case R_386_TLS_LE:
+ /* We never need a relocation in the output file. */
+ break;
+
+ case R_386_TLS_IE:
+ if (statep->file_type == dso_file_type)
+ error (EXIT_FAILURE, 0, gettext ("initial-executable TLS relocation cannot be used "));
+ if (!scninfo->fileinfo->symref[r_sym]->defined
+ || scninfo->fileinfo->symref[r_sym]->in_dso)
+ {
+ abort ();
+ }
+ break;
+
case R_386_TLS_GD:
+ if (statep->file_type != executable_file_type
+ || !scninfo->fileinfo->symref[r_sym]->defined
+ || scninfo->fileinfo->symref[r_sym]->in_dso)
+ {
+ abort ();
+ }
+ break;
+
+ case R_386_TLS_GOTIE:
case R_386_TLS_LDM:
case R_386_TLS_GD_32:
case R_386_TLS_GD_PUSH:
@@ -624,7 +685,6 @@ elf_i386_count_relocations (struct ld_state *statep, struct scninfo *scninfo)
case R_386_TLS_LDM_PUSH:
case R_386_TLS_LDM_CALL:
case R_386_TLS_LDM_POP:
- case R_386_TLS_LDO_32:
case R_386_TLS_IE_32:
case R_386_TLS_LE_32:
/* XXX */
@@ -666,15 +726,25 @@ elf_i386_create_relocations (struct ld_state *statep,
Elf32_Addr pltaddr = shdr->sh_addr;
Elf_Scn *gotscn = elf_getscn (statep->outelf, statep->gotscnidx);
- shdr = elf32_getshdr (gotscn);
+ // XXX Adjust the address, if necessary, for relro
+ Elf_Data *gotdata = NULL;
+ if (statep->need_got)
+ {
+ gotdata = elf_getdata (gotscn, NULL);
+ assert (gotdata != NULL);
+ }
+
+ Elf_Scn *gotpltscn = elf_getscn (statep->outelf, statep->gotpltscnidx);
+ shdr = elf32_getshdr (gotpltscn);
assert (shdr != NULL);
Elf32_Addr gotaddr = shdr->sh_addr;
Elf_Scn *reldynscn = elf_getscn (statep->outelf, statep->reldynscnidx);
Elf_Data *reldyndata = elf_getdata (reldynscn, NULL);
+ assert (reldyndata != NULL);
size_t nreldyn = 0;
-#define ngot_used (3 + statep->nplt + nreldyn)
+ size_t ngotconst = statep->nrel_got;
struct scninfo *first = statep->rellist->next;
struct scninfo *runp = first;
@@ -684,7 +754,7 @@ elf_i386_create_relocations (struct ld_state *statep,
Elf_Data *reldata = elf_getdata (runp->scn, NULL);
int nrels = rshdr->sh_size / rshdr->sh_entsize;
- /* We will need the following vlaues a couple of times. Help
+ /* We will need the following values a couple of times. Help
the compiler and improve readability. */
struct symbol **symref = runp->fileinfo->symref;
struct scninfo *scninfo = runp->fileinfo->scninfo;
@@ -718,7 +788,7 @@ elf_i386_create_relocations (struct ld_state *statep,
XElf_Sym_vardef (sym);
xelf_getsym (symdata, idx, sym);
- /* The value just depends on the position of the referenced
+ /* The value only depends on the position of the referenced
section in the output file and the addend. */
value = scninfo[sym->st_shndx].offset + sym->st_value;
}
@@ -728,22 +798,20 @@ elf_i386_create_relocations (struct ld_state *statep,
/* Symbol in ignored COMDAT group section. */
continue;
+ value = symref[idx]->merge.value;
if (symref[idx]->in_dso)
{
- /* MERGE.VALUE contains the PLT index. We have to
- add 1 since there is this one special PLT entry
- at the beginning. */
- assert (symref[idx]->merge.value != 0
- || symref[idx]->type != STT_FUNC);
- value = pltaddr + symref[idx]->merge.value * PLT_ENTRY_SIZE;
+ /* MERGE.VALUE contains the PLT index. If this is not for
+ a function the actual value will be computed later. */
+ assert (value != 0 || symref[idx]->type != STT_FUNC);
+ value = pltaddr + value * PLT_ENTRY_SIZE;
}
- else
- value = symref[idx]->merge.value;
}
/* Address of the relocated memory in the data buffer. */
- void *relloc = (char *) data->d_buf + rel->r_offset;
+ unsigned char *relloc = (unsigned char *) data->d_buf + rel->r_offset;
+ uint32_t thisgotidx;
switch (XELF_R_TYPE (rel->r_info))
{
/* These three cases can be handled together since the
@@ -779,6 +847,7 @@ elf_i386_create_relocations (struct ld_state *statep,
= XELF_R_INFO (symref[idx]->outdynsymidx, R_386_COPY);
(void) xelf_update_rel (reldyndata, nreldyn, rel2);
++nreldyn;
+ assert (nreldyn <= statep->nrel_got);
/* Update the symbol table record for the new
address. */
@@ -831,6 +900,7 @@ elf_i386_create_relocations (struct ld_state *statep,
= XELF_R_INFO (symref[idx]->outdynsymidx, R_386_32);
(void) xelf_update_rel (reldyndata, nreldyn, rel2);
++nreldyn;
+ assert (nreldyn <= statep->nrel_got);
value = 0;
}
@@ -838,31 +908,142 @@ elf_i386_create_relocations (struct ld_state *statep,
break;
case R_386_GOT32:
- store_4ubyte_unaligned (relloc, ngot_used * sizeof (Elf32_Addr));
+ if (! symref[idx]->defined || symref[idx]->in_dso)
+ {
+ thisgotidx = nreldyn++;
+ assert (thisgotidx < statep->nrel_got);
- /* Add a relocation to initialize the GOT entry. */
+ /* Add a relocation to initialize the GOT entry. */
#if NATIVE_ELF != 0
- xelf_getrel_ptr (reldyndata, nreldyn, rel2);
+ xelf_getrel_ptr (reldyndata, thisgotidx, rel2);
#else
- rel2 = &rel_mem;
+ rel2 = &rel_mem;
#endif
- rel2->r_offset = gotaddr + ngot_used * sizeof (Elf32_Addr);
- rel2->r_info
- = XELF_R_INFO (symref[idx]->outdynsymidx, R_386_GLOB_DAT);
- (void) xelf_update_rel (reldyndata, nreldyn, rel2);
- ++nreldyn;
+ rel2->r_offset = gotaddr + ((thisgotidx - statep->ngot)
+ * sizeof (Elf32_Addr));
+ rel2->r_info
+ = XELF_R_INFO (symref[idx]->outdynsymidx, R_386_GLOB_DAT);
+ (void) xelf_update_rel (reldyndata, thisgotidx, rel2);
+ }
+ else if (statep->file_type != dso_file_type)
+ {
+ thisgotidx = ngotconst++;
+ assert (thisgotidx < statep->ngot);
+
+ /* We have to use a GOT since the generated code
+ requires it but we know the address and therefore
+ do not need a relocation. */
+ ((uint32_t *) gotdata->d_buf)[thisgotidx] = value;
+ }
+ else
+ {
+ thisgotidx = nreldyn++;
+ assert (thisgotidx < statep->nrel_got);
+
+ // XXX generate a relative relocation.
+ abort ();
+ }
+
+ store_4ubyte_unaligned (relloc,
+ (thisgotidx - statep->ngot)
+ * sizeof (Elf32_Addr));
break;
case R_386_GOTOFF:
add_4ubyte_unaligned (relloc, value - gotaddr);
break;
+ case R_386_TLS_LE:
+ value = symref[idx]->merge.value - ld_state.tls_tcb;
+ store_4ubyte_unaligned (relloc, value);
+ break;
+
+ case R_386_TLS_IE:
+ if (symref[idx]->defined && !symref[idx]->in_dso)
+ {
+ /* The symbol is defined in the executable.
+ Perform the IE->LE optimization.
+ There are multiple versions, though.
+
+ First version: mov ADDR,REG. */
+ if (relloc[-2] == 0x8b
+ && ((relloc[-1] & 0xc7) == 0x05))
+ {
+ relloc[-2] = 0xc7;
+ relloc[-1] = 0xc0 | ((relloc[-1] >> 3) & 7);
+ store_4ubyte_unaligned (relloc, (symref[idx]->merge.value
+ - ld_state.tls_tcb));
+ }
+ else
+ {
+ abort ();
+ }
+ }
+ else
+ {
+ abort ();
+ }
+ break;
+
+ case R_386_TLS_LDO_32:
+ value = symref[idx]->merge.value - ld_state.tls_start;
+ store_4ubyte_unaligned (relloc, value);
+ break;
+
+ case R_386_TLS_GD:
+ if (ld_state.file_type == executable_file_type)
+ {
+ if (symref[idx]->defined && !symref[idx]->in_dso)
+ {
+ /* The symbol is defined in the executable.
+ Perform the GD->LE optimization. */
+ static const char gd_to_le[] =
+ {
+ /* mov %gs:0x0,%eax */
+ 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00,
+ /* sub $OFFSET,%eax */
+ 0x81, 0xe8
+ };
+#ifndef NDEBUG
+ static const char gd_text[] =
+ {
+ /* lea 0x0(,%ebx,1),%eax */
+ 0x8d, 0x04, 0x1d, 0x00, 0x00, 0x00, 0x00,
+ /* call ___tls_get_addr */
+ 0xe8
+ };
+ assert (memcmp (relloc - 3, gd_text, sizeof (gd_text))
+ == 0);
+#endif
+ relloc = mempcpy (relloc - 3, gd_to_le,
+ sizeof (gd_to_le));
+ value = ld_state.tls_tcb- symref[idx]->merge.value;
+ store_4ubyte_unaligned (relloc, value);
+
+ /* We have to skip over the next relocation which is
+ the matching R_i386_PLT32 for __tls_get_addr. */
+ ++cnt;
+#ifndef NDEBUG
+ assert (cnt < nrels);
+ XElf_Off old_offset = rel->r_offset;
+ xelf_getrel (reldata, cnt, rel);
+ assert (rel != NULL);
+ assert (XELF_R_TYPE (rel->r_info) == R_386_PLT32);
+ idx = XELF_R_SYM (rel->r_info);
+ assert (strcmp (symref[idx]->name, "___tls_get_addr")
+ == 0);
+ assert (old_offset + 5 == rel->r_offset);
+#endif
+
+ break;
+ }
+ }
+ abort ();
+ break;
+
case R_386_32PLT:
case R_386_TLS_TPOFF:
- case R_386_TLS_IE:
case R_386_TLS_GOTIE:
- case R_386_TLS_LE:
- case R_386_TLS_GD:
case R_386_TLS_LDM:
case R_386_16:
case R_386_PC16:
@@ -876,11 +1057,9 @@ elf_i386_create_relocations (struct ld_state *statep,
case R_386_TLS_LDM_PUSH:
case R_386_TLS_LDM_CALL:
case R_386_TLS_LDM_POP:
- case R_386_TLS_LDO_32:
case R_386_TLS_IE_32:
case R_386_TLS_LE_32:
// XXX For now fall through
- printf("ignored relocation %d\n", (int) XELF_R_TYPE (rel->r_info));
break;
case R_386_NONE:
@@ -917,6 +1096,7 @@ elf_i386_ld_init (struct ld_state *statep)
statep->callbacks.initialize_pltrel = elf_i386_initialize_pltrel;
statep->callbacks.initialize_got = elf_i386_initialize_got;
+ statep->callbacks.initialize_gotplt = elf_i386_initialize_gotplt;
statep->callbacks.finalize_plt = elf_i386_finalize_plt;