Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions docs/userguide/documentation/layout.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Assigns the absolute address org to the named output section.
You may use this option multiple times to place multiple sections at specific addresses.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if you specify the --section-start with the same section name multiple times ? Can we add that to the documentation ?


-Ttext=org
Same as ``--section-start`` with ``.text`` as the section name.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if there is no .text section ?


-Tdata=org
Same as ``--section-start`` with ``.data`` as the section name.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as previous, what if there is no data section ?


-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.

Expand Down
10 changes: 10 additions & 0 deletions include/eld/Config/GeneralOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,13 @@ class GeneralOptions {
const std::optional<uint64_t> &imageBase() const { return ImageBase; }

void setImageBase(uint64_t Value) { ImageBase = Value; }

const std::optional<uint64_t> &textSegment() const { return TextSegment; }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the PR for adding tests and docs modifying functionality?

Copy link
Copy Markdown
Author

@sai18022001 sai18022001 May 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point.
Tests wouldn't pass without -Text-segment, -Trodata-segment and -Tldata-segment as it were not implemented previously
should i split them into 2 PR - one for tests/docs and one for implemetation ?
or you want to have a look at those implementations ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what @parth-07 is mentioning is the commit message says adding tests but now we are implementing support. The issue needs to be properly documented and also the commit message.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll update the commit message. Thanks for clarifying.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we convert these functions to use verbs, get/set.

I recommend using getTextSegmentAddress(), it would be very clear.

Also update the text map file so that an user inspecting the text map file can know what is going on.

void setTextSegment(uint64_t Value) { TextSegment = Value; }
const std::optional<uint64_t> &rodataSegment() const { return RodataSegment; }
void setRodataSegment(uint64_t Value) { RodataSegment = Value; }
const std::optional<uint64_t> &ldataSegment() const { return LdataSegment; }
void setLdataSegment(uint64_t Value) { LdataSegment = Value; }

/// entry point
const std::string &entry() const;
Expand Down Expand Up @@ -1377,6 +1384,9 @@ class GeneralOptions {
std::vector<std::string> LTOOutputFile;
bool BCompactDyn = false; // z,compactdyn
std::optional<uint64_t> ImageBase; // --image-base=value
std::optional<uint64_t> TextSegment;
std::optional<uint64_t> RodataSegment;
std::optional<uint64_t> LdataSegment;
std::string Entry;
SymbolRenameMap SymbolRenames;
AddressMapType AddressMap;
Expand Down
10 changes: 10 additions & 0 deletions include/eld/Driver/GnuLinkerOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,16 @@ defm Ttext_segment
"Specify an address for the .text-segment segment">,
MetaVarName<"<address>">,
Group<grp_scriptopts>;
defm Trodata_segment
: dashEqWithOpt<"Trodata-segment", "Trodata-segment", "Trodata_segment",
"Specify an address for the .rodata-segment segment">,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you reword this ? Is there anything like .rodata-segment ?

MetaVarName<"<address>">,
Group<grp_scriptopts>;
defm Tldata_segment
: dashEqWithOpt<"Tldata-segment", "Tldata-segment", "Tldata_segment",
"Specify an address for the .ldata-segment segment">,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is .ldata-segment ? Can you simplify this and reword ?

MetaVarName<"<address>">,
Group<grp_scriptopts>;
defm Tdata
: smDash<"Tdata", "Tdata", "Specify an address for the .data section">,
MetaVarName<"<address>">,
Expand Down
21 changes: 21 additions & 0 deletions lib/LinkerWrapper/GnuLdDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should report an error if the argument is incorrect for the new options added.

Config.options().setTextSegment(addr);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be useful to give a warning with linker scripts if the user used a linker script and users using this option.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also add a diagnostic if the value is not represented as a integer or does not fit the target address space.

For example using a 64bit address on a 32bit image.

}

// -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);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this handled in program layout ?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is currently parsed and stored but not yet handled in program layout. Would you like me to implement it in this PR or open a separate issue for it?

}

// -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);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this handled in program layout ?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is currently parsed and stored but not yet handled in program layout. Would you like me to implement it in this PR or open a separate issue for it?

}

// --dynamic-list
for (auto *Arg : Args.filtered(T::dynamic_list))
Config.options().getDynList().emplace(Arg->getValue());
Expand Down
2 changes: 2 additions & 0 deletions lib/Target/GNULDBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4060,6 +4060,8 @@ bool GNULDBackend::symbolNeedsCopyReloc(const Relocation &pReloc,
}

uint64_t GNULDBackend::getImageBase(bool HasInterp, bool LoadEHdr) const {
if (auto TextSegment = config().options().textSegment())
return *TextSegment;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does -Ttext-segment override linker script assignment ?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this, when both -Ttext-segment and a linker script address assignment are specified, the linker script takes precedence. Is this the expected behavior, or should -Ttext-segment always override the linker script ?

Copy link
Copy Markdown
Author

@sai18022001 sai18022001 May 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pinging on this - wanted to confirm the expected behavior before making any further changes to GNULDBackend.cpp.
Based on GNU ld behavior, the linker script takes precedence over -Ttext-segment when an explicit address is assigned in the script. The current implementation follows this behavior. Please let me know if a different behavior is expected for ELD.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for confirming. Please go ahead.

if (auto ImageBase = config().options().imageBase())
return *ImageBase;
return m_pInfo->startAddr(
Expand Down
3 changes: 3 additions & 0 deletions test/Common/standalone/CommandLine/Ttext/Inputs/1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
int data_var = 1;
int bss_var;
int foo() { return 0; }
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
SECTIONS {
.text : { *(.text*) }
.data : { *(.data*) *(.sdata*) }
.bss : { *(.bss*) *(.sbss*) }
}
16 changes: 16 additions & 0 deletions test/Common/standalone/CommandLine/Ttext/Ttext.test
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions test/Common/standalone/CommandLine/TtextSegment/Inputs/1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
int foo() { return 0; }
10 changes: 10 additions & 0 deletions test/Common/standalone/CommandLine/TtextSegment/TtextSegment.test
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions test/Hexagon/standalone/CommandLine/SectionStart/SectionStart.test
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this test hexagon specific?

Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions test/x86_64/standalone/CommandLine/TldataSegment/Inputs/1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
int data_var = 1;
int foo() { return 0; }
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions test/x86_64/standalone/CommandLine/TrodataSegment/Inputs/1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const int rodata_var = 1;
int foo() { return 0; }
Original file line number Diff line number Diff line change
@@ -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