diff options
| author | Mark Wielaard <[email protected]> | 2014-06-14 17:15:37 +0200 |
|---|---|---|
| committer | Mark Wielaard <[email protected]> | 2014-06-22 13:47:48 +0200 |
| commit | c1c1c06e30f0b3b4ae66fcfec6318a93b8f31569 (patch) | |
| tree | e5b811236c230f2ea82749f0ad9c2c4ac1bcf396 /src | |
| parent | ba9e5156207e3c2bb85adc747376e774af3c0df6 (diff) | |
libebl: Add ebl_func_addr_mask plus ARM backend implementation.
The ARM EABI says that the zero bit of function symbol st_value indicates
whether the symbol points to a THUMB or ARM function. Also the return
value address in an unwind will contain the same extra bit to indicate
whether to return to a regular ARM or THUMB function. Add a new ebl
function to mask off such bits and turn a function value into a function
address so that we get the actual value that a function symbol or return
address points to. It isn't easily possible to reuse the existing
ebl_resolve_sym_value for this purpose, so we end up with another hook
that can be used from dwfl_module_getsym, handle_cfi and elflint.
Signed-off-by: Mark Wielaard <[email protected]>
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 4 | ||||
| -rw-r--r-- | src/elflint.c | 20 |
2 files changed, 17 insertions, 7 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 7e680361..30234237 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,7 @@ +2014-06-14 Mark Wielaard <[email protected]> + + * elflint (check_symtab): Use ebl_func_addr_mask on st_value. + 2014-05-27 Mark Wielaard <[email protected]> * readelf.c (print_debug): Skip section if name is NULL. diff --git a/src/elflint.c b/src/elflint.c index bf6d044b..5568c65c 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -768,12 +768,18 @@ section [%2d] '%s': symbol %zu: function in COMMON section is nonsense\n"), { GElf_Addr sh_addr = (ehdr->e_type == ET_REL ? 0 : destshdr->sh_addr); + GElf_Addr st_value; + if (GELF_ST_TYPE (sym->st_info) == STT_FUNC + || (GELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)) + st_value = sym->st_value & ebl_func_addr_mask (ebl); + else + st_value = sym->st_value; if (GELF_ST_TYPE (sym->st_info) != STT_TLS) { if (! ebl_check_special_symbol (ebl, ehdr, sym, name, destshdr)) { - if (sym->st_value - sh_addr > destshdr->sh_size) + if (st_value - sh_addr > destshdr->sh_size) { /* GNU ld has severe bugs. When it decides to remove empty sections it leaves symbols referencing them @@ -798,7 +804,7 @@ section [%2d] '%s': symbol %zu: function in COMMON section is nonsense\n"), section [%2d] '%s': symbol %zu: st_value out of bounds\n"), idx, section_name (ebl, idx), cnt); } - else if ((sym->st_value - sh_addr + else if ((st_value - sh_addr + sym->st_size) > destshdr->sh_size) ERROR (gettext ("\ section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"), @@ -818,12 +824,12 @@ section [%2d] '%s': symbol %zu: referenced section [%2d] '%s' does not have SHF_ { /* For object files the symbol value must fall into the section. */ - if (sym->st_value > destshdr->sh_size) + if (st_value > destshdr->sh_size) ERROR (gettext ("\ section [%2d] '%s': symbol %zu: st_value out of bounds of referenced section [%2d] '%s'\n"), idx, section_name (ebl, idx), cnt, (int) xndx, section_name (ebl, xndx)); - else if (sym->st_value + sym->st_size + else if (st_value + sym->st_size > destshdr->sh_size) ERROR (gettext ("\ section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"), @@ -852,20 +858,20 @@ section [%2d] '%s': symbol %zu: TLS symbol but no TLS program header entry\n"), } else { - if (sym->st_value + if (st_value < destshdr->sh_offset - phdr->p_offset) ERROR (gettext ("\ section [%2d] '%s': symbol %zu: st_value short of referenced section [%2d] '%s'\n"), idx, section_name (ebl, idx), cnt, (int) xndx, section_name (ebl, xndx)); - else if (sym->st_value + else if (st_value > (destshdr->sh_offset - phdr->p_offset + destshdr->sh_size)) ERROR (gettext ("\ section [%2d] '%s': symbol %zu: st_value out of bounds of referenced section [%2d] '%s'\n"), idx, section_name (ebl, idx), cnt, (int) xndx, section_name (ebl, xndx)); - else if (sym->st_value + sym->st_size + else if (st_value + sym->st_size > (destshdr->sh_offset - phdr->p_offset + destshdr->sh_size)) ERROR (gettext ("\ |
