Add linker option to include local symbols in the linker map.
authorNick Clifton <nickc@redhat.com>
Wed, 10 May 2023 09:29:52 +0000 (10:29 +0100)
committerNick Clifton <nickc@redhat.com>
Wed, 10 May 2023 09:29:52 +0000 (10:29 +0100)
  PR 16566
  * ldlang.c (ld_is_local_symbol): New function. (print_input_section): Add code to display local symbols in the section.
  * ldlex.h (enum option_values): Add OPTION_PRINT_MAP_LOCALS and OPTION_PRINT_MAP_LOCALS.
  * lexsup.c (ld_options[]): Add entries for --print-map-locals and --no-print-map-locals.
  * NEWS: Mention the new feature.
  * ld.h (struct ld_config_type): Add print_map_locals field.
  * ld.texi: Document the new command line option.
  * testsuite/ld-scripts/sizeof.s: Add a local symbol.
  * testsuite/ld-scripts/map-locals.d: New test control file.
  * testsuite/ld-scripts/map-address.exp: Run the new test.

ld/ChangeLog
ld/NEWS
ld/ld.h
ld/ld.texi
ld/ldlang.c
ld/ldlex.h
ld/lexsup.c
ld/testsuite/ld-scripts/map-address.exp
ld/testsuite/ld-scripts/map-locals.d [new file with mode: 0644]
ld/testsuite/ld-scripts/sizeof.s

index 121bdfd735f8e08739e9c55b752b86e43864a85e..dac58cd575b5d35a04c8365120b82a9923fa749a 100644 (file)
@@ -1,3 +1,20 @@
+2023-05-10  Nick Clifton  <nickc@redhat.com>
+
+       PR 16566
+       * ldlang.c (ld_is_local_symbol): New function.
+       (print_input_section): Add code to display local symbols in the
+       section.
+       * ldlex.h (enum option_values): Add OPTION_PRINT_MAP_LOCALS and
+       OPTION_PRINT_MAP_LOCALS.
+       * lexsup.c (ld_options[]): Add entries for --print-map-locals
+       and --no-print-map-locals.
+       * NEWS: Mention the new feature.
+       * ld.h (struct ld_config_type): Add print_map_locals field.
+       * ld.texi: Document the new command line option.
+       * testsuite/ld-scripts/sizeof.s: Add a local symbol.
+       * testsuite/ld-scripts/map-locals.d: New test control file.
+       * testsuite/ld-scripts/map-address.exp: Run the new test.
+
 2023-05-04  Nick Clifton  <nickc@redhat.com>
 
        PR 30300
diff --git a/ld/NEWS b/ld/NEWS
index 37041e7456f207b476402bfda708aca4a54971e6..9920d0209b828b0e2303b229b86451020b476436 100644 (file)
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* The linker command line option --print-map-locals can be used to include
+  local symbols in a linker map.  (ELF targets only).
+
 * For most ELF based targets, if the --enable-linker-version option is used
   then the version of the linker will be inserted as a string into the .comment
   section.
diff --git a/ld/ld.h b/ld/ld.h
index 05649ff61b8e2a165cefdb7d1ad21e57851a7799..1882a2820202200d4d371bb90194f5473f4f86f3 100644 (file)
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -297,6 +297,9 @@ typedef struct
   /* If set, print discarded sections in map file output.  */
   bool print_map_discarded;
 
+  /* If set, print local symbols in map file output.  */
+  bool print_map_locals;
+
   /* If set, emit the names and types of statically-linked variables
      into the CTF.  */
   bool ctf_variables;
index 1ea6874cbb09a905196406fc478389f686289777..012eec2e809d3e727d34c6d20da29a161e5d090a 100644 (file)
@@ -870,6 +870,16 @@ is 0x1, and @file{bar.o}, whose 0xc0010001 property value is 0x1.
 Print (or do not print) the list of discarded and garbage collected sections
 in the link map.  Enabled by default.
 
+@kindex --print-map-locals
+@kindex --no-print-map-locals
+@item --print-map-locals
+@itemx --no-print-map-locals
+Print (or do not print) local symbols in the link map.  Local symbols
+will have the text @samp{(local)} printed before their name, and will
+be listed after all of the global symbols in a given section.
+Temporary local symbols (typically those that start with @samp{.L})
+will not be included in the output.  Disabled by default.
+
 @kindex -n
 @cindex read-only text
 @cindex NMAGIC
index aa01c81e661e4ccf8693ea0c21fd394a5ba12610..a9c4a4d5bd7010e5ee5d6afa900a7acd87a15cef 100644 (file)
@@ -2296,13 +2296,15 @@ lang_map (void)
            {
              if (! dis_header_printed)
                {
-                 fprintf (config.map_file, _("\nDiscarded input sections\n\n"));
+                 minfo (_("\nDiscarded input sections\n\n"));
                  dis_header_printed = true;
                }
 
              print_input_section (s, true);
            }
     }
+  if (config.print_map_discarded && ! dis_header_printed)
+    minfo (_("\nThere are no discarded input sections\n"));
 
   minfo (_("\nMemory Configuration\n\n"));
   fprintf (config.map_file, "%-16s %-18s %-18s %s\n",
@@ -2330,7 +2332,7 @@ lang_map (void)
       print_nl ();
     }
 
-  fprintf (config.map_file, _("\nLinker script and memory map\n\n"));
+  minfo (_("\nLinker script and memory map\n\n"));
 
   if (!link_info.reduce_memory_overheads)
     {
@@ -4797,6 +4799,50 @@ print_all_symbols (asection *sec)
   obstack_free (&map_obstack, entries);
 }
 
+/* Returns TRUE if SYM is a symbol suitable for printing
+   in a linker map as a local symbol.  */
+
+static bool
+ld_is_local_symbol (asymbol * sym)
+{
+  const char * name = bfd_asymbol_name (sym);
+
+  if (name == NULL || *name == 0)
+    return false;
+
+  if (strcmp (name, "(null)") == 0)
+    return false;
+
+  /* Skip .Lxxx and such like.  */
+  if (bfd_is_local_label (link_info.output_bfd, sym))
+    return false;
+
+  /* FIXME: This is intended to skip ARM mapping symbols,
+     which for some reason are not excluded by bfd_is_local_label,
+     but maybe it is wrong for other architectures.
+     It would be better to fix bfd_is_local_label.  */  
+  if (*name == '$')
+    return false;
+
+  /* Some local symbols, eg _GLOBAL_OFFSET_TABLE_, are present
+     in the hash table, so do not print duplicates here.  */
+  struct bfd_link_hash_entry * h;
+  h = bfd_link_hash_lookup (link_info.hash, name, false /* create */, 
+                           false /* copy */, true /* follow */);
+  if (h == NULL)
+    return true;
+  
+  /* Symbols from the plugin owned BFD will not get their own
+     iteration of this function, but can be on the link_info
+     list.  So include them here.  */
+  if (h->u.def.section->owner != NULL
+      && ((bfd_get_file_flags (h->u.def.section->owner) & (BFD_LINKER_CREATED | BFD_PLUGIN))
+         == (BFD_LINKER_CREATED | BFD_PLUGIN)))
+    return true;
+
+  return false;
+}
+
 /* Print information about an input section to the map file.  */
 
 static void
@@ -4852,6 +4898,44 @@ print_input_section (asection *i, bool is_discarded)
         later overlay is shorter than an earier one.  */
       if (addr + TO_ADDR (size) > print_dot)
        print_dot = addr + TO_ADDR (size);
+
+      if (config.print_map_locals)
+       {
+         long  storage_needed;
+
+         /* FIXME: It would be better to cache this table, rather
+            than recreating it for each output section.  */
+         /* FIXME: This call is not working for non-ELF based targets.
+            Find out why.  */
+         storage_needed = bfd_get_symtab_upper_bound (link_info.output_bfd);
+         if (storage_needed > 0)
+           {
+             asymbol **  symbol_table;
+             long        number_of_symbols;
+             long        j;
+
+             symbol_table = xmalloc (storage_needed);
+             number_of_symbols = bfd_canonicalize_symtab (link_info.output_bfd, symbol_table);
+
+             for (j = 0; j < number_of_symbols; j++)
+               {
+                 asymbol *     sym = symbol_table[j];
+                 bfd_vma       sym_addr = sym->value + i->output_section->vma;
+                 
+                 if (sym->section == i->output_section
+                     && (sym->flags & BSF_LOCAL) != 0
+                     && sym_addr >= addr
+                     && sym_addr < print_dot
+                     && ld_is_local_symbol (sym))
+                   {
+                     print_spaces (SECTION_NAME_MAP_LENGTH);
+                     minfo ("0x%V        (local) %s\n", sym_addr, bfd_asymbol_name (sym));
+                   }
+               }
+
+             free (symbol_table);
+           }
+       }
     }
 }
 
index 48d323d0265fc15aff98df0413f57e3f54729607..be942ec432733f9f7a86b260fe87ee370f429ad8 100644 (file)
@@ -160,6 +160,8 @@ enum option_values
   OPTION_FORCE_GROUP_ALLOCATION,
   OPTION_PRINT_MAP_DISCARDED,
   OPTION_NO_PRINT_MAP_DISCARDED,
+  OPTION_PRINT_MAP_LOCALS,
+  OPTION_NO_PRINT_MAP_LOCALS,
   OPTION_NON_CONTIGUOUS_REGIONS,
   OPTION_NON_CONTIGUOUS_REGIONS_WARNINGS,
   OPTION_DEPENDENCY_FILE,
index 7dc2228a833a2f6d2f2d744114c7e2c484124607..6090921bda434575fa037b37afd5d3f83a9339a1 100644 (file)
@@ -605,6 +605,12 @@ static const struct ld_option ld_options[] =
   { {"no-print-map-discarded", no_argument, NULL, OPTION_NO_PRINT_MAP_DISCARDED},
     '\0', NULL, N_("Do not show discarded sections in map file output"),
     TWO_DASHES },
+  { {"print-map-locals", no_argument, NULL, OPTION_PRINT_MAP_LOCALS},
+    '\0', NULL, N_("Show local symbols in map file output"),
+    TWO_DASHES },
+  { {"no-print-map-locals", no_argument, NULL, OPTION_NO_PRINT_MAP_LOCALS},
+    '\0', NULL, N_("Do not show local symbols in map file output (default)"),
+    TWO_DASHES },
   { {"ctf-variables", no_argument, NULL, OPTION_CTF_VARIABLES},
     '\0', NULL, N_("Emit names and types of static variables in CTF"),
     TWO_DASHES },
@@ -1748,6 +1754,14 @@ parse_args (unsigned argc, char **argv)
          config.print_map_discarded = true;
          break;
 
+       case OPTION_NO_PRINT_MAP_LOCALS:
+         config.print_map_locals = false;
+         break;
+
+       case OPTION_PRINT_MAP_LOCALS:
+         config.print_map_locals = true;
+         break;
+
        case OPTION_DEPENDENCY_FILE:
          config.dependency_file = optarg;
          break;
index 0eeca10fdd88174c0baff6ca466142c7c30bc725..fbea9064265f7ff295fd44e1bd891dddaf022d25 100644 (file)
@@ -120,3 +120,30 @@ if {[regexp_diff \
 } else {
     pass $testname
 }
+
+if { [is_elf_format] } {
+    set testname "map with locals"
+
+    if {![ld_link $ld tmpdir/map-address \
+             "$LDFLAGS -T $srcdir/$subdir/map-address.t \
+             $IMAGE_BASE tmpdir/map-address.o \
+             -Map=tmpdir/map-locals.map --print-map-locals"]} {
+       fail $testname
+       return
+    }
+
+    if [is_remote host] then {
+       remote_upload host "tmpdir/map-locals.map"
+    }
+
+    # Some ELF targets do not preserve their local symbols.
+    setup_xfail "d30v-*-*" "dlx-*-*" "pj-*-*" "s12z-*-*" "xgate-*-*"
+    
+    if {[regexp_diff \
+            "tmpdir/map-locals.map" \
+            "$srcdir/$subdir/map-locals.d"]} {
+       fail $testname
+    } else {
+       pass $testname
+    }
+}
diff --git a/ld/testsuite/ld-scripts/map-locals.d b/ld/testsuite/ld-scripts/map-locals.d
new file mode 100644 (file)
index 0000000..f3137f1
--- /dev/null
@@ -0,0 +1,5 @@
+#...
+Linker script and memory map
+#...
+.*\(local\)[   ]+local_sym
+#pass
index e221ca3c0b37a18b6643717d3e9003e409621bfb..7cd1677bc85a99b59de20513c333d86f1a77e6ea 100644 (file)
@@ -1 +1,2 @@
+local_sym:
        .space  16