summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--trunk/ChangeLog7
-rw-r--r--trunk/src/arch-s390.c117
2 files changed, 109 insertions, 15 deletions
diff --git a/trunk/ChangeLog b/trunk/ChangeLog
index 79316a8..8c16f0d 100644
--- a/trunk/ChangeLog
+++ b/trunk/ChangeLog
@@ -1,3 +1,10 @@
+2010-01-05 Jakub Jelinek <jakub@redhat.com>
+
+ * src/arch-s390.c (s390_prelink_rela, s390_apply_rela,
+ s390_prelink_conflict_rela, s390_prelink_conflict_rela,
+ s390_undo_prelink_rela, s390_reloc_size): Handle
+ R_390_{PC32DBL,16,PC16,PC16DBL,8} relocs.
+
2009-12-16 Jakub Jelinek <jakub@redhat.com>
* testsuite/reloc2.sh: Don't assume textrel works if getenforce
diff --git a/trunk/src/arch-s390.c b/trunk/src/arch-s390.c
index b750beb..cf9f84c 100644
--- a/trunk/src/arch-s390.c
+++ b/trunk/src/arch-s390.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2009 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2009, 2010 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -122,20 +122,40 @@ s390_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
}
value = info->resolve (info, GELF_R_SYM (rela->r_info),
GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
switch (GELF_R_TYPE (rela->r_info))
{
case R_390_GLOB_DAT:
case R_390_JMP_SLOT:
- write_be32 (dso, rela->r_offset, value);
+ write_be32 (dso, rela->r_offset, value - rela->r_addend);
break;
case R_390_32:
- write_be32 (dso, rela->r_offset, value + rela->r_addend);
+ write_be32 (dso, rela->r_offset, value);
break;
case R_390_PC32:
- write_be32 (dso, rela->r_offset, value + rela->r_addend - rela->r_offset);
+ write_be32 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ case R_390_PC32DBL:
+ case R_390_PLT32DBL:
+ write_be32 (dso, rela->r_offset,
+ ((Elf32_Sword) (value - rela->r_offset)) >> 1);
+ break;
+ case R_390_16:
+ write_be16 (dso, rela->r_offset, value);
+ break;
+ case R_390_PC16:
+ write_be16 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ case R_390_PC16DBL:
+ case R_390_PLT16DBL:
+ write_be16 (dso, rela->r_offset,
+ ((int16_t) (value - rela->r_offset)) >> 1);
+ break;
+ case R_390_8:
+ write_8 (dso, rela->r_offset, value);
break;
case R_390_TLS_DTPOFF:
- write_be32 (dso, rela->r_offset, value + rela->r_addend);
+ write_be32 (dso, rela->r_offset, value);
break;
/* DTPMOD and TPOFF is impossible to predict in shared libraries
unless prelink sets the rules. */
@@ -150,7 +170,7 @@ s390_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
case R_390_TLS_TPOFF:
if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
write_be32 (dso, rela->r_offset,
- value + rela->r_addend - info->resolvetls->offset);
+ value - info->resolvetls->offset);
break;
case R_390_COPY:
if (dso->ehdr.e_type == ET_EXEC)
@@ -175,6 +195,12 @@ s390_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
case R_390_32:
buf_write_be32 (buf, rela->r_addend);
break;
+ case R_390_16:
+ buf_write_be16 (buf, rela->r_addend);
+ break;
+ case R_390_8:
+ buf_write_8 (buf, rela->r_addend);
+ break;
default:
abort ();
}
@@ -195,19 +221,37 @@ s390_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
value = info->resolve (info, GELF_R_SYM (rela->r_info),
GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
switch (GELF_R_TYPE (rela->r_info))
{
case R_390_NONE:
break;
case R_390_GLOB_DAT:
case R_390_JMP_SLOT:
- buf_write_be32 (buf, value);
+ buf_write_be32 (buf, value - rela->r_addend);
break;
case R_390_32:
- buf_write_be32 (buf, value + rela->r_addend);
+ buf_write_be32 (buf, value);
break;
case R_390_PC32:
- buf_write_be32 (buf, value + rela->r_addend - rela->r_offset);
+ buf_write_be32 (buf, value - rela->r_offset);
+ break;
+ case R_390_PC32DBL:
+ case R_390_PLT32DBL:
+ buf_write_be32 (buf, ((Elf32_Sword) (value - rela->r_offset)) >> 1);
+ break;
+ case R_390_16:
+ buf_write_be16 (buf, value);
+ break;
+ case R_390_PC16:
+ buf_write_be16 (buf, value - rela->r_offset);
+ break;
+ case R_390_PC16DBL:
+ case R_390_PLT16DBL:
+ buf_write_be16 (buf, ((int16_t) (value - rela->r_offset)) >> 1);
+ break;
+ case R_390_8:
+ buf_write_8 (buf, value);
break;
case R_390_COPY:
abort ();
@@ -281,17 +325,38 @@ s390_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
return 1;
ret->r_offset = rela->r_offset;
ret->r_info = GELF_R_INFO (0, R_390_32);
+ value += rela->r_addend;
switch (GELF_R_TYPE (rela->r_info))
{
case R_390_GLOB_DAT:
case R_390_JMP_SLOT:
- ret->r_addend = (Elf32_Sword) value;
+ ret->r_addend = (Elf32_Sword) (value - rela->r_addend);
break;
case R_390_32:
- ret->r_addend = (Elf32_Sword) (value + rela->r_addend);
+ ret->r_addend = (Elf32_Sword) value;
break;
case R_390_PC32:
- ret->r_addend = (Elf32_Sword) (value + rela->r_addend - rela->r_offset);
+ ret->r_addend = (Elf32_Sword) (value - rela->r_offset);
+ break;
+ case R_390_PC32DBL:
+ case R_390_PLT32DBL:
+ ret->r_addend
+ = (Elf32_Addr) (((Elf32_Sword) (value - rela->r_offset)) >> 1);
+ break;
+ case R_390_PC16:
+ value -= rela->r_offset;
+ case R_390_16:
+ ret->r_addend = (Elf32_Half) value;
+ ret->r_info = GELF_R_INFO (0, R_390_16);
+ break;
+ case R_390_PC16DBL:
+ case R_390_PLT16DBL:
+ ret->r_addend = (Elf32_Half) (((int16_t) (value - rela->r_offset)) >> 1);
+ ret->r_info = GELF_R_INFO (0, R_390_16);
+ break;
+ case R_390_8:
+ ret->r_addend = value & 0xff;
+ ret->r_info = GELF_R_INFO (0, R_390_8);
break;
case R_390_COPY:
error (0, 0, "R_390_COPY should not be present in shared libraries");
@@ -314,10 +379,10 @@ s390_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
ret->r_addend = tls->modid;
break;
case R_390_TLS_DTPOFF:
- ret->r_addend = value + rela->r_addend;
+ ret->r_addend = value;
break;
case R_390_TLS_TPOFF:
- ret->r_addend = value + rela->r_addend - tls->offset;
+ ret->r_addend = value - tls->offset;
break;
}
break;
@@ -441,11 +506,22 @@ s390_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
case R_390_GLOB_DAT:
case R_390_32:
case R_390_PC32:
+ case R_390_PC32DBL:
+ case R_390_PLT32DBL:
case R_390_TLS_DTPMOD:
case R_390_TLS_DTPOFF:
case R_390_TLS_TPOFF:
write_be32 (dso, rela->r_offset, 0);
break;
+ case R_390_16:
+ case R_390_PC16:
+ case R_390_PC16DBL:
+ case R_390_PLT16DBL:
+ write_be16 (dso, rela->r_offset, 0);
+ break;
+ case R_390_8:
+ write_8 (dso, rela->r_offset, 0);
+ break;
case R_390_COPY:
if (dso->ehdr.e_type == ET_EXEC)
/* COPY relocs are handled specially in generic code. */
@@ -463,7 +539,18 @@ s390_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
static int
s390_reloc_size (int reloc_type)
{
- return 4;
+ switch (reloc_type)
+ {
+ case R_390_16:
+ case R_390_PC16:
+ case R_390_PC16DBL:
+ case R_390_PLT16DBL:
+ return 2;
+ case R_390_8:
+ return 1;
+ default:
+ return 4;
+ }
}
static int