diff options
| author | Roland McGrath <[email protected]> | 2005-08-13 01:59:10 +0000 |
|---|---|---|
| committer | Roland McGrath <[email protected]> | 2005-08-13 01:59:10 +0000 |
| commit | 653d3763e986da9f1c8a92ff9103d85c534754cd (patch) | |
| tree | 66c2402ec55cf778e36e98c52e5c5d5c4e9aae25 /src/elflint.c | |
| parent | 1c83bf1fd46b74492297694b642df36d18c6e7b5 (diff) | |
libebl/
2005-08-12 Roland McGrath <[email protected]>
* 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 <[email protected]>
* 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.
Diffstat (limited to 'src/elflint.c')
| -rw-r--r-- | src/elflint.c | 110 |
1 files changed, 71 insertions, 39 deletions
diff --git a/src/elflint.c b/src/elflint.c index ecf6a723..73a4061a 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); |
