1 //===- SymbolSize.cpp -----------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Object/SymbolSize.h"
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/Object/COFF.h"
12 #include "llvm/Object/ELFObjectFile.h"
13 #include "llvm/Object/MachO.h"
14 #include "llvm/Object/Wasm.h"
15 #include "llvm/Object/XCOFFObjectFile.h"
18 using namespace object
;
20 // Orders increasingly by (SectionID, Address).
21 int llvm::object::compareAddress(const SymEntry
*A
, const SymEntry
*B
) {
22 if (A
->SectionID
!= B
->SectionID
)
23 return A
->SectionID
< B
->SectionID
? -1 : 1;
24 if (A
->Address
!= B
->Address
)
25 return A
->Address
< B
->Address
? -1 : 1;
29 static unsigned getSectionID(const ObjectFile
&O
, SectionRef Sec
) {
30 if (auto *M
= dyn_cast
<MachOObjectFile
>(&O
))
31 return M
->getSectionID(Sec
);
32 if (isa
<WasmObjectFile
>(&O
))
33 return Sec
.getIndex();
34 if (isa
<XCOFFObjectFile
>(&O
))
35 return Sec
.getIndex();
36 return cast
<COFFObjectFile
>(O
).getSectionID(Sec
);
39 static unsigned getSymbolSectionID(const ObjectFile
&O
, SymbolRef Sym
) {
40 if (auto *M
= dyn_cast
<MachOObjectFile
>(&O
))
41 return M
->getSymbolSectionID(Sym
);
42 if (const auto *M
= dyn_cast
<WasmObjectFile
>(&O
))
43 return M
->getSymbolSectionId(Sym
);
44 if (const auto *M
= dyn_cast
<XCOFFObjectFile
>(&O
))
45 return M
->getSymbolSectionID(Sym
);
46 return cast
<COFFObjectFile
>(O
).getSymbolSectionID(Sym
);
49 std::vector
<std::pair
<SymbolRef
, uint64_t>>
50 llvm::object::computeSymbolSizes(const ObjectFile
&O
) {
51 std::vector
<std::pair
<SymbolRef
, uint64_t>> Ret
;
53 if (const auto *E
= dyn_cast
<ELFObjectFileBase
>(&O
)) {
54 auto Syms
= E
->symbols();
56 Syms
= E
->getDynamicSymbolIterators();
57 for (ELFSymbolRef Sym
: Syms
)
58 Ret
.push_back({Sym
, Sym
.getSize()});
62 // Collect sorted symbol addresses. Include dummy addresses for the end
64 std::vector
<SymEntry
> Addresses
;
66 for (symbol_iterator I
= O
.symbol_begin(), E
= O
.symbol_end(); I
!= E
; ++I
) {
68 Expected
<uint64_t> ValueOrErr
= Sym
.getValue();
70 // TODO: Actually report errors helpfully.
71 report_fatal_error(ValueOrErr
.takeError());
72 Addresses
.push_back({I
, *ValueOrErr
, SymNum
, getSymbolSectionID(O
, Sym
)});
75 for (SectionRef Sec
: O
.sections()) {
76 uint64_t Address
= Sec
.getAddress();
77 uint64_t Size
= Sec
.getSize();
79 {O
.symbol_end(), Address
+ Size
, 0, getSectionID(O
, Sec
)});
82 if (Addresses
.empty())
85 array_pod_sort(Addresses
.begin(), Addresses
.end(), compareAddress
);
87 // Compute the size as the gap to the next symbol. If multiple symbols have
88 // the same address, give both the same size. Because Addresses is sorted,
89 // use two pointers to keep track of the current symbol vs. the next symbol
90 // that doesn't have the same address for size computation.
91 for (unsigned I
= 0, NextI
= 0, N
= Addresses
.size() - 1; I
< N
; ++I
) {
92 auto &P
= Addresses
[I
];
93 if (P
.I
== O
.symbol_end())
96 // If the next pointer is behind, update it to the next symbol.
99 while (NextI
< N
&& Addresses
[NextI
].Address
== P
.Address
)
103 uint64_t Size
= Addresses
[NextI
].Address
- P
.Address
;
107 // Assign the sorted symbols in the original order.
109 for (SymEntry
&P
: Addresses
) {
110 if (P
.I
== O
.symbol_end())
112 Ret
[P
.Number
] = {*P
.I
, P
.Address
};