From 33be255d62af533189f1f7bc66c06602b703980a Mon Sep 17 00:00:00 2001 From: Dave Lerner Date: Thu, 2 Jun 2016 13:07:47 -0500 Subject: [PATCH 1/3] Fix prelink section ordering on subsequent prelink Some linkers create a binary which has a section header table that is not in section header offset order. However, as noted in check_dso(), several routines in prelink and in libelf-0.7.0 too rely on sh_offsets monotonically increasing, and if that fails then prelink quits. But the check is only on dso's, not binaries. For binaries, fdopen_dso() reorders the section headers to section header offset order prior to work on the section data, so that the new prelinked binary is written in section order. However, on subsequent prelinks of a prelinked binary, the prelink_exec() works on the undone section, not the fdopen_dso() reordered sections, and may construct a section header table with section orders different than the first prelink of the binary. The function below tests for that case and resets the section header order to the offset order by enforcing the binutils linker change: 'The net effect is .shstrab section is now placed after .symtab and .strtab sections'. See binutils-gdb.git commit 3e19fb8f990e4c. Signed-off-by: Dave Lerner 2016-06-03 Dave Lerner * src/exec.c: New check_reorder_needed, section_reorder_fix functions Signed-off-by: Mark Hatle --- ChangeLog | 3 ++ src/exec.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/ChangeLog b/ChangeLog index f6e75b2..548a848 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2016-06-03 Dave Lerner + * src/exec.c: New check_reorder_needed, section_reorder_fix functions + 2016-03-22 Mark Hatle * src/gather.c, src/get.c: Fix LD_PRELOAD diff --git a/src/exec.c b/src/exec.c index 22870c2..4f56629 100644 --- a/src/exec.c +++ b/src/exec.c @@ -72,6 +72,91 @@ update_dynamic_tags (DSO *dso, GElf_Shdr *shdr, GElf_Shdr *old_shdr, return 0; } +static int +check_reorder_needed(DSO *dso, struct section_move *moves, int fixed_shstrndx, + int fixed_undo, int fixed_strtab, int fixed_symtab) +{ + const char *shstrtab_str = + strptr (dso, fixed_shstrndx, dso->shdr[fixed_shstrndx].sh_name); + const char *prelink_undo_str = + strptr (dso, fixed_shstrndx, dso->shdr[fixed_undo].sh_name); + const char *strtab_str = + strptr (dso, fixed_shstrndx, dso->shdr[fixed_strtab].sh_name); + const char *symtab_str = + strptr (dso, fixed_shstrndx, dso->shdr[fixed_symtab].sh_name); + + if (!shstrtab_str || !prelink_undo_str || !strtab_str || !symtab_str + || strcmp (shstrtab_str, ".shstrtab") + || strcmp(prelink_undo_str, ".gnu.prelink_undo") + || strcmp(strtab_str, ".strtab") + || strcmp(symtab_str, ".symtab") + || (moves->old_to_new[fixed_shstrndx] == fixed_shstrndx) + || (dso->shdr[fixed_shstrndx].sh_offset < dso->shdr[fixed_strtab].sh_offset) + || (dso->shdr[fixed_shstrndx].sh_offset < dso->shdr[fixed_symtab].sh_offset)) + return 0; + + return 1; +} + +/* + * Some linkers create a binary which has a section header table that is + * not in section header offset order. However, as noted in check_dso(), + * several routines in prelink and in libelf-0.7.0 too rely on sh_offsets + * monotonically increasing, and if that fails then prelink quits. But + * the check is only on dso's, not binaries. For binaries, fdopen_dso() + * reorders the section headers to section header offset order prior to + * work on the section data, so that the new prelinked binary is written + * in section order. + * However, on subsequent prelinks of a prelinked binary, the + * prelink_exec() works on the undone section, not the fdopen_dso() + * reordered sections, and may construct a section header table with + * section orders different than the first prelink of the binary. + * The function below tests for that case and resets the section header + * order to the offset order by enforcing the binutils linker change: + * 'The net effect is .shstrab section is now placed after .symtab and + * .strtab sections'. See binutils-gdb.git commit 3e19fb8f990e4c. + */ +static void +section_reorder_fix(DSO *dso, GElf_Shdr *shdr, struct section_move *move, + int *undo) +{ + int i; + int fixed_shstrndx = dso->ehdr.e_shstrndx; + int fixed_undo = fixed_shstrndx - 1; + int fixed_strtab = fixed_shstrndx- 2; + int fixed_symtab = fixed_shstrndx - 3; + int section_reorder_cnt = 4; + GElf_Shdr undone_shdr[dso->ehdr.e_shnum]; + + if (!check_reorder_needed(dso, move, + fixed_shstrndx, fixed_undo, fixed_strtab, fixed_symtab)) + return; + + /* get a copy of the undo section's shdr ordering */ + for (i = 0 ; i < dso->ehdr.e_shnum; ++i) + undone_shdr[i] = shdr[i]; + + /* copy the undo section's shdr to the corrected index */ + for (i = 0 ; i < section_reorder_cnt; ++i) + { + int ndx = fixed_shstrndx - i; + if (ndx != fixed_undo) + { + shdr[ndx] = undone_shdr[move->old_to_new[ndx]]; + move->old_to_new[ndx] = ndx; + move->new_to_old[ndx] = ndx; + } + else + { + shdr[fixed_undo] = undone_shdr[*undo]; + /* the moves are specially flagged for the undo secton */ + move->old_to_new[fixed_undo] = -1; + move->new_to_old[fixed_undo] = -1; + } + } + *undo = fixed_undo; +} + int prelink_exec (struct prelink_info *info) { @@ -93,6 +178,7 @@ prelink_exec (struct prelink_info *info) Elf32_Lib *liblist = NULL; struct readonly_adjust adjust; struct section_move *move = NULL; + int undo_sections_done = 0; if (prelink_build_conflicts (info)) return 1; @@ -140,7 +226,9 @@ prelink_exec (struct prelink_info *info) goto error_out; } memcpy (dso->undo.d_buf, data->d_buf, data->d_size); + ehdr.e_shstrndx = dso->ehdr.e_shstrndx; + undo_sections_done = 1; } undo = 0; @@ -438,6 +526,10 @@ prelink_exec (struct prelink_info *info) ehdr.e_shnum = dso->ehdr.e_shnum; dso->ehdr = ehdr; memcpy (dso->phdr, phdr, ehdr.e_phnum * sizeof (GElf_Phdr)); + + if (undo_sections_done) + section_reorder_fix(dso, shdr, move, &undo); + if (reopen_dso (dso, move, NULL)) goto error_out; From e09997c6839c6207f8ce303fd98001bbbdbd67f9 Mon Sep 17 00:00:00 2001 From: Mark Hatle Date: Wed, 17 Aug 2016 13:41:51 -0500 Subject: [PATCH 2/3] src/rtld/dl-open.c: Change to work with older compilers 2016-08-17 Mark Hatle * src/rtld/dl-open.c: Change to work with older compilers Signed-off-by: Mark Hatle --- ChangeLog | 3 +++ src/rtld/ChangeLog | 3 +++ src/rtld/dl-open.c | 9 ++++++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 548a848..6d693d2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2016-08-17 Mark Hatle + * src/rtld/dl-open.c: Change to work with older compilers + 2016-06-03 Dave Lerner * src/exec.c: New check_reorder_needed, section_reorder_fix functions diff --git a/src/rtld/ChangeLog b/src/rtld/ChangeLog index c53c6dd..0f77d9c 100644 --- a/src/rtld/ChangeLog +++ b/src/rtld/ChangeLog @@ -1,3 +1,6 @@ +2016-08-17 Mark Hatle + * dl-open.c: Change function to work with older compilers + 2016-03-18 Donn Seeley * rtld.c: rewrite build_local_scope to ensure breadth-first processing diff --git a/src/rtld/dl-open.c b/src/rtld/dl-open.c index 070a3f5..de699a5 100644 --- a/src/rtld/dl-open.c +++ b/src/rtld/dl-open.c @@ -25,12 +25,14 @@ _dl_show_scope (struct link_map *l, int from) { _dl_debug_printf ("object=%s [%lu]\n", DSO_FILENAME (l->l_name), 0UL); - if (l->l_local_scope != NULL) - for (int scope_cnt = from; l->l_local_scope[scope_cnt] != NULL; ++scope_cnt) + if (l->l_local_scope != NULL) { + int scope_cnt; + for (scope_cnt = from; l->l_local_scope[scope_cnt] != NULL; ++scope_cnt) { _dl_debug_printf (" scope %u:", scope_cnt); - for (unsigned int cnt = 0; cnt < l->l_local_scope[scope_cnt]->r_nlist; ++cnt) + unsigned int cnt; + for (cnt = 0; cnt < l->l_local_scope[scope_cnt]->r_nlist; ++cnt) if (*l->l_local_scope[scope_cnt]->r_list[cnt]->l_name) _dl_debug_printf_c (" %s", l->l_local_scope[scope_cnt]->r_list[cnt]->l_name); @@ -39,6 +41,7 @@ _dl_show_scope (struct link_map *l, int from) _dl_debug_printf_c ("\n"); } + } else _dl_debug_printf (" no scope\n"); _dl_debug_printf ("\n"); From ef20628dd78b92e1a3123afc67b64cf010bdd9e4 Mon Sep 17 00:00:00 2001 From: Mark Hatle Date: Wed, 17 Aug 2016 21:18:49 -0500 Subject: [PATCH 3/3] README: Add known issues to the README 2016-08-17 Mark Hatle * README: Update to include a few known issues Signed-off-by: Mark Hatle --- ChangeLog | 3 +++ README | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/ChangeLog b/ChangeLog index 6d693d2..33d4fdd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2016-08-17 Mark Hatle + * README: Update to include a few known issues + 2016-08-17 Mark Hatle * src/rtld/dl-open.c: Change to work with older compilers diff --git a/README b/README index 345134a..583d145 100644 --- a/README +++ b/README @@ -19,3 +19,21 @@ Cc: yocto@yoctoproject.org Subject: [prelink-cross] .... +Known Issues +------------ + +The --preload option does not always work. The preload1 test currently fails. + +quick2 test will fail if you do not have static libc installed. + +IFUNC on glibc. glibc appears to have a bug related to specific IFUNC +ordering. build_local_scope in glibc is processing depth first instead of +breadth-first processing as it should be. The prelink-rtld version works +around this issue. (Prelink-rtld is only available in the cross compile +version.) See: + +https://bugzilla.yoctoproject.org/show_bug.cgi?id=9131 + +ARM & PPC: both are currently failing the reloc8 and reloc9 test +Further investigation is in progress on these items. Until an explanation +is found, you should hold off using this for ARM and PPC.