diff options
author | Nick Clifton <nickc@redhat.com> | 2014-04-11 16:02:52 +0100 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2014-04-11 16:02:52 +0100 |
commit | 32ae0d80cd430150ad9536aa160f34f504e129bc (patch) | |
tree | 76b9dab3571164bcc1e07302277c471a07ae7f68 /bfd/peXXigen.c | |
parent | 58a84dcf29b735ee776536b4c51ba90b51612b71 (diff) | |
download | gdb-32ae0d80cd430150ad9536aa160f34f504e129bc.zip gdb-32ae0d80cd430150ad9536aa160f34f504e129bc.tar.gz gdb-32ae0d80cd430150ad9536aa160f34f504e129bc.tar.bz2 |
PE32+ binaries that use addresses > 1^32 have a problem in that the linker
converts some address expressions into absolute values, but the PE format
only stores absolutes as 32-bits. This is a partial solution which attempts
to convert such absolute values back to section relative ones instead. It
fails for symbols like __image_base and ImageBase__, but it is unclear as to
whether these values are ever actually used by applications.
PR ld/16821
* peXXigen.c (abs_finder): New function.
(_bfd_XXi_swap_sym_out): For absolute symbols with values larger
than 1^32 try to convert them into section relative values
instead.
Diffstat (limited to 'bfd/peXXigen.c')
-rw-r--r-- | bfd/peXXigen.c | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c index ea7846f..36d90cc 100644 --- a/bfd/peXXigen.c +++ b/bfd/peXXigen.c @@ -207,6 +207,14 @@ _bfd_XXi_swap_sym_in (bfd * abfd, void * ext1, void * in1) #endif } +static bfd_boolean +abs_finder (bfd * abfd ATTRIBUTE_UNUSED, asection * sec, void * data) +{ + bfd_vma abs_val = * (bfd_vma *) data; + + return (sec->vma <= abs_val) && ((sec->vma + (1L << 32)) > abs_val); +} + unsigned int _bfd_XXi_swap_sym_out (bfd * abfd, void * inp, void * extp) { @@ -221,6 +229,29 @@ _bfd_XXi_swap_sym_out (bfd * abfd, void * inp, void * extp) else memcpy (ext->e.e_name, in->_n._n_name, SYMNMLEN); + /* The PE32 and PE32+ formats only use 4 bytes to hold the value of a + symbol. This is a problem on 64-bit targets where we can generate + absolute symbols with values >= 1^32. We try to work around this + problem by finding a section whose base address is sufficient to + reduce the absolute value to < 1^32, and then transforming the + symbol into a section relative symbol. This of course is a hack. */ + if (sizeof (in->n_value) > 4 + && in->n_value > ((1L << 32) - 1) + && in->n_scnum == -1) + { + asection * sec; + + sec = bfd_sections_find_if (abfd, abs_finder, & in->n_value); + if (sec) + { + in->n_value -= sec->vma; + in->n_scnum = sec->target_index; + } + /* else: FIXME: The value is outside the range of any section. This + happens for __image_base__ and __ImageBase__ and maybe some other + symbols as well. We should find a way to handle these values. */ + } + H_PUT_32 (abfd, in->n_value, ext->e_value); H_PUT_16 (abfd, in->n_scnum, ext->e_scnum); |