Skip to content

Commit 4323517

Browse files
committed
Fix control-flow recovery relocation handling
Previous version would miss some functions only reachable via indirect calls.
1 parent b59068c commit 4323517

7 files changed

Lines changed: 61 additions & 28 deletions

File tree

src/e9tool/e9cfg.cpp

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ extern bool option_debug;
5050
} \
5151
while (false)
5252

53-
typedef std::set<intptr_t> RelaInfo;
54-
5553
/*
5654
* Insert target information.
5755
*/
@@ -251,7 +249,7 @@ static void CFGCodeAnalysis(const ELF *elf, bool pic, const Instr *Is,
251249
* Section analysis pass: find potential code pointers in data.
252250
*/
253251
static void CFGSectionAnalysis(const ELF *elf, bool pic, const char *name,
254-
const Elf64_Shdr *shdr, const Instr *Is, size_t size, const RelaInfo relas,
252+
const Elf64_Shdr *shdr, const Instr *Is, size_t size,
255253
const std::set<intptr_t> &tables, Targets &targets)
256254
{
257255
if ((shdr->sh_flags & SHF_EXECINSTR) != 0 || shdr->sh_addr == 0x0)
@@ -316,26 +314,6 @@ static void CFGSectionAnalysis(const ELF *elf, bool pic, const char *name,
316314
}
317315
}
318316
}
319-
320-
if (shdr->sh_type == SHT_PROGBITS)
321-
{
322-
// Scan for code pointers using relocation information.
323-
auto bounds = getBounds<int64_t>(sh_data, sh_data + sh_size);
324-
for (const int64_t *p = bounds.first; p < bounds.second; p++)
325-
{
326-
intptr_t offset = (intptr_t)shdr->sh_addr +
327-
((intptr_t)p - (intptr_t)sh_data);
328-
auto i = relas.find(offset);
329-
if (i == relas.end())
330-
continue;
331-
332-
intptr_t target = *p;
333-
if (findInstr(Is, size, target) < 0)
334-
continue;
335-
DEBUG(targets, target, "Reloc : %p (F)", (void *)target);
336-
addTarget(target, TARGET_INDIRECT | TARGET_FUNCTION, targets);
337-
}
338-
}
339317
}
340318
}
341319

@@ -347,7 +325,6 @@ static void CFGDataAnalysis(const ELF *elf, bool pic, const Instr *Is,
347325
{
348326
// Gather relocation information:
349327
const SectionInfo &sections = getELFSectionInfo(elf);
350-
RelaInfo relas;
351328
for (const auto &entry: sections)
352329
{
353330
const Elf64_Shdr *shdr = entry.second;
@@ -359,16 +336,19 @@ static void CFGDataAnalysis(const ELF *elf, bool pic, const Instr *Is,
359336
const Elf64_Rela *rela_end = rela + sh_size / sizeof(Elf64_Rela);
360337
for (; rela < rela_end; rela++)
361338
{
362-
if (ELF64_R_TYPE(rela->r_info) == R_X86_64_RELATIVE &&
363-
rela->r_addend == 0)
364-
relas.insert(rela->r_offset);
339+
if (ELF64_R_TYPE(rela->r_info) == R_X86_64_RELATIVE)
340+
{
341+
intptr_t target = (intptr_t)rela->r_addend;
342+
DEBUG(targets, target, "Reloc : %p (F)", (void *)target);
343+
addTarget(target, TARGET_INDIRECT | TARGET_FUNCTION, targets);
344+
}
365345
}
366346
}
367347

368348
// Analyze each data section:
369349
for (const auto &entry: sections)
370350
CFGSectionAnalysis(elf, pic, entry.first, entry.second, Is, size,
371-
relas, tables, targets);
351+
tables, targets);
372352
}
373353

374354
/*

test/regtest/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ all:
1818
gcc -x assembler-with-cpp -shared -o libtest.so libtest.s
1919
gcc -O2 -fPIC $(FCF_NONE) -pie -o test_c test_c.c \
2020
-Wl,--export-dynamic -U_FORTIFY_SOURCE
21+
strip test_c
2122
../../e9compile.sh inst.c -I ../../examples/ -D NO_GLIBC
2223
../../e9compile.sh patch.cpp -std=c++11 -I ../../examples/ -D NO_GLIBC
2324
../../e9compile.sh dl.c -I ../../examples/

test/regtest/call_func.exp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Hello world!
2+
Hello world!
3+
fib = 89
4+
prime(121) = 0
5+
prime(131) = 1
6+
*
7+
***
8+
*****
9+
*******
10+
*********
11+
* *
12+
*** ***
13+
***** *****
14+
******* *******
15+
********* *********
16+
invoke data_func()

test/regtest/call_func.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
./test_c -M 'mnemonic==/xchg.*/ && reg[0] == %r15 && reg[0] == reg[1] && addr == F.addr' -P 'exit(0)'

test/regtest/repair_fib.exp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@ prime(131) = 1
1313
***** *****
1414
******* *******
1515
********* *********
16+
invoke data_func()
17+
invoked data_func()

test/regtest/repair_fib_2.exp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@ prime(131) = 1
1313
***** *****
1414
******* *******
1515
********* *********
16+
invoke data_func()
17+
invoked data_func()

test/regtest/test_c.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,34 @@ __attribute__((__noinline__)) void triforce(ssize_t n)
6666
}
6767
}
6868

69+
void data_func_2(void)
70+
{
71+
printf("invoked data_func()\n");
72+
asm volatile ("nop");
73+
}
74+
75+
static void data_func(void)
76+
{
77+
asm volatile (
78+
"xchg %r15, %r15\n"
79+
"callq data_func_2");
80+
}
81+
82+
struct call_s
83+
{
84+
void (*f)(void);
85+
const char *name;
86+
};
87+
88+
static const struct call_s call_info = {data_func, "data_func"};
89+
90+
__attribute__((__noinline__)) void invoke(const struct call_s *info)
91+
{
92+
printf("invoke %s()\n", info->name);
93+
fflush(stdout);
94+
info->f();
95+
}
96+
6997
int main(void)
7098
{
7199
printf("Hello world!\n");
@@ -88,6 +116,9 @@ int main(void)
88116
printf("prime(131) = %d\n", is_prime(131));
89117
triforce(9);
90118

119+
fflush(stdout);
120+
invoke(&call_info);
121+
91122
return 0;
92123
}
93124

0 commit comments

Comments
 (0)