From 5b93746b59c57c20334a90e07412361e2853bffe Mon Sep 17 00:00:00 2001 From: David McCullough Date: Tue, 17 Aug 2010 04:25:26 +0000 Subject: [PATCH] When we converted ld-elf2flt from the shell script to C, one small nuance was missed: argv[0] contains the full path only when invoked with the full path. This is not the same behavior for shell scripts as $0 is always the full path to the script in question. Most of the time this isn't an issue as gcc will invoke all of its tools (like the linker) with a full relative path to itself. However, if we attempt to invoke the linker directly, we can see misbehavior such as: bfin-uclinux-ld.real: cannot open linker script file ./../lib/elf2flt.ld: No such file or directory So, to fix this, we lean on more libiberty functions. Specifically, the make_relative_prefix() function. This function locates a full argv[0] by scanning $PATH to see where it was invoked. This might sound a little dodgy, but this is fundamental to how gcc and binutils implement support for their runtime relocation, so it can't break ld-elf2flt without first breaking every one else ;). In the fall out of this fix, we can cull a bunch of local code that does custom path parsing. So not only do we get to fix an annoying bug, we get to shrink code in the process. Signed-off-by: Steve Kilbane Signed-off-by: Mike Frysinger --- ld-elf2flt.c | 76 ++++++++++++++++++++++++++++-------------------------------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/ld-elf2flt.c b/ld-elf2flt.c index 707e9e1..e4cb073 100644 --- a/ld-elf2flt.c +++ b/ld-elf2flt.c @@ -46,7 +46,6 @@ static const char *elf2flt = NULL; static const char *nm = NULL; static const char *objdump = NULL; static const char *objcopy = NULL; -static const char *tooldir = "."; static const char *ldscriptpath = BINUTILS_LDSCRIPTDIR; /* A list of sed commands */ @@ -473,47 +472,49 @@ static void parse_args(int argc, char **argv) int main(int argc, char *argv[]) { - const char *ptr; - char *tmp; const char *argv0 = argv[0]; - size_t len; + const char *argv0_dir = make_relative_prefix(argv0, "/", "/"); + char *tooldir = argv0_dir; + char *bindir = argv0_dir; + char *tmp; struct stat buf; const char *have_exe = NULL; int status; - len = strlen(argv0); #ifdef __WIN32 /* Remove the .exe extension, if it's there. */ + size_t len = strlen(argv0); if (len > 4 && streq(&argv0[len - 4], ".exe")) { have_exe = ".exe"; len -= 4; argv0 = tmp = xstrdup(argv0); tmp[len] = 0; + argv[0][len] = '\0'; } #endif - elf2flt_progname = argv0; - for (ptr = elf2flt_progname + len; ptr != elf2flt_progname; ptr--) - if (IS_DIR_SEPARATOR(ptr[-1])) { - tooldir = tmp = xmalloc(len); - memcpy(tmp, argv0, len); - tmp[ptr - elf2flt_progname - 1] = 0; - elf2flt_progname = ptr; - /* The standard binutils tool layout has: - - bin/-foo - lib/ - /bin/foo - /lib - - It's / that we want here: files in lib/ are for - the host while those in /lib are for the target. */ - if (streqn(elf2flt_progname, TARGET_ALIAS)) { - tmp = concat(tooldir, "/../" TARGET_ALIAS "/bin", NULL); - if (stat(tmp, &buf) == 0 && S_ISDIR(buf.st_mode)) - tooldir = tmp; - } - break; - } + elf2flt_progname = lbasename(argv0); + + /* The standard binutils tool layout has: + + bin/-foo + lib/ + /bin/foo + /lib + + It's / that we want here: files in lib/ are for + the host while those in /lib are for the target. + Make bindir point to the bin dir for bin/-foo. + Make tooldir point to the bin dir for /bin/foo. */ + if (streqn(elf2flt_progname, TARGET_ALIAS)) { + tmp = concat(argv0_dir, "../" TARGET_ALIAS "/bin/", NULL); + if (stat(tmp, &buf) == 0 && S_ISDIR(buf.st_mode)) + tooldir = tmp; + } else { + tmp = concat(argv0_dir, "../../bin/", NULL); + if (stat(tmp, &buf) == 0 && S_ISDIR(buf.st_mode)) + bindir = tmp; + } + /* Typically ld-elf2flt is invoked as `ld` which means error * messages from it will look like "ld: " which is completely * confusing. So append an identifier to keep things clear. @@ -522,25 +523,20 @@ int main(int argc, char *argv[]) xmalloc_set_program_name(elf2flt_progname); - tmp = xmalloc(len + 16); - memcpy(tmp, argv0, len); - while (len && tmp[len - 1] != '-' && !IS_DIR_SEPARATOR(tmp[len - 1])) - len--; - tmp[len] = 0; - - linker = concat(tmp, "ld.real", have_exe, NULL); - elf2flt = concat(tmp, "elf2flt", have_exe, NULL); - nm = concat(tmp, "nm", have_exe, NULL); - objdump = concat(tooldir, "/../../bin/", TARGET_ALIAS, "-objdump", have_exe, NULL); - objcopy = concat(tooldir, "/../../bin/", TARGET_ALIAS, "-objcopy", have_exe, NULL); + linker = concat(tooldir, "ld.real", have_exe, NULL); + elf2flt = concat(tooldir, "elf2flt", have_exe, NULL); + nm = concat(tooldir, "nm", have_exe, NULL); + objdump = concat(bindir, TARGET_ALIAS "-objdump", have_exe, NULL); + objcopy = concat(bindir, TARGET_ALIAS "-objcopy", have_exe, NULL); if (stat(ldscriptpath, &buf) || !S_ISDIR(buf.st_mode)) - ldscriptpath = concat(tooldir, "/../lib", NULL); + ldscriptpath = concat(tooldir, "../lib", NULL); parse_args(argc, argv); if (flag_verbose) { fprintf(stderr, "argv[0] = '%s'\n", argv[0]); + fprintf(stderr, "bindir = '%s'\n", bindir); fprintf(stderr, "tooldir = '%s'\n", tooldir); fprintf(stderr, "linker = '%s'\n", linker); fprintf(stderr, "elf2flt = '%s'\n", elf2flt); -- 2.11.0