Hello, I’ve met a problem about how to merge relocation sections by using linker script in lld.
The story was I want to link C++ relocatable object files into one giant object file in partial linking (-r
) and use linker script to reorder some sections like .text.hot .text.cold .text.whatever ...
. The output seemed failed for there were a huge amount of independent .rela.text.xxx
sections, so I changed my linker script to merge .rela.text.xxx
sections into .rela.text
section, but still failed.
Snippets
It seems that lld can not merge .rela.text
section? The linker script likes this.
SECTIONS
{
/* Output sections : { Input sections } // Simplified like this. */
.text : { *(.text.*Z*) }
.rela.text : { *(.rela.text.*Z*) }
/DISCARD/ : { *(.group) }
}
Here is demo code.
// test.cpp
#include "edge.h"
Vertex g_v(11);
Edge g_e(2, 1, 10);
int main()
{
printf("main()~\n");
Edge e = g_e;
return 0;
}
// edge.cpp
#include "edge.h"
int Edge::cnt = 0;
Edge::Edge(int v_, int w_, double weight_) : v(v_), w(w_), weight(weight_) {
cnt++;
printf("Edge cnt=%d, defualt ctor.\n", cnt);
}
Edge::Edge(const Edge& e) {
cnt++;
printf("Edge cnt=%d, copy ctor.\n", cnt);
v = e.v; w = e.w;
weight = e.weight;
}
// edge.h
#include"stdio.h"
class Vertex {
public:
Vertex() = default;
Vertex(int i) : v(i) {}
~Vertex() { printf("Vertex dtor.\n"); }
private:
int v;
};
class Edge {
public:
Edge(int v_, int w_, double weight_);
Edge(const Edge& e);
~Edge() {
printf("Edge cnt=%d, dtor.\n", cnt);
cnt--;
}
private:
Vertex v, w;
double weight;
static int cnt;
};
Here is my compile and link commands. And I have tried in clang15.04 and clang17.0 on x86-64 machine.
clang++ test.cpp -c -O2
clang++ edge.cpp -c -O2
ld.lld edge.o test.o -T myscript.ld -r -o lld-T.o
ld.lld edge.o test.o -r -o lld.o
Here is readelf info, it worked fot .text
section mergence, but not .rela.text
section.
# lld.o
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 0000000000000000 000040 0000d8 00 AX 0 0 16
[ 2] .rela.text RELA 0000000000000000 000320 0001b0 18 I 21 1 8
...
[10] .text._ZN6VertexD2Ev PROGBITS 0000000000000000 000260 00000c 00 AXG 0 0 16
[11] .rela.text._ZN6VertexD2Ev RELA 0000000000000000 0005e0 000030 18 IG 21 10 8
[12] .group GROUP 0000000000000000 000610 00000c 04 21 31 4
[13] .text._ZN4EdgeD2Ev PROGBITS 0000000000000000 000270 000032 00 AXG 0 0 16
[14] .rela.text._ZN4EdgeD2Ev RELA 0000000000000000 000620 000090 18 IG 21 13 8
..
# lld-T.o
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 0000000000000000 000040 000128 00 AXG 0 0 16
[ 2] .rela.text RELA 0000000000000000 000330 0001b0 18 I 17 1 8
...
[ 9] .rela.text._ZN6VertexD2Ev RELA 0000000000000000 0005e8 000030 18 IG 17 1 8
[10] .rela.text._ZN4EdgeD2Ev RELA 0000000000000000 000618 000090 18 IG 17 1 8
Myself Investigation
I found the code in ELF/LinkerScript.cpp
as below, it seems that here let the merging of relocation section abort. The comment says that should be ignore for --emit-relocs
, but I don’t use the option. Is this a bug?
// For --emit-relocs we have to ignore entries like
// .rela.dyn : { *(.rela.data) }
// which are common because they are in the default bfd script.
// We do not ignore SHT_REL[A] linker-synthesized sections here because
// want to support scripts that do custom layout for them.
if (isa<InputSection>(sec) &&
cast<InputSection>(sec)->getRelocatedSection())
continue;