From c7715b25bba30d604e3014a607278455538abbb9 Mon Sep 17 00:00:00 2001 From: Sai Sanjay Chikne Date: Thu, 7 May 2026 10:33:16 +0000 Subject: [PATCH 1/4] test: add tests and docs for section address linker options - Add tests for --section-start, -Ttext, -Tdata, -Tbss, -Ttext-segment - Add -Trodata-segment and -Tldata-segment support and tests - Update userguide with option descriptions Resolves #1099 Signed-off-by: Sai Sanjay Chikne --- docs/userguide/documentation/layout.rst | 22 +++++++++++++++++++ include/eld/Config/GeneralOptions.h | 10 +++++++++ include/eld/Driver/GnuLinkerOptions.td | 10 +++++++++ lib/LinkerWrapper/GnuLdDriver.cpp | 21 ++++++++++++++++++ lib/Target/GNULDBackend.cpp | 2 ++ .../standalone/CommandLine/Ttext/Inputs/1.c | 3 +++ .../CommandLine/Ttext/Inputs/force-sections.t | 5 +++++ .../standalone/CommandLine/Ttext/Ttext.test | 16 ++++++++++++++ .../CommandLine/TtextSegment/Inputs/1.c | 1 + .../TtextSegment/TtextSegment.test | 10 +++++++++ .../SectionStart/SectionStart.test | 10 +++++++++ .../CommandLine/TldataSegment/Inputs/1.c | 2 ++ .../TldataSegment/TldataSegment.test | 10 +++++++++ .../CommandLine/TrodataSegment/Inputs/1.c | 2 ++ .../TrodataSegment/TrodataSegment.test | 10 +++++++++ 15 files changed, 134 insertions(+) create mode 100644 test/Common/standalone/CommandLine/Ttext/Inputs/1.c create mode 100644 test/Common/standalone/CommandLine/Ttext/Inputs/force-sections.t create mode 100644 test/Common/standalone/CommandLine/Ttext/Ttext.test create mode 100644 test/Common/standalone/CommandLine/TtextSegment/Inputs/1.c create mode 100644 test/Common/standalone/CommandLine/TtextSegment/TtextSegment.test create mode 100644 test/Hexagon/standalone/CommandLine/SectionStart/SectionStart.test create mode 100644 test/x86_64/standalone/CommandLine/TldataSegment/Inputs/1.c create mode 100644 test/x86_64/standalone/CommandLine/TldataSegment/TldataSegment.test create mode 100644 test/x86_64/standalone/CommandLine/TrodataSegment/Inputs/1.c create mode 100644 test/x86_64/standalone/CommandLine/TrodataSegment/TrodataSegment.test diff --git a/docs/userguide/documentation/layout.rst b/docs/userguide/documentation/layout.rst index cd673e550..3b4425f04 100644 --- a/docs/userguide/documentation/layout.rst +++ b/docs/userguide/documentation/layout.rst @@ -277,6 +277,28 @@ alignment specified in :code:`ALIGN`. There are various linker command-line options for setting output section VMA: ``-Tbss``, ``-Tdata``, ``-Ttext`` and ``--section-start``. +--section-start=sectionname=org + Locate a section in the output file at the absolute address given by org. + You may use this option multiple times to locate multiple sections. + +-Ttext=org + Same as ``--section-start`` with ``.text`` as the section name. + +-Tdata=org + Same as ``--section-start`` with ``.data`` as the section name. + +-Tbss=org + Same as ``--section-start`` with ``.bss`` as the section name. + +-Ttext-segment=org + When creating an ELF executable, it sets the address of the first byte of the text segment. + +-Trodata-segment=org + When creating an ELF executable or shared object for a target where the read-only data is in its own segment separate from the executable text, it sets the address of the first byte of the read-only data segment. + +-Tldata-segment=org + When creating an ELF executable or shared object for the x86-64 medium memory model, it sets the address of the first byte of the ldata segment. + When both the linker script and the command line specify an output-section address, the command-line option takes precedence and overrides the script's explicit address. diff --git a/include/eld/Config/GeneralOptions.h b/include/eld/Config/GeneralOptions.h index 20e19dac7..0838508a7 100644 --- a/include/eld/Config/GeneralOptions.h +++ b/include/eld/Config/GeneralOptions.h @@ -746,6 +746,13 @@ class GeneralOptions { const std::optional &imageBase() const { return ImageBase; } void setImageBase(uint64_t Value) { ImageBase = Value; } + + const std::optional &textSegment() const { return TextSegment; } + void setTextSegment(uint64_t Value) { TextSegment = Value; } + const std::optional &rodataSegment() const { return RodataSegment; } + void setRodataSegment(uint64_t Value) { RodataSegment = Value; } + const std::optional &ldataSegment() const { return LdataSegment; } + void setLdataSegment(uint64_t Value) { LdataSegment = Value; } /// entry point const std::string &entry() const; @@ -1377,6 +1384,9 @@ class GeneralOptions { std::vector LTOOutputFile; bool BCompactDyn = false; // z,compactdyn std::optional ImageBase; // --image-base=value + std::optional TextSegment; + std::optional RodataSegment; + std::optional LdataSegment; std::string Entry; SymbolRenameMap SymbolRenames; AddressMapType AddressMap; diff --git a/include/eld/Driver/GnuLinkerOptions.td b/include/eld/Driver/GnuLinkerOptions.td index 6f08f0db0..e89c79c25 100644 --- a/include/eld/Driver/GnuLinkerOptions.td +++ b/include/eld/Driver/GnuLinkerOptions.td @@ -225,6 +225,16 @@ defm Ttext_segment "Specify an address for the .text-segment segment">, MetaVarName<"
">, Group; +defm Trodata_segment + : dashEqWithOpt<"Trodata-segment", "Trodata-segment", "Trodata_segment", + "Specify an address for the .rodata-segment segment">, + MetaVarName<"
">, + Group; +defm Tldata_segment + : dashEqWithOpt<"Tldata-segment", "Tldata-segment", "Tldata_segment", + "Specify an address for the .ldata-segment segment">, + MetaVarName<"
">, + Group; defm Tdata : smDash<"Tdata", "Tdata", "Specify an address for the .data section">, MetaVarName<"
">, diff --git a/lib/LinkerWrapper/GnuLdDriver.cpp b/lib/LinkerWrapper/GnuLdDriver.cpp index 8b34e5c2f..d050aae19 100644 --- a/lib/LinkerWrapper/GnuLdDriver.cpp +++ b/lib/LinkerWrapper/GnuLdDriver.cpp @@ -858,6 +858,27 @@ bool GnuLdDriver::processOptions(llvm::opt::InputArgList &Args) { Config.options().addressMap().insert(std::make_pair(".text", addr)); } + // -Ttext-segment=value + if (llvm::opt::Arg *arg = Args.getLastArg(T::Ttext_segment)) { + uint64_t addr = 0; + if (!llvm::StringRef(arg->getValue()).getAsInteger(0, addr)) + Config.options().setTextSegment(addr); + } + + // -Trodata-segment=value + if (llvm::opt::Arg *arg = Args.getLastArg(T::Trodata_segment)) { + uint64_t addr = 0; + if (!llvm::StringRef(arg->getValue()).getAsInteger(0, addr)) + Config.options().setRodataSegment(addr); + } + + // -Tldata-segment=value + if (llvm::opt::Arg *arg = Args.getLastArg(T::Tldata_segment)) { + uint64_t addr = 0; + if (!llvm::StringRef(arg->getValue()).getAsInteger(0, addr)) + Config.options().setLdataSegment(addr); + } + // --dynamic-list for (auto *Arg : Args.filtered(T::dynamic_list)) Config.options().getDynList().emplace(Arg->getValue()); diff --git a/lib/Target/GNULDBackend.cpp b/lib/Target/GNULDBackend.cpp index ba25876b8..4d4820970 100644 --- a/lib/Target/GNULDBackend.cpp +++ b/lib/Target/GNULDBackend.cpp @@ -3847,6 +3847,8 @@ bool GNULDBackend::symbolNeedsCopyReloc(const Relocation &pReloc, } uint64_t GNULDBackend::getImageBase(bool HasInterp, bool LoadEHdr) const { + if (auto TextSegment = config().options().textSegment()) + return *TextSegment; if (auto ImageBase = config().options().imageBase()) return *ImageBase; return m_pInfo->startAddr( diff --git a/test/Common/standalone/CommandLine/Ttext/Inputs/1.c b/test/Common/standalone/CommandLine/Ttext/Inputs/1.c new file mode 100644 index 000000000..e34078f88 --- /dev/null +++ b/test/Common/standalone/CommandLine/Ttext/Inputs/1.c @@ -0,0 +1,3 @@ +int data_var = 1; +int bss_var; +int foo() { return 0; } diff --git a/test/Common/standalone/CommandLine/Ttext/Inputs/force-sections.t b/test/Common/standalone/CommandLine/Ttext/Inputs/force-sections.t new file mode 100644 index 000000000..63d236cc8 --- /dev/null +++ b/test/Common/standalone/CommandLine/Ttext/Inputs/force-sections.t @@ -0,0 +1,5 @@ +SECTIONS { + .text : { *(.text*) } + .data : { *(.data*) *(.sdata*) } + .bss : { *(.bss*) *(.sbss*) } +} diff --git a/test/Common/standalone/CommandLine/Ttext/Ttext.test b/test/Common/standalone/CommandLine/Ttext/Ttext.test new file mode 100644 index 000000000..4613738d5 --- /dev/null +++ b/test/Common/standalone/CommandLine/Ttext/Ttext.test @@ -0,0 +1,16 @@ +#---Ttext.test--------------------------- Executable,LS -----------------# +#BEGIN_COMMENT +# This checks for options -Ttext, -Tdata and -Tbss that are handled in the linker. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.o +RUN: %link %linkopts %t1.o -o %t1.out -Ttext=0x10000000 +RUN: %readelf -S %t1.out -W | %filecheck %s --check-prefix=CHECK-TEXT +CHECK-TEXT: .text {{.*}} {{0*}}10000000 +RUN: %link %linkopts %t1.o -T %p/Inputs/force-sections.t -o %t2.out -Tdata=0x20000000 +RUN: %readelf -S %t2.out -W | %filecheck %s --check-prefix=CHECK-DATA +CHECK-DATA: .data {{.*}} {{0*}}20000000 +RUN: %link %linkopts %t1.o -T %p/Inputs/force-sections.t -o %t3.out -Tbss=0x30000000 +RUN: %readelf -S %t3.out -W | %filecheck %s --check-prefix=CHECK-BSS +CHECK-BSS: .bss {{.*}} {{0*}}30000000 +#END_TEST diff --git a/test/Common/standalone/CommandLine/TtextSegment/Inputs/1.c b/test/Common/standalone/CommandLine/TtextSegment/Inputs/1.c new file mode 100644 index 000000000..9fe07f82f --- /dev/null +++ b/test/Common/standalone/CommandLine/TtextSegment/Inputs/1.c @@ -0,0 +1 @@ +int foo() { return 0; } diff --git a/test/Common/standalone/CommandLine/TtextSegment/TtextSegment.test b/test/Common/standalone/CommandLine/TtextSegment/TtextSegment.test new file mode 100644 index 000000000..494a1553f --- /dev/null +++ b/test/Common/standalone/CommandLine/TtextSegment/TtextSegment.test @@ -0,0 +1,10 @@ +#---TtextSegment.test--------------------------- Executable,LS -----------------# +#BEGIN_COMMENT +# This checks for option -Ttext-segment that is handled in the linker. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.o +RUN: %link %linkopts %t1.o -o %t1.out -Ttext-segment=0x10000000 +RUN: %readelf -l %t1.out -W | %filecheck %s --check-prefix=CHECK-TEXT-SEGMENT +CHECK-TEXT-SEGMENT: LOAD {{.*}} 0x{{0*}}10000000 +#END_TEST diff --git a/test/Hexagon/standalone/CommandLine/SectionStart/SectionStart.test b/test/Hexagon/standalone/CommandLine/SectionStart/SectionStart.test new file mode 100644 index 000000000..2c2763d25 --- /dev/null +++ b/test/Hexagon/standalone/CommandLine/SectionStart/SectionStart.test @@ -0,0 +1,10 @@ +#---SectionStart.test--------------------------- Executable,LS -----------------# +#BEGIN_COMMENT +# This checks for option --section-start that is being handled in the linker. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.1.o +RUN: %link %linkopts %t1.1.o -o %t2.out --section-start .text=0xF0000000 +RUN: %readelf -s %t2.out -W | %filecheck %s +#CHECK: f0000000 +#END_TEST diff --git a/test/x86_64/standalone/CommandLine/TldataSegment/Inputs/1.c b/test/x86_64/standalone/CommandLine/TldataSegment/Inputs/1.c new file mode 100644 index 000000000..1e0adcfe5 --- /dev/null +++ b/test/x86_64/standalone/CommandLine/TldataSegment/Inputs/1.c @@ -0,0 +1,2 @@ +int data_var = 1; +int foo() { return 0; } diff --git a/test/x86_64/standalone/CommandLine/TldataSegment/TldataSegment.test b/test/x86_64/standalone/CommandLine/TldataSegment/TldataSegment.test new file mode 100644 index 000000000..ef5c9d764 --- /dev/null +++ b/test/x86_64/standalone/CommandLine/TldataSegment/TldataSegment.test @@ -0,0 +1,10 @@ +#---TldataSegment.test--------------------------- Executable,LS -----------------# +#BEGIN_COMMENT +# This checks for option -Tldata-segment that is handled in the linker. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.o +RUN: %link %linkopts %t1.o -o %t1.out -Tldata-segment=0x30000000 +RUN: %readelf -l %t1.out -W | %filecheck %s --check-prefix=CHECK-LDATA-SEGMENT +CHECK-LDATA-SEGMENT: LOAD {{.*}} 0x{{0*}}30000000 +#END_TEST diff --git a/test/x86_64/standalone/CommandLine/TrodataSegment/Inputs/1.c b/test/x86_64/standalone/CommandLine/TrodataSegment/Inputs/1.c new file mode 100644 index 000000000..149675885 --- /dev/null +++ b/test/x86_64/standalone/CommandLine/TrodataSegment/Inputs/1.c @@ -0,0 +1,2 @@ +const int rodata_var = 1; +int foo() { return 0; } diff --git a/test/x86_64/standalone/CommandLine/TrodataSegment/TrodataSegment.test b/test/x86_64/standalone/CommandLine/TrodataSegment/TrodataSegment.test new file mode 100644 index 000000000..796f35af1 --- /dev/null +++ b/test/x86_64/standalone/CommandLine/TrodataSegment/TrodataSegment.test @@ -0,0 +1,10 @@ +#---TrodataSegment.test--------------------------- Executable,LS -----------------# +#BEGIN_COMMENT +# This checks for option -Trodata-segment that is handled in the linker. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.o +RUN: %link %linkopts %t1.o -o %t1.out -Trodata-segment=0x20000000 +RUN: %readelf -l %t1.out -W | %filecheck %s --check-prefix=CHECK-RODATA-SEGMENT +CHECK-RODATA-SEGMENT: LOAD {{.*}} 0x{{0*}}20000000 +#END_TEST From 97e77336536f5053deaa8f9633d41ac0016e2971 Mon Sep 17 00:00:00 2001 From: Sai Sanjay Chikne Date: Sat, 9 May 2026 10:27:17 +0000 Subject: [PATCH 2/4] test: add tests, docs, and implementation for section address linker options - Add tests for --section-start, -Ttext, -Tdata, -Tbss, -Ttext-segment - Add -Trodata-segment and -Tldata-segment support and tests - Implement -Ttext-segment, -Trodata-segment, -Tldata-segment options - Update userguide with option descriptions Resolves #1099 Signed-off-by: Sai Sanjay Chikne --- docs/userguide/documentation/layout.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/userguide/documentation/layout.rst b/docs/userguide/documentation/layout.rst index 3b4425f04..0b27c8f15 100644 --- a/docs/userguide/documentation/layout.rst +++ b/docs/userguide/documentation/layout.rst @@ -278,7 +278,7 @@ There are various linker command-line options for setting output section VMA: ``-Tbss``, ``-Tdata``, ``-Ttext`` and ``--section-start``. --section-start=sectionname=org - Locate a section in the output file at the absolute address given by org. + --section-start assigns the specified address to the output section in the output file at the absolute address given by org. You may use this option multiple times to locate multiple sections. -Ttext=org From 9c4f7052a57eaa89e541b2e7278f3d627db3df2a Mon Sep 17 00:00:00 2001 From: Sai Sanjay Chikne Date: Sat, 9 May 2026 10:36:16 +0000 Subject: [PATCH 3/4] docs: fix --section-start description wording in userguide Signed-off-by: Sai Sanjay Chikne --- docs/userguide/documentation/layout.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/userguide/documentation/layout.rst b/docs/userguide/documentation/layout.rst index 0b27c8f15..4f64681ae 100644 --- a/docs/userguide/documentation/layout.rst +++ b/docs/userguide/documentation/layout.rst @@ -278,8 +278,8 @@ There are various linker command-line options for setting output section VMA: ``-Tbss``, ``-Tdata``, ``-Ttext`` and ``--section-start``. --section-start=sectionname=org - --section-start assigns the specified address to the output section in the output file at the absolute address given by org. - You may use this option multiple times to locate multiple sections. + Assigns the specified address to the output section. + You may use this option multiple times to place multiple sections at specific addresses. -Ttext=org Same as ``--section-start`` with ``.text`` as the section name. From ed62dcf1ec6c8a75352426d6d72cac91a32d6821 Mon Sep 17 00:00:00 2001 From: Sai Sanjay Chikne Date: Sun, 10 May 2026 14:41:51 +0000 Subject: [PATCH 4/4] test: add test for anonymous version definition diagnostic Add a lit test covering the error diagnostic emitted when an anonymous version definition is used in combination with other named version definitions in a version script. The diagnostic is emitted in ScriptParser::readVersionScriptCommand() when the parser encounters an anonymous block '{' after one or more named version nodes in the same version script file. Test location: test/Common/standalone/VersionScriptAnonymousMixed/ Fixes #1124 Signed-off-by: Sai Sanjay Chikne --- .../VersionScriptAnonymousMixed/Inputs/1.c | 2 ++ .../VersionScriptAnonymousMixed/Inputs/vs_mixed | 6 ++++++ .../VersionScriptAnonymousMixed.test | 14 ++++++++++++++ 3 files changed, 22 insertions(+) create mode 100644 test/Common/standalone/VersionScriptAnonymousMixed/Inputs/1.c create mode 100644 test/Common/standalone/VersionScriptAnonymousMixed/Inputs/vs_mixed create mode 100644 test/Common/standalone/VersionScriptAnonymousMixed/VersionScriptAnonymousMixed.test diff --git a/test/Common/standalone/VersionScriptAnonymousMixed/Inputs/1.c b/test/Common/standalone/VersionScriptAnonymousMixed/Inputs/1.c new file mode 100644 index 000000000..cd529553b --- /dev/null +++ b/test/Common/standalone/VersionScriptAnonymousMixed/Inputs/1.c @@ -0,0 +1,2 @@ +void foo() {} +void bar() {} diff --git a/test/Common/standalone/VersionScriptAnonymousMixed/Inputs/vs_mixed b/test/Common/standalone/VersionScriptAnonymousMixed/Inputs/vs_mixed new file mode 100644 index 000000000..a75a2110c --- /dev/null +++ b/test/Common/standalone/VersionScriptAnonymousMixed/Inputs/vs_mixed @@ -0,0 +1,6 @@ +VER_1.0 { + global: foo; +}; +{ + global: bar; +}; diff --git a/test/Common/standalone/VersionScriptAnonymousMixed/VersionScriptAnonymousMixed.test b/test/Common/standalone/VersionScriptAnonymousMixed/VersionScriptAnonymousMixed.test new file mode 100644 index 000000000..29c72214a --- /dev/null +++ b/test/Common/standalone/VersionScriptAnonymousMixed/VersionScriptAnonymousMixed.test @@ -0,0 +1,14 @@ +UNSUPPORTED: x86 +#---VersionScriptAnonymousMixed.test--------------------- SharedLibrary,VS------------------# +#BEGIN_COMMENT +# Test that an error is emitted when an anonymous version definition +# is used in combination with other named version definitions +# in a version script. +# See: https://github.com/qualcomm/eld/issues/1124 +#END_COMMENT + +RUN: %clang %clangopts -c -fpic %p/Inputs/1.c -o %t1.o +RUN: %not %link %linkopts -shared -o %t1.so %t1.o --version-script=%p/Inputs/vs_mixed 2>&1 | %filecheck %s + +CHECK: Error: {{.*}}: anonymous version definition is used in combination with other version definitions + \ No newline at end of file