From: Roland McGrath Date: Sat, 13 Aug 2005 01:59:10 +0000 (+0000) Subject: libebl/ X-Git-Tag: elfutils-0.120~126 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=653d3763e986da9f1c8a92ff9103d85c534754cd;p=platform%2Fupstream%2Felfutils.git libebl/ 2005-08-12 Roland McGrath * libeblP.h (struct ebl): Add bss_plt_p hook. * eblopenbackend.c (default_bss_plt_p): New function. (fill_defaults): Use it. * eblbsspltp.c: New file. * Makefile.am (gen_SOURCES): Add it. * libebl.h: Declare ebl_bss_plt_p. * ppc_symbol.c (ppc_bss_plt_p): New function. * libebl_ppc.h: Declare it. * ppc_init.c (ppc_init): Use it. * ppc64_symbol.c (ppc64_bss_plt_p): New function. * libebl_ppc64.h: Declare it. * ppc64_init.c (ppc64_init): Use it. * ebl_check_special_symbol.c: New file. * Makefile.am (gen_SOURCES): Add it. * libebl.h: Declare ebl_check_special_symbol. * libeblP.h (struct ebl): Add check_special_symbol hook. * eblopenbackend.c (default_check_special_symbol): New function. (fill_defaults): Use it. * ppc_symbol.c (ppc_check_special_symbol): New function. * libebl_ppc.h: Add prototype. * ppc_init.c (ppc_init): Use it. * ppc64_symbol.c (ppc64_check_special_symbol): New function. * libebl_ppc64.h: Add prototype. * ppc64_init.c (ppc64_init): Use it. src/ 2005-08-12 Roland McGrath * elflint.c (check_symtab): Check that _GLOBAL_OFFSET_TABLE_ st_shndx refers to the right section if it's not SHN_ABS. Let ebl_check_special_symbol override _G_O_T_ value and size checks. * elflint.c (check_sections): Don't complain about a non-NOBITS section taking no segment space, if it's sh_size is 0. * elflint.c (check_sections): Use ebl_bss_plt_p to see if .plt should be PROGBITS or NOBITS. * elflint.c (check_symtab): Use ebl_check_special_symbol to override standard st_value and st_size checks. --- diff --git a/libebl/ChangeLog b/libebl/ChangeLog index 5553cc4..68ec221 100644 --- a/libebl/ChangeLog +++ b/libebl/ChangeLog @@ -1,3 +1,31 @@ +2005-08-12 Roland McGrath + + * libeblP.h (struct ebl): Add bss_plt_p hook. + * eblopenbackend.c (default_bss_plt_p): New function. + (fill_defaults): Use it. + * eblbsspltp.c: New file. + * Makefile.am (gen_SOURCES): Add it. + * libebl.h: Declare ebl_bss_plt_p. + * ppc_symbol.c (ppc_bss_plt_p): New function. + * libebl_ppc.h: Declare it. + * ppc_init.c (ppc_init): Use it. + * ppc64_symbol.c (ppc64_bss_plt_p): New function. + * libebl_ppc64.h: Declare it. + * ppc64_init.c (ppc64_init): Use it. + + * ebl_check_special_symbol.c: New file. + * Makefile.am (gen_SOURCES): Add it. + * libebl.h: Declare ebl_check_special_symbol. + * libeblP.h (struct ebl): Add check_special_symbol hook. + * eblopenbackend.c (default_check_special_symbol): New function. + (fill_defaults): Use it. + * ppc_symbol.c (ppc_check_special_symbol): New function. + * libebl_ppc.h: Add prototype. + * ppc_init.c (ppc_init): Use it. + * ppc64_symbol.c (ppc64_check_special_symbol): New function. + * libebl_ppc64.h: Add prototype. + * ppc64_init.c (ppc64_init): Use it. + 2005-08-07 Ulrich Drepper * ppc_init.c: Add support for new DT_PPC_* and R_PPC_* values. diff --git a/libebl/Makefile.am b/libebl/Makefile.am index eeac7e5..ead129b 100644 --- a/libebl/Makefile.am +++ b/libebl/Makefile.am @@ -48,7 +48,8 @@ gen_SOURCES = eblopenbackend.c eblclosebackend.c eblstrtab.c \ ebldynamictagcheck.c eblcorenotetypename.c eblobjnotetypename.c \ eblcorenote.c eblobjnote.c ebldebugscnp.c \ eblgotpcreloccheck.c eblcopyrelocp.c eblsectionstripp.c \ - eblelfclass.c eblelfdata.c eblelfmachine.c + eblelfclass.c eblelfdata.c eblelfmachine.c \ + ebl_check_special_symbol.c eblbsspltp.c libebl_a_SOURCES = $(gen_SOURCES) diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c index a104d73..f3ae7ab 100644 --- a/libebl/eblopenbackend.c +++ b/libebl/eblopenbackend.c @@ -153,6 +153,11 @@ static bool default_object_note (const char *name, uint32_t type, uint32_t descsz, const char *desc); static bool default_debugscn_p (const char *name); static bool default_copy_reloc_p (int reloc); +static bool default_check_special_symbol (Elf *elf, + const GElf_Sym *sym, + const char *name, + const GElf_Shdr *destshdr); +static bool default_bss_plt_p (Elf *elf); static void @@ -181,6 +186,8 @@ fill_defaults (Ebl *result) result->object_note = default_object_note; result->debugscn_p = default_debugscn_p; result->copy_reloc_p = default_copy_reloc_p; + result->check_special_symbol = default_check_special_symbol; + result->bss_plt_p = default_bss_plt_p; result->destr = default_destr; } @@ -553,3 +560,18 @@ default_copy_reloc_p (int reloc __attribute__ ((unused))) { return false; } + +static bool +default_check_special_symbol (Elf *elf __attribute__ ((unused)), + const GElf_Sym *sym __attribute__ ((unused)), + const char *name __attribute__ ((unused)), + const GElf_Shdr *destshdr __attribute__ ((unused))) +{ + return false; +} + +static bool +default_bss_plt_p (Elf *elf __attribute__ ((unused))) +{ + return false; +} diff --git a/libebl/libebl.h b/libebl/libebl.h index a59d4dd..4637344 100644 --- a/libebl/libebl.h +++ b/libebl/libebl.h @@ -112,6 +112,12 @@ extern const char *ebl_dynamic_tag_name (Ebl *ebl, int64_t tag, /* Check dynamic tag. */ extern bool ebl_dynamic_tag_check (Ebl *ebl, int64_t tag); +/* Check whether given symbol's st_value and st_size are OK despite failing + normal checks. */ +extern bool ebl_check_special_symbol (Ebl *ebl, + const GElf_Sym *sym, const char *name, + const GElf_Shdr *destshdr); + /* Return combined section header flags value. */ extern GElf_Word ebl_sh_flags_combine (Ebl *ebl, GElf_Word flags1, GElf_Word flags2); @@ -142,12 +148,14 @@ extern bool ebl_debugscn_p (Ebl *ebl, const char *name); /* Check whether given relocation is a copy relocation. */ extern bool ebl_copy_reloc_p (Ebl *ebl, int reloc); - -/* CHeck whether section should be stripped. */ +/* Check whether section should be stripped. */ extern bool ebl_section_strip_p (Ebl *ebl, const GElf_Ehdr *ehdr, const GElf_Shdr *shdr, const char *name, bool remove_comment, bool only_remove_debug); +/* Check if backend uses a bss PLT in this file. */ +extern bool ebl_bss_plt_p (Ebl *ebl); + /* ELF string table handling. */ struct Ebl_Strtab; diff --git a/libebl/libeblP.h b/libebl/libeblP.h index 9d47e8c..adf5191 100644 --- a/libebl/libeblP.h +++ b/libebl/libeblP.h @@ -105,6 +105,14 @@ struct ebl /* Check whether given relocation is a copy relocation. */ bool (*copy_reloc_p) (int); + /* Check whether given symbol's value is ok despite normal checks. */ + bool (*check_special_symbol) (Elf *elf, + const GElf_Sym *sym, const char *name, + const GElf_Shdr *destshdr); + + /* Check if backend uses a bss PLT in this file. */ + bool (*bss_plt_p) (Elf *elf); + /* Destructor for ELF backend handle. */ void (*destr) (struct ebl *); diff --git a/libebl/libebl_ppc.h b/libebl/libebl_ppc.h index e3c6d21..03df06d 100644 --- a/libebl/libebl_ppc.h +++ b/libebl/libebl_ppc.h @@ -50,4 +50,14 @@ extern bool ppc_dynamic_tag_check (int64_t tag); /* Check whether given relocation is a copy relocation. */ extern bool ppc_copy_reloc_p (int reloc); +/* Check whether given symbol's st_value and st_size are OK despite normal + checks. */ +extern bool ppc_check_special_symbol (Elf *elf, + const GElf_Sym *sym, const char *name, + const GElf_Shdr *destshdr); + +/* Check if backend uses a bss PLT in this file. */ +extern bool ppc_bss_plt_p (Elf *elf); + + #endif /* libebl_ppc.h */ diff --git a/libebl/libebl_ppc64.h b/libebl/libebl_ppc64.h index 148e224..d8d445f 100644 --- a/libebl/libebl_ppc64.h +++ b/libebl/libebl_ppc64.h @@ -50,4 +50,14 @@ extern bool ppc64_dynamic_tag_check (int64_t tag); /* Check whether given relocation is a copy relocation. */ extern bool ppc64_copy_reloc_p (int reloc); +/* Check whether given symbol's st_value and st_size are OK despite normal + checks. */ +extern bool ppc64_check_special_symbol (Elf *elf, + const GElf_Sym *sym, const char *name, + const GElf_Shdr *destshdr); + +/* Check if backend uses a bss PLT in this file. */ +extern bool ppc64_bss_plt_p (Elf *elf); + + #endif /* libebl_ppc.h */ diff --git a/libebl/ppc64_init.c b/libebl/ppc64_init.c index 347444c..c8235bb 100644 --- a/libebl/ppc64_init.c +++ b/libebl/ppc64_init.c @@ -39,6 +39,8 @@ ppc64_init (elf, machine, eh, ehlen) eh->dynamic_tag_name = ppc64_dynamic_tag_name; eh->dynamic_tag_check = ppc64_dynamic_tag_check; eh->copy_reloc_p = ppc64_copy_reloc_p; + eh->check_special_symbol = ppc64_check_special_symbol; + eh->bss_plt_p = ppc64_bss_plt_p; eh->destr = ppc64_destr; return MODVERSION; diff --git a/libebl/ppc64_symbol.c b/libebl/ppc64_symbol.c index 457e84e..ef0f5f7 100644 --- a/libebl/ppc64_symbol.c +++ b/libebl/ppc64_symbol.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -242,3 +243,28 @@ ppc64_copy_reloc_p (int reloc) { return reloc == R_PPC64_COPY; } + + +/* Check whether given symbol's st_size is ok despite normal check failing. */ +bool +ppc64_check_special_symbol (Elf *elf, + const GElf_Sym *sym __attribute__ ((unused)), + const char *name __attribute__ ((unused)), + const GElf_Shdr *destshdr) +{ + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + return false; + const char *sname = elf_strptr (elf, ehdr->e_shstrndx, destshdr->sh_name); + if (sname == NULL) + return false; + return !strcmp (sname, ".opd"); +} + +/* Check if backend uses a bss PLT in this file. */ +bool +ppc64_bss_plt_p (Elf *elf __attribute__ ((unused))) +{ + return true; +} diff --git a/libebl/ppc_init.c b/libebl/ppc_init.c index dca780b..d76b1b1 100644 --- a/libebl/ppc_init.c +++ b/libebl/ppc_init.c @@ -39,6 +39,8 @@ ppc_init (elf, machine, eh, ehlen) eh->dynamic_tag_name = ppc_dynamic_tag_name; eh->dynamic_tag_check = ppc_dynamic_tag_check; eh->copy_reloc_p = ppc_copy_reloc_p; + eh->check_special_symbol = ppc_check_special_symbol; + eh->bss_plt_p = ppc_bss_plt_p; eh->destr = ppc_destr; return MODVERSION; diff --git a/libebl/ppc_symbol.c b/libebl/ppc_symbol.c index e865eaa..8afabba 100644 --- a/libebl/ppc_symbol.c +++ b/libebl/ppc_symbol.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -201,3 +202,68 @@ ppc_copy_reloc_p (int reloc) { return reloc == R_PPC_COPY; } + +/* Check whether given symbol's value is ok despite failing normal checks. */ +bool +ppc_check_special_symbol (Elf *elf, + const GElf_Sym *sym, + const char *name, + const GElf_Shdr *destshdr) +{ + if (name == NULL) + return false; + + if (!strcmp (name, "_GLOBAL_OFFSET_TABLE_")) + { + return sym->st_value == destshdr->sh_addr + 4; + } + + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + return false; + const char *sname = elf_strptr (elf, ehdr->e_shstrndx, destshdr->sh_name); + if (sname == NULL) + return false; + + if (!strcmp (name, "_SDA_BASE_")) + return (!strcmp (sname, ".sdata") + && sym->st_value == destshdr->sh_addr + 0x8000 + && sym->st_size == 0); + + if (!strcmp (name, "_SDA2_BASE_")) + return (!strcmp (sname, ".sdata2") + && sym->st_value == destshdr->sh_addr + 0x8000 + && sym->st_size == 0); + + return false; +} + +/* Check if backend uses a bss PLT in this file. */ +bool +ppc_bss_plt_p (Elf *elf) +{ + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC) + { + Elf_Data *data = elf_getdata (scn, NULL); + if (data == NULL) + break; + for (unsigned int i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i) + { + GElf_Dyn dyn_mem; + GElf_Dyn *dyn = gelf_getdyn (data, i, &dyn_mem); + if (dyn == NULL) + break; + if (dyn->d_tag == DT_PPC_GOT) + return false; + } + } + } + + return true; +} diff --git a/src/ChangeLog b/src/ChangeLog index 7aae3f9..e353588 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,18 @@ +2005-08-12 Roland McGrath + + * elflint.c (check_symtab): Check that _GLOBAL_OFFSET_TABLE_ st_shndx + refers to the right section if it's not SHN_ABS. + Let ebl_check_special_symbol override _G_O_T_ value and size checks. + + * elflint.c (check_sections): Don't complain about a non-NOBITS + section taking no segment space, if it's sh_size is 0. + + * elflint.c (check_sections): Use ebl_bss_plt_p to see if .plt should + be PROGBITS or NOBITS. + + * elflint.c (check_symtab): Use ebl_check_special_symbol to override + standard st_value and st_size checks. + 2005-07-28 Roland McGrath * addr2line.c (options, parse_opt): Don't handle -e here. diff --git a/src/elflint.c b/src/elflint.c index ecf6a72..73a4061 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -713,12 +713,16 @@ section [%2d] '%s': symbol %zu: function in COMMON section is nonsense\n"), { if (GELF_ST_TYPE (sym->st_info) != STT_TLS) { - if ((sym->st_value - destshdr->sh_addr) > destshdr->sh_size) + bool special = ebl_check_special_symbol (ebl, sym, name, + destshdr); + if ((sym->st_value - destshdr->sh_addr) > destshdr->sh_size + && !special) ERROR (gettext ("\ section [%2d] '%s': symbol %zu: st_value out of bounds\n"), idx, section_name (ebl, idx), cnt); else if ((sym->st_value - destshdr->sh_addr + sym->st_size) - > destshdr->sh_size) + > destshdr->sh_size + && !special) ERROR (gettext ("\ section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"), idx, section_name (ebl, idx), cnt, @@ -821,59 +825,79 @@ section [%2d] '%s': symbol %zu: non-local section symbol\n"), { if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) { - /* Check that address and size match the global offset - table. We have to locate the GOT by searching for a - section named ".got". */ - Elf_Scn *gscn = NULL; - GElf_Addr addr = 0; - GElf_Xword size = 0; - bool found = false; - - while ((gscn = elf_nextscn (ebl->elf, gscn)) != NULL) + /* Check that address and size match the global offset table. */ + + GElf_Shdr destshdr_mem; + GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, xndx), + &destshdr_mem); + + if (destshdr == NULL && xndx == SHN_ABS) { - GElf_Shdr gshdr_mem; - GElf_Shdr *gshdr = gelf_getshdr (gscn, &gshdr_mem); - assert (gshdr != NULL); + /* In a DSO, we have to find the GOT section by name. */ - const char *sname = elf_strptr (ebl->elf, ehdr->e_shstrndx, - gshdr->sh_name); - if (sname != NULL) + Elf_Scn *gscn = NULL; + + Elf_Scn *gotscn = NULL; + while ((gscn = elf_nextscn (ebl->elf, gscn)) != NULL) { - if (strcmp (sname, ".got.plt") == 0) - { - addr = gshdr->sh_addr; - size = gshdr->sh_size; - found = true; - break; - } - if (strcmp (sname, ".got") == 0) + destshdr = gelf_getshdr (gscn, &destshdr_mem); + assert (destshdr != NULL); + const char *sname = elf_strptr (ebl->elf, + ehdr->e_shstrndx, + destshdr->sh_name); + if (sname != NULL) { - addr = gshdr->sh_addr; - size = gshdr->sh_size; - found = true; - /* Do not stop looking. There might be a - .got.plt section. */ + if (!strcmp (sname, ".got.plt")) + break; + if (!strcmp (sname, ".got")) + /* Do not stop looking. + There might be a .got.plt section. */ + gotscn = gscn; } + + destshdr = NULL; } + + if (destshdr == NULL && gotscn != NULL) + destshdr = gelf_getshdr (gotscn, &destshdr_mem); } - if (found) + const char *sname = (destshdr == NULL ? NULL + : elf_strptr (ebl->elf, ehdr->e_shstrndx, + destshdr->sh_name)); + if (sname == NULL) + ERROR (gettext ("\ +section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol refers to bad section\n"), + idx, section_name (ebl, idx)); + else if (strcmp (sname, ".got.plt") != 0 + && strcmp (sname, ".got") != 0) + ERROR (gettext ("\ +section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol refers to '%s' section\n"), + idx, section_name (ebl, idx), sname); + + if (destshdr != NULL) { /* Found it. */ - if (sym->st_value != addr) + + bool special = ebl_check_special_symbol (ebl, sym, name, + destshdr); + + if (sym->st_value != destshdr->sh_addr && !special) /* This test is more strict than the psABIs which usually allow the symbol to be in the middle of the .got section, allowing negative offsets. */ ERROR (gettext ("\ -section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol value %#" PRIx64 " does not match .got section address %#" PRIx64 "\n"), +section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol value %#" PRIx64 " does not match %s section address %#" PRIx64 "\n"), idx, section_name (ebl, idx), - (uint64_t) sym->st_value, (uint64_t) addr); + (uint64_t) sym->st_value, + sname, (uint64_t) destshdr->sh_addr); - if (!gnuld && sym->st_size != size) + if (!gnuld && sym->st_size != destshdr->sh_size && !special) ERROR (gettext ("\ -section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol size %" PRIu64 " does not match .got section size %" PRIu64 "\n"), +section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol size %" PRIu64 " does not match %s section size %" PRIu64 "\n"), idx, section_name (ebl, idx), - (uint64_t) sym->st_size, (uint64_t) size); + (uint64_t) sym->st_size, + sname, (uint64_t) destshdr->sh_size); } else ERROR (gettext ("\ @@ -2562,7 +2586,13 @@ cannot get section header for section [%2zu] '%s': %s\n"), char stbuf2[100]; char stbuf3[100]; - if (shdr->sh_type != special_sections[s].type + GElf_Word good_type = special_sections[s].type; + if (special_sections[s].namelen == sizeof ".plt" && + !memcmp (special_sections[s].name, ".plt", sizeof ".plt") + && ebl_bss_plt_p (ebl)) + good_type = SHT_NOBITS; + + if (shdr->sh_type != good_type && !(is_debuginfo && shdr->sh_type == SHT_NOBITS)) ERROR (gettext ("\ section [%2d] '%s' has wrong type: expected %s, is %s\n"), @@ -2759,7 +2789,9 @@ section [%2zu] '%s' has type NOBITS but is read from the file in segment of prog } else { - if (shdr->sh_offset >= phdr->p_offset + phdr->p_filesz) + const GElf_Off end = phdr->p_offset + phdr->p_filesz; + if (shdr->sh_offset > end || + (shdr->sh_offset == end && shdr->sh_size != 0)) ERROR (gettext ("\ section [%2zu] '%s' has not type NOBITS but is not read from the file in segment of program header entry %d\n"), cnt, section_name (ebl, cnt), pcnt);