aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Hatle <mark.hatle@windriver.com>2019-06-24 11:24:52 -0400
committerMark Hatle <mark.hatle@windriver.com>2019-06-24 11:24:52 -0400
commitd89fb6060e57f0aaa329de9ad81abe76c180ac66 (patch)
treef922353787ff97e32d365abc0489837d3191c2ed
parent1f2b5469d1a10e9bfd53aafb8501b361ef08bcb0 (diff)
parentf9975537dbfd9ade0fc813bd5cf5fcbe41753a37 (diff)
downloadprelink-cross-master.tar.gz
prelink-cross-master.tar.bz2
prelink-cross-master.zip
Merge branch 'cross_prelink'HEADmaster_stagingmaster
Conflicts: ChangeLog src/rtld/dl-lookupX.h testsuite/functions.sh testsuite/order.sh Signed-off-by: Mark Hatle <mark.hatle@windriver.com>
-rw-r--r--ChangeLog38
-rw-r--r--README9
-rw-r--r--src/arch-mips.c3
-rw-r--r--src/arch-x86_64.c4
-rw-r--r--src/conflict.c51
-rw-r--r--src/doit.c16
-rw-r--r--src/dso.c37
-rw-r--r--src/exec.c9
-rw-r--r--src/main.c8
-rw-r--r--src/prelink.h3
-rw-r--r--src/undo.c9
-rw-r--r--testsuite/Makefile.am2
-rwxr-xr-xtestsuite/functions.sh6
-rw-r--r--testsuite/reloc12.c19
-rw-r--r--testsuite/reloc12.h11
-rwxr-xr-xtestsuite/reloc12.sh22
-rw-r--r--testsuite/reloc12lib1.c11
-rw-r--r--testsuite/reloc12lib2.c16
-rwxr-xr-xtestsuite/unprel1.sh2
19 files changed, 249 insertions, 27 deletions
diff --git a/ChangeLog b/ChangeLog
index 5412317..db91b06 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,41 @@
+2019-06-24 Mark Hatle <mark.hatle@windriver.com>
+ * Merge with cross_prelink
+
+2018-10-12 Kyl Russel <bkylerussel@gmail.com
+ * doit.c, main.c prelink.h: Add -e option to return an error if
+ not everything can be prelinked.
+
+2018-10-12 Mark Hatle <mark.hatle@windriver.com>
+ * testsuite/order.sh: Explain failure in log
+
+2018-10-12 Mark Hatle <mark.hatle@windriver.com>
+ * testsuite/reloc12.sh: Detect if compiler/linker support test
+
+2018-10-12 Robert Yang <liezhi.yang@windriver.com>
+ * src/arch-mips.c: Make tls offset optional on tls usage
+
+2018-10-12 Sergei Trofimovich <slyfox@gentoo.org>
+ * src/arch-x86_64.c, src/dso.c, src/prelink.h: Allow prelink of
+ pie executables with COPY relocs
+
+2018-10-12 Sergei Trofimovich <slyfox@gentoo.org>
+ * tessuite/functions.sh: Avoid timestamp drift
+
+2018-10-12 Joseph Myers <joseph@codesourcery.com>
+ * testsuite/unprel1.sh: Fix for cross testing
+
+2018-10-12 Kyle Russell <bkylerussell@gmail.com>
+ * src/conflict.c, src/undo.c: Add knowledge of .data.rel.ro for
+ read-only dynamic symbols
+
+2018-10-12 Kyle Russell <bkylerussell@gmail.com>
+ * testsuite/Makefile.am, testsuite/reloc12.c, testsuite/reloc12.h,
+ testsuite/reloc12.sh, testsuite/reloc12lib1.c, testsuite/reloc12lib2.c:
+ Add a new test for these relocations
+
+2018-10-12 Mark Hatle <mark.hatle@windriver.com>
+ * Add 'Developer's Certificate of Origin' to patch requirements
+
2018-08-29 Mark Hatle <mark.hatle@windriver.com>
* Merge with cross_prelink
diff --git a/README b/README
index 910a8e3..2d8893b 100644
--- a/README
+++ b/README
@@ -19,6 +19,15 @@ Cc: yocto@yoctoproject.org
Subject: [prelink-cross] ....
+Additionally, a 'Developer's Certificate of Origin' statement will be required
+for all submitted patches. See:
+
+ https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin
+
+Effectively this means at then end of your commit, please add a
+Signed-off-by: line. If you are not the original author of the patch, please
+indicate this and then add your Signed-off-by: line after.
+
Known Issues
------------
diff --git a/src/arch-mips.c b/src/arch-mips.c
index ccb1834..02c608f 100644
--- a/src/arch-mips.c
+++ b/src/arch-mips.c
@@ -567,7 +567,8 @@ mips_prelink_reloc (struct prelink_info *info, GElf_Addr r_offset,
if (dso->ehdr.e_type == ET_EXEC)
{
value = info->resolve (info, r_sym, r_type);
- value += info->resolvetls->offset - TLS_TP_OFFSET;
+ if (info->resolvetls != NULL)
+ value += info->resolvetls->offset - TLS_TP_OFFSET;
if (r_type == R_MIPS_TLS_TPREL32)
mips_prelink_32bit_reloc (dso, rela, value);
else
diff --git a/src/arch-x86_64.c b/src/arch-x86_64.c
index 5c95f47..2f6c551 100644
--- a/src/arch-x86_64.c
+++ b/src/arch-x86_64.c
@@ -179,7 +179,7 @@ x86_64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
value + rela->r_addend - info->resolvetls->offset);
break;
case R_X86_64_COPY:
- if (dso->ehdr.e_type == ET_EXEC)
+ if (dso->ehdr.e_type == ET_EXEC || dso_is_pie(dso))
/* COPY relocs are handled specially in generic code. */
return 0;
error (0, 0, "%s: R_X86_64_COPY reloc in shared library?", dso->filename);
@@ -503,7 +503,7 @@ x86_64_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
write_le32 (dso, rela->r_offset, 0);
break;
case R_X86_64_COPY:
- if (dso->ehdr.e_type == ET_EXEC)
+ if (dso->ehdr.e_type == ET_EXEC || dso_is_pie(dso))
/* COPY relocs are handled specially in generic code. */
return 0;
error (0, 0, "%s: R_X86_64_COPY reloc in shared library?", dso->filename);
diff --git a/src/conflict.c b/src/conflict.c
index 9ae2ddb..5613ace 100644
--- a/src/conflict.c
+++ b/src/conflict.c
@@ -450,7 +450,7 @@ get_relocated_mem (struct prelink_info *info, DSO *dso, GElf_Addr addr,
int
prelink_build_conflicts (struct prelink_info *info)
{
- int i, ndeps = info->ent->ndepends + 1;
+ int i, reset_dynbss = 0, reset_sdynbss = 0, ndeps = info->ent->ndepends + 1;
struct prelink_entry *ent;
int ret = 0;
DSO *dso;
@@ -675,6 +675,11 @@ prelink_build_conflicts (struct prelink_info *info)
dso->filename);
goto error_out;
}
+
+ name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[bss1].sh_name);
+ if (strcmp(name, ".data.rel.ro") == 0)
+ reset_sdynbss = 1;
+
firstbss2 = i;
info->sdynbss_size = cr.rela[i - 1].r_offset - cr.rela[0].r_offset;
info->sdynbss_size += cr.rela[i - 1].r_addend;
@@ -702,6 +707,10 @@ prelink_build_conflicts (struct prelink_info *info)
}
}
+ name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[bss2].sh_name);
+ if (strcmp(name, ".data.rel.ro") == 0)
+ reset_dynbss = 1;
+
info->dynbss_size = cr.rela[cr.count - 1].r_offset
- cr.rela[firstbss2].r_offset;
info->dynbss_size += cr.rela[cr.count - 1].r_addend;
@@ -719,9 +728,9 @@ prelink_build_conflicts (struct prelink_info *info)
&& strcmp (name = strptr (dso, dso->ehdr.e_shstrndx,
dso->shdr[bss1].sh_name),
".dynbss") != 0
- && strcmp (name, ".sdynbss") != 0)
+ && strcmp (name, ".sdynbss") != 0 && strcmp (name, ".data.rel.ro") != 0)
{
- error (0, 0, "%s: COPY relocations don't point into .bss or .sbss section",
+ error (0, 0, "%s: COPY relocations don't point into .bss, .sbss, or .data.rel.ro sections",
dso->filename);
goto error_out;
}
@@ -730,9 +739,9 @@ prelink_build_conflicts (struct prelink_info *info)
&& strcmp (name = strptr (dso, dso->ehdr.e_shstrndx,
dso->shdr[bss2].sh_name),
".dynbss") != 0
- && strcmp (name, ".sdynbss") != 0)
+ && strcmp (name, ".sdynbss") != 0 && strcmp (name, ".data.rel.ro") != 0)
{
- error (0, 0, "%s: COPY relocations don't point into .bss or .sbss section",
+ error (0, 0, "%s: COPY relocations don't point into .bss, .sbss, or .data.rel.ro section",
dso->filename);
goto error_out;
}
@@ -768,16 +777,21 @@ prelink_build_conflicts (struct prelink_info *info)
}
assert (j < ndeps);
+ GElf_Addr symaddr = s->u.ent->base + s->value;
+ char *buf;
+
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,
- cr.rela[i].r_offset);
+ if (reset_sdynbss)
+ buf = get_data(dso, cr.rela[i].r_offset, NULL, NULL);
+ else
+ buf = info->sdynbss + cr.rela[i].r_offset - info->sdynbss_base;
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,
- cr.rela[i].r_offset);
+ if (reset_dynbss)
+ buf = get_data(dso, cr.rela[i].r_offset, NULL, NULL);
+ else
+ buf = info->dynbss + cr.rela[i].r_offset - info->dynbss_base;
+
+ j = get_relocated_mem (info, ndso, symaddr, buf, cr.rela[i].r_addend, cr.rela[i].r_offset);
switch (j)
{
@@ -815,6 +829,17 @@ prelink_build_conflicts (struct prelink_info *info)
if (info->dsos[i])
close_dso (info->dsos[i]);
+ if (reset_sdynbss)
+ {
+ free (info->sdynbss);
+ info->sdynbss = NULL;
+ }
+
+ if (reset_dynbss)
+ {
+ free (info->dynbss);
+ info->dynbss = NULL;
+ }
info->dsos = NULL;
free (cr.rela);
return ret;
diff --git a/src/doit.c b/src/doit.c
index 1e32ad5..3784866 100644
--- a/src/doit.c
+++ b/src/doit.c
@@ -237,11 +237,11 @@ error_out:
return;
}
-void
+int
prelink_all (void)
{
struct collect_ents l;
- int i;
+ int i, fails = 0;
l.ents =
(struct prelink_entry **) alloca (prelink_entry_count
@@ -250,7 +250,13 @@ prelink_all (void)
htab_traverse (prelink_filename_htab, find_ents, &l);
for (i = 0; i < l.nents; ++i)
- if (l.ents[i]->done == 1
- || (l.ents[i]->done == 0 && l.ents[i]->type == ET_EXEC))
- prelink_ent (l.ents[i]);
+ {
+ if (l.ents[i]->done == 1
+ || (l.ents[i]->done == 0 && l.ents[i]->type == ET_EXEC))
+ prelink_ent (l.ents[i]);
+ if (l.ents[i]->type == ET_UNPRELINKABLE)
+ fails++;
+ }
+
+ return fails;
}
diff --git a/src/dso.c b/src/dso.c
index a5fcec5..949abf9 100644
--- a/src/dso.c
+++ b/src/dso.c
@@ -221,8 +221,22 @@ check_dso (DSO *dso)
|| RELOCATE_SCN (dso->shdr[last].sh_flags)
|| RELOCATE_SCN (dso->shdr[i].sh_flags))
{
- error (0, 0, "%s: section file offsets not monotonically increasing",
- dso->filename);
+ int j = 0;
+ for (j = 1; j < dso->ehdr.e_shnum; ++j) {
+ const char *name
+ = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[j].sh_name);
+
+ error(0, 0, "section %d %s file offset range %08lx and %08lx",
+ j, name,
+ dso->shdr[j].sh_offset,
+ dso->shdr[j].sh_offset + (dso->shdr[j].sh_type == SHT_NOBITS ? 0 : dso->shdr[j].sh_size));
+ }
+
+ error (0, 0, "%s: section [%d and %d] file offsets [%08lx and %08lx] not monotonically increasing",
+ dso->filename, last, i,
+ dso->shdr[last].sh_offset + (dso->shdr[last].sh_type == SHT_NOBITS ? 0 : dso->shdr[last].sh_size),
+ dso->shdr[i].sh_offset
+ );
return 1;
}
}
@@ -1126,6 +1140,25 @@ adjust_old_to_new (DSO *dso, GElf_Addr addr)
return addr;
}
+/* Return true is DSO is position independent executable.
+
+ There is no simple way to distinct between shared library
+ and PIE executable. Use presence of interpreter as a heuristic. */
+
+int dso_is_pie(DSO *dso)
+{
+ int i;
+
+ if (dso->ehdr.e_type != ET_DYN)
+ return 0;
+
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_INTERP)
+ return 1;
+
+ return 0;
+}
+
GElf_Addr
adjust_new_to_old (DSO *dso, GElf_Addr addr)
{
diff --git a/src/exec.c b/src/exec.c
index 4f56629..ca7fd14 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -1122,6 +1122,15 @@ error_out:
goto error_out;
if (set_dynamic (dso, DT_GNU_CONFLICTSZ, dso->shdr[i].sh_size, 1))
goto error_out;
+ /* Check if we're going to run over the next section */
+ if (dso->shdr[i].sh_offset
+ + (dso->shdr[i].sh_type == SHT_NOBITS
+ ? 0 : dso->shdr[i].sh_size) > dso->shdr[i+1].sh_offset)
+ {
+ error (0, ENOMEM, "%s: Could not create .gnu.conflict section [overwrites next section]",
+ dso->filename);
+ goto error_out;
+ }
}
if (undo != -1)
diff --git a/src/main.c b/src/main.c
index 0cea86d..6ba89d5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -47,6 +47,7 @@ int one_file_system;
int enable_cxx_optimizations = 1;
int exec_shield;
int undo, verify;
+int errors;
enum verify_method_t verify_method;
int quick;
int compute_checksum;
@@ -90,6 +91,7 @@ static struct argp_option options[] = {
{"black-list", 'b', "PATH", 0, "Blacklist path" },
{"cache-file", 'C', "CACHE", 0, "Use CACHE as cache file" },
{"config-file", 'c', "CONF", 0, "Use CONF as configuration file" },
+ {"errors", 'e', 0, 0, "Returns an error if all binaries are not prelinkable" },
{"force", 'f', 0, 0, "Force prelinking" },
{"dereference", 'h', 0, 0, "Follow symlinks when processing directory trees from command line" },
{"one-file-system", 'l', 0, 0, "Stay in local file system when processing directories from command line" },
@@ -139,6 +141,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
if (add_to_blacklist (arg, dereference, one_file_system))
exit (EXIT_FAILURE);
break;
+ case 'e':
+ errors = 1;
+ break;
case 'f':
force = 1;
break;
@@ -524,7 +529,8 @@ main (int argc, char *argv[])
prelink_load_cache ();
layout_libs ();
- prelink_all ();
+ if(prelink_all () && errors)
+ return EXIT_FAILURE;
if (! no_update && ! dry_run)
prelink_save_cache (all);
diff --git a/src/prelink.h b/src/prelink.h
index 93dbf7a..39c4390 100644
--- a/src/prelink.h
+++ b/src/prelink.h
@@ -298,6 +298,7 @@ int reopen_dso (DSO *dso, struct section_move *move, const char *);
int adjust_symbol_p (DSO *dso, GElf_Sym *sym);
int check_dso (DSO *dso);
int dso_is_rdwr (DSO *dso);
+int dso_is_pie(DSO *dso);
void read_dynamic (DSO *dso);
int set_dynamic (DSO *dso, GElf_Word tag, GElf_Addr value, int fatal);
int addr_to_sec (DSO *dso, GElf_Addr addr);
@@ -574,7 +575,7 @@ int get_relocated_mem (struct prelink_info *info, DSO *dso, GElf_Addr addr,
int layout_libs (void);
-void prelink_all (void);
+int prelink_all (void);
int undo_all (void);
diff --git a/src/undo.c b/src/undo.c
index 8a55bf2..4c38dab 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -633,6 +633,15 @@ prelink_undo (DSO *dso)
d->d_buf = NULL;
dso->shdr[i].sh_type = SHT_NOBITS;
}
+ else if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && strcmp (name, ".data.rel.ro") == 0)
+ {
+ scn = dso->scn[i];
+ d = elf_getdata (scn, NULL);
+ assert (d != NULL && elf_getdata (scn, d) == NULL);
+ assert (d->d_size == dso->shdr[i].sh_size);
+ assert (memset(d->d_buf, 0, d->d_size) == d->d_buf);
+ }
else if (dso->shdr[i].sh_type == SHT_RELA
&& shdr[i].sh_type == SHT_REL)
{
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index 94ad5e9..867f650 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -5,7 +5,7 @@ AM_CFLAGS = -Wall
TESTS = movelibs.sh \
reloc1.sh reloc2.sh reloc3.sh reloc4.sh reloc5.sh reloc6.sh \
- reloc7.sh reloc8.sh reloc9.sh reloc10.sh reloc11.sh \
+ reloc7.sh reloc8.sh reloc9.sh reloc10.sh reloc11.sh reloc12.sh \
shuffle1.sh shuffle2.sh shuffle3.sh shuffle4.sh shuffle5.sh \
shuffle6.sh shuffle7.sh shuffle8.sh shuffle9.sh undo1.sh \
layout1.sh layout2.sh unprel1.sh \
diff --git a/testsuite/functions.sh b/testsuite/functions.sh
index 85bf875..5e98725 100755
--- a/testsuite/functions.sh
+++ b/testsuite/functions.sh
@@ -4,6 +4,12 @@ CCLINK=${CCLINK:-${CC} -Wl,--dynamic-linker=`echo ./ld*.so.*[0-9]`}
CXX="${CXX:-g++} ${LINKOPTS}"
CXXLINK=${CXXLINK:-${CXX} -Wl,--dynamic-linker=`echo ./ld*.so.*[0-9]`}
PRELINK=${PRELINK:-../src/prelink -c ./prelink.conf -C ./prelink.cache --ld-library-path=. --dynamic-linker=`echo ./ld*.so.*[0-9]`}
+
+# force deterministic timestamps to make double prelinking
+# to produce unmodified binary.
+PRELINK_TIMESTAMP=${PRELINK_TIMESTAMP:-12345678}
+export PRELINK_TIMESTAMP
+
srcdir=${srcdir:-`dirname $0`}
savelibs() {
for i in $LIBS $BINS; do cp -p $i $i.orig; done
diff --git a/testsuite/reloc12.c b/testsuite/reloc12.c
new file mode 100644
index 0000000..cfa8888
--- /dev/null
+++ b/testsuite/reloc12.c
@@ -0,0 +1,19 @@
+#include "reloc12.h"
+#include <stdlib.h>
+
+int main()
+{
+ A* ptr = find('b');
+ if(b(ptr) != 0)
+ abort();
+
+ ptr = find('a');
+ if(b(ptr) != 1)
+ abort();
+
+ ptr = find('r');
+ if(b(ptr) != 2)
+ abort();
+
+ exit(0);
+}
diff --git a/testsuite/reloc12.h b/testsuite/reloc12.h
new file mode 100644
index 0000000..8e09405
--- /dev/null
+++ b/testsuite/reloc12.h
@@ -0,0 +1,11 @@
+typedef struct
+ {
+ char a;
+ int b;
+ } A;
+
+extern A foo[] __attribute ((visibility ("protected")));
+
+A* find(char a);
+char a(const A*);
+int b(const A*);
diff --git a/testsuite/reloc12.sh b/testsuite/reloc12.sh
new file mode 100755
index 0000000..74d1fa8
--- /dev/null
+++ b/testsuite/reloc12.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+. `dirname $0`/functions.sh
+rm -f reloc12 reloc12lib*.so reloc12.log
+rm -f prelink.cache
+$CC -shared -O2 -fpic -o reloc12lib1.so $srcdir/reloc12lib1.c
+$CC -shared -O2 -fpic -o reloc12lib2.so $srcdir/reloc12lib2.c
+if [ $? -ne 0 ]; then
+ echo "tested relocation not available in this GCC/Linker"
+ exit 77
+fi
+BINS="reloc12"
+LIBS="reloc12lib1.so reloc12lib2.so"
+$CCLINK -o reloc12 $srcdir/reloc12.c -Wl,--rpath-link,. ${LIBS}
+savelibs
+echo $PRELINK ${PRELINK_OPTS--vm} ./reloc12 > reloc12.log
+$PRELINK ${PRELINK_OPTS--vm} ./reloc12 >> reloc12.log 2>&1 || exit 1
+grep -q ^`echo $PRELINK | sed 's/ .*$/: /'` reloc12.log && exit 2
+LD_LIBRARY_PATH=. ./reloc12 || exit 3
+readelf -a ./reloc12 >> reloc12.log 2>&1 || exit 4
+# So that it is not prelinked again
+chmod -x ./reloc12
+comparelibs >> reloc12.log 2>&1 || exit 5
diff --git a/testsuite/reloc12lib1.c b/testsuite/reloc12lib1.c
new file mode 100644
index 0000000..db7e64f
--- /dev/null
+++ b/testsuite/reloc12lib1.c
@@ -0,0 +1,11 @@
+#include "reloc12.h"
+
+char a(const A *d)
+{
+ return d ? d->a : 0;
+}
+
+int b(const A *d)
+{
+ return d ? d->b : -1;
+}
diff --git a/testsuite/reloc12lib2.c b/testsuite/reloc12lib2.c
new file mode 100644
index 0000000..ffa60a0
--- /dev/null
+++ b/testsuite/reloc12lib2.c
@@ -0,0 +1,16 @@
+#include "reloc12.h"
+
+A foo[] = {
+ { 'b', 0 },
+ { 'a', 1 },
+ { 'r', 2 }
+};
+
+A* find(char a)
+{
+ for(A* ptr = foo; ptr < foo + sizeof(foo)/sizeof(foo[0]); ptr++)
+ if(ptr->a == a)
+ return ptr;
+
+ return 0;
+}
diff --git a/testsuite/unprel1.sh b/testsuite/unprel1.sh
index 0463358..401f8bf 100755
--- a/testsuite/unprel1.sh
+++ b/testsuite/unprel1.sh
@@ -43,7 +43,7 @@ grep -q 'lib/lib2.so because its dependency unprel1.tree/opt/lib1.so could not b
unprel1.log || exit 4
grep -q 'bin/bin1 because its dependency unprel1.tree/lib/lib2.so could not be prelinked' \
unprel1.log || exit 5
-unprel1.tree/bin/bin1 || exit 6
+$RUN unprel1.tree/bin/bin1 || exit 6
# So that it is not prelinked again
chmod -x unprel1.tree/bin/bin1
LIBS=unprel1.tree/lib/lib1.so