1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-20 11:11:24 +00:00

The ADDR16 relocations were assuming that non-local symbols had an

addend of 0. This isn't correct, and was quite easy to break by
referring to the address of an element within a structure.

 However, fixing this exposed the fact that symbol lookups for
local variables were returning the base of the section they
were contained in. This case is detected by comparing the return
value from elf_lookup() to the relocbase+addend value: if it is
lesser, but greater than relocbase, then relocbase+addend is
taken to be the authoritative value.

bug reported by:  gallatin
This commit is contained in:
Peter Grehan 2004-07-23 00:46:05 +00:00
parent a7092dac2e
commit 163fac2c58
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=132562

View File

@ -147,24 +147,34 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
break;
case R_PPC_ADDR16_LO: /* #lo(S) */
if (addend != 0) {
addr = relocbase + addend;
} else {
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
}
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
/*
* addend values are sometimes relative to sections
* (i.e. .rodata) in rela, where in reality they
* are relative to relocbase. Detect this condition.
*/
if (addr > relocbase && addr <= (relocbase + addend))
addr = relocbase + addend;
else
addr += addend;
*hwhere = addr & 0xffff;
break;
case R_PPC_ADDR16_HA: /* #ha(S) */
if (addend != 0) {
addr = relocbase + addend;
} else {
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
}
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
/*
* addend values are sometimes relative to sections
* (i.e. .rodata) in rela, where in reality they
* are relative to relocbase. Detect this condition.
*/
if (addr > relocbase && addr <= (relocbase + addend))
addr = relocbase + addend;
else
addr += addend;
*hwhere = ((addr >> 16) + ((addr & 0x8000) ? 1 : 0))
& 0xffff;
break;