summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordavidm <davidm>2010-08-17 08:25:26 +0400
committerdavidm <davidm>2010-08-17 08:25:26 +0400
commit1101ea0b76943ee64a429f36b9422811e3bc1680 (patch)
treed062e79c2a9dd132406fa35569bf7eb3af6b7e31
parent0a4959ba2b2d06c099f7923f6b3cdd23aff9bc87 (diff)
downloadelf2flt-1101ea0b76943ee64a429f36b9422811e3bc1680.tar.xz
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 <steve@whitecrow.demon.co.uk> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
-rw-r--r--ld-elf2flt.c76
1 files 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/<TARGET_ALIAS>-foo
- lib/
- <TARGET_ALIAS>/bin/foo
- <TARGET_ALIAS>/lib
-
- It's <TARGET_ALIAS>/ that we want here: files in lib/ are for
- the host while those in <TARGET_ALIAS>/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/<TARGET_ALIAS>-foo
+ lib/
+ <TARGET_ALIAS>/bin/foo
+ <TARGET_ALIAS>/lib
+
+ It's <TARGET_ALIAS>/ that we want here: files in lib/ are for
+ the host while those in <TARGET_ALIAS>/lib are for the target.
+ Make bindir point to the bin dir for bin/<TARGET_ALIAS>-foo.
+ Make tooldir point to the bin dir for <TARGET_ALIAS>/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);