summaryrefslogtreecommitdiffstats
path: root/trunk/src
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src')
-rw-r--r--trunk/src/Makefile.am4
-rw-r--r--trunk/src/Makefile.in4
-rw-r--r--trunk/src/arch-alpha.c20
-rw-r--r--trunk/src/arch-arm.c35
-rw-r--r--trunk/src/arch-cris.c14
-rw-r--r--trunk/src/arch-i386.c52
-rw-r--r--trunk/src/arch-ia64.c14
-rw-r--r--trunk/src/arch-mips.c16
-rw-r--r--trunk/src/arch-ppc.c28
-rw-r--r--trunk/src/arch-ppc64.c25
-rw-r--r--trunk/src/arch-s390.c16
-rw-r--r--trunk/src/arch-s390x.c24
-rw-r--r--trunk/src/arch-sh.c26
-rw-r--r--trunk/src/arch-sparc.c20
-rw-r--r--trunk/src/arch-sparc64.c28
-rw-r--r--trunk/src/arch-x86_64.c40
-rw-r--r--trunk/src/conflict.c177
-rw-r--r--trunk/src/cxx.c490
-rw-r--r--trunk/src/doit.c60
-rw-r--r--trunk/src/dso.c1
-rw-r--r--trunk/src/dwarf2.c74
-rw-r--r--trunk/src/dwarf2.h25
-rw-r--r--trunk/src/fptr.c15
-rw-r--r--trunk/src/gather.c113
-rw-r--r--trunk/src/get.c119
-rw-r--r--trunk/src/main.c9
-rw-r--r--trunk/src/prelink.c36
-rw-r--r--trunk/src/prelink.h43
-rw-r--r--trunk/src/space.c350
-rw-r--r--trunk/src/verify.c7
30 files changed, 1308 insertions, 577 deletions
diff --git a/trunk/src/Makefile.am b/trunk/src/Makefile.am
index 64dad8f..387b6ef 100644
--- a/trunk/src/Makefile.am
+++ b/trunk/src/Makefile.am
@@ -5,8 +5,8 @@ AUTOMAKE_OPTIONS = 1.4 gnu
PKGVERSION = "\"@PKGVERSION@\""
REPORT_BUGS_TO = "\"@REPORT_BUGS_TO@\""
-DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -Wall
-AM_CFLAGS = -Wall
+DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -Wall -Wno-pointer-sign
+AM_CFLAGS = -Wall -Wno-pointer-sign
AM_CPPFLAGS = -DSBINDIR='"@sbindir@"' -DBINDIR='"@bindir@"' \
-DEXECSTACK_PROG="\"`echo execstack | sed '$(transform)'`\"" \
-DPRELINK_PROG="\"`echo prelink | sed '$(transform)'`\"" \
diff --git a/trunk/src/Makefile.in b/trunk/src/Makefile.in
index 7dbe941..85cf845 100644
--- a/trunk/src/Makefile.in
+++ b/trunk/src/Makefile.in
@@ -97,8 +97,8 @@ install_sh = @install_sh@
AUTOMAKE_OPTIONS = 1.4 gnu
-DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -Wall
-AM_CFLAGS = -Wall
+DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -Wall -Wno-pointer-sign
+AM_CFLAGS = -Wall -Wno-pointer-sign
AM_CPPFLAGS = -DSBINDIR='"@sbindir@"'
INCLUDES = @GELFINCLUDE@
diff --git a/trunk/src/arch-alpha.c b/trunk/src/arch-alpha.c
index f35ee18..7802a3e 100644
--- a/trunk/src/arch-alpha.c
+++ b/trunk/src/arch-alpha.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -30,14 +30,14 @@
static int
alpha_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
return 0;
}
static int
alpha_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
error (0, 0, "%s: Alpha doesn't support REL relocs", dso->filename);
return 1;
@@ -45,7 +45,7 @@ alpha_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
alpha_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (GELF_R_TYPE (rela->r_info) == R_ALPHA_RELATIVE
|| GELF_R_TYPE (rela->r_info) == R_ALPHA_JMP_SLOT)
@@ -195,7 +195,7 @@ alpha_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
alpha_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info) & 0xff)
{
@@ -260,7 +260,8 @@ alpha_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
GElf_Rela *ret;
if (GELF_R_TYPE (rela->r_info) == R_ALPHA_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_ALPHA_NONE)
+ || GELF_R_TYPE (rela->r_info) == R_ALPHA_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
@@ -280,6 +281,12 @@ alpha_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
}
value = 0;
}
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on Alpha yet",
+ dso->filename);
+ return 1;
+ }
else
{
/* DTPREL64 wants to see only real conflicts, not lookups
@@ -467,6 +474,7 @@ PL_ARCH(alpha) = {
.R_JMP_SLOT = R_ALPHA_JMP_SLOT,
.R_COPY = -1,
.R_RELATIVE = R_ALPHA_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
.dynamic_linker = "/lib/ld-linux.so.2",
.adjust_dyn = alpha_adjust_dyn,
.adjust_rel = alpha_adjust_rel,
diff --git a/trunk/src/arch-arm.c b/trunk/src/arch-arm.c
index 0dddaac..ba53929 100644
--- a/trunk/src/arch-arm.c
+++ b/trunk/src/arch-arm.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2004 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2004, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -36,7 +36,7 @@
static int
arm_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (dyn->d_tag == DT_PLTGOT)
{
@@ -73,7 +73,7 @@ arm_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
static int
arm_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
Elf32_Addr data;
switch (GELF_R_TYPE (rel->r_info))
@@ -90,7 +90,7 @@ arm_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
arm_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
Elf32_Addr data;
@@ -186,7 +186,7 @@ arm_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
static int
arm_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
- GElf_Addr relaaddr)
+ GElf_Addr relaaddr)
{
DSO *dso;
GElf_Addr value;
@@ -254,7 +254,7 @@ arm_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
arm_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info))
{
@@ -354,7 +354,7 @@ arm_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
static int
arm_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
- GElf_Addr reladdr)
+ GElf_Addr reladdr)
{
GElf_Addr value;
struct prelink_conflict *conflict;
@@ -362,7 +362,8 @@ arm_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
GElf_Rela *ret;
if (GELF_R_TYPE (rel->r_info) == R_ARM_RELATIVE
- || GELF_R_TYPE (rel->r_info) == R_ARM_NONE)
+ || GELF_R_TYPE (rel->r_info) == R_ARM_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rel->r_info),
@@ -384,6 +385,12 @@ arm_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
}
value = 0;
}
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on ARM yet",
+ dso->filename);
+ return 1;
+ }
else
{
/* DTPOFF32 wants to see only real conflicts, not lookups
@@ -452,7 +459,7 @@ arm_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
static int
arm_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
- GElf_Rela *rela, GElf_Addr relaaddr)
+ GElf_Rela *rela, GElf_Addr relaaddr)
{
GElf_Addr value;
struct prelink_conflict *conflict;
@@ -461,7 +468,8 @@ arm_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
Elf32_Sword val;
if (GELF_R_TYPE (rela->r_info) == R_ARM_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_ARM_NONE)
+ || GELF_R_TYPE (rela->r_info) == R_ARM_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
@@ -484,6 +492,12 @@ arm_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
}
value = 0;
}
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on ARM yet",
+ dso->filename);
+ return 1;
+ }
else
{
/* DTPOFF32 wants to see only real conflicts, not lookups
@@ -823,6 +837,7 @@ PL_ARCH(arm) = {
.R_JMP_SLOT = R_ARM_JUMP_SLOT,
.R_COPY = R_ARM_COPY,
.R_RELATIVE = R_ARM_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
.dynamic_linker = "/lib/ld-linux.so.2",
.dynamic_linker_alt = "/lib/ld-linux.so.3",
.adjust_dyn = arm_adjust_dyn,
diff --git a/trunk/src/arch-cris.c b/trunk/src/arch-cris.c
index b110539..3272779 100644
--- a/trunk/src/arch-cris.c
+++ b/trunk/src/arch-cris.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2004 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2004, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -159,7 +159,7 @@ cris_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
cris_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info))
{
@@ -247,13 +247,20 @@ cris_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
GElf_Rela *ret;
if (GELF_R_TYPE (rela->r_info) == R_CRIS_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_CRIS_NONE)
+ || GELF_R_TYPE (rela->r_info) == R_CRIS_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
GELF_R_TYPE (rela->r_info));
if (conflict == NULL)
return 0;
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on CRIS yet",
+ dso->filename);
+ return 1;
+ }
value = conflict_lookup_value (conflict);
ret = prelink_conflict_add_rela (info);
if (ret == NULL)
@@ -375,6 +382,7 @@ PL_ARCH(cris) = {
.R_JUMP_SLOT = R_CRIS_JUMP_SLOT,
.R_COPY = R_CRIS_COPY,
.R_RELATIVE = R_CRIS_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
.dynamic_linker = "/lib/ld.so.1",
.adjust_dyn = cris_adjust_dyn,
.adjust_rel = cris_adjust_rel,
diff --git a/trunk/src/arch-i386.c b/trunk/src/arch-i386.c
index 37b5c67..5661dcb 100644
--- a/trunk/src/arch-i386.c
+++ b/trunk/src/arch-i386.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -75,6 +75,7 @@ i386_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
{
case R_386_RELATIVE:
case R_386_JMP_SLOT:
+ case R_386_IRELATIVE:
data = read_ule32 (dso, rel->r_offset);
if (data >= start)
write_le32 (dso, rel->r_offset, data + adjust);
@@ -92,6 +93,7 @@ i386_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
switch (GELF_R_TYPE (rela->r_info))
{
case R_386_RELATIVE:
+ case R_386_IRELATIVE:
if ((Elf32_Addr) rela->r_addend >= start)
{
rela->r_addend += (Elf32_Sword) adjust;
@@ -117,6 +119,7 @@ i386_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
GElf_Addr value;
if (GELF_R_TYPE (rel->r_info) == R_386_RELATIVE
+ || GELF_R_TYPE (rel->r_info) == R_386_IRELATIVE
|| GELF_R_TYPE (rel->r_info) == R_386_NONE)
/* Fast path: nothing to do. */
return 0;
@@ -187,6 +190,7 @@ i386_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
GElf_Addr value;
if (GELF_R_TYPE (rela->r_info) == R_386_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_386_IRELATIVE
|| GELF_R_TYPE (rela->r_info) == R_386_NONE)
/* Fast path: nothing to do. */
return 0;
@@ -244,8 +248,10 @@ i386_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
i386_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
+ GElf_Rela *ret;
+
switch (GELF_R_TYPE (rela->r_info))
{
case R_386_GLOB_DAT:
@@ -253,6 +259,16 @@ i386_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
case R_386_32:
buf_write_le32 (buf, rela->r_addend);
break;
+ case R_386_IRELATIVE:
+ if (dest_addr == 0)
+ return 5;
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = dest_addr;
+ ret->r_info = GELF_R_INFO (0, R_386_IRELATIVE);
+ ret->r_addend = rela->r_addend;
+ break;
default:
abort ();
}
@@ -339,20 +355,25 @@ i386_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
GELF_R_TYPE (rel->r_info));
if (conflict == NULL)
{
- if (info->curtls == NULL)
- return 0;
switch (GELF_R_TYPE (rel->r_info))
{
/* Even local DTPMOD and TPOFF relocs need conflicts. */
case R_386_TLS_DTPMOD32:
case R_386_TLS_TPOFF32:
case R_386_TLS_TPOFF:
+ if (info->curtls == NULL || info->dso == dso)
+ return 0;
+ break;
+ /* Similarly IRELATIVE relocations always need conflicts. */
+ case R_386_IRELATIVE:
break;
default:
return 0;
}
value = 0;
}
+ else if (info->dso == dso && !conflict->ifunc)
+ return 0;
else
{
/* DTPOFF32 wants to see only real conflicts, not lookups
@@ -376,6 +397,11 @@ i386_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
/* FALLTHROUGH */
case R_386_JMP_SLOT:
ret->r_addend = (Elf32_Sword) value;
+ if (conflict != NULL && conflict->ifunc)
+ ret->r_info = GELF_R_INFO (0, R_386_IRELATIVE);
+ break;
+ case R_386_IRELATIVE:
+ ret->r_addend = (Elf32_Sword) read_ule32 (dso, rel->r_offset);
break;
case R_386_32:
case R_386_PC32:
@@ -441,20 +467,25 @@ i386_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
GELF_R_TYPE (rela->r_info));
if (conflict == NULL)
{
- if (info->curtls == NULL)
- return 0;
switch (GELF_R_TYPE (rela->r_info))
{
/* Even local DTPMOD and TPOFF relocs need conflicts. */
case R_386_TLS_DTPMOD32:
case R_386_TLS_TPOFF32:
case R_386_TLS_TPOFF:
+ if (info->curtls == NULL || info->dso == dso)
+ return 0;
+ break;
+ /* Similarly IRELATIVE relocations always need conflicts. */
+ case R_386_IRELATIVE:
break;
default:
return 0;
}
value = 0;
}
+ else if (info->dso == dso && !conflict->ifunc)
+ return 0;
else
{
/* DTPOFF32 wants to see only real conflicts, not lookups
@@ -477,11 +508,16 @@ i386_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
ret->r_info = GELF_R_INFO (0, R_386_32);
/* FALLTHROUGH */
case R_386_JMP_SLOT:
+ case R_386_IRELATIVE:
ret->r_addend = (Elf32_Sword) (value + rela->r_addend);
+ if (conflict != NULL && conflict->ifunc)
+ ret->r_info = GELF_R_INFO (0, R_386_IRELATIVE);
break;
case R_386_32:
value += rela->r_addend;
ret->r_addend = (Elf32_Sword) value;
+ if (conflict != NULL && conflict->ifunc)
+ ret->r_info = GELF_R_INFO (0, R_386_IRELATIVE);
break;
case R_386_PC32:
ret->r_addend = (Elf32_Sword) (value + rela->r_addend - rela->r_offset);
@@ -539,6 +575,7 @@ i386_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
/* We should be never converting .rel.plt into .rela.plt. */
abort ();
case R_386_RELATIVE:
+ case R_386_IRELATIVE:
case R_386_32:
case R_386_PC32:
case R_386_TLS_TPOFF32:
@@ -672,6 +709,7 @@ i386_undo_prelink_rel (DSO *dso, GElf_Rel *rel, GElf_Addr reladdr)
{
case R_386_NONE:
case R_386_RELATIVE:
+ case R_386_IRELATIVE:
break;
case R_386_JMP_SLOT:
sec = addr_to_sec (dso, rel->r_offset);
@@ -746,6 +784,7 @@ i386_rela_to_rel (DSO *dso, GElf_Rela *rela, GElf_Rel *rel)
and thus never .rela.plt back to .rel.plt. */
abort ();
case R_386_RELATIVE:
+ case R_386_IRELATIVE:
case R_386_32:
case R_386_PC32:
case R_386_TLS_TPOFF32:
@@ -1052,6 +1091,7 @@ PL_ARCH(i386) = {
.R_JMP_SLOT = R_386_JMP_SLOT,
.R_COPY = R_386_COPY,
.R_RELATIVE = R_386_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
.dynamic_linker = "/lib/ld-linux.so.2",
.adjust_dyn = i386_adjust_dyn,
.adjust_rel = i386_adjust_rel,
diff --git a/trunk/src/arch-ia64.c b/trunk/src/arch-ia64.c
index 89df85e..6039115 100644
--- a/trunk/src/arch-ia64.c
+++ b/trunk/src/arch-ia64.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -196,7 +196,7 @@ ia64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
ia64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
if ((GELF_R_TYPE (rela->r_info) & ~1) == R_IA64_IPLTMSB)
{
@@ -312,13 +312,20 @@ ia64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
GElf_Rela *ret;
if ((GELF_R_TYPE (rela->r_info) & ~3) == R_IA64_REL32MSB
- || GELF_R_TYPE (rela->r_info) == R_IA64_NONE)
+ || GELF_R_TYPE (rela->r_info) == R_IA64_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
GELF_R_TYPE (rela->r_info));
if (conflict == NULL)
return 0;
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on IA-64 yet",
+ dso->filename);
+ return 1;
+ }
value = conflict_lookup_value (conflict);
ret = prelink_conflict_add_rela (info);
if (ret == NULL)
@@ -493,6 +500,7 @@ PL_ARCH(ia64) = {
.R_JMP_SLOT = R_IA64_IPLTLSB,
.R_COPY = -1,
.R_RELATIVE = R_IA64_REL64LSB,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
.dynamic_linker = "/lib/ld-linux-ia64.so.2",
.adjust_dyn = ia64_adjust_dyn,
.adjust_rel = ia64_adjust_rel,
diff --git a/trunk/src/arch-mips.c b/trunk/src/arch-mips.c
index b85616e..2e0ea4c 100644
--- a/trunk/src/arch-mips.c
+++ b/trunk/src/arch-mips.c
@@ -660,11 +660,14 @@ mips_prelink_conflict_reloc (DSO *dso, struct prelink_info *info,
{
GElf_Addr value;
struct prelink_conflict *conflict;
- struct prelink_tls *tls;
+ struct prelink_tls *tls = NULL;
GElf_Rela *entry;
GElf_Word r_sym;
int r_type;
+ if (info->dso == dso)
+ return 0;
+
r_sym = reloc_r_sym (dso, r_info);
r_type = reloc_r_type (dso, r_info);
conflict = prelink_conflict (info, r_sym, r_type);
@@ -688,6 +691,12 @@ mips_prelink_conflict_reloc (DSO *dso, struct prelink_info *info,
return 0;
}
}
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on MIPS yet",
+ dso->filename);
+ return 1;
+ }
else
{
/* DTPREL32/DTPREL64 relocations just involve the symbol value;
@@ -791,7 +800,7 @@ mips_arch_prelink_conflict (DSO *dso, struct prelink_info *info)
struct prelink_conflict *conflict;
GElf_Rela *entry;
- if (dso->info[DT_PLTGOT] == 0)
+ if (info->dso == dso || dso->info[DT_PLTGOT] == 0)
return 0;
/* Add a conflict for every global GOT entry that does not hold the
@@ -829,7 +838,7 @@ mips_arch_prelink_conflict (DSO *dso, struct prelink_info *info)
static int
mips_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
DSO *dso;
@@ -1348,6 +1357,7 @@ PL_ARCH(mips) = {
/* R_MIPS_REL32 relocations against symbol 0 do act as relative relocs,
but those against other symbols don't. */
.R_RELATIVE = ~0U,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
.arch_adjust = mips_arch_adjust,
.adjust_dyn = mips_adjust_dyn,
.adjust_rel = mips_adjust_rel,
diff --git a/trunk/src/arch-ppc.c b/trunk/src/arch-ppc.c
index 4bf5aca..99dbea5 100644
--- a/trunk/src/arch-ppc.c
+++ b/trunk/src/arch-ppc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -37,7 +37,7 @@
static int
ppc_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (dyn->d_tag == DT_PPC_GOT)
{
@@ -116,7 +116,7 @@ ppc_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
static int
ppc_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
error (0, 0, "%s: PowerPC doesn't support REL relocs", dso->filename);
return 1;
@@ -124,7 +124,7 @@ ppc_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
ppc_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (GELF_R_TYPE (rela->r_info) == R_PPC_RELATIVE)
{
@@ -143,7 +143,7 @@ ppc_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
static int
ppc_prelink_rel (struct prelink_info *info, GElf_Rel *rel,
- GElf_Addr reladdr)
+ GElf_Addr reladdr)
{
error (0, 0, "%s: PowerPC doesn't support REL relocs", info->dso->filename);
return 1;
@@ -201,7 +201,7 @@ ppc_fixup_plt (DSO *dso, GElf_Rela *rela, GElf_Addr value)
static int
ppc_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
- GElf_Addr relaaddr)
+ GElf_Addr relaaddr)
{
DSO *dso = info->dso;
GElf_Addr value;
@@ -330,7 +330,7 @@ ppc_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
ppc_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info))
{
@@ -418,7 +418,7 @@ ppc_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
static int
ppc_prelink_conflict_rel (DSO *dso, struct prelink_info *info,
- GElf_Rel *rel, GElf_Addr reladdr)
+ GElf_Rel *rel, GElf_Addr reladdr)
{
error (0, 0, "%s: PowerPC doesn't support REL relocs", dso->filename);
return 1;
@@ -426,7 +426,7 @@ ppc_prelink_conflict_rel (DSO *dso, struct prelink_info *info,
static int
ppc_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
- GElf_Rela *rela, GElf_Addr relaaddr)
+ GElf_Rela *rela, GElf_Addr relaaddr)
{
GElf_Addr value;
struct prelink_conflict *conflict;
@@ -435,7 +435,8 @@ ppc_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
int r_type;
if (GELF_R_TYPE (rela->r_info) == R_PPC_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_PPC_NONE)
+ || GELF_R_TYPE (rela->r_info) == R_PPC_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
@@ -459,6 +460,12 @@ ppc_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
}
value = 0;
}
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on PowerPC yet",
+ dso->filename);
+ return 1;
+ }
else
{
/* DTPREL wants to see only real conflicts, not lookups
@@ -1122,6 +1129,7 @@ PL_ARCH(ppc) = {
.R_JMP_SLOT = R_PPC_JMP_SLOT,
.R_COPY = R_PPC_COPY,
.R_RELATIVE = R_PPC_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
.dynamic_linker = "/lib/ld.so.1",
.adjust_dyn = ppc_adjust_dyn,
.adjust_rel = ppc_adjust_rel,
diff --git a/trunk/src/arch-ppc64.c b/trunk/src/arch-ppc64.c
index ec28ee8..6f9f644 100644
--- a/trunk/src/arch-ppc64.c
+++ b/trunk/src/arch-ppc64.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004 Red Hat, Inc.
+/* Copyright (C) 2002, 2003, 2004, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2002.
This program is free software; you can redistribute it and/or modify
@@ -60,7 +60,7 @@ ppc64_adjust_section (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
static int
ppc64_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (dyn->d_tag == DT_PPC64_GLINK && dyn->d_un.d_ptr >= start)
{
@@ -73,7 +73,7 @@ ppc64_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
static int
ppc64_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
error (0, 0, "%s: PowerPC64 doesn't support REL relocs", dso->filename);
return 1;
@@ -81,7 +81,7 @@ ppc64_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
ppc64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (GELF_R_TYPE (rela->r_info) == R_PPC64_RELATIVE)
{
@@ -306,7 +306,7 @@ ppc64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
ppc64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info))
{
@@ -439,7 +439,8 @@ ppc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
int r_type;
if (GELF_R_TYPE (rela->r_info) == R_PPC64_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_PPC64_NONE)
+ || GELF_R_TYPE (rela->r_info) == R_PPC64_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
@@ -463,6 +464,12 @@ ppc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
}
value = 0;
}
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on PowerPC64 yet",
+ dso->filename);
+ return 1;
+ }
else
{
/* DTPREL wants to see only real conflicts, not lookups
@@ -771,13 +778,12 @@ ppc64_reloc_class (int reloc_type)
{
switch (reloc_type)
{
- case R_PPC64_COPY: return RTYPE_CLASS_COPY;
- case R_PPC64_ADDR24: return RTYPE_CLASS_PLT;
+ case R_PPC64_COPY: return RTYPE_CLASS_COPY | RTYPE_CLASS_PLT;
default:
if (reloc_type >= R_PPC64_DTPMOD64
&& reloc_type <= R_PPC64_TPREL16_HIGHESTA)
return RTYPE_CLASS_TLS;
- return RTYPE_CLASS_VALID;
+ return RTYPE_CLASS_PLT;
}
}
@@ -824,6 +830,7 @@ PL_ARCH(ppc64) = {
.R_JMP_SLOT = R_PPC64_JMP_SLOT,
.R_COPY = R_PPC64_COPY,
.R_RELATIVE = R_PPC64_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_PLT,
.dynamic_linker = "/lib64/ld64.so.1",
.adjust_section = ppc64_adjust_section,
.adjust_dyn = ppc64_adjust_dyn,
diff --git a/trunk/src/arch-s390.c b/trunk/src/arch-s390.c
index f2ca7e1..7907e83 100644
--- a/trunk/src/arch-s390.c
+++ b/trunk/src/arch-s390.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -67,7 +67,7 @@ s390_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
static int
s390_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
error (0, 0, "%s: S390 doesn't support REL relocs", dso->filename);
return 1;
@@ -168,7 +168,7 @@ s390_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
s390_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info))
{
@@ -238,7 +238,8 @@ s390_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
GElf_Rela *ret;
if (GELF_R_TYPE (rela->r_info) == R_390_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_390_NONE)
+ || GELF_R_TYPE (rela->r_info) == R_390_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
@@ -258,6 +259,12 @@ s390_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
}
value = 0;
}
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on S390 yet",
+ dso->filename);
+ return 1;
+ }
else
{
/* DTPOFF wants to see only real conflicts, not lookups
@@ -482,6 +489,7 @@ PL_ARCH(s390) = {
.R_JMP_SLOT = R_390_JMP_SLOT,
.R_COPY = R_390_COPY,
.R_RELATIVE = R_390_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
.dynamic_linker = "/lib/ld.so.1",
.adjust_dyn = s390_adjust_dyn,
.adjust_rel = s390_adjust_rel,
diff --git a/trunk/src/arch-s390x.c b/trunk/src/arch-s390x.c
index e1c213b..8676fff 100644
--- a/trunk/src/arch-s390x.c
+++ b/trunk/src/arch-s390x.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -67,7 +67,7 @@ s390x_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
static int
s390x_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
error (0, 0, "%s: S390 doesn't support REL relocs", dso->filename);
return 1;
@@ -75,7 +75,7 @@ s390x_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
s390x_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
Elf64_Addr addr;
@@ -108,7 +108,7 @@ s390x_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
static int
s390x_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
- GElf_Addr relaaddr)
+ GElf_Addr relaaddr)
{
DSO *dso = info->dso;
GElf_Addr value;
@@ -191,7 +191,7 @@ s390x_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
s390x_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info))
{
@@ -276,7 +276,7 @@ s390x_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
static int
s390x_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
- GElf_Addr reladdr)
+ GElf_Addr reladdr)
{
error (0, 0, "%s: S390 doesn't support REL relocs", dso->filename);
return 1;
@@ -284,7 +284,7 @@ s390x_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
static int
s390x_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
- GElf_Rela *rela, GElf_Addr relaaddr)
+ GElf_Rela *rela, GElf_Addr relaaddr)
{
GElf_Addr value;
struct prelink_conflict *conflict;
@@ -293,7 +293,8 @@ s390x_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
int r_type;
if (GELF_R_TYPE (rela->r_info) == R_390_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_390_NONE)
+ || GELF_R_TYPE (rela->r_info) == R_390_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
@@ -313,6 +314,12 @@ s390x_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
}
value = 0;
}
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on S390x yet",
+ dso->filename);
+ return 1;
+ }
else
{
/* DTPOFF wants to see only real conflicts, not lookups
@@ -598,6 +605,7 @@ PL_ARCH(s390x) = {
.R_JMP_SLOT = R_390_JMP_SLOT,
.R_COPY = R_390_COPY,
.R_RELATIVE = R_390_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
.dynamic_linker = "/lib/ld64.so.1",
.adjust_dyn = s390x_adjust_dyn,
.adjust_rel = s390x_adjust_rel,
diff --git a/trunk/src/arch-sh.c b/trunk/src/arch-sh.c
index d851a4d..1b11312 100644
--- a/trunk/src/arch-sh.c
+++ b/trunk/src/arch-sh.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -30,7 +30,7 @@
static int
sh_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (dyn->d_tag == DT_PLTGOT)
{
@@ -67,7 +67,7 @@ sh_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
static int
sh_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
error (0, 0, "%s: SH doesn't support REL relocs", dso->filename);
return 1;
@@ -75,7 +75,7 @@ sh_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
sh_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
Elf32_Addr data;
@@ -107,7 +107,7 @@ sh_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
static int
sh_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
- GElf_Addr relaaddr)
+ GElf_Addr relaaddr)
{
DSO *dso;
GElf_Addr value;
@@ -151,7 +151,7 @@ sh_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
sh_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info))
{
@@ -206,7 +206,7 @@ sh_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
static int
sh_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
- GElf_Addr reladdr)
+ GElf_Addr reladdr)
{
error (0, 0, "%s: SH doesn't support REL relocs", dso->filename);
return 1;
@@ -214,20 +214,27 @@ sh_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
static int
sh_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
- GElf_Rela *rela, GElf_Addr relaaddr)
+ GElf_Rela *rela, GElf_Addr relaaddr)
{
GElf_Addr value;
struct prelink_conflict *conflict;
GElf_Rela *ret;
if (GELF_R_TYPE (rela->r_info) == R_SH_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_SH_NONE)
+ || GELF_R_TYPE (rela->r_info) == R_SH_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
GELF_R_TYPE (rela->r_info));
if (conflict == NULL)
return 0;
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on SuperH yet",
+ dso->filename);
+ return 1;
+ }
value = conflict_lookup_value (conflict);
ret = prelink_conflict_add_rela (info);
if (ret == NULL)
@@ -414,6 +421,7 @@ PL_ARCH(sh) = {
.R_JMP_SLOT = R_SH_JMP_SLOT,
.R_COPY = R_SH_COPY,
.R_RELATIVE = R_SH_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
.dynamic_linker = "/lib/ld-linux.so.2",
.adjust_dyn = sh_adjust_dyn,
.adjust_rel = sh_adjust_rel,
diff --git a/trunk/src/arch-sparc.c b/trunk/src/arch-sparc.c
index 6594c8f..e016a79 100644
--- a/trunk/src/arch-sparc.c
+++ b/trunk/src/arch-sparc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2004 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2004, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -30,7 +30,7 @@
static int
sparc_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (dyn->d_tag == DT_PLTGOT)
{
@@ -55,7 +55,7 @@ sparc_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
static int
sparc_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
error (0, 0, "%s: Sparc doesn't support REL relocs", dso->filename);
return 1;
@@ -63,7 +63,7 @@ sparc_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
sparc_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (GELF_R_TYPE (rela->r_info) == R_SPARC_RELATIVE)
{
@@ -235,7 +235,7 @@ sparc_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
sparc_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info))
{
@@ -333,7 +333,8 @@ sparc_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
int r_type;
if (GELF_R_TYPE (rela->r_info) == R_SPARC_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_SPARC_NONE)
+ || GELF_R_TYPE (rela->r_info) == R_SPARC_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
@@ -355,6 +356,12 @@ sparc_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
}
value = 0;
}
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on SPARC yet",
+ dso->filename);
+ return 1;
+ }
else
{
/* DTPOFF32 wants to see only real conflicts, not lookups
@@ -607,6 +614,7 @@ PL_ARCH(sparc) = {
.R_JMP_SLOT = R_SPARC_JMP_SLOT,
.R_COPY = R_SPARC_COPY,
.R_RELATIVE = R_SPARC_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
.dynamic_linker = "/lib/ld-linux.so.2",
.adjust_dyn = sparc_adjust_dyn,
.adjust_rel = sparc_adjust_rel,
diff --git a/trunk/src/arch-sparc64.c b/trunk/src/arch-sparc64.c
index 70d3fd7..aee4601 100644
--- a/trunk/src/arch-sparc64.c
+++ b/trunk/src/arch-sparc64.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2004 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2004, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -32,7 +32,7 @@
static int
sparc64_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (dyn->d_tag == DT_PLTGOT)
{
@@ -57,7 +57,7 @@ sparc64_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
static int
sparc64_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
error (0, 0, "%s: Sparc doesn't support REL relocs", dso->filename);
return 1;
@@ -65,7 +65,7 @@ sparc64_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
sparc64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (SPARC64_R_TYPE (rela->r_info) == R_SPARC_RELATIVE)
{
@@ -84,7 +84,7 @@ sparc64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
static int
sparc64_prelink_rel (struct prelink_info *info, GElf_Rel *rel,
- GElf_Addr reladdr)
+ GElf_Addr reladdr)
{
error (0, 0, "%s: Sparc doesn't support REL relocs", info->dso->filename);
return 1;
@@ -166,7 +166,7 @@ sparc64_fixup_plt (DSO *dso, GElf_Rela *rela, GElf_Addr value)
static int
sparc64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
- GElf_Addr relaaddr)
+ GElf_Addr relaaddr)
{
DSO *dso = info->dso;
GElf_Addr value;
@@ -309,7 +309,7 @@ sparc64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
sparc64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (SPARC64_R_TYPE (rela->r_info))
{
@@ -425,7 +425,7 @@ sparc64_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
static int
sparc64_prelink_conflict_rel (DSO *dso, struct prelink_info *info,
- GElf_Rel *rel, GElf_Addr reladdr)
+ GElf_Rel *rel, GElf_Addr reladdr)
{
error (0, 0, "%s: Sparc doesn't support REL relocs", dso->filename);
return 1;
@@ -433,7 +433,7 @@ sparc64_prelink_conflict_rel (DSO *dso, struct prelink_info *info,
static int
sparc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
- GElf_Rela *rela, GElf_Addr relaaddr)
+ GElf_Rela *rela, GElf_Addr relaaddr)
{
GElf_Addr value;
struct prelink_conflict *conflict;
@@ -442,7 +442,8 @@ sparc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
int r_type;
if (SPARC64_R_TYPE (rela->r_info) == R_SPARC_RELATIVE
- || SPARC64_R_TYPE (rela->r_info) == R_SPARC_NONE)
+ || SPARC64_R_TYPE (rela->r_info) == R_SPARC_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
@@ -464,6 +465,12 @@ sparc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
}
value = 0;
}
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on SPARC64 yet",
+ dso->filename);
+ return 1;
+ }
else
{
/* DTPOFF64 wants to see only real conflicts, not lookups
@@ -807,6 +814,7 @@ PL_ARCH(sparc64) = {
.R_JMP_SLOT = R_SPARC_JMP_SLOT,
.R_COPY = R_SPARC_COPY,
.R_RELATIVE = R_SPARC_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
.dynamic_linker = "/lib64/ld-linux.so.2",
.adjust_dyn = sparc64_adjust_dyn,
.adjust_rel = sparc64_adjust_rel,
diff --git a/trunk/src/arch-x86_64.c b/trunk/src/arch-x86_64.c
index 8846672..83286e9 100644
--- a/trunk/src/arch-x86_64.c
+++ b/trunk/src/arch-x86_64.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2006 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2006, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -30,7 +30,7 @@
static int
x86_64_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (dyn->d_tag == DT_PLTGOT)
{
@@ -75,7 +75,7 @@ x86_64_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
x86_64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
Elf64_Addr addr;
@@ -89,6 +89,10 @@ x86_64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
rela->r_addend += adjust;
}
break;
+ case R_X86_64_IRELATIVE:
+ if (rela->r_addend >= start)
+ rela->r_addend += adjust;
+ /* FALLTHROUGH */
case R_X86_64_JUMP_SLOT:
addr = read_ule64 (dso, rela->r_offset);
if (addr >= start)
@@ -113,7 +117,8 @@ x86_64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
GElf_Addr value;
dso = info->dso;
- if (GELF_R_TYPE (rela->r_info) == R_X86_64_NONE)
+ if (GELF_R_TYPE (rela->r_info) == R_X86_64_NONE
+ || GELF_R_TYPE (rela->r_info) == R_X86_64_IRELATIVE)
return 0;
else if (GELF_R_TYPE (rela->r_info) == R_X86_64_RELATIVE)
{
@@ -169,8 +174,9 @@ x86_64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
x86_64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
+ GElf_Rela *ret;
switch (GELF_R_TYPE (rela->r_info))
{
case R_X86_64_GLOB_DAT:
@@ -178,6 +184,16 @@ x86_64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
case R_X86_64_64:
buf_write_le64 (buf, rela->r_addend);
break;
+ case R_X86_64_IRELATIVE:
+ if (dest_addr == 0)
+ return 5;
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = dest_addr;
+ ret->r_info = GELF_R_INFO (0, R_X86_64_IRELATIVE);
+ ret->r_addend = rela->r_addend;
+ break;
case R_X86_64_32:
buf_write_le32 (buf, rela->r_addend);
break;
@@ -252,19 +268,24 @@ x86_64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
GELF_R_TYPE (rela->r_info));
if (conflict == NULL)
{
- if (info->curtls == NULL)
- return 0;
switch (GELF_R_TYPE (rela->r_info))
{
/* Even local DTPMOD and TPOFF relocs need conflicts. */
case R_X86_64_DTPMOD64:
case R_X86_64_TPOFF64:
+ if (info->curtls == NULL || info->dso == dso)
+ return 0;
+ break;
+ /* Similarly IRELATIVE relocations always need conflicts. */
+ case R_X86_64_IRELATIVE:
break;
default:
return 0;
}
value = 0;
}
+ else if (info->dso == dso && !conflict->ifunc)
+ return 0;
else
{
/* DTPOFF wants to see only real conflicts, not lookups
@@ -288,7 +309,10 @@ x86_64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
/* FALLTHROUGH */
case R_X86_64_JUMP_SLOT:
case R_X86_64_64:
+ case R_X86_64_IRELATIVE:
ret->r_addend = value + rela->r_addend;
+ if (conflict != NULL && conflict->ifunc)
+ ret->r_info = GELF_R_INFO (0, R_X86_64_IRELATIVE);
break;
case R_X86_64_32:
value += rela->r_addend;
@@ -422,6 +446,7 @@ x86_64_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
{
case R_X86_64_NONE:
case R_X86_64_RELATIVE:
+ case R_X86_64_IRELATIVE:
break;
case R_X86_64_JUMP_SLOT:
sec = addr_to_sec (dso, rela->r_offset);
@@ -505,6 +530,7 @@ PL_ARCH(x86_64) = {
.R_JMP_SLOT = R_X86_64_JUMP_SLOT,
.R_COPY = R_X86_64_COPY,
.R_RELATIVE = R_X86_64_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
.dynamic_linker = "/lib64/ld-linux-x86-64.so.2",
.adjust_dyn = x86_64_adjust_dyn,
.adjust_rel = x86_64_adjust_rel,
diff --git a/trunk/src/conflict.c b/trunk/src/conflict.c
index cb0ba80..3181de1 100644
--- a/trunk/src/conflict.c
+++ b/trunk/src/conflict.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2007, 2009 Red Hat, Inc.
Copyright (C) 2008 CodeSourcery.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
Updated by Maciej W. Rozycki <macro@codesourcery.com>, 2008.
@@ -36,8 +36,12 @@ prelink_conflict (struct prelink_info *info, GElf_Word r_sym,
GElf_Word symoff = info->symtab_start + r_sym * info->symtab_entsize;
struct prelink_conflict *conflict;
int reloc_class = info->dso->arch->reloc_class (reloc_type);
+ size_t idx = 0;
- for (conflict = info->curconflicts; conflict; conflict = conflict->next)
+ if (info->curconflicts->hash != &info->curconflicts->first)
+ idx = symoff % 251;
+ for (conflict = info->curconflicts->hash[idx]; conflict;
+ conflict = conflict->next)
if (conflict->symoff == symoff && conflict->reloc_class == reloc_class)
{
conflict->used = 1;
@@ -278,7 +282,7 @@ conflict_rela_cmp (const void *A, const void *B)
int
get_relocated_mem (struct prelink_info *info, DSO *dso, GElf_Addr addr,
- char *buf, GElf_Word size)
+ char *buf, GElf_Word size, GElf_Addr dest_addr)
{
int sec = addr_to_sec (dso, addr), j;
Elf_Scn *scn;
@@ -323,7 +327,7 @@ get_relocated_mem (struct prelink_info *info, DSO *dso, GElf_Addr addr,
reloc offset. */
for (j = 0; j < info->conflict_rela_size; ++j)
{
- int reloc_type, reloc_size;
+ int reloc_type, reloc_size, ret;
off_t off;
if (info->conflict_rela[j].r_offset >= addr + size)
@@ -345,8 +349,12 @@ get_relocated_mem (struct prelink_info *info, DSO *dso, GElf_Addr addr,
return 2;
/* Note that apply_conflict_rela shouldn't rely on R_SYM
field of conflict to be 0. */
- dso->arch->apply_conflict_rela (info, info->conflict_rela + j,
- buf + off);
+ ret
+ = dso->arch->apply_conflict_rela (info, info->conflict_rela + j,
+ buf + off,
+ dest_addr ? dest_addr + off : 0);
+ if (ret)
+ return ret;
}
}
else
@@ -469,15 +477,17 @@ prelink_build_conflicts (struct prelink_info *info)
}
}
- for (i = 1; i < ndeps; ++i)
+ for (i = 0; i < ndeps; ++i)
{
+ int j, sec, first_conflict, maxidx;
+ struct prelink_conflict *conflict;
+
dso = info->dsos[i];
- ent = info->ent->depends[i - 1];
+ ent = i ? info->ent->depends[i - 1] : info->ent;
/* Verify .gnu.liblist sections of all dependent libraries. */
- if (ent->ndepends > 0)
+ if (i && ent->ndepends > 0)
{
- int j;
const char *name;
int nliblist;
Elf32_Lib *liblist;
@@ -541,83 +551,88 @@ prelink_build_conflicts (struct prelink_info *info)
}
}
- if (info->conflicts[i] || info->tls[i].modid)
+ info->curconflicts = &info->conflicts[i];
+ info->curtls = info->tls[i].modid ? info->tls + i : NULL;
+ first_conflict = info->conflict_rela_size;
+ sec = addr_to_sec (dso, dso->info[DT_SYMTAB]);
+ /* DT_SYMTAB should be found and should point to
+ start of .dynsym section. */
+ if (sec == -1 || dso->info[DT_SYMTAB] != dso->shdr[sec].sh_addr)
{
- int j, sec, first_conflict;
- struct prelink_conflict *conflict;
-
- info->curconflicts = info->conflicts[i];
- info->curtls = info->tls[i].modid ? info->tls + i : NULL;
- first_conflict = info->conflict_rela_size;
- sec = addr_to_sec (dso, dso->info[DT_SYMTAB]);
- /* DT_SYMTAB should be found and should point to
- start of .dynsym section. */
- if (sec == -1
- || dso->info[DT_SYMTAB] != dso->shdr[sec].sh_addr)
+ error (0, 0, "Bad symtab");
+ goto error_out;
+ }
+ info->symtab_start = dso->shdr[sec].sh_addr - dso->base;
+ info->symtab_end = info->symtab_start + dso->shdr[sec].sh_size;
+ for (j = 0; j < dso->ehdr.e_shnum; ++j)
+ {
+ if (! (dso->shdr[j].sh_flags & SHF_ALLOC))
+ continue;
+ switch (dso->shdr[j].sh_type)
{
- error (0, 0, "Bad symtab");
- goto error_out;
+ case SHT_REL:
+ if (i == 0
+ && strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[j].sh_name),
+ ".gnu.conflict") == 0)
+ break;
+ if (prelink_conflict_rel (dso, j, info))
+ goto error_out;
+ break;
+ case SHT_RELA:
+ if (i == 0
+ && strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[j].sh_name),
+ ".gnu.conflict") == 0)
+ break;
+ if (prelink_conflict_rela (dso, j, info))
+ goto error_out;
+ break;
}
- info->symtab_start = dso->shdr[sec].sh_addr - dso->base;
- info->symtab_end = info->symtab_start + dso->shdr[sec].sh_size;
- for (j = 0; j < dso->ehdr.e_shnum; ++j)
+ }
+
+ if (dso->arch->arch_prelink_conflict
+ && dso->arch->arch_prelink_conflict (dso, info))
+ goto error_out;
+
+ maxidx = 1;
+ if (info->curconflicts->hash != &info->curconflicts->first)
+ maxidx = 251;
+ for (j = 0; j < maxidx; j++)
+ for (conflict = info->curconflicts->hash[j]; conflict;
+ conflict = conflict->next)
+ if (! conflict->used && (i || conflict->ifunc))
{
- if (! (dso->shdr[j].sh_flags & SHF_ALLOC))
- continue;
- switch (dso->shdr[j].sh_type)
- {
- case SHT_REL:
- if (prelink_conflict_rel (dso, j, info))
- goto error_out;
- break;
- case SHT_RELA:
- if (prelink_conflict_rela (dso, j, info))
- goto error_out;
- break;
- }
+ error (0, 0, "%s: Conflict %08llx not found in any relocation",
+ dso->filename, (unsigned long long) conflict->symoff);
+ ret = 1;
}
- if (dso->arch->arch_prelink_conflict
- && dso->arch->arch_prelink_conflict (dso, info))
- goto error_out;
+ /* Record library's position in search scope into R_SYM field. */
+ for (j = first_conflict; j < info->conflict_rela_size; ++j)
+ info->conflict_rela[j].r_info
+ = GELF_R_INFO (i, GELF_R_TYPE (info->conflict_rela[j].r_info));
- for (conflict = info->curconflicts; conflict;
- conflict = conflict->next)
- if (! conflict->used)
- {
- error (0, 0, "%s: Conflict %08llx not found in any relocation",
- dso->filename, (unsigned long long) conflict->symoff);
- ret = 1;
- }
+ if (dynamic_info_is_set (dso, DT_TEXTREL)
+ && info->conflict_rela_size > first_conflict)
+ {
+ /* We allow prelinking against non-PIC libraries, as long as
+ no conflict is against read-only segment. */
+ int k;
- /* Record library's position in search scope into R_SYM field. */
for (j = first_conflict; j < info->conflict_rela_size; ++j)
- info->conflict_rela[j].r_info
- = reloc_r_info (dso, i,
- reloc_r_type (dso,
- info->conflict_rela[j].r_info));
-
- if (dynamic_info_is_set (dso, DT_TEXTREL)
- && info->conflict_rela_size > first_conflict)
- {
- /* We allow prelinking against non-PIC libraries, as long as
- no conflict is against read-only segment. */
- int k;
-
- for (j = first_conflict; j < info->conflict_rela_size; ++j)
- for (k = 0; k < dso->ehdr.e_phnum; ++k)
- if (dso->phdr[k].p_type == PT_LOAD
- && (dso->phdr[k].p_flags & PF_W) == 0
- && dso->phdr[k].p_vaddr
- <= info->conflict_rela[j].r_offset
- && dso->phdr[k].p_vaddr + dso->phdr[k].p_memsz
- > info->conflict_rela[j].r_offset)
- {
- error (0, 0, "%s: Cannot prelink against non-PIC shared library %s",
- info->dso->filename, dso->filename);
- goto error_out;
- }
- }
+ for (k = 0; k < dso->ehdr.e_phnum; ++k)
+ if (dso->phdr[k].p_type == PT_LOAD
+ && (dso->phdr[k].p_flags & PF_W) == 0
+ && dso->phdr[k].p_vaddr
+ <= info->conflict_rela[j].r_offset
+ && dso->phdr[k].p_vaddr + dso->phdr[k].p_memsz
+ > info->conflict_rela[j].r_offset)
+ {
+ error (0, 0, "%s: Cannot prelink against non-PIC shared library %s",
+ info->dso->filename, dso->filename);
+ goto error_out;
+ }
}
}
@@ -755,11 +770,13 @@ prelink_build_conflicts (struct prelink_info *info)
if (i < firstbss2)
j = get_relocated_mem (info, ndso, s->u.ent->base + s->value,
info->sdynbss + cr.rela[i].r_offset
- - info->sdynbss_base, cr.rela[i].r_addend);
+ - info->sdynbss_base, cr.rela[i].r_addend,
+ cr.rela[i].r_offset);
else
j = get_relocated_mem (info, ndso, s->u.ent->base + s->value,
info->dynbss + cr.rela[i].r_offset
- - info->dynbss_base, cr.rela[i].r_addend);
+ - info->dynbss_base, cr.rela[i].r_addend,
+ cr.rela[i].r_offset);
switch (j)
{
diff --git a/trunk/src/cxx.c b/trunk/src/cxx.c
index abb97a5..438cdfe 100644
--- a/trunk/src/cxx.c
+++ b/trunk/src/cxx.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2007, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -16,6 +16,7 @@
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <config.h>
+#include <alloca.h>
#include <assert.h>
#include <errno.h>
#include <error.h>
@@ -27,24 +28,168 @@
#include "prelink.h"
#include "reloc-info.h"
+static struct
+ {
+ const char *prefix;
+ unsigned char prefix_len, st_info, check_pltref;
+ }
+specials[] =
+ {
+ /* G++ 3.0 ABI. */
+ /* Virtual table. */
+ { "_ZTV", 4, GELF_ST_INFO (STB_WEAK, STT_OBJECT), 1 },
+ /* Typeinfo. */
+ { "_ZTI", 4, GELF_ST_INFO (STB_WEAK, STT_OBJECT), 0 },
+ /* G++ 2.96-RH ABI. */
+ /* Virtual table. */
+ { "__vt_", 5, GELF_ST_INFO (STB_WEAK, STT_OBJECT), 0 },
+ { NULL, 0, 0, 0 }
+ };
+
+struct find_cxx_sym_valsize
+{
+ GElf_Addr start;
+ GElf_Addr end;
+ unsigned int idx;
+ unsigned char mark;
+};
+
+struct find_cxx_sym_cache
+{
+ Elf_Data *symtab, *strtab;
+ int symsec, strsec, count;
+ struct find_cxx_sym_valsize vals[];
+};
+
struct find_cxx_sym
{
DSO *dso;
int n;
+ struct find_cxx_sym_cache *cache;
struct prelink_entry *ent;
Elf_Data *symtab, *strtab;
int symsec, strsec;
+ int lastndx;
GElf_Sym sym;
};
static int
+cachecmp (const void *a, const void *b)
+{
+ GElf_Addr va = ((const struct find_cxx_sym_valsize *) a)->start;
+ GElf_Addr vb = ((const struct find_cxx_sym_valsize *) b)->start;
+
+ if (va < vb)
+ return -1;
+ if (va > vb)
+ return 1;
+
+ va = ((const struct find_cxx_sym_valsize *) a)->end;
+ vb = ((const struct find_cxx_sym_valsize *) b)->end;
+
+ if (va < vb)
+ return -1;
+
+ return va > vb;
+}
+
+static struct find_cxx_sym_cache *
+create_cache (DSO *dso, int plt)
+{
+ Elf_Data *symtab, *strtab;
+ Elf_Scn *scn;
+ int symsec, strsec, ndx, dndx, maxndx;
+ struct find_cxx_sym_cache *cache;
+ GElf_Addr top;
+
+ symsec = addr_to_sec (dso, dso->info[DT_SYMTAB]);
+ if (symsec == -1)
+ return (struct find_cxx_sym_cache *) -1UL;
+ scn = dso->scn[symsec];
+ symtab = elf_getdata (scn, NULL);
+ assert (elf_getdata (scn, symtab) == NULL);
+ strsec = addr_to_sec (dso, dso->info[DT_STRTAB]);
+ if (strsec == -1)
+ return (struct find_cxx_sym_cache *) -1UL;
+ scn = dso->scn[strsec];
+ strtab = elf_getdata (scn, NULL);
+ assert (elf_getdata (scn, strtab) == NULL);
+ maxndx = symtab->d_size / dso->shdr[symsec].sh_entsize;
+
+ cache = malloc (sizeof (*cache) + sizeof (cache->vals[0]) * maxndx);
+ if (cache == NULL)
+ {
+ error (0, ENOMEM, "%s: Could load symbol table", dso->filename);
+ return NULL;
+ }
+
+ cache->symsec = symsec;
+ cache->strsec = strsec;
+ cache->symtab = symtab;
+ cache->strtab = strtab;
+ for (ndx = 0, dndx = 0; ndx < maxndx; ++ndx)
+ {
+ GElf_Sym sym;
+ const char *name;
+ int k;
+
+ gelfx_getsym (dso->elf, symtab, ndx, &sym);
+ if (plt)
+ {
+ if (sym.st_shndx != SHN_UNDEF || sym.st_value == 0)
+ continue;
+ }
+ else if (sym.st_shndx == SHN_UNDEF)
+ continue;
+ cache->vals[dndx].start = sym.st_value;
+ cache->vals[dndx].end = sym.st_value + sym.st_size;
+ cache->vals[dndx].idx = ndx;
+ cache->vals[dndx].mark = 0;
+ name = (const char *) strtab->d_buf + sym.st_name;
+ if (!plt && ELF32_ST_VISIBILITY (sym.st_other) == STV_DEFAULT)
+ for (k = 0; specials[k].prefix; ++k)
+ if (sym.st_info == specials[k].st_info
+ && strncmp (name, specials[k].prefix,
+ specials[k].prefix_len) == 0)
+ {
+ cache->vals[dndx].mark = 1;
+ break;
+ }
+ ++dndx;
+ }
+
+ maxndx = dndx;
+ qsort (cache->vals, maxndx, sizeof (cache->vals[0]), cachecmp);
+
+ if (!plt)
+ {
+ for (top = 0, ndx = 0; ndx < maxndx; ++ndx)
+ {
+ if (cache->vals[ndx].start < top
+ || (ndx < maxndx - 1
+ && cache->vals[ndx].end > cache->vals[ndx + 1].start))
+ cache->vals[ndx].mark = 0;
+ if (cache->vals[ndx].end > top)
+ top = cache->vals[ndx].end;
+ }
+
+ for (ndx = dndx = 0; ndx < maxndx; ++ndx)
+ if (cache->vals[ndx].mark)
+ cache->vals[dndx++] = cache->vals[ndx];
+ }
+ cache->count = dndx;
+ return cache;
+}
+
+static int
find_cxx_sym (struct prelink_info *info, GElf_Addr addr,
- struct find_cxx_sym *fcs, int reloc_size)
+ struct find_cxx_sym *fcs, int reloc_size,
+ struct find_cxx_sym_cache **cache)
{
int n, ndeps = info->ent->ndepends + 1;
- int ndx, maxndx;
+ unsigned int hi, lo, mid;
DSO *dso = NULL;
- Elf_Scn *scn;
+ struct find_cxx_sym_cache *c;
if (fcs->dso == NULL
|| addr < fcs->dso->base
@@ -67,44 +212,76 @@ find_cxx_sym (struct prelink_info *info, GElf_Addr addr,
}
assert (n < ndeps);
+
+ if (cache[n] == NULL)
+ {
+ cache[n] = create_cache (dso, 0);
+ if (cache[n] == NULL)
+ return -2;
+ }
+ if (cache[n] == (struct find_cxx_sym_cache *) -1UL)
+ return -1;
+
fcs->n = n;
fcs->ent = n ? info->ent->depends[n - 1] : info->ent;
fcs->dso = dso;
- fcs->symsec = addr_to_sec (dso, dso->info[DT_SYMTAB]);
- if (fcs->symsec == -1)
+ fcs->cache = cache[n];
+ fcs->symsec = fcs->cache->symsec;
+ fcs->symtab = fcs->cache->symtab;
+ fcs->strsec = fcs->cache->strsec;
+ fcs->strtab = fcs->cache->strtab;
+ fcs->lastndx = -1;
+ }
+ else
+ dso = fcs->dso;
+
+ c = fcs->cache;
+ lo = 0;
+ hi = c->count;
+ if (fcs->lastndx != -1)
+ {
+ if (c->vals[fcs->lastndx].start <= addr)
{
- fcs->ent = NULL;
- return -1;
+ lo = fcs->lastndx;
+ if (hi - lo >= 16)
+ {
+ if (c->vals[lo + 2].start > addr)
+ hi = lo + 2;
+ else if (c->vals[lo + 15].start > addr)
+ hi = lo + 15;
+ }
}
- scn = dso->scn[fcs->symsec];
- fcs->symtab = elf_getdata (scn, NULL);
- assert (elf_getdata (scn, fcs->symtab) == NULL);
- fcs->strsec = addr_to_sec (dso, dso->info[DT_STRTAB]);
- if (fcs->strsec == -1)
+ else
{
- fcs->ent = NULL;
- return -1;
+ hi = fcs->lastndx;
+ if (hi >= 15)
+ {
+ if (c->vals[hi - 2].start <= addr)
+ lo = hi - 2;
+ else if (c->vals[hi - 15].start <= addr)
+ lo = hi - 15;
+ }
}
- scn = dso->scn[fcs->strsec];
- fcs->strtab = elf_getdata (scn, NULL);
- assert (elf_getdata (scn, fcs->strtab) == NULL);
}
- else
- dso = fcs->dso;
-
- maxndx = fcs->symtab->d_size / dso->shdr[fcs->symsec].sh_entsize;
- for (ndx = 0; ndx < maxndx; ++ndx)
+ while (lo < hi)
{
- gelfx_getsym (dso->elf, fcs->symtab, ndx, &fcs->sym);
- if (fcs->sym.st_value <= addr
- && fcs->sym.st_value + fcs->sym.st_size >= addr + reloc_size)
- break;
+ mid = (lo + hi) / 2;
+ if (c->vals[mid].start <= addr)
+ {
+ if (c->vals[mid].end >= addr + reloc_size)
+ {
+ gelfx_getsym (dso->elf, fcs->symtab, c->vals[mid].idx,
+ &fcs->sym);
+ fcs->lastndx = mid;
+ return c->vals[mid].idx;
+ }
+ lo = mid + 1;
+ }
+ else
+ hi = mid;
}
- if (ndx == maxndx)
- return -1;
-
- return ndx;
+ return -1;
}
/* The idea here is that C++ virtual tables are always emitted
@@ -117,7 +294,8 @@ int
remove_redundant_cxx_conflicts (struct prelink_info *info)
{
int i, j, k, n, o, state, removed = 0;
- int ndx, maxndx, sec;
+ int ndx, sec;
+ unsigned int hi, lo, mid;
int reloc_type, reloc_size;
struct find_cxx_sym fcs1, fcs2;
char *mem1, *mem2;
@@ -127,24 +305,10 @@ remove_redundant_cxx_conflicts (struct prelink_info *info)
Elf_Data *binsymtab = NULL;
int binsymtabsec;
struct prelink_conflict *conflict;
- static struct
- {
- unsigned char *prefix;
- unsigned char prefix_len, st_info, check_pltref;
- unsigned char *section;
- }
- specials[] =
- {
- /* G++ 3.0 ABI. */
- /* Virtual table. */
- { "_ZTV", 4, GELF_ST_INFO (STB_WEAK, STT_OBJECT), 1, ".data" },
- /* Typeinfo. */
- { "_ZTI", 4, GELF_ST_INFO (STB_WEAK, STT_OBJECT), 0, ".data" },
- /* G++ 2.96-RH ABI. */
- /* Virtual table. */
- { "__vt_", 5, GELF_ST_INFO (STB_WEAK, STT_OBJECT), 0, ".data" },
- { NULL, 0, 0, 0, NULL }
- };
+ struct find_cxx_sym_cache **cache;
+ struct find_cxx_sym_cache *binsymcache = NULL;
+ int ret = 0;
+ int rtype_class_valid;
/* Don't bother doing this for non-C++ programs. */
for (i = 0; i < info->ent->ndepends; ++i)
@@ -162,11 +326,19 @@ remove_redundant_cxx_conflicts (struct prelink_info *info)
assert (elf_getdata (scn, binsymtab) == NULL);
}
+ rtype_class_valid = info->dso->arch->rtype_class_valid;
+
state = 0;
memset (&fcs1, 0, sizeof (fcs1));
memset (&fcs2, 0, sizeof (fcs2));
+ cache = alloca (sizeof (struct find_cxx_sym_cache *)
+ * (info->ent->ndepends + 1));
+ memset (cache, '\0', sizeof (struct find_cxx_sym_cache *)
+ * (info->ent->ndepends + 1));
for (i = 0; i < info->conflict_rela_size; ++i)
{
+ size_t cidx;
+
reloc_type = reloc_r_type (info->dso, info->conflict_rela[i].r_info);
reloc_size = info->dso->arch->reloc_size (reloc_type);
@@ -186,12 +358,16 @@ remove_redundant_cxx_conflicts (struct prelink_info *info)
}
n = find_cxx_sym (info, info->conflict_rela[i].r_offset,
- &fcs1, reloc_size);
+ &fcs1, reloc_size, cache);
- name = (const char *) fcs1.strtab->d_buf + fcs1.sym.st_name;
state = 0;
if (n == -1)
continue;
+ if (n == -2)
+ {
+ ret = 1;
+ goto out_free_cache;
+ }
state = 1;
sec = addr_to_sec (fcs1.dso, fcs1.sym.st_value);
if (sec == -1)
@@ -201,31 +377,20 @@ remove_redundant_cxx_conflicts (struct prelink_info *info)
if (secname == NULL)
continue;
+ name = (const char *) fcs1.strtab->d_buf + fcs1.sym.st_name;
+
for (k = 0; specials[k].prefix; ++k)
if (ELF32_ST_VISIBILITY (fcs1.sym.st_other) == STV_DEFAULT
&& fcs1.sym.st_info == specials[k].st_info
- && strncmp (name, specials[k].prefix, specials[k].prefix_len) == 0
- && strcmp (secname, specials[k].section) == 0)
+ && strncmp (name, specials[k].prefix, specials[k].prefix_len) == 0)
break;
if (specials[k].prefix == NULL)
continue;
- /* Now check there are no other symbols pointing to it. */
- maxndx = fcs1.symtab->d_size / fcs1.dso->shdr[fcs1.symsec].sh_entsize;
- for (ndx = 0; ndx < maxndx; ++ndx)
- if (ndx != n)
- {
- GElf_Sym sym;
-
- gelfx_getsym (fcs1.dso->elf, fcs1.symtab, ndx, &sym);
- if ((sym.st_value + sym.st_size > fcs1.sym.st_value
- && sym.st_value < fcs1.sym.st_value + fcs1.sym.st_size)
- || sym.st_value == fcs1.sym.st_value)
- break;
- }
-
- if (ndx < maxndx)
+ if (strcmp (secname, ".data") != 0
+ && strcmp (secname, ".data.rel.ro") != 0
+ && strcmp (secname, ".sdata") != 0)
continue;
if (specials[k].check_pltref)
@@ -234,10 +399,13 @@ remove_redundant_cxx_conflicts (struct prelink_info *info)
symtab_start = fcs1.dso->shdr[fcs1.symsec].sh_addr - fcs1.dso->base;
symoff = symtab_start + n * fcs1.dso->shdr[fcs1.symsec].sh_entsize;
- for (conflict = info->conflicts[fcs1.n]; conflict;
+ cidx = 0;
+ if (info->conflicts[fcs1.n].hash != &info->conflicts[fcs1.n].first)
+ cidx = symoff % 251;
+ for (conflict = info->conflicts[fcs1.n].hash[cidx]; conflict;
conflict = conflict->next)
if (conflict->symoff == symoff
- && conflict->reloc_class == RTYPE_CLASS_VALID)
+ && conflict->reloc_class == rtype_class_valid)
break;
if (conflict == NULL)
@@ -257,7 +425,13 @@ remove_redundant_cxx_conflicts (struct prelink_info *info)
goto check_pltref;
o = find_cxx_sym (info, conflict->lookup.ent->base + conflict->lookupval,
- &fcs2, fcs1.sym.st_size);
+ &fcs2, fcs1.sym.st_size, cache);
+
+ if (o == -2)
+ {
+ ret = 1;
+ goto out_free_cache;
+ }
if (o == -1
|| fcs1.sym.st_size != fcs2.sym.st_size
@@ -271,15 +445,16 @@ remove_redundant_cxx_conflicts (struct prelink_info *info)
{
error (0, ENOMEM, "%s: Could not compare %s arrays",
info->dso->filename, name);
- return 1;
+ ret = 1;
+ goto out_free_cache;
}
mem2 = mem1 + fcs1.sym.st_size;
if (get_relocated_mem (info, fcs1.dso, fcs1.sym.st_value, mem1,
- fcs1.sym.st_size)
+ fcs1.sym.st_size, 0)
|| get_relocated_mem (info, fcs2.dso, fcs2.sym.st_value, mem2,
- fcs1.sym.st_size)
+ fcs1.sym.st_size, 0)
|| memcmp (mem1, mem2, fcs1.sym.st_size) != 0)
{
free (mem1);
@@ -314,50 +489,133 @@ check_pltref:
|| binsymtab == NULL)
continue;
- maxndx = binsymtab->d_size / info->dso->shdr[binsymtabsec].sh_entsize;
- for (ndx = 0; ndx < maxndx; ++ndx)
+ if (binsymcache == NULL)
+ {
+ binsymcache = create_cache (info->dso, 1);
+ if (binsymcache == NULL)
+ {
+ ret = 1;
+ goto out_free_cache;
+ }
+ }
+ if (binsymcache == (struct find_cxx_sym_cache *) -1UL)
+ continue;
+
+ lo = 0;
+ mid = 0;
+ hi = binsymcache->count;
+ while (lo < hi)
+ {
+ mid = (lo + hi) / 2;
+ if (binsymcache->vals[mid].start < info->conflict_rela[i].r_addend)
+ lo = mid + 1;
+ else if (binsymcache->vals[mid].start
+ > info->conflict_rela[i].r_addend)
+ hi = mid;
+ else
+ break;
+ }
+ if (lo >= hi)
+ continue;
+
+ while (mid > 0 && binsymcache->vals[mid - 1].start
+ == info->conflict_rela[i].r_addend)
+ --mid;
+
+ while (mid < binsymcache->count
+ && binsymcache->vals[mid].start
+ == info->conflict_rela[i].r_addend)
{
GElf_Sym sym;
+ ndx = binsymcache->vals[mid].idx;
+ mid++;
gelfx_getsym (info->dso->elf, binsymtab, ndx, &sym);
- if (sym.st_value == info->conflict_rela[i].r_addend)
+ assert (sym.st_value == info->conflict_rela[i].r_addend);
+ if (sym.st_shndx == SHN_UNDEF && sym.st_value)
{
- if (sym.st_shndx == SHN_UNDEF && sym.st_value)
+ struct prelink_symbol *s;
+ size_t maxidx, l;
+
+ if (verbose > 4)
+ error (0, 0, "Possible C++ conflict removal due to reference to binary's .plt at %s:%s+%d",
+ fcs1.dso->filename, name,
+ (int) (info->conflict_rela[i].r_offset
+ - fcs1.sym.st_value));
+
+ for (s = &info->symbols[ndx]; s; s = s->next)
+ if (s->reloc_class == RTYPE_CLASS_PLT)
+ break;
+
+ if (s == NULL)
+ break;
+
+ maxidx = 1;
+ if (info->conflicts[fcs1.n].hash
+ != &info->conflicts[fcs1.n].first)
{
- struct prelink_symbol *s;
-
- if (verbose > 4)
- error (0, 0, "Possible C++ conflict removal due to reference to binary's .plt at %s:%s+%d",
- fcs1.dso->filename, name,
- (int) (info->conflict_rela[i].r_offset
- - fcs1.sym.st_value));
-
- for (s = &info->symbols[ndx]; s; s = s->next)
- if (s->reloc_class == RTYPE_CLASS_PLT)
- {
- for (conflict = info->conflicts[fcs1.n]; conflict;
- conflict = conflict->next)
- if (conflict->lookup.ent->base + conflict->lookupval
- == info->conflict_rela[i].r_addend
- && conflict->conflict.ent
- && (conflict->conflict.ent->base
- + conflict->conflictval
- == s->u.ent->base + s->value)
- && conflict->reloc_class == RTYPE_CLASS_VALID)
- {
- if (verbose > 3)
- error (0, 0, "Removing C++ conflict due to reference to binary's .plt at %s:%s+%d",
- fcs1.dso->filename, name,
- (int) (info->conflict_rela[i].r_offset
- - fcs1.sym.st_value));
-
- info->conflict_rela[i].r_info =
- reloc_r_info (info->dso, 1, reloc_r_type (info->dso, info->conflict_rela[i].r_info));
- ++removed;
- }
- break;
- }
+ if (info->conflicts[fcs1.n].hash2 == NULL)
+ {
+ info->conflicts[fcs1.n].hash2
+ = calloc (sizeof (struct prelink_conflict *), 251);
+ if (info->conflicts[fcs1.n].hash2 != NULL)
+ {
+ for (l = 0; l < 251; l++)
+ for (conflict = info->conflicts[fcs1.n].hash[l];
+ conflict; conflict = conflict->next)
+ if (conflict->reloc_class == rtype_class_valid
+ && conflict->conflict.ent)
+ {
+ size_t ccidx
+ = (conflict->lookup.ent->base
+ + conflict->lookupval) % 251;
+ conflict->next2
+ = info->conflicts[fcs1.n].hash2[ccidx];
+ info->conflicts[fcs1.n].hash2[ccidx]
+ = conflict;
+ }
+ }
+ }
+ if (info->conflicts[fcs1.n].hash2 != NULL)
+ {
+ size_t ccidx = info->conflict_rela[i].r_addend % 251;
+ for (conflict = info->conflicts[fcs1.n].hash2[ccidx];
+ conflict; conflict = conflict->next2)
+ if (conflict->lookup.ent->base + conflict->lookupval
+ == info->conflict_rela[i].r_addend
+ && (conflict->conflict.ent->base
+ + conflict->conflictval
+ == s->u.ent->base + s->value))
+ goto pltref_remove;
+ break;
+ }
+ maxidx = 251;
}
+
+ for (l = 0; l < maxidx; l++)
+ for (conflict = info->conflicts[fcs1.n].hash[l];
+ conflict; conflict = conflict->next)
+ if (conflict->lookup.ent->base + conflict->lookupval
+ == info->conflict_rela[i].r_addend
+ && conflict->conflict.ent
+ && (conflict->conflict.ent->base
+ + conflict->conflictval == s->u.ent->base + s->value)
+ && conflict->reloc_class == rtype_class_valid)
+ {
+pltref_remove:
+ if (verbose > 3)
+ error (0, 0, "Removing C++ conflict due to reference to binary's .plt at %s:%s+%d",
+ fcs1.dso->filename, name,
+ (int) (info->conflict_rela[i].r_offset
+ - fcs1.sym.st_value));
+
+ info->conflict_rela[i].r_info =
+ GELF_R_INFO (1, GELF_R_TYPE (info->conflict_rela[i].r_info));
+ ++removed;
+ goto pltref_check_done;
+ }
+
+pltref_check_done:
break;
}
}
@@ -375,5 +633,11 @@ check_pltref:
info->conflict_rela_size = j;
}
- return 0;
+out_free_cache:
+ for (i = 0; i < info->ent->ndepends + 1; i++)
+ if (cache[i] && cache[i] != (struct find_cxx_sym_cache *) -1UL)
+ free (cache[i]);
+ if (binsymcache && binsymcache != (struct find_cxx_sym_cache *) -1UL)
+ free (binsymcache);
+ return ret;
}
diff --git a/trunk/src/doit.c b/trunk/src/doit.c
index 2208ece..c94fc53 100644
--- a/trunk/src/doit.c
+++ b/trunk/src/doit.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2003, 2004, 2005 Red Hat, Inc.
+/* Copyright (C) 2001, 2003, 2004, 2005, 2007 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -38,6 +38,7 @@ find_ents (void **p, void *info)
struct collect_ents *l = (struct collect_ents *) info;
struct prelink_entry *e = * (struct prelink_entry **) p;
+ e->u.tmp = 0;
if ((e->type == ET_DYN && e->done == 1)
|| (e->type == ET_EXEC && e->done == 0 && ! libs_only))
l->ents[l->nents++] = e;
@@ -46,39 +47,14 @@ find_ents (void **p, void *info)
}
static void
-clear_ent_marks (struct prelink_entry *ent)
-{
- int i;
-
- ent->u.tmp = 0;
- for (i = 0; i < ent->ndepends; ++i)
- clear_ent_marks (ent->depends[i]);
-}
-
-static struct prelink_entry *
-find_unlisted_dependency (struct prelink_entry *ent)
-{
- int i;
- struct prelink_entry *ret;
-
- if (ent->u.tmp == 0)
- return ent;
- for (i = 0; i < ent->ndepends; ++i)
- if ((ret = find_unlisted_dependency (ent->depends[i])) != NULL)
- return ret;
- return NULL;
-}
-
-static void
prelink_ent (struct prelink_entry *ent)
{
- int i;
+ int i, j;
DSO *dso;
struct stat64 st;
struct prelink_link *hardlink;
char *move = NULL;
size_t movelen = 0;
- struct prelink_entry *dep;
for (i = 0; i < ent->ndepends; ++i)
if (ent->depends[i]->done == 1)
@@ -95,23 +71,31 @@ prelink_ent (struct prelink_entry *ent)
ent->filename, ent->depends[i]->filename);
return;
}
- else
- clear_ent_marks (ent->depends[i]);
ent->u.tmp = 1;
for (i = 0; i < ent->ndepends; ++i)
ent->depends[i]->u.tmp = 1;
-
- if ((dep = find_unlisted_dependency (ent)) != NULL)
+ for (i = 0; i < ent->ndepends; ++i)
{
- ent->done = 0;
- if (! undo)
- ent->type = ET_UNPRELINKABLE;
- if (verbose)
- error (0, 0, "Could not prelink %s because it doesn't use %s, but one of its dependencies has been prelinked against it",
- ent->filename, dep->filename);
- return;
+ struct prelink_entry *dent = ent->depends[i];
+ for (j = 0; j < dent->ndepends; ++j)
+ if (dent->depends[j]->u.tmp == 0)
+ {
+ ent->done = 0;
+ if (! undo)
+ ent->type = ET_UNPRELINKABLE;
+ if (verbose)
+ error (0, 0, "Could not prelink %s because it doesn't use %s, but one of its dependencies has been prelinked against it",
+ ent->filename, dent->depends[j]->filename);
+ ent->u.tmp = 0;
+ for (i = 0; i < ent->ndepends; ++i)
+ ent->depends[i]->u.tmp = 0;
+ return;
+ }
}
+ ent->u.tmp = 0;
+ for (i = 0; i < ent->ndepends; ++i)
+ ent->depends[i]->u.tmp = 0;
if (verbose)
{
diff --git a/trunk/src/dso.c b/trunk/src/dso.c
index 3c61ff2..b3b6ee3 100644
--- a/trunk/src/dso.c
+++ b/trunk/src/dso.c
@@ -849,6 +849,7 @@ reopen_dso (DSO *dso, struct section_move *move, const char *temp_base)
}
else
{
+ memset (&data, 0, sizeof data);
data.d_type = ELF_T_NUM;
data1 = NULL;
while ((data1 = elf_getdata (dso->scn[j], data1))
diff --git a/trunk/src/dwarf2.c b/trunk/src/dwarf2.c
index a0a89dd..e831a18 100644
--- a/trunk/src/dwarf2.c
+++ b/trunk/src/dwarf2.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2005, 2006 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2005, 2006, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -155,16 +155,18 @@ static struct
#define DEBUG_LINE 2
#define DEBUG_ARANGES 3
#define DEBUG_PUBNAMES 4
-#define DEBUG_MACINFO 5
-#define DEBUG_LOC 6
-#define DEBUG_STR 7
-#define DEBUG_FRAME 8
-#define DEBUG_RANGES 9
+#define DEBUG_PUBTYPES 5
+#define DEBUG_MACINFO 6
+#define DEBUG_LOC 7
+#define DEBUG_STR 8
+#define DEBUG_FRAME 9
+#define DEBUG_RANGES 10
{ ".debug_info", NULL, 0, 0 },
{ ".debug_abbrev", NULL, 0, 0 },
{ ".debug_line", NULL, 0, 0 },
{ ".debug_aranges", NULL, 0, 0 },
{ ".debug_pubnames", NULL, 0, 0 },
+ { ".debug_pubtypes", NULL, 0, 0 },
{ ".debug_macinfo", NULL, 0, 0 },
{ ".debug_loc", NULL, 0, 0 },
{ ".debug_str", NULL, 0, 0 },
@@ -191,6 +193,7 @@ struct cu_data
{
GElf_Addr cu_entry_pc;
GElf_Addr cu_low_pc;
+ unsigned char cu_version;
};
static hashval_t
@@ -250,7 +253,7 @@ no_memory:
}
if (*slot != NULL)
{
- error (0, 0, "%s: Duplicate DWARF-2 abbreviation %d", dso->filename,
+ error (0, 0, "%s: Duplicate DWARF abbreviation %d", dso->filename,
t->entry);
free (t);
htab_delete (h);
@@ -270,7 +273,7 @@ no_memory:
form = read_uleb128 (ptr);
if (form == 2 || form > DW_FORM_indirect)
{
- error (0, 0, "%s: Unknown DWARF-2 DW_FORM_%d", dso->filename, form);
+ error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename, form);
htab_delete (h);
return NULL;
}
@@ -280,7 +283,7 @@ no_memory:
}
if (read_uleb128 (ptr) != 0)
{
- error (0, 0, "%s: DWARF-2 abbreviation does not end with 2 zeros",
+ error (0, 0, "%s: DWARF abbreviation does not end with 2 zeros",
dso->filename);
htab_delete (h);
return NULL;
@@ -340,8 +343,11 @@ adjust_location_list (DSO *dso, unsigned char *ptr, size_t len,
case DW_OP_reg0 ... DW_OP_reg31:
case DW_OP_nop:
case DW_OP_push_object_address:
- case DW_OP_call_ref:
+ case DW_OP_form_tls_address:
+ case DW_OP_call_frame_cfa:
+ case DW_OP_stack_value:
case DW_OP_GNU_push_tls_address:
+ case DW_OP_GNU_uninit:
break;
case DW_OP_const1u:
case DW_OP_pick:
@@ -360,6 +366,7 @@ adjust_location_list (DSO *dso, unsigned char *ptr, size_t len,
case DW_OP_const4u:
case DW_OP_const4s:
case DW_OP_call4:
+ case DW_OP_call_ref:
ptr += 4;
break;
case DW_OP_const8u:
@@ -376,11 +383,17 @@ adjust_location_list (DSO *dso, unsigned char *ptr, size_t len,
read_uleb128 (ptr);
break;
case DW_OP_bregx:
+ case DW_OP_bit_piece:
read_uleb128 (ptr);
read_uleb128 (ptr);
break;
+ case DW_OP_implicit_value:
+ {
+ uint32_t len = read_uleb128 (ptr);
+ ptr += len;
+ }
default:
- error (0, 0, "%s: Unknown DWARF-2 DW_OP_%d", dso->filename, op);
+ error (0, 0, "%s: Unknown DWARF DW_OP_%d", dso->filename, op);
return 1;
}
}
@@ -596,6 +609,11 @@ adjust_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t,
read_uleb128 (ptr);
break;
case DW_FORM_ref_addr:
+ if (cu->cu_version == 2)
+ ptr += ptr_size;
+ else
+ ptr += 4;
+ break;
case DW_FORM_strp:
ptr += 4;
break;
@@ -622,7 +640,7 @@ adjust_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t,
assert (len < UINT_MAX);
break;
default:
- error (0, 0, "%s: Unknown DWARF-2 DW_FORM_%d", dso->filename,
+ error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename,
form);
return NULL;
}
@@ -645,7 +663,7 @@ adjust_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t,
|| (t->attr[i].attr >= DW_AT_sf_names
&& t->attr[i].attr <= DW_AT_body_end))
break;
- error (0, 0, "%s: Unknown DWARF-2 DW_AT_%d with block DW_FORM",
+ error (0, 0, "%s: Unknown DWARF DW_AT_%d with block DW_FORM",
dso->filename, t->attr[i].attr);
return NULL;
}
@@ -688,7 +706,7 @@ adjust_dwarf2_line (DSO *dso, GElf_Addr start, GElf_Addr adjust)
}
value = read_16 (ptr);
- if (value != 2)
+ if (value != 2 && value != 3)
{
error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
value);
@@ -836,7 +854,13 @@ adjust_dwarf2_frame (DSO *dso, GElf_Addr start, GElf_Addr adjust)
if (value == 0xffffffff)
{
/* CIE. */
- ptr++; /* Skip version. */
+ uint32_t version = *ptr++;
+ if (version != 1 && version != 3)
+ {
+ error (0, 0, "%s: unhandled .debug_frame version %d",
+ dso->filename, version);
+ return 1;
+ }
if (*ptr != '\0')
{
error (0, 0, "%s: .debug_frame unhandled augmentation \"%s\"",
@@ -846,7 +870,10 @@ adjust_dwarf2_frame (DSO *dso, GElf_Addr start, GElf_Addr adjust)
ptr++; /* Skip augmentation. */
read_uleb128 (ptr); /* Skip code_alignment factor. */
read_uleb128 (ptr); /* Skip data_alignment factor. */
- read_uleb128 (ptr); /* Skip return_address_register. */
+ if (version >= 3)
+ read_uleb128 (ptr); /* Skip return_address_register. */
+ else
+ ptr++;
}
else
{
@@ -881,6 +908,8 @@ adjust_dwarf2_frame (DSO *dso, GElf_Addr start, GElf_Addr adjust)
case DW_CFA_offset_extended_sf:
case DW_CFA_def_cfa_sf:
case DW_CFA_GNU_negative_offset_extended:
+ case DW_CFA_val_offset:
+ case DW_CFA_val_offset_sf:
read_uleb128 (ptr);
/* FALLTHROUGH */
case DW_CFA_restore_extended:
@@ -907,6 +936,7 @@ adjust_dwarf2_frame (DSO *dso, GElf_Addr start, GElf_Addr adjust)
ptr += 4;
break;
case DW_CFA_expression:
+ case DW_CFA_val_expression:
read_uleb128 (ptr);
/* FALLTHROUGH */
case DW_CFA_def_cfa_expression:
@@ -1041,12 +1071,13 @@ adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
}
value = read_16 (ptr);
- if (value != 2)
+ if (value != 2 && value != 3)
{
error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
value);
return 1;
}
+ cu.cu_version = value;
value = read_32 (ptr);
if (value >= debug_sections[DEBUG_ABBREV].size)
@@ -1054,7 +1085,7 @@ adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
if (debug_sections[DEBUG_ABBREV].data == NULL)
error (0, 0, "%s: .debug_abbrev not present", dso->filename);
else
- error (0, 0, "%s: DWARF-2 CU abbrev offset too large",
+ error (0, 0, "%s: DWARF CU abbrev offset too large",
dso->filename);
return 1;
}
@@ -1074,14 +1105,14 @@ adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
}
else
{
- error (0, 0, "%s: Invalid DWARF-2 pointer size %d",
+ error (0, 0, "%s: Invalid DWARF pointer size %d",
dso->filename, ptr_size);
return 1;
}
}
else if (read_1 (ptr) != ptr_size)
{
- error (0, 0, "%s: DWARF-2 pointer size differs between CUs",
+ error (0, 0, "%s: DWARF pointer size differs between CUs",
dso->filename);
return 1;
}
@@ -1102,7 +1133,7 @@ adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
t = htab_find_with_hash (abbrev, &tag, tag.entry);
if (t == NULL)
{
- error (0, 0, "%s: Could not find DWARF-2 abbreviation %d",
+ error (0, 0, "%s: Could not find DWARF abbreviation %d",
dso->filename, tag.entry);
htab_delete (abbrev);
return 1;
@@ -1138,6 +1169,7 @@ adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
/* .debug_abbrev requires no adjustement. */
/* .debug_pubnames requires no adjustement. */
+ /* .debug_pubtypes requires no adjustement. */
/* .debug_macinfo requires no adjustement. */
/* .debug_str requires no adjustement. */
/* .debug_ranges adjusted for each DW_AT_ranges pointing into it. */
diff --git a/trunk/src/dwarf2.h b/trunk/src/dwarf2.h
index 1f938f5..143a00b 100644
--- a/trunk/src/dwarf2.h
+++ b/trunk/src/dwarf2.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -71,6 +71,8 @@
#define DW_TAG_unspecified_type 0x3b
#define DW_TAG_partial_unit 0x3c
#define DW_TAG_imported_unit 0x3d
+#define DW_TAG_condition 0x3f
+#define DW_TAG_shared_type 0x40
#define DW_TAG_MIPS_loop 0x4081
#define DW_TAG_format_label 0x4101
#define DW_TAG_function_template 0x4102
@@ -348,7 +350,14 @@
#define DW_OP_call2 0x98
#define DW_OP_call4 0x99
#define DW_OP_call_ref 0x9a
+#define DW_OP_form_tls_address 0x9b
+#define DW_OP_call_frame_cfa 0x9c
+#define DW_OP_bit_piece 0x9d
+#define DW_OP_implicit_value 0x9e
+#define DW_OP_stack_value 0x9f
#define DW_OP_GNU_push_tls_address 0xe0
+#define DW_OP_GNU_uninit 0xf0
+#define DW_OP_GNU_encoded_addr 0xf1
#define DW_OP_lo_user 0xe0
#define DW_OP_hi_user 0xff
@@ -362,6 +371,12 @@
#define DW_ATE_unsigned 0x7
#define DW_ATE_unsigned_char 0x8
#define DW_ATE_imaginary_float 0x9
+#define DW_ATE_packed_decimal 0xa
+#define DW_ATE_numeric_string 0xb
+#define DW_ATE_edited 0xc
+#define DW_ATE_signed_fixed 0xd
+#define DW_ATE_unsigned_fixed 0xe
+#define DW_ATE_decimal_float 0xf
#define DW_ATE_lo_user 0x80
#define DW_ATE_hi_user 0xff
@@ -437,6 +452,9 @@
#define DW_CFA_offset_extended_sf 0x11
#define DW_CFA_def_cfa_sf 0x12
#define DW_CFA_def_cfa_offset_sf 0x13
+#define DW_CFA_val_offset 0x14
+#define DW_CFA_val_offset_sf 0x15
+#define DW_CFA_val_expression 0x16
#define DW_CFA_MIPS_advance_loc8 0x1d
#define DW_CFA_GNU_window_save 0x2d
#define DW_CFA_GNU_args_size 0x2e
@@ -468,6 +486,11 @@
#define DW_LANG_C99 0x000c
#define DW_LANG_Ada95 0x000d
#define DW_LANG_Fortran95 0x000e
+#define DW_LANG_PLI 0x000f
+#define DW_LANG_ObjC 0x0010
+#define DW_LANG_ObjC_plus_plus 0x0011
+#define DW_LANG_UPC 0x0012
+#define DW_LANG_D 0x0013
#define DW_LANG_Mips_Assembler 0x8001
#define DW_LANG_lo_user 0x8000
#define DW_LANG_hi_user 0xffff
diff --git a/trunk/src/fptr.c b/trunk/src/fptr.c
index 7602d5e..cfe3aed 100644
--- a/trunk/src/fptr.c
+++ b/trunk/src/fptr.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2007 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -147,17 +147,21 @@ opd_init (struct prelink_info *info)
struct prelink_entry *ent;
struct prelink_conflict *conflict;
struct opd_lib *ol;
+ size_t maxidx = 1;
ent = info->ent->depends[i];
ol = ent->opd;
+ if (info->conflicts[i + 1].hash != &info->conflicts[i + 1].first)
+ maxidx = 251;
for (j = 0; j < ol->nrefs; ++j)
{
+ GElf_Addr symoff = ol->u.refs[j].symoff;
refent.val = ol->u.refs[j].ent->val;
refent.gp = ol->u.refs[j].ent->gp;
- for (conflict = info->conflicts[i + 1]; conflict;
+ for (conflict = info->conflicts[i + 1].hash[symoff % maxidx]; conflict;
conflict = conflict->next)
{
- if (conflict->symoff == ol->u.refs[j].symoff
+ if (conflict->symoff == symoff
&& conflict->reloc_class != RTYPE_CLASS_COPY
&& conflict->reloc_class != RTYPE_CLASS_TLS)
break;
@@ -183,6 +187,7 @@ opd_init (struct prelink_info *info)
struct opd_ent_plt *entp
= (struct opd_ent_plt *) ol->u.refs[j].ent;
int k;
+ size_t idx = 0;
for (k = 0; k < info->ent->ndepends; ++k)
if (info->ent->depends[k] == entp->lib)
@@ -190,7 +195,9 @@ opd_init (struct prelink_info *info)
assert (k < info->ent->ndepends);
- for (conflict = info->conflicts[k + 1]; conflict;
+ if (info->conflicts[k + 1].hash != &info->conflicts[k + 1].first)
+ idx = entp->symoff % 251;
+ for (conflict = info->conflicts[k + 1].hash[idx]; conflict;
conflict = conflict->next)
{
if (conflict->symoff == entp->symoff
diff --git a/trunk/src/gather.c b/trunk/src/gather.c
index 958a8ad..16ed21b 100644
--- a/trunk/src/gather.c
+++ b/trunk/src/gather.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -1077,6 +1077,8 @@ gather_object (const char *name, int deref, int onefs)
++implicit;
ret = wrap_nftw64 (name, gather_func, 20, flags | FTW_ACTIONRETVAL);
--implicit;
+ if (ret < 0)
+ error (0, errno, "Failed searching %s", name);
#ifndef HAVE_FTW_ACTIONRETVAL
free (blacklist_dir);
blacklist_dir = NULL;
@@ -1087,13 +1089,20 @@ gather_object (const char *name, int deref, int onefs)
return gather_binlib (name, &st);
}
+static struct config_line
+{
+ struct config_line *next;
+ char line[1];
+} *config_lines, **config_end = &config_lines;
+
int
-gather_config (const char *config)
+read_config (const char *config)
{
FILE *file = fopen (config, "r");
char *line = NULL;
- size_t len;
+ size_t len, llen;
int ret = 0;
+ struct config_line *c;
if (file == NULL)
{
@@ -1101,12 +1110,9 @@ gather_config (const char *config)
return 1;
}
- implicit = 1;
do
{
ssize_t i = getline (&line, &len, file);
- int deref = 0;
- int onefs = 0;
char *p;
if (i < 0)
@@ -1120,6 +1126,62 @@ gather_config (const char *config)
*p = '\0';
p = line + strspn (line, " \t");
+ if (p[0] == '-' && p[1] == 'c' && (p[2] == ' ' || p[2] == '\t'))
+ {
+ glob_t g;
+ p += 2 + strspn (p + 2, " \t");
+
+ if (!glob (p, GLOB_BRACE, NULL, &g))
+ {
+ size_t n;
+
+ for (n = 0; n < g.gl_pathc; ++n)
+ if (read_config (g.gl_pathv[n]))
+ {
+ ret = 1;
+ break;
+ }
+
+ globfree (&g);
+ if (ret)
+ break;
+ }
+ continue;
+ }
+
+ llen = strlen (p);
+ c = malloc (sizeof (*c) + llen);
+ if (c == NULL)
+ {
+ error (0, ENOMEM, "Could not cache config file");
+ ret = 1;
+ break;
+ }
+
+ c->next = NULL;
+ memcpy (c->line, p, llen + 1);
+ *config_end = c;
+ config_end = &c->next;
+ }
+ while (!feof (file));
+
+ free (line);
+ fclose (file);
+ return ret;
+}
+
+int
+gather_config (void)
+{
+ struct config_line *c;
+ int ret = 0;
+
+ implicit = 1;
+ for (c = config_lines; c; c = c->next)
+ {
+ int deref = 0;
+ int onefs = 0;
+ char *p = c->line;
while (*p == '-')
{
@@ -1127,7 +1189,7 @@ gather_config (const char *config)
{
case 'h': deref = 1; break;
case 'l': onefs = 1; break;
- case 'b': *p = '\0'; continue;
+ case 'b': p = ""; continue;
default:
error (0, 0, "Unknown directory option `%s'\n", p);
break;
@@ -1170,10 +1232,8 @@ gather_config (const char *config)
break;
}
}
- } while (!feof (file));
+ }
- free (line);
- fclose (file);
implicit = 0;
return ret;
}
@@ -1351,39 +1411,18 @@ add_blacklist_ext (const char *ext)
}
int
-blacklist_from_config (const char *config)
+blacklist_from_config (void)
{
- FILE *file = fopen (config, "r");
- char *line = NULL;
- size_t len;
+ struct config_line *c;
int ret = 0;
- if (file == NULL)
- {
- error (0, errno, "Can't open configuration file %s", config);
- return 1;
- }
-
implicit = 1;
- do
+ for (c = config_lines; c; c = c->next)
{
- ssize_t i = getline (&line, &len, file);
int deref = 0;
int onefs = 0;
int blacklist = 0;
- char *p;
-
- if (i < 0)
- break;
-
- if (line[i - 1] == '\n')
- line[i - 1] = '\0';
-
- p = strchr (line, '#');
- if (p != NULL)
- *p = '\0';
-
- p = line + strspn (line, " \t");
+ char *p = c->line;
while (*p == '-')
{
@@ -1437,10 +1476,8 @@ blacklist_from_config (const char *config)
break;
}
}
- } while (!feof (file));
+ }
- free (line);
- fclose (file);
implicit = 0;
return ret;
}
diff --git a/trunk/src/get.c b/trunk/src/get.c
index 0ae418b..001bb1e 100644
--- a/trunk/src/get.c
+++ b/trunk/src/get.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -39,6 +39,27 @@ is_ldso_soname (const char *soname)
return 0;
}
+static void
+conflict_hash_init (struct prelink_conflicts *conflicts)
+{
+ struct prelink_conflict **hash
+ = calloc (sizeof (struct prelink_conflict *), 251);
+ struct prelink_conflict *conflict, *next;
+ size_t idx;
+
+ if (hash == NULL)
+ return;
+
+ for (conflict = conflicts->first; conflict; conflict = next)
+ {
+ next = conflict->next;
+ idx = conflict->symoff % 251;
+ conflict->next = hash[idx];
+ hash[idx] = conflict;
+ }
+ conflicts->hash = hash;
+}
+
static int
prelink_record_relocations (struct prelink_info *info, FILE *f,
const char *ent_filename)
@@ -208,18 +229,20 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
if (dso->ehdr.e_type == ET_EXEC || dso->arch->create_opd)
{
- info->conflicts = (struct prelink_conflict **)
- calloc (sizeof (struct prelink_conflict *), ndeps);
+ info->conflicts = (struct prelink_conflicts *)
+ calloc (sizeof (struct prelink_conflicts), ndeps);
if (info->conflicts == NULL)
{
error (0, ENOMEM, "%s: Can't build list of conflicts", info->ent->filename);
goto error_out;
}
+ for (i = 0; i < ndeps; i++)
+ info->conflicts[i].hash = &info->conflicts[i].first;
}
do
{
unsigned long long symstart, symoff, valstart[3], value[3];
- int reloc_class, len, type = 1;
+ int reloc_class, len, type = 1, ifunc = 0;
char *symname;
r = strchr (buffer, '\n');
@@ -253,14 +276,26 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
if (type)
reloc_class = dso->arch->reloc_class (reloc_class);
else
- reloc_class |= RTYPE_CLASS_VALID;
+ {
+ if (reloc_class & 8)
+ {
+ reloc_class = ((reloc_class & ~8)
+ | dso->arch->rtype_class_valid);
+ ifunc = 1;
+ }
+ else if ((reloc_class | RTYPE_CLASS_VALID) == RTYPE_CLASS_TLS)
+ reloc_class |= RTYPE_CLASS_VALID;
+ else
+ reloc_class |= dso->arch->rtype_class_valid;
+ }
while (*symname == ' ' || *symname == '\t') ++symname;
ent = NULL;
tls = NULL;
if (symstart == deps[0].start
- || (reloc_class == RTYPE_CLASS_TLS && info->conflicts))
+ || ((reloc_class == RTYPE_CLASS_TLS || ifunc)
+ && info->conflicts))
{
for (i = 0; i < ndeps; i++)
if (deps[i].start == valstart[0])
@@ -289,7 +324,7 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
}
}
- if (symstart == deps[0].start)
+ if (symstart == deps[0].start && (!ifunc || info->conflicts == NULL))
{
/* Only interested in relocations from the current object. */
if (symoff < info->symtab_start || symoff >= info->symtab_end)
@@ -299,7 +334,8 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
goto error_out;
}
- if (ent == info->ent && reloc_class != RTYPE_CLASS_TLS)
+ if (ent == info->ent
+ && reloc_class != RTYPE_CLASS_TLS)
value[0] = adjust_old_to_new (info->dso, value[0]);
s = &info->symbols[(symoff - info->symtab_start)
@@ -344,12 +380,14 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
s->next = NULL;
}
}
- else if (reloc_class == RTYPE_CLASS_TLS && info->conflicts)
+ else if ((reloc_class == RTYPE_CLASS_TLS || ifunc)
+ && info->conflicts)
{
struct prelink_conflict *conflict;
int symowner;
+ size_t idx;
- for (symowner = 1; symowner < ndeps; symowner++)
+ for (symowner = 0; symowner < ndeps; symowner++)
if (deps[symowner].start == symstart)
break;
if (symowner == ndeps)
@@ -359,13 +397,20 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
goto error_out;
}
- for (conflict = info->conflicts[symowner]; conflict;
+ idx = 0;
+ if (info->conflicts[symowner].hash != &info->conflicts[symowner].first)
+ idx = symoff % 251;
+ for (conflict = info->conflicts[symowner].hash[idx]; conflict;
conflict = conflict->next)
if (conflict->symoff == symoff
&& conflict->reloc_class == reloc_class)
{
- if (conflict->lookup.tls != tls
- || conflict->conflict.tls != tls
+ if ((reloc_class != RTYPE_CLASS_TLS
+ && (conflict->lookup.ent != ent
+ || conflict->conflict.ent != ent))
+ || (reloc_class == RTYPE_CLASS_TLS
+ && (conflict->lookup.tls != tls
+ || conflict->conflict.tls != tls))
|| conflict->lookupval != value[0]
|| conflict->conflictval != value[0])
{
@@ -384,15 +429,27 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
goto error_out;
}
- conflict->next = info->conflicts[symowner];
- info->conflicts[symowner] = conflict;
- conflict->lookup.tls = tls;
- conflict->conflict.tls = tls;
+ conflict->next = info->conflicts[symowner].hash[idx];
+ conflict->next2 = NULL;
+ info->conflicts[symowner].hash[idx] = conflict;
+ if (reloc_class != RTYPE_CLASS_TLS)
+ {
+ conflict->lookup.ent = ent;
+ conflict->conflict.ent = ent;
+ }
+ else
+ {
+ conflict->lookup.tls = tls;
+ conflict->conflict.tls = tls;
+ }
conflict->lookupval = value[0];
conflict->conflictval = value[0];
conflict->symoff = symoff;
conflict->reloc_class = reloc_class;
conflict->used = 0;
+ conflict->ifunc = ifunc;
+ if (++info->conflicts[symowner].count == 16)
+ conflict_hash_init (&info->conflicts[symowner]);
}
}
}
@@ -423,7 +480,18 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
if (type)
reloc_class = dso->arch->reloc_class (reloc_class);
else
- reloc_class |= RTYPE_CLASS_VALID;
+ {
+ if (reloc_class & 8)
+ {
+ reloc_class = ((reloc_class & ~8)
+ | dso->arch->rtype_class_valid);
+ ifunc = 1;
+ }
+ else if ((reloc_class | RTYPE_CLASS_VALID) == RTYPE_CLASS_TLS)
+ reloc_class |= RTYPE_CLASS_VALID;
+ else
+ reloc_class |= dso->arch->rtype_class_valid;
+ }
while (*symname == ' ' || *symname == '\t') ++symname;
@@ -439,6 +507,7 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
struct prelink_tls *tlss[2];
struct prelink_conflict *conflict;
int symowner, j;
+ size_t idx;
for (symowner = 1; symowner < ndeps; symowner++)
if (deps[symowner].start == symstart)
@@ -480,7 +549,11 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
}
}
- for (conflict = info->conflicts[symowner]; conflict;
+ idx = 0;
+ if (info->conflicts[symowner].hash
+ != &info->conflicts[symowner].first)
+ idx = symoff % 251;
+ for (conflict = info->conflicts[symowner].hash[idx]; conflict;
conflict = conflict->next)
if (conflict->symoff == symoff
&& conflict->reloc_class == reloc_class)
@@ -509,8 +582,9 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
goto error_out;
}
- conflict->next = info->conflicts[symowner];
- info->conflicts[symowner] = conflict;
+ conflict->next = info->conflicts[symowner].hash[idx];
+ conflict->next2 = NULL;
+ info->conflicts[symowner].hash[idx] = conflict;
if (reloc_class != RTYPE_CLASS_TLS)
{
conflict->lookup.ent = ents[0];
@@ -526,6 +600,9 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
conflict->symoff = symoff;
conflict->reloc_class = reloc_class;
conflict->used = 0;
+ conflict->ifunc = ifunc;
+ if (++info->conflicts[symowner].count == 16)
+ conflict_hash_init (&info->conflicts[symowner]);
}
}
}
diff --git a/trunk/src/main.c b/trunk/src/main.c
index 7c3e1a4..2c442e8 100644
--- a/trunk/src/main.c
+++ b/trunk/src/main.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -453,13 +453,16 @@ main (int argc, char *argv[])
return failures;
}
- if (blacklist_from_config (prelink_conf))
+ if (read_config (prelink_conf))
+ return EXIT_FAILURE;
+
+ if (blacklist_from_config ())
return EXIT_FAILURE;
if (quick)
prelink_load_cache ();
- if (gather_config (prelink_conf))
+ if (gather_config ())
return EXIT_FAILURE;
while (remaining < argc)
diff --git a/trunk/src/prelink.c b/trunk/src/prelink.c
index 663a071..0798811 100644
--- a/trunk/src/prelink.c
+++ b/trunk/src/prelink.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -817,15 +817,37 @@ free_info (struct prelink_info *info)
{
for (i = 0; i < info->ent->ndepends + 1; ++i)
{
- struct prelink_conflict *c = info->conflicts[i];
- void *f;
+ if (info->conflicts[i].hash == &info->conflicts[i].first)
+ {
+ struct prelink_conflict *c = info->conflicts[i].first;
+ void *f;
- while (c != NULL)
+ while (c != NULL)
+ {
+ f = c;
+ c = c->next;
+ free (f);
+ }
+ }
+ else
{
- f = c;
- c = c->next;
- free (f);
+ int j;
+ for (j = 0; j < 251; j++)
+ {
+ struct prelink_conflict *c = info->conflicts[i].hash[j];
+ void *f;
+
+ while (c != NULL)
+ {
+ f = c;
+ c = c->next;
+ free (f);
+ }
+ }
+ free (info->conflicts[i].hash);
}
+ if (info->conflicts[i].hash2 != NULL)
+ free (info->conflicts[i].hash2);
}
free (info->conflicts);
}
diff --git a/trunk/src/prelink.h b/trunk/src/prelink.h
index a50ddfe..78f775d 100644
--- a/trunk/src/prelink.h
+++ b/trunk/src/prelink.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009
+ Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
Updated by Maciej W. Rozycki <macro@codesourcery.com>, 2008.
@@ -103,6 +104,20 @@ typedef uint8_t Elf64_Byte;
#define RSS_UNDEF 0
#endif
+#ifndef R_ARM_TLS_DTPMOD32
+#define R_ARM_TLS_DTPMOD32 17
+#define R_ARM_TLS_DTPOFF32 18
+#define R_ARM_TLS_TPOFF32 19
+#endif
+
+#ifndef R_386_IRELATIVE
+#define R_386_IRELATIVE 42
+#endif
+
+#ifndef R_X86_64_IRELATIVE
+#define R_X86_64_IRELATIVE 37
+#endif
+
struct prelink_entry;
struct prelink_info;
struct PLArch;
@@ -180,6 +195,7 @@ struct PLArch
int R_COPY;
int R_JMP_SLOT;
int R_RELATIVE;
+ int rtype_class_valid;
int (*arch_adjust) (DSO *dso, GElf_Addr start, GElf_Addr adjust);
int (*adjust_section) (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust);
int (*adjust_dyn) (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
@@ -198,7 +214,7 @@ struct PLArch
GElf_Rela *rela, GElf_Addr relaaddr);
int (*arch_prelink_conflict) (DSO *dso, struct prelink_info *info);
int (*apply_conflict_rela) (struct prelink_info *info, GElf_Rela *rela,
- char *buf);
+ char *buf, GElf_Addr dest_addr);
int (*apply_rel) (struct prelink_info *info, GElf_Rel *rel, char *buf);
int (*apply_rela) (struct prelink_info *info, GElf_Rela *rela, char *buf);
int (*rel_to_rela) (DSO *dso, GElf_Rel *rel, GElf_Rela *rela);
@@ -416,6 +432,7 @@ struct prelink_symbol
struct prelink_conflict
{
struct prelink_conflict *next;
+ struct prelink_conflict *next2;
/* Object which it was relocated to. */
union
{
@@ -431,7 +448,16 @@ struct prelink_conflict
/* Value it has in conflict.ent. */
GElf_Addr conflictval;
int reloc_class;
- int used;
+ unsigned char used;
+ unsigned char ifunc;
+};
+
+struct prelink_conflicts
+{
+ struct prelink_conflict *first;
+ struct prelink_conflict **hash;
+ struct prelink_conflict **hash2;
+ size_t count;
};
#define conflict_lookup_value(cfl) \
@@ -444,8 +470,8 @@ struct prelink_info
DSO **dsos;
struct prelink_entry *ent;
struct prelink_symbol *symbols;
- struct prelink_conflict **conflicts;
- struct prelink_conflict *curconflicts;
+ struct prelink_conflicts *conflicts;
+ struct prelink_conflicts *curconflicts;
struct prelink_tls *tls, *curtls;
const char **sonames;
char *dynbss, *sdynbss;
@@ -488,17 +514,18 @@ int prelink_undo (DSO *dso);
int prelink_verify (const char *filename);
int gather_object (const char *dir, int deref, int onefs);
-int gather_config (const char *config);
+int read_config (const char *config);
+int gather_config (void);
int gather_check_libs (void);
int add_to_blacklist (const char *name, int deref, int onefs);
-int blacklist_from_config (const char *config);
+int blacklist_from_config (void);
FILE *execve_open (const char *path, char *const argv[], char *const envp[]);
int execve_close (FILE *f);
int remove_redundant_cxx_conflicts (struct prelink_info *info);
int get_relocated_mem (struct prelink_info *info, DSO *dso, GElf_Addr addr,
- char *buf, GElf_Word size);
+ char *buf, GElf_Word size, GElf_Addr dest_addr);
int layout_libs (void);
diff --git a/trunk/src/space.c b/trunk/src/space.c
index 35bcfc7..4bd4760 100644
--- a/trunk/src/space.c
+++ b/trunk/src/space.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2006 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -412,14 +412,20 @@ find_readonly_space (DSO *dso, GElf_Shdr *add, GElf_Ehdr *ehdr,
if (shdr[k].sh_addr > add->sh_addr)
{
/* Don't allow inserting in between reloc sections
- if they are adjacent. */
- if (shdr[k].sh_type != SHT_REL
- && shdr[k].sh_type != SHT_RELA)
+ if they are adjacent. Similarly for adjacent
+ note sections. */
+ int sh_type1 = (shdr[k - 1].sh_type == SHT_RELA)
+ ? SHT_REL : shdr[k - 1].sh_type;
+ int sh_type2 = (shdr[k].sh_type == SHT_RELA)
+ ? SHT_REL : shdr[k].sh_type;
+
+ if (sh_type1 != sh_type2)
break;
- if (shdr[k - 1].sh_type != SHT_REL
- && shdr[k - 1].sh_type != SHT_RELA)
+
+ if (sh_type1 != SHT_REL && sh_type1 != SHT_NOTE)
break;
- if (shdr[k - 1].sh_addr + shdr[k - 1].sh_size
+ if ((shdr[k - 1].sh_addr
+ + ((shdr[k - 1].sh_size + 3) & -4))
!= shdr[k].sh_addr)
break;
}
@@ -512,150 +518,208 @@ find_readonly_space (DSO *dso, GElf_Shdr *add, GElf_Ehdr *ehdr,
{
addr = ehdr->e_phoff + (ehdr->e_phnum + 1) * ehdr->e_phentsize;
for (j = 1; j < ehdr->e_shnum; ++j)
- if (addr > shdr[j].sh_offset)
- {
- GElf_Addr start, addstart, endaddr, *old_addr;
- GElf_Addr minsize = ~(GElf_Addr) 0;
- int movesec = -1, last, k, e;
-
- if (ehdr->e_phoff < phdr[i].p_offset
- || ehdr->e_phoff + (ehdr->e_phnum + 1) * ehdr->e_phentsize
- > phdr[i].p_offset + phdr[i].p_filesz
- || ! readonly_is_movable (dso, ehdr, shdr, j)
- || shdr[j].sh_addr >= phdr[i].p_vaddr + phdr[i].p_filesz)
- {
- error (0, 0, "%s: No space in ELF segment table to add new ELF segment",
- dso->filename);
- return 0;
- }
-
- start = phdr[i].p_vaddr - phdr[i].p_offset + ehdr->e_phoff
- + (ehdr->e_phnum + 1) * ehdr->e_phentsize;
- for (last = 1; last < ehdr->e_shnum; ++last)
- if (! readonly_is_movable (dso, ehdr, shdr, last)
- || shdr[last].sh_addr >= phdr[i].p_vaddr + phdr[i].p_filesz)
- break;
- for (j = 1; j < last; ++j)
- {
- addstart = (start + add->sh_addralign - 1)
- & ~(add->sh_addralign - 1);
- start = (start + shdr[j].sh_addralign - 1)
- & ~(shdr[j].sh_addralign - 1);
- endaddr = -1;
- if (j + 1 < ehdr->e_shnum)
- endaddr = shdr[j + 1].sh_addr;
- if (phdr[i].p_vaddr + phdr[i].p_filesz < endaddr)
- endaddr = phdr[i].p_vaddr + phdr[i].p_filesz;
-
- switch (shdr[j].sh_type)
- {
- case SHT_HASH:
- case SHT_GNU_HASH:
- case SHT_DYNSYM:
- case SHT_STRTAB:
- case SHT_GNU_verdef:
- case SHT_GNU_verneed:
- case SHT_GNU_versym:
- case SHT_GNU_LIBLIST:
- if (endaddr >= start
- && endaddr - start < minsize)
- {
- minsize = endaddr - start;
- movesec = j;
- }
- if (endaddr > addstart
- && endaddr - addstart > add->sh_size
- && endaddr - addstart - add->sh_size
- < minsize)
- {
- minsize = endaddr - addstart - add->sh_size;
- movesec = j;
- }
- break;
- }
-
- if (start + shdr[j].sh_size <= endaddr)
- {
- movesec = j + 1;
- break;
- }
- start += shdr[j].sh_size;
- }
-
- if (movesec == -1)
- {
- error (0, 0, "%s: No space in ELF segment table to add new ELF segment",
- dso->filename);
- return 0;
- }
-
- start = phdr[i].p_vaddr - phdr[i].p_offset + ehdr->e_phoff
- + (ehdr->e_phnum + 1) * ehdr->e_phentsize;
- old_addr = (GElf_Addr *) alloca (movesec * sizeof (GElf_Addr));
- for (k = 1; k < movesec; ++k)
- {
- start = (start + shdr[k].sh_addralign - 1)
- & ~(shdr[k].sh_addralign - 1);
- old_addr[k] = shdr[k].sh_addr;
- shdr[k].sh_addr = start;
- shdr[k].sh_offset = start + phdr[i].p_offset
- - phdr[i].p_vaddr;
- start += shdr[k].sh_size;
- }
+ {
+ if (addr > shdr[j].sh_offset)
+ {
+ GElf_Addr start, addstart, endaddr, *old_addr;
+ GElf_Addr minsize = ~(GElf_Addr) 0;
+ int movesec = -1, last, k, e;
+
+ if (ehdr->e_phoff < phdr[i].p_offset
+ || ehdr->e_phoff + (ehdr->e_phnum + 1) * ehdr->e_phentsize
+ > phdr[i].p_offset + phdr[i].p_filesz
+ || ! readonly_is_movable (dso, ehdr, shdr, j)
+ || shdr[j].sh_addr >= phdr[i].p_vaddr + phdr[i].p_filesz)
+ {
+ error (0, 0, "%s: No space in ELF segment table to add new ELF segment",
+ dso->filename);
+ return 0;
+ }
- for (e = 0; e < ehdr->e_phnum; ++e)
- if (phdr[e].p_type != PT_LOAD
- && phdr[e].p_type != PT_GNU_STACK)
- for (k = 1; k < movesec; ++k)
- if (old_addr[k] == phdr[e].p_vaddr)
+ start = phdr[i].p_vaddr - phdr[i].p_offset + ehdr->e_phoff
+ + (ehdr->e_phnum + 1) * ehdr->e_phentsize;
+ for (last = 1; last < ehdr->e_shnum; ++last)
+ if (! readonly_is_movable (dso, ehdr, shdr, last)
+ || shdr[last].sh_addr >= phdr[i].p_vaddr + phdr[i].p_filesz)
+ break;
+ for (j = 1; j < last; ++j)
+ {
+ addstart = (start + add->sh_addralign - 1)
+ & ~(add->sh_addralign - 1);
+ start = (start + shdr[j].sh_addralign - 1)
+ & ~(shdr[j].sh_addralign - 1);
+ endaddr = -1;
+ if (j + 1 < ehdr->e_shnum)
+ endaddr = shdr[j + 1].sh_addr;
+ if (phdr[i].p_vaddr + phdr[i].p_filesz < endaddr)
+ endaddr = phdr[i].p_vaddr + phdr[i].p_filesz;
+
+ switch (shdr[j].sh_type)
{
- if (phdr[e].p_filesz != shdr[k].sh_size
- || phdr[e].p_memsz != shdr[k].sh_size)
+ case SHT_HASH:
+ case SHT_GNU_HASH:
+ case SHT_DYNSYM:
+ case SHT_STRTAB:
+ case SHT_GNU_verdef:
+ case SHT_GNU_verneed:
+ case SHT_GNU_versym:
+ case SHT_GNU_LIBLIST:
+ if (endaddr >= start
+ && endaddr - start < minsize)
+ {
+ minsize = endaddr - start;
+ movesec = j;
+ }
+ if (endaddr > addstart
+ && endaddr - addstart > add->sh_size
+ && endaddr - addstart - add->sh_size
+ < minsize)
{
- error (0, 0, "%s: Non-PT_LOAD segment spanning more than one section",
- dso->filename);
- return 0;
+ minsize = endaddr - addstart - add->sh_size;
+ movesec = j;
}
- phdr[e].p_vaddr += shdr[k].sh_addr - old_addr[k];
- phdr[e].p_paddr += shdr[k].sh_addr - old_addr[k];
- phdr[e].p_offset += shdr[k].sh_addr - old_addr[k];
break;
+ case SHT_REL:
+ case SHT_RELA:
+ case SHT_NOTE:
+ /* Don't allow inserting in between reloc sections
+ if they are adjacent. Similarly for adjacent
+ note sections. */
+ if (j + 1 < ehdr->e_shnum)
+ {
+ if (shdr[j].sh_type == SHT_NOTE)
+ {
+ if (shdr[j + 1].sh_type != SHT_NOTE)
+ break;
+ }
+ else if (shdr[j + 1].sh_type != SHT_REL
+ && shdr[j + 1].sh_type != SHT_RELA)
+ {
+ break;
+ }
+
+ if ((shdr[j].sh_addr
+ + ((shdr[j].sh_size + 3) & -4))
+ != shdr[j + 1].sh_addr)
+ break;
+
+ start += shdr[j].sh_size;
+ continue;
+ }
+ break;
}
- if (j < last)
- /* Now continue as if there was place for a new PT_LOAD
- in ElfW(Phdr) table initially. */
- break;
- else
- {
- GElf_Shdr moveshdr;
- int newidx, ret, movedidx, oldidx;
-
- moveshdr = shdr[movesec];
- newidx = remove_readonly_section (ehdr, shdr, movesec, adjust);
- oldidx = adjust->move->new_to_old[movesec];
- remove_section (adjust->move, movesec);
- ret = find_readonly_space (dso, add, ehdr, phdr, shdr, adjust);
- if (ret == 0)
- return 0;
- movedidx = find_readonly_space (dso, &moveshdr, ehdr, phdr,
- shdr, adjust);
- if (movedidx == 0)
+ if (start + shdr[j].sh_size <= endaddr)
+ {
+ movesec = j + 1;
+ break;
+ }
+ start += shdr[j].sh_size;
+ }
+
+ if (movesec == -1)
+ {
+ error (0, 0, "%s: No space in ELF segment table to add new ELF segment",
+ dso->filename);
return 0;
- if (newidx != -1)
- adjust->new[newidx] = movedidx;
- add_section (adjust->move, movedidx);
- if (oldidx != -1)
- {
- adjust->move->old_to_new[oldidx] = movedidx;
- adjust->move->new_to_old[movedidx] = oldidx;
- }
- if (movedidx <= ret)
- ++ret;
- return ret;
- }
- }
- }
+ }
+
+ start = phdr[i].p_vaddr - phdr[i].p_offset + ehdr->e_phoff
+ + (ehdr->e_phnum + 1) * ehdr->e_phentsize;
+ old_addr = (GElf_Addr *) alloca (movesec * sizeof (GElf_Addr));
+ for (k = 1; k < movesec; ++k)
+ {
+ start = (start + shdr[k].sh_addralign - 1)
+ & ~(shdr[k].sh_addralign - 1);
+ old_addr[k] = shdr[k].sh_addr;
+ shdr[k].sh_addr = start;
+ shdr[k].sh_offset = start + phdr[i].p_offset
+ - phdr[i].p_vaddr;
+ start += shdr[k].sh_size;
+ }
+
+ for (e = 0; e < ehdr->e_phnum; ++e)
+ if (phdr[e].p_type != PT_LOAD
+ && phdr[e].p_type != PT_GNU_STACK)
+ for (k = 1; k < movesec; ++k)
+ if (old_addr[k] == phdr[e].p_vaddr)
+ {
+ if (phdr[e].p_filesz != shdr[k].sh_size
+ || phdr[e].p_memsz != shdr[k].sh_size)
+ {
+ int k1 = -1;
+ if (phdr[e].p_type == PT_NOTE
+ && shdr[k].sh_type == SHT_NOTE
+ && phdr[e].p_filesz == phdr[e].p_memsz)
+ {
+ k1 = k;
+ while (k1 < movesec)
+ {
+ if (shdr[k1].sh_type != SHT_NOTE
+ || shdr[k1].sh_addr - old_addr[k1]
+ != shdr[k].sh_addr - old_addr[k]
+ || old_addr[k1] + shdr[k1].sh_size
+ > phdr[e].p_vaddr + phdr[e].p_filesz)
+ {
+ k1 = -1;
+ break;
+ }
+ if (old_addr[k1] + shdr[k1].sh_size
+ == phdr[e].p_vaddr + phdr[e].p_filesz)
+ break;
+ ++k1;
+ }
+ if (k1 == movesec)
+ k1 = -1;
+ }
+ if (k1 == -1)
+ {
+ error (0, 0, "%s: Non-PT_LOAD segment spanning more than one section",
+ dso->filename);
+ return 0;
+ }
+ }
+ phdr[e].p_vaddr += shdr[k].sh_addr - old_addr[k];
+ phdr[e].p_paddr += shdr[k].sh_addr - old_addr[k];
+ phdr[e].p_offset += shdr[k].sh_addr - old_addr[k];
+ break;
+ }
+
+ if (j < last)
+ /* Now continue as if there was place for a new PT_LOAD
+ in ElfW(Phdr) table initially. */
+ break;
+ else
+ {
+ GElf_Shdr moveshdr;
+ int newidx, ret, movedidx, oldidx;
+
+ moveshdr = shdr[movesec];
+ newidx = remove_readonly_section (ehdr, shdr, movesec, adjust);
+ oldidx = adjust->move->new_to_old[movesec];
+ remove_section (adjust->move, movesec);
+ ret = find_readonly_space (dso, add, ehdr, phdr, shdr, adjust);
+ if (ret == 0)
+ return 0;
+ movedidx = find_readonly_space (dso, &moveshdr, ehdr, phdr,
+ shdr, adjust);
+ if (movedidx == 0)
+ return 0;
+ if (newidx != -1)
+ adjust->new[newidx] = movedidx;
+ add_section (adjust->move, movedidx);
+ if (oldidx != -1)
+ {
+ adjust->move->old_to_new[oldidx] = movedidx;
+ adjust->move->new_to_old[movedidx] = oldidx;
+ }
+ if (movedidx <= ret)
+ ++ret;
+ return ret;
+ }
+ }
+ }
+ }
for (i = 0, j = 0; i < ehdr->e_phnum; ++i)
if (phdr[i].p_type == PT_LOAD)
diff --git a/trunk/src/verify.c b/trunk/src/verify.c
index 8a3d89a..b04709b 100644
--- a/trunk/src/verify.c
+++ b/trunk/src/verify.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2006 Red Hat, Inc.
+/* Copyright (C) 2002, 2003, 2006, 2007 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2002.
This program is free software; you can redistribute it and/or modify
@@ -227,7 +227,10 @@ prelink_verify (const char *filename)
goto failure;
}
- if (gather_config (prelink_conf))
+ if (read_config (prelink_conf))
+ goto failure;
+
+ if (gather_config ())
goto failure;
if (gather_object (filename, 0, 0))