[lld] [lld][WebAssembly] Add new __rodata_end symbol (PR #172102)

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 12 15:50:10 PST 2025


https://github.com/sbc100 updated https://github.com/llvm/llvm-project/pull/172102

>From c5fa5e43e9d202f7355f27caebf1485c10fc80d5 Mon Sep 17 00:00:00 2001
From: Sam Clegg <sbc at chromium.org>
Date: Fri, 12 Dec 2025 14:59:01 -0800
Subject: [PATCH] [lld][WebAssembly] Add new __rodata_start/__rodata_end
 symbols

This is similar to etext/_etext in the ELF linker.  Its useful in
emscripten to know where the RO data data ends and the data begins (even
though the Wasm format itself has no concept of RO data).

See https://github.com/emscripten-core/emscripten/discussions/25939#discussioncomment-15243731
---
 lld/test/wasm/export-all.s             | 20 +++++++++++++-------
 lld/test/wasm/mutable-global-exports.s | 22 ++++++++++++++--------
 lld/wasm/Config.h                      |  5 +++++
 lld/wasm/Driver.cpp                    |  5 ++++-
 lld/wasm/Writer.cpp                    |  7 +++++++
 5 files changed, 43 insertions(+), 16 deletions(-)

diff --git a/lld/test/wasm/export-all.s b/lld/test/wasm/export-all.s
index 617dcc4a54d8b..8f4dfc8e2ca7e 100644
--- a/lld/test/wasm/export-all.s
+++ b/lld/test/wasm/export-all.s
@@ -34,24 +34,30 @@ foo:
 # CHECK-NEXT:       - Name:            __data_end
 # CHECK-NEXT:         Kind:            GLOBAL
 # CHECK-NEXT:         Index:           2
-# CHECK-NEXT:       - Name:            __stack_low
+# CHECK-NEXT:       - Name:            __rodata_start
 # CHECK-NEXT:         Kind:            GLOBAL
 # CHECK-NEXT:         Index:           3
-# CHECK-NEXT:       - Name:            __stack_high
+# CHECK-NEXT:       - Name:            __rodata_end
 # CHECK-NEXT:         Kind:            GLOBAL
 # CHECK-NEXT:         Index:           4
-# CHECK-NEXT:       - Name:            __global_base
+# CHECK-NEXT:       - Name:            __stack_low
 # CHECK-NEXT:         Kind:            GLOBAL
 # CHECK-NEXT:         Index:           5
-# CHECK-NEXT:       - Name:            __heap_base
+# CHECK-NEXT:       - Name:            __stack_high
 # CHECK-NEXT:         Kind:            GLOBAL
 # CHECK-NEXT:         Index:           6
-# CHECK-NEXT:       - Name:            __heap_end
+# CHECK-NEXT:       - Name:            __global_base
 # CHECK-NEXT:         Kind:            GLOBAL
 # CHECK-NEXT:         Index:           7
-# CHECK-NEXT:       - Name:            __memory_base
+# CHECK-NEXT:       - Name:            __heap_base
 # CHECK-NEXT:         Kind:            GLOBAL
 # CHECK-NEXT:         Index:           8
-# CHECK-NEXT:       - Name:            __table_base
+# CHECK-NEXT:       - Name:            __heap_end
 # CHECK-NEXT:         Kind:            GLOBAL
 # CHECK-NEXT:         Index:           9
+# CHECK-NEXT:       - Name:            __memory_base
+# CHECK-NEXT:         Kind:            GLOBAL
+# CHECK-NEXT:         Index:           10
+# CHECK-NEXT:       - Name:            __table_base
+# CHECK-NEXT:         Kind:            GLOBAL
+# CHECK-NEXT:         Index:           11
diff --git a/lld/test/wasm/mutable-global-exports.s b/lld/test/wasm/mutable-global-exports.s
index 1c10e92083b5c..1ff25f6c3a9c1 100644
--- a/lld/test/wasm/mutable-global-exports.s
+++ b/lld/test/wasm/mutable-global-exports.s
@@ -91,30 +91,36 @@ _start:
 # CHECK-ALL-NEXT:      - Name:            __data_end
 # CHECK-ALL-NEXT:        Kind:            GLOBAL
 # CHECK-ALL-NEXT:        Index:           4
-# CHECK-ALL-NEXT:      - Name:            __stack_low
+# CHECK-ALL-NEXT:      - Name:            __rodata_start
 # CHECK-ALL-NEXT:        Kind:            GLOBAL
 # CHECK-ALL-NEXT:        Index:           5
-# CHECK-ALL-NEXT:      - Name:            __stack_high
+# CHECK-ALL-NEXT:      - Name:            __rodata_end
 # CHECK-ALL-NEXT:        Kind:            GLOBAL
 # CHECK-ALL-NEXT:        Index:           6
-# CHECK-ALL-NEXT:      - Name:            __global_base
+# CHECK-ALL-NEXT:      - Name:            __stack_low
 # CHECK-ALL-NEXT:        Kind:            GLOBAL
 # CHECK-ALL-NEXT:        Index:           7
-# CHECK-ALL-NEXT:      - Name:            __heap_base
+# CHECK-ALL-NEXT:      - Name:            __stack_high
 # CHECK-ALL-NEXT:        Kind:            GLOBAL
 # CHECK-ALL-NEXT:        Index:           8
-# CHECK-ALL-NEXT:      - Name:            __heap_end
+# CHECK-ALL-NEXT:      - Name:            __global_base
 # CHECK-ALL-NEXT:        Kind:            GLOBAL
 # CHECK-ALL-NEXT:        Index:           9
-# CHECK-ALL-NEXT:      - Name:            __memory_base
+# CHECK-ALL-NEXT:      - Name:            __heap_base
 # CHECK-ALL-NEXT:        Kind:            GLOBAL
 # CHECK-ALL-NEXT:        Index:           10
-# CHECK-ALL-NEXT:      - Name:            __table_base
+# CHECK-ALL-NEXT:      - Name:            __heap_end
 # CHECK-ALL-NEXT:        Kind:            GLOBAL
 # CHECK-ALL-NEXT:        Index:           11
-# CHECK-ALL-NEXT:      - Name:            __wasm_first_page_end
+# CHECK-ALL-NEXT:      - Name:            __memory_base
 # CHECK-ALL-NEXT:        Kind:            GLOBAL
 # CHECK-ALL-NEXT:        Index:           12
+# CHECK-ALL-NEXT:      - Name:            __table_base
+# CHECK-ALL-NEXT:        Kind:            GLOBAL
+# CHECK-ALL-NEXT:        Index:           13
+# CHECK-ALL-NEXT:      - Name:            __wasm_first_page_end
+# CHECK-ALL-NEXT:        Kind:            GLOBAL
+# CHECK-ALL-NEXT:        Index:           14
 # CHECK-ALL-NEXT:  - Type:            CODE
 
 # CHECK-ALL:         Name:            target_features
diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h
index 9d903e0c799db..94c3b8c82efd6 100644
--- a/lld/wasm/Config.h
+++ b/lld/wasm/Config.h
@@ -173,6 +173,11 @@ struct Ctx {
     // Symbol whose value is the alignment of the TLS block.
     GlobalSymbol *tlsAlign;
 
+    // __rodata_start/__rodata_end
+    // Symbols marking the start/end of readonly data
+    DefinedData *rodataStart;
+    DefinedData *rodataEnd;
+
     // __data_end
     // Symbol marking the end of the data and bss.
     DefinedData *dataEnd;
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index 97e50783985a8..378e2d019b83c 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -988,8 +988,11 @@ static void createOptionalSymbols() {
 
   ctx.sym.dsoHandle = symtab->addOptionalDataSymbol("__dso_handle");
 
-  if (!ctx.arg.shared)
+  if (!ctx.arg.shared) {
     ctx.sym.dataEnd = symtab->addOptionalDataSymbol("__data_end");
+    ctx.sym.rodataStart = symtab->addOptionalDataSymbol("__rodata_start");
+    ctx.sym.rodataEnd = symtab->addOptionalDataSymbol("__rodata_end");
+  }
 
   if (!ctx.isPic) {
     ctx.sym.stackLow = symtab->addOptionalDataSymbol("__stack_low");
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 9a5b56fc52e2f..4389d002c4da8 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -401,7 +401,14 @@ void Writer::layoutMemory() {
       }
     }
 
+    if (ctx.sym.rodataStart && seg->name.starts_with(".rodata") && !ctx.sym.rodataStart->getVA())
+      ctx.sym.rodataStart->setVA(memoryPtr);
+
     memoryPtr += seg->size;
+
+    // Might get set more than once if segment merging is not enabled.
+    if (ctx.sym.rodataEnd && seg->name.starts_with(".rodata"))
+      ctx.sym.rodataEnd->setVA(memoryPtr);
   }
 
   // Make space for the memory initialization flag



More information about the llvm-commits mailing list