This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 9bd1780df968d74404400cd152d5b9d1e9565b50
Author: Marco Casaroli <[email protected]>
AuthorDate: Mon Oct 19 10:13:28 2026 +0200

    tools/nxflat/ldnxflat: Place the sections without the linker script.
    
    ld -r keeps each member of a section group as a section of its own, and
    the NXFLAT linker scripts do not place it.  It stays at address zero, on
    top of .text or .data, and the sections that the script places after it
    move.  C++ puts inline functions and template instances in COMDAT
    groups, so many C++ modules have such sections.
    
    For example, the emutls control objects of a static thread_local member
    of a class template are in two groups.  ld put them at D-Space address 0
    and .bss at 0x10, so all three overlapped .data.  ldnxflat copied one
    over the other with no message.  exec() then failed with ENOENT: the
    loader read the name of the first import as "flat_abi_v2".
    
    Place the sections in ldnxflat: in the order of the section headers, each
    at its alignment, the data of D-Space before its .bss.  A relocatable ELF
    object gives symbols and relocations as offsets in their section, so
    nothing else changes.  The modules of apps/examples/nxflat convert to the
    same bytes as before.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 tools/nxflat/ldnxflat.c | 50 +++++++++++++++++++++++++++----------------------
 1 file changed, 28 insertions(+), 22 deletions(-)

diff --git a/tools/nxflat/ldnxflat.c b/tools/nxflat/ldnxflat.c
index 61d095d94d4..469d19faea0 100644
--- a/tools/nxflat/ldnxflat.c
+++ b/tools/nxflat/ldnxflat.c
@@ -306,9 +306,15 @@ static void read_elf(void)
  * Name: place_sections
  *
  * Description:
- *   Sort the allocated sections into the two segments and size them.  The
- *   linker script has placed each one within its segment already, both
- *   segments starting at zero -- hence -no-check-sections on the link.
+ *   Sort the allocated sections into the two segments and place them, in
+ *   the order of the section headers.  D-Space holds its data, then its
+ *   .bss.
+ *
+ *   The addresses that the linker script gave are not used.  ld -r keeps
+ *   each member of a section group (C++ puts inline functions and template
+ *   instances in COMDAT groups) as a section of its own, which the script
+ *   does not place:  it stays at address zero, on top of another section,
+ *   and moves the sections that follow it.
  *
  *   Executable is I-Space; everything else allocated is D-Space, read-only
  *   data included, because the model reaches that through the GOT.
@@ -319,10 +325,18 @@ static void read_elf(void)
  *
  ****************************************************************************/
 
+static uint32_t place_at(struct elf32_shdr_s *s, uint32_t addr)
+{
+  uint32_t align = s->sh_addralign > 1 ? s->sh_addralign : 1;
+
+  s->sh_addr = (addr + align - 1) & ~(align - 1);
+  return s->sh_addr + s->sh_size;
+}
+
 static void place_sections(void)
 {
   uint32_t dataend = 0;
-  uint32_t bssend  = 0;
+  uint32_t bssend;
   size_t i;
 
   g_segof = calloc(g_ehdr->e_shnum, sizeof(*g_segof));
@@ -334,7 +348,6 @@ static void place_sections(void)
   for (i = 1; i < g_ehdr->e_shnum; i++)
     {
       struct elf32_shdr_s *s = &g_shdr[i];
-      uint32_t end = s->sh_addr + s->sh_size;
 
       if ((s->sh_flags & SHF_ALLOC) == 0 ||
           strncmp(g_shstrtab + s->sh_name, ".ARM.exidx", 10) == 0 ||
@@ -354,33 +367,26 @@ static void place_sections(void)
 
       if ((s->sh_flags & SHF_EXECINSTR) != 0)
         {
-          g_segof[i] = SEG_TEXT;
-          if (end > g_text.size)
-            {
-              g_text.size = end;
-            }
+          g_segof[i]  = SEG_TEXT;
+          g_text.size = place_at(s, g_text.size);
         }
       else
         {
           g_segof[i] = SEG_DATA;
-
-          if (s->sh_type == SHT_NOBITS)
+          if (s->sh_type != SHT_NOBITS)
             {
-              if (end > bssend)
-                {
-                  bssend = end;
-                }
-            }
-          else if (end > dataend)
-            {
-              dataend = end;
+              dataend = place_at(s, dataend);
             }
         }
     }
 
-  if (bssend < dataend)
+  bssend = dataend;
+  for (i = 1; i < g_ehdr->e_shnum; i++)
     {
-      bssend = dataend;
+      if (g_segof[i] == SEG_DATA && g_shdr[i].sh_type == SHT_NOBITS)
+        {
+          bssend = place_at(&g_shdr[i], bssend);
+        }
     }
 
   g_data.size = dataend;

Reply via email to