diff options
| author | Ulrich Drepper <[email protected]> | 2008-02-23 06:50:01 +0000 |
|---|---|---|
| committer | Ulrich Drepper <[email protected]> | 2008-02-23 06:50:01 +0000 |
| commit | 834de6f38901b6add14b6f5f7dda8550638d98ec (patch) | |
| tree | c6d7a7e7d25e33ac5a1e0c7a7cd650324298b028 /src | |
| parent | 658094acf8d506867e62c10f70c51f65b8f7a829 (diff) | |
Add missing file
Add more TLS support for x86 linker.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 6 | ||||
| -rw-r--r-- | src/i386_ld.c | 102 | ||||
| -rw-r--r-- | src/ld.c | 3 | ||||
| -rw-r--r-- | src/ldgeneric.c | 10 |
4 files changed, 113 insertions, 8 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index f28c7006..71b82b1e 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2008-02-03 Ulrich Drepper <[email protected]> + + * i386_ld.c (elf_i386_count_relocations): Implement R_386_TLS_GD + when linked into executable. + (elf_i386_create_relocations): Likewise. + 2008-02-20 Roland McGrath <[email protected]> * readelf.c (print_attributes): New function. diff --git a/src/i386_ld.c b/src/i386_ld.c index c123d823..2702ef85 100644 --- a/src/i386_ld.c +++ b/src/i386_ld.c @@ -649,6 +649,7 @@ elf_i386_count_relocations (struct ld_state *statep, struct scninfo *scninfo) 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: @@ -656,8 +657,25 @@ elf_i386_count_relocations (struct ld_state *statep, struct scninfo *scninfo) break; case R_386_TLS_IE: - case R_386_TLS_GOTIE: + 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: @@ -791,7 +809,7 @@ elf_i386_create_relocations (struct ld_state *statep, } /* 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)) @@ -940,16 +958,92 @@ elf_i386_create_relocations (struct ld_state *statep, 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_GD: case R_386_TLS_LDM: case R_386_16: case R_386_PC16: @@ -507,7 +507,8 @@ replace_args (int argc, char *argv[]) } args[] = { { "-export-dynamic", "--export-dynamic" }, - { "-dynamic-linker", "--dynamic-linker" } + { "-dynamic-linker", "--dynamic-linker" }, + { "-static", "--static" }, }; const size_t nargs = sizeof (args) / sizeof (args[0]); diff --git a/src/ldgeneric.c b/src/ldgeneric.c index e0cc4b48..8df2a57e 100644 --- a/src/ldgeneric.c +++ b/src/ldgeneric.c @@ -1108,6 +1108,7 @@ add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype) size_t nsymbols = 0; size_t nlocalsymbols = 0; bool has_merge_sections = false; + bool has_tls_symbols = false; /* Unless we have different information we assume the code needs an executable stack. */ enum execstack execstack = execstack_true; @@ -1164,6 +1165,7 @@ add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype) /* Check whether this section is marked as merge-able. */ has_merge_sections |= (shdr->sh_flags & SHF_MERGE) != 0; + has_tls_symbols |= (shdr->sh_flags & SHF_TLS) != 0; /* Get the ELF section header and data. */ /* Make the file structure available. */ @@ -1392,7 +1394,7 @@ add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype) /* In case this file contains merge-able sections we have to locate the symbols which are in these sections. */ fileinfo->has_merge_sections = has_merge_sections; - if (likely (has_merge_sections)) + if (likely (has_merge_sections || has_tls_symbols)) { fileinfo->symref = (struct symbol **) obstack_calloc (&ld_state.smem, @@ -1424,8 +1426,9 @@ add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype) if (XELF_ST_TYPE (sym->st_info) != STT_SECTION && (shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE) - && (SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_flags - & SHF_MERGE)) + && ((SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_flags + & SHF_MERGE) + || XELF_ST_TYPE (sym->st_info) == STT_TLS)) { /* Create a symbol record for this symbol and add it to the list for this section. */ @@ -1437,6 +1440,7 @@ add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype) newp->symidx = cnt; newp->scndx = shndx; newp->file = fileinfo; + newp->defined = 1; fileinfo->symref[cnt] = newp; if (fileinfo->scninfo[shndx].symbols == NULL) |
