Skip to content

Commit 0121f5e

Browse files
authored
Merge pull request #180 from iv-m/mips-fixes
Fixes for MIPS binaries
2 parents 374c92a + bf73d6e commit 0121f5e

File tree

4 files changed

+78
-6
lines changed

4 files changed

+78
-6
lines changed

src/elf.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,9 +1574,10 @@ typedef struct
15741574

15751575
/* Legal values for p_type field of Elf32_Phdr. */
15761576

1577-
#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */
1578-
#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */
1579-
#define PT_MIPS_OPTIONS 0x70000002
1577+
#define PT_MIPS_REGINFO 0x70000000 /* Register usage information. */
1578+
#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */
1579+
#define PT_MIPS_OPTIONS 0x70000002
1580+
#define PT_MIPS_ABIFLAGS 0x70000003 /* FP mode requirement. */
15801581

15811582
/* Special program header types. */
15821583

@@ -1642,7 +1643,11 @@ typedef struct
16421643
PLT is writable. For a non-writable PLT, this is omitted or has a zero
16431644
value. */
16441645
#define DT_MIPS_RWPLT 0x70000034
1645-
#define DT_MIPS_NUM 0x35
1646+
/* An alternative description of the classic MIPS RLD_MAP that is usable
1647+
in a PIE as it stores a relative offset from the address of the tag
1648+
rather than an absolute address. */
1649+
#define DT_MIPS_RLD_MAP_REL 0x70000035
1650+
#define DT_MIPS_NUM 0x36
16461651

16471652
/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */
16481653

src/patchelf.cc

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,18 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
766766
}
767767
}
768768

769+
/* If there is .MIPS.abiflags section, then the PT_MIPS_ABIFLAGS
770+
segment must be sync'ed with it. */
771+
if (sectionName == ".MIPS.abiflags") {
772+
for (auto & phdr : phdrs) {
773+
if (rdi(phdr.p_type) == PT_MIPS_ABIFLAGS) {
774+
phdr.p_offset = shdr.sh_offset;
775+
phdr.p_vaddr = phdr.p_paddr = shdr.sh_addr;
776+
phdr.p_filesz = phdr.p_memsz = shdr.sh_size;
777+
}
778+
}
779+
}
780+
769781
curOff += roundUp(i.second.size(), sectionAlignment);
770782
}
771783

@@ -1098,9 +1110,9 @@ void ElfFile<ElfFileParamNames>::rewriteHeaders(Elf_Addr phdrAddress)
10981110
(e.g., those produced by klibc's klcc). */
10991111
auto shdrDynamic = findSection2(".dynamic");
11001112
if (shdrDynamic) {
1101-
auto dyn = (Elf_Dyn *)(contents + rdi(shdrDynamic->sh_offset));
1113+
auto dyn_table = (Elf_Dyn *) (contents + rdi(shdrDynamic->sh_offset));
11021114
unsigned int d_tag;
1103-
for ( ; (d_tag = rdi(dyn->d_tag)) != DT_NULL; dyn++)
1115+
for (auto dyn = dyn_table; (d_tag = rdi(dyn->d_tag)) != DT_NULL; dyn++)
11041116
if (d_tag == DT_STRTAB)
11051117
dyn->d_un.d_ptr = findSection(".dynstr").sh_addr;
11061118
else if (d_tag == DT_STRSZ)
@@ -1142,6 +1154,23 @@ void ElfFile<ElfFileParamNames>::rewriteHeaders(Elf_Addr phdrAddress)
11421154
dyn->d_un.d_ptr = findSection(".gnu.version_r").sh_addr;
11431155
else if (d_tag == DT_VERSYM)
11441156
dyn->d_un.d_ptr = findSection(".gnu.version").sh_addr;
1157+
else if (d_tag == DT_MIPS_RLD_MAP_REL) {
1158+
/* the MIPS_RLD_MAP_REL tag stores the offset to the debug
1159+
pointer, relative to the address of the tag */
1160+
auto shdr = findSection2(".rld_map");
1161+
if (shdr) {
1162+
auto rld_map_addr = findSection(".rld_map").sh_addr;
1163+
auto dyn_offset = ((char*)dyn) - ((char*)dyn_table);
1164+
dyn->d_un.d_ptr = rld_map_addr + dyn_offset - shdrDynamic->sh_addr;
1165+
} else {
1166+
/* ELF file with DT_MIPS_RLD_MAP_REL but without .rld_map
1167+
is broken, and it's not our job to fix it; yet, we have
1168+
to find some location for dynamic loader to write the
1169+
debug pointer to; well, let's write it right here */
1170+
fprintf(stderr, "warning: DT_MIPS_RLD_MAP_REL entry is present, but .rld_map section is not\n");
1171+
dyn->d_un.d_ptr = 0;
1172+
}
1173+
}
11451174
}
11461175

11471176

tests/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ src_TESTS = \
2222
plain-fail.sh plain-run.sh shrink-rpath.sh set-interpreter-short.sh \
2323
set-interpreter-long.sh set-rpath.sh add-rpath.sh no-rpath.sh big-dynstr.sh \
2424
set-rpath-library.sh soname.sh shrink-rpath-with-allowed-prefixes.sh \
25+
set-rpath-rel-map.sh \
2526
force-rpath.sh \
2627
plain-needed.sh \
2728
output-flag.sh \

tests/set-rpath-rel-map.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#! /bin/sh -e
2+
3+
if ! objdump -p main | grep -q MIPS_RLD_MAP_REL; then
4+
echo "No MIPS_RLD_MAP_REL dynamic section entry, skipping"
5+
exit 0
6+
fi
7+
8+
SCRATCH=scratch/$(basename $0 .sh)
9+
10+
rm -rf ${SCRATCH}
11+
mkdir -p ${SCRATCH}
12+
mkdir -p ${SCRATCH}/libsA
13+
mkdir -p ${SCRATCH}/libsB
14+
15+
cp main ${SCRATCH}/
16+
cp libfoo.so ${SCRATCH}/libsA/
17+
cp libbar.so ${SCRATCH}/libsB/
18+
19+
# break the main executable by removing .rld_map section
20+
objcopy --remove-section .rld_map ${SCRATCH}/main
21+
22+
oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/main)
23+
if test -z "$oldRPath"; then oldRPath="/oops"; fi
24+
../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/main
25+
26+
if test "$(uname)" = FreeBSD; then
27+
export LD_LIBRARY_PATH=$(pwd)/${SCRATCH}/libsB
28+
fi
29+
30+
exitCode=0
31+
32+
(cd ${SCRATCH} && ./main) || exitCode=$?
33+
34+
if test "$exitCode" != 46; then
35+
echo "bad exit code!"
36+
exit 1
37+
fi

0 commit comments

Comments
 (0)