From 2dcf3d486380ca349e6cf76bda2ec19ca49a3d16 Mon Sep 17 00:00:00 2001 From: "Azamat H. Hackimov" Date: Mon, 29 Jan 2024 01:52:05 +0300 Subject: [PATCH] Resolve GNU ld scripts Resolve GNU ld scripts with additional checks for UNIX-like systems (fixes #17). --- libwhich.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/libwhich.c b/libwhich.c index 15787fa..5fdcd5b 100644 --- a/libwhich.c +++ b/libwhich.c @@ -208,6 +208,48 @@ const char *dlpath(void *handle, struct vector_t name) #elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__ELF__) #include +#include + +/* Check for a recognized ld script line. */ +static char *check_ldscript(const char *buf) +{ + char *p, *e; + // Check only GROUP and INPUT entries + if ((!strncmp(buf, "GROUP", 5) || !strncmp(buf, "INPUT", 5)) && (p = strchr(buf, '('))) { + while (*++p == ' ') ; + for (e = p; *e && *e != ' ' && *e != ')'; e++); + char *name = malloc(e - p); + strncpy(name, p, e - p); + return name; + } + return NULL; +} + +/* Try to resolve file as GNU ld script */ +static char *resolve_ldscript(const char *name) +{ + FILE *fp = fopen(name, "r"); + char *p = NULL; + if (fp) { + char buf[256]; + if (fgets(buf, sizeof(buf), fp)) { + // Let's hope that every ld script begins with that "magic" + if (!strncmp(buf, "/* GNU ld script", 16)) { + while (fgets(buf, sizeof(buf), fp)) { + p = check_ldscript(buf); + if (p) { + break; + } + } + } else { + /* Otherwise check only the first line. */ + p = check_ldscript(buf); + } + } + fclose(fp); + } + return p; +} int get_names(struct dl_phdr_info *info, size_t size, void *data) { @@ -339,6 +381,26 @@ int main(int argc, STR *argv) struct vector_t before = dllist(); void *lib = dlopen(libname, RTLD_LAZY); if (!lib) { +#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__ELF__) + /* Try to resolve ld script references. */ + char *name; + const char *e, *err = dlerror(); + if (err && *err == '/' && (e = strchr(err, ':'))) { + name = malloc(e - err); + strncpy(name, err, e - err); + char *test = resolve_ldscript(name); + if (test != NULL) { + // Let's try again... + lib = dlopen(test, RTLD_LAZY); + free(test); + } + if (name != NULL) + free(name); + } + } + + if (!lib) { +#endif fputs(T("failed to open library: "), stdout); #if defined(_WIN32) fputs(T("LoadLibrary("), stdout);