summaryrefslogtreecommitdiffstats
path: root/trunk/src/arch-x86_64.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/arch-x86_64.c')
-rw-r--r--trunk/src/arch-x86_64.c104
1 files changed, 38 insertions, 66 deletions
diff --git a/trunk/src/arch-x86_64.c b/trunk/src/arch-x86_64.c
index 67c9f8c..4fb3efb 100644
--- a/trunk/src/arch-x86_64.c
+++ b/trunk/src/arch-x86_64.c
@@ -1,5 +1,7 @@
/* Copyright (C) 2001, 2002, 2003, 2004, 2006, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+ Copyright (C) 2011 Wind River Systems, Inc.
+ x32 support by Mark Hatle <mark.hatle@windriver.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -28,6 +30,22 @@
#include "prelink.h"
+/* The x32 ABI: https://sites.google.com/site/x32abi/documents/abi.pdf
+ * documents a "class" value for specific reads and writes. All this
+ * indicates is that we should be using the ELFCLASS to determine if
+ * this should be a 32/64 bit read/write. (See table 4.9)
+ *
+ * We emulate this behavior below...
+ */
+#define read_uleclass(DSO, ADDR) \
+( gelf_getclass(DSO->elf) == ELFCLASS32 ? read_ule32(DSO, ADDR) : read_ule64(DSO, ADDR) )
+
+#define write_leclass(DSO, ADDR, VAL) \
+( gelf_getclass(DSO->elf) == ELFCLASS32 ? write_le32(DSO, ADDR, VAL) : write_le64(DSO, ADDR, VAL) )
+
+#define buf_write_leclass(DSO, BUF, VAL) \
+( gelf_getclass(DSO->elf) == ELFCLASS32 ? buf_write_le32(BUF, VAL) : buf_write_le64(BUF, VAL) )
+
static int
x86_64_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
GElf_Addr adjust)
@@ -84,13 +102,8 @@ x86_64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
case R_X86_64_RELATIVE:
if (rela->r_addend >= start)
{
- if (gelf_getclass (dso->elf) == ELFCLASS32) {
- if (read_ule32 (dso, rela->r_offset) == rela->r_addend)
- write_le32 (dso, rela->r_offset, rela->r_addend + adjust);
- } else {
- if (read_ule64 (dso, rela->r_offset) == rela->r_addend)
- write_le64 (dso, rela->r_offset, rela->r_addend + adjust);
- }
+ if (read_uleclass (dso, rela->r_offset) == rela->r_addend)
+ write_leclass (dso, rela->r_offset, rela->r_addend + adjust);
rela->r_addend += adjust;
}
break;
@@ -99,15 +112,9 @@ x86_64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
rela->r_addend += adjust;
/* FALLTHROUGH */
case R_X86_64_JUMP_SLOT:
- if (gelf_getclass (dso->elf) == ELFCLASS32) {
- addr = read_ule32 (dso, rela->r_offset);
- if (addr >= start)
- write_le32 (dso, rela->r_offset, addr + adjust);
- } else {
- addr = read_ule64 (dso, rela->r_offset);
- if (addr >= start)
- write_le64 (dso, rela->r_offset, addr + adjust);
- }
+ addr = read_uleclass (dso, rela->r_offset);
+ if (addr >= start)
+ write_leclass (dso, rela->r_offset, addr + adjust);
break;
}
return 0;
@@ -133,10 +140,7 @@ x86_64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
return 0;
else if (GELF_R_TYPE (rela->r_info) == R_X86_64_RELATIVE)
{
- if (gelf_getclass (dso->elf) == ELFCLASS32)
- write_le32 (dso, rela->r_offset, rela->r_addend);
- else
- write_le64 (dso, rela->r_offset, rela->r_addend);
+ write_leclass (dso, rela->r_offset, rela->r_addend);
return 0;
}
value = info->resolve (info, GELF_R_SYM (rela->r_info),
@@ -145,11 +149,8 @@ x86_64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
{
case R_X86_64_GLOB_DAT:
case R_X86_64_JUMP_SLOT:
- if (gelf_getclass (dso->elf) == ELFCLASS32)
- {
- write_le32 (dso, rela->r_offset, value + rela->r_addend);
- break;
- }
+ write_leclass (dso, rela->r_offset, value + rela->r_addend);
+ break;
case R_X86_64_64:
write_le64 (dso, rela->r_offset, value + rela->r_addend);
break;
@@ -196,18 +197,12 @@ x86_64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
char *buf, GElf_Addr dest_addr)
{
GElf_Rela *ret;
- DSO *dso;
-
- dso = info->dso;
-
switch (GELF_R_TYPE (rela->r_info))
{
case R_X86_64_GLOB_DAT:
case R_X86_64_JUMP_SLOT:
- if (gelf_getclass (dso->elf) == ELFCLASS32) {
- buf_write_le32 (buf, rela->r_addend);
- break;
- }
+ buf_write_leclass (info->dso, buf, rela->r_addend);
+ break;
case R_X86_64_64:
buf_write_le64 (buf, rela->r_addend);
break;
@@ -241,9 +236,6 @@ static int
x86_64_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
{
GElf_Addr value;
- DSO *dso;
-
- dso = info->dso;
value = info->resolve (info, GELF_R_SYM (rela->r_info),
GELF_R_TYPE (rela->r_info));
@@ -253,11 +245,8 @@ x86_64_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
break;
case R_X86_64_GLOB_DAT:
case R_X86_64_JUMP_SLOT:
- if (gelf_getclass (dso->elf) == ELFCLASS32)
- {
- buf_write_le32 (buf, value + rela->r_addend);
- break;
- }
+ buf_write_leclass (info->dso, buf, value + rela->r_addend);
+ break;
case R_X86_64_64:
buf_write_le64 (buf, value + rela->r_addend);
break;
@@ -340,10 +329,7 @@ x86_64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
switch (GELF_R_TYPE (rela->r_info))
{
case R_X86_64_GLOB_DAT:
- if (gelf_getclass (dso->elf) == ELFCLASS32)
- ret->r_info = GELF_R_INFO (0, R_X86_64_32);
- else
- ret->r_info = GELF_R_INFO (0, R_X86_64_64);
+ ret->r_info = GELF_R_INFO (0, (gelf_getclass (dso->elf) == ELFCLASS32 ? R_X86_64_32 : R_X86_64_64));
/* FALLTHROUGH */
case R_X86_64_JUMP_SLOT:
case R_X86_64_IRELATIVE:
@@ -501,31 +487,18 @@ x86_64_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
}
else
{
- if (gelf_getclass (dso->elf) == ELFCLASS32) {
- Elf64_Addr data = read_ule32 (dso, dso->shdr[sec].sh_addr + 8);
-
- assert (rela->r_offset >= dso->shdr[sec].sh_addr + 24);
- assert (((rela->r_offset - dso->shdr[sec].sh_addr) & 7) == 0);
- write_le32 (dso, rela->r_offset,
- 2 * (rela->r_offset - dso->shdr[sec].sh_addr - 24)
- + data);
- } else {
- Elf64_Addr data = read_ule64 (dso, dso->shdr[sec].sh_addr + 8);
+ Elf64_Addr data = read_uleclass (dso, dso->shdr[sec].sh_addr + 8);
- assert (rela->r_offset >= dso->shdr[sec].sh_addr + 24);
- assert (((rela->r_offset - dso->shdr[sec].sh_addr) & 7) == 0);
- write_le64 (dso, rela->r_offset,
+ assert (rela->r_offset >= dso->shdr[sec].sh_addr + 24);
+ assert (((rela->r_offset - dso->shdr[sec].sh_addr) & 7) == 0);
+ write_leclass (dso, rela->r_offset,
2 * (rela->r_offset - dso->shdr[sec].sh_addr - 24)
+ data);
- }
}
break;
case R_X86_64_GLOB_DAT:
- if (gelf_getclass (dso->elf) == ELFCLASS32)
- {
- write_le32 (dso, rela->r_offset, 0);
- break;
- }
+ write_leclass (dso, rela->r_offset, 0);
+ break;
case R_X86_64_64:
case R_X86_64_DTPMOD64:
case R_X86_64_DTPOFF64:
@@ -557,8 +530,8 @@ x86_64_reloc_size (int reloc_type)
{
case R_X86_64_GLOB_DAT:
case R_X86_64_JUMP_SLOT:
- case R_X86_64_IRELATIVE:
case R_X86_64_64:
+ case R_X86_64_IRELATIVE:
return 8;
default:
return 4;
@@ -630,7 +603,6 @@ PL_ARCH(x32) = {
even dlopened libraries will get the slots they desire. */
.mmap_base = 0x41000000,
.mmap_end = 0x50000000,
-// .max_page_size = 0x1000,
.max_page_size = 0x200000,
.page_size = 0x1000
};