Skip to content

Commit 7e57061

Browse files
authored
Parse both .rela.dyn and .rela.plt of libraries. (#1074)
1 parent 5fe149a commit 7e57061

File tree

4 files changed

+111
-23
lines changed

4 files changed

+111
-23
lines changed

Makefile

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ JAVA=$(JAVA_HOME)/bin/java
3737
JAVA_TARGET=8
3838
JAVAC_OPTIONS=--release $(JAVA_TARGET) -Xlint:-options
3939

40+
TEST_LIB_DIR=build/test/lib
4041
LOG_DIR=build/test/logs
4142
LOG_LEVEL=
4243
SKIP=
@@ -115,13 +116,7 @@ ifneq (,$(findstring $(ARCH_TAG),x86 x64 arm64))
115116
endif
116117

117118

118-
.PHONY: all jar release build-test test native clean coverage clean-coverage build-test-java build-test-cpp test-cpp test-java format-md check-md
119-
120-
check-md:
121-
prettier -c README.md "docs/**/*.md"
122-
123-
format-md:
124-
prettier -w README.md "docs/**/*.md"
119+
.PHONY: all jar release build-test test native clean coverage clean-coverage build-test-java build-test-cpp build-test-libs test-cpp test-java check-md format-md
125120

126121
all: build/bin build/lib build/$(LIB_PROFILER) build/$(ASPROF) jar build/$(JFRCONV)
127122

@@ -186,23 +181,26 @@ build/$(CONVERTER_JAR): $(CONVERTER_SOURCES) $(RESOURCES)
186181

187182
build/test/cpptests: $(CPP_TEST_SOURCES) $(CPP_TEST_HEADER) $(SOURCES) $(HEADERS) $(RESOURCES) $(JAVA_HELPER_CLASSES)
188183
mkdir -p build/test
189-
190184
ifeq ($(MERGE),true)
191185
for f in src/*.cpp test/native/*.cpp; do echo '#include "'$$f'"'; done |\
192186
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEFS) $(INCLUDES) $(CPP_TEST_INCLUDES) -fPIC -o $@ -xc++ - $(LIBS)
193187
else
194188
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEFS) $(INCLUDES) $(CPP_TEST_INCLUDES) -fPIC -o $@ $(SOURCES) $(CPP_TEST_SOURCES) $(LIBS)
195189
endif
196190

197-
build-test-java: all build/$(TEST_JAR)
191+
build-test-java: all build/$(TEST_JAR) build-test-libs
198192

199-
build-test-cpp: build/test/cpptests
193+
build-test-cpp: build/test/cpptests build-test-libs
200194

201195
build-test: build-test-cpp build-test-java
202196

197+
build-test-libs:
198+
@mkdir -p $(TEST_LIB_DIR)
199+
$(CC) -shared -fPIC -o $(TEST_LIB_DIR)/libreladyn.$(SOEXT) test/native/libs/reladyn.c
200+
203201
test-cpp: build-test-cpp
204202
echo "Running cpp tests..."
205-
build/test/cpptests
203+
LD_LIBRARY_PATH="$(TEST_LIB_DIR)" build/test/cpptests
206204

207205
test-java: build-test-java
208206
echo "Running tests against $(LIB_PROFILER)"
@@ -228,6 +226,12 @@ native:
228226
tar xfO async-profiler-$(PROFILER_VERSION)-linux-arm64.tar.gz */build/libasyncProfiler.so > native/linux-arm64/libasyncProfiler.so
229227
unzip -p async-profiler-$(PROFILER_VERSION)-macos.zip */build/libasyncProfiler.dylib > native/macos/libasyncProfiler.dylib
230228

229+
check-md:
230+
prettier -c README.md "docs/**/*.md"
231+
232+
format-md:
233+
prettier -w README.md "docs/**/*.md"
234+
231235
clean-coverage:
232236
$(RM) -rf build/test/cpptests build/test/coverage
233237

src/symbols_linux.cpp

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -145,22 +145,29 @@ typedef Elf32_Dyn ElfDyn;
145145

146146
#if defined(__x86_64__)
147147
# define R_GLOB_DAT R_X86_64_GLOB_DAT
148+
# define R_ABS64 R_X86_64_64
148149
#elif defined(__i386__)
149150
# define R_GLOB_DAT R_386_GLOB_DAT
151+
# define R_ABS64 -1
150152
#elif defined(__arm__) || defined(__thumb__)
151153
# define R_GLOB_DAT R_ARM_GLOB_DAT
154+
# define R_ABS64 -1
152155
#elif defined(__aarch64__)
153156
# define R_GLOB_DAT R_AARCH64_GLOB_DAT
157+
# define R_ABS64 R_AARCH64_ABS64
154158
#elif defined(__PPC64__)
155159
# define R_GLOB_DAT R_PPC64_GLOB_DAT
160+
# define R_ABS64 -1
156161
#elif defined(__riscv) && (__riscv_xlen == 64)
157162
// RISC-V does not have GLOB_DAT relocation, use something neutral,
158163
// like the impossible relocation number.
159164
# define R_GLOB_DAT -1
165+
# define R_ABS64 -1
160166
#elif defined(__loongarch_lp64)
161167
// LOONGARCH does not have GLOB_DAT relocation, use something neutral,
162168
// like the impossible relocation number.
163169
# define R_GLOB_DAT -1
170+
# define R_ABS64 -1
164171
#else
165172
# error "Compiling on unsupported arch"
166173
#endif
@@ -385,6 +392,21 @@ void ElfParser::parseDynamicSection() {
385392
}
386393

387394
const char* base = this->base();
395+
if (rel != NULL && relsz != 0) {
396+
// If a shared library is built without PLT (-fno-plt), relocation entries for imports
397+
// can be found in .rela.dyn. However, if both sections exist, .rela.plt entries
398+
// should take precedence, that's why we parse .rela.dyn first.
399+
for (size_t offs = relcount * relent; offs < relsz; offs += relent) {
400+
ElfRelocation* r = (ElfRelocation*)(rel + offs);
401+
if (ELF_R_TYPE(r->r_info) == R_GLOB_DAT || ELF_R_TYPE(r->r_info) == R_ABS64) {
402+
ElfSymbol* sym = (ElfSymbol*)(symtab + ELF_R_SYM(r->r_info) * syment);
403+
if (sym->st_name != 0) {
404+
_cc->addImport((void**)(base + r->r_offset), strtab + sym->st_name);
405+
}
406+
}
407+
}
408+
}
409+
388410
if (jmprel != NULL && pltrelsz != 0) {
389411
// Parse .rela.plt table
390412
for (size_t offs = 0; offs < pltrelsz; offs += relent) {
@@ -394,18 +416,6 @@ void ElfParser::parseDynamicSection() {
394416
_cc->addImport((void**)(base + r->r_offset), strtab + sym->st_name);
395417
}
396418
}
397-
} else if (rel != NULL && relsz != 0) {
398-
// Shared library was built without PLT (-fno-plt)
399-
// Relocation entries have been moved from .rela.plt to .rela.dyn
400-
for (size_t offs = relcount * relent; offs < relsz; offs += relent) {
401-
ElfRelocation* r = (ElfRelocation*)(rel + offs);
402-
if (ELF_R_TYPE(r->r_info) == R_GLOB_DAT) {
403-
ElfSymbol* sym = (ElfSymbol*)(symtab + ELF_R_SYM(r->r_info) * syment);
404-
if (sym->st_name != 0) {
405-
_cc->addImport((void**)(base + r->r_offset), strtab + sym->st_name);
406-
}
407-
}
408-
}
409419
}
410420
}
411421
}

test/native/libs/reladyn.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright The async-profiler authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include <pthread.h>
7+
#include <stdio.h>
8+
9+
// Force pthread_setspecific into .rela.dyn with R_X86_64_GLOB_DAT.
10+
int (*indirect_pthread_setspecific)(pthread_key_t, const void*);
11+
12+
// Force pthread_exit into .rela.dyn with R_X86_64_64.
13+
void (*static_pthread_exit)(void*) = pthread_exit;
14+
15+
void* thread_function(void* arg) {
16+
printf("Thread running\n");
17+
return NULL;
18+
}
19+
20+
// Not indended to be executed.
21+
int reladyn() {
22+
pthread_t thread;
23+
pthread_key_t key;
24+
25+
pthread_key_create(&key, NULL);
26+
27+
// Direct call, forces into .rela.plt.
28+
pthread_create(&thread, NULL, thread_function, NULL);
29+
30+
// Assign to a function pointer at runtime, forces into .rela.dyn as R_X86_64_GLOB_DAT.
31+
indirect_pthread_setspecific = pthread_setspecific;
32+
indirect_pthread_setspecific(key, "Thread-specific value");
33+
34+
// Use pthread_exit via the static pointer, forces into .rela.dyn as R_X86_64_64.
35+
static_pthread_exit(NULL);
36+
37+
return 0;
38+
}

test/native/symbolsLinuxTest.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright The async-profiler authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#ifdef __linux__
7+
8+
#include "codeCache.h"
9+
#include "profiler.h"
10+
#include "testRunner.hpp"
11+
#include <dlfcn.h>
12+
13+
#define ASSERT_RESOLVE(id) \
14+
{ \
15+
void* result = dlopen("libreladyn.so", RTLD_NOW); /* see reladyn.c */ \
16+
ASSERT(result); \
17+
Profiler::instance()->updateSymbols(false); \
18+
CodeCache* libreladyn = Profiler::instance()->findLibraryByName("libreladyn"); \
19+
ASSERT(libreladyn); \
20+
void* sym = libreladyn->findImport(id); \
21+
ASSERT(sym); \
22+
}
23+
24+
TEST_CASE(ResolveFromRela_plt) {
25+
ASSERT_RESOLVE(im_pthread_create);
26+
}
27+
28+
TEST_CASE(ResolveFromRela_dyn_R_GLOB_DAT) {
29+
ASSERT_RESOLVE(im_pthread_setspecific);
30+
}
31+
32+
TEST_CASE(ResolveFromRela_dyn_R_ABS64) {
33+
ASSERT_RESOLVE(im_pthread_exit);
34+
}
35+
36+
#endif // __linux__

0 commit comments

Comments
 (0)