summaryrefslogtreecommitdiff
path: root/sysdeps/arm
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2000-07-29 19:36:10 +0000
committerUlrich Drepper <drepper@redhat.com>2000-07-29 19:36:10 +0000
commitfb032fbd8888df1391bfb3a43f1a39a7b64d7423 (patch)
tree855bd486670128219961fd16fa2aac714721ed16 /sysdeps/arm
parent497b8ef43fa893f36cd96abfe117e00e2b4854be (diff)
downloadglibc-fb032fbd8888df1391bfb3a43f1a39a7b64d7423.tar.gz
Update.
2000-07-26 Philip Blundell <philb@gnu.org> * sysdeps/arm/dl-machine.h (fix_bad_pc24): New function. (elf_machine_rel): Use it for out-of-range PC24 relocs.
Diffstat (limited to 'sysdeps/arm')
-rw-r--r--sysdeps/arm/dl-machine.h46
1 files changed, 39 insertions, 7 deletions
diff --git a/sysdeps/arm/dl-machine.h b/sysdeps/arm/dl-machine.h
index 44087585f0..cbef92f3ae 100644
--- a/sysdeps/arm/dl-machine.h
+++ b/sysdeps/arm/dl-machine.h
@@ -376,6 +376,37 @@ elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc,
extern char **_dl_argv;
+/* Deal with an out-of-range PC24 reloc. */
+static Elf32_Addr
+fix_bad_pc24 (Elf32_Addr *const reloc_addr, Elf32_Addr value)
+{
+ static void *fix_page;
+ static unsigned int fix_offset;
+ static size_t pagesize;
+ Elf32_Word *fix_address;
+
+ if (! fix_page)
+ {
+ if (! pagesize)
+ pagesize = getpagesize ();
+ fix_page = mmap (NULL, pagesize, PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (! fix_page)
+ assert (! "could not map page for fixup");
+ fix_offset = 0;
+ }
+
+ fix_address = (Elf32_Word *)(fix_page + fix_offset);
+ fix_address[0] = 0xe51ff004; /* ldr pc, [pc, #-4] */
+ fix_address[1] = value;
+
+ fix_offset += 8;
+ if (fix_offset >= pagesize)
+ fix_page = NULL;
+
+ return (Elf32_Addr)fix_address;
+}
+
/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
MAP is the object containing the reloc. */
@@ -452,18 +483,19 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
}
case R_ARM_PC24:
{
- signed int addend;
+ Elf32_Sword addend;
+ Elf32_Addr newvalue;
addend = *reloc_addr & 0x00ffffff;
if (addend & 0x00800000) addend |= 0xff000000;
- value = value - (unsigned int)reloc_addr + (addend << 2);
- if (value & 0xfc000003)
- _dl_signal_error (0, map->l_name,
- "R_ARM_PC24 relocation out of range");
+ newvalue = value - (Elf32_Addr)reloc_addr + (addend << 2);
+ if (newvalue & 0xfc000003)
+ newvalue = fix_bad_pc24(reloc_addr, value)
+ - (Elf32_Addr)reloc_addr + (addend << 2);
- value = value >> 2;
- value = (*reloc_addr & 0xff000000) | (value & 0x00ffffff);
+ newvalue = newvalue >> 2;
+ value = (*reloc_addr & 0xff000000) | (newvalue & 0x00ffffff);
*reloc_addr = value;
}
break;