From 2c72361c810f4b6223949363f635376e4311ac7a Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Fri, 6 Nov 2020 14:36:45 +0000 Subject: [PATCH] Extend ld's -Map= functionality by allowing '%' to be replaced with the output file path. * lexsup.c (parse_args): Add more checks of the mapfile. If it is a directory use the basename of the output file as the file component. If the % character is present, replace it with the full output filepath. * testsuite/ld-scripts/map-address.exp: Add test of % functionality. * ld.texi: Document the new behaviour. --- ld/ChangeLog | 10 ++++ ld/ld.texi | 32 ++++++++++-- ld/lexsup.c | 68 +++++++++++++++++++------ ld/testsuite/ld-scripts/map-address.exp | 47 +++++++++++++++++ 4 files changed, 137 insertions(+), 20 deletions(-) diff --git a/ld/ChangeLog b/ld/ChangeLog index 54c337df3cb..0909d6a62ba 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,13 @@ +2020-11-06 Nick Clifton + + * lexsup.c (parse_args): Add more checks of the mapfile. If it is + a directory use the basename of the output file as the file + component. If the % character is present, replace it with the + full output filepath. + * testsuite/ld-scripts/map-address.exp: Add test of % + functionality. + * ld.texi: Document the new behaviour. + 2020-11-06 Nick Clifton * po/sr.po: Updated Serbian translation. diff --git a/ld/ld.texi b/ld/ld.texi index cf8f05c39e0..9b74b893c19 100644 --- a/ld/ld.texi +++ b/ld/ld.texi @@ -1866,10 +1866,34 @@ Print a summary of all target-specific options on the standard output and exit. @kindex -Map=@var{mapfile} @item -Map=@var{mapfile} Print a link map to the file @var{mapfile}. See the description of the -@option{-M} option, above. Specifying a directory as @var{mapfile} -causes the linker map to be written into a file inside the directory. -The name of the file is based upon the @var{output} filename with -@code{.map} appended. +@option{-M} option, above. If @var{mapfile} is just the character +@code{-} then the map will be written to stdout. + +Specifying a directory as @var{mapfile} causes the linker map to be +written as a file inside the directory. Normally name of the file +inside the directory is computed as the basename of the @var{output} +file with @code{.map} appended. If however the special character +@code{%} is used then this will be replaced by the full path of the +output file. Additionally if there are any characters after the +@var{%} symbol then @code{.map} will no longer be appended. + +@smallexample + -o foo.exe -Map=bar [Creates ./bar] + -o ../dir/foo.exe -Map=bar [Creates ./bar] + -o foo.exe -Map=../dir [Creates ../dir/foo.exe.map] + -o ../dir2/foo.exe -Map=../dir [Creates ../dir/foo.exe.map] + -o foo.exe -Map=% [Creates ./foo.exe.map] + -o ../dir/foo.exe -Map=% [Creates ../dir/foo.exe.map] + -o foo.exe -Map=%.bar [Creates ./foo.exe.bar] + -o ../dir/foo.exe -Map=%.bar [Creates ../dir/foo.exe.bar] + -o ../dir2/foo.exe -Map=../dir/% [Creates ../dir/../dir2/foo.exe.map] + -o ../dir2/foo.exe -Map=../dir/%.bar [Creates ../dir/../dir2/foo.exe.bar] +@end smallexample + +It is an error to specify more than one @code{%} character. + +If the map file already exists then it will be overwritten by this +operation. @cindex memory usage @kindex --no-keep-memory diff --git a/ld/lexsup.c b/ld/lexsup.c index eae64932dfc..0d10bc6fba8 100644 --- a/ld/lexsup.c +++ b/ld/lexsup.c @@ -22,8 +22,10 @@ #include "bfd.h" #include "bfdver.h" #include "libiberty.h" +#include "filenames.h" #include #include +#include #include "safe-ctype.h" #include "getopt.h" #include "bfdlink.h" @@ -1700,35 +1702,69 @@ parse_args (unsigned argc, char **argv) /* Run a couple of checks on the map filename. */ if (config.map_filename) { + char * new_name = NULL; + char * percent; + int res = 0; + if (config.map_filename[0] == 0) { einfo (_("%P: no file/directory name provided for map output; ignored\n")); config.map_filename = NULL; } + else if (strcmp (config.map_filename, "-") == 0) + ; /* Write to stdout. Handled in main(). */ + else if ((percent = strchr (config.map_filename, '%')) != NULL) + { + /* FIXME: Check for a second % character and issue an error ? */ + + /* Construct a map file by replacing the % character with the (full) + output filename. If the % character was the last character in + the original map filename then add a .map extension. */ + percent[0] = 0; + res = asprintf (&new_name, "%s%s%s", config.map_filename, + output_filename, + percent[1] ? percent + 1 : ".map"); + + /* FIXME: Should we ensure that any directory components in new_name exist ? */ + } else { struct stat s; /* If the map filename is actually a directory then create a file inside it, based upon the output filename. */ - if (stat (config.map_filename, &s) >= 0 - && S_ISDIR (s.st_mode)) + if (stat (config.map_filename, &s) < 0) { - char * new_name; - - /* FIXME: This is a (trivial) memory leak. */ - if (asprintf (&new_name, "%s/%s.map", - config.map_filename, output_filename) < 0) - { - /* If this alloc fails then something is probably very - wrong. Better to halt now rather than continue on - into more problems. */ - einfo (_("%P%F: cannot create name for linker map file: %E\n")); - new_name = NULL; - } - - config.map_filename = new_name; + if (errno != ENOENT) + einfo (_("%P: cannot stat linker map file: %E\n")); } + else if (S_ISDIR (s.st_mode)) + { + char lastc = config.map_filename[strlen (config.map_filename) - 1]; + res = asprintf (&new_name, "%s%s%s.map", + config.map_filename, + IS_DIR_SEPARATOR (lastc) ? "" : "/", + lbasename (output_filename)); + } + else if (! S_ISREG (s.st_mode)) + { + einfo (_("%P: linker map file is not a regular file\n")); + config.map_filename = NULL; + } + /* else FIXME: Check write permission ? */ + } + + if (res < 0) + { + /* If the asprintf failed then something is probably very + wrong. Better to halt now rather than continue on + into more problems. */ + einfo (_("%P%F: cannot create name for linker map file: %E\n")); + } + else if (new_name != NULL) + { + /* This is a trivial memory leak. */ + config.map_filename = new_name; } } diff --git a/ld/testsuite/ld-scripts/map-address.exp b/ld/testsuite/ld-scripts/map-address.exp index 1f9457a8cdb..e8d3683c018 100644 --- a/ld/testsuite/ld-scripts/map-address.exp +++ b/ld/testsuite/ld-scripts/map-address.exp @@ -46,6 +46,7 @@ if {[regexp_diff \ pass $testname } + set testname "map to directory" if {![ld_link $ld tmpdir/map-address \ @@ -67,3 +68,49 @@ if {[regexp_diff \ } else { pass $testname } + + +set testname "map to % directory" + +if {![ld_link $ld tmpdir/map-address \ + "$LDFLAGS -T $srcdir/$subdir/map-address.t \ + tmpdir/map-address.o \ + -Map=tmpdir/% --output fred"]} { + fail $testname + return +} + +if [is_remote host] then { + remote_upload host "tmpdir/fred.map" +} + +if {[regexp_diff \ + "tmpdir/fred.map" \ + "$srcdir/$subdir/map-address.d"]} { + fail $testname +} else { + pass $testname +} + + +set testname "map to %.foo directory" + +if {![ld_link $ld tmpdir/map-address \ + "$LDFLAGS -T $srcdir/$subdir/map-address.t \ + tmpdir/map-address.o \ + -Map=tmpdir/%.foo --output fred"]} { + fail $testname + return +} + +if [is_remote host] then { + remote_upload host "tmpdir/fred.foo" +} + +if {[regexp_diff \ + "tmpdir/fred.foo" \ + "$srcdir/$subdir/map-address.d"]} { + fail $testname +} else { + pass $testname +} -- 2.30.2