2 changes: 2 additions & 0 deletions lld/ELF/Symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@ void replaceSymbol(Symbol *S, ArgT &&... Arg) {
if (S->Traced)
printTraceSymbol(S);
}

void warnUnorderableSymbol(const Symbol *Sym);
} // namespace elf

std::string toString(const elf::Symbol &B);
Expand Down
25 changes: 6 additions & 19 deletions lld/ELF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "Writer.h"
#include "AArch64ErrataFix.h"
#include "CallGraphSort.h"
#include "Config.h"
#include "Filesystem.h"
#include "LinkerScript.h"
Expand Down Expand Up @@ -1029,6 +1030,10 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B,
// Builds section order for handling --symbol-ordering-file.
static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
DenseMap<const InputSectionBase *, int> SectionOrder;
// Use the rarely used option -call-graph-ordering-file to sort sections.
if (!Config->CallGraphProfile.empty())
return computeCallGraphProfileOrder();

if (Config->SymbolOrderingFile.empty())
return SectionOrder;

Expand All @@ -1053,25 +1058,7 @@ static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
SymbolOrderEntry &Ent = It->second;
Ent.Present = true;

if (Config->WarnSymbolOrdering) {
auto *D = dyn_cast<Defined>(&Sym);
InputFile *File = Sym.File;
if (Sym.isUndefined())
warn(toString(File) +
": unable to order undefined symbol: " + Sym.getName());
else if (Sym.isShared())
warn(toString(File) +
": unable to order shared symbol: " + Sym.getName());
else if (D && !D->Section)
warn(toString(File) +
": unable to order absolute symbol: " + Sym.getName());
else if (D && isa<OutputSection>(D->Section))
warn(toString(File) +
": unable to order synthetic symbol: " + Sym.getName());
else if (D && !D->Section->Repl->Live)
warn(toString(File) +
": unable to order discarded symbol: " + Sym.getName());
}
warnUnorderableSymbol(&Sym);

if (auto *D = dyn_cast<Defined>(&Sym)) {
if (auto *Sec = dyn_cast_or_null<InputSectionBase>(D->Section)) {
Expand Down
71 changes: 71 additions & 0 deletions lld/test/ELF/cgprofile-bad-clusters.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# This test checks that CallGraphSort ignores edges that would form "bad"
# clusters.

# REQUIRES: x86

# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
# RUN: echo "A C 1" > %t.call_graph
# RUN: echo "E B 4" >> %t.call_graph
# RUN: echo "C D 2" >> %t.call_graph
# RUN: echo "B D 1" >> %t.call_graph
# RUN: echo "F G 6" >> %t.call_graph
# RUN: echo "G H 5" >> %t.call_graph
# RUN: echo "H I 4" >> %t.call_graph
# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2
# RUN: llvm-readobj -symbols %t2 | FileCheck %s

.section .text.A,"ax",@progbits
.globl A
A:
retq

.section .text.D,"ax",@progbits
D:
.fill 1000, 1, 0

.section .text.E,"ax",@progbits
E:
retq

.section .text.C,"ax",@progbits
C:
retq

.section .text.B,"ax",@progbits
B:
.fill 1000, 1, 0

.section .text.F,"ax",@progbits
F:
.fill (1024 * 1024) - 1, 1, 0

.section .text.G,"ax",@progbits
G:
retq

.section .text.H,"ax",@progbits
H:
retq

.section .text.I,"ax",@progbits
I:
.fill 13, 1, 0

# CHECK: Name: B
# CHECK-NEXT: Value: 0x201011
# CHECK: Name: C
# CHECK-NEXT: Value: 0x20100F
# CHECK: Name: D
# CHECK-NEXT: Value: 0x2013F9
# CHECK: Name: E
# CHECK-NEXT: Value: 0x201010
# CHECK: Name: F
# CHECK-NEXT: Value: 0x2017E1
# CHECK: Name: G
# CHECK-NEXT: Value: 0x3017E0
# CHECK: Name: H
# CHECK-NEXT: Value: 0x201000
# CHECK: Name: I
# CHECK-NEXT: Value: 0x201001
# CHECK: Name: A
# CHECK-NEXT: Value: 0x20100E
53 changes: 53 additions & 0 deletions lld/test/ELF/cgprofile-icf.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# REQUIRES: x86

# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t

# RUN: echo "A B 100" > %t.call_graph
# RUN: echo "A C 40" >> %t.call_graph
# RUN: echo "C D 61" >> %t.call_graph
# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t.out -icf=all
# RUN: llvm-readobj -symbols %t.out | FileCheck %s
# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2.out
# RUN: llvm-readobj -symbols %t2.out | FileCheck %s --check-prefix=NOICF

.section .text.D,"ax",@progbits
.globl D
D:
mov $60, %rax
retq

.section .text.C,"ax",@progbits
.globl C
C:
mov $60, %rax
retq

.section .text.B,"ax",@progbits
.globl B
B:
mov $2, %rax
retq

.section .text.A,"ax",@progbits
.globl A
A:
mov $42, %rax
retq

# CHECK: Name: A
# CHECK-NEXT: Value: 0x201000
# CHECK: Name: B
# CHECK-NEXT: Value: 0x201010
# CHECK: Name: C
# CHECK-NEXT: Value: 0x201008
# CHECK: Name: D
# CHECK-NEXT: Value: 0x201008

# NOICF: Name: A
# NOICF-NEXT: Value: 0x201000
# NOICF: Name: B
# NOICF-NEXT: Value: 0x201008
# NOICF: Name: C
# NOICF-NEXT: Value: 0x201010
# NOICF: Name: D
# NOICF-NEXT: Value: 0x201018
185 changes: 185 additions & 0 deletions lld/test/ELF/cgprofile-txt.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
# REQUIRES: x86

# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
# RUN: ld.lld -e A %t -o %t2
# RUN: llvm-readobj -symbols %t2 | FileCheck %s --check-prefix=NOSORT

# RUN: echo "A B 10" > %t.call_graph
# RUN: echo "A B 10" >> %t.call_graph
# RUN: echo "Aa B 80" >> %t.call_graph
# RUN: echo "A C 40" >> %t.call_graph
# RUN: echo "B C 30" >> %t.call_graph
# RUN: echo "C D 90" >> %t.call_graph
# RUN: echo "PP TS 100" >> %t.call_graph
# RUN: echo "_init2 _init 24567837" >> %t.call_graph
# RUN: echo "TS QC 9001" >> %t.call_graph
# RUN: echo "TooManyPreds0 TooManyPreds 10" >> %t.call_graph
# RUN: echo "TooManyPreds1 TooManyPreds 10" >> %t.call_graph
# RUN: echo "TooManyPreds2 TooManyPreds 10" >> %t.call_graph
# RUN: echo "TooManyPreds3 TooManyPreds 10" >> %t.call_graph
# RUN: echo "TooManyPreds4 TooManyPreds 10" >> %t.call_graph
# RUN: echo "TooManyPreds5 TooManyPreds 10" >> %t.call_graph
# RUN: echo "TooManyPreds6 TooManyPreds 10" >> %t.call_graph
# RUN: echo "TooManyPreds7 TooManyPreds 10" >> %t.call_graph
# RUN: echo "TooManyPreds8 TooManyPreds 10" >> %t.call_graph
# RUN: echo "TooManyPreds9 TooManyPreds 10" >> %t.call_graph
# RUN: echo "TooManyPreds10 TooManyPreds 11" >> %t.call_graph
# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2
# RUN: llvm-readobj -symbols %t2 | FileCheck %s

.section .text.D,"ax",@progbits
D:
retq

.section .text.C,"ax",@progbits
.globl C
C:
retq

.section .text.B,"ax",@progbits
.globl B
B:
retq

.section .text.A,"ax",@progbits
.globl A
A:
Aa:
retq

.section .ponies,"ax",@progbits,unique,1
.globl TS
TS:
retq

.section .ponies,"ax",@progbits,unique,2
.globl PP
PP:
retq

.section .other,"ax",@progbits,unique,1
.globl QC
QC:
retq

.section .other,"ax",@progbits,unique,2
.globl GB
GB:
retq

.section .init,"ax",@progbits,unique,1
.globl _init
_init:
retq

.section .init,"ax",@progbits,unique,2
.globl _init2
_init2:
retq

.section .text.TooManyPreds,"ax",@progbits
TooManyPreds:
retq
retq
retq
retq
retq
retq
retq
retq
retq
retq

.section .text.TooManyPreds0,"ax",@progbits
TooManyPreds0:
retq

.section .text.TooManyPreds1,"ax",@progbits
TooManyPreds1:
retq

.section .text.TooManyPreds2,"ax",@progbits
TooManyPreds2:
retq

.section .text.TooManyPreds3,"ax",@progbits
TooManyPreds3:
retq

.section .text.TooManyPreds4,"ax",@progbits
TooManyPreds4:
retq

.section .text.TooManyPreds5,"ax",@progbits
TooManyPreds5:
retq

.section .text.TooManyPreds6,"ax",@progbits
TooManyPreds6:
retq

.section .text.TooManyPreds7,"ax",@progbits
TooManyPreds7:
retq

.section .text.TooManyPreds8,"ax",@progbits
TooManyPreds8:
retq

.section .text.TooManyPreds9,"ax",@progbits
TooManyPreds9:
retq

.section .text.TooManyPreds10,"ax",@progbits
TooManyPreds10:
retq

# CHECK: Name: D
# CHECK-NEXT: Value: 0x201003
# CHECK: Name: TooManyPreds
# CHECK-NEXT: Value: 0x201004
# CHECK: Name: TooManyPreds10
# CHECK-NEXT: Value: 0x201018
# CHECK: Name: A
# CHECK-NEXT: Value: 0x201000
# CHECK: Name: B
# CHECK-NEXT: Value: 0x201001
# CHECK: Name: C
# CHECK-NEXT: Value: 0x201002
# CHECK: Name: GB
# CHECK-NEXT: Value: 0x20101F
# CHECK: Name: PP
# CHECK-NEXT: Value: 0x20101C
# CHECK: Name: QC
# CHECK-NEXT: Value: 0x20101E
# CHECK: Name: TS
# CHECK-NEXT: Value: 0x20101D
# CHECK: Name: _init
# CHECK-NEXT: Value: 0x201020
# CHECK: Name: _init2
# CHECK-NEXT: Value: 0x201021

# NOSORT: Name: D
# NOSORT-NEXT: Value: 0x201000
# NOSORT: Name: TooManyPreds
# NOSORT-NEXT: Value: 0x201004
# NOSORT: Name: TooManyPreds10
# NOSORT-NEXT: Value: 0x201018
# NOSORT: Name: A
# NOSORT-NEXT: Value: 0x201003
# NOSORT: Name: B
# NOSORT-NEXT: Value: 0x201002
# NOSORT: Name: C
# NOSORT-NEXT: Value: 0x201001
# NOSORT: Name: GB
# NOSORT-NEXT: Value: 0x20101C
# NOSORT: Name: PP
# NOSORT-NEXT: Value: 0x20101A
# NOSORT: Name: QC
# NOSORT-NEXT: Value: 0x20101B
# NOSORT: Name: TS
# NOSORT-NEXT: Value: 0x201019
# NOSORT: Name: _init
# NOSORT-NEXT: Value: 0x20101D
# NOSORT: Name: _init2
# NOSORT-NEXT: Value: 0x20101E
29 changes: 29 additions & 0 deletions lld/test/ELF/cgprofile-warn.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# REQUIRES: x86

# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t

# RUN: echo "A B 100" > %t.call_graph
# RUN: echo "A C 40" >> %t.call_graph
# RUN: echo "B C 30" >> %t.call_graph
# RUN: echo "adena A 30" >> %t.call_graph
# RUN: echo "poppy A 30" >> %t.call_graph
# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t.out \
# RUN: -noinhibit-exec -icf=all 2>&1 | FileCheck %s

.section .text.C,"ax",@progbits
.globl C
C:
mov poppy, %rax
retq

B = 0x1234

.section .text.A,"ax",@progbits
.globl A
A:
mov poppy, %rax
retq

# CHECK: unable to order absolute symbol: B
# CHECK: call graph file: no such symbol: adena
# CHECK: unable to order undefined symbol: poppy