Maksim Panchenko | 2f09f44 | 2021-12-21 18:21:41 | [diff] [blame] | 1 | //===- bolt/Rewrite/RewriteInstance.cpp - ELF rewriter --------------------===// |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 2 | // |
Rafael Auler | 16521f1 | 2021-03-16 01:04:18 | [diff] [blame] | 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 |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 8 | |
Rafael Auler | a34c753 | 2021-10-08 18:47:10 | [diff] [blame] | 9 | #include "bolt/Rewrite/RewriteInstance.h" |
| 10 | #include "bolt/Core/BinaryContext.h" |
| 11 | #include "bolt/Core/BinaryEmitter.h" |
| 12 | #include "bolt/Core/BinaryFunction.h" |
| 13 | #include "bolt/Core/DebugData.h" |
| 14 | #include "bolt/Core/Exceptions.h" |
| 15 | #include "bolt/Core/MCPlusBuilder.h" |
| 16 | #include "bolt/Core/ParallelUtilities.h" |
| 17 | #include "bolt/Core/Relocation.h" |
| 18 | #include "bolt/Passes/CacheMetrics.h" |
| 19 | #include "bolt/Passes/ReorderFunctions.h" |
| 20 | #include "bolt/Profile/BoltAddressTranslation.h" |
| 21 | #include "bolt/Profile/DataAggregator.h" |
| 22 | #include "bolt/Profile/DataReader.h" |
| 23 | #include "bolt/Profile/YAMLProfileReader.h" |
| 24 | #include "bolt/Profile/YAMLProfileWriter.h" |
| 25 | #include "bolt/Rewrite/BinaryPassManager.h" |
| 26 | #include "bolt/Rewrite/DWARFRewriter.h" |
| 27 | #include "bolt/Rewrite/ExecutableFileMemoryManager.h" |
| 28 | #include "bolt/RuntimeLibs/HugifyRuntimeLibrary.h" |
| 29 | #include "bolt/RuntimeLibs/InstrumentationRuntimeLibrary.h" |
| 30 | #include "bolt/Utils/CommandLineOpts.h" |
| 31 | #include "bolt/Utils/Utils.h" |
Maksim Panchenko | ae409f0 | 2017-07-17 18:22:22 | [diff] [blame] | 32 | #include "llvm/ADT/Optional.h" |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 33 | #include "llvm/DebugInfo/DWARF/DWARFContext.h" |
serge-sans-paille | 290e482 | 2022-02-14 15:27:04 | [diff] [blame] | 34 | #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" |
Amir Ayupov | f1bfb18 | 2021-03-18 20:06:18 | [diff] [blame] | 35 | #include "llvm/ExecutionEngine/RuntimeDyld.h" |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 36 | #include "llvm/MC/MCAsmBackend.h" |
| 37 | #include "llvm/MC/MCAsmInfo.h" |
laith sakka | 7d42835 | 2019-07-12 14:25:50 | [diff] [blame] | 38 | #include "llvm/MC/MCAsmLayout.h" |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 39 | #include "llvm/MC/MCDisassembler/MCDisassembler.h" |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 40 | #include "llvm/MC/MCObjectStreamer.h" |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 41 | #include "llvm/MC/MCStreamer.h" |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 42 | #include "llvm/MC/MCSymbol.h" |
Rafael Auler | a34c753 | 2021-10-08 18:47:10 | [diff] [blame] | 43 | #include "llvm/MC/TargetRegistry.h" |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 44 | #include "llvm/Object/ObjectFile.h" |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 45 | #include "llvm/Support/Alignment.h" |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 46 | #include "llvm/Support/Casting.h" |
| 47 | #include "llvm/Support/CommandLine.h" |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 48 | #include "llvm/Support/DataExtractor.h" |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 49 | #include "llvm/Support/Errc.h" |
Amir Ayupov | 32d2473 | 2022-02-17 04:39:59 | [diff] [blame] | 50 | #include "llvm/Support/Error.h" |
Amir Ayupov | 081e39a | 2021-03-29 23:04:57 | [diff] [blame] | 51 | #include "llvm/Support/FileSystem.h" |
James Luo | 3e55dea | 2021-07-15 21:58:32 | [diff] [blame] | 52 | #include "llvm/Support/LEB128.h" |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 53 | #include "llvm/Support/ManagedStatic.h" |
Bill Nell | 591e0ef | 2017-11-28 02:00:24 | [diff] [blame] | 54 | #include "llvm/Support/Timer.h" |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 55 | #include "llvm/Support/ToolOutputFile.h" |
Bill Nell | 5cd5896 | 2017-05-24 21:14:16 | [diff] [blame] | 56 | #include "llvm/Support/raw_ostream.h" |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 57 | #include <algorithm> |
Maksim Panchenko | 218c5f0 | 2016-01-27 00:03:58 | [diff] [blame] | 58 | #include <fstream> |
Amir Ayupov | 32d2473 | 2022-02-17 04:39:59 | [diff] [blame] | 59 | #include <memory> |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 60 | #include <system_error> |
| 61 | |
| 62 | #undef DEBUG_TYPE |
Maksim Panchenko | d152608 | 2016-02-05 22:42:04 | [diff] [blame] | 63 | #define DEBUG_TYPE "bolt" |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 64 | |
| 65 | using namespace llvm; |
| 66 | using namespace object; |
Maksim Panchenko | d152608 | 2016-02-05 22:42:04 | [diff] [blame] | 67 | using namespace bolt; |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 68 | |
Rafael Auler | c82e7fd | 2020-02-11 02:50:53 | [diff] [blame] | 69 | extern cl::opt<uint32_t> X86AlignBranchBoundary; |
| 70 | extern cl::opt<bool> X86AlignBranchWithin32BBoundaries; |
| 71 | |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 72 | namespace opts { |
| 73 | |
Maksim Panchenko | 120d267 | 2018-04-13 22:46:19 | [diff] [blame] | 74 | extern cl::opt<MacroFusionType> AlignMacroOpFusion; |
Rafael Auler | a34c753 | 2021-10-08 18:47:10 | [diff] [blame] | 75 | extern cl::list<std::string> HotTextMoveSections; |
Xun Li | 9bd7161 | 2020-05-02 18:14:38 | [diff] [blame] | 76 | extern cl::opt<bool> Hugify; |
Xun Li | 00892a5fd | 2020-05-21 21:28:47 | [diff] [blame] | 77 | extern cl::opt<bool> Instrument; |
Maksim Panchenko | 6ff1795 | 2017-01-17 23:49:59 | [diff] [blame] | 78 | extern cl::opt<JumpTableSupportLevel> JumpTables; |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 79 | extern cl::list<std::string> ReorderData; |
Maksim Panchenko | 492e4a5 | 2019-04-26 00:00:05 | [diff] [blame] | 80 | extern cl::opt<bolt::ReorderFunctions::ReorderType> ReorderFunctions; |
laith sakka | 7d42835 | 2019-07-12 14:25:50 | [diff] [blame] | 81 | extern cl::opt<bool> TimeBuild; |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 82 | |
Fangrui Song | b92436e | 2022-06-05 20:29:49 | [diff] [blame] | 83 | static cl::opt<bool> ForceToDataRelocations( |
| 84 | "force-data-relocations", |
| 85 | cl::desc("force relocations to data sections to always be processed"), |
| 86 | |
| 87 | cl::Hidden, cl::cat(BoltCategory)); |
Bill Nell | 89feb84 | 2018-01-24 13:42:11 | [diff] [blame] | 88 | |
Rafael Auler | f91d121 | 2020-05-07 00:31:25 | [diff] [blame] | 89 | cl::opt<std::string> |
Fangrui Song | b92436e | 2022-06-05 20:29:49 | [diff] [blame] | 90 | BoltID("bolt-id", |
| 91 | cl::desc("add any string to tag this execution in the " |
| 92 | "output binary via bolt info section"), |
| 93 | cl::cat(BoltCategory)); |
Rafael Auler | f91d121 | 2020-05-07 00:31:25 | [diff] [blame] | 94 | |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 95 | cl::opt<bool> |
| 96 | AllowStripped("allow-stripped", |
| 97 | cl::desc("allow processing of stripped binaries"), |
| 98 | cl::Hidden, |
| 99 | cl::cat(BoltCategory)); |
| 100 | |
Amir Ayupov | 6333e5d | 2022-06-02 07:26:23 | [diff] [blame] | 101 | cl::opt<bool> DumpDotAll( |
| 102 | "dump-dot-all", |
| 103 | cl::desc("dump function CFGs to graphviz format after each stage;" |
| 104 | "enable '-print-loops' for color-coded blocks"), |
Fangrui Song | b92436e | 2022-06-05 20:29:49 | [diff] [blame] | 105 | cl::Hidden, cl::cat(BoltCategory)); |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 106 | |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 107 | static cl::list<std::string> |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 108 | ForceFunctionNames("funcs", |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 109 | cl::CommaSeparated, |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 110 | cl::desc("limit optimizations to functions from the list"), |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 111 | cl::value_desc("func1,func2,func3,..."), |
| 112 | cl::Hidden, |
| 113 | cl::cat(BoltCategory)); |
| 114 | |
| 115 | static cl::opt<std::string> |
| 116 | FunctionNamesFile("funcs-file", |
| 117 | cl::desc("file with list of functions to optimize"), |
| 118 | cl::Hidden, |
| 119 | cl::cat(BoltCategory)); |
| 120 | |
Amir Ayupov | d474dbd | 2021-06-05 01:49:29 | [diff] [blame] | 121 | static cl::list<std::string> ForceFunctionNamesNR( |
| 122 | "funcs-no-regex", cl::CommaSeparated, |
| 123 | cl::desc("limit optimizations to functions from the list (non-regex)"), |
| 124 | cl::value_desc("func1,func2,func3,..."), cl::Hidden, cl::cat(BoltCategory)); |
| 125 | |
| 126 | static cl::opt<std::string> FunctionNamesFileNR( |
| 127 | "funcs-file-no-regex", |
| 128 | cl::desc("file with list of functions to optimize (non-regex)"), cl::Hidden, |
| 129 | cl::cat(BoltCategory)); |
| 130 | |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 131 | cl::opt<bool> |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 132 | KeepTmp("keep-tmp", |
| 133 | cl::desc("preserve intermediate .o file"), |
| 134 | cl::Hidden, |
| 135 | cl::cat(BoltCategory)); |
| 136 | |
Fangrui Song | b92436e | 2022-06-05 20:29:49 | [diff] [blame] | 137 | cl::opt<bool> Lite("lite", cl::desc("skip processing of cold functions"), |
| 138 | cl::cat(BoltCategory)); |
Maksim Panchenko | 924d0bd | 2020-05-03 22:49:58 | [diff] [blame] | 139 | |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 140 | static cl::opt<unsigned> |
Rafael Auler | e3898d5 | 2020-12-30 20:23:58 | [diff] [blame] | 141 | LiteThresholdPct("lite-threshold-pct", |
| 142 | cl::desc("threshold (in percent) for selecting functions to process in lite " |
| 143 | "mode. Higher threshold means fewer functions to process. E.g " |
| 144 | "threshold of 90 means only top 10 percent of functions with " |
| 145 | "profile will be processed."), |
| 146 | cl::init(0), |
| 147 | cl::ZeroOrMore, |
| 148 | cl::Hidden, |
| 149 | cl::cat(BoltOptCategory)); |
| 150 | |
Fangrui Song | b92436e | 2022-06-05 20:29:49 | [diff] [blame] | 151 | static cl::opt<unsigned> LiteThresholdCount( |
| 152 | "lite-threshold-count", |
| 153 | cl::desc("similar to '-lite-threshold-pct' but specify threshold using " |
| 154 | "absolute function call count. I.e. limit processing to functions " |
| 155 | "executed at least the specified number of times."), |
| 156 | cl::init(0), cl::Hidden, cl::cat(BoltOptCategory)); |
Rafael Auler | e3898d5 | 2020-12-30 20:23:58 | [diff] [blame] | 157 | |
| 158 | static cl::opt<unsigned> |
Fangrui Song | b92436e | 2022-06-05 20:29:49 | [diff] [blame] | 159 | MaxFunctions("max-funcs", |
| 160 | cl::desc("maximum number of functions to process"), cl::Hidden, |
| 161 | cl::cat(BoltCategory)); |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 162 | |
Fangrui Song | b92436e | 2022-06-05 20:29:49 | [diff] [blame] | 163 | static cl::opt<unsigned> MaxDataRelocations( |
| 164 | "max-data-relocations", |
| 165 | cl::desc("maximum number of data relocations to process"), cl::Hidden, |
| 166 | cl::cat(BoltCategory)); |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 167 | |
Fangrui Song | b92436e | 2022-06-05 20:29:49 | [diff] [blame] | 168 | cl::opt<bool> PrintAll("print-all", |
| 169 | cl::desc("print functions after each stage"), cl::Hidden, |
| 170 | cl::cat(BoltCategory)); |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 171 | |
Fangrui Song | b92436e | 2022-06-05 20:29:49 | [diff] [blame] | 172 | cl::opt<bool> PrintCFG("print-cfg", |
| 173 | cl::desc("print functions after CFG construction"), |
| 174 | cl::Hidden, cl::cat(BoltCategory)); |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 175 | |
Alexander Shaposhnikov | 5b64bf2 | 2020-02-11 22:30:33 | [diff] [blame] | 176 | cl::opt<bool> PrintDisasm("print-disasm", |
Fangrui Song | b92436e | 2022-06-05 20:29:49 | [diff] [blame] | 177 | cl::desc("print function after disassembly"), |
| 178 | cl::Hidden, cl::cat(BoltCategory)); |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 179 | |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 180 | static cl::opt<bool> |
Fangrui Song | b92436e | 2022-06-05 20:29:49 | [diff] [blame] | 181 | PrintGlobals("print-globals", |
| 182 | cl::desc("print global symbols after disassembly"), cl::Hidden, |
| 183 | cl::cat(BoltCategory)); |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 184 | |
Alexander Shaposhnikov | 36cf37c | 2020-01-30 21:10:48 | [diff] [blame] | 185 | extern cl::opt<bool> PrintSections; |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 186 | |
Fangrui Song | b92436e | 2022-06-05 20:29:49 | [diff] [blame] | 187 | static cl::opt<bool> PrintLoopInfo("print-loops", |
| 188 | cl::desc("print loop related information"), |
| 189 | cl::Hidden, cl::cat(BoltCategory)); |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 190 | |
Fangrui Song | b92436e | 2022-06-05 20:29:49 | [diff] [blame] | 191 | static cl::opt<bool> PrintSDTMarkers("print-sdt", |
| 192 | cl::desc("print all SDT markers"), |
| 193 | cl::Hidden, cl::cat(BoltCategory)); |
Laith Saed Sakka | 4755825 | 2019-05-16 00:19:18 | [diff] [blame] | 194 | |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 195 | enum PrintPseudoProbesOptions { |
| 196 | PPP_None = 0, |
| 197 | PPP_Probes_Section_Decode = 0x1, |
| 198 | PPP_Probes_Address_Conversion = 0x2, |
James Luo | 0df7bf7 | 2021-07-16 23:05:18 | [diff] [blame] | 199 | PPP_Encoded_Probes = 0x3, |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 200 | PPP_All = 0xf |
| 201 | }; |
| 202 | |
| 203 | cl::opt<PrintPseudoProbesOptions> PrintPseudoProbes( |
| 204 | "print-pseudo-probes", cl::desc("print pseudo probe info"), |
| 205 | cl::init(PPP_None), |
| 206 | cl::values(clEnumValN(PPP_Probes_Section_Decode, "decode", |
| 207 | "decode probes section from binary"), |
| 208 | clEnumValN(PPP_Probes_Address_Conversion, "address_conversion", |
| 209 | "update address2ProbesMap with output block address"), |
James Luo | 0df7bf7 | 2021-07-16 23:05:18 | [diff] [blame] | 210 | clEnumValN(PPP_Encoded_Probes, "encoded_probes", |
| 211 | "display the encoded probes in binary section"), |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 212 | clEnumValN(PPP_All, "all", "enable all debugging printout")), |
| 213 | cl::ZeroOrMore, cl::Hidden, cl::cat(BoltCategory)); |
James Luo | 8a91959 | 2021-06-11 20:06:12 | [diff] [blame] | 214 | |
Fangrui Song | b92436e | 2022-06-05 20:29:49 | [diff] [blame] | 215 | static cl::opt<cl::boolOrDefault> RelocationMode( |
| 216 | "relocs", cl::desc("use relocations in the binary (default=autodetect)"), |
| 217 | cl::cat(BoltCategory)); |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 218 | |
Maksim Panchenko | b6cb112 | 2017-12-14 07:12:01 | [diff] [blame] | 219 | static cl::opt<std::string> |
| 220 | SaveProfile("w", |
| 221 | cl::desc("save recorded profile to a file"), |
| 222 | cl::cat(BoltOutputCategory)); |
| 223 | |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 224 | static cl::list<std::string> |
| 225 | SkipFunctionNames("skip-funcs", |
| 226 | cl::CommaSeparated, |
| 227 | cl::desc("list of functions to skip"), |
| 228 | cl::value_desc("func1,func2,func3,..."), |
| 229 | cl::Hidden, |
| 230 | cl::cat(BoltCategory)); |
| 231 | |
| 232 | static cl::opt<std::string> |
| 233 | SkipFunctionNamesFile("skip-funcs-file", |
| 234 | cl::desc("file with list of functions to skip"), |
| 235 | cl::Hidden, |
| 236 | cl::cat(BoltCategory)); |
| 237 | |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 238 | cl::opt<bool> |
| 239 | TrapOldCode("trap-old-code", |
| 240 | cl::desc("insert traps in old function bodies (relocation mode)"), |
| 241 | cl::Hidden, |
| 242 | cl::cat(BoltCategory)); |
| 243 | |
Rafael Auler | e485a98 | 2021-06-16 16:52:03 | [diff] [blame] | 244 | static cl::opt<std::string> DWPPathName("dwp", |
| 245 | cl::desc("Path and name to DWP file."), |
Fangrui Song | 36c7d79 | 2022-06-04 07:10:42 | [diff] [blame] | 246 | cl::Hidden, cl::init(""), |
| 247 | cl::cat(BoltCategory)); |
Rafael Auler | e485a98 | 2021-06-16 16:52:03 | [diff] [blame] | 248 | |
Maksim Panchenko | 0bde796 | 2017-03-28 21:40:20 | [diff] [blame] | 249 | static cl::opt<bool> |
| 250 | UseGnuStack("use-gnu-stack", |
| 251 | cl::desc("use GNU_STACK program header for new segment (workaround for " |
| 252 | "issues with strip/objcopy)"), |
| 253 | cl::ZeroOrMore, |
| 254 | cl::cat(BoltCategory)); |
| 255 | |
Rafael Auler | 0ed144a | 2017-10-06 21:42:46 | [diff] [blame] | 256 | static cl::opt<bool> |
Fangrui Song | b92436e | 2022-06-05 20:29:49 | [diff] [blame] | 257 | TimeRewrite("time-rewrite", |
| 258 | cl::desc("print time spent in rewriting passes"), cl::Hidden, |
| 259 | cl::cat(BoltCategory)); |
Bill Nell | 591e0ef | 2017-11-28 02:00:24 | [diff] [blame] | 260 | |
laith sakka | 7d42835 | 2019-07-12 14:25:50 | [diff] [blame] | 261 | static cl::opt<bool> |
| 262 | SequentialDisassembly("sequential-disassembly", |
| 263 | cl::desc("performs disassembly sequentially"), |
| 264 | cl::init(false), |
| 265 | cl::cat(BoltOptCategory)); |
| 266 | |
Fangrui Song | b92436e | 2022-06-05 20:29:49 | [diff] [blame] | 267 | static cl::opt<bool> WriteBoltInfoSection( |
| 268 | "bolt-info", cl::desc("write bolt info section in the output binary"), |
| 269 | cl::init(true), cl::Hidden, cl::cat(BoltOutputCategory)); |
laith sakka | c1564a1 | 2019-07-31 00:55:27 | [diff] [blame] | 270 | |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 271 | } // namespace opts |
| 272 | |
Maksim Panchenko | 96adec5 | 2017-05-16 16:27:34 | [diff] [blame] | 273 | constexpr const char *RewriteInstance::SectionsToOverwrite[]; |
Amir Ayupov | 12e9fec | 2021-04-01 18:43:00 | [diff] [blame] | 274 | std::vector<std::string> RewriteInstance::DebugSectionsToOverwrite = { |
Alexander Yermolovich | 014cd37 | 2022-04-21 22:47:49 | [diff] [blame] | 275 | ".debug_abbrev", ".debug_aranges", ".debug_line", ".debug_line_str", |
| 276 | ".debug_loc", ".debug_loclists", ".debug_ranges", ".debug_rnglists", |
| 277 | ".gdb_index", ".debug_addr"}; |
Bill Nell | c1d1c2e | 2016-07-23 03:52:57 | [diff] [blame] | 278 | |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 279 | const char RewriteInstance::TimerGroupName[] = "rewrite"; |
| 280 | const char RewriteInstance::TimerGroupDesc[] = "Rewrite passes"; |
Bill Nell | 591e0ef | 2017-11-28 02:00:24 | [diff] [blame] | 281 | |
Bill Nell | 5cd5896 | 2017-05-24 21:14:16 | [diff] [blame] | 282 | namespace llvm { |
| 283 | namespace bolt { |
Alexander Shaposhnikov | 36cf37c | 2020-01-30 21:10:48 | [diff] [blame] | 284 | |
Bill Nell | 5cd5896 | 2017-05-24 21:14:16 | [diff] [blame] | 285 | extern const char *BoltRevision; |
Bill Nell | 5cd5896 | 2017-05-24 21:14:16 | [diff] [blame] | 286 | |
Rafael Auler | a34c753 | 2021-10-08 18:47:10 | [diff] [blame] | 287 | MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch, |
| 288 | const MCInstrAnalysis *Analysis, |
| 289 | const MCInstrInfo *Info, |
| 290 | const MCRegisterInfo *RegInfo) { |
| 291 | #ifdef X86_AVAILABLE |
| 292 | if (Arch == Triple::x86_64) |
| 293 | return createX86MCPlusBuilder(Analysis, Info, RegInfo); |
| 294 | #endif |
| 295 | |
| 296 | #ifdef AARCH64_AVAILABLE |
| 297 | if (Arch == Triple::aarch64) |
| 298 | return createAArch64MCPlusBuilder(Analysis, Info, RegInfo); |
| 299 | #endif |
| 300 | |
| 301 | llvm_unreachable("architecture unsupported by MCPlusBuilder"); |
| 302 | } |
| 303 | |
Vladislav Khmelevsky | 20e9d4c | 2022-01-26 20:45:46 | [diff] [blame] | 304 | } // namespace bolt |
| 305 | } // namespace llvm |
| 306 | |
| 307 | namespace { |
| 308 | |
| 309 | bool refersToReorderedSection(ErrorOr<BinarySection &> Section) { |
| 310 | auto Itr = |
Amir Ayupov | d2c8769 | 2022-06-24 05:15:47 | [diff] [blame^] | 311 | llvm::find_if(opts::ReorderData, [&](const std::string &SectionName) { |
| 312 | return (Section && Section->getName() == SectionName); |
| 313 | }); |
Vladislav Khmelevsky | 20e9d4c | 2022-01-26 20:45:46 | [diff] [blame] | 314 | return Itr != opts::ReorderData.end(); |
| 315 | } |
| 316 | |
Rafael Auler | a34c753 | 2021-10-08 18:47:10 | [diff] [blame] | 317 | } // anonymous namespace |
Maksim Panchenko | 003d106c | 2016-08-11 21:23:54 | [diff] [blame] | 318 | |
Amir Ayupov | 32d2473 | 2022-02-17 04:39:59 | [diff] [blame] | 319 | Expected<std::unique_ptr<RewriteInstance>> |
| 320 | RewriteInstance::createRewriteInstance(ELFObjectFileBase *File, const int Argc, |
| 321 | const char *const *Argv, |
| 322 | StringRef ToolPath) { |
| 323 | Error Err = Error::success(); |
| 324 | auto RI = std::make_unique<RewriteInstance>(File, Argc, Argv, ToolPath, Err); |
| 325 | if (Err) |
| 326 | return std::move(Err); |
Vladislav Khmelevsky | 63686af | 2022-04-19 15:48:27 | [diff] [blame] | 327 | return std::move(RI); |
Amir Ayupov | 32d2473 | 2022-02-17 04:39:59 | [diff] [blame] | 328 | } |
| 329 | |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 330 | RewriteInstance::RewriteInstance(ELFObjectFileBase *File, const int Argc, |
Amir Ayupov | 32d2473 | 2022-02-17 04:39:59 | [diff] [blame] | 331 | const char *const *Argv, StringRef ToolPath, |
| 332 | Error &Err) |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 333 | : InputFile(File), Argc(Argc), Argv(Argv), ToolPath(ToolPath), |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 334 | SHStrTab(StringTableBuilder::ELF) { |
Amir Ayupov | 32d2473 | 2022-02-17 04:39:59 | [diff] [blame] | 335 | ErrorAsOutParameter EAO(&Err); |
Maksim Panchenko | 4f4239c | 2020-11-04 19:44:02 | [diff] [blame] | 336 | auto ELF64LEFile = dyn_cast<ELF64LEObjectFile>(InputFile); |
| 337 | if (!ELF64LEFile) { |
Amir Ayupov | 32d2473 | 2022-02-17 04:39:59 | [diff] [blame] | 338 | Err = createStringError(errc::not_supported, |
| 339 | "Only 64-bit LE ELF binaries are supported"); |
| 340 | return; |
Maksim Panchenko | 4f4239c | 2020-11-04 19:44:02 | [diff] [blame] | 341 | } |
| 342 | |
| 343 | bool IsPIC = false; |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 344 | const ELFFile<ELF64LE> &Obj = ELF64LEFile->getELFFile(); |
| 345 | if (Obj.getHeader().e_type != ELF::ET_EXEC) { |
Maksim Panchenko | 4f4239c | 2020-11-04 19:44:02 | [diff] [blame] | 346 | outs() << "BOLT-INFO: shared object or position-independent executable " |
| 347 | "detected\n"; |
| 348 | IsPIC = true; |
| 349 | } |
| 350 | |
Amir Ayupov | 32d2473 | 2022-02-17 04:39:59 | [diff] [blame] | 351 | auto BCOrErr = BinaryContext::createBinaryContext( |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 352 | File, IsPIC, |
Rafael Auler | a8cbc80 | 2021-10-06 20:03:56 | [diff] [blame] | 353 | DWARFContext::create(*File, DWARFContext::ProcessDebugRelocations::Ignore, |
| 354 | nullptr, opts::DWPPathName, |
| 355 | WithColor::defaultErrorHandler, |
| 356 | WithColor::defaultWarningHandler)); |
Amir Ayupov | 32d2473 | 2022-02-17 04:39:59 | [diff] [blame] | 357 | if (Error E = BCOrErr.takeError()) { |
| 358 | Err = std::move(E); |
| 359 | return; |
| 360 | } |
| 361 | BC = std::move(BCOrErr.get()); |
Rafael Auler | a34c753 | 2021-10-08 18:47:10 | [diff] [blame] | 362 | BC->initializeTarget(std::unique_ptr<MCPlusBuilder>(createMCPlusBuilder( |
| 363 | BC->TheTriple->getArch(), BC->MIA.get(), BC->MII.get(), BC->MRI.get()))); |
| 364 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 365 | BAT = std::make_unique<BoltAddressTranslation>(*BC); |
Maksim Panchenko | 4f4239c | 2020-11-04 19:44:02 | [diff] [blame] | 366 | |
| 367 | if (opts::UpdateDebugSections) |
Amir Ayupov | f1bfb18 | 2021-03-18 20:06:18 | [diff] [blame] | 368 | DebugInfoRewriter = std::make_unique<DWARFRewriter>(*BC); |
Maksim Panchenko | 4f4239c | 2020-11-04 19:44:02 | [diff] [blame] | 369 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 370 | if (opts::Instrument) |
Rafael Auler | b3c34d5 | 2021-03-15 23:34:25 | [diff] [blame] | 371 | BC->setRuntimeLibrary(std::make_unique<InstrumentationRuntimeLibrary>()); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 372 | else if (opts::Hugify) |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 373 | BC->setRuntimeLibrary(std::make_unique<HugifyRuntimeLibrary>()); |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 374 | } |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 375 | |
| 376 | RewriteInstance::~RewriteInstance() {} |
| 377 | |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 378 | Error RewriteInstance::setProfile(StringRef Filename) { |
| 379 | if (!sys::fs::exists(Filename)) |
| 380 | return errorCodeToError(make_error_code(errc::no_such_file_or_directory)); |
| 381 | |
| 382 | if (ProfileReader) { |
| 383 | // Already exists |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 384 | return make_error<StringError>(Twine("multiple profiles specified: ") + |
| 385 | ProfileReader->getFilename() + " and " + |
| 386 | Filename, |
| 387 | inconvertibleErrorCode()); |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 388 | } |
| 389 | |
| 390 | // Spawn a profile reader based on file contents. |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 391 | if (DataAggregator::checkPerfDataMagic(Filename)) |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 392 | ProfileReader = std::make_unique<DataAggregator>(Filename); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 393 | else if (YAMLProfileReader::isYAML(Filename)) |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 394 | ProfileReader = std::make_unique<YAMLProfileReader>(Filename); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 395 | else |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 396 | ProfileReader = std::make_unique<DataReader>(Filename); |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 397 | |
| 398 | return Error::success(); |
| 399 | } |
| 400 | |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 401 | /// Return true if the function \p BF should be disassembled. |
| 402 | static bool shouldDisassemble(const BinaryFunction &BF) { |
| 403 | if (BF.isPseudo()) |
Maksim Panchenko | c6ce2ab | 2019-01-16 07:43:40 | [diff] [blame] | 404 | return false; |
Maksim Panchenko | c6ce2ab | 2019-01-16 07:43:40 | [diff] [blame] | 405 | |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 406 | if (opts::processAllFunctions()) |
| 407 | return true; |
| 408 | |
| 409 | return !BF.isIgnored(); |
Maksim Panchenko | c6ce2ab | 2019-01-16 07:43:40 | [diff] [blame] | 410 | } |
| 411 | |
Amir Ayupov | af6e66f | 2022-02-24 03:30:30 | [diff] [blame] | 412 | Error RewriteInstance::discoverStorage() { |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 413 | NamedRegionTimer T("discoverStorage", "discover storage", TimerGroupName, |
| 414 | TimerGroupDesc, opts::TimeRewrite); |
spupyrev | 48a53a7 | 2017-11-15 00:51:24 | [diff] [blame] | 415 | |
Rafael Auler | 624b2d9 | 2017-09-20 17:43:01 | [diff] [blame] | 416 | // Stubs are harmful because RuntimeDyld may try to increase the size of |
| 417 | // sections accounting for stubs when we need those sections to match the |
| 418 | // same size seen in the input binary, in case this section is a copy |
| 419 | // of the original one seen in the binary. |
Maksim Panchenko | d414acf | 2019-12-17 19:17:31 | [diff] [blame] | 420 | BC->EFMM.reset(new ExecutableFileMemoryManager(*BC, /*AllowStubs*/ false)); |
Maksim Panchenko | 6ff1795 | 2017-01-17 23:49:59 | [diff] [blame] | 421 | |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 422 | auto ELF64LEFile = dyn_cast<ELF64LEObjectFile>(InputFile); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 423 | const ELFFile<ELF64LE> &Obj = ELF64LEFile->getELFFile(); |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 424 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 425 | BC->StartFunctionAddress = Obj.getHeader().e_entry; |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 426 | |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 427 | NextAvailableAddress = 0; |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 428 | uint64_t NextAvailableOffset = 0; |
Amir Ayupov | af6e66f | 2022-02-24 03:30:30 | [diff] [blame] | 429 | Expected<ELF64LE::PhdrRange> PHsOrErr = Obj.program_headers(); |
| 430 | if (Error E = PHsOrErr.takeError()) |
| 431 | return E; |
| 432 | |
| 433 | ELF64LE::PhdrRange PHs = PHsOrErr.get(); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 434 | for (const ELF64LE::Phdr &Phdr : PHs) { |
Vasily Leonenko | ad79d51 | 2021-06-18 20:08:35 | [diff] [blame] | 435 | switch (Phdr.p_type) { |
| 436 | case ELF::PT_LOAD: |
Maksim Panchenko | a76b13d | 2018-10-03 00:16:26 | [diff] [blame] | 437 | BC->FirstAllocAddress = std::min(BC->FirstAllocAddress, |
| 438 | static_cast<uint64_t>(Phdr.p_vaddr)); |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 439 | NextAvailableAddress = std::max(NextAvailableAddress, |
| 440 | Phdr.p_vaddr + Phdr.p_memsz); |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 441 | NextAvailableOffset = std::max(NextAvailableOffset, |
| 442 | Phdr.p_offset + Phdr.p_filesz); |
Maksim Panchenko | 6ff1795 | 2017-01-17 23:49:59 | [diff] [blame] | 443 | |
Maksim Panchenko | 250ca40 | 2020-06-26 23:52:07 | [diff] [blame] | 444 | BC->SegmentMapInfo[Phdr.p_vaddr] = SegmentInfo{Phdr.p_vaddr, |
| 445 | Phdr.p_memsz, |
| 446 | Phdr.p_offset, |
| 447 | Phdr.p_filesz, |
| 448 | Phdr.p_align}; |
Vasily Leonenko | ad79d51 | 2021-06-18 20:08:35 | [diff] [blame] | 449 | break; |
| 450 | case ELF::PT_INTERP: |
| 451 | BC->HasInterpHeader = true; |
| 452 | break; |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 453 | } |
| 454 | } |
| 455 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 456 | for (const SectionRef &Section : InputFile->sections()) { |
Amir Ayupov | af6e66f | 2022-02-24 03:30:30 | [diff] [blame] | 457 | Expected<StringRef> SectionNameOrErr = Section.getName(); |
| 458 | if (Error E = SectionNameOrErr.takeError()) |
| 459 | return E; |
| 460 | StringRef SectionName = SectionNameOrErr.get(); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 461 | if (SectionName == ".text") { |
Rafael Auler | 624b2d9 | 2017-09-20 17:43:01 | [diff] [blame] | 462 | BC->OldTextSectionAddress = Section.getAddress(); |
| 463 | BC->OldTextSectionSize = Section.getSize(); |
Maksim Panchenko | 2df4e7b | 2020-02-25 01:12:41 | [diff] [blame] | 464 | |
Amir Ayupov | af6e66f | 2022-02-24 03:30:30 | [diff] [blame] | 465 | Expected<StringRef> SectionContentsOrErr = Section.getContents(); |
| 466 | if (Error E = SectionContentsOrErr.takeError()) |
| 467 | return E; |
| 468 | StringRef SectionContents = SectionContentsOrErr.get(); |
Rafael Auler | 624b2d9 | 2017-09-20 17:43:01 | [diff] [blame] | 469 | BC->OldTextSectionOffset = |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 470 | SectionContents.data() - InputFile->getData().data(); |
Maksim Panchenko | c89821c | 2017-02-07 23:31:14 | [diff] [blame] | 471 | } |
| 472 | |
Rafael Auler | 6c8fc28 | 2020-07-17 00:35:55 | [diff] [blame] | 473 | if (!opts::HeatmapMode && |
Rafael Auler | 21f4303 | 2019-04-13 00:33:46 | [diff] [blame] | 474 | !(opts::AggregateOnly && BAT->enabledFor(InputFile)) && |
Maksim Panchenko | a07f1a2 | 2020-03-11 22:51:32 | [diff] [blame] | 475 | (SectionName.startswith(getOrgSecPrefix()) || |
Amir Ayupov | af6e66f | 2022-02-24 03:30:30 | [diff] [blame] | 476 | SectionName == getBOLTTextSectionName())) |
| 477 | return createStringError( |
| 478 | errc::function_not_supported, |
| 479 | "BOLT-ERROR: input file was processed by BOLT. Cannot re-optimize"); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 480 | } |
| 481 | |
Amir Ayupov | af6e66f | 2022-02-24 03:30:30 | [diff] [blame] | 482 | if (!NextAvailableAddress || !NextAvailableOffset) |
| 483 | return createStringError(errc::executable_format_error, |
| 484 | "no PT_LOAD pheader seen"); |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 485 | |
Bill Nell | c27a6a5 | 2016-09-02 21:15:29 | [diff] [blame] | 486 | outs() << "BOLT-INFO: first alloc address is 0x" |
Maksim Panchenko | a76b13d | 2018-10-03 00:16:26 | [diff] [blame] | 487 | << Twine::utohexstr(BC->FirstAllocAddress) << '\n'; |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 488 | |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 489 | FirstNonAllocatableOffset = NextAvailableOffset; |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 490 | |
Maksim Panchenko | 1387a9d | 2018-09-25 03:58:31 | [diff] [blame] | 491 | NextAvailableAddress = alignTo(NextAvailableAddress, BC->PageAlign); |
| 492 | NextAvailableOffset = alignTo(NextAvailableOffset, BC->PageAlign); |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 493 | |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 494 | if (!opts::UseGnuStack) { |
| 495 | // This is where the black magic happens. Creating PHDR table in a segment |
| 496 | // other than that containing ELF header is tricky. Some loaders and/or |
| 497 | // parts of loaders will apply e_phoff from ELF header assuming both are in |
| 498 | // the same segment, while others will do the proper calculation. |
| 499 | // We create the new PHDR table in such a way that both of the methods |
| 500 | // of loading and locating the table work. There's a slight file size |
| 501 | // overhead because of that. |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 502 | // |
| 503 | // NB: bfd's strip command cannot do the above and will corrupt the |
| 504 | // binary during the process of stripping non-allocatable sections. |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 505 | if (NextAvailableOffset <= NextAvailableAddress - BC->FirstAllocAddress) |
Maksim Panchenko | a76b13d | 2018-10-03 00:16:26 | [diff] [blame] | 506 | NextAvailableOffset = NextAvailableAddress - BC->FirstAllocAddress; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 507 | else |
Maksim Panchenko | a76b13d | 2018-10-03 00:16:26 | [diff] [blame] | 508 | NextAvailableAddress = NextAvailableOffset + BC->FirstAllocAddress; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 509 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 510 | assert(NextAvailableOffset == |
| 511 | NextAvailableAddress - BC->FirstAllocAddress && |
| 512 | "PHDR table address calculation error"); |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 513 | |
Bill Nell | c27a6a5 | 2016-09-02 21:15:29 | [diff] [blame] | 514 | outs() << "BOLT-INFO: creating new program header table at address 0x" |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 515 | << Twine::utohexstr(NextAvailableAddress) << ", offset 0x" |
| 516 | << Twine::utohexstr(NextAvailableOffset) << '\n'; |
| 517 | |
| 518 | PHDRTableAddress = NextAvailableAddress; |
| 519 | PHDRTableOffset = NextAvailableOffset; |
| 520 | |
| 521 | // Reserve space for 3 extra pheaders. |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 522 | unsigned Phnum = Obj.getHeader().e_phnum; |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 523 | Phnum += 3; |
| 524 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 525 | NextAvailableAddress += Phnum * sizeof(ELF64LEPhdrTy); |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 526 | NextAvailableOffset += Phnum * sizeof(ELF64LEPhdrTy); |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 527 | } |
| 528 | |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 529 | // Align at cache line. |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 530 | NextAvailableAddress = alignTo(NextAvailableAddress, 64); |
| 531 | NextAvailableOffset = alignTo(NextAvailableOffset, 64); |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 532 | |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 533 | NewTextSegmentAddress = NextAvailableAddress; |
| 534 | NewTextSegmentOffset = NextAvailableOffset; |
Rafael Auler | 76d7740 | 2017-08-31 18:45:37 | [diff] [blame] | 535 | BC->LayoutStartAddress = NextAvailableAddress; |
Maksim Panchenko | 250ca40 | 2020-06-26 23:52:07 | [diff] [blame] | 536 | |
| 537 | // Tools such as objcopy can strip section contents but leave header |
| 538 | // entries. Check that at least .text is mapped in the file. |
Amir Ayupov | af6e66f | 2022-02-24 03:30:30 | [diff] [blame] | 539 | if (!getFileOffsetForAddress(BC->OldTextSectionAddress)) |
| 540 | return createStringError(errc::executable_format_error, |
| 541 | "BOLT-ERROR: input binary is not a valid ELF " |
| 542 | "executable as its text section is not " |
| 543 | "mapped to a valid segment"); |
| 544 | return Error::success(); |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 545 | } |
| 546 | |
Laith Saed Sakka | 4755825 | 2019-05-16 00:19:18 | [diff] [blame] | 547 | void RewriteInstance::parseSDTNotes() { |
| 548 | if (!SDTSection) |
| 549 | return; |
| 550 | |
| 551 | StringRef Buf = SDTSection->getContents(); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 552 | DataExtractor DE = DataExtractor(Buf, BC->AsmInfo->isLittleEndian(), |
| 553 | BC->AsmInfo->getCodePointerSize()); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 554 | uint64_t Offset = 0; |
Laith Saed Sakka | 4755825 | 2019-05-16 00:19:18 | [diff] [blame] | 555 | |
| 556 | while (DE.isValidOffset(Offset)) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 557 | uint32_t NameSz = DE.getU32(&Offset); |
Laith Saed Sakka | 4755825 | 2019-05-16 00:19:18 | [diff] [blame] | 558 | DE.getU32(&Offset); // skip over DescSz |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 559 | uint32_t Type = DE.getU32(&Offset); |
Laith Saed Sakka | 4755825 | 2019-05-16 00:19:18 | [diff] [blame] | 560 | Offset = alignTo(Offset, 4); |
| 561 | |
| 562 | if (Type != 3) |
| 563 | errs() << "BOLT-WARNING: SDT note type \"" << Type |
| 564 | << "\" is not expected\n"; |
| 565 | |
| 566 | if (NameSz == 0) |
| 567 | errs() << "BOLT-WARNING: SDT note has empty name\n"; |
| 568 | |
| 569 | StringRef Name = DE.getCStr(&Offset); |
| 570 | |
| 571 | if (!Name.equals("stapsdt")) |
| 572 | errs() << "BOLT-WARNING: SDT note name \"" << Name |
| 573 | << "\" is not expected\n"; |
| 574 | |
| 575 | // Parse description |
| 576 | SDTMarkerInfo Marker; |
Laith Sakka | 3df2c9e | 2019-05-17 14:58:27 | [diff] [blame] | 577 | Marker.PCOffset = Offset; |
Laith Saed Sakka | 4755825 | 2019-05-16 00:19:18 | [diff] [blame] | 578 | Marker.PC = DE.getU64(&Offset); |
| 579 | Marker.Base = DE.getU64(&Offset); |
| 580 | Marker.Semaphore = DE.getU64(&Offset); |
| 581 | Marker.Provider = DE.getCStr(&Offset); |
| 582 | Marker.Name = DE.getCStr(&Offset); |
| 583 | Marker.Args = DE.getCStr(&Offset); |
Laith Saed Sakka | 4755825 | 2019-05-16 00:19:18 | [diff] [blame] | 584 | Offset = alignTo(Offset, 4); |
Laith Saed Sakka | ca659e4 | 2019-05-16 19:46:32 | [diff] [blame] | 585 | BC->SDTMarkers[Marker.PC] = Marker; |
Laith Saed Sakka | 4755825 | 2019-05-16 00:19:18 | [diff] [blame] | 586 | } |
| 587 | |
| 588 | if (opts::PrintSDTMarkers) |
| 589 | printSDTMarkers(); |
| 590 | } |
| 591 | |
James Luo | 8a91959 | 2021-06-11 20:06:12 | [diff] [blame] | 592 | void RewriteInstance::parsePseudoProbe() { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 593 | if (!PseudoProbeDescSection && !PseudoProbeSection) { |
James Luo | 8a91959 | 2021-06-11 20:06:12 | [diff] [blame] | 594 | // pesudo probe is not added to binary. It is normal and no warning needed. |
| 595 | return; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 596 | } |
| 597 | |
James Luo | 8a91959 | 2021-06-11 20:06:12 | [diff] [blame] | 598 | // If only one section is found, it might mean the ELF is corrupted. |
| 599 | if (!PseudoProbeDescSection) { |
| 600 | errs() << "BOLT-WARNING: fail in reading .pseudo_probe_desc binary\n"; |
| 601 | return; |
| 602 | } else if (!PseudoProbeSection) { |
| 603 | errs() << "BOLT-WARNING: fail in reading .pseudo_probe binary\n"; |
| 604 | return; |
| 605 | } |
| 606 | |
| 607 | StringRef Contents = PseudoProbeDescSection->getContents(); |
| 608 | if (!BC->ProbeDecoder.buildGUID2FuncDescMap( |
| 609 | reinterpret_cast<const uint8_t *>(Contents.data()), |
| 610 | Contents.size())) { |
| 611 | errs() << "BOLT-WARNING: fail in building GUID2FuncDescMap\n"; |
| 612 | return; |
| 613 | } |
| 614 | Contents = PseudoProbeSection->getContents(); |
| 615 | if (!BC->ProbeDecoder.buildAddress2ProbeMap( |
| 616 | reinterpret_cast<const uint8_t *>(Contents.data()), |
| 617 | Contents.size())) { |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 618 | BC->ProbeDecoder.getAddress2ProbesMap().clear(); |
James Luo | 8a91959 | 2021-06-11 20:06:12 | [diff] [blame] | 619 | errs() << "BOLT-WARNING: fail in building Address2ProbeMap\n"; |
| 620 | return; |
| 621 | } |
| 622 | |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 623 | if (opts::PrintPseudoProbes == opts::PrintPseudoProbesOptions::PPP_All || |
| 624 | opts::PrintPseudoProbes == |
| 625 | opts::PrintPseudoProbesOptions::PPP_Probes_Section_Decode) { |
| 626 | outs() << "Report of decoding input pseudo probe binaries \n"; |
James Luo | 8a91959 | 2021-06-11 20:06:12 | [diff] [blame] | 627 | BC->ProbeDecoder.printGUID2FuncDescMap(outs()); |
| 628 | BC->ProbeDecoder.printProbesForAllAddresses(outs()); |
| 629 | } |
| 630 | } |
| 631 | |
Laith Saed Sakka | 4755825 | 2019-05-16 00:19:18 | [diff] [blame] | 632 | void RewriteInstance::printSDTMarkers() { |
| 633 | outs() << "BOLT-INFO: Number of SDT markers is " << BC->SDTMarkers.size() |
| 634 | << "\n"; |
Laith Saed Sakka | ca659e4 | 2019-05-16 19:46:32 | [diff] [blame] | 635 | for (auto It : BC->SDTMarkers) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 636 | SDTMarkerInfo &Marker = It.second; |
Laith Saed Sakka | 4755825 | 2019-05-16 00:19:18 | [diff] [blame] | 637 | outs() << "BOLT-INFO: PC: " << utohexstr(Marker.PC) |
| 638 | << ", Base: " << utohexstr(Marker.Base) |
| 639 | << ", Semaphore: " << utohexstr(Marker.Semaphore) |
| 640 | << ", Provider: " << Marker.Provider << ", Name: " << Marker.Name |
| 641 | << ", Args: " << Marker.Args << "\n"; |
| 642 | } |
| 643 | } |
| 644 | |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 645 | void RewriteInstance::parseBuildID() { |
| 646 | if (!BuildIDSection) |
| 647 | return; |
Rafael Auler | 0ed144a | 2017-10-06 21:42:46 | [diff] [blame] | 648 | |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 649 | StringRef Buf = BuildIDSection->getContents(); |
Rafael Auler | 0ed144a | 2017-10-06 21:42:46 | [diff] [blame] | 650 | |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 651 | // Reading notes section (see Portable Formats Specification, Version 1.1, |
| 652 | // pg 2-5, section "Note Section"). |
| 653 | DataExtractor DE = DataExtractor(Buf, true, 8); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 654 | uint64_t Offset = 0; |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 655 | if (!DE.isValidOffset(Offset)) |
| 656 | return; |
| 657 | uint32_t NameSz = DE.getU32(&Offset); |
| 658 | if (!DE.isValidOffset(Offset)) |
| 659 | return; |
| 660 | uint32_t DescSz = DE.getU32(&Offset); |
| 661 | if (!DE.isValidOffset(Offset)) |
| 662 | return; |
| 663 | uint32_t Type = DE.getU32(&Offset); |
Rafael Auler | 0ed144a | 2017-10-06 21:42:46 | [diff] [blame] | 664 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 665 | LLVM_DEBUG(dbgs() << "NameSz = " << NameSz << "; DescSz = " << DescSz |
| 666 | << "; Type = " << Type << "\n"); |
Rafael Auler | 0ed144a | 2017-10-06 21:42:46 | [diff] [blame] | 667 | |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 668 | // Type 3 is a GNU build-id note section |
| 669 | if (Type != 3) |
| 670 | return; |
Rafael Auler | 0ed144a | 2017-10-06 21:42:46 | [diff] [blame] | 671 | |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 672 | StringRef Name = Buf.slice(Offset, Offset + NameSz); |
| 673 | Offset = alignTo(Offset + NameSz, 4); |
| 674 | if (Name.substr(0, 3) != "GNU") |
| 675 | return; |
Rafael Auler | 0ed144a | 2017-10-06 21:42:46 | [diff] [blame] | 676 | |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 677 | BuildID = Buf.slice(Offset, Offset + DescSz); |
| 678 | } |
Rafael Auler | 0ed144a | 2017-10-06 21:42:46 | [diff] [blame] | 679 | |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 680 | Optional<std::string> RewriteInstance::getPrintableBuildID() const { |
| 681 | if (BuildID.empty()) |
| 682 | return NoneType(); |
| 683 | |
| 684 | std::string Str; |
| 685 | raw_string_ostream OS(Str); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 686 | const unsigned char *CharIter = BuildID.bytes_begin(); |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 687 | while (CharIter != BuildID.bytes_end()) { |
| 688 | if (*CharIter < 0x10) |
| 689 | OS << "0"; |
| 690 | OS << Twine::utohexstr(*CharIter); |
| 691 | ++CharIter; |
Rafael Auler | 0ed144a | 2017-10-06 21:42:46 | [diff] [blame] | 692 | } |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 693 | return OS.str(); |
| 694 | } |
| 695 | |
| 696 | void RewriteInstance::patchBuildID() { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 697 | raw_fd_ostream &OS = Out->os(); |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 698 | |
| 699 | if (BuildID.empty()) |
| 700 | return; |
| 701 | |
| 702 | size_t IDOffset = BuildIDSection->getContents().rfind(BuildID); |
| 703 | assert(IDOffset != StringRef::npos && "failed to patch build-id"); |
| 704 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 705 | uint64_t FileOffset = getFileOffsetForAddress(BuildIDSection->getAddress()); |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 706 | if (!FileOffset) { |
| 707 | errs() << "BOLT-WARNING: Non-allocatable build-id will not be updated.\n"; |
| 708 | return; |
| 709 | } |
| 710 | |
| 711 | char LastIDByte = BuildID[BuildID.size() - 1]; |
| 712 | LastIDByte ^= 1; |
| 713 | OS.pwrite(&LastIDByte, 1, FileOffset + IDOffset + BuildID.size() - 1); |
| 714 | |
| 715 | outs() << "BOLT-INFO: patched build-id (flipped last bit)\n"; |
Rafael Auler | 0ed144a | 2017-10-06 21:42:46 | [diff] [blame] | 716 | } |
| 717 | |
Amir Ayupov | af6e66f | 2022-02-24 03:30:30 | [diff] [blame] | 718 | Error RewriteInstance::run() { |
| 719 | assert(BC && "failed to create a binary context"); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 720 | |
Rafael Auler | 787db1c | 2017-07-25 16:11:42 | [diff] [blame] | 721 | outs() << "BOLT-INFO: Target architecture: " |
| 722 | << Triple::getArchTypeName( |
| 723 | (llvm::Triple::ArchType)InputFile->getArch()) |
| 724 | << "\n"; |
Rafael Auler | d7fb998 | 2020-10-05 19:41:03 | [diff] [blame] | 725 | outs() << "BOLT-INFO: BOLT version: " << BoltRevision << "\n"; |
Rafael Auler | 787db1c | 2017-07-25 16:11:42 | [diff] [blame] | 726 | |
Amir Ayupov | af6e66f | 2022-02-24 03:30:30 | [diff] [blame] | 727 | if (Error E = discoverStorage()) |
| 728 | return E; |
Amir Ayupov | ced5472 | 2022-03-08 17:12:19 | [diff] [blame] | 729 | if (Error E = readSpecialSections()) |
| 730 | return E; |
Maksim Panchenko | e9c6c73 | 2019-09-11 22:42:22 | [diff] [blame] | 731 | adjustCommandLineOptions(); |
| 732 | discoverFileObjects(); |
| 733 | |
Rafael Auler | e3898d5 | 2020-12-30 20:23:58 | [diff] [blame] | 734 | preprocessProfileData(); |
| 735 | |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 736 | // Skip disassembling if we have a translation table and we are running an |
| 737 | // aggregation job. |
| 738 | if (opts::AggregateOnly && BAT->enabledFor(InputFile)) { |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 739 | processProfileData(); |
Amir Ayupov | af6e66f | 2022-02-24 03:30:30 | [diff] [blame] | 740 | return Error::success(); |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 741 | } |
Maksim Panchenko | e9c6c73 | 2019-09-11 22:42:22 | [diff] [blame] | 742 | |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 743 | selectFunctionsToProcess(); |
| 744 | |
Maksim Panchenko | e9c6c73 | 2019-09-11 22:42:22 | [diff] [blame] | 745 | readDebugInfo(); |
| 746 | |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 747 | disassembleFunctions(); |
Maksim Panchenko | e9c6c73 | 2019-09-11 22:42:22 | [diff] [blame] | 748 | |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 749 | processProfileDataPreCFG(); |
| 750 | |
| 751 | buildFunctionsCFG(); |
Maksim Panchenko | e9c6c73 | 2019-09-11 22:42:22 | [diff] [blame] | 752 | |
| 753 | processProfileData(); |
| 754 | |
Maksim Panchenko | e9c6c73 | 2019-09-11 22:42:22 | [diff] [blame] | 755 | postProcessFunctions(); |
Maksim Panchenko | 4349b63 | 2016-03-31 23:38:49 | [diff] [blame] | 756 | |
Maksim Panchenko | e9c6c73 | 2019-09-11 22:42:22 | [diff] [blame] | 757 | if (opts::DiffOnly) |
Amir Ayupov | af6e66f | 2022-02-24 03:30:30 | [diff] [blame] | 758 | return Error::success(); |
Gabriel Poesia | f6c8929 | 2016-04-12 00:46:18 | [diff] [blame] | 759 | |
Maksim Panchenko | e9c6c73 | 2019-09-11 22:42:22 | [diff] [blame] | 760 | runOptimizationPasses(); |
| 761 | |
| 762 | emitAndLink(); |
| 763 | |
Maksim Panchenko | f2b257b | 2019-11-04 05:57:15 | [diff] [blame] | 764 | updateMetadata(); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 765 | |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 766 | if (opts::LinuxKernelMode) { |
| 767 | errs() << "BOLT-WARNING: not writing the output file for Linux Kernel\n"; |
Amir Ayupov | af6e66f | 2022-02-24 03:30:30 | [diff] [blame] | 768 | return Error::success(); |
Amir Ayupov | 081e39a | 2021-03-29 23:04:57 | [diff] [blame] | 769 | } else if (opts::OutputFilename == "/dev/null") { |
| 770 | outs() << "BOLT-INFO: skipping writing final binary to disk\n"; |
Amir Ayupov | af6e66f | 2022-02-24 03:30:30 | [diff] [blame] | 771 | return Error::success(); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 772 | } |
| 773 | |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 774 | // Rewrite allocatable contents and copy non-allocatable parts with mods. |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 775 | rewriteFile(); |
Amir Ayupov | af6e66f | 2022-02-24 03:30:30 | [diff] [blame] | 776 | return Error::success(); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 777 | } |
| 778 | |
Maksim Panchenko | e7e9e15 | 2016-03-11 19:09:34 | [diff] [blame] | 779 | void RewriteInstance::discoverFileObjects() { |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 780 | NamedRegionTimer T("discoverFileObjects", "discover file objects", |
| 781 | TimerGroupName, TimerGroupDesc, opts::TimeRewrite); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 782 | FileSymRefs.clear(); |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 783 | BC->getBinaryFunctions().clear(); |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 784 | BC->clearBinaryData(); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 785 | |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 786 | // For local symbols we want to keep track of associated FILE symbol name for |
| 787 | // disambiguation by combined name. |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 788 | StringRef FileSymbolName; |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 789 | bool SeenFileName = false; |
| 790 | struct SymbolRefHash { |
Maksim Panchenko | ee0371a | 2020-04-07 07:21:37 | [diff] [blame] | 791 | size_t operator()(SymbolRef const &S) const { |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 792 | return std::hash<decltype(DataRefImpl::p)>{}(S.getRawDataRefImpl().p); |
| 793 | } |
| 794 | }; |
| 795 | std::unordered_map<SymbolRef, StringRef, SymbolRefHash> SymbolToFileName; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 796 | for (const ELFSymbolRef &Symbol : InputFile->symbols()) { |
| 797 | Expected<StringRef> NameOrError = Symbol.getName(); |
Maksim Panchenko | 6b0b5bb | 2017-02-07 23:56:00 | [diff] [blame] | 798 | if (NameOrError && NameOrError->startswith("__asan_init")) { |
| 799 | errs() << "BOLT-ERROR: input file was compiled or linked with sanitizer " |
| 800 | "support. Cannot optimize.\n"; |
| 801 | exit(1); |
| 802 | } |
Maksim Panchenko | f7d32f7 | 2017-03-31 14:51:30 | [diff] [blame] | 803 | if (NameOrError && NameOrError->startswith("__llvm_coverage_mapping")) { |
| 804 | errs() << "BOLT-ERROR: input file was compiled or linked with coverage " |
| 805 | "support. Cannot optimize.\n"; |
| 806 | exit(1); |
| 807 | } |
Maksim Panchenko | 6b0b5bb | 2017-02-07 23:56:00 | [diff] [blame] | 808 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 809 | if (cantFail(Symbol.getFlags()) & SymbolRef::SF_Undefined) |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 810 | continue; |
| 811 | |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 812 | if (cantFail(Symbol.getType()) == SymbolRef::ST_File) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 813 | StringRef Name = |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 814 | cantFail(std::move(NameOrError), "cannot get symbol name for file"); |
Maksim Panchenko | f32784f | 2017-09-26 01:05:37 | [diff] [blame] | 815 | // Ignore Clang LTO artificial FILE symbol as it is not always generated, |
| 816 | // and this uncertainty is causing havoc in function name matching. |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 817 | if (Name == "ld-temp.o") |
Maksim Panchenko | f32784f | 2017-09-26 01:05:37 | [diff] [blame] | 818 | continue; |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 819 | FileSymbolName = Name; |
Maksim Panchenko | 84b5b9e | 2016-07-12 01:51:13 | [diff] [blame] | 820 | SeenFileName = true; |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 821 | continue; |
| 822 | } |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 823 | if (!FileSymbolName.empty() && |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 824 | !(cantFail(Symbol.getFlags()) & SymbolRef::SF_Global)) |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 825 | SymbolToFileName[Symbol] = FileSymbolName; |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 826 | } |
| 827 | |
Maksim Panchenko | 53b72d0f | 2018-09-05 21:36:52 | [diff] [blame] | 828 | // Sort symbols in the file by value. Ignore symbols from non-allocatable |
| 829 | // sections. |
| 830 | auto isSymbolInMemory = [this](const SymbolRef &Sym) { |
| 831 | if (cantFail(Sym.getType()) == SymbolRef::ST_File) |
| 832 | return false; |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 833 | if (cantFail(Sym.getFlags()) & SymbolRef::SF_Absolute) |
Maksim Panchenko | 53b72d0f | 2018-09-05 21:36:52 | [diff] [blame] | 834 | return true; |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 835 | if (cantFail(Sym.getFlags()) & SymbolRef::SF_Undefined) |
Maksim Panchenko | 53b72d0f | 2018-09-05 21:36:52 | [diff] [blame] | 836 | return false; |
| 837 | BinarySection Section(*BC, *cantFail(Sym.getSection())); |
| 838 | return Section.isAllocatable(); |
| 839 | }; |
| 840 | std::vector<SymbolRef> SortedFileSymbols; |
Amir Ayupov | d2c8769 | 2022-06-24 05:15:47 | [diff] [blame^] | 841 | llvm::copy_if(InputFile->symbols(), std::back_inserter(SortedFileSymbols), |
| 842 | isSymbolInMemory); |
Denis Revunov | 8579db9 | 2022-05-31 18:50:59 | [diff] [blame] | 843 | auto CompareSymbols = [this](const SymbolRef &A, const SymbolRef &B) { |
| 844 | // Marker symbols have the highest precedence, while |
| 845 | // SECTIONs have the lowest. |
| 846 | auto AddressA = cantFail(A.getAddress()); |
| 847 | auto AddressB = cantFail(B.getAddress()); |
| 848 | if (AddressA != AddressB) |
| 849 | return AddressA < AddressB; |
Maksim Panchenko | 53b72d0f | 2018-09-05 21:36:52 | [diff] [blame] | 850 | |
Denis Revunov | 8579db9 | 2022-05-31 18:50:59 | [diff] [blame] | 851 | bool AMarker = BC->isMarker(A); |
| 852 | bool BMarker = BC->isMarker(B); |
| 853 | if (AMarker || BMarker) { |
| 854 | return AMarker && !BMarker; |
| 855 | } |
Maksim Panchenko | 99ef4c9 | 2019-04-16 17:24:34 | [diff] [blame] | 856 | |
Denis Revunov | 8579db9 | 2022-05-31 18:50:59 | [diff] [blame] | 857 | auto AType = cantFail(A.getType()); |
| 858 | auto BType = cantFail(B.getType()); |
| 859 | if (AType == SymbolRef::ST_Function && BType != SymbolRef::ST_Function) |
| 860 | return true; |
| 861 | if (BType == SymbolRef::ST_Debug && AType != SymbolRef::ST_Debug) |
| 862 | return true; |
Maksim Panchenko | 99ef4c9 | 2019-04-16 17:24:34 | [diff] [blame] | 863 | |
Denis Revunov | 8579db9 | 2022-05-31 18:50:59 | [diff] [blame] | 864 | return false; |
| 865 | }; |
| 866 | |
Amir Ayupov | d2c8769 | 2022-06-24 05:15:47 | [diff] [blame^] | 867 | llvm::stable_sort(SortedFileSymbols, CompareSymbols); |
Denis Revunov | 8579db9 | 2022-05-31 18:50:59 | [diff] [blame] | 868 | |
| 869 | auto LastSymbol = SortedFileSymbols.end() - 1; |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 870 | |
Rafael Auler | 907ca25 | 2017-11-23 00:17:36 | [diff] [blame] | 871 | // For aarch64, the ABI defines mapping symbols so we identify data in the |
| 872 | // code section (see IHI0056B). $d identifies data contents. |
Denis Revunov | 8579db9 | 2022-05-31 18:50:59 | [diff] [blame] | 873 | // Compilers usually merge multiple data objects in a single $d-$x interval, |
| 874 | // but we need every data object to be marked with $d. Because of that we |
| 875 | // create a vector of MarkerSyms with all locations of data objects. |
| 876 | |
| 877 | struct MarkerSym { |
| 878 | uint64_t Address; |
| 879 | MarkerSymType Type; |
| 880 | }; |
| 881 | |
| 882 | std::vector<MarkerSym> SortedMarkerSymbols; |
| 883 | auto addExtraDataMarkerPerSymbol = |
| 884 | [this](const std::vector<SymbolRef> &SortedFileSymbols, |
| 885 | std::vector<MarkerSym> &SortedMarkerSymbols) { |
| 886 | bool IsData = false; |
| 887 | uint64_t LastAddr = 0; |
| 888 | for (auto Sym = SortedFileSymbols.begin(); |
| 889 | Sym < SortedFileSymbols.end(); ++Sym) { |
| 890 | uint64_t Address = cantFail(Sym->getAddress()); |
| 891 | if (LastAddr == Address) // don't repeat markers |
| 892 | continue; |
| 893 | |
| 894 | MarkerSymType MarkerType = BC->getMarkerType(*Sym); |
| 895 | if (MarkerType != MarkerSymType::NONE) { |
| 896 | SortedMarkerSymbols.push_back(MarkerSym{Address, MarkerType}); |
| 897 | LastAddr = Address; |
| 898 | IsData = MarkerType == MarkerSymType::DATA; |
| 899 | continue; |
| 900 | } |
| 901 | |
| 902 | if (IsData) { |
| 903 | SortedMarkerSymbols.push_back( |
| 904 | MarkerSym{cantFail(Sym->getAddress()), MarkerSymType::DATA}); |
| 905 | LastAddr = Address; |
| 906 | } |
| 907 | } |
| 908 | }; |
| 909 | |
Rafael Auler | 7df6a6d | 2018-03-20 21:34:58 | [diff] [blame] | 910 | if (BC->isAArch64()) { |
Denis Revunov | 8579db9 | 2022-05-31 18:50:59 | [diff] [blame] | 911 | addExtraDataMarkerPerSymbol(SortedFileSymbols, SortedMarkerSymbols); |
Maksim Panchenko | 8c6ea85 | 2019-10-08 18:03:33 | [diff] [blame] | 912 | LastSymbol = std::stable_partition( |
Rafael Auler | 907ca25 | 2017-11-23 00:17:36 | [diff] [blame] | 913 | SortedFileSymbols.begin(), SortedFileSymbols.end(), |
Denis Revunov | 8579db9 | 2022-05-31 18:50:59 | [diff] [blame] | 914 | [this](const SymbolRef &Symbol) { return !BC->isMarker(Symbol); }); |
Maksim Panchenko | 8c6ea85 | 2019-10-08 18:03:33 | [diff] [blame] | 915 | --LastSymbol; |
Rafael Auler | 907ca25 | 2017-11-23 00:17:36 | [diff] [blame] | 916 | } |
| 917 | |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 918 | BinaryFunction *PreviousFunction = nullptr; |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 919 | unsigned AnonymousId = 0; |
| 920 | |
Denis Revunov | 8579db9 | 2022-05-31 18:50:59 | [diff] [blame] | 921 | const auto SortedSymbolsEnd = std::next(LastSymbol); |
| 922 | for (auto ISym = SortedFileSymbols.begin(); ISym != SortedSymbolsEnd; |
| 923 | ++ISym) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 924 | const SymbolRef &Symbol = *ISym; |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 925 | // Keep undefined symbols for pretty printing? |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 926 | if (cantFail(Symbol.getFlags()) & SymbolRef::SF_Undefined) |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 927 | continue; |
| 928 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 929 | const SymbolRef::Type SymbolType = cantFail(Symbol.getType()); |
Maksim Panchenko | 8c6ea85 | 2019-10-08 18:03:33 | [diff] [blame] | 930 | |
| 931 | if (SymbolType == SymbolRef::ST_File) |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 932 | continue; |
| 933 | |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 934 | StringRef SymName = cantFail(Symbol.getName(), "cannot get symbol name"); |
| 935 | uint64_t Address = |
| 936 | cantFail(Symbol.getAddress(), "cannot get symbol address"); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 937 | if (Address == 0) { |
Maksim Panchenko | 8c6ea85 | 2019-10-08 18:03:33 | [diff] [blame] | 938 | if (opts::Verbosity >= 1 && SymbolType == SymbolRef::ST_Function) |
Maksim Panchenko | d152608 | 2016-02-05 22:42:04 | [diff] [blame] | 939 | errs() << "BOLT-WARNING: function with 0 address seen\n"; |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 940 | continue; |
| 941 | } |
| 942 | |
Rafael Auler | e4396c4 | 2020-10-17 07:50:27 | [diff] [blame] | 943 | // Ignore input hot markers |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 944 | if (SymName == "__hot_start" || SymName == "__hot_end") |
Rafael Auler | e4396c4 | 2020-10-17 07:50:27 | [diff] [blame] | 945 | continue; |
Rafael Auler | e4396c4 | 2020-10-17 07:50:27 | [diff] [blame] | 946 | |
Rafael Auler | 907ca25 | 2017-11-23 00:17:36 | [diff] [blame] | 947 | FileSymRefs[Address] = Symbol; |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 948 | |
Maksim Panchenko | c9f5f47 | 2021-06-30 21:41:41 | [diff] [blame] | 949 | // Skip section symbols that will be registered by disassemblePLT(). |
| 950 | if ((cantFail(Symbol.getType()) == SymbolRef::ST_Debug)) { |
| 951 | ErrorOr<BinarySection &> BSection = BC->getSectionForAddress(Address); |
| 952 | if (BSection && getPLTSectionInfo(BSection->getName())) |
| 953 | continue; |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 954 | } |
| 955 | |
Maksim Panchenko | 84b5b9e | 2016-07-12 01:51:13 | [diff] [blame] | 956 | /// It is possible we are seeing a globalized local. LLVM might treat it as |
| 957 | /// a local if it has a "private global" prefix, e.g. ".L". Thus we have to |
| 958 | /// change the prefix to enforce global scope of the symbol. |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 959 | std::string Name = SymName.startswith(BC->AsmInfo->getPrivateGlobalPrefix()) |
| 960 | ? "PG" + std::string(SymName) |
| 961 | : std::string(SymName); |
Maksim Panchenko | 84b5b9e | 2016-07-12 01:51:13 | [diff] [blame] | 962 | |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 963 | // Disambiguate all local symbols before adding to symbol table. |
Maksim Panchenko | 84b5b9e | 2016-07-12 01:51:13 | [diff] [blame] | 964 | // Since we don't know if we will see a global with the same name, |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 965 | // always modify the local name. |
Maksim Panchenko | 84b5b9e | 2016-07-12 01:51:13 | [diff] [blame] | 966 | // |
| 967 | // NOTE: the naming convention for local symbols should match |
| 968 | // the one we use for profile data. |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 969 | std::string UniqueName; |
Maksim Panchenko | 84b5b9e | 2016-07-12 01:51:13 | [diff] [blame] | 970 | std::string AlternativeName; |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 971 | if (Name.empty()) { |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 972 | UniqueName = "ANONYMOUS." + std::to_string(AnonymousId++); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 973 | } else if (cantFail(Symbol.getFlags()) & SymbolRef::SF_Global) { |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 974 | assert(!BC->getBinaryDataByName(Name) && "global name not unique"); |
Maksim Panchenko | 84b5b9e | 2016-07-12 01:51:13 | [diff] [blame] | 975 | UniqueName = Name; |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 976 | } else { |
Maksim Panchenko | 84b5b9e | 2016-07-12 01:51:13 | [diff] [blame] | 977 | // If we have a local file name, we should create 2 variants for the |
| 978 | // function name. The reason is that perf profile might have been |
| 979 | // collected on a binary that did not have the local file name (e.g. as |
| 980 | // a side effect of stripping debug info from the binary): |
| 981 | // |
| 982 | // primary: <function>/<id> |
| 983 | // alternative: <function>/<file>/<id2> |
| 984 | // |
| 985 | // The <id> field is used for disambiguation of local symbols since there |
| 986 | // could be identical function names coming from identical file names |
| 987 | // (e.g. from different directories). |
Maksim Panchenko | 84b5b9e | 2016-07-12 01:51:13 | [diff] [blame] | 988 | std::string AltPrefix; |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 989 | auto SFI = SymbolToFileName.find(Symbol); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 990 | if (SymbolType == SymbolRef::ST_Function && SFI != SymbolToFileName.end()) |
Maksim Panchenko | 8c6ea85 | 2019-10-08 18:03:33 | [diff] [blame] | 991 | AltPrefix = Name + "/" + std::string(SFI->second); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 992 | |
Alexander Shaposhnikov | 16630f5 | 2020-02-17 22:37:46 | [diff] [blame] | 993 | UniqueName = NR.uniquify(Name); |
Maksim Panchenko | 84b5b9e | 2016-07-12 01:51:13 | [diff] [blame] | 994 | if (!AltPrefix.empty()) |
Alexander Shaposhnikov | 16630f5 | 2020-02-17 22:37:46 | [diff] [blame] | 995 | AlternativeName = NR.uniquify(AltPrefix); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 996 | } |
| 997 | |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 998 | uint64_t SymbolSize = ELFSymbolRef(Symbol).getSize(); |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 999 | uint64_t SymbolAlignment = Symbol.getAlignment(); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1000 | unsigned SymbolFlags = cantFail(Symbol.getFlags()); |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 1001 | |
| 1002 | auto registerName = [&](uint64_t FinalSize) { |
| 1003 | // Register names even if it's not a function, e.g. for an entry point. |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 1004 | BC->registerNameAtAddress(UniqueName, Address, FinalSize, SymbolAlignment, |
| 1005 | SymbolFlags); |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 1006 | if (!AlternativeName.empty()) |
| 1007 | BC->registerNameAtAddress(AlternativeName, Address, FinalSize, |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 1008 | SymbolAlignment, SymbolFlags); |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 1009 | }; |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 1010 | |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 1011 | section_iterator Section = |
| 1012 | cantFail(Symbol.getSection(), "cannot get symbol section"); |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 1013 | if (Section == InputFile->section_end()) { |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 1014 | // Could be an absolute symbol. Could record for pretty printing. |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1015 | LLVM_DEBUG(if (opts::Verbosity > 1) { |
| 1016 | dbgs() << "BOLT-INFO: absolute sym " << UniqueName << "\n"; |
| 1017 | }); |
Maksim Panchenko | b11c826 | 2021-03-15 19:06:56 | [diff] [blame] | 1018 | registerName(SymbolSize); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 1019 | continue; |
| 1020 | } |
| 1021 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1022 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: considering symbol " << UniqueName |
| 1023 | << " for function\n"); |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1024 | |
| 1025 | if (!Section->isText()) { |
Maksim Panchenko | 8c6ea85 | 2019-10-08 18:03:33 | [diff] [blame] | 1026 | assert(SymbolType != SymbolRef::ST_Function && |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1027 | "unexpected function inside non-code section"); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1028 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: rejecting as symbol is not in code\n"); |
Maksim Panchenko | b11c826 | 2021-03-15 19:06:56 | [diff] [blame] | 1029 | registerName(SymbolSize); |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1030 | continue; |
| 1031 | } |
| 1032 | |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1033 | // Assembly functions could be ST_NONE with 0 size. Check that the |
| 1034 | // corresponding section is a code section and they are not inside any |
| 1035 | // other known function to consider them. |
| 1036 | // |
| 1037 | // Sometimes assembly functions are not marked as functions and neither are |
| 1038 | // their local labels. The only way to tell them apart is to look at |
| 1039 | // symbol scope - global vs local. |
Maksim Panchenko | 8c6ea85 | 2019-10-08 18:03:33 | [diff] [blame] | 1040 | if (PreviousFunction && SymbolType != SymbolRef::ST_Function) { |
| 1041 | if (PreviousFunction->containsAddress(Address)) { |
| 1042 | if (PreviousFunction->isSymbolValidInScope(Symbol, SymbolSize)) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1043 | LLVM_DEBUG(dbgs() |
| 1044 | << "BOLT-DEBUG: symbol is a function local symbol\n"); |
Maksim Panchenko | 8c6ea85 | 2019-10-08 18:03:33 | [diff] [blame] | 1045 | } else if (Address == PreviousFunction->getAddress() && !SymbolSize) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1046 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: ignoring symbol as a marker\n"); |
Maksim Panchenko | 8c6ea85 | 2019-10-08 18:03:33 | [diff] [blame] | 1047 | } else if (opts::Verbosity > 1) { |
| 1048 | errs() << "BOLT-WARNING: symbol " << UniqueName |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1049 | << " seen in the middle of function " << *PreviousFunction |
| 1050 | << ". Could be a new entry.\n"; |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1051 | } |
Maksim Panchenko | 8c6ea85 | 2019-10-08 18:03:33 | [diff] [blame] | 1052 | registerName(SymbolSize); |
| 1053 | continue; |
| 1054 | } else if (PreviousFunction->getSize() == 0 && |
| 1055 | PreviousFunction->isSymbolValidInScope(Symbol, SymbolSize)) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1056 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: symbol is a function local symbol\n"); |
Maksim Panchenko | 8c6ea85 | 2019-10-08 18:03:33 | [diff] [blame] | 1057 | registerName(SymbolSize); |
| 1058 | continue; |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1059 | } |
| 1060 | } |
| 1061 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 1062 | if (PreviousFunction && PreviousFunction->containsAddress(Address) && |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1063 | PreviousFunction->getAddress() != Address) { |
| 1064 | if (PreviousFunction->isSymbolValidInScope(Symbol, SymbolSize)) { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1065 | if (opts::Verbosity >= 1) |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1066 | outs() << "BOLT-INFO: skipping possibly another entry for function " |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1067 | << *PreviousFunction << " : " << UniqueName << '\n'; |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1068 | } else { |
| 1069 | outs() << "BOLT-INFO: using " << UniqueName << " as another entry to " |
| 1070 | << "function " << *PreviousFunction << '\n'; |
| 1071 | |
Maksim Panchenko | 4946b88 | 2020-06-22 23:16:08 | [diff] [blame] | 1072 | registerName(0); |
| 1073 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 1074 | PreviousFunction->addEntryPointAtOffset(Address - |
| 1075 | PreviousFunction->getAddress()); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1076 | |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1077 | // Remove the symbol from FileSymRefs so that we can skip it from |
| 1078 | // in the future. |
| 1079 | auto SI = FileSymRefs.find(Address); |
| 1080 | assert(SI != FileSymRefs.end() && "symbol expected to be present"); |
| 1081 | assert(SI->second == Symbol && "wrong symbol found"); |
| 1082 | FileSymRefs.erase(SI); |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1083 | } |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 1084 | registerName(SymbolSize); |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1085 | continue; |
| 1086 | } |
| 1087 | |
Maksim Panchenko | e7e9e15 | 2016-03-11 19:09:34 | [diff] [blame] | 1088 | // Checkout for conflicts with function data from FDEs. |
| 1089 | bool IsSimple = true; |
| 1090 | auto FDEI = CFIRdWrt->getFDEs().lower_bound(Address); |
| 1091 | if (FDEI != CFIRdWrt->getFDEs().end()) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1092 | const dwarf::FDE &FDE = *FDEI->second; |
Maksim Panchenko | e7e9e15 | 2016-03-11 19:09:34 | [diff] [blame] | 1093 | if (FDEI->first != Address) { |
| 1094 | // There's no matching starting address in FDE. Make sure the previous |
| 1095 | // FDE does not contain this address. |
| 1096 | if (FDEI != CFIRdWrt->getFDEs().begin()) { |
| 1097 | --FDEI; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1098 | const dwarf::FDE &PrevFDE = *FDEI->second; |
| 1099 | uint64_t PrevStart = PrevFDE.getInitialLocation(); |
| 1100 | uint64_t PrevLength = PrevFDE.getAddressRange(); |
Maksim Panchenko | c4e36c1 | 2016-09-15 22:47:10 | [diff] [blame] | 1101 | if (Address > PrevStart && Address < PrevStart + PrevLength) { |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1102 | errs() << "BOLT-ERROR: function " << UniqueName |
| 1103 | << " is in conflict with FDE [" |
| 1104 | << Twine::utohexstr(PrevStart) << ", " |
| 1105 | << Twine::utohexstr(PrevStart + PrevLength) |
| 1106 | << "). Skipping.\n"; |
Maksim Panchenko | e7e9e15 | 2016-03-11 19:09:34 | [diff] [blame] | 1107 | IsSimple = false; |
| 1108 | } |
| 1109 | } |
| 1110 | } else if (FDE.getAddressRange() != SymbolSize) { |
Maksim Panchenko | c4e36c1 | 2016-09-15 22:47:10 | [diff] [blame] | 1111 | if (SymbolSize) { |
| 1112 | // Function addresses match but sizes differ. |
Maksim Panchenko | 4b485f4 | 2017-06-03 01:41:31 | [diff] [blame] | 1113 | errs() << "BOLT-WARNING: sizes differ for function " << UniqueName |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1114 | << ". FDE : " << FDE.getAddressRange() |
Maksim Panchenko | 4b485f4 | 2017-06-03 01:41:31 | [diff] [blame] | 1115 | << "; symbol table : " << SymbolSize << ". Using max size.\n"; |
Maksim Panchenko | c4e36c1 | 2016-09-15 22:47:10 | [diff] [blame] | 1116 | } |
Maksim Panchenko | e7e9e15 | 2016-03-11 19:09:34 | [diff] [blame] | 1117 | SymbolSize = std::max(SymbolSize, FDE.getAddressRange()); |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 1118 | if (BC->getBinaryDataAtAddress(Address)) { |
| 1119 | BC->setBinaryDataSize(Address, SymbolSize); |
| 1120 | } else { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1121 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: No BD @ 0x" |
| 1122 | << Twine::utohexstr(Address) << "\n"); |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 1123 | } |
Maksim Panchenko | e7e9e15 | 2016-03-11 19:09:34 | [diff] [blame] | 1124 | } |
| 1125 | } |
Rafael Auler | 31fc56b | 2019-04-16 21:35:29 | [diff] [blame] | 1126 | |
Maksim Panchenko | fe37f18 | 2021-05-13 17:50:47 | [diff] [blame] | 1127 | BinaryFunction *BF = nullptr; |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 1128 | // Since function may not have yet obtained its real size, do a search |
| 1129 | // using the list of registered functions instead of calling |
| 1130 | // getBinaryFunctionAtAddress(). |
| 1131 | auto BFI = BC->getBinaryFunctions().find(Address); |
| 1132 | if (BFI != BC->getBinaryFunctions().end()) { |
Maksim Panchenko | 003d106c | 2016-08-11 21:23:54 | [diff] [blame] | 1133 | BF = &BFI->second; |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 1134 | // Duplicate the function name. Make sure everything matches before we add |
Maksim Panchenko | f1192a7 | 2016-06-11 00:13:05 | [diff] [blame] | 1135 | // an alternative name. |
Maksim Panchenko | c4e36c1 | 2016-09-15 22:47:10 | [diff] [blame] | 1136 | if (SymbolSize != BF->getSize()) { |
| 1137 | if (opts::Verbosity >= 1) { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1138 | if (SymbolSize && BF->getSize()) |
Maksim Panchenko | c4e36c1 | 2016-09-15 22:47:10 | [diff] [blame] | 1139 | errs() << "BOLT-WARNING: size mismatch for duplicate entries " |
| 1140 | << *BF << " and " << UniqueName << '\n'; |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 1141 | outs() << "BOLT-INFO: adjusting size of function " << *BF << " old " |
| 1142 | << BF->getSize() << " new " << SymbolSize << "\n"; |
Maksim Panchenko | c4e36c1 | 2016-09-15 22:47:10 | [diff] [blame] | 1143 | } |
| 1144 | BF->setSize(std::max(SymbolSize, BF->getSize())); |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 1145 | BC->setBinaryDataSize(Address, BF->getSize()); |
Maksim Panchenko | f1192a7 | 2016-06-11 00:13:05 | [diff] [blame] | 1146 | } |
Maksim Panchenko | 003d106c | 2016-08-11 21:23:54 | [diff] [blame] | 1147 | BF->addAlternativeName(UniqueName); |
Maksim Panchenko | f1192a7 | 2016-06-11 00:13:05 | [diff] [blame] | 1148 | } else { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1149 | ErrorOr<BinarySection &> Section = BC->getSectionForAddress(Address); |
takh | 48b71ad | 2020-06-11 06:00:39 | [diff] [blame] | 1150 | // Skip symbols from invalid sections |
| 1151 | if (!Section) { |
| 1152 | errs() << "BOLT-WARNING: " << UniqueName << " (0x" |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 1153 | << Twine::utohexstr(Address) << ") does not have any section\n"; |
takh | 48b71ad | 2020-06-11 06:00:39 | [diff] [blame] | 1154 | continue; |
| 1155 | } |
Maksim Panchenko | 06e7a1e | 2019-06-27 10:20:17 | [diff] [blame] | 1156 | assert(Section && "section for functions must be registered"); |
Wenlei He | 459add2 | 2019-06-26 18:06:46 | [diff] [blame] | 1157 | |
Maksim Panchenko | 06e7a1e | 2019-06-27 10:20:17 | [diff] [blame] | 1158 | // Skip symbols from zero-sized sections. |
| 1159 | if (!Section->getSize()) |
Wenlei He | 459add2 | 2019-06-26 18:06:46 | [diff] [blame] | 1160 | continue; |
laith sakka | 7d42835 | 2019-07-12 14:25:50 | [diff] [blame] | 1161 | |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 1162 | BF = BC->createBinaryFunction(UniqueName, *Section, Address, SymbolSize); |
| 1163 | if (!IsSimple) |
| 1164 | BF->setSimple(false); |
Maksim Panchenko | f1192a7 | 2016-06-11 00:13:05 | [diff] [blame] | 1165 | } |
Maksim Panchenko | 84b5b9e | 2016-07-12 01:51:13 | [diff] [blame] | 1166 | if (!AlternativeName.empty()) |
Maksim Panchenko | 003d106c | 2016-08-11 21:23:54 | [diff] [blame] | 1167 | BF->addAlternativeName(AlternativeName); |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1168 | |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 1169 | registerName(SymbolSize); |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1170 | PreviousFunction = BF; |
Maksim Panchenko | 84b5b9e | 2016-07-12 01:51:13 | [diff] [blame] | 1171 | } |
| 1172 | |
Maksim Panchenko | 38c5887 | 2021-06-22 20:46:06 | [diff] [blame] | 1173 | // Read dynamic relocation first as their presence affects the way we process |
| 1174 | // static relocations. E.g. we will ignore a static relocation at an address |
| 1175 | // that is a subject to dynamic relocation processing. |
| 1176 | processDynamicRelocations(); |
| 1177 | |
Maksim Panchenko | 49d1f56 | 2017-08-04 18:21:05 | [diff] [blame] | 1178 | // Process PLT section. |
Vladislav Khmelevsky | 00b6efc | 2022-01-25 00:22:47 | [diff] [blame] | 1179 | disassemblePLT(); |
Maksim Panchenko | 49d1f56 | 2017-08-04 18:21:05 | [diff] [blame] | 1180 | |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1181 | // See if we missed any functions marked by FDE. |
| 1182 | for (const auto &FDEI : CFIRdWrt->getFDEs()) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1183 | const uint64_t Address = FDEI.first; |
| 1184 | const dwarf::FDE *FDE = FDEI.second; |
| 1185 | const BinaryFunction *BF = BC->getBinaryFunctionAtAddress(Address); |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 1186 | if (BF) |
| 1187 | continue; |
| 1188 | |
| 1189 | BF = BC->getBinaryFunctionContainingAddress(Address); |
| 1190 | if (BF) { |
| 1191 | errs() << "BOLT-WARNING: FDE [0x" << Twine::utohexstr(Address) << ", 0x" |
| 1192 | << Twine::utohexstr(Address + FDE->getAddressRange()) |
| 1193 | << ") conflicts with function " << *BF << '\n'; |
| 1194 | continue; |
Maksim Panchenko | 4b485f4 | 2017-06-03 01:41:31 | [diff] [blame] | 1195 | } |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 1196 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1197 | if (opts::Verbosity >= 1) |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 1198 | errs() << "BOLT-WARNING: FDE [0x" << Twine::utohexstr(Address) << ", 0x" |
| 1199 | << Twine::utohexstr(Address + FDE->getAddressRange()) |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 1200 | << ") has no corresponding symbol table entry\n"; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1201 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1202 | ErrorOr<BinarySection &> Section = BC->getSectionForAddress(Address); |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 1203 | assert(Section && "cannot get section for address from FDE"); |
| 1204 | std::string FunctionName = |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 1205 | "__BOLT_FDE_FUNCat" + Twine::utohexstr(Address).str(); |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 1206 | BC->createBinaryFunction(FunctionName, *Section, Address, |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 1207 | FDE->getAddressRange()); |
Maksim Panchenko | 4b485f4 | 2017-06-03 01:41:31 | [diff] [blame] | 1208 | } |
| 1209 | |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 1210 | BC->setHasSymbolsWithFileName(SeenFileName); |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1211 | |
| 1212 | // Now that all the functions were created - adjust their boundaries. |
| 1213 | adjustFunctionBoundaries(); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1214 | |
Rafael Auler | 907ca25 | 2017-11-23 00:17:36 | [diff] [blame] | 1215 | // Annotate functions with code/data markers in AArch64 |
Denis Revunov | 8579db9 | 2022-05-31 18:50:59 | [diff] [blame] | 1216 | for (auto ISym = SortedMarkerSymbols.begin(); |
| 1217 | ISym != SortedMarkerSymbols.end(); ++ISym) { |
| 1218 | |
| 1219 | auto *BF = |
| 1220 | BC->getBinaryFunctionContainingAddress(ISym->Address, true, true); |
| 1221 | |
Rafael Auler | 907ca25 | 2017-11-23 00:17:36 | [diff] [blame] | 1222 | if (!BF) { |
| 1223 | // Stray marker |
| 1224 | continue; |
| 1225 | } |
Denis Revunov | 8579db9 | 2022-05-31 18:50:59 | [diff] [blame] | 1226 | const auto EntryOffset = ISym->Address - BF->getAddress(); |
| 1227 | if (ISym->Type == MarkerSymType::CODE) { |
Rafael Auler | 907ca25 | 2017-11-23 00:17:36 | [diff] [blame] | 1228 | BF->markCodeAtOffset(EntryOffset); |
| 1229 | continue; |
| 1230 | } |
Denis Revunov | 8579db9 | 2022-05-31 18:50:59 | [diff] [blame] | 1231 | if (ISym->Type == MarkerSymType::DATA) { |
Rafael Auler | 907ca25 | 2017-11-23 00:17:36 | [diff] [blame] | 1232 | BF->markDataAtOffset(EntryOffset); |
Denis Revunov | 8579db9 | 2022-05-31 18:50:59 | [diff] [blame] | 1233 | BC->AddressToConstantIslandMap[ISym->Address] = BF; |
Rafael Auler | 907ca25 | 2017-11-23 00:17:36 | [diff] [blame] | 1234 | continue; |
| 1235 | } |
| 1236 | llvm_unreachable("Unknown marker"); |
| 1237 | } |
| 1238 | |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 1239 | if (opts::LinuxKernelMode) { |
| 1240 | // Read all special linux kernel sections and their relocations |
| 1241 | processLKSections(); |
| 1242 | } else { |
| 1243 | // Read all relocations now that we have binary functions mapped. |
| 1244 | processRelocations(); |
| 1245 | } |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1246 | } |
| 1247 | |
Vladislav Khmelevsky | 00b6efc | 2022-01-25 00:22:47 | [diff] [blame] | 1248 | void RewriteInstance::createPLTBinaryFunction(uint64_t TargetAddress, |
| 1249 | uint64_t EntryAddress, |
| 1250 | uint64_t EntrySize) { |
| 1251 | if (!TargetAddress) |
| 1252 | return; |
| 1253 | |
Vladislav Khmelevsky | 8bdbcfe | 2022-03-02 21:34:41 | [diff] [blame] | 1254 | auto setPLTSymbol = [&](BinaryFunction *BF, StringRef Name) { |
| 1255 | const unsigned PtrSize = BC->AsmInfo->getCodePointerSize(); |
| 1256 | MCSymbol *TargetSymbol = BC->registerNameAtAddress( |
| 1257 | Name.str() + "@GOT", TargetAddress, PtrSize, PtrSize); |
| 1258 | BF->setPLTSymbol(TargetSymbol); |
| 1259 | }; |
| 1260 | |
| 1261 | BinaryFunction *BF = BC->getBinaryFunctionAtAddress(EntryAddress); |
| 1262 | if (BF && BC->isAArch64()) { |
| 1263 | // Handle IFUNC trampoline |
| 1264 | setPLTSymbol(BF, BF->getOneName()); |
| 1265 | return; |
| 1266 | } |
| 1267 | |
Vladislav Khmelevsky | 00b6efc | 2022-01-25 00:22:47 | [diff] [blame] | 1268 | const Relocation *Rel = BC->getDynamicRelocationAt(TargetAddress); |
| 1269 | if (!Rel || !Rel->Symbol) |
| 1270 | return; |
| 1271 | |
Vladislav Khmelevsky | 00b6efc | 2022-01-25 00:22:47 | [diff] [blame] | 1272 | ErrorOr<BinarySection &> Section = BC->getSectionForAddress(EntryAddress); |
| 1273 | assert(Section && "cannot get section for address"); |
Vladislav Khmelevsky | 8bdbcfe | 2022-03-02 21:34:41 | [diff] [blame] | 1274 | BF = BC->createBinaryFunction(Rel->Symbol->getName().str() + "@PLT", *Section, |
| 1275 | EntryAddress, 0, EntrySize, |
| 1276 | Section->getAlignment()); |
| 1277 | setPLTSymbol(BF, Rel->Symbol->getName()); |
Vladislav Khmelevsky | 00b6efc | 2022-01-25 00:22:47 | [diff] [blame] | 1278 | } |
| 1279 | |
| 1280 | void RewriteInstance::disassemblePLTSectionAArch64(BinarySection &Section) { |
| 1281 | const uint64_t SectionAddress = Section.getAddress(); |
| 1282 | const uint64_t SectionSize = Section.getSize(); |
| 1283 | StringRef PLTContents = Section.getContents(); |
| 1284 | ArrayRef<uint8_t> PLTData( |
| 1285 | reinterpret_cast<const uint8_t *>(PLTContents.data()), SectionSize); |
| 1286 | |
| 1287 | auto disassembleInstruction = [&](uint64_t InstrOffset, MCInst &Instruction, |
| 1288 | uint64_t &InstrSize) { |
| 1289 | const uint64_t InstrAddr = SectionAddress + InstrOffset; |
| 1290 | if (!BC->DisAsm->getInstruction(Instruction, InstrSize, |
| 1291 | PLTData.slice(InstrOffset), InstrAddr, |
| 1292 | nulls())) { |
| 1293 | errs() << "BOLT-ERROR: unable to disassemble instruction in PLT section " |
| 1294 | << Section.getName() << " at offset 0x" |
| 1295 | << Twine::utohexstr(InstrOffset) << '\n'; |
| 1296 | exit(1); |
| 1297 | } |
| 1298 | }; |
| 1299 | |
| 1300 | uint64_t InstrOffset = 0; |
| 1301 | // Locate new plt entry |
| 1302 | while (InstrOffset < SectionSize) { |
| 1303 | InstructionListType Instructions; |
| 1304 | MCInst Instruction; |
| 1305 | uint64_t EntryOffset = InstrOffset; |
| 1306 | uint64_t EntrySize = 0; |
| 1307 | uint64_t InstrSize; |
| 1308 | // Loop through entry instructions |
| 1309 | while (InstrOffset < SectionSize) { |
| 1310 | disassembleInstruction(InstrOffset, Instruction, InstrSize); |
| 1311 | EntrySize += InstrSize; |
| 1312 | if (!BC->MIB->isIndirectBranch(Instruction)) { |
| 1313 | Instructions.emplace_back(Instruction); |
| 1314 | InstrOffset += InstrSize; |
| 1315 | continue; |
| 1316 | } |
| 1317 | |
| 1318 | const uint64_t EntryAddress = SectionAddress + EntryOffset; |
| 1319 | const uint64_t TargetAddress = BC->MIB->analyzePLTEntry( |
| 1320 | Instruction, Instructions.begin(), Instructions.end(), EntryAddress); |
| 1321 | |
| 1322 | createPLTBinaryFunction(TargetAddress, EntryAddress, EntrySize); |
| 1323 | break; |
| 1324 | } |
| 1325 | |
| 1326 | // Branch instruction |
| 1327 | InstrOffset += InstrSize; |
| 1328 | |
| 1329 | // Skip nops if any |
| 1330 | while (InstrOffset < SectionSize) { |
| 1331 | disassembleInstruction(InstrOffset, Instruction, InstrSize); |
| 1332 | if (!BC->MIB->isNoop(Instruction)) |
| 1333 | break; |
| 1334 | |
| 1335 | InstrOffset += InstrSize; |
| 1336 | } |
| 1337 | } |
| 1338 | } |
| 1339 | |
| 1340 | void RewriteInstance::disassemblePLTSectionX86(BinarySection &Section, |
| 1341 | uint64_t EntrySize) { |
| 1342 | const uint64_t SectionAddress = Section.getAddress(); |
| 1343 | const uint64_t SectionSize = Section.getSize(); |
| 1344 | StringRef PLTContents = Section.getContents(); |
| 1345 | ArrayRef<uint8_t> PLTData( |
| 1346 | reinterpret_cast<const uint8_t *>(PLTContents.data()), SectionSize); |
| 1347 | |
| 1348 | auto disassembleInstruction = [&](uint64_t InstrOffset, MCInst &Instruction, |
| 1349 | uint64_t &InstrSize) { |
| 1350 | const uint64_t InstrAddr = SectionAddress + InstrOffset; |
| 1351 | if (!BC->DisAsm->getInstruction(Instruction, InstrSize, |
| 1352 | PLTData.slice(InstrOffset), InstrAddr, |
| 1353 | nulls())) { |
| 1354 | errs() << "BOLT-ERROR: unable to disassemble instruction in PLT section " |
| 1355 | << Section.getName() << " at offset 0x" |
| 1356 | << Twine::utohexstr(InstrOffset) << '\n'; |
| 1357 | exit(1); |
| 1358 | } |
| 1359 | }; |
| 1360 | |
| 1361 | for (uint64_t EntryOffset = 0; EntryOffset + EntrySize <= SectionSize; |
| 1362 | EntryOffset += EntrySize) { |
| 1363 | MCInst Instruction; |
| 1364 | uint64_t InstrSize, InstrOffset = EntryOffset; |
| 1365 | while (InstrOffset < EntryOffset + EntrySize) { |
| 1366 | disassembleInstruction(InstrOffset, Instruction, InstrSize); |
| 1367 | // Check if the entry size needs adjustment. |
| 1368 | if (EntryOffset == 0 && BC->MIB->isTerminateBranch(Instruction) && |
| 1369 | EntrySize == 8) |
| 1370 | EntrySize = 16; |
| 1371 | |
| 1372 | if (BC->MIB->isIndirectBranch(Instruction)) |
| 1373 | break; |
| 1374 | |
| 1375 | InstrOffset += InstrSize; |
| 1376 | } |
| 1377 | |
| 1378 | if (InstrOffset + InstrSize > EntryOffset + EntrySize) |
| 1379 | continue; |
| 1380 | |
| 1381 | uint64_t TargetAddress; |
| 1382 | if (!BC->MIB->evaluateMemOperandTarget(Instruction, TargetAddress, |
| 1383 | SectionAddress + InstrOffset, |
| 1384 | InstrSize)) { |
| 1385 | errs() << "BOLT-ERROR: error evaluating PLT instruction at offset 0x" |
| 1386 | << Twine::utohexstr(SectionAddress + InstrOffset) << '\n'; |
| 1387 | exit(1); |
| 1388 | } |
| 1389 | |
| 1390 | createPLTBinaryFunction(TargetAddress, SectionAddress + EntryOffset, |
| 1391 | EntrySize); |
| 1392 | } |
| 1393 | } |
| 1394 | |
Maksim Panchenko | 49d1f56 | 2017-08-04 18:21:05 | [diff] [blame] | 1395 | void RewriteInstance::disassemblePLT() { |
Maksim Panchenko | c9f5f47 | 2021-06-30 21:41:41 | [diff] [blame] | 1396 | auto analyzeOnePLTSection = [&](BinarySection &Section, uint64_t EntrySize) { |
Vladislav Khmelevsky | 00b6efc | 2022-01-25 00:22:47 | [diff] [blame] | 1397 | if (BC->isAArch64()) |
| 1398 | return disassemblePLTSectionAArch64(Section); |
| 1399 | return disassemblePLTSectionX86(Section, EntrySize); |
Rafael Auler | 1f6564f | 2019-08-26 22:03:38 | [diff] [blame] | 1400 | }; |
| 1401 | |
Maksim Panchenko | c9f5f47 | 2021-06-30 21:41:41 | [diff] [blame] | 1402 | for (BinarySection &Section : BC->allocatableSections()) { |
| 1403 | const PLTSectionInfo *PLTSI = getPLTSectionInfo(Section.getName()); |
| 1404 | if (!PLTSI) |
| 1405 | continue; |
Maksim Panchenko | 49d1f56 | 2017-08-04 18:21:05 | [diff] [blame] | 1406 | |
Maksim Panchenko | c9f5f47 | 2021-06-30 21:41:41 | [diff] [blame] | 1407 | analyzeOnePLTSection(Section, PLTSI->EntrySize); |
| 1408 | // If we did not register any function at the start of the section, |
| 1409 | // then it must be a general PLT entry. Add a function at the location. |
| 1410 | if (BC->getBinaryFunctions().find(Section.getAddress()) == |
Rafael Auler | 1f6564f | 2019-08-26 22:03:38 | [diff] [blame] | 1411 | BC->getBinaryFunctions().end()) { |
Maksim Panchenko | c9f5f47 | 2021-06-30 21:41:41 | [diff] [blame] | 1412 | BinaryFunction *BF = BC->createBinaryFunction( |
| 1413 | "__BOLT_PSEUDO_" + Section.getName().str(), Section, |
| 1414 | Section.getAddress(), 0, PLTSI->EntrySize, Section.getAlignment()); |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 1415 | BF->setPseudo(true); |
Maksim Panchenko | 49d1f56 | 2017-08-04 18:21:05 | [diff] [blame] | 1416 | } |
| 1417 | } |
| 1418 | } |
| 1419 | |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1420 | void RewriteInstance::adjustFunctionBoundaries() { |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 1421 | for (auto BFI = BC->getBinaryFunctions().begin(), |
| 1422 | BFE = BC->getBinaryFunctions().end(); |
Maksim Panchenko | 2ab7472 | 2017-10-10 21:54:09 | [diff] [blame] | 1423 | BFI != BFE; ++BFI) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1424 | BinaryFunction &Function = BFI->second; |
Maksim Panchenko | fe37f18 | 2021-05-13 17:50:47 | [diff] [blame] | 1425 | const BinaryFunction *NextFunction = nullptr; |
Maksim Panchenko | 078ece1 | 2019-06-28 18:53:34 | [diff] [blame] | 1426 | if (std::next(BFI) != BFE) |
| 1427 | NextFunction = &std::next(BFI)->second; |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1428 | |
Maksim Panchenko | 99ef4c9 | 2019-04-16 17:24:34 | [diff] [blame] | 1429 | // Check if it's a fragment of a function. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1430 | Optional<StringRef> FragName = |
| 1431 | Function.hasRestoredNameRegex(".*\\.cold(\\.[0-9]+)?"); |
Maksim Panchenko | 9ef9a7b | 2019-05-30 01:33:09 | [diff] [blame] | 1432 | if (FragName) { |
Maksim Panchenko | 99ef4c9 | 2019-04-16 17:24:34 | [diff] [blame] | 1433 | static bool PrintedWarning = false; |
| 1434 | if (BC->HasRelocations && !PrintedWarning) { |
| 1435 | errs() << "BOLT-WARNING: split function detected on input : " |
Rafael Auler | 1f6564f | 2019-08-26 22:03:38 | [diff] [blame] | 1436 | << *FragName << ". The support is limited in relocation mode.\n"; |
Maksim Panchenko | 99ef4c9 | 2019-04-16 17:24:34 | [diff] [blame] | 1437 | PrintedWarning = true; |
| 1438 | } |
| 1439 | Function.IsFragment = true; |
| 1440 | } |
| 1441 | |
Maksim Panchenko | 2ab7472 | 2017-10-10 21:54:09 | [diff] [blame] | 1442 | // Check if there's a symbol or a function with a larger address in the |
| 1443 | // same section. If there is - it determines the maximum size for the |
| 1444 | // current function. Otherwise, it is the size of a containing section |
| 1445 | // the defines it. |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1446 | // |
| 1447 | // NOTE: ignore some symbols that could be tolerated inside the body |
| 1448 | // of a function. |
| 1449 | auto NextSymRefI = FileSymRefs.upper_bound(Function.getAddress()); |
| 1450 | while (NextSymRefI != FileSymRefs.end()) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1451 | SymbolRef &Symbol = NextSymRefI->second; |
| 1452 | const uint64_t SymbolAddress = NextSymRefI->first; |
| 1453 | const uint64_t SymbolSize = ELFSymbolRef(Symbol).getSize(); |
Maksim Panchenko | 078ece1 | 2019-06-28 18:53:34 | [diff] [blame] | 1454 | |
| 1455 | if (NextFunction && SymbolAddress >= NextFunction->getAddress()) |
| 1456 | break; |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1457 | |
| 1458 | if (!Function.isSymbolValidInScope(Symbol, SymbolSize)) |
| 1459 | break; |
| 1460 | |
| 1461 | // This is potentially another entry point into the function. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1462 | uint64_t EntryOffset = NextSymRefI->first - Function.getAddress(); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1463 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: adding entry point to function " |
| 1464 | << Function << " at offset 0x" |
| 1465 | << Twine::utohexstr(EntryOffset) << '\n'); |
Rafael Auler | 907ca25 | 2017-11-23 00:17:36 | [diff] [blame] | 1466 | Function.addEntryPointAtOffset(EntryOffset); |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1467 | |
| 1468 | ++NextSymRefI; |
| 1469 | } |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1470 | |
Maksim Panchenko | 2ab7472 | 2017-10-10 21:54:09 | [diff] [blame] | 1471 | // Function runs at most till the end of the containing section. |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 1472 | uint64_t NextObjectAddress = Function.getOriginSection()->getEndAddress(); |
Maksim Panchenko | 2ab7472 | 2017-10-10 21:54:09 | [diff] [blame] | 1473 | // Or till the next object marked by a symbol. |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1474 | if (NextSymRefI != FileSymRefs.end()) |
Maksim Panchenko | 2ab7472 | 2017-10-10 21:54:09 | [diff] [blame] | 1475 | NextObjectAddress = std::min(NextSymRefI->first, NextObjectAddress); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1476 | |
Maksim Panchenko | 2ab7472 | 2017-10-10 21:54:09 | [diff] [blame] | 1477 | // Or till the next function not marked by a symbol. |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1478 | if (NextFunction) |
Rafael Auler | 1f6564f | 2019-08-26 22:03:38 | [diff] [blame] | 1479 | NextObjectAddress = |
| 1480 | std::min(NextFunction->getAddress(), NextObjectAddress); |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1481 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1482 | const uint64_t MaxSize = NextObjectAddress - Function.getAddress(); |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1483 | if (MaxSize < Function.getSize()) { |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1484 | errs() << "BOLT-ERROR: symbol seen in the middle of the function " |
| 1485 | << Function << ". Skipping.\n"; |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1486 | Function.setSimple(false); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1487 | Function.setMaxSize(Function.getSize()); |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1488 | continue; |
| 1489 | } |
| 1490 | Function.setMaxSize(MaxSize); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1491 | if (!Function.getSize() && Function.isSimple()) { |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1492 | // Some assembly functions have their size set to 0, use the max |
| 1493 | // size as their real size. |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1494 | if (opts::Verbosity >= 1) |
Rafael Auler | 1f6564f | 2019-08-26 22:03:38 | [diff] [blame] | 1495 | outs() << "BOLT-INFO: setting size of function " << Function << " to " |
| 1496 | << Function.getMaxSize() << " (was 0)\n"; |
Maksim Panchenko | e241e9c | 2016-09-29 18:19:06 | [diff] [blame] | 1497 | Function.setSize(Function.getMaxSize()); |
| 1498 | } |
| 1499 | } |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 1500 | } |
| 1501 | |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 1502 | void RewriteInstance::relocateEHFrameSection() { |
Bill Nell | 2640b40 | 2018-01-23 23:10:24 | [diff] [blame] | 1503 | assert(EHFrameSection && "non-empty .eh_frame section expected"); |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 1504 | |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 1505 | DWARFDataExtractor DE(EHFrameSection->getContents(), |
| 1506 | BC->AsmInfo->isLittleEndian(), |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 1507 | BC->AsmInfo->getCodePointerSize()); |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 1508 | auto createReloc = [&](uint64_t Value, uint64_t Offset, uint64_t DwarfType) { |
| 1509 | if (DwarfType == dwarf::DW_EH_PE_omit) |
| 1510 | return; |
| 1511 | |
Maksim Panchenko | 606532b | 2020-04-16 07:02:35 | [diff] [blame] | 1512 | // Only fix references that are relative to other locations. |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 1513 | if (!(DwarfType & dwarf::DW_EH_PE_pcrel) && |
| 1514 | !(DwarfType & dwarf::DW_EH_PE_textrel) && |
| 1515 | !(DwarfType & dwarf::DW_EH_PE_funcrel) && |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1516 | !(DwarfType & dwarf::DW_EH_PE_datarel)) |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 1517 | return; |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 1518 | |
| 1519 | if (!(DwarfType & dwarf::DW_EH_PE_sdata4)) |
| 1520 | return; |
| 1521 | |
| 1522 | uint64_t RelType; |
| 1523 | switch (DwarfType & 0x0f) { |
| 1524 | default: |
| 1525 | llvm_unreachable("unsupported DWARF encoding type"); |
| 1526 | case dwarf::DW_EH_PE_sdata4: |
| 1527 | case dwarf::DW_EH_PE_udata4: |
Rafael Auler | 35632d4 | 2020-10-07 22:40:51 | [diff] [blame] | 1528 | RelType = Relocation::getPC32(); |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 1529 | Offset -= 4; |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 1530 | break; |
| 1531 | case dwarf::DW_EH_PE_sdata8: |
| 1532 | case dwarf::DW_EH_PE_udata8: |
Rafael Auler | 35632d4 | 2020-10-07 22:40:51 | [diff] [blame] | 1533 | RelType = Relocation::getPC64(); |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 1534 | Offset -= 8; |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 1535 | break; |
| 1536 | } |
| 1537 | |
Maksim Panchenko | 606532b | 2020-04-16 07:02:35 | [diff] [blame] | 1538 | // Create a relocation against an absolute value since the goal is to |
| 1539 | // preserve the contents of the section independent of the new values |
| 1540 | // of referenced symbols. |
| 1541 | EHFrameSection->addRelocation(Offset, nullptr, RelType, Value); |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 1542 | }; |
| 1543 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 1544 | Error E = EHFrameParser::parse(DE, EHFrameSection->getAddress(), createReloc); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1545 | check_error(std::move(E), "failed to patch EH frame"); |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 1546 | } |
| 1547 | |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 1548 | ArrayRef<uint8_t> RewriteInstance::getLSDAData() { |
| 1549 | return ArrayRef<uint8_t>(LSDASection->getData(), |
| 1550 | LSDASection->getContents().size()); |
| 1551 | } |
| 1552 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 1553 | uint64_t RewriteInstance::getLSDAAddress() { return LSDASection->getAddress(); } |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 1554 | |
Amir Ayupov | ced5472 | 2022-03-08 17:12:19 | [diff] [blame] | 1555 | Error RewriteInstance::readSpecialSections() { |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 1556 | NamedRegionTimer T("readSpecialSections", "read special sections", |
| 1557 | TimerGroupName, TimerGroupDesc, opts::TimeRewrite); |
Bill Nell | 591e0ef | 2017-11-28 02:00:24 | [diff] [blame] | 1558 | |
Maksim Panchenko | d5a0264 | 2017-03-23 05:05:50 | [diff] [blame] | 1559 | bool HasTextRelocations = false; |
Maksim Panchenko | 2b15233 | 2019-04-26 22:30:12 | [diff] [blame] | 1560 | bool HasDebugInfo = false; |
Maksim Panchenko | d5a0264 | 2017-03-23 05:05:50 | [diff] [blame] | 1561 | |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 1562 | // Process special sections. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1563 | for (const SectionRef &Section : InputFile->sections()) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1564 | Expected<StringRef> SectionNameOrErr = Section.getName(); |
| 1565 | check_error(SectionNameOrErr.takeError(), "cannot get section name"); |
| 1566 | StringRef SectionName = *SectionNameOrErr; |
Maksim Panchenko | c6d0c56 | 2016-07-21 19:45:35 | [diff] [blame] | 1567 | |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 1568 | // Only register sections with names. |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 1569 | if (!SectionName.empty()) { |
Amir Ayupov | ced5472 | 2022-03-08 17:12:19 | [diff] [blame] | 1570 | if (Error E = Section.getContents().takeError()) |
| 1571 | return E; |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 1572 | BC->registerSection(Section); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1573 | LLVM_DEBUG( |
| 1574 | dbgs() << "BOLT-DEBUG: registering section " << SectionName << " @ 0x" |
| 1575 | << Twine::utohexstr(Section.getAddress()) << ":0x" |
| 1576 | << Twine::utohexstr(Section.getAddress() + Section.getSize()) |
| 1577 | << "\n"); |
Maksim Panchenko | 2b15233 | 2019-04-26 22:30:12 | [diff] [blame] | 1578 | if (isDebugSection(SectionName)) |
| 1579 | HasDebugInfo = true; |
takh | 48b71ad | 2020-06-11 06:00:39 | [diff] [blame] | 1580 | if (isKSymtabSection(SectionName)) |
| 1581 | opts::LinuxKernelMode = true; |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 1582 | } |
| 1583 | } |
| 1584 | |
Rafael Auler | 21f4303 | 2019-04-13 00:33:46 | [diff] [blame] | 1585 | if (HasDebugInfo && !opts::UpdateDebugSections && !opts::AggregateOnly) { |
Maksim Panchenko | 2b15233 | 2019-04-26 22:30:12 | [diff] [blame] | 1586 | errs() << "BOLT-WARNING: debug info will be stripped from the binary. " |
| 1587 | "Use -update-debug-sections to keep it.\n"; |
| 1588 | } |
| 1589 | |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 1590 | HasTextRelocations = (bool)BC->getUniqueSectionByName(".rela.text"); |
| 1591 | LSDASection = BC->getUniqueSectionByName(".gcc_except_table"); |
| 1592 | EHFrameSection = BC->getUniqueSectionByName(".eh_frame"); |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 1593 | GOTPLTSection = BC->getUniqueSectionByName(".got.plt"); |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 1594 | RelaPLTSection = BC->getUniqueSectionByName(".rela.plt"); |
Rafael Auler | 1f6564f | 2019-08-26 22:03:38 | [diff] [blame] | 1595 | RelaDynSection = BC->getUniqueSectionByName(".rela.dyn"); |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 1596 | BuildIDSection = BC->getUniqueSectionByName(".note.gnu.build-id"); |
Laith Saed Sakka | 4755825 | 2019-05-16 00:19:18 | [diff] [blame] | 1597 | SDTSection = BC->getUniqueSectionByName(".note.stapsdt"); |
James Luo | 8a91959 | 2021-06-11 20:06:12 | [diff] [blame] | 1598 | PseudoProbeDescSection = BC->getUniqueSectionByName(".pseudo_probe_desc"); |
| 1599 | PseudoProbeSection = BC->getUniqueSectionByName(".pseudo_probe"); |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 1600 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1601 | if (ErrorOr<BinarySection &> BATSec = |
Rafael Auler | 21f4303 | 2019-04-13 00:33:46 | [diff] [blame] | 1602 | BC->getUniqueSectionByName(BoltAddressTranslation::SECTION_NAME)) { |
Rafael Auler | 698a468 | 2019-10-11 20:32:14 | [diff] [blame] | 1603 | // Do not read BAT when plotting a heatmap |
| 1604 | if (!opts::HeatmapMode) { |
| 1605 | if (std::error_code EC = BAT->parse(BATSec->getContents())) { |
| 1606 | errs() << "BOLT-ERROR: failed to parse BOLT address translation " |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 1607 | "table.\n"; |
Rafael Auler | 698a468 | 2019-10-11 20:32:14 | [diff] [blame] | 1608 | exit(1); |
| 1609 | } |
Rafael Auler | 21f4303 | 2019-04-13 00:33:46 | [diff] [blame] | 1610 | } |
| 1611 | } |
| 1612 | |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 1613 | if (opts::PrintSections) { |
| 1614 | outs() << "BOLT-INFO: Sections from original binary:\n"; |
| 1615 | BC->printSections(outs()); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 1616 | } |
| 1617 | |
Maksim Panchenko | b6f7c68 | 2017-12-10 05:40:39 | [diff] [blame] | 1618 | if (opts::RelocationMode == cl::BOU_TRUE && !HasTextRelocations) { |
Maksim Panchenko | d5a0264 | 2017-03-23 05:05:50 | [diff] [blame] | 1619 | errs() << "BOLT-ERROR: relocations against code are missing from the input " |
| 1620 | "file. Cannot proceed in relocations mode (-relocs).\n"; |
| 1621 | exit(1); |
| 1622 | } |
| 1623 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 1624 | BC->HasRelocations = |
| 1625 | HasTextRelocations && (opts::RelocationMode != cl::BOU_FALSE); |
laith sakka | 7d42835 | 2019-07-12 14:25:50 | [diff] [blame] | 1626 | |
Wenlei He | 459add2 | 2019-06-26 18:06:46 | [diff] [blame] | 1627 | // Force non-relocation mode for heatmap generation |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1628 | if (opts::HeatmapMode) |
Wenlei He | 459add2 | 2019-06-26 18:06:46 | [diff] [blame] | 1629 | BC->HasRelocations = false; |
laith sakka | 7d42835 | 2019-07-12 14:25:50 | [diff] [blame] | 1630 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1631 | if (BC->HasRelocations) |
Maksim Panchenko | e89ad0d | 2019-06-28 16:21:27 | [diff] [blame] | 1632 | outs() << "BOLT-INFO: enabling " << (opts::StrictMode ? "strict " : "") |
| 1633 | << "relocation mode\n"; |
Maksim Panchenko | b6f7c68 | 2017-12-10 05:40:39 | [diff] [blame] | 1634 | |
Maksim Panchenko | 3355936 | 2021-04-21 18:24:15 | [diff] [blame] | 1635 | // Read EH frame for function boundaries info. |
| 1636 | Expected<const DWARFDebugFrame *> EHFrameOrError = BC->DwCtx->getEHFrame(); |
| 1637 | if (!EHFrameOrError) |
| 1638 | report_error("expected valid eh_frame section", EHFrameOrError.takeError()); |
Maksim Panchenko | 3355936 | 2021-04-21 18:24:15 | [diff] [blame] | 1639 | CFIRdWrt.reset(new CFIReaderWriter(*EHFrameOrError.get())); |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 1640 | |
| 1641 | // Parse build-id |
| 1642 | parseBuildID(); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1643 | if (Optional<std::string> FileBuildID = getPrintableBuildID()) |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 1644 | BC->setFileBuildID(*FileBuildID); |
Laith Saed Sakka | 4755825 | 2019-05-16 00:19:18 | [diff] [blame] | 1645 | |
| 1646 | parseSDTNotes(); |
Maksim Panchenko | 74a2777 | 2020-03-09 02:04:39 | [diff] [blame] | 1647 | |
Maksim Panchenko | 250ca40 | 2020-06-26 23:52:07 | [diff] [blame] | 1648 | // Read .dynamic/PT_DYNAMIC. |
Amir Ayupov | 1e016c3 | 2022-03-08 17:17:41 | [diff] [blame] | 1649 | return readELFDynamic(); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 1650 | } |
| 1651 | |
Maksim Panchenko | 120d267 | 2018-04-13 22:46:19 | [diff] [blame] | 1652 | void RewriteInstance::adjustCommandLineOptions() { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1653 | if (BC->isAArch64() && !BC->HasRelocations) |
Maksim Panchenko | 120d267 | 2018-04-13 22:46:19 | [diff] [blame] | 1654 | errs() << "BOLT-WARNING: non-relocation mode for AArch64 is not fully " |
| 1655 | "supported\n"; |
Maksim Panchenko | 120d267 | 2018-04-13 22:46:19 | [diff] [blame] | 1656 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1657 | if (RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary()) |
Xun Li | 9bd7161 | 2020-05-02 18:14:38 | [diff] [blame] | 1658 | RtLibrary->adjustCommandLineOptions(*BC); |
Rafael Auler | 0d23cba | 2019-06-20 03:10:49 | [diff] [blame] | 1659 | |
Maksim Panchenko | 120d267 | 2018-04-13 22:46:19 | [diff] [blame] | 1660 | if (opts::AlignMacroOpFusion != MFT_NONE && !BC->isX86()) { |
| 1661 | outs() << "BOLT-INFO: disabling -align-macro-fusion on non-x86 platform\n"; |
| 1662 | opts::AlignMacroOpFusion = MFT_NONE; |
| 1663 | } |
Maksim Panchenko | 6bcb338 | 2019-03-15 20:43:36 | [diff] [blame] | 1664 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1665 | if (BC->isX86() && BC->MAB->allowAutoPadding()) { |
Rafael Auler | c82e7fd | 2020-02-11 02:50:53 | [diff] [blame] | 1666 | if (!BC->HasRelocations) { |
| 1667 | errs() << "BOLT-ERROR: cannot apply mitigations for Intel JCC erratum in " |
| 1668 | "non-relocation mode\n"; |
| 1669 | exit(1); |
| 1670 | } |
| 1671 | outs() << "BOLT-WARNING: using mitigation for Intel JCC erratum, layout " |
| 1672 | "may take several minutes\n"; |
| 1673 | opts::AlignMacroOpFusion = MFT_NONE; |
| 1674 | } |
| 1675 | |
Maksim Panchenko | 23edb3e | 2020-04-19 22:02:50 | [diff] [blame] | 1676 | if (opts::AlignMacroOpFusion != MFT_NONE && !BC->HasRelocations) { |
Maksim Panchenko | 120d267 | 2018-04-13 22:46:19 | [diff] [blame] | 1677 | outs() << "BOLT-INFO: disabling -align-macro-fusion in non-relocation " |
| 1678 | "mode\n"; |
| 1679 | opts::AlignMacroOpFusion = MFT_NONE; |
| 1680 | } |
Maksim Panchenko | 6bcb338 | 2019-03-15 20:43:36 | [diff] [blame] | 1681 | |
Rafael Auler | 72ecd12f | 2018-06-25 21:55:48 | [diff] [blame] | 1682 | if (opts::SplitEH && !BC->HasRelocations) { |
Maksim Panchenko | 492e4a5 | 2019-04-26 00:00:05 | [diff] [blame] | 1683 | errs() << "BOLT-WARNING: disabling -split-eh in non-relocation mode\n"; |
Rafael Auler | 72ecd12f | 2018-06-25 21:55:48 | [diff] [blame] | 1684 | opts::SplitEH = false; |
| 1685 | } |
Maksim Panchenko | 6bcb338 | 2019-03-15 20:43:36 | [diff] [blame] | 1686 | |
Maksim Panchenko | e89ad0d | 2019-06-28 16:21:27 | [diff] [blame] | 1687 | if (opts::StrictMode && !BC->HasRelocations) { |
| 1688 | errs() << "BOLT-WARNING: disabling strict mode (-strict) in non-relocation " |
| 1689 | "mode\n"; |
| 1690 | opts::StrictMode = false; |
| 1691 | } |
| 1692 | |
Maksim Panchenko | 79ff4ec | 2019-06-11 20:24:10 | [diff] [blame] | 1693 | if (BC->HasRelocations && opts::AggregateOnly && |
| 1694 | !opts::StrictMode.getNumOccurrences()) { |
Rafael Auler | 28f9187 | 2019-11-15 00:07:11 | [diff] [blame] | 1695 | outs() << "BOLT-INFO: enabling strict relocation mode for aggregation " |
Maksim Panchenko | 79ff4ec | 2019-06-11 20:24:10 | [diff] [blame] | 1696 | "purposes\n"; |
| 1697 | opts::StrictMode = true; |
| 1698 | } |
| 1699 | |
Maksim Panchenko | 120d267 | 2018-04-13 22:46:19 | [diff] [blame] | 1700 | if (BC->isX86() && BC->HasRelocations && |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 1701 | opts::AlignMacroOpFusion == MFT_HOT && !ProfileReader) { |
Maksim Panchenko | 120d267 | 2018-04-13 22:46:19 | [diff] [blame] | 1702 | outs() << "BOLT-INFO: enabling -align-macro-fusion=all since no profile " |
| 1703 | "was specified\n"; |
| 1704 | opts::AlignMacroOpFusion = MFT_ALL; |
| 1705 | } |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 1706 | |
Maksim Panchenko | 492e4a5 | 2019-04-26 00:00:05 | [diff] [blame] | 1707 | if (!BC->HasRelocations && |
| 1708 | opts::ReorderFunctions != ReorderFunctions::RT_NONE) { |
| 1709 | errs() << "BOLT-ERROR: function reordering only works when " |
| 1710 | << "relocations are enabled\n"; |
| 1711 | exit(1); |
| 1712 | } |
| 1713 | |
| 1714 | if (opts::ReorderFunctions != ReorderFunctions::RT_NONE && |
| 1715 | !opts::HotText.getNumOccurrences()) { |
| 1716 | opts::HotText = true; |
| 1717 | } else if (opts::HotText && !BC->HasRelocations) { |
| 1718 | errs() << "BOLT-WARNING: hot text is disabled in non-relocation mode\n"; |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 1719 | opts::HotText = false; |
| 1720 | } |
Maksim Panchenko | 6bcb338 | 2019-03-15 20:43:36 | [diff] [blame] | 1721 | |
| 1722 | if (opts::HotText && opts::HotTextMoveSections.getNumOccurrences() == 0) { |
| 1723 | opts::HotTextMoveSections.addValue(".stub"); |
| 1724 | opts::HotTextMoveSections.addValue(".mover"); |
Maksim Panchenko | 22ba3dc | 2019-04-16 17:39:05 | [diff] [blame] | 1725 | opts::HotTextMoveSections.addValue(".never_hugify"); |
Maksim Panchenko | 6bcb338 | 2019-03-15 20:43:36 | [diff] [blame] | 1726 | } |
Maksim Panchenko | 2df4e7b | 2020-02-25 01:12:41 | [diff] [blame] | 1727 | |
| 1728 | if (opts::UseOldText && !BC->OldTextSectionAddress) { |
| 1729 | errs() << "BOLT-WARNING: cannot use old .text as the section was not found" |
| 1730 | "\n"; |
| 1731 | opts::UseOldText = false; |
| 1732 | } |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 1733 | if (opts::UseOldText && !BC->HasRelocations) { |
| 1734 | errs() << "BOLT-WARNING: cannot use old .text in non-relocation mode\n"; |
| 1735 | opts::UseOldText = false; |
| 1736 | } |
| 1737 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1738 | if (!opts::AlignText.getNumOccurrences()) |
Maksim Panchenko | 23edb3e | 2020-04-19 22:02:50 | [diff] [blame] | 1739 | opts::AlignText = BC->PageAlign; |
Maksim Panchenko | 924d0bd | 2020-05-03 22:49:58 | [diff] [blame] | 1740 | |
Vladislav Khmelevsky | 62a289d | 2022-03-15 19:17:51 | [diff] [blame] | 1741 | if (opts::AlignText < opts::AlignFunctions) |
| 1742 | opts::AlignText = (unsigned)opts::AlignFunctions; |
| 1743 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 1744 | if (BC->isX86() && opts::Lite.getNumOccurrences() == 0 && !opts::StrictMode && |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1745 | !opts::UseOldText) |
Maksim Panchenko | 924d0bd | 2020-05-03 22:49:58 | [diff] [blame] | 1746 | opts::Lite = true; |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 1747 | |
| 1748 | if (opts::Lite && opts::UseOldText) { |
| 1749 | errs() << "BOLT-WARNING: cannot combine -lite with -use-old-text. " |
| 1750 | "Disabling -use-old-text.\n"; |
| 1751 | opts::UseOldText = false; |
| 1752 | } |
| 1753 | |
Maksim Panchenko | d6d8839 | 2020-10-17 22:09:06 | [diff] [blame] | 1754 | if (opts::Lite && opts::StrictMode) { |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 1755 | errs() << "BOLT-ERROR: -strict and -lite cannot be used at the same time\n"; |
| 1756 | exit(1); |
Maksim Panchenko | 924d0bd | 2020-05-03 22:49:58 | [diff] [blame] | 1757 | } |
Rafael Auler | 6547813 | 2020-08-06 21:43:33 | [diff] [blame] | 1758 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1759 | if (opts::Lite) |
Rafael Auler | 6547813 | 2020-08-06 21:43:33 | [diff] [blame] | 1760 | outs() << "BOLT-INFO: enabling lite mode\n"; |
Maksim Panchenko | aaf49b0 | 2020-08-13 01:10:41 | [diff] [blame] | 1761 | |
| 1762 | if (!opts::SaveProfile.empty() && BAT->enabledFor(InputFile)) { |
| 1763 | errs() << "BOLT-ERROR: unable to save profile in YAML format for input " |
| 1764 | "file processed by BOLT. Please remove -w option and use branch " |
| 1765 | "profile.\n"; |
| 1766 | exit(1); |
| 1767 | } |
Maksim Panchenko | 120d267 | 2018-04-13 22:46:19 | [diff] [blame] | 1768 | } |
| 1769 | |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1770 | namespace { |
| 1771 | template <typename ELFT> |
| 1772 | int64_t getRelocationAddend(const ELFObjectFile<ELFT> *Obj, |
| 1773 | const RelocationRef &RelRef) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1774 | using ELFShdrTy = typename ELFT::Shdr; |
| 1775 | using Elf_Rela = typename ELFT::Rela; |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1776 | int64_t Addend = 0; |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1777 | const ELFFile<ELFT> &EF = Obj->getELFFile(); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1778 | DataRefImpl Rel = RelRef.getRawDataRefImpl(); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1779 | const ELFShdrTy *RelocationSection = cantFail(EF.getSection(Rel.d.a)); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1780 | switch (RelocationSection->sh_type) { |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 1781 | default: |
| 1782 | llvm_unreachable("unexpected relocation section type"); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1783 | case ELF::SHT_REL: |
| 1784 | break; |
| 1785 | case ELF::SHT_RELA: { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1786 | const Elf_Rela *RelA = Obj->getRela(Rel); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1787 | Addend = RelA->r_addend; |
| 1788 | break; |
| 1789 | } |
| 1790 | } |
| 1791 | |
| 1792 | return Addend; |
| 1793 | } |
| 1794 | |
| 1795 | int64_t getRelocationAddend(const ELFObjectFileBase *Obj, |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 1796 | const RelocationRef &Rel) { |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1797 | if (auto *ELF32LE = dyn_cast<ELF32LEObjectFile>(Obj)) |
| 1798 | return getRelocationAddend(ELF32LE, Rel); |
| 1799 | if (auto *ELF64LE = dyn_cast<ELF64LEObjectFile>(Obj)) |
| 1800 | return getRelocationAddend(ELF64LE, Rel); |
| 1801 | if (auto *ELF32BE = dyn_cast<ELF32BEObjectFile>(Obj)) |
| 1802 | return getRelocationAddend(ELF32BE, Rel); |
| 1803 | auto *ELF64BE = cast<ELF64BEObjectFile>(Obj); |
| 1804 | return getRelocationAddend(ELF64BE, Rel); |
| 1805 | } |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 1806 | |
| 1807 | template <typename ELFT> |
| 1808 | uint32_t getRelocationSymbol(const ELFObjectFile<ELFT> *Obj, |
| 1809 | const RelocationRef &RelRef) { |
| 1810 | using ELFShdrTy = typename ELFT::Shdr; |
| 1811 | uint32_t Symbol = 0; |
| 1812 | const ELFFile<ELFT> &EF = Obj->getELFFile(); |
| 1813 | DataRefImpl Rel = RelRef.getRawDataRefImpl(); |
| 1814 | const ELFShdrTy *RelocationSection = cantFail(EF.getSection(Rel.d.a)); |
| 1815 | switch (RelocationSection->sh_type) { |
| 1816 | default: |
| 1817 | llvm_unreachable("unexpected relocation section type"); |
| 1818 | case ELF::SHT_REL: |
| 1819 | Symbol = Obj->getRel(Rel)->getSymbol(EF.isMips64EL()); |
| 1820 | break; |
| 1821 | case ELF::SHT_RELA: |
| 1822 | Symbol = Obj->getRela(Rel)->getSymbol(EF.isMips64EL()); |
| 1823 | break; |
| 1824 | } |
| 1825 | |
| 1826 | return Symbol; |
| 1827 | } |
| 1828 | |
| 1829 | uint32_t getRelocationSymbol(const ELFObjectFileBase *Obj, |
| 1830 | const RelocationRef &Rel) { |
| 1831 | if (auto *ELF32LE = dyn_cast<ELF32LEObjectFile>(Obj)) |
| 1832 | return getRelocationSymbol(ELF32LE, Rel); |
| 1833 | if (auto *ELF64LE = dyn_cast<ELF64LEObjectFile>(Obj)) |
| 1834 | return getRelocationSymbol(ELF64LE, Rel); |
| 1835 | if (auto *ELF32BE = dyn_cast<ELF32BEObjectFile>(Obj)) |
| 1836 | return getRelocationSymbol(ELF32BE, Rel); |
| 1837 | auto *ELF64BE = cast<ELF64BEObjectFile>(Obj); |
| 1838 | return getRelocationSymbol(ELF64BE, Rel); |
| 1839 | } |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 1840 | } // anonymous namespace |
| 1841 | |
Vladislav Khmelevsky | 00c0659 | 2021-09-08 10:37:19 | [diff] [blame] | 1842 | bool RewriteInstance::analyzeRelocation( |
| 1843 | const RelocationRef &Rel, uint64_t RType, std::string &SymbolName, |
| 1844 | bool &IsSectionRelocation, uint64_t &SymbolAddress, int64_t &Addend, |
| 1845 | uint64_t &ExtractedValue, bool &Skip) const { |
| 1846 | Skip = false; |
Maksim Panchenko | e50e89b | 2019-04-12 00:11:08 | [diff] [blame] | 1847 | if (!Relocation::isSupported(RType)) |
Bill Nell | 89feb84 | 2018-01-24 13:42:11 | [diff] [blame] | 1848 | return false; |
| 1849 | |
Rafael Auler | 7df6a6d | 2018-03-20 21:34:58 | [diff] [blame] | 1850 | const bool IsAArch64 = BC->isAArch64(); |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 1851 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1852 | const size_t RelSize = Relocation::getSizeForType(RType); |
Maksim Panchenko | a8e05d0 | 2019-04-09 19:29:40 | [diff] [blame] | 1853 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1854 | ErrorOr<uint64_t> Value = |
| 1855 | BC->getUnsignedValueAtAddress(Rel.getOffset(), RelSize); |
Maksim Panchenko | a8e05d0 | 2019-04-09 19:29:40 | [diff] [blame] | 1856 | assert(Value && "failed to extract relocated value"); |
Vladislav Khmelevsky | 00c0659 | 2021-09-08 10:37:19 | [diff] [blame] | 1857 | if ((Skip = Relocation::skipRelocationProcess(RType, *Value))) |
| 1858 | return true; |
| 1859 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 1860 | ExtractedValue = Relocation::extractValue(RType, *Value, Rel.getOffset()); |
Maksim Panchenko | ce508b5 | 2018-09-21 19:00:20 | [diff] [blame] | 1861 | Addend = getRelocationAddend(InputFile, Rel); |
| 1862 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1863 | const bool IsPCRelative = Relocation::isPCRelative(RType); |
| 1864 | const uint64_t PCRelOffset = IsPCRelative && !IsAArch64 ? Rel.getOffset() : 0; |
Maksim Panchenko | ce508b5 | 2018-09-21 19:00:20 | [diff] [blame] | 1865 | bool SkipVerification = false; |
| 1866 | auto SymbolIter = Rel.getSymbol(); |
| 1867 | if (SymbolIter == InputFile->symbol_end()) { |
Maksim Panchenko | 06e7a1e | 2019-06-27 10:20:17 | [diff] [blame] | 1868 | SymbolAddress = ExtractedValue - Addend + PCRelOffset; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1869 | MCSymbol *RelSymbol = |
| 1870 | BC->getOrCreateGlobalSymbol(SymbolAddress, "RELSYMat"); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1871 | SymbolName = std::string(RelSymbol->getName()); |
Maksim Panchenko | ce508b5 | 2018-09-21 19:00:20 | [diff] [blame] | 1872 | IsSectionRelocation = false; |
| 1873 | } else { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1874 | const SymbolRef &Symbol = *SymbolIter; |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1875 | SymbolName = std::string(cantFail(Symbol.getName())); |
Maksim Panchenko | ce508b5 | 2018-09-21 19:00:20 | [diff] [blame] | 1876 | SymbolAddress = cantFail(Symbol.getAddress()); |
| 1877 | SkipVerification = (cantFail(Symbol.getType()) == SymbolRef::ST_Other); |
| 1878 | // Section symbols are marked as ST_Debug. |
| 1879 | IsSectionRelocation = (cantFail(Symbol.getType()) == SymbolRef::ST_Debug); |
Vladislav Khmelevsky | 00b6efc | 2022-01-25 00:22:47 | [diff] [blame] | 1880 | // Check for PLT entry registered with symbol name |
| 1881 | if (!SymbolAddress && IsAArch64) { |
Vladislav Khmelevsky | 4956e0e | 2022-04-03 16:11:31 | [diff] [blame] | 1882 | const BinaryData *BD = BC->getPLTBinaryDataByName(SymbolName); |
Vladislav Khmelevsky | 00b6efc | 2022-01-25 00:22:47 | [diff] [blame] | 1883 | SymbolAddress = BD ? BD->getAddress() : 0; |
| 1884 | } |
Maksim Panchenko | 06e7a1e | 2019-06-27 10:20:17 | [diff] [blame] | 1885 | } |
Rafael Auler | 28f9187 | 2019-11-15 00:07:11 | [diff] [blame] | 1886 | // For PIE or dynamic libs, the linker may choose not to put the relocation |
| 1887 | // result at the address if it is a X86_64_64 one because it will emit a |
| 1888 | // dynamic relocation (X86_RELATIVE) for the dynamic linker and loader to |
| 1889 | // resolve it at run time. The static relocation result goes as the addend |
| 1890 | // of the dynamic relocation in this case. We can't verify these cases. |
| 1891 | // FIXME: perhaps we can try to find if it really emitted a corresponding |
| 1892 | // RELATIVE relocation at this offset with the correct value as the addend. |
| 1893 | if (!BC->HasFixedLoadAddress && RelSize == 8) |
| 1894 | SkipVerification = true; |
Maksim Panchenko | 06e7a1e | 2019-06-27 10:20:17 | [diff] [blame] | 1895 | |
| 1896 | if (IsSectionRelocation && !IsAArch64) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1897 | ErrorOr<BinarySection &> Section = BC->getSectionForAddress(SymbolAddress); |
Maksim Panchenko | 06e7a1e | 2019-06-27 10:20:17 | [diff] [blame] | 1898 | assert(Section && "section expected for section relocation"); |
| 1899 | SymbolName = "section " + std::string(Section->getName()); |
| 1900 | // Convert section symbol relocations to regular relocations inside |
| 1901 | // non-section symbols. |
| 1902 | if (Section->containsAddress(ExtractedValue) && !IsPCRelative) { |
| 1903 | SymbolAddress = ExtractedValue; |
| 1904 | Addend = 0; |
| 1905 | } else { |
| 1906 | Addend = ExtractedValue - (SymbolAddress - PCRelOffset); |
Maksim Panchenko | ce508b5 | 2018-09-21 19:00:20 | [diff] [blame] | 1907 | } |
| 1908 | } |
Bill Nell | 89feb84 | 2018-01-24 13:42:11 | [diff] [blame] | 1909 | |
| 1910 | // If no symbol has been found or if it is a relocation requiring the |
| 1911 | // creation of a GOT entry, do not link against the symbol but against |
| 1912 | // whatever address was extracted from the instruction itself. We are |
| 1913 | // not creating a GOT entry as this was already processed by the linker. |
Rafael Auler | 74a71c6 | 2018-10-12 01:12:09 | [diff] [blame] | 1914 | // For GOT relocs, do not subtract addend as the addend does not refer |
| 1915 | // to this instruction's target, but it refers to the target in the GOT |
| 1916 | // entry. |
Maksim Panchenko | e50e89b | 2019-04-12 00:11:08 | [diff] [blame] | 1917 | if (Relocation::isGOT(RType)) { |
Rafael Auler | 74a71c6 | 2018-10-12 01:12:09 | [diff] [blame] | 1918 | Addend = 0; |
| 1919 | SymbolAddress = ExtractedValue + PCRelOffset; |
Vladislav Khmelevsky | 542c03c | 2021-09-02 18:04:33 | [diff] [blame] | 1920 | } else if (Relocation::isTLS(RType)) { |
| 1921 | SkipVerification = true; |
Rafael Auler | 74a71c6 | 2018-10-12 01:12:09 | [diff] [blame] | 1922 | } else if (!SymbolAddress) { |
Maksim Panchenko | ce508b5 | 2018-09-21 19:00:20 | [diff] [blame] | 1923 | assert(!IsSectionRelocation); |
Rafael Auler | 74a71c6 | 2018-10-12 01:12:09 | [diff] [blame] | 1924 | if (ExtractedValue || Addend == 0 || IsPCRelative) { |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 1925 | SymbolAddress = |
| 1926 | truncateToSize(ExtractedValue - Addend + PCRelOffset, RelSize); |
Bill Nell | 89feb84 | 2018-01-24 13:42:11 | [diff] [blame] | 1927 | } else { |
| 1928 | // This is weird case. The extracted value is zero but the addend is |
| 1929 | // non-zero and the relocation is not pc-rel. Using the previous logic, |
| 1930 | // the SymbolAddress would end up as a huge number. Seen in |
| 1931 | // exceptions_pic.test. |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1932 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: relocation @ 0x" |
| 1933 | << Twine::utohexstr(Rel.getOffset()) |
| 1934 | << " value does not match addend for " |
| 1935 | << "relocation to undefined symbol.\n"); |
Bill Nell | 89feb84 | 2018-01-24 13:42:11 | [diff] [blame] | 1936 | return true; |
| 1937 | } |
Bill Nell | 89feb84 | 2018-01-24 13:42:11 | [diff] [blame] | 1938 | } |
| 1939 | |
Maksim Panchenko | 39f6fcc | 2018-07-30 17:29:47 | [diff] [blame] | 1940 | auto verifyExtractedValue = [&]() { |
Maksim Panchenko | ce508b5 | 2018-09-21 19:00:20 | [diff] [blame] | 1941 | if (SkipVerification) |
| 1942 | return true; |
| 1943 | |
Maksim Panchenko | 39f6fcc | 2018-07-30 17:29:47 | [diff] [blame] | 1944 | if (IsAArch64) |
| 1945 | return true; |
Bill Nell | 89feb84 | 2018-01-24 13:42:11 | [diff] [blame] | 1946 | |
Maksim Panchenko | 39f6fcc | 2018-07-30 17:29:47 | [diff] [blame] | 1947 | if (SymbolName == "__hot_start" || SymbolName == "__hot_end") |
| 1948 | return true; |
Bill Nell | 89feb84 | 2018-01-24 13:42:11 | [diff] [blame] | 1949 | |
Maksim Panchenko | e233dec | 2020-07-01 02:58:43 | [diff] [blame] | 1950 | if (RType == ELF::R_X86_64_PLT32) |
| 1951 | return true; |
| 1952 | |
Maksim Panchenko | 39f6fcc | 2018-07-30 17:29:47 | [diff] [blame] | 1953 | return truncateToSize(ExtractedValue, RelSize) == |
| 1954 | truncateToSize(SymbolAddress + Addend - PCRelOffset, RelSize); |
| 1955 | }; |
| 1956 | |
Joey Thaman | 4c12afc | 2021-06-29 19:11:56 | [diff] [blame] | 1957 | (void)verifyExtractedValue; |
Maksim Panchenko | 39f6fcc | 2018-07-30 17:29:47 | [diff] [blame] | 1958 | assert(verifyExtractedValue() && "mismatched extracted relocation value"); |
Bill Nell | 89feb84 | 2018-01-24 13:42:11 | [diff] [blame] | 1959 | |
| 1960 | return true; |
| 1961 | } |
| 1962 | |
Maksim Panchenko | 38c5887 | 2021-06-22 20:46:06 | [diff] [blame] | 1963 | void RewriteInstance::processDynamicRelocations() { |
Maksim Panchenko | 1de0746 | 2021-06-30 21:38:50 | [diff] [blame] | 1964 | // Read relocations for PLT - DT_JMPREL. |
| 1965 | if (PLTRelocationsSize > 0) { |
| 1966 | ErrorOr<BinarySection &> PLTRelSectionOrErr = |
| 1967 | BC->getSectionForAddress(*PLTRelocationsAddress); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1968 | if (!PLTRelSectionOrErr) |
Maksim Panchenko | 1de0746 | 2021-06-30 21:38:50 | [diff] [blame] | 1969 | report_error("unable to find section corresponding to DT_JMPREL", |
| 1970 | PLTRelSectionOrErr.getError()); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1971 | if (PLTRelSectionOrErr->getSize() != PLTRelocationsSize) |
Maksim Panchenko | 1de0746 | 2021-06-30 21:38:50 | [diff] [blame] | 1972 | report_error("section size mismatch for DT_PLTRELSZ", |
| 1973 | errc::executable_format_error); |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 1974 | readDynamicRelocations(PLTRelSectionOrErr->getSectionRef(), |
| 1975 | /*IsJmpRel*/ true); |
Maksim Panchenko | 1de0746 | 2021-06-30 21:38:50 | [diff] [blame] | 1976 | } |
| 1977 | |
| 1978 | // The rest of dynamic relocations - DT_RELA. |
| 1979 | if (DynamicRelocationsSize > 0) { |
| 1980 | ErrorOr<BinarySection &> DynamicRelSectionOrErr = |
| 1981 | BC->getSectionForAddress(*DynamicRelocationsAddress); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1982 | if (!DynamicRelSectionOrErr) |
Maksim Panchenko | 1de0746 | 2021-06-30 21:38:50 | [diff] [blame] | 1983 | report_error("unable to find section corresponding to DT_RELA", |
| 1984 | DynamicRelSectionOrErr.getError()); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1985 | if (DynamicRelSectionOrErr->getSize() != DynamicRelocationsSize) |
Maksim Panchenko | 1de0746 | 2021-06-30 21:38:50 | [diff] [blame] | 1986 | report_error("section size mismatch for DT_RELASZ", |
| 1987 | errc::executable_format_error); |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 1988 | readDynamicRelocations(DynamicRelSectionOrErr->getSectionRef(), |
| 1989 | /*IsJmpRel*/ false); |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 1990 | } |
Maksim Panchenko | 38c5887 | 2021-06-22 20:46:06 | [diff] [blame] | 1991 | } |
| 1992 | |
| 1993 | void RewriteInstance::processRelocations() { |
| 1994 | if (!BC->HasRelocations) |
| 1995 | return; |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 1996 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 1997 | for (const SectionRef &Section : InputFile->sections()) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 1998 | if (cantFail(Section.getRelocatedSection()) != InputFile->section_end() && |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 1999 | !BinarySection(*BC, Section).isAllocatable()) |
Maksim Panchenko | d89bb53 | 2020-02-25 01:10:02 | [diff] [blame] | 2000 | readRelocations(Section); |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 2001 | } |
Vladislav Khmelevsky | a1036e4 | 2021-08-21 23:44:30 | [diff] [blame] | 2002 | |
| 2003 | if (NumFailedRelocations) |
| 2004 | errs() << "BOLT-WARNING: Failed to analyze " << NumFailedRelocations |
| 2005 | << " relocations\n"; |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 2006 | } |
| 2007 | |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2008 | void RewriteInstance::insertLKMarker(uint64_t PC, uint64_t SectionOffset, |
| 2009 | int32_t PCRelativeOffset, |
| 2010 | bool IsPCRelative, StringRef SectionName) { |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2011 | BC->LKMarkers[PC].emplace_back(LKInstructionMarkerInfo{ |
| 2012 | SectionOffset, PCRelativeOffset, IsPCRelative, SectionName}); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2013 | } |
| 2014 | |
| 2015 | void RewriteInstance::processLKSections() { |
| 2016 | assert(opts::LinuxKernelMode && |
| 2017 | "process Linux Kernel special sections and their relocations only in " |
| 2018 | "linux kernel mode.\n"); |
| 2019 | |
| 2020 | processLKExTable(); |
| 2021 | processLKPCIFixup(); |
| 2022 | processLKKSymtab(); |
| 2023 | processLKKSymtab(true); |
| 2024 | processLKBugTable(); |
| 2025 | processLKSMPLocks(); |
| 2026 | } |
| 2027 | |
| 2028 | /// Process __ex_table section of Linux Kernel. |
| 2029 | /// This section contains information regarding kernel level exception |
| 2030 | /// handling (https://www.kernel.org/doc/html/latest/x86/exception-tables.html). |
| 2031 | /// More documentation is in arch/x86/include/asm/extable.h. |
| 2032 | /// |
| 2033 | /// The section is the list of the following structures: |
| 2034 | /// |
| 2035 | /// struct exception_table_entry { |
| 2036 | /// int insn; |
| 2037 | /// int fixup; |
| 2038 | /// int handler; |
| 2039 | /// }; |
| 2040 | /// |
| 2041 | void RewriteInstance::processLKExTable() { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2042 | ErrorOr<BinarySection &> SectionOrError = |
| 2043 | BC->getUniqueSectionByName("__ex_table"); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2044 | if (!SectionOrError) |
| 2045 | return; |
| 2046 | |
| 2047 | const uint64_t SectionSize = SectionOrError->getSize(); |
| 2048 | const uint64_t SectionAddress = SectionOrError->getAddress(); |
| 2049 | assert((SectionSize % 12) == 0 && |
| 2050 | "The size of the __ex_table section should be a multiple of 12"); |
| 2051 | for (uint64_t I = 0; I < SectionSize; I += 4) { |
| 2052 | const uint64_t EntryAddress = SectionAddress + I; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2053 | ErrorOr<uint64_t> Offset = BC->getSignedValueAtAddress(EntryAddress, 4); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2054 | assert(Offset && "failed reading PC-relative offset for __ex_table"); |
| 2055 | int32_t SignedOffset = *Offset; |
| 2056 | const uint64_t RefAddress = EntryAddress + SignedOffset; |
| 2057 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2058 | BinaryFunction *ContainingBF = |
| 2059 | BC->getBinaryFunctionContainingAddress(RefAddress); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2060 | if (!ContainingBF) |
| 2061 | continue; |
| 2062 | |
| 2063 | MCSymbol *ReferencedSymbol = ContainingBF->getSymbol(); |
| 2064 | const uint64_t FunctionOffset = RefAddress - ContainingBF->getAddress(); |
| 2065 | switch (I % 12) { |
| 2066 | default: |
| 2067 | llvm_unreachable("bad alignment of __ex_table"); |
| 2068 | break; |
| 2069 | case 0: |
| 2070 | // insn |
| 2071 | insertLKMarker(RefAddress, I, SignedOffset, true, "__ex_table"); |
| 2072 | break; |
| 2073 | case 4: |
| 2074 | // fixup |
| 2075 | if (FunctionOffset) |
| 2076 | ReferencedSymbol = ContainingBF->addEntryPointAtOffset(FunctionOffset); |
Rafael Auler | 35632d4 | 2020-10-07 22:40:51 | [diff] [blame] | 2077 | BC->addRelocation(EntryAddress, ReferencedSymbol, Relocation::getPC32(), |
| 2078 | 0, *Offset); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2079 | break; |
| 2080 | case 8: |
| 2081 | // handler |
| 2082 | assert(!FunctionOffset && |
| 2083 | "__ex_table handler entry should point to function start"); |
Rafael Auler | 35632d4 | 2020-10-07 22:40:51 | [diff] [blame] | 2084 | BC->addRelocation(EntryAddress, ReferencedSymbol, Relocation::getPC32(), |
| 2085 | 0, *Offset); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2086 | break; |
| 2087 | } |
| 2088 | } |
| 2089 | } |
| 2090 | |
| 2091 | /// Process .pci_fixup section of Linux Kernel. |
| 2092 | /// This section contains a list of entries for different PCI devices and their |
| 2093 | /// corresponding hook handler (code pointer where the fixup |
| 2094 | /// code resides, usually on x86_64 it is an entry PC relative 32 bit offset). |
| 2095 | /// Documentation is in include/linux/pci.h. |
| 2096 | void RewriteInstance::processLKPCIFixup() { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2097 | ErrorOr<BinarySection &> SectionOrError = |
| 2098 | BC->getUniqueSectionByName(".pci_fixup"); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2099 | assert(SectionOrError && |
| 2100 | ".pci_fixup section not found in Linux Kernel binary"); |
| 2101 | const uint64_t SectionSize = SectionOrError->getSize(); |
| 2102 | const uint64_t SectionAddress = SectionOrError->getAddress(); |
| 2103 | assert((SectionSize % 16) == 0 && ".pci_fixup size is not a multiple of 16"); |
| 2104 | |
| 2105 | for (uint64_t I = 12; I + 4 <= SectionSize; I += 16) { |
| 2106 | const uint64_t PC = SectionAddress + I; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2107 | ErrorOr<uint64_t> Offset = BC->getSignedValueAtAddress(PC, 4); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2108 | assert(Offset && "cannot read value from .pci_fixup"); |
| 2109 | const int32_t SignedOffset = *Offset; |
| 2110 | const uint64_t HookupAddress = PC + SignedOffset; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2111 | BinaryFunction *HookupFunction = |
| 2112 | BC->getBinaryFunctionAtAddress(HookupAddress); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2113 | assert(HookupFunction && "expected function for entry in .pci_fixup"); |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2114 | BC->addRelocation(PC, HookupFunction->getSymbol(), Relocation::getPC32(), 0, |
| 2115 | *Offset); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2116 | } |
| 2117 | } |
| 2118 | |
| 2119 | /// Process __ksymtab[_gpl] sections of Linux Kernel. |
| 2120 | /// This section lists all the vmlinux symbols that kernel modules can access. |
| 2121 | /// |
| 2122 | /// All the entries are 4 bytes each and hence we can read them by one by one |
| 2123 | /// and ignore the ones that are not pointing to the .text section. All pointers |
| 2124 | /// are PC relative offsets. Always, points to the beginning of the function. |
| 2125 | void RewriteInstance::processLKKSymtab(bool IsGPL) { |
| 2126 | StringRef SectionName = "__ksymtab"; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2127 | if (IsGPL) |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2128 | SectionName = "__ksymtab_gpl"; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2129 | ErrorOr<BinarySection &> SectionOrError = |
| 2130 | BC->getUniqueSectionByName(SectionName); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2131 | assert(SectionOrError && |
| 2132 | "__ksymtab[_gpl] section not found in Linux Kernel binary"); |
| 2133 | const uint64_t SectionSize = SectionOrError->getSize(); |
| 2134 | const uint64_t SectionAddress = SectionOrError->getAddress(); |
| 2135 | assert((SectionSize % 4) == 0 && |
| 2136 | "The size of the __ksymtab[_gpl] section should be a multiple of 4"); |
| 2137 | |
| 2138 | for (uint64_t I = 0; I < SectionSize; I += 4) { |
| 2139 | const uint64_t EntryAddress = SectionAddress + I; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2140 | ErrorOr<uint64_t> Offset = BC->getSignedValueAtAddress(EntryAddress, 4); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2141 | assert(Offset && "Reading valid PC-relative offset for a ksymtab entry"); |
| 2142 | const int32_t SignedOffset = *Offset; |
| 2143 | const uint64_t RefAddress = EntryAddress + SignedOffset; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2144 | BinaryFunction *BF = BC->getBinaryFunctionAtAddress(RefAddress); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2145 | if (!BF) |
| 2146 | continue; |
| 2147 | |
Rafael Auler | 35632d4 | 2020-10-07 22:40:51 | [diff] [blame] | 2148 | BC->addRelocation(EntryAddress, BF->getSymbol(), Relocation::getPC32(), 0, |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2149 | *Offset); |
| 2150 | } |
| 2151 | } |
| 2152 | |
| 2153 | /// Process __bug_table section. |
| 2154 | /// This section contains information useful for kernel debugging. |
| 2155 | /// Each entry in the section is a struct bug_entry that contains a pointer to |
| 2156 | /// the ud2 instruction corresponding to the bug, corresponding file name (both |
| 2157 | /// pointers use PC relative offset addressing), line number, and flags. |
| 2158 | /// The definition of the struct bug_entry can be found in |
| 2159 | /// `include/asm-generic/bug.h` |
| 2160 | void RewriteInstance::processLKBugTable() { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2161 | ErrorOr<BinarySection &> SectionOrError = |
| 2162 | BC->getUniqueSectionByName("__bug_table"); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2163 | if (!SectionOrError) |
| 2164 | return; |
| 2165 | |
| 2166 | const uint64_t SectionSize = SectionOrError->getSize(); |
| 2167 | const uint64_t SectionAddress = SectionOrError->getAddress(); |
| 2168 | assert((SectionSize % 12) == 0 && |
| 2169 | "The size of the __bug_table section should be a multiple of 12"); |
| 2170 | for (uint64_t I = 0; I < SectionSize; I += 12) { |
| 2171 | const uint64_t EntryAddress = SectionAddress + I; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2172 | ErrorOr<uint64_t> Offset = BC->getSignedValueAtAddress(EntryAddress, 4); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2173 | assert(Offset && |
| 2174 | "Reading valid PC-relative offset for a __bug_table entry"); |
| 2175 | const int32_t SignedOffset = *Offset; |
| 2176 | const uint64_t RefAddress = EntryAddress + SignedOffset; |
Joey Thaman | 4c12afc | 2021-06-29 19:11:56 | [diff] [blame] | 2177 | assert(BC->getBinaryFunctionContainingAddress(RefAddress) && |
| 2178 | "__bug_table entries should point to a function"); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2179 | |
| 2180 | insertLKMarker(RefAddress, I, SignedOffset, true, "__bug_table"); |
| 2181 | } |
| 2182 | } |
| 2183 | |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2184 | /// .smp_locks section contains PC-relative references to instructions with LOCK |
| 2185 | /// prefix. The prefix can be converted to NOP at boot time on non-SMP systems. |
| 2186 | void RewriteInstance::processLKSMPLocks() { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2187 | ErrorOr<BinarySection &> SectionOrError = |
| 2188 | BC->getUniqueSectionByName(".smp_locks"); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2189 | if (!SectionOrError) |
| 2190 | return; |
| 2191 | |
| 2192 | uint64_t SectionSize = SectionOrError->getSize(); |
| 2193 | const uint64_t SectionAddress = SectionOrError->getAddress(); |
| 2194 | assert((SectionSize % 4) == 0 && |
| 2195 | "The size of the .smp_locks section should be a multiple of 4"); |
| 2196 | |
| 2197 | for (uint64_t I = 0; I < SectionSize; I += 4) { |
| 2198 | const uint64_t EntryAddress = SectionAddress + I; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2199 | ErrorOr<uint64_t> Offset = BC->getSignedValueAtAddress(EntryAddress, 4); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2200 | assert(Offset && "Reading valid PC-relative offset for a .smp_locks entry"); |
| 2201 | int32_t SignedOffset = *Offset; |
| 2202 | uint64_t RefAddress = EntryAddress + SignedOffset; |
| 2203 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2204 | BinaryFunction *ContainingBF = |
| 2205 | BC->getBinaryFunctionContainingAddress(RefAddress); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 2206 | if (!ContainingBF) |
| 2207 | continue; |
| 2208 | |
| 2209 | insertLKMarker(RefAddress, I, SignedOffset, true, ".smp_locks"); |
| 2210 | } |
| 2211 | } |
| 2212 | |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 2213 | void RewriteInstance::readDynamicRelocations(const SectionRef &Section, |
| 2214 | bool IsJmpRel) { |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 2215 | assert(BinarySection(*BC, Section).isAllocatable() && "allocatable expected"); |
| 2216 | |
Joey Thaman | 4c12afc | 2021-06-29 19:11:56 | [diff] [blame] | 2217 | LLVM_DEBUG({ |
| 2218 | StringRef SectionName = cantFail(Section.getName()); |
| 2219 | dbgs() << "BOLT-DEBUG: reading relocations for section " << SectionName |
| 2220 | << ":\n"; |
| 2221 | }); |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 2222 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2223 | for (const RelocationRef &Rel : Section.relocations()) { |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 2224 | const uint64_t RType = Rel.getType(); |
Vladislav Khmelevsky | ec9751e | 2021-02-17 23:36:58 | [diff] [blame] | 2225 | if (Relocation::isNone(RType)) |
| 2226 | continue; |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 2227 | |
| 2228 | StringRef SymbolName = "<none>"; |
| 2229 | MCSymbol *Symbol = nullptr; |
| 2230 | uint64_t SymbolAddress = 0; |
| 2231 | const uint64_t Addend = getRelocationAddend(InputFile, Rel); |
| 2232 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2233 | symbol_iterator SymbolIter = Rel.getSymbol(); |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 2234 | if (SymbolIter != InputFile->symbol_end()) { |
| 2235 | SymbolName = cantFail(SymbolIter->getName()); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2236 | BinaryData *BD = BC->getBinaryDataByName(SymbolName); |
Maksim Panchenko | 1de0746 | 2021-06-30 21:38:50 | [diff] [blame] | 2237 | Symbol = BD ? BD->getSymbol() |
| 2238 | : BC->getOrCreateUndefinedGlobalSymbol(SymbolName); |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 2239 | SymbolAddress = cantFail(SymbolIter->getAddress()); |
| 2240 | (void)SymbolAddress; |
| 2241 | } |
| 2242 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 2243 | LLVM_DEBUG( |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 2244 | SmallString<16> TypeName; |
| 2245 | Rel.getTypeName(TypeName); |
| 2246 | dbgs() << "BOLT-DEBUG: dynamic relocation at 0x" |
| 2247 | << Twine::utohexstr(Rel.getOffset()) << " : " << TypeName |
| 2248 | << " : " << SymbolName << " : " << Twine::utohexstr(SymbolAddress) |
| 2249 | << " : + 0x" << Twine::utohexstr(Addend) << '\n' |
| 2250 | ); |
| 2251 | |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 2252 | if (IsJmpRel) |
| 2253 | IsJmpRelocation[RType] = true; |
| 2254 | |
| 2255 | if (Symbol) |
| 2256 | SymbolIndex[Symbol] = getRelocationSymbol(InputFile, Rel); |
| 2257 | |
| 2258 | BC->addDynamicRelocation(Rel.getOffset(), Symbol, RType, Addend); |
Maksim Panchenko | d89bb53 | 2020-02-25 01:10:02 | [diff] [blame] | 2259 | } |
| 2260 | } |
| 2261 | |
| 2262 | void RewriteInstance::readRelocations(const SectionRef &Section) { |
Joey Thaman | 4c12afc | 2021-06-29 19:11:56 | [diff] [blame] | 2263 | LLVM_DEBUG({ |
| 2264 | StringRef SectionName = cantFail(Section.getName()); |
| 2265 | dbgs() << "BOLT-DEBUG: reading relocations for section " << SectionName |
| 2266 | << ":\n"; |
| 2267 | }); |
Maksim Panchenko | ce508b5 | 2018-09-21 19:00:20 | [diff] [blame] | 2268 | if (BinarySection(*BC, Section).isAllocatable()) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 2269 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: ignoring runtime relocations\n"); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2270 | return; |
| 2271 | } |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2272 | section_iterator SecIter = cantFail(Section.getRelocatedSection()); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2273 | assert(SecIter != InputFile->section_end() && "relocated section expected"); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2274 | SectionRef RelocatedSection = *SecIter; |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2275 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 2276 | StringRef RelocatedSectionName = cantFail(RelocatedSection.getName()); |
| 2277 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: relocated section is " |
| 2278 | << RelocatedSectionName << '\n'); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2279 | |
Maksim Panchenko | ce508b5 | 2018-09-21 19:00:20 | [diff] [blame] | 2280 | if (!BinarySection(*BC, RelocatedSection).isAllocatable()) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 2281 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: ignoring relocations against " |
| 2282 | << "non-allocatable section\n"); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2283 | return; |
| 2284 | } |
| 2285 | const bool SkipRelocs = StringSwitch<bool>(RelocatedSectionName) |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 2286 | .Cases(".plt", ".rela.plt", ".got.plt", |
| 2287 | ".eh_frame", ".gcc_except_table", true) |
| 2288 | .Default(false); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2289 | if (SkipRelocs) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 2290 | LLVM_DEBUG( |
| 2291 | dbgs() << "BOLT-DEBUG: ignoring relocations against known section\n"); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2292 | return; |
| 2293 | } |
| 2294 | |
Rafael Auler | 7df6a6d | 2018-03-20 21:34:58 | [diff] [blame] | 2295 | const bool IsAArch64 = BC->isAArch64(); |
Bill Nell | 89feb84 | 2018-01-24 13:42:11 | [diff] [blame] | 2296 | const bool IsFromCode = RelocatedSection.isText(); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2297 | |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 2298 | auto printRelocationInfo = [&](const RelocationRef &Rel, |
| 2299 | StringRef SymbolName, |
| 2300 | uint64_t SymbolAddress, |
| 2301 | uint64_t Addend, |
| 2302 | uint64_t ExtractedValue) { |
| 2303 | SmallString<16> TypeName; |
| 2304 | Rel.getTypeName(TypeName); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2305 | const uint64_t Address = SymbolAddress + Addend; |
| 2306 | ErrorOr<BinarySection &> Section = BC->getSectionForAddress(SymbolAddress); |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 2307 | dbgs() << "Relocation: offset = 0x" |
| 2308 | << Twine::utohexstr(Rel.getOffset()) |
Maksim Panchenko | 771d976 | 2018-07-12 17:13:03 | [diff] [blame] | 2309 | << "; type = " << TypeName |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 2310 | << "; value = 0x" << Twine::utohexstr(ExtractedValue) |
| 2311 | << "; symbol = " << SymbolName |
| 2312 | << " (" << (Section ? Section->getName() : "") << ")" |
| 2313 | << "; symbol address = 0x" << Twine::utohexstr(SymbolAddress) |
| 2314 | << "; addend = 0x" << Twine::utohexstr(Addend) |
| 2315 | << "; address = 0x" << Twine::utohexstr(Address) |
| 2316 | << "; in = "; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2317 | if (BinaryFunction *Func = BC->getBinaryFunctionContainingAddress( |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2318 | Rel.getOffset(), false, IsAArch64)) |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 2319 | dbgs() << Func->getPrintName() << "\n"; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2320 | else |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 2321 | dbgs() << BC->getSectionForAddress(Rel.getOffset())->getName() << "\n"; |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 2322 | }; |
| 2323 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2324 | for (const RelocationRef &Rel : Section.relocations()) { |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2325 | SmallString<16> TypeName; |
| 2326 | Rel.getTypeName(TypeName); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2327 | uint64_t RType = Rel.getType(); |
Vladislav Khmelevsky | 6e26ffa | 2022-06-09 16:00:24 | [diff] [blame] | 2328 | if (Relocation::skipRelocationType(RType)) |
Vladislav Khmelevsky | dc4b32e | 2021-10-17 13:36:24 | [diff] [blame] | 2329 | continue; |
Maksim Panchenko | e50e89b | 2019-04-12 00:11:08 | [diff] [blame] | 2330 | |
| 2331 | // Adjust the relocation type as the linker might have skewed it. |
| 2332 | if (BC->isX86() && (RType & ELF::R_X86_64_converted_reloc_bit)) { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2333 | if (opts::Verbosity >= 1) |
Maksim Panchenko | e50e89b | 2019-04-12 00:11:08 | [diff] [blame] | 2334 | dbgs() << "BOLT-WARNING: ignoring R_X86_64_converted_reloc_bit\n"; |
Maksim Panchenko | e50e89b | 2019-04-12 00:11:08 | [diff] [blame] | 2335 | RType &= ~ELF::R_X86_64_converted_reloc_bit; |
| 2336 | } |
Bill Nell | 89feb84 | 2018-01-24 13:42:11 | [diff] [blame] | 2337 | |
Vladislav Khmelevsky | 542c03c | 2021-09-02 18:04:33 | [diff] [blame] | 2338 | if (Relocation::isTLS(RType)) { |
| 2339 | // No special handling required for TLS relocations on X86. |
| 2340 | if (BC->isX86()) |
| 2341 | continue; |
| 2342 | |
| 2343 | // The non-got related TLS relocations on AArch64 also could be skipped. |
| 2344 | if (!Relocation::isGOT(RType)) |
| 2345 | continue; |
| 2346 | } |
Maksim Panchenko | e89ad0d | 2019-06-28 16:21:27 | [diff] [blame] | 2347 | |
Vladislav Khmelevsky | 3b1314f | 2022-03-20 14:15:56 | [diff] [blame] | 2348 | if (!IsAArch64 && BC->getDynamicRelocationAt(Rel.getOffset())) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 2349 | LLVM_DEBUG( |
| 2350 | dbgs() << "BOLT-DEBUG: address 0x" |
| 2351 | << Twine::utohexstr(Rel.getOffset()) |
| 2352 | << " has a dynamic relocation against it. Ignoring static " |
| 2353 | "relocation.\n"); |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 2354 | continue; |
| 2355 | } |
| 2356 | |
Bill Nell | 89feb84 | 2018-01-24 13:42:11 | [diff] [blame] | 2357 | std::string SymbolName; |
| 2358 | uint64_t SymbolAddress; |
| 2359 | int64_t Addend; |
| 2360 | uint64_t ExtractedValue; |
Maksim Panchenko | ce508b5 | 2018-09-21 19:00:20 | [diff] [blame] | 2361 | bool IsSectionRelocation; |
Vladislav Khmelevsky | 00c0659 | 2021-09-08 10:37:19 | [diff] [blame] | 2362 | bool Skip; |
| 2363 | if (!analyzeRelocation(Rel, RType, SymbolName, IsSectionRelocation, |
| 2364 | SymbolAddress, Addend, ExtractedValue, Skip)) { |
| 2365 | LLVM_DEBUG(dbgs() << "BOLT-WARNING: failed to analyze relocation @ " |
| 2366 | << "offset = 0x" << Twine::utohexstr(Rel.getOffset()) |
| 2367 | << "; type name = " << TypeName << '\n'); |
| 2368 | ++NumFailedRelocations; |
| 2369 | continue; |
| 2370 | } |
| 2371 | |
| 2372 | if (Skip) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 2373 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: skipping relocation @ offset = 0x" |
| 2374 | << Twine::utohexstr(Rel.getOffset()) |
| 2375 | << "; type name = " << TypeName << '\n'); |
Maksim Panchenko | 29d4f4c | 2017-09-13 18:21:47 | [diff] [blame] | 2376 | continue; |
| 2377 | } |
| 2378 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2379 | const uint64_t Address = SymbolAddress + Addend; |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2380 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2381 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: "; printRelocationInfo( |
| 2382 | Rel, SymbolName, SymbolAddress, Addend, ExtractedValue)); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2383 | |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2384 | BinaryFunction *ContainingBF = nullptr; |
| 2385 | if (IsFromCode) { |
Bill Nell | 89feb84 | 2018-01-24 13:42:11 | [diff] [blame] | 2386 | ContainingBF = |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2387 | BC->getBinaryFunctionContainingAddress(Rel.getOffset(), |
| 2388 | /*CheckPastEnd*/ false, |
| 2389 | /*UseMaxSize*/ true); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2390 | assert(ContainingBF && "cannot find function for address in code"); |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 2391 | if (!IsAArch64 && !ContainingBF->containsAddress(Rel.getOffset())) { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2392 | if (opts::Verbosity >= 1) |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 2393 | outs() << "BOLT-INFO: " << *ContainingBF |
| 2394 | << " has relocations in padding area\n"; |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 2395 | ContainingBF->setSize(ContainingBF->getMaxSize()); |
| 2396 | ContainingBF->setSimple(false); |
| 2397 | continue; |
| 2398 | } |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2399 | } |
| 2400 | |
Maksim Panchenko | 4101aa13 | 2022-02-24 06:54:42 | [diff] [blame] | 2401 | MCSymbol *ReferencedSymbol = nullptr; |
Maksim Panchenko | 36cb736 | 2022-04-13 01:42:19 | [diff] [blame] | 2402 | if (!IsSectionRelocation) |
Maksim Panchenko | 4101aa13 | 2022-02-24 06:54:42 | [diff] [blame] | 2403 | if (BinaryData *BD = BC->getBinaryDataByName(SymbolName)) |
| 2404 | ReferencedSymbol = BD->getSymbol(); |
Maksim Panchenko | 4101aa13 | 2022-02-24 06:54:42 | [diff] [blame] | 2405 | |
Maksim Panchenko | 36cb736 | 2022-04-13 01:42:19 | [diff] [blame] | 2406 | ErrorOr<BinarySection &> ReferencedSection = |
| 2407 | BC->getSectionForAddress(SymbolAddress); |
| 2408 | |
| 2409 | const bool IsToCode = ReferencedSection && ReferencedSection->isText(); |
| 2410 | |
| 2411 | // Special handling of PC-relative relocations. |
Maksim Panchenko | e50e89b | 2019-04-12 00:11:08 | [diff] [blame] | 2412 | if (!IsAArch64 && Relocation::isPCRelative(RType)) { |
Maksim Panchenko | 36cb736 | 2022-04-13 01:42:19 | [diff] [blame] | 2413 | if (!IsFromCode && IsToCode) { |
| 2414 | // PC-relative relocations from data to code are tricky since the |
| 2415 | // original information is typically lost after linking, even with |
| 2416 | // '--emit-relocs'. Such relocations are normally used by PIC-style |
| 2417 | // jump tables and they reference both the jump table and jump |
| 2418 | // targets by computing the difference between the two. If we blindly |
| 2419 | // apply the relocation, it will appear that it references an arbitrary |
| 2420 | // location in the code, possibly in a different function from the one |
| 2421 | // containing the jump table. |
| 2422 | // |
| 2423 | // For that reason, we only register the fact that there is a |
| 2424 | // PC-relative relocation at a given address against the code. |
| 2425 | // The actual referenced label/address will be determined during jump |
| 2426 | // table analysis. |
Maksim Panchenko | 658f270 | 2019-11-20 02:52:08 | [diff] [blame] | 2427 | BC->addPCRelativeDataRelocation(Rel.getOffset()); |
Maksim Panchenko | 36cb736 | 2022-04-13 01:42:19 | [diff] [blame] | 2428 | } else if (ContainingBF && !IsSectionRelocation && ReferencedSymbol) { |
| 2429 | // If we know the referenced symbol, register the relocation from |
| 2430 | // the code. It's required to properly handle cases where |
| 2431 | // "symbol + addend" references an object different from "symbol". |
Maksim Panchenko | 4101aa13 | 2022-02-24 06:54:42 | [diff] [blame] | 2432 | ContainingBF->addRelocation(Rel.getOffset(), ReferencedSymbol, RType, |
| 2433 | Addend, ExtractedValue); |
Maksim Panchenko | 36cb736 | 2022-04-13 01:42:19 | [diff] [blame] | 2434 | } else { |
Maksim Panchenko | 4101aa13 | 2022-02-24 06:54:42 | [diff] [blame] | 2435 | LLVM_DEBUG( |
| 2436 | dbgs() << "BOLT-DEBUG: not creating PC-relative relocation at 0x" |
| 2437 | << Twine::utohexstr(Rel.getOffset()) << " for " << SymbolName |
| 2438 | << "\n"); |
Maksim Panchenko | 36cb736 | 2022-04-13 01:42:19 | [diff] [blame] | 2439 | } |
| 2440 | |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2441 | continue; |
| 2442 | } |
| 2443 | |
Maksim Panchenko | db4642d | 2020-06-18 18:10:41 | [diff] [blame] | 2444 | bool ForceRelocation = BC->forceSymbolRelocations(SymbolName); |
Maksim Panchenko | 36cb736 | 2022-04-13 01:42:19 | [diff] [blame] | 2445 | if (BC->isAArch64() && Relocation::isGOT(RType)) |
Vladislav Khmelevsky | 542c03c | 2021-09-02 18:04:33 | [diff] [blame] | 2446 | ForceRelocation = true; |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2447 | |
Maksim Panchenko | 36cb736 | 2022-04-13 01:42:19 | [diff] [blame] | 2448 | if (!ReferencedSection && !ForceRelocation) { |
| 2449 | LLVM_DEBUG( |
| 2450 | dbgs() << "BOLT-DEBUG: cannot determine referenced section.\n"); |
| 2451 | continue; |
| 2452 | } |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2453 | |
| 2454 | // Occasionally we may see a reference past the last byte of the function |
| 2455 | // typically as a result of __builtin_unreachable(). Check it here. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2456 | BinaryFunction *ReferencedBF = BC->getBinaryFunctionContainingAddress( |
Rafael Auler | d6003e9 | 2018-04-12 17:07:11 | [diff] [blame] | 2457 | Address, /*CheckPastEnd*/ true, /*UseMaxSize*/ IsAArch64); |
Maksim Panchenko | 3af35373 | 2018-05-14 18:10:26 | [diff] [blame] | 2458 | |
| 2459 | if (!IsSectionRelocation) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2460 | if (BinaryFunction *BF = |
| 2461 | BC->getBinaryFunctionContainingAddress(SymbolAddress)) { |
Maksim Panchenko | 3af35373 | 2018-05-14 18:10:26 | [diff] [blame] | 2462 | if (BF != ReferencedBF) { |
| 2463 | // It's possible we are referencing a function without referencing any |
| 2464 | // code, e.g. when taking a bitmask action on a function address. |
| 2465 | errs() << "BOLT-WARNING: non-standard function reference (e.g. " |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2466 | "bitmask) detected against function " |
| 2467 | << *BF; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2468 | if (IsFromCode) |
Maksim Panchenko | 3af35373 | 2018-05-14 18:10:26 | [diff] [blame] | 2469 | errs() << " from function " << *ContainingBF << '\n'; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2470 | else |
Maksim Panchenko | 3af35373 | 2018-05-14 18:10:26 | [diff] [blame] | 2471 | errs() << " from data section at 0x" |
| 2472 | << Twine::utohexstr(Rel.getOffset()) << '\n'; |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2473 | LLVM_DEBUG(printRelocationInfo(Rel, SymbolName, SymbolAddress, Addend, |
| 2474 | ExtractedValue)); |
Maksim Panchenko | 3af35373 | 2018-05-14 18:10:26 | [diff] [blame] | 2475 | ReferencedBF = BF; |
| 2476 | } |
| 2477 | } |
Maksim Panchenko | 06e7a1e | 2019-06-27 10:20:17 | [diff] [blame] | 2478 | } else if (ReferencedBF) { |
Maksim Panchenko | 36cb736 | 2022-04-13 01:42:19 | [diff] [blame] | 2479 | assert(ReferencedSection && "section expected for section relocation"); |
| 2480 | if (*ReferencedBF->getOriginSection() != *ReferencedSection) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 2481 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: ignoring false function reference\n"); |
Maksim Panchenko | 06e7a1e | 2019-06-27 10:20:17 | [diff] [blame] | 2482 | ReferencedBF = nullptr; |
| 2483 | } |
Maksim Panchenko | 3af35373 | 2018-05-14 18:10:26 | [diff] [blame] | 2484 | } |
| 2485 | |
Maksim Panchenko | c823220 | 2019-09-17 21:24:31 | [diff] [blame] | 2486 | // Workaround for a member function pointer de-virtualization bug. We check |
| 2487 | // if a non-pc-relative relocation in the code is pointing to (fptr - 1). |
| 2488 | if (IsToCode && ContainingBF && !Relocation::isPCRelative(RType) && |
| 2489 | (!ReferencedBF || (ReferencedBF->getAddress() != Address))) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2490 | if (const BinaryFunction *RogueBF = |
| 2491 | BC->getBinaryFunctionAtAddress(Address + 1)) { |
Maksim Panchenko | c823220 | 2019-09-17 21:24:31 | [diff] [blame] | 2492 | // Do an extra check that the function was referenced previously. |
| 2493 | // It's a linear search, but it should rarely happen. |
Maksim Panchenko | fe37f18 | 2021-05-13 17:50:47 | [diff] [blame] | 2494 | bool Found = false; |
Maksim Panchenko | c823220 | 2019-09-17 21:24:31 | [diff] [blame] | 2495 | for (const auto &RelKV : ContainingBF->Relocations) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2496 | const Relocation &Rel = RelKV.second; |
Maksim Panchenko | c823220 | 2019-09-17 21:24:31 | [diff] [blame] | 2497 | if (Rel.Symbol == RogueBF->getSymbol() && |
| 2498 | !Relocation::isPCRelative(Rel.Type)) { |
| 2499 | Found = true; |
| 2500 | break; |
| 2501 | } |
| 2502 | } |
| 2503 | |
| 2504 | if (Found) { |
| 2505 | errs() << "BOLT-WARNING: detected possible compiler " |
| 2506 | "de-virtualization bug: -1 addend used with " |
| 2507 | "non-pc-relative relocation against function " |
| 2508 | << *RogueBF << " in function " << *ContainingBF << '\n'; |
| 2509 | continue; |
| 2510 | } |
| 2511 | } |
| 2512 | } |
| 2513 | |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2514 | if (ForceRelocation) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2515 | std::string Name = Relocation::isGOT(RType) ? "Zero" : SymbolName; |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 2516 | ReferencedSymbol = BC->registerNameAtAddress(Name, 0, 0, 0); |
Bill Nell | 89feb84 | 2018-01-24 13:42:11 | [diff] [blame] | 2517 | SymbolAddress = 0; |
Maksim Panchenko | e50e89b | 2019-04-12 00:11:08 | [diff] [blame] | 2518 | if (Relocation::isGOT(RType)) |
Rafael Auler | d0a80b0 | 2018-08-29 01:15:13 | [diff] [blame] | 2519 | Addend = Address; |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 2520 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: forcing relocation against symbol " |
| 2521 | << SymbolName << " with addend " << Addend << '\n'); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2522 | } else if (ReferencedBF) { |
Maksim Panchenko | 3af35373 | 2018-05-14 18:10:26 | [diff] [blame] | 2523 | ReferencedSymbol = ReferencedBF->getSymbol(); |
Maksim Panchenko | a09659f | 2019-11-18 22:08:17 | [diff] [blame] | 2524 | uint64_t RefFunctionOffset = 0; |
Maksim Panchenko | 3af35373 | 2018-05-14 18:10:26 | [diff] [blame] | 2525 | |
| 2526 | // Adjust the point of reference to a code location inside a function. |
| 2527 | if (ReferencedBF->containsAddress(Address, /*UseMaxSize = */true)) { |
| 2528 | RefFunctionOffset = Address - ReferencedBF->getAddress(); |
| 2529 | if (RefFunctionOffset) { |
Maksim Panchenko | efce443 | 2020-06-22 20:05:13 | [diff] [blame] | 2530 | if (ContainingBF && ContainingBF != ReferencedBF) { |
| 2531 | ReferencedSymbol = |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2532 | ReferencedBF->addEntryPointAtOffset(RefFunctionOffset); |
Maksim Panchenko | efce443 | 2020-06-22 20:05:13 | [diff] [blame] | 2533 | } else { |
| 2534 | ReferencedSymbol = |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2535 | ReferencedBF->getOrCreateLocalLabel(Address, |
| 2536 | /*CreatePastEnd =*/true); |
Maksim Panchenko | efce443 | 2020-06-22 20:05:13 | [diff] [blame] | 2537 | ReferencedBF->registerReferencedOffset(RefFunctionOffset); |
| 2538 | } |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 2539 | if (opts::Verbosity > 1 && |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2540 | !BinarySection(*BC, RelocatedSection).isReadOnly()) |
| 2541 | errs() << "BOLT-WARNING: writable reference into the middle of " |
Maksim Panchenko | e89ad0d | 2019-06-28 16:21:27 | [diff] [blame] | 2542 | << "the function " << *ReferencedBF |
| 2543 | << " detected at address 0x" |
| 2544 | << Twine::utohexstr(Rel.getOffset()) << '\n'; |
Maksim Panchenko | 3af35373 | 2018-05-14 18:10:26 | [diff] [blame] | 2545 | } |
| 2546 | SymbolAddress = Address; |
| 2547 | Addend = 0; |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2548 | } |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 2549 | LLVM_DEBUG( |
Maksim Panchenko | 3af35373 | 2018-05-14 18:10:26 | [diff] [blame] | 2550 | dbgs() << " referenced function " << *ReferencedBF; |
| 2551 | if (Address != ReferencedBF->getAddress()) |
| 2552 | dbgs() << " at offset 0x" << Twine::utohexstr(RefFunctionOffset); |
| 2553 | dbgs() << '\n' |
| 2554 | ); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2555 | } else { |
Maksim Panchenko | e89ad0d | 2019-06-28 16:21:27 | [diff] [blame] | 2556 | if (IsToCode && SymbolAddress) { |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2557 | // This can happen e.g. with PIC-style jump tables. |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 2558 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: no corresponding function for " |
| 2559 | "relocation against code\n"); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2560 | } |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 2561 | |
Rafael Auler | 7df6a6d | 2018-03-20 21:34:58 | [diff] [blame] | 2562 | // In AArch64 there are zero reasons to keep a reference to the |
| 2563 | // "original" symbol plus addend. The original symbol is probably just a |
| 2564 | // section symbol. If we are here, this means we are probably accessing |
| 2565 | // data, so it is imperative to keep the original address. |
| 2566 | if (IsAArch64) { |
| 2567 | SymbolName = ("SYMBOLat0x" + Twine::utohexstr(Address)).str(); |
| 2568 | SymbolAddress = Address; |
| 2569 | Addend = 0; |
| 2570 | } |
| 2571 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2572 | if (BinaryData *BD = BC->getBinaryDataContainingAddress(SymbolAddress)) { |
Rafael Auler | 7df6a6d | 2018-03-20 21:34:58 | [diff] [blame] | 2573 | // Note: this assertion is trying to check sanity of BinaryData objects |
| 2574 | // but AArch64 has inferred and incomplete object locations coming from |
| 2575 | // GOT/TLS or any other non-trivial relocation (that requires creation |
| 2576 | // of sections and whose symbol address is not really what should be |
| 2577 | // encoded in the instruction). So we essentially disabled this check |
| 2578 | // for AArch64 and live with bogus names for objects. |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2579 | assert((IsAArch64 || IsSectionRelocation || |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 2580 | BD->nameStartsWith(SymbolName) || |
| 2581 | BD->nameStartsWith("PG" + SymbolName) || |
| 2582 | (BD->nameStartsWith("ANONYMOUS") && |
| 2583 | (BD->getSectionName().startswith(".plt") || |
| 2584 | BD->getSectionName().endswith(".plt")))) && |
Maksim Panchenko | a7d0251 | 2018-06-14 21:27:20 | [diff] [blame] | 2585 | "BOLT symbol names of all non-section relocations must match " |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 2586 | "up with symbol names referenced in the relocation"); |
| 2587 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2588 | if (IsSectionRelocation) |
Maksim Panchenko | a09659f | 2019-11-18 22:08:17 | [diff] [blame] | 2589 | BC->markAmbiguousRelocations(*BD, Address); |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 2590 | |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 2591 | ReferencedSymbol = BD->getSymbol(); |
| 2592 | Addend += (SymbolAddress - BD->getAddress()); |
| 2593 | SymbolAddress = BD->getAddress(); |
| 2594 | assert(Address == SymbolAddress + Addend); |
| 2595 | } else { |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 2596 | // These are mostly local data symbols but undefined symbols |
| 2597 | // in relocation sections can get through here too, from .plt. |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2598 | assert( |
| 2599 | (IsAArch64 || IsSectionRelocation || |
| 2600 | BC->getSectionNameForAddress(SymbolAddress)->startswith(".plt")) && |
| 2601 | "known symbols should not resolve to anonymous locals"); |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 2602 | |
Maksim Panchenko | ce508b5 | 2018-09-21 19:00:20 | [diff] [blame] | 2603 | if (IsSectionRelocation) { |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2604 | ReferencedSymbol = |
| 2605 | BC->getOrCreateGlobalSymbol(SymbolAddress, "SYMBOLat"); |
Maksim Panchenko | ce508b5 | 2018-09-21 19:00:20 | [diff] [blame] | 2606 | } else { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2607 | SymbolRef Symbol = *Rel.getSymbol(); |
Maksim Panchenko | ce508b5 | 2018-09-21 19:00:20 | [diff] [blame] | 2608 | const uint64_t SymbolSize = |
| 2609 | IsAArch64 ? 0 : ELFSymbolRef(Symbol).getSize(); |
| 2610 | const uint64_t SymbolAlignment = |
| 2611 | IsAArch64 ? 1 : Symbol.getAlignment(); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2612 | const uint32_t SymbolFlags = cantFail(Symbol.getFlags()); |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 2613 | std::string Name; |
Maksim Panchenko | ce508b5 | 2018-09-21 19:00:20 | [diff] [blame] | 2614 | if (SymbolFlags & SymbolRef::SF_Global) { |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 2615 | Name = SymbolName; |
Rafael Auler | 7df6a6d | 2018-03-20 21:34:58 | [diff] [blame] | 2616 | } else { |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2617 | if (StringRef(SymbolName) |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2618 | .startswith(BC->AsmInfo->getPrivateGlobalPrefix())) |
Alexander Shaposhnikov | 16630f5 | 2020-02-17 22:37:46 | [diff] [blame] | 2619 | Name = NR.uniquify("PG" + SymbolName); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2620 | else |
Alexander Shaposhnikov | 16630f5 | 2020-02-17 22:37:46 | [diff] [blame] | 2621 | Name = NR.uniquify(SymbolName); |
Rafael Auler | 7df6a6d | 2018-03-20 21:34:58 | [diff] [blame] | 2622 | } |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2623 | ReferencedSymbol = BC->registerNameAtAddress( |
| 2624 | Name, SymbolAddress, SymbolSize, SymbolAlignment, SymbolFlags); |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 2625 | } |
| 2626 | |
Maksim Panchenko | cb9c991 | 2020-03-03 23:51:24 | [diff] [blame] | 2627 | if (IsSectionRelocation) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2628 | BinaryData *BD = BC->getBinaryDataByName(ReferencedSymbol->getName()); |
Maksim Panchenko | a09659f | 2019-11-18 22:08:17 | [diff] [blame] | 2629 | BC->markAmbiguousRelocations(*BD, Address); |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 2630 | } |
| 2631 | } |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2632 | } |
| 2633 | |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 2634 | auto checkMaxDataRelocations = [&]() { |
| 2635 | ++NumDataRelocations; |
| 2636 | if (opts::MaxDataRelocations && |
| 2637 | NumDataRelocations + 1 == opts::MaxDataRelocations) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 2638 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: processing ending on data relocation " |
| 2639 | << NumDataRelocations << ": "); |
| 2640 | printRelocationInfo(Rel, ReferencedSymbol->getName(), SymbolAddress, |
| 2641 | Addend, ExtractedValue); |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 2642 | } |
| 2643 | |
| 2644 | return (!opts::MaxDataRelocations || |
| 2645 | NumDataRelocations < opts::MaxDataRelocations); |
| 2646 | }; |
| 2647 | |
Maksim Panchenko | 36cb736 | 2022-04-13 01:42:19 | [diff] [blame] | 2648 | if ((ReferencedSection && refersToReorderedSection(ReferencedSection)) || |
Maksim Panchenko | 771d976 | 2018-07-12 17:13:03 | [diff] [blame] | 2649 | (opts::ForceToDataRelocations && checkMaxDataRelocations())) |
| 2650 | ForceRelocation = true; |
| 2651 | |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2652 | if (IsFromCode) { |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2653 | ContainingBF->addRelocation(Rel.getOffset(), ReferencedSymbol, RType, |
| 2654 | Addend, ExtractedValue); |
Maksim Panchenko | 771d976 | 2018-07-12 17:13:03 | [diff] [blame] | 2655 | } else if (IsToCode || ForceRelocation) { |
Maksim Panchenko | e89ad0d | 2019-06-28 16:21:27 | [diff] [blame] | 2656 | BC->addRelocation(Rel.getOffset(), ReferencedSymbol, RType, Addend, |
| 2657 | ExtractedValue); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2658 | } else { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 2659 | LLVM_DEBUG( |
| 2660 | dbgs() << "BOLT-DEBUG: ignoring relocation from data to data\n"); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2661 | } |
| 2662 | } |
| 2663 | } |
| 2664 | |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2665 | void RewriteInstance::selectFunctionsToProcess() { |
| 2666 | // Extend the list of functions to process or skip from a file. |
| 2667 | auto populateFunctionNames = [](cl::opt<std::string> &FunctionNamesFile, |
| 2668 | cl::list<std::string> &FunctionNames) { |
| 2669 | if (FunctionNamesFile.empty()) |
| 2670 | return; |
| 2671 | std::ifstream FuncsFile(FunctionNamesFile, std::ios::in); |
| 2672 | std::string FuncName; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2673 | while (std::getline(FuncsFile, FuncName)) |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2674 | FunctionNames.push_back(FuncName); |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2675 | }; |
| 2676 | populateFunctionNames(opts::FunctionNamesFile, opts::ForceFunctionNames); |
| 2677 | populateFunctionNames(opts::SkipFunctionNamesFile, opts::SkipFunctionNames); |
Amir Ayupov | d474dbd | 2021-06-05 01:49:29 | [diff] [blame] | 2678 | populateFunctionNames(opts::FunctionNamesFileNR, opts::ForceFunctionNamesNR); |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2679 | |
Amir Ayupov | d474dbd | 2021-06-05 01:49:29 | [diff] [blame] | 2680 | // Make a set of functions to process to speed up lookups. |
| 2681 | std::unordered_set<std::string> ForceFunctionsNR( |
| 2682 | opts::ForceFunctionNamesNR.begin(), opts::ForceFunctionNamesNR.end()); |
| 2683 | |
| 2684 | if ((!opts::ForceFunctionNames.empty() || |
| 2685 | !opts::ForceFunctionNamesNR.empty()) && |
| 2686 | !opts::SkipFunctionNames.empty()) { |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2687 | errs() << "BOLT-ERROR: cannot select functions to process and skip at the " |
| 2688 | "same time. Please use only one type of selection.\n"; |
| 2689 | exit(1); |
| 2690 | } |
| 2691 | |
Rafael Auler | e3898d5 | 2020-12-30 20:23:58 | [diff] [blame] | 2692 | uint64_t LiteThresholdExecCount = 0; |
| 2693 | if (opts::LiteThresholdPct) { |
| 2694 | if (opts::LiteThresholdPct > 100) |
| 2695 | opts::LiteThresholdPct = 100; |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2696 | |
Rafael Auler | e3898d5 | 2020-12-30 20:23:58 | [diff] [blame] | 2697 | std::vector<const BinaryFunction *> TopFunctions; |
| 2698 | for (auto &BFI : BC->getBinaryFunctions()) { |
| 2699 | const BinaryFunction &Function = BFI.second; |
| 2700 | if (ProfileReader->mayHaveProfileData(Function)) |
| 2701 | TopFunctions.push_back(&Function); |
| 2702 | } |
Amir Ayupov | d2c8769 | 2022-06-24 05:15:47 | [diff] [blame^] | 2703 | llvm::sort( |
| 2704 | TopFunctions, [](const BinaryFunction *A, const BinaryFunction *B) { |
| 2705 | return A->getKnownExecutionCount() < B->getKnownExecutionCount(); |
| 2706 | }); |
Rafael Auler | e3898d5 | 2020-12-30 20:23:58 | [diff] [blame] | 2707 | |
| 2708 | size_t Index = TopFunctions.size() * opts::LiteThresholdPct / 100; |
| 2709 | if (Index) |
| 2710 | --Index; |
| 2711 | LiteThresholdExecCount = TopFunctions[Index]->getKnownExecutionCount(); |
| 2712 | outs() << "BOLT-INFO: limiting processing to functions with at least " |
| 2713 | << LiteThresholdExecCount << " invocations\n"; |
| 2714 | } |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2715 | LiteThresholdExecCount = std::max( |
| 2716 | LiteThresholdExecCount, static_cast<uint64_t>(opts::LiteThresholdCount)); |
Rafael Auler | e3898d5 | 2020-12-30 20:23:58 | [diff] [blame] | 2717 | |
| 2718 | uint64_t NumFunctionsToProcess = 0; |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2719 | auto shouldProcess = [&](const BinaryFunction &Function) { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2720 | if (opts::MaxFunctions && NumFunctionsToProcess > opts::MaxFunctions) |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2721 | return false; |
| 2722 | |
| 2723 | // If the list is not empty, only process functions from the list. |
Amir Ayupov | d474dbd | 2021-06-05 01:49:29 | [diff] [blame] | 2724 | if (!opts::ForceFunctionNames.empty() || !ForceFunctionsNR.empty()) { |
| 2725 | // Regex check (-funcs and -funcs-file options). |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2726 | for (std::string &Name : opts::ForceFunctionNames) |
| 2727 | if (Function.hasNameRegex(Name)) |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2728 | return true; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2729 | |
Amir Ayupov | d474dbd | 2021-06-05 01:49:29 | [diff] [blame] | 2730 | // Non-regex check (-funcs-no-regex and -funcs-file-no-regex). |
| 2731 | Optional<StringRef> Match = |
| 2732 | Function.forEachName([&ForceFunctionsNR](StringRef Name) { |
| 2733 | return ForceFunctionsNR.count(Name.str()); |
| 2734 | }); |
| 2735 | return Match.hasValue(); |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2736 | } |
| 2737 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2738 | for (std::string &Name : opts::SkipFunctionNames) |
| 2739 | if (Function.hasNameRegex(Name)) |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2740 | return false; |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2741 | |
Maksim Panchenko | 924d0bd | 2020-05-03 22:49:58 | [diff] [blame] | 2742 | if (opts::Lite) { |
Rafael Auler | e3898d5 | 2020-12-30 20:23:58 | [diff] [blame] | 2743 | if (ProfileReader && !ProfileReader->mayHaveProfileData(Function)) |
Maksim Panchenko | 924d0bd | 2020-05-03 22:49:58 | [diff] [blame] | 2744 | return false; |
Rafael Auler | e3898d5 | 2020-12-30 20:23:58 | [diff] [blame] | 2745 | |
| 2746 | if (Function.getKnownExecutionCount() < LiteThresholdExecCount) |
| 2747 | return false; |
Maksim Panchenko | 924d0bd | 2020-05-03 22:49:58 | [diff] [blame] | 2748 | } |
| 2749 | |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2750 | return true; |
| 2751 | }; |
| 2752 | |
| 2753 | for (auto &BFI : BC->getBinaryFunctions()) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2754 | BinaryFunction &Function = BFI.second; |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2755 | |
Rafael Auler | e3898d5 | 2020-12-30 20:23:58 | [diff] [blame] | 2756 | // Pseudo functions are explicitly marked by us not to be processed. |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 2757 | if (Function.isPseudo()) { |
| 2758 | Function.IsIgnored = true; |
| 2759 | Function.HasExternalRefRelocations = true; |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2760 | continue; |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 2761 | } |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2762 | |
| 2763 | if (!shouldProcess(Function)) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 2764 | LLVM_DEBUG(dbgs() << "BOLT-INFO: skipping processing of function " |
| 2765 | << Function << " per user request\n"); |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 2766 | Function.setIgnored(); |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2767 | } else { |
| 2768 | ++NumFunctionsToProcess; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2769 | if (opts::MaxFunctions && NumFunctionsToProcess == opts::MaxFunctions) |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 2770 | outs() << "BOLT-INFO: processing ending on " << Function << '\n'; |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 2771 | } |
| 2772 | } |
| 2773 | } |
| 2774 | |
Maksim Panchenko | d01172f | 2016-03-15 01:48:05 | [diff] [blame] | 2775 | void RewriteInstance::readDebugInfo() { |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 2776 | NamedRegionTimer T("readDebugInfo", "read debug info", TimerGroupName, |
| 2777 | TimerGroupDesc, opts::TimeRewrite); |
Maksim Panchenko | d01172f | 2016-03-15 01:48:05 | [diff] [blame] | 2778 | if (!opts::UpdateDebugSections) |
| 2779 | return; |
| 2780 | |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 2781 | BC->preprocessDebugInfo(); |
Maksim Panchenko | d01172f | 2016-03-15 01:48:05 | [diff] [blame] | 2782 | } |
| 2783 | |
Maksim Panchenko | c6ce2ab | 2019-01-16 07:43:40 | [diff] [blame] | 2784 | void RewriteInstance::preprocessProfileData() { |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2785 | if (!ProfileReader) |
| 2786 | return; |
| 2787 | |
Maksim Panchenko | c6ce2ab | 2019-01-16 07:43:40 | [diff] [blame] | 2788 | NamedRegionTimer T("preprocessprofile", "pre-process profile data", |
| 2789 | TimerGroupName, TimerGroupDesc, opts::TimeRewrite); |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2790 | |
| 2791 | outs() << "BOLT-INFO: pre-processing profile using " |
| 2792 | << ProfileReader->getReaderName() << '\n'; |
| 2793 | |
| 2794 | if (BAT->enabledFor(InputFile)) { |
| 2795 | outs() << "BOLT-INFO: profile collection done on a binary already " |
| 2796 | "processed by BOLT\n"; |
| 2797 | ProfileReader->setBAT(&*BAT); |
Rafael Auler | 21f4303 | 2019-04-13 00:33:46 | [diff] [blame] | 2798 | } |
Maksim Panchenko | 924d0bd | 2020-05-03 22:49:58 | [diff] [blame] | 2799 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2800 | if (Error E = ProfileReader->preprocessProfile(*BC.get())) |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2801 | report_error("cannot pre-process profile", std::move(E)); |
| 2802 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2803 | if (!BC->hasSymbolsWithFileName() && ProfileReader->hasLocalsWithFileName() && |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2804 | !opts::AllowStripped) { |
| 2805 | errs() << "BOLT-ERROR: input binary does not have local file symbols " |
| 2806 | "but profile data includes function names with embedded file " |
| 2807 | "names. It appears that the input binary was stripped while a " |
| 2808 | "profiled binary was not. If you know what you are doing and " |
| 2809 | "wish to proceed, use -allow-stripped option.\n"; |
| 2810 | exit(1); |
Maksim Panchenko | 924d0bd | 2020-05-03 22:49:58 | [diff] [blame] | 2811 | } |
Maksim Panchenko | c6ce2ab | 2019-01-16 07:43:40 | [diff] [blame] | 2812 | } |
| 2813 | |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2814 | void RewriteInstance::processProfileDataPreCFG() { |
| 2815 | if (!ProfileReader) |
| 2816 | return; |
| 2817 | |
| 2818 | NamedRegionTimer T("processprofile-precfg", "process profile data pre-CFG", |
| 2819 | TimerGroupName, TimerGroupDesc, opts::TimeRewrite); |
| 2820 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2821 | if (Error E = ProfileReader->readProfilePreCFG(*BC.get())) |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2822 | report_error("cannot read profile pre-CFG", std::move(E)); |
| 2823 | } |
| 2824 | |
Maksim Panchenko | b6cb112 | 2017-12-14 07:12:01 | [diff] [blame] | 2825 | void RewriteInstance::processProfileData() { |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2826 | if (!ProfileReader) |
| 2827 | return; |
| 2828 | |
Maksim Panchenko | c6ce2ab | 2019-01-16 07:43:40 | [diff] [blame] | 2829 | NamedRegionTimer T("processprofile", "process profile data", TimerGroupName, |
| 2830 | TimerGroupDesc, opts::TimeRewrite); |
Maksim Panchenko | 924d0bd | 2020-05-03 22:49:58 | [diff] [blame] | 2831 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2832 | if (Error E = ProfileReader->readProfile(*BC.get())) |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2833 | report_error("cannot read profile", std::move(E)); |
Maksim Panchenko | ae409f0 | 2017-07-17 18:22:22 | [diff] [blame] | 2834 | |
Maksim Panchenko | b6cb112 | 2017-12-14 07:12:01 | [diff] [blame] | 2835 | if (!opts::SaveProfile.empty()) { |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2836 | YAMLProfileWriter PW(opts::SaveProfile); |
Maksim Panchenko | 8b049d3 | 2018-04-10 02:10:19 | [diff] [blame] | 2837 | PW.writeProfile(*this); |
Maksim Panchenko | ae409f0 | 2017-07-17 18:22:22 | [diff] [blame] | 2838 | } |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2839 | |
| 2840 | // Release memory used by profile reader. |
| 2841 | ProfileReader.reset(); |
| 2842 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2843 | if (opts::AggregateOnly) |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2844 | exit(0); |
Maksim Panchenko | ae409f0 | 2017-07-17 18:22:22 | [diff] [blame] | 2845 | } |
| 2846 | |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 2847 | void RewriteInstance::disassembleFunctions() { |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 2848 | NamedRegionTimer T("disassembleFunctions", "disassemble functions", |
| 2849 | TimerGroupName, TimerGroupDesc, opts::TimeRewrite); |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 2850 | for (auto &BFI : BC->getBinaryFunctions()) { |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 2851 | BinaryFunction &Function = BFI.second; |
| 2852 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 2853 | ErrorOr<ArrayRef<uint8_t>> FunctionData = Function.getData(); |
Bill Nell | c4d7460 | 2017-10-20 19:11:34 | [diff] [blame] | 2854 | if (!FunctionData) { |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2855 | errs() << "BOLT-ERROR: corresponding section is non-executable or " |
| 2856 | << "empty for function " << Function << '\n'; |
Maksim Panchenko | 924d0bd | 2020-05-03 22:49:58 | [diff] [blame] | 2857 | exit(1); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 2858 | } |
| 2859 | |
Maksim Panchenko | c4e36c1 | 2016-09-15 22:47:10 | [diff] [blame] | 2860 | // Treat zero-sized functions as non-simple ones. |
| 2861 | if (Function.getSize() == 0) { |
| 2862 | Function.setSimple(false); |
| 2863 | continue; |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 2864 | } |
| 2865 | |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 2866 | // Offset of the function in the file. |
Maksim Panchenko | d15b93b | 2017-11-28 17:57:21 | [diff] [blame] | 2867 | const auto *FileBegin = |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2868 | reinterpret_cast<const uint8_t *>(InputFile->getData().data()); |
Bill Nell | c4d7460 | 2017-10-20 19:11:34 | [diff] [blame] | 2869 | Function.setFileOffset(FunctionData->begin() - FileBegin); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 2870 | |
Maksim Panchenko | 924d0bd | 2020-05-03 22:49:58 | [diff] [blame] | 2871 | if (!shouldDisassemble(Function)) { |
| 2872 | NamedRegionTimer T("scan", "scan functions", "buildfuncs", |
| 2873 | "Scan Binary Functions", opts::TimeBuild); |
| 2874 | Function.scanExternalRefs(); |
| 2875 | Function.setSimple(false); |
| 2876 | continue; |
| 2877 | } |
| 2878 | |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 2879 | if (!Function.disassemble()) { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2880 | if (opts::processAllFunctions()) |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 2881 | BC->exitWithBugReport("function cannot be properly disassembled. " |
| 2882 | "Unable to continue in relocation mode.", |
| 2883 | Function); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2884 | if (opts::Verbosity >= 1) |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 2885 | outs() << "BOLT-INFO: could not disassemble function " << Function |
| 2886 | << ". Will ignore.\n"; |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 2887 | // Forcefully ignore the function. |
| 2888 | Function.setIgnored(); |
| 2889 | continue; |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 2890 | } |
| 2891 | |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 2892 | if (opts::PrintAll || opts::PrintDisasm) |
Bill Nell | c27a6a5 | 2016-09-02 21:15:29 | [diff] [blame] | 2893 | Function.print(outs(), "after disassembly", true); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 2894 | |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 2895 | BC->processInterproceduralReferences(Function); |
Maksim Panchenko | d660f8b | 2018-02-14 20:06:17 | [diff] [blame] | 2896 | } |
| 2897 | |
Huan Nguyen | 28b1dcb | 2022-06-17 23:17:22 | [diff] [blame] | 2898 | BC->clearJumpTableOffsets(); |
Maksim Panchenko | 9e2ad3f | 2019-06-13 01:21:02 | [diff] [blame] | 2899 | BC->populateJumpTables(); |
Amir Ayupov | 6aa735c | 2021-12-02 05:14:56 | [diff] [blame] | 2900 | BC->skipMarkedFragments(); |
Maksim Panchenko | 9e2ad3f | 2019-06-13 01:21:02 | [diff] [blame] | 2901 | |
| 2902 | for (auto &BFI : BC->getBinaryFunctions()) { |
| 2903 | BinaryFunction &Function = BFI.second; |
| 2904 | |
| 2905 | if (!shouldDisassemble(Function)) |
| 2906 | continue; |
| 2907 | |
Rafael Auler | 961d3d0 | 2020-01-15 01:12:03 | [diff] [blame] | 2908 | Function.postProcessEntryPoints(); |
Maksim Panchenko | 9e2ad3f | 2019-06-13 01:21:02 | [diff] [blame] | 2909 | Function.postProcessJumpTables(); |
| 2910 | } |
| 2911 | |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 2912 | BC->adjustCodePadding(); |
Maksim Panchenko | a9b9aa1 | 2019-07-24 03:48:41 | [diff] [blame] | 2913 | |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 2914 | for (auto &BFI : BC->getBinaryFunctions()) { |
Maksim Panchenko | d660f8b | 2018-02-14 20:06:17 | [diff] [blame] | 2915 | BinaryFunction &Function = BFI.second; |
| 2916 | |
Maksim Panchenko | c6ce2ab | 2019-01-16 07:43:40 | [diff] [blame] | 2917 | if (!shouldDisassemble(Function)) |
Maksim Panchenko | d660f8b | 2018-02-14 20:06:17 | [diff] [blame] | 2918 | continue; |
Maksim Panchenko | d660f8b | 2018-02-14 20:06:17 | [diff] [blame] | 2919 | |
| 2920 | if (!Function.isSimple()) { |
Huan Nguyen | 82095bd | 2022-06-10 22:48:13 | [diff] [blame] | 2921 | assert((!BC->HasRelocations || Function.getSize() == 0 || |
| 2922 | Function.hasSplitJumpTable()) && |
Maksim Panchenko | d660f8b | 2018-02-14 20:06:17 | [diff] [blame] | 2923 | "unexpected non-simple function in relocation mode"); |
| 2924 | continue; |
| 2925 | } |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 2926 | |
| 2927 | // Fill in CFI information for this function |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 2928 | if (!Function.trapsOnEntry() && !CFIRdWrt->fillCFIInfoFor(Function)) { |
| 2929 | if (BC->HasRelocations) { |
| 2930 | BC->exitWithBugReport("unable to fill CFI.", Function); |
| 2931 | } else { |
| 2932 | errs() << "BOLT-WARNING: unable to fill CFI for function " << Function |
| 2933 | << ". Skipping.\n"; |
| 2934 | Function.setSimple(false); |
| 2935 | continue; |
Maksim Panchenko | 73e9afe | 2016-02-23 02:25:43 | [diff] [blame] | 2936 | } |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 2937 | } |
| 2938 | |
| 2939 | // Parse LSDA. |
Maksim Panchenko | d660f8b | 2018-02-14 20:06:17 | [diff] [blame] | 2940 | if (Function.getLSDAAddress() != 0) |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 2941 | Function.parseLSDA(getLSDAData(), getLSDAAddress()); |
laith sakka | 7d42835 | 2019-07-12 14:25:50 | [diff] [blame] | 2942 | } |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2943 | } |
| 2944 | |
| 2945 | void RewriteInstance::buildFunctionsCFG() { |
| 2946 | NamedRegionTimer T("buildCFG", "buildCFG", "buildfuncs", |
| 2947 | "Build Binary Functions", opts::TimeBuild); |
| 2948 | |
| 2949 | // Create annotation indices to allow lock-free execution |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2950 | BC->MIB->getOrCreateAnnotationIndex("JTIndexReg"); |
Maksim Panchenko | ccb99dd | 2021-12-19 01:05:00 | [diff] [blame] | 2951 | BC->MIB->getOrCreateAnnotationIndex("NOP"); |
| 2952 | BC->MIB->getOrCreateAnnotationIndex("Size"); |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2953 | |
| 2954 | ParallelUtilities::WorkFuncWithAllocTy WorkFun = |
| 2955 | [&](BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocId) { |
| 2956 | if (!BF.buildCFG(AllocId)) |
| 2957 | return; |
| 2958 | |
Amir Ayupov | d1638cb | 2022-03-10 04:27:15 | [diff] [blame] | 2959 | if (opts::PrintAll) { |
| 2960 | auto L = BC->scopeLock(); |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2961 | BF.print(outs(), "while building cfg", true); |
Amir Ayupov | d1638cb | 2022-03-10 04:27:15 | [diff] [blame] | 2962 | } |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2963 | }; |
| 2964 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 2965 | ParallelUtilities::PredicateTy SkipPredicate = [&](const BinaryFunction &BF) { |
| 2966 | return !shouldDisassemble(BF) || !BF.isSimple(); |
| 2967 | }; |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 2968 | |
| 2969 | ParallelUtilities::runOnEachFunctionWithUniqueAllocId( |
| 2970 | *BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, WorkFun, |
| 2971 | SkipPredicate, "disassembleFunctions-buildCFG", |
| 2972 | /*ForceSequential*/ opts::SequentialDisassembly || opts::PrintAll); |
laith sakka | 7d42835 | 2019-07-12 14:25:50 | [diff] [blame] | 2973 | |
Bill Nell | 706abb6 | 2018-06-06 10:17:32 | [diff] [blame] | 2974 | BC->postProcessSymbolTable(); |
Maksim Panchenko | d15b93b | 2017-11-28 17:57:21 | [diff] [blame] | 2975 | } |
| 2976 | |
| 2977 | void RewriteInstance::postProcessFunctions() { |
| 2978 | BC->TotalScore = 0; |
| 2979 | BC->SumExecutionCount = 0; |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 2980 | for (auto &BFI : BC->getBinaryFunctions()) { |
Maksim Panchenko | d15b93b | 2017-11-28 17:57:21 | [diff] [blame] | 2981 | BinaryFunction &Function = BFI.second; |
| 2982 | |
| 2983 | if (Function.empty()) |
| 2984 | continue; |
| 2985 | |
| 2986 | Function.postProcessCFG(); |
| 2987 | |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 2988 | if (opts::PrintAll || opts::PrintCFG) |
Bill Nell | c27a6a5 | 2016-09-02 21:15:29 | [diff] [blame] | 2989 | Function.print(outs(), "after building cfg", true); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 2990 | |
Bill Nell | 260f6fb | 2016-07-01 15:40:56 | [diff] [blame] | 2991 | if (opts::DumpDotAll) |
Amir Ayupov | 5f2f96c | 2020-10-22 00:08:32 | [diff] [blame] | 2992 | Function.dumpGraphForPass("00_build-cfg"); |
Bill Nell | 260f6fb | 2016-07-01 15:40:56 | [diff] [blame] | 2993 | |
Theodoros Kasampalis | 17b8465 | 2016-05-26 17:58:01 | [diff] [blame] | 2994 | if (opts::PrintLoopInfo) { |
| 2995 | Function.calculateLoopInfo(); |
Bill Nell | c27a6a5 | 2016-09-02 21:15:29 | [diff] [blame] | 2996 | Function.printLoopInfo(outs()); |
Theodoros Kasampalis | 17b8465 | 2016-05-26 17:58:01 | [diff] [blame] | 2997 | } |
| 2998 | |
Maksim Panchenko | d15b93b | 2017-11-28 17:57:21 | [diff] [blame] | 2999 | BC->TotalScore += Function.getFunctionScore(); |
Rafael Auler | d850ca3 | 2017-05-01 23:52:54 | [diff] [blame] | 3000 | BC->SumExecutionCount += Function.getKnownExecutionCount(); |
Maksim Panchenko | 4a44d18 | 2016-01-16 22:58:22 | [diff] [blame] | 3001 | } |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 3002 | |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 3003 | if (opts::PrintGlobals) { |
| 3004 | outs() << "BOLT-INFO: Global symbols:\n"; |
| 3005 | BC->printGlobalSymbols(outs()); |
| 3006 | } |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 3007 | } |
| 3008 | |
| 3009 | void RewriteInstance::runOptimizationPasses() { |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 3010 | NamedRegionTimer T("runOptimizationPasses", "run optimization passes", |
| 3011 | TimerGroupName, TimerGroupDesc, opts::TimeRewrite); |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 3012 | BinaryFunctionPassManager::runAllPasses(*BC); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 3013 | } |
| 3014 | |
Bill Nell | 96943d2 | 2017-05-25 01:40:29 | [diff] [blame] | 3015 | namespace { |
| 3016 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3017 | class BOLTSymbolResolver : public JITSymbolResolver { |
| 3018 | BinaryContext &BC; |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 3019 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3020 | public: |
Rafael Auler | a23726b | 2021-11-17 00:47:02 | [diff] [blame] | 3021 | BOLTSymbolResolver(BinaryContext &BC) : BC(BC) {} |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3022 | |
| 3023 | // We are responsible for all symbols |
| 3024 | Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) override { |
| 3025 | return Symbols; |
| 3026 | } |
| 3027 | |
| 3028 | // Some of our symbols may resolve to zero and this should not be an error |
| 3029 | bool allowsZeroSymbols() override { return true; } |
| 3030 | |
| 3031 | /// Resolves the address of each symbol requested |
| 3032 | void lookup(const LookupSet &Symbols, |
| 3033 | OnResolvedFunction OnResolved) override { |
| 3034 | JITSymbolResolver::LookupResult AllResults; |
| 3035 | |
| 3036 | if (BC.EFMM->ObjectsLoaded) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3037 | for (const StringRef &Symbol : Symbols) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3038 | std::string SymName = Symbol.str(); |
| 3039 | LLVM_DEBUG(dbgs() << "BOLT: looking for " << SymName << "\n"); |
Rafael Auler | a23726b | 2021-11-17 00:47:02 | [diff] [blame] | 3040 | // Resolve to a PLT entry if possible |
Vladislav Khmelevsky | 4956e0e | 2022-04-03 16:11:31 | [diff] [blame] | 3041 | if (const BinaryData *I = BC.getPLTBinaryDataByName(SymName)) { |
Rafael Auler | a23726b | 2021-11-17 00:47:02 | [diff] [blame] | 3042 | AllResults[Symbol] = |
| 3043 | JITEvaluatedSymbol(I->getAddress(), JITSymbolFlags()); |
| 3044 | continue; |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3045 | } |
Rafael Auler | a23726b | 2021-11-17 00:47:02 | [diff] [blame] | 3046 | OnResolved(make_error<StringError>( |
| 3047 | "Symbol not found required by runtime: " + Symbol, |
| 3048 | inconvertibleErrorCode())); |
| 3049 | return; |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3050 | } |
| 3051 | OnResolved(std::move(AllResults)); |
| 3052 | return; |
| 3053 | } |
| 3054 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3055 | for (const StringRef &Symbol : Symbols) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3056 | std::string SymName = Symbol.str(); |
| 3057 | LLVM_DEBUG(dbgs() << "BOLT: looking for " << SymName << "\n"); |
| 3058 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3059 | if (BinaryData *I = BC.getBinaryDataByName(SymName)) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3060 | uint64_t Address = I->isMoved() && !I->isJumpTable() |
| 3061 | ? I->getOutputAddress() |
| 3062 | : I->getAddress(); |
| 3063 | LLVM_DEBUG(dbgs() << "Resolved to address 0x" |
| 3064 | << Twine::utohexstr(Address) << "\n"); |
| 3065 | AllResults[Symbol] = JITEvaluatedSymbol(Address, JITSymbolFlags()); |
| 3066 | continue; |
| 3067 | } |
| 3068 | LLVM_DEBUG(dbgs() << "Resolved to address 0x0\n"); |
| 3069 | AllResults[Symbol] = JITEvaluatedSymbol(0, JITSymbolFlags()); |
| 3070 | } |
| 3071 | |
| 3072 | OnResolved(std::move(AllResults)); |
| 3073 | } |
| 3074 | }; |
| 3075 | |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 3076 | } // anonymous namespace |
| 3077 | |
Rafael Auler | 62aa74f | 2019-07-24 21:03:43 | [diff] [blame] | 3078 | void RewriteInstance::emitAndLink() { |
| 3079 | NamedRegionTimer T("emitAndLink", "emit and link", TimerGroupName, |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 3080 | TimerGroupDesc, opts::TimeRewrite); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 3081 | std::error_code EC; |
| 3082 | |
| 3083 | // This is an object file, which we keep for debugging purposes. |
| 3084 | // Once we decide it's useless, we should create it in memory. |
Amir Ayupov | 081e39a | 2021-03-29 23:04:57 | [diff] [blame] | 3085 | SmallString<128> OutObjectPath; |
| 3086 | sys::fs::getPotentiallyUniqueTempFileName("output", "o", OutObjectPath); |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 3087 | std::unique_ptr<ToolOutputFile> TempOut = |
Amir Ayupov | 081e39a | 2021-03-29 23:04:57 | [diff] [blame] | 3088 | std::make_unique<ToolOutputFile>(OutObjectPath, EC, sys::fs::OF_None); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 3089 | check_error(EC, "cannot create output object file"); |
| 3090 | |
| 3091 | std::unique_ptr<buffer_ostream> BOS = |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 3092 | std::make_unique<buffer_ostream>(TempOut->os()); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 3093 | raw_pwrite_stream *OS = BOS.get(); |
| 3094 | |
| 3095 | // Implicitly MCObjectStreamer takes ownership of MCAsmBackend (MAB) |
| 3096 | // and MCCodeEmitter (MCE). ~MCObjectStreamer() will delete these |
| 3097 | // two instances. |
Amir Ayupov | 12e9fec | 2021-04-01 18:43:00 | [diff] [blame] | 3098 | std::unique_ptr<MCStreamer> Streamer = BC->createStreamer(*OS); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 3099 | |
Bill Nell | 2640b40 | 2018-01-23 23:10:24 | [diff] [blame] | 3100 | if (EHFrameSection) { |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 3101 | if (opts::UseOldText || opts::StrictMode) { |
Maksim Panchenko | 33e0b2a | 2020-04-19 19:55:43 | [diff] [blame] | 3102 | // The section is going to be regenerated from scratch. |
| 3103 | // Empty the contents, but keep the section reference. |
Xun Li | 8a68074 | 2020-05-21 23:25:05 | [diff] [blame] | 3104 | EHFrameSection->clearContents(); |
Maksim Panchenko | 33e0b2a | 2020-04-19 19:55:43 | [diff] [blame] | 3105 | } else { |
| 3106 | // Make .eh_frame relocatable. |
| 3107 | relocateEHFrameSection(); |
| 3108 | } |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 3109 | } |
| 3110 | |
Maksim Panchenko | a07f1a2 | 2020-03-11 22:51:32 | [diff] [blame] | 3111 | emitBinaryContext(*Streamer, *BC, getOrgSecPrefix()); |
Maksim Panchenko | 1f3e351 | 2020-03-06 23:06:37 | [diff] [blame] | 3112 | |
Fangrui Song | 15d82c6 | 2022-06-07 07:31:02 | [diff] [blame] | 3113 | Streamer->finish(); |
Amir Ayupov | 9b02dc6 | 2022-04-09 04:07:27 | [diff] [blame] | 3114 | if (Streamer->getContext().hadError()) { |
| 3115 | errs() << "BOLT-ERROR: Emission failed.\n"; |
| 3116 | exit(1); |
| 3117 | } |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 3118 | |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 3119 | ////////////////////////////////////////////////////////////////////////////// |
Maksim Panchenko | 3f42fdf | 2017-05-09 05:51:36 | [diff] [blame] | 3120 | // Assign addresses to new sections. |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 3121 | ////////////////////////////////////////////////////////////////////////////// |
| 3122 | |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 3123 | // Get output object as ObjectFile. |
| 3124 | std::unique_ptr<MemoryBuffer> ObjectMemBuffer = |
| 3125 | MemoryBuffer::getMemBuffer(BOS->str(), "in-memory object file", false); |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 3126 | std::unique_ptr<object::ObjectFile> Obj = cantFail( |
| 3127 | object::ObjectFile::createObjectFile(ObjectMemBuffer->getMemBufferRef()), |
| 3128 | "error creating in-memory object"); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 3129 | |
Rafael Auler | a23726b | 2021-11-17 00:47:02 | [diff] [blame] | 3130 | BOLTSymbolResolver Resolver = BOLTSymbolResolver(*BC); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3131 | |
Maksim Panchenko | 3f42fdf | 2017-05-09 05:51:36 | [diff] [blame] | 3132 | MCAsmLayout FinalLayout( |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 3133 | static_cast<MCObjectStreamer *>(Streamer.get())->getAssembler()); |
Gabriel Poesia | ffa9641 | 2016-03-29 00:45:22 | [diff] [blame] | 3134 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3135 | RTDyld.reset(new decltype(RTDyld)::element_type(*BC->EFMM, Resolver)); |
Maksim Panchenko | a263703 | 2021-05-26 23:23:34 | [diff] [blame] | 3136 | RTDyld->setProcessAllSections(false); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3137 | RTDyld->loadObject(*Obj); |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 3138 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3139 | // Assign addresses to all sections. If key corresponds to the object |
| 3140 | // created by ourselves, call our regular mapping function. If we are |
| 3141 | // loading additional objects as part of runtime libraries for |
| 3142 | // instrumentation, treat them as extra sections. |
| 3143 | mapFileSections(*RTDyld); |
| 3144 | |
| 3145 | RTDyld->finalizeWithMemoryManagerLocking(); |
| 3146 | if (RTDyld->hasError()) { |
Amir Ayupov | 9b02dc6 | 2022-04-09 04:07:27 | [diff] [blame] | 3147 | errs() << "BOLT-ERROR: RTDyld failed: " << RTDyld->getErrorString() << "\n"; |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3148 | exit(1); |
| 3149 | } |
| 3150 | |
| 3151 | // Update output addresses based on the new section map and |
| 3152 | // layout. Only do this for the object created by ourselves. |
| 3153 | updateOutputValues(FinalLayout); |
Maksim Panchenko | e1a61e1 | 2016-02-08 18:08:28 | [diff] [blame] | 3154 | |
Maksim Panchenko | 96bb090 | 2021-10-13 20:19:06 | [diff] [blame] | 3155 | if (opts::UpdateDebugSections) |
| 3156 | DebugInfoRewriter->updateLineTableOffsets(FinalLayout); |
| 3157 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3158 | if (RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary()) |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3159 | RtLibrary->link(*BC, ToolPath, *RTDyld, [this](RuntimeDyld &R) { |
| 3160 | this->mapExtraSections(*RTDyld); |
| 3161 | }); |
Rafael Auler | 62aa74f | 2019-07-24 21:03:43 | [diff] [blame] | 3162 | |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 3163 | // Once the code is emitted, we can rename function sections to actual |
| 3164 | // output sections and de-register sections used for emission. |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 3165 | for (BinaryFunction *Function : BC->getAllBinaryFunctions()) { |
| 3166 | ErrorOr<BinarySection &> Section = Function->getCodeSection(); |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 3167 | if (Section && |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3168 | (Function->getImageAddress() == 0 || Function->getImageSize() == 0)) |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 3169 | continue; |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 3170 | |
| 3171 | // Restore origin section for functions that were emitted or supposed to |
| 3172 | // be emitted to patch sections. |
| 3173 | if (Section) |
| 3174 | BC->deregisterSection(*Section); |
| 3175 | assert(Function->getOriginSectionName() && "expected origin section"); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3176 | Function->CodeSectionName = std::string(*Function->getOriginSectionName()); |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 3177 | if (Function->isSplit()) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3178 | if (ErrorOr<BinarySection &> ColdSection = Function->getColdCodeSection()) |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 3179 | BC->deregisterSection(*ColdSection); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3180 | Function->ColdCodeSectionName = std::string(getBOLTTextSectionName()); |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 3181 | } |
| 3182 | } |
| 3183 | |
spupyrev | b77172c | 2017-10-16 23:53:50 | [diff] [blame] | 3184 | if (opts::PrintCacheMetrics) { |
spupyrev | 48a53a7 | 2017-11-15 00:51:24 | [diff] [blame] | 3185 | outs() << "BOLT-INFO: cache metrics after emitting functions:\n"; |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 3186 | CacheMetrics::printAll(BC->getSortedFunctions()); |
spupyrev | b77172c | 2017-10-16 23:53:50 | [diff] [blame] | 3187 | } |
| 3188 | |
Amir Ayupov | 081e39a | 2021-03-29 23:04:57 | [diff] [blame] | 3189 | if (opts::KeepTmp) { |
Maksim Panchenko | e1a61e1 | 2016-02-08 18:08:28 | [diff] [blame] | 3190 | TempOut->keep(); |
Amir Ayupov | 081e39a | 2021-03-29 23:04:57 | [diff] [blame] | 3191 | outs() << "BOLT-INFO: intermediary output object file saved for debugging " |
| 3192 | "purposes: " |
| 3193 | << OutObjectPath << "\n"; |
| 3194 | } |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 3195 | } |
| 3196 | |
Maksim Panchenko | f2b257b | 2019-11-04 05:57:15 | [diff] [blame] | 3197 | void RewriteInstance::updateMetadata() { |
| 3198 | updateSDTMarkers(); |
takh | 0033a76 | 2020-08-04 20:50:00 | [diff] [blame] | 3199 | updateLKMarkers(); |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3200 | parsePseudoProbe(); |
| 3201 | updatePseudoProbes(); |
Maksim Panchenko | f2b257b | 2019-11-04 05:57:15 | [diff] [blame] | 3202 | |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 3203 | if (opts::UpdateDebugSections) { |
| 3204 | NamedRegionTimer T("updateDebugInfo", "update debug info", TimerGroupName, |
| 3205 | TimerGroupDesc, opts::TimeRewrite); |
| 3206 | DebugInfoRewriter->updateDebugInfo(); |
| 3207 | } |
Maksim Panchenko | e9c6c73 | 2019-09-11 22:42:22 | [diff] [blame] | 3208 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3209 | if (opts::WriteBoltInfoSection) |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 3210 | addBoltInfoSection(); |
Maksim Panchenko | e9c6c73 | 2019-09-11 22:42:22 | [diff] [blame] | 3211 | } |
| 3212 | |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3213 | void RewriteInstance::updatePseudoProbes() { |
James Luo | 3e55dea | 2021-07-15 21:58:32 | [diff] [blame] | 3214 | // check if there is pseudo probe section decoded |
| 3215 | if (BC->ProbeDecoder.getAddress2ProbesMap().empty()) |
| 3216 | return; |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3217 | // input address converted to output |
| 3218 | AddressProbesMap &Address2ProbesMap = BC->ProbeDecoder.getAddress2ProbesMap(); |
| 3219 | const GUIDProbeFunctionMap &GUID2Func = |
| 3220 | BC->ProbeDecoder.getGUID2FuncDescMap(); |
James Luo | 0df7bf7 | 2021-07-16 23:05:18 | [diff] [blame] | 3221 | |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3222 | for (auto &AP : Address2ProbesMap) { |
| 3223 | BinaryFunction *F = BC->getBinaryFunctionContainingAddress(AP.first); |
James Luo | 0df7bf7 | 2021-07-16 23:05:18 | [diff] [blame] | 3224 | // If F is removed, eliminate all probes inside it from inline tree |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3225 | // Setting probes' addresses as INT64_MAX means elimination |
James Luo | 0df7bf7 | 2021-07-16 23:05:18 | [diff] [blame] | 3226 | if (!F) { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3227 | for (MCDecodedPseudoProbe &Probe : AP.second) |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3228 | Probe.setAddress(INT64_MAX); |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3229 | continue; |
| 3230 | } |
James Luo | 0df7bf7 | 2021-07-16 23:05:18 | [diff] [blame] | 3231 | // If F is not emitted, the function will remain in the same address as its |
| 3232 | // input |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3233 | if (!F->isEmitted()) |
James Luo | 0df7bf7 | 2021-07-16 23:05:18 | [diff] [blame] | 3234 | continue; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3235 | |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3236 | uint64_t Offset = AP.first - F->getAddress(); |
| 3237 | const BinaryBasicBlock *BB = F->getBasicBlockContainingOffset(Offset); |
| 3238 | uint64_t BlkOutputAddress = BB->getOutputAddressRange().first; |
| 3239 | // Check if block output address is defined. |
| 3240 | // If not, such block is removed from binary. Then remove the probes from |
| 3241 | // inline tree |
| 3242 | if (BlkOutputAddress == 0) { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3243 | for (MCDecodedPseudoProbe &Probe : AP.second) |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3244 | Probe.setAddress(INT64_MAX); |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3245 | continue; |
| 3246 | } |
James Luo | 0df7bf7 | 2021-07-16 23:05:18 | [diff] [blame] | 3247 | |
| 3248 | unsigned ProbeTrack = AP.second.size(); |
| 3249 | std::list<MCDecodedPseudoProbe>::iterator Probe = AP.second.begin(); |
| 3250 | while (ProbeTrack != 0) { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3251 | if (Probe->isBlock()) { |
James Luo | 0df7bf7 | 2021-07-16 23:05:18 | [diff] [blame] | 3252 | Probe->setAddress(BlkOutputAddress); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3253 | } else if (Probe->isCall()) { |
James Luo | 0df7bf7 | 2021-07-16 23:05:18 | [diff] [blame] | 3254 | // A call probe may be duplicated due to ICP |
| 3255 | // Go through output of InputOffsetToAddressMap to collect all related |
| 3256 | // probes |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3257 | const InputOffsetToAddressMapTy &Offset2Addr = |
| 3258 | F->getInputOffsetToAddressMap(); |
James Luo | 0df7bf7 | 2021-07-16 23:05:18 | [diff] [blame] | 3259 | auto CallOutputAddresses = Offset2Addr.equal_range(Offset); |
| 3260 | auto CallOutputAddress = CallOutputAddresses.first; |
| 3261 | if (CallOutputAddress == CallOutputAddresses.second) { |
| 3262 | Probe->setAddress(INT64_MAX); |
| 3263 | } else { |
| 3264 | Probe->setAddress(CallOutputAddress->second); |
| 3265 | CallOutputAddress = std::next(CallOutputAddress); |
| 3266 | } |
| 3267 | |
| 3268 | while (CallOutputAddress != CallOutputAddresses.second) { |
| 3269 | AP.second.push_back(*Probe); |
| 3270 | AP.second.back().setAddress(CallOutputAddress->second); |
| 3271 | Probe->getInlineTreeNode()->addProbes(&(AP.second.back())); |
| 3272 | CallOutputAddress = std::next(CallOutputAddress); |
| 3273 | } |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3274 | } |
James Luo | 0df7bf7 | 2021-07-16 23:05:18 | [diff] [blame] | 3275 | Probe = std::next(Probe); |
| 3276 | ProbeTrack--; |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3277 | } |
| 3278 | } |
| 3279 | |
| 3280 | if (opts::PrintPseudoProbes == opts::PrintPseudoProbesOptions::PPP_All || |
| 3281 | opts::PrintPseudoProbes == |
| 3282 | opts::PrintPseudoProbesOptions::PPP_Probes_Address_Conversion) { |
| 3283 | outs() << "Pseudo Probe Address Conversion results:\n"; |
| 3284 | // table that correlates address to block |
| 3285 | std::unordered_map<uint64_t, StringRef> Addr2BlockNames; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3286 | for (auto &F : BC->getBinaryFunctions()) |
| 3287 | for (BinaryBasicBlock &BinaryBlock : F.second) |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3288 | Addr2BlockNames[BinaryBlock.getOutputAddressRange().first] = |
| 3289 | BinaryBlock.getName(); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3290 | |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3291 | // scan all addresses -> correlate probe to block when print out |
| 3292 | std::vector<uint64_t> Addresses; |
| 3293 | for (auto &Entry : Address2ProbesMap) |
| 3294 | Addresses.push_back(Entry.first); |
Amir Ayupov | d2c8769 | 2022-06-24 05:15:47 | [diff] [blame^] | 3295 | llvm::sort(Addresses); |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3296 | for (uint64_t Key : Addresses) { |
| 3297 | for (MCDecodedPseudoProbe &Probe : Address2ProbesMap[Key]) { |
| 3298 | if (Probe.getAddress() == INT64_MAX) |
| 3299 | outs() << "Deleted Probe: "; |
| 3300 | else |
| 3301 | outs() << "Address: " << format_hex(Probe.getAddress(), 8) << " "; |
| 3302 | Probe.print(outs(), GUID2Func, true); |
| 3303 | // print block name only if the probe is block type and undeleted. |
| 3304 | if (Probe.isBlock() && Probe.getAddress() != INT64_MAX) |
| 3305 | outs() << format_hex(Probe.getAddress(), 8) << " Probe is in " |
| 3306 | << Addr2BlockNames[Probe.getAddress()] << "\n"; |
| 3307 | } |
| 3308 | } |
| 3309 | outs() << "=======================================\n"; |
| 3310 | } |
James Luo | 3e55dea | 2021-07-15 21:58:32 | [diff] [blame] | 3311 | |
| 3312 | // encode pseudo probes with updated addresses |
| 3313 | encodePseudoProbes(); |
| 3314 | } |
| 3315 | |
| 3316 | template <typename F> |
| 3317 | static void emitLEB128IntValue(F encode, uint64_t Value, |
| 3318 | SmallString<8> &Contents) { |
| 3319 | SmallString<128> Tmp; |
| 3320 | raw_svector_ostream OSE(Tmp); |
| 3321 | encode(Value, OSE); |
| 3322 | Contents.append(OSE.str().begin(), OSE.str().end()); |
| 3323 | } |
| 3324 | |
| 3325 | void RewriteInstance::encodePseudoProbes() { |
| 3326 | // Buffer for new pseudo probes section |
| 3327 | SmallString<8> Contents; |
| 3328 | MCDecodedPseudoProbe *LastProbe = nullptr; |
| 3329 | |
Rafael Auler | ae585be | 2021-11-12 02:14:53 | [diff] [blame] | 3330 | auto EmitInt = [&](uint64_t Value, uint32_t Size) { |
James Luo | 3e55dea | 2021-07-15 21:58:32 | [diff] [blame] | 3331 | const bool IsLittleEndian = BC->AsmInfo->isLittleEndian(); |
| 3332 | uint64_t Swapped = support::endian::byte_swap( |
| 3333 | Value, IsLittleEndian ? support::little : support::big); |
| 3334 | unsigned Index = IsLittleEndian ? 0 : 8 - Size; |
| 3335 | auto Entry = StringRef(reinterpret_cast<char *>(&Swapped) + Index, Size); |
| 3336 | Contents.append(Entry.begin(), Entry.end()); |
| 3337 | }; |
| 3338 | |
| 3339 | auto EmitULEB128IntValue = [&](uint64_t Value) { |
| 3340 | SmallString<128> Tmp; |
| 3341 | raw_svector_ostream OSE(Tmp); |
| 3342 | encodeULEB128(Value, OSE, 0); |
| 3343 | Contents.append(OSE.str().begin(), OSE.str().end()); |
| 3344 | }; |
| 3345 | |
| 3346 | auto EmitSLEB128IntValue = [&](int64_t Value) { |
| 3347 | SmallString<128> Tmp; |
| 3348 | raw_svector_ostream OSE(Tmp); |
| 3349 | encodeSLEB128(Value, OSE); |
| 3350 | Contents.append(OSE.str().begin(), OSE.str().end()); |
| 3351 | }; |
| 3352 | |
| 3353 | // Emit indiviual pseudo probes in a inline tree node |
| 3354 | // Probe index, type, attribute, address type and address are encoded |
| 3355 | // Address of the first probe is absolute. |
| 3356 | // Other probes' address are represented by delta |
| 3357 | auto EmitDecodedPseudoProbe = [&](MCDecodedPseudoProbe *&CurProbe) { |
| 3358 | EmitULEB128IntValue(CurProbe->getIndex()); |
| 3359 | uint8_t PackedType = CurProbe->getType() | (CurProbe->getAttributes() << 4); |
| 3360 | uint8_t Flag = |
| 3361 | LastProbe ? ((int8_t)MCPseudoProbeFlag::AddressDelta << 7) : 0; |
| 3362 | EmitInt(Flag | PackedType, 1); |
| 3363 | if (LastProbe) { |
| 3364 | // Emit the delta between the address label and LastProbe. |
| 3365 | int64_t Delta = CurProbe->getAddress() - LastProbe->getAddress(); |
| 3366 | EmitSLEB128IntValue(Delta); |
| 3367 | } else { |
| 3368 | // Emit absolute address for encoding the first pseudo probe. |
Rafael Auler | ae585be | 2021-11-12 02:14:53 | [diff] [blame] | 3369 | uint32_t AddrSize = BC->AsmInfo->getCodePointerSize(); |
James Luo | 3e55dea | 2021-07-15 21:58:32 | [diff] [blame] | 3370 | EmitInt(CurProbe->getAddress(), AddrSize); |
| 3371 | } |
| 3372 | }; |
| 3373 | |
| 3374 | std::map<InlineSite, MCDecodedPseudoProbeInlineTree *, |
| 3375 | std::greater<InlineSite>> |
| 3376 | Inlinees; |
| 3377 | |
| 3378 | // DFS of inline tree to emit pseudo probes in all tree node |
| 3379 | // Inline site index of a probe is emitted first. |
| 3380 | // Then tree node Guid, size of pseudo probes and children nodes, and detail |
| 3381 | // of contained probes are emitted Deleted probes are skipped Root node is not |
| 3382 | // encoded to binaries. It's a "wrapper" of inline trees of each function. |
| 3383 | std::list<std::pair<uint64_t, MCDecodedPseudoProbeInlineTree *>> NextNodes; |
| 3384 | const MCDecodedPseudoProbeInlineTree &Root = |
| 3385 | BC->ProbeDecoder.getDummyInlineRoot(); |
| 3386 | for (auto Child = Root.getChildren().begin(); |
| 3387 | Child != Root.getChildren().end(); ++Child) |
| 3388 | Inlinees[Child->first] = Child->second.get(); |
| 3389 | |
| 3390 | for (auto Inlinee : Inlinees) |
| 3391 | // INT64_MAX is "placeholder" of unused callsite index field in the pair |
| 3392 | NextNodes.push_back({INT64_MAX, Inlinee.second}); |
| 3393 | |
| 3394 | Inlinees.clear(); |
| 3395 | |
| 3396 | while (!NextNodes.empty()) { |
| 3397 | uint64_t ProbeIndex = NextNodes.back().first; |
| 3398 | MCDecodedPseudoProbeInlineTree *Cur = NextNodes.back().second; |
| 3399 | NextNodes.pop_back(); |
| 3400 | |
| 3401 | if (Cur->Parent && !Cur->Parent->isRoot()) |
| 3402 | // Emit probe inline site |
| 3403 | EmitULEB128IntValue(ProbeIndex); |
| 3404 | |
| 3405 | // Emit probes grouped by GUID. |
| 3406 | LLVM_DEBUG({ |
| 3407 | dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); |
| 3408 | dbgs() << "GUID: " << Cur->Guid << "\n"; |
| 3409 | }); |
| 3410 | // Emit Guid |
| 3411 | EmitInt(Cur->Guid, 8); |
| 3412 | // Emit number of probes in this node |
| 3413 | uint64_t Deleted = 0; |
| 3414 | for (MCDecodedPseudoProbe *&Probe : Cur->getProbes()) |
| 3415 | if (Probe->getAddress() == INT64_MAX) |
| 3416 | Deleted++; |
| 3417 | LLVM_DEBUG(dbgs() << "Deleted Probes:" << Deleted << "\n"); |
| 3418 | uint64_t ProbesSize = Cur->getProbes().size() - Deleted; |
| 3419 | EmitULEB128IntValue(ProbesSize); |
| 3420 | // Emit number of direct inlinees |
| 3421 | EmitULEB128IntValue(Cur->getChildren().size()); |
| 3422 | // Emit probes in this group |
| 3423 | for (MCDecodedPseudoProbe *&Probe : Cur->getProbes()) { |
| 3424 | if (Probe->getAddress() == INT64_MAX) |
| 3425 | continue; |
| 3426 | EmitDecodedPseudoProbe(Probe); |
| 3427 | LastProbe = Probe; |
| 3428 | } |
| 3429 | |
| 3430 | for (auto Child = Cur->getChildren().begin(); |
| 3431 | Child != Cur->getChildren().end(); ++Child) |
| 3432 | Inlinees[Child->first] = Child->second.get(); |
| 3433 | for (const auto &Inlinee : Inlinees) { |
| 3434 | assert(Cur->Guid != 0 && "non root tree node must have nonzero Guid"); |
| 3435 | NextNodes.push_back({std::get<1>(Inlinee.first), Inlinee.second}); |
| 3436 | LLVM_DEBUG({ |
| 3437 | dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); |
| 3438 | dbgs() << "InlineSite: " << std::get<1>(Inlinee.first) << "\n"; |
| 3439 | }); |
| 3440 | } |
| 3441 | Inlinees.clear(); |
| 3442 | } |
| 3443 | |
| 3444 | // Create buffer for new contents for the section |
| 3445 | // Freed when parent section is destroyed |
| 3446 | uint8_t *Output = new uint8_t[Contents.str().size()]; |
| 3447 | memcpy(Output, Contents.str().data(), Contents.str().size()); |
| 3448 | addToDebugSectionsToOverwrite(".pseudo_probe"); |
| 3449 | BC->registerOrUpdateSection(".pseudo_probe", PseudoProbeSection->getELFType(), |
| 3450 | PseudoProbeSection->getELFFlags(), Output, |
| 3451 | Contents.str().size(), 1); |
James Luo | 0df7bf7 | 2021-07-16 23:05:18 | [diff] [blame] | 3452 | if (opts::PrintPseudoProbes == opts::PrintPseudoProbesOptions::PPP_All || |
| 3453 | opts::PrintPseudoProbes == |
| 3454 | opts::PrintPseudoProbesOptions::PPP_Encoded_Probes) { |
| 3455 | // create a dummy decoder; |
| 3456 | MCPseudoProbeDecoder DummyDecoder; |
| 3457 | StringRef DescContents = PseudoProbeDescSection->getContents(); |
| 3458 | DummyDecoder.buildGUID2FuncDescMap( |
| 3459 | reinterpret_cast<const uint8_t *>(DescContents.data()), |
| 3460 | DescContents.size()); |
| 3461 | StringRef ProbeContents = PseudoProbeSection->getOutputContents(); |
| 3462 | DummyDecoder.buildAddress2ProbeMap( |
| 3463 | reinterpret_cast<const uint8_t *>(ProbeContents.data()), |
| 3464 | ProbeContents.size()); |
| 3465 | DummyDecoder.printProbesForAllAddresses(outs()); |
| 3466 | } |
James Luo | dea6c24 | 2021-06-25 18:42:58 | [diff] [blame] | 3467 | } |
| 3468 | |
Maksim Panchenko | f2b257b | 2019-11-04 05:57:15 | [diff] [blame] | 3469 | void RewriteInstance::updateSDTMarkers() { |
| 3470 | NamedRegionTimer T("updateSDTMarkers", "update SDT markers", TimerGroupName, |
| 3471 | TimerGroupDesc, opts::TimeRewrite); |
| 3472 | |
Amir Ayupov | f1bfb18 | 2021-03-18 20:06:18 | [diff] [blame] | 3473 | if (!SDTSection) |
| 3474 | return; |
| 3475 | SDTSection->registerPatcher(std::make_unique<SimpleBinaryPatcher>()); |
| 3476 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3477 | SimpleBinaryPatcher *SDTNotePatcher = |
Amir Ayupov | f1bfb18 | 2021-03-18 20:06:18 | [diff] [blame] | 3478 | static_cast<SimpleBinaryPatcher *>(SDTSection->getPatcher()); |
Maksim Panchenko | f2b257b | 2019-11-04 05:57:15 | [diff] [blame] | 3479 | for (auto &SDTInfoKV : BC->SDTMarkers) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3480 | const uint64_t OriginalAddress = SDTInfoKV.first; |
| 3481 | SDTMarkerInfo &SDTInfo = SDTInfoKV.second; |
| 3482 | const BinaryFunction *F = |
| 3483 | BC->getBinaryFunctionContainingAddress(OriginalAddress); |
Maksim Panchenko | f2b257b | 2019-11-04 05:57:15 | [diff] [blame] | 3484 | if (!F) |
| 3485 | continue; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3486 | const uint64_t NewAddress = |
| 3487 | F->translateInputToOutputAddress(OriginalAddress); |
Maksim Panchenko | f2b257b | 2019-11-04 05:57:15 | [diff] [blame] | 3488 | SDTNotePatcher->addLE64Patch(SDTInfo.PCOffset, NewAddress); |
| 3489 | } |
| 3490 | } |
| 3491 | |
takh | 0033a76 | 2020-08-04 20:50:00 | [diff] [blame] | 3492 | void RewriteInstance::updateLKMarkers() { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3493 | if (BC->LKMarkers.size() == 0) |
takh | 0033a76 | 2020-08-04 20:50:00 | [diff] [blame] | 3494 | return; |
takh | 0033a76 | 2020-08-04 20:50:00 | [diff] [blame] | 3495 | |
| 3496 | NamedRegionTimer T("updateLKMarkers", "update LK markers", TimerGroupName, |
| 3497 | TimerGroupDesc, opts::TimeRewrite); |
| 3498 | |
| 3499 | std::unordered_map<std::string, uint64_t> PatchCounts; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3500 | for (std::pair<const uint64_t, std::vector<LKInstructionMarkerInfo>> |
| 3501 | &LKMarkerInfoKV : BC->LKMarkers) { |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 3502 | const uint64_t OriginalAddress = LKMarkerInfoKV.first; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3503 | const BinaryFunction *BF = |
takh | 0033a76 | 2020-08-04 20:50:00 | [diff] [blame] | 3504 | BC->getBinaryFunctionContainingAddress(OriginalAddress, false, true); |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 3505 | if (!BF) |
takh | 0033a76 | 2020-08-04 20:50:00 | [diff] [blame] | 3506 | continue; |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 3507 | |
| 3508 | uint64_t NewAddress = BF->translateInputToOutputAddress(OriginalAddress); |
| 3509 | if (NewAddress == 0) |
takh | 0033a76 | 2020-08-04 20:50:00 | [diff] [blame] | 3510 | continue; |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 3511 | |
| 3512 | // Apply base address. |
| 3513 | if (OriginalAddress >= 0xffffffff00000000 && NewAddress < 0xffffffff) |
takh | 0033a76 | 2020-08-04 20:50:00 | [diff] [blame] | 3514 | NewAddress = NewAddress + 0xffffffff00000000; |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 3515 | |
| 3516 | if (OriginalAddress == NewAddress) |
takh | 0033a76 | 2020-08-04 20:50:00 | [diff] [blame] | 3517 | continue; |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 3518 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3519 | for (LKInstructionMarkerInfo &LKMarkerInfo : LKMarkerInfoKV.second) { |
Maksim Panchenko | a10f799 | 2020-09-15 18:42:03 | [diff] [blame] | 3520 | StringRef SectionName = LKMarkerInfo.SectionName; |
takh | 0033a76 | 2020-08-04 20:50:00 | [diff] [blame] | 3521 | SimpleBinaryPatcher *LKPatcher; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3522 | ErrorOr<BinarySection &> BSec = BC->getUniqueSectionByName(SectionName); |
Amir Ayupov | f1bfb18 | 2021-03-18 20:06:18 | [diff] [blame] | 3523 | assert(BSec && "missing section info for kernel section"); |
| 3524 | if (!BSec->getPatcher()) |
| 3525 | BSec->registerPatcher(std::make_unique<SimpleBinaryPatcher>()); |
| 3526 | LKPatcher = static_cast<SimpleBinaryPatcher *>(BSec->getPatcher()); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3527 | PatchCounts[std::string(SectionName)]++; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3528 | if (LKMarkerInfo.IsPCRelative) |
takh | 0033a76 | 2020-08-04 20:50:00 | [diff] [blame] | 3529 | LKPatcher->addLE32Patch(LKMarkerInfo.SectionOffset, |
| 3530 | NewAddress - OriginalAddress + |
| 3531 | LKMarkerInfo.PCRelativeOffset); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3532 | else |
takh | 0033a76 | 2020-08-04 20:50:00 | [diff] [blame] | 3533 | LKPatcher->addLE64Patch(LKMarkerInfo.SectionOffset, NewAddress); |
takh | 0033a76 | 2020-08-04 20:50:00 | [diff] [blame] | 3534 | } |
| 3535 | } |
| 3536 | outs() << "BOLT-INFO: patching linux kernel sections. Total patches per " |
| 3537 | "section are as follows:\n"; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3538 | for (const std::pair<const std::string, uint64_t> &KV : PatchCounts) |
takh | 0033a76 | 2020-08-04 20:50:00 | [diff] [blame] | 3539 | outs() << " Section: " << KV.first << ", patch-counts: " << KV.second |
| 3540 | << '\n'; |
takh | 0033a76 | 2020-08-04 20:50:00 | [diff] [blame] | 3541 | } |
| 3542 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3543 | void RewriteInstance::mapFileSections(RuntimeDyld &RTDyld) { |
| 3544 | mapCodeSections(RTDyld); |
| 3545 | mapDataSections(RTDyld); |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 3546 | } |
Rafael Auler | 35c09dc | 2018-06-20 19:03:24 | [diff] [blame] | 3547 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 3548 | std::vector<BinarySection *> RewriteInstance::getCodeSections() { |
Maksim Panchenko | 6bcb338 | 2019-03-15 20:43:36 | [diff] [blame] | 3549 | std::vector<BinarySection *> CodeSections; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3550 | for (BinarySection &Section : BC->textSections()) |
Maksim Panchenko | 6bcb338 | 2019-03-15 20:43:36 | [diff] [blame] | 3551 | if (Section.hasValidSectionID()) |
| 3552 | CodeSections.emplace_back(&Section); |
Maksim Panchenko | 6bcb338 | 2019-03-15 20:43:36 | [diff] [blame] | 3553 | |
| 3554 | auto compareSections = [&](const BinarySection *A, const BinarySection *B) { |
| 3555 | // Place movers before anything else. |
| 3556 | if (A->getName() == BC->getHotTextMoverSectionName()) |
| 3557 | return true; |
| 3558 | if (B->getName() == BC->getHotTextMoverSectionName()) |
| 3559 | return false; |
| 3560 | |
| 3561 | // Depending on the option, put main text at the beginning or at the end. |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3562 | if (opts::HotFunctionsAtEnd) |
Maksim Panchenko | 6bcb338 | 2019-03-15 20:43:36 | [diff] [blame] | 3563 | return B->getName() == BC->getMainCodeSectionName(); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3564 | else |
Maksim Panchenko | 6bcb338 | 2019-03-15 20:43:36 | [diff] [blame] | 3565 | return A->getName() == BC->getMainCodeSectionName(); |
Maksim Panchenko | 6bcb338 | 2019-03-15 20:43:36 | [diff] [blame] | 3566 | }; |
| 3567 | |
| 3568 | // Determine the order of sections. |
Amir Ayupov | d2c8769 | 2022-06-24 05:15:47 | [diff] [blame^] | 3569 | llvm::stable_sort(CodeSections, compareSections); |
Maksim Panchenko | 6bcb338 | 2019-03-15 20:43:36 | [diff] [blame] | 3570 | |
| 3571 | return CodeSections; |
| 3572 | } |
| 3573 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3574 | void RewriteInstance::mapCodeSections(RuntimeDyld &RTDyld) { |
Maksim Panchenko | b6f7c68 | 2017-12-10 05:40:39 | [diff] [blame] | 3575 | if (BC->HasRelocations) { |
Rafael Auler | 47ce9b3 | 2021-09-16 01:03:50 | [diff] [blame] | 3576 | ErrorOr<BinarySection &> TextSection = |
| 3577 | BC->getUniqueSectionByName(BC->getMainCodeSectionName()); |
| 3578 | assert(TextSection && ".text section not found in output"); |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3579 | assert(TextSection->hasValidSectionID() && ".text section should be valid"); |
| 3580 | |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 3581 | // Map sections for functions with pre-assigned addresses. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3582 | for (BinaryFunction *InjectedFunction : BC->getInjectedBinaryFunctions()) { |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 3583 | const uint64_t OutputAddress = InjectedFunction->getOutputAddress(); |
| 3584 | if (!OutputAddress) |
| 3585 | continue; |
| 3586 | |
| 3587 | ErrorOr<BinarySection &> FunctionSection = |
| 3588 | InjectedFunction->getCodeSection(); |
| 3589 | assert(FunctionSection && "function should have section"); |
| 3590 | FunctionSection->setOutputAddress(OutputAddress); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3591 | RTDyld.reassignSectionAddress(FunctionSection->getSectionID(), |
| 3592 | OutputAddress); |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 3593 | InjectedFunction->setImageAddress(FunctionSection->getAllocAddress()); |
| 3594 | InjectedFunction->setImageSize(FunctionSection->getOutputSize()); |
| 3595 | } |
| 3596 | |
Maksim Panchenko | 0a55001 | 2019-03-15 03:32:04 | [diff] [blame] | 3597 | // Populate the list of sections to be allocated. |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 3598 | std::vector<BinarySection *> CodeSections = getCodeSections(); |
| 3599 | |
| 3600 | // Remove sections that were pre-allocated (patch sections). |
Amir Ayupov | d2c8769 | 2022-06-24 05:15:47 | [diff] [blame^] | 3601 | llvm::erase_if(CodeSections, [](BinarySection *Section) { |
| 3602 | return Section->getOutputAddress(); |
| 3603 | }); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3604 | LLVM_DEBUG(dbgs() << "Code sections in the order of output:\n"; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3605 | for (const BinarySection *Section : CodeSections) |
Maksim Panchenko | 0a55001 | 2019-03-15 03:32:04 | [diff] [blame] | 3606 | dbgs() << Section->getName() << '\n'; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3607 | ); |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 3608 | |
Maksim Panchenko | fe37f18 | 2021-05-13 17:50:47 | [diff] [blame] | 3609 | uint64_t PaddingSize = 0; // size of padding required at the end |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3610 | |
| 3611 | // Allocate sections starting at a given Address. |
| 3612 | auto allocateAt = [&](uint64_t Address) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3613 | for (BinarySection *Section : CodeSections) { |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3614 | Address = alignTo(Address, Section->getAlignment()); |
| 3615 | Section->setOutputAddress(Address); |
| 3616 | Address += Section->getOutputSize(); |
| 3617 | } |
| 3618 | |
| 3619 | // Make sure we allocate enough space for huge pages. |
| 3620 | if (opts::HotText) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3621 | uint64_t HotTextEnd = |
| 3622 | TextSection->getOutputAddress() + TextSection->getOutputSize(); |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3623 | HotTextEnd = alignTo(HotTextEnd, BC->PageAlign); |
| 3624 | if (HotTextEnd > Address) { |
| 3625 | PaddingSize = HotTextEnd - Address; |
| 3626 | Address = HotTextEnd; |
| 3627 | } |
| 3628 | } |
| 3629 | return Address; |
| 3630 | }; |
Maksim Panchenko | 0a55001 | 2019-03-15 03:32:04 | [diff] [blame] | 3631 | |
| 3632 | // Check if we can fit code in the original .text |
Maksim Panchenko | fe37f18 | 2021-05-13 17:50:47 | [diff] [blame] | 3633 | bool AllocationDone = false; |
Maksim Panchenko | 0a55001 | 2019-03-15 03:32:04 | [diff] [blame] | 3634 | if (opts::UseOldText) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3635 | const uint64_t CodeSize = |
| 3636 | allocateAt(BC->OldTextSectionAddress) - BC->OldTextSectionAddress; |
Maksim Panchenko | 0a55001 | 2019-03-15 03:32:04 | [diff] [blame] | 3637 | |
| 3638 | if (CodeSize <= BC->OldTextSectionSize) { |
| 3639 | outs() << "BOLT-INFO: using original .text for new code with 0x" |
Maksim Panchenko | 23edb3e | 2020-04-19 22:02:50 | [diff] [blame] | 3640 | << Twine::utohexstr(opts::AlignText) << " alignment\n"; |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3641 | AllocationDone = true; |
| 3642 | } else { |
Maksim Panchenko | 1387a9d | 2018-09-25 03:58:31 | [diff] [blame] | 3643 | errs() << "BOLT-WARNING: original .text too small to fit the new code" |
Maksim Panchenko | 23edb3e | 2020-04-19 22:02:50 | [diff] [blame] | 3644 | << " using 0x" << Twine::utohexstr(opts::AlignText) |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 3645 | << " alignment. " << CodeSize << " bytes needed, have " |
| 3646 | << BC->OldTextSectionSize << " bytes available.\n"; |
Maksim Panchenko | 1387a9d | 2018-09-25 03:58:31 | [diff] [blame] | 3647 | opts::UseOldText = false; |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3648 | } |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3649 | } |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3650 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3651 | if (!AllocationDone) |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3652 | NextAvailableAddress = allocateAt(NextAvailableAddress); |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3653 | |
| 3654 | // Do the mapping for ORC layer based on the allocation. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3655 | for (BinarySection *Section : CodeSections) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3656 | LLVM_DEBUG( |
| 3657 | dbgs() << "BOLT: mapping " << Section->getName() << " at 0x" |
| 3658 | << Twine::utohexstr(Section->getAllocAddress()) << " to 0x" |
| 3659 | << Twine::utohexstr(Section->getOutputAddress()) << '\n'); |
| 3660 | RTDyld.reassignSectionAddress(Section->getSectionID(), |
| 3661 | Section->getOutputAddress()); |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 3662 | Section->setOutputFileOffset( |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3663 | getFileOffsetForAddress(Section->getOutputAddress())); |
Maksim Panchenko | 0a55001 | 2019-03-15 03:32:04 | [diff] [blame] | 3664 | } |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 3665 | |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3666 | // Check if we need to insert a padding section for hot text. |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3667 | if (PaddingSize && !opts::UseOldText) |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3668 | outs() << "BOLT-INFO: padding code to 0x" |
| 3669 | << Twine::utohexstr(NextAvailableAddress) |
| 3670 | << " to accommodate hot text\n"; |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 3671 | |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3672 | return; |
| 3673 | } |
Laith Saed Sakka | 27f3032 | 2018-07-08 19:14:08 | [diff] [blame] | 3674 | |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3675 | // Processing in non-relocation mode. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3676 | uint64_t NewTextSectionStartAddress = NextAvailableAddress; |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 3677 | |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 3678 | for (auto &BFI : BC->getBinaryFunctions()) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3679 | BinaryFunction &Function = BFI.second; |
Maksim Panchenko | 04c5d4f | 2020-05-03 20:54:45 | [diff] [blame] | 3680 | if (!Function.isEmitted()) |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3681 | continue; |
| 3682 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3683 | bool TooLarge = false; |
| 3684 | ErrorOr<BinarySection &> FuncSection = Function.getCodeSection(); |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3685 | assert(FuncSection && "cannot find section for function"); |
| 3686 | FuncSection->setOutputAddress(Function.getAddress()); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3687 | LLVM_DEBUG(dbgs() << "BOLT: mapping 0x" |
| 3688 | << Twine::utohexstr(FuncSection->getAllocAddress()) |
| 3689 | << " to 0x" << Twine::utohexstr(Function.getAddress()) |
| 3690 | << '\n'); |
| 3691 | RTDyld.reassignSectionAddress(FuncSection->getSectionID(), |
| 3692 | Function.getAddress()); |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3693 | Function.setImageAddress(FuncSection->getAllocAddress()); |
| 3694 | Function.setImageSize(FuncSection->getOutputSize()); |
| 3695 | if (Function.getImageSize() > Function.getMaxSize()) { |
| 3696 | TooLarge = true; |
| 3697 | FailedAddresses.emplace_back(Function.getAddress()); |
Laith Saed Sakka | 27f3032 | 2018-07-08 19:14:08 | [diff] [blame] | 3698 | } |
| 3699 | |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3700 | // Map jump tables if updating in-place. |
| 3701 | if (opts::JumpTables == JTS_BASIC) { |
| 3702 | for (auto &JTI : Function.JumpTables) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3703 | JumpTable *JT = JTI.second; |
| 3704 | BinarySection &Section = JT->getOutputSection(); |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3705 | Section.setOutputAddress(JT->getAddress()); |
Rafael Auler | 7b779f8 | 2021-09-10 23:19:50 | [diff] [blame] | 3706 | Section.setOutputFileOffset(getFileOffsetForAddress(JT->getAddress())); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3707 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: mapping " << Section.getName() |
| 3708 | << " to 0x" << Twine::utohexstr(JT->getAddress()) |
| 3709 | << '\n'); |
Rafael Auler | 7b779f8 | 2021-09-10 23:19:50 | [diff] [blame] | 3710 | RTDyld.reassignSectionAddress(Section.getSectionID(), JT->getAddress()); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3711 | } |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3712 | } |
| 3713 | |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3714 | if (!Function.isSplit()) |
| 3715 | continue; |
| 3716 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3717 | ErrorOr<BinarySection &> ColdSection = Function.getColdCodeSection(); |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3718 | assert(ColdSection && "cannot find section for cold part"); |
| 3719 | // Cold fragments are aligned at 16 bytes. |
| 3720 | NextAvailableAddress = alignTo(NextAvailableAddress, 16); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3721 | BinaryFunction::FragmentInfo &ColdPart = Function.cold(); |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3722 | if (TooLarge) { |
| 3723 | // The corresponding FDE will refer to address 0. |
| 3724 | ColdPart.setAddress(0); |
| 3725 | ColdPart.setImageAddress(0); |
| 3726 | ColdPart.setImageSize(0); |
| 3727 | ColdPart.setFileOffset(0); |
| 3728 | } else { |
| 3729 | ColdPart.setAddress(NextAvailableAddress); |
| 3730 | ColdPart.setImageAddress(ColdSection->getAllocAddress()); |
| 3731 | ColdPart.setImageSize(ColdSection->getOutputSize()); |
| 3732 | ColdPart.setFileOffset(getFileOffsetForAddress(NextAvailableAddress)); |
| 3733 | ColdSection->setOutputAddress(ColdPart.getAddress()); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3734 | } |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3735 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3736 | LLVM_DEBUG(dbgs() << "BOLT: mapping cold fragment 0x" |
| 3737 | << Twine::utohexstr(ColdPart.getImageAddress()) |
| 3738 | << " to 0x" << Twine::utohexstr(ColdPart.getAddress()) |
| 3739 | << " with size " |
| 3740 | << Twine::utohexstr(ColdPart.getImageSize()) << '\n'); |
| 3741 | RTDyld.reassignSectionAddress(ColdSection->getSectionID(), |
| 3742 | ColdPart.getAddress()); |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3743 | |
| 3744 | NextAvailableAddress += ColdPart.getImageSize(); |
| 3745 | } |
| 3746 | |
| 3747 | // Add the new text section aggregating all existing code sections. |
| 3748 | // This is pseudo-section that serves a purpose of creating a corresponding |
| 3749 | // entry in section header table. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3750 | int64_t NewTextSectionSize = |
| 3751 | NextAvailableAddress - NewTextSectionStartAddress; |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3752 | if (NewTextSectionSize) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3753 | const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/true, |
| 3754 | /*IsText=*/true, |
| 3755 | /*IsAllocatable=*/true); |
| 3756 | BinarySection &Section = |
Maksim Panchenko | a07f1a2 | 2020-03-11 22:51:32 | [diff] [blame] | 3757 | BC->registerOrUpdateSection(getBOLTTextSectionName(), |
| 3758 | ELF::SHT_PROGBITS, |
| 3759 | Flags, |
| 3760 | /*Data=*/nullptr, |
| 3761 | NewTextSectionSize, |
| 3762 | 16); |
Maksim Panchenko | d1b76f2 | 2019-03-22 04:13:45 | [diff] [blame] | 3763 | Section.setOutputAddress(NewTextSectionStartAddress); |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 3764 | Section.setOutputFileOffset( |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 3765 | getFileOffsetForAddress(NewTextSectionStartAddress)); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3766 | } |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 3767 | } |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3768 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3769 | void RewriteInstance::mapDataSections(RuntimeDyld &RTDyld) { |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3770 | // Map special sections to their addresses in the output image. |
| 3771 | // These are the sections that we generate via MCStreamer. |
| 3772 | // The order is important. |
Rafael Auler | 0d23cba | 2019-06-20 03:10:49 | [diff] [blame] | 3773 | std::vector<std::string> Sections = { |
Maksim Panchenko | a07f1a2 | 2020-03-11 22:51:32 | [diff] [blame] | 3774 | ".eh_frame", Twine(getOrgSecPrefix(), ".eh_frame").str(), |
Xun Li | 9bd7161 | 2020-05-02 18:14:38 | [diff] [blame] | 3775 | ".gcc_except_table", ".rodata", ".rodata.cold"}; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3776 | if (RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary()) |
Xun Li | 9bd7161 | 2020-05-02 18:14:38 | [diff] [blame] | 3777 | RtLibrary->addRuntimeLibSections(Sections); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3778 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3779 | for (std::string &SectionName : Sections) { |
| 3780 | ErrorOr<BinarySection &> Section = BC->getUniqueSectionByName(SectionName); |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 3781 | if (!Section || !Section->isAllocatable() || !Section->isFinalized()) |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3782 | continue; |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 3783 | NextAvailableAddress = |
| 3784 | alignTo(NextAvailableAddress, Section->getAlignment()); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3785 | LLVM_DEBUG(dbgs() << "BOLT: mapping section " << SectionName << " (0x" |
| 3786 | << Twine::utohexstr(Section->getAllocAddress()) |
| 3787 | << ") to 0x" << Twine::utohexstr(NextAvailableAddress) |
| 3788 | << ":0x" |
| 3789 | << Twine::utohexstr(NextAvailableAddress + |
| 3790 | Section->getOutputSize()) |
| 3791 | << '\n'); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3792 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3793 | RTDyld.reassignSectionAddress(Section->getSectionID(), |
| 3794 | NextAvailableAddress); |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 3795 | Section->setOutputAddress(NextAvailableAddress); |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 3796 | Section->setOutputFileOffset(getFileOffsetForAddress(NextAvailableAddress)); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3797 | |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 3798 | NextAvailableAddress += Section->getOutputSize(); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3799 | } |
| 3800 | |
| 3801 | // Handling for sections with relocations. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3802 | for (BinarySection &Section : BC->sections()) { |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 3803 | if (!Section.hasSectionRef()) |
Bill Nell | 2640b40 | 2018-01-23 23:10:24 | [diff] [blame] | 3804 | continue; |
| 3805 | |
| 3806 | StringRef SectionName = Section.getName(); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3807 | ErrorOr<BinarySection &> OrgSection = |
| 3808 | BC->getUniqueSectionByName((getOrgSecPrefix() + SectionName).str()); |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 3809 | if (!OrgSection || |
| 3810 | !OrgSection->isAllocatable() || |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 3811 | !OrgSection->isFinalized() || |
| 3812 | !OrgSection->hasValidSectionID()) |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3813 | continue; |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3814 | |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 3815 | if (OrgSection->getOutputAddress()) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3816 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: section " << SectionName |
| 3817 | << " is already mapped at 0x" |
| 3818 | << Twine::utohexstr(OrgSection->getOutputAddress()) |
| 3819 | << '\n'); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3820 | continue; |
| 3821 | } |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3822 | LLVM_DEBUG( |
| 3823 | dbgs() << "BOLT: mapping original section " << SectionName << " (0x" |
| 3824 | << Twine::utohexstr(OrgSection->getAllocAddress()) << ") to 0x" |
| 3825 | << Twine::utohexstr(Section.getAddress()) << '\n'); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3826 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3827 | RTDyld.reassignSectionAddress(OrgSection->getSectionID(), |
| 3828 | Section.getAddress()); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3829 | |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 3830 | OrgSection->setOutputAddress(Section.getAddress()); |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 3831 | OrgSection->setOutputFileOffset(Section.getContents().data() - |
| 3832 | InputFile->getData().data()); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3833 | } |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 3834 | } |
| 3835 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3836 | void RewriteInstance::mapExtraSections(RuntimeDyld &RTDyld) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3837 | for (BinarySection &Section : BC->allocatableSections()) { |
Rafael Auler | 62aa74f | 2019-07-24 21:03:43 | [diff] [blame] | 3838 | if (Section.getOutputAddress() || !Section.hasValidSectionID()) |
| 3839 | continue; |
| 3840 | NextAvailableAddress = |
| 3841 | alignTo(NextAvailableAddress, Section.getAlignment()); |
| 3842 | Section.setOutputAddress(NextAvailableAddress); |
| 3843 | NextAvailableAddress += Section.getOutputSize(); |
| 3844 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3845 | LLVM_DEBUG(dbgs() << "BOLT: (extra) mapping " << Section.getName() |
| 3846 | << " at 0x" << Twine::utohexstr(Section.getAllocAddress()) |
| 3847 | << " to 0x" |
| 3848 | << Twine::utohexstr(Section.getOutputAddress()) << '\n'); |
Rafael Auler | 62aa74f | 2019-07-24 21:03:43 | [diff] [blame] | 3849 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3850 | RTDyld.reassignSectionAddress(Section.getSectionID(), |
| 3851 | Section.getOutputAddress()); |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 3852 | Section.setOutputFileOffset( |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3853 | getFileOffsetForAddress(Section.getOutputAddress())); |
Rafael Auler | 62aa74f | 2019-07-24 21:03:43 | [diff] [blame] | 3854 | } |
| 3855 | } |
| 3856 | |
Maksim Panchenko | 3f42fdf | 2017-05-09 05:51:36 | [diff] [blame] | 3857 | void RewriteInstance::updateOutputValues(const MCAsmLayout &Layout) { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 3858 | for (BinaryFunction *Function : BC->getAllBinaryFunctions()) |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 3859 | Function->updateOutputValues(Layout); |
Maksim Panchenko | 3f42fdf | 2017-05-09 05:51:36 | [diff] [blame] | 3860 | } |
| 3861 | |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 3862 | void RewriteInstance::patchELFPHDRTable() { |
| 3863 | auto ELF64LEFile = dyn_cast<ELF64LEObjectFile>(InputFile); |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 3864 | if (!ELF64LEFile) { |
| 3865 | errs() << "BOLT-ERROR: only 64-bit LE ELF binaries are supported\n"; |
| 3866 | exit(1); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 3867 | } |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3868 | const ELFFile<ELF64LE> &Obj = ELF64LEFile->getELFFile(); |
| 3869 | raw_fd_ostream &OS = Out->os(); |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 3870 | |
| 3871 | // Write/re-write program headers. |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3872 | Phnum = Obj.getHeader().e_phnum; |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 3873 | if (PHDRTableOffset) { |
| 3874 | // Writing new pheader table. |
| 3875 | Phnum += 1; // only adding one new segment |
| 3876 | // Segment size includes the size of the PHDR area. |
| 3877 | NewTextSegmentSize = NextAvailableAddress - PHDRTableAddress; |
| 3878 | } else { |
| 3879 | assert(!PHDRTableAddress && "unexpected address for program header table"); |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 3880 | // Update existing table. |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3881 | PHDRTableOffset = Obj.getHeader().e_phoff; |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 3882 | NewTextSegmentSize = NextAvailableAddress - NewTextSegmentAddress; |
| 3883 | } |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 3884 | OS.seek(PHDRTableOffset); |
| 3885 | |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 3886 | bool ModdedGnuStack = false; |
Maksim Panchenko | 2428567 | 2017-05-25 17:29:38 | [diff] [blame] | 3887 | (void)ModdedGnuStack; |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 3888 | bool AddedSegment = false; |
Maksim Panchenko | 2428567 | 2017-05-25 17:29:38 | [diff] [blame] | 3889 | (void)AddedSegment; |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 3890 | |
Maksim Panchenko | 250ca40 | 2020-06-26 23:52:07 | [diff] [blame] | 3891 | auto createNewTextPhdr = [&]() { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3892 | ELF64LEPhdrTy NewPhdr; |
Maksim Panchenko | 250ca40 | 2020-06-26 23:52:07 | [diff] [blame] | 3893 | NewPhdr.p_type = ELF::PT_LOAD; |
| 3894 | if (PHDRTableAddress) { |
| 3895 | NewPhdr.p_offset = PHDRTableOffset; |
| 3896 | NewPhdr.p_vaddr = PHDRTableAddress; |
| 3897 | NewPhdr.p_paddr = PHDRTableAddress; |
| 3898 | } else { |
| 3899 | NewPhdr.p_offset = NewTextSegmentOffset; |
| 3900 | NewPhdr.p_vaddr = NewTextSegmentAddress; |
| 3901 | NewPhdr.p_paddr = NewTextSegmentAddress; |
| 3902 | } |
| 3903 | NewPhdr.p_filesz = NewTextSegmentSize; |
| 3904 | NewPhdr.p_memsz = NewTextSegmentSize; |
| 3905 | NewPhdr.p_flags = ELF::PF_X | ELF::PF_R; |
| 3906 | // FIXME: Currently instrumentation is experimental and the runtime data |
| 3907 | // is emitted with code, thus everything needs to be writable |
| 3908 | if (opts::Instrument) |
| 3909 | NewPhdr.p_flags |= ELF::PF_W; |
| 3910 | NewPhdr.p_align = BC->PageAlign; |
| 3911 | |
| 3912 | return NewPhdr; |
| 3913 | }; |
| 3914 | |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 3915 | // Copy existing program headers with modifications. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3916 | for (const ELF64LE::Phdr &Phdr : cantFail(Obj.program_headers())) { |
| 3917 | ELF64LE::Phdr NewPhdr = Phdr; |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 3918 | if (PHDRTableAddress && Phdr.p_type == ELF::PT_PHDR) { |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 3919 | NewPhdr.p_offset = PHDRTableOffset; |
| 3920 | NewPhdr.p_vaddr = PHDRTableAddress; |
| 3921 | NewPhdr.p_paddr = PHDRTableAddress; |
| 3922 | NewPhdr.p_filesz = sizeof(NewPhdr) * Phnum; |
| 3923 | NewPhdr.p_memsz = sizeof(NewPhdr) * Phnum; |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 3924 | } else if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3925 | ErrorOr<BinarySection &> EHFrameHdrSec = |
| 3926 | BC->getUniqueSectionByName(".eh_frame_hdr"); |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 3927 | if (EHFrameHdrSec && EHFrameHdrSec->isAllocatable() && |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 3928 | EHFrameHdrSec->isFinalized()) { |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 3929 | NewPhdr.p_offset = EHFrameHdrSec->getOutputFileOffset(); |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 3930 | NewPhdr.p_vaddr = EHFrameHdrSec->getOutputAddress(); |
| 3931 | NewPhdr.p_paddr = EHFrameHdrSec->getOutputAddress(); |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 3932 | NewPhdr.p_filesz = EHFrameHdrSec->getOutputSize(); |
| 3933 | NewPhdr.p_memsz = EHFrameHdrSec->getOutputSize(); |
Bill Nell | 674dbcc | 2016-07-12 23:43:53 | [diff] [blame] | 3934 | } |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 3935 | } else if (opts::UseGnuStack && Phdr.p_type == ELF::PT_GNU_STACK) { |
Maksim Panchenko | 250ca40 | 2020-06-26 23:52:07 | [diff] [blame] | 3936 | NewPhdr = createNewTextPhdr(); |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 3937 | ModdedGnuStack = true; |
| 3938 | } else if (!opts::UseGnuStack && Phdr.p_type == ELF::PT_DYNAMIC) { |
Maksim Panchenko | 250ca40 | 2020-06-26 23:52:07 | [diff] [blame] | 3939 | // Insert the new header before DYNAMIC. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3940 | ELF64LE::Phdr NewTextPhdr = createNewTextPhdr(); |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 3941 | OS.write(reinterpret_cast<const char *>(&NewTextPhdr), |
| 3942 | sizeof(NewTextPhdr)); |
| 3943 | AddedSegment = true; |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 3944 | } |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 3945 | OS.write(reinterpret_cast<const char *>(&NewPhdr), sizeof(NewPhdr)); |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 3946 | } |
| 3947 | |
Maksim Panchenko | 250ca40 | 2020-06-26 23:52:07 | [diff] [blame] | 3948 | if (!opts::UseGnuStack && !AddedSegment) { |
| 3949 | // Append the new header to the end of the table. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3950 | ELF64LE::Phdr NewTextPhdr = createNewTextPhdr(); |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 3951 | OS.write(reinterpret_cast<const char *>(&NewTextPhdr), sizeof(NewTextPhdr)); |
Maksim Panchenko | 250ca40 | 2020-06-26 23:52:07 | [diff] [blame] | 3952 | } |
| 3953 | |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 3954 | assert((!opts::UseGnuStack || ModdedGnuStack) && |
| 3955 | "could not find GNU_STACK program header to modify"); |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 3956 | } |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 3957 | |
Maksim Panchenko | 4464861 | 2016-09-16 22:54:32 | [diff] [blame] | 3958 | namespace { |
Maksim Panchenko | 075f076 | 2017-04-06 17:49:59 | [diff] [blame] | 3959 | |
| 3960 | /// Write padding to \p OS such that its current \p Offset becomes aligned |
| 3961 | /// at \p Alignment. Return new (aligned) offset. |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 3962 | uint64_t appendPadding(raw_pwrite_stream &OS, uint64_t Offset, |
Maksim Panchenko | 075f076 | 2017-04-06 17:49:59 | [diff] [blame] | 3963 | uint64_t Alignment) { |
Maksim Panchenko | 69b5863 | 2017-05-17 00:29:31 | [diff] [blame] | 3964 | if (!Alignment) |
| 3965 | return Offset; |
| 3966 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3967 | const uint64_t PaddingSize = |
| 3968 | offsetToAlignment(Offset, llvm::Align(Alignment)); |
Maksim Panchenko | 075f076 | 2017-04-06 17:49:59 | [diff] [blame] | 3969 | for (unsigned I = 0; I < PaddingSize; ++I) |
Maksim Panchenko | 4464861 | 2016-09-16 22:54:32 | [diff] [blame] | 3970 | OS.write((unsigned char)0); |
Maksim Panchenko | 075f076 | 2017-04-06 17:49:59 | [diff] [blame] | 3971 | return Offset + PaddingSize; |
Maksim Panchenko | 4464861 | 2016-09-16 22:54:32 | [diff] [blame] | 3972 | } |
Maksim Panchenko | 075f076 | 2017-04-06 17:49:59 | [diff] [blame] | 3973 | |
Maksim Panchenko | 4464861 | 2016-09-16 22:54:32 | [diff] [blame] | 3974 | } |
| 3975 | |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 3976 | void RewriteInstance::rewriteNoteSections() { |
| 3977 | auto ELF64LEFile = dyn_cast<ELF64LEObjectFile>(InputFile); |
| 3978 | if (!ELF64LEFile) { |
| 3979 | errs() << "BOLT-ERROR: only 64-bit LE ELF binaries are supported\n"; |
| 3980 | exit(1); |
| 3981 | } |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3982 | const ELFFile<ELF64LE> &Obj = ELF64LEFile->getELFFile(); |
| 3983 | raw_fd_ostream &OS = Out->os(); |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 3984 | |
Maksim Panchenko | 6ff1795 | 2017-01-17 23:49:59 | [diff] [blame] | 3985 | uint64_t NextAvailableOffset = getFileOffsetForAddress(NextAvailableAddress); |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 3986 | assert(NextAvailableOffset >= FirstNonAllocatableOffset && |
| 3987 | "next available offset calculation failure"); |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 3988 | OS.seek(NextAvailableOffset); |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 3989 | |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 3990 | // Copy over non-allocatable section contents and update file offsets. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3991 | for (const ELF64LE::Shdr &Section : cantFail(Obj.sections())) { |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 3992 | if (Section.sh_type == ELF::SHT_NULL) |
| 3993 | continue; |
| 3994 | if (Section.sh_flags & ELF::SHF_ALLOC) |
| 3995 | continue; |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 3996 | |
Maksim Panchenko | 1ed3ac1 | 2019-10-29 21:49:49 | [diff] [blame] | 3997 | StringRef SectionName = |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 3998 | cantFail(Obj.getSectionName(Section), "cannot get section name"); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 3999 | ErrorOr<BinarySection &> BSec = BC->getUniqueSectionByName(SectionName); |
Maksim Panchenko | 1ed3ac1 | 2019-10-29 21:49:49 | [diff] [blame] | 4000 | |
| 4001 | if (shouldStrip(Section, SectionName)) |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 4002 | continue; |
| 4003 | |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 4004 | // Insert padding as needed. |
Maksim Panchenko | 075f076 | 2017-04-06 17:49:59 | [diff] [blame] | 4005 | NextAvailableOffset = |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4006 | appendPadding(OS, NextAvailableOffset, Section.sh_addralign); |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 4007 | |
Maksim Panchenko | f047b9d | 2016-05-17 00:02:17 | [diff] [blame] | 4008 | // New section size. |
Gabriel Poesia | 80ea31b | 2016-03-11 19:30:30 | [diff] [blame] | 4009 | uint64_t Size = 0; |
Amir Ayupov | 12e9fec | 2021-04-01 18:43:00 | [diff] [blame] | 4010 | bool DataWritten = false; |
| 4011 | uint8_t *SectionData = nullptr; |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 4012 | // Copy over section contents unless it's one of the sections we overwrite. |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 4013 | if (!willOverwriteSection(SectionName)) { |
Gabriel Poesia | 80ea31b | 2016-03-11 19:30:30 | [diff] [blame] | 4014 | Size = Section.sh_size; |
Alexander Yermolovich | 1c2f4bb | 2021-11-16 01:19:24 | [diff] [blame] | 4015 | StringRef Dataref = InputFile->getData().substr(Section.sh_offset, Size); |
| 4016 | std::string Data; |
| 4017 | if (BSec && BSec->getPatcher()) { |
| 4018 | Data = BSec->getPatcher()->patchBinary(Dataref); |
| 4019 | Dataref = StringRef(Data); |
| 4020 | } |
Maksim Panchenko | 075f076 | 2017-04-06 17:49:59 | [diff] [blame] | 4021 | |
Amir Ayupov | 12e9fec | 2021-04-01 18:43:00 | [diff] [blame] | 4022 | // Section was expanded, so need to treat it as overwrite. |
Alexander Yermolovich | 1c2f4bb | 2021-11-16 01:19:24 | [diff] [blame] | 4023 | if (Size != Dataref.size()) { |
| 4024 | BSec = BC->registerOrUpdateNoteSection( |
| 4025 | SectionName, copyByteArray(Dataref), Dataref.size()); |
Amir Ayupov | 12e9fec | 2021-04-01 18:43:00 | [diff] [blame] | 4026 | Size = 0; |
| 4027 | } else { |
Alexander Yermolovich | 1c2f4bb | 2021-11-16 01:19:24 | [diff] [blame] | 4028 | OS << Dataref; |
Amir Ayupov | 12e9fec | 2021-04-01 18:43:00 | [diff] [blame] | 4029 | DataWritten = true; |
| 4030 | |
| 4031 | // Add padding as the section extension might rely on the alignment. |
| 4032 | Size = appendPadding(OS, Size, Section.sh_addralign); |
| 4033 | } |
Gabriel Poesia | 80ea31b | 2016-03-11 19:30:30 | [diff] [blame] | 4034 | } |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 4035 | |
Maksim Panchenko | f2df1a8 | 2016-03-10 00:06:41 | [diff] [blame] | 4036 | // Perform section post-processing. |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 4037 | if (BSec && !BSec->isAllocatable()) { |
| 4038 | assert(BSec->getAlignment() <= Section.sh_addralign && |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 4039 | "alignment exceeds value in file"); |
Maksim Panchenko | f2df1a8 | 2016-03-10 00:06:41 | [diff] [blame] | 4040 | |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 4041 | if (BSec->getAllocAddress()) { |
Amir Ayupov | 12e9fec | 2021-04-01 18:43:00 | [diff] [blame] | 4042 | assert(!DataWritten && "Writing section twice."); |
Amir Ayupov | c907d6e | 2022-05-17 21:30:00 | [diff] [blame] | 4043 | (void)DataWritten; |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 4044 | SectionData = BSec->getOutputData(); |
Amir Ayupov | 12e9fec | 2021-04-01 18:43:00 | [diff] [blame] | 4045 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4046 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: " << (Size ? "appending" : "writing") |
| 4047 | << " contents to section " << SectionName << '\n'); |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4048 | OS.write(reinterpret_cast<char *>(SectionData), BSec->getOutputSize()); |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 4049 | Size += BSec->getOutputSize(); |
Maksim Panchenko | f2df1a8 | 2016-03-10 00:06:41 | [diff] [blame] | 4050 | } |
| 4051 | |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 4052 | BSec->setOutputFileOffset(NextAvailableOffset); |
| 4053 | BSec->flushPendingRelocations(OS, |
| 4054 | [this] (const MCSymbol *S) { |
| 4055 | return getNewValueForSymbol(S->getName()); |
| 4056 | }); |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 4057 | } |
| 4058 | |
| 4059 | // Set/modify section info. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4060 | BinarySection &NewSection = |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 4061 | BC->registerOrUpdateNoteSection(SectionName, |
| 4062 | SectionData, |
| 4063 | Size, |
| 4064 | Section.sh_addralign, |
| 4065 | BSec ? BSec->isReadOnly() : false, |
| 4066 | BSec ? BSec->getELFType() |
Maksim Panchenko | 9711286 | 2020-02-18 17:20:17 | [diff] [blame] | 4067 | : ELF::SHT_PROGBITS); |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4068 | NewSection.setOutputAddress(0); |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 4069 | NewSection.setOutputFileOffset(NextAvailableOffset); |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 4070 | |
| 4071 | NextAvailableOffset += Size; |
| 4072 | } |
Maksim Panchenko | 69b5863 | 2017-05-17 00:29:31 | [diff] [blame] | 4073 | |
| 4074 | // Write new note sections. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4075 | for (BinarySection &Section : BC->nonAllocatableSections()) { |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 4076 | if (Section.getOutputFileOffset() || !Section.getAllocAddress()) |
Maksim Panchenko | 69b5863 | 2017-05-17 00:29:31 | [diff] [blame] | 4077 | continue; |
| 4078 | |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 4079 | assert(!Section.hasPendingRelocations() && "cannot have pending relocs"); |
Maksim Panchenko | 69b5863 | 2017-05-17 00:29:31 | [diff] [blame] | 4080 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4081 | NextAvailableOffset = |
| 4082 | appendPadding(OS, NextAvailableOffset, Section.getAlignment()); |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 4083 | Section.setOutputFileOffset(NextAvailableOffset); |
Maksim Panchenko | 69b5863 | 2017-05-17 00:29:31 | [diff] [blame] | 4084 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4085 | LLVM_DEBUG( |
| 4086 | dbgs() << "BOLT-DEBUG: writing out new section " << Section.getName() |
| 4087 | << " of size " << Section.getOutputSize() << " at offset 0x" |
| 4088 | << Twine::utohexstr(Section.getOutputFileOffset()) << '\n'); |
Maksim Panchenko | 69b5863 | 2017-05-17 00:29:31 | [diff] [blame] | 4089 | |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 4090 | OS.write(Section.getOutputContents().data(), Section.getOutputSize()); |
| 4091 | NextAvailableOffset += Section.getOutputSize(); |
Maksim Panchenko | 69b5863 | 2017-05-17 00:29:31 | [diff] [blame] | 4092 | } |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 4093 | } |
| 4094 | |
Maksim Panchenko | e212805 | 2017-02-07 20:20:46 | [diff] [blame] | 4095 | template <typename ELFT> |
Maksim Panchenko | 69b5863 | 2017-05-17 00:29:31 | [diff] [blame] | 4096 | void RewriteInstance::finalizeSectionStringTable(ELFObjectFile<ELFT> *File) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4097 | using ELFShdrTy = typename ELFT::Shdr; |
| 4098 | const ELFFile<ELFT> &Obj = File->getELFFile(); |
Maksim Panchenko | e212805 | 2017-02-07 20:20:46 | [diff] [blame] | 4099 | |
| 4100 | // Pre-populate section header string table. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4101 | for (const ELFShdrTy &Section : cantFail(Obj.sections())) { |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 4102 | StringRef SectionName = |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4103 | cantFail(Obj.getSectionName(Section), "cannot get section name"); |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 4104 | SHStrTab.add(SectionName); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4105 | std::string OutputSectionName = getOutputSectionName(Obj, Section); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 4106 | if (OutputSectionName != SectionName) |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4107 | SHStrTabPool.emplace_back(std::move(OutputSectionName)); |
Maksim Panchenko | e212805 | 2017-02-07 20:20:46 | [diff] [blame] | 4108 | } |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 4109 | for (const std::string &Str : SHStrTabPool) |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4110 | SHStrTab.add(Str); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 4111 | for (const BinarySection &Section : BC->sections()) |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 4112 | SHStrTab.add(Section.getName()); |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 4113 | SHStrTab.finalize(); |
Maksim Panchenko | e212805 | 2017-02-07 20:20:46 | [diff] [blame] | 4114 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4115 | const size_t SHStrTabSize = SHStrTab.getSize(); |
Maksim Panchenko | 69b5863 | 2017-05-17 00:29:31 | [diff] [blame] | 4116 | uint8_t *DataCopy = new uint8_t[SHStrTabSize]; |
Rafael Auler | 8a5a301 | 2018-02-06 23:00:23 | [diff] [blame] | 4117 | memset(DataCopy, 0, SHStrTabSize); |
| 4118 | SHStrTab.write(DataCopy); |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 4119 | BC->registerOrUpdateNoteSection(".shstrtab", |
| 4120 | DataCopy, |
| 4121 | SHStrTabSize, |
| 4122 | /*Alignment=*/1, |
| 4123 | /*IsReadOnly=*/true, |
| 4124 | ELF::SHT_STRTAB); |
Maksim Panchenko | e212805 | 2017-02-07 20:20:46 | [diff] [blame] | 4125 | } |
| 4126 | |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 4127 | void RewriteInstance::addBoltInfoSection() { |
| 4128 | std::string DescStr; |
| 4129 | raw_string_ostream DescOS(DescStr); |
| 4130 | |
| 4131 | DescOS << "BOLT revision: " << BoltRevision << ", " |
| 4132 | << "command line:"; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 4133 | for (int I = 0; I < Argc; ++I) |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 4134 | DescOS << " " << Argv[I]; |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 4135 | DescOS.flush(); |
| 4136 | |
Rafael Auler | 821480d | 2019-08-02 18:20:13 | [diff] [blame] | 4137 | // Encode as GNU GOLD VERSION so it is easily printable by 'readelf -n' |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4138 | const std::string BoltInfo = |
Rafael Auler | 821480d | 2019-08-02 18:20:13 | [diff] [blame] | 4139 | BinarySection::encodeELFNote("GNU", DescStr, 4 /*NT_GNU_GOLD_VERSION*/); |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 4140 | BC->registerOrUpdateNoteSection(".note.bolt_info", copyByteArray(BoltInfo), |
| 4141 | BoltInfo.size(), |
| 4142 | /*Alignment=*/1, |
| 4143 | /*IsReadOnly=*/true, ELF::SHT_NOTE); |
Bill Nell | 5cd5896 | 2017-05-24 21:14:16 | [diff] [blame] | 4144 | } |
| 4145 | |
Rafael Auler | 21f4303 | 2019-04-13 00:33:46 | [diff] [blame] | 4146 | void RewriteInstance::addBATSection() { |
| 4147 | BC->registerOrUpdateNoteSection(BoltAddressTranslation::SECTION_NAME, nullptr, |
| 4148 | 0, |
| 4149 | /*Alignment=*/1, |
| 4150 | /*IsReadOnly=*/true, ELF::SHT_NOTE); |
| 4151 | } |
| 4152 | |
| 4153 | void RewriteInstance::encodeBATSection() { |
| 4154 | std::string DescStr; |
| 4155 | raw_string_ostream DescOS(DescStr); |
| 4156 | |
| 4157 | BAT->write(DescOS); |
| 4158 | DescOS.flush(); |
| 4159 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4160 | const std::string BoltInfo = |
Rafael Auler | 821480d | 2019-08-02 18:20:13 | [diff] [blame] | 4161 | BinarySection::encodeELFNote("BOLT", DescStr, BinarySection::NT_BOLT_BAT); |
Rafael Auler | 21f4303 | 2019-04-13 00:33:46 | [diff] [blame] | 4162 | BC->registerOrUpdateNoteSection(BoltAddressTranslation::SECTION_NAME, |
| 4163 | copyByteArray(BoltInfo), BoltInfo.size(), |
| 4164 | /*Alignment=*/1, |
| 4165 | /*IsReadOnly=*/true, ELF::SHT_NOTE); |
| 4166 | } |
| 4167 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4168 | template <typename ELFObjType, typename ELFShdrTy> |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4169 | std::string RewriteInstance::getOutputSectionName(const ELFObjType &Obj, |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4170 | const ELFShdrTy &Section) { |
| 4171 | if (Section.sh_type == ELF::SHT_NULL) |
| 4172 | return ""; |
| 4173 | |
| 4174 | StringRef SectionName = |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4175 | cantFail(Obj.getSectionName(Section), "cannot get section name"); |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4176 | |
Maksim Panchenko | 2b15233 | 2019-04-26 22:30:12 | [diff] [blame] | 4177 | if ((Section.sh_flags & ELF::SHF_ALLOC) && willOverwriteSection(SectionName)) |
Maksim Panchenko | a07f1a2 | 2020-03-11 22:51:32 | [diff] [blame] | 4178 | return (getOrgSecPrefix() + SectionName).str(); |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4179 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4180 | return std::string(SectionName); |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4181 | } |
| 4182 | |
Maksim Panchenko | 1ed3ac1 | 2019-10-29 21:49:49 | [diff] [blame] | 4183 | template <typename ELFShdrTy> |
| 4184 | bool RewriteInstance::shouldStrip(const ELFShdrTy &Section, |
| 4185 | StringRef SectionName) { |
| 4186 | // Strip non-allocatable relocation sections. |
| 4187 | if (!(Section.sh_flags & ELF::SHF_ALLOC) && Section.sh_type == ELF::SHT_RELA) |
| 4188 | return true; |
| 4189 | |
| 4190 | // Strip debug sections if not updating them. |
| 4191 | if (isDebugSection(SectionName) && !opts::UpdateDebugSections) |
| 4192 | return true; |
| 4193 | |
Vladislav Khmelevsky | 95ee129 | 2021-10-16 14:02:45 | [diff] [blame] | 4194 | // Strip symtab section if needed |
| 4195 | if (opts::RemoveSymtab && Section.sh_type == ELF::SHT_SYMTAB) |
| 4196 | return true; |
| 4197 | |
Maksim Panchenko | 1ed3ac1 | 2019-10-29 21:49:49 | [diff] [blame] | 4198 | return false; |
| 4199 | } |
| 4200 | |
Amir Ayupov | 29fe14c | 2022-01-14 20:57:37 | [diff] [blame] | 4201 | template <typename ELFT> |
| 4202 | std::vector<typename object::ELFObjectFile<ELFT>::Elf_Shdr> |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4203 | RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File, |
| 4204 | std::vector<uint32_t> &NewSectionIndex) { |
Amir Ayupov | 29fe14c | 2022-01-14 20:57:37 | [diff] [blame] | 4205 | using ELFShdrTy = typename ELFObjectFile<ELFT>::Elf_Shdr; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4206 | const ELFFile<ELFT> &Obj = File->getELFFile(); |
| 4207 | typename ELFT::ShdrRange Sections = cantFail(Obj.sections()); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4208 | |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4209 | // Keep track of section header entries together with their name. |
| 4210 | std::vector<std::pair<std::string, ELFShdrTy>> OutputSections; |
| 4211 | auto addSection = [&](const std::string &Name, const ELFShdrTy &Section) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4212 | ELFShdrTy NewSection = Section; |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4213 | NewSection.sh_name = SHStrTab.getOffset(Name); |
Amir Ayupov | 9a88454 | 2021-05-08 01:43:25 | [diff] [blame] | 4214 | OutputSections.emplace_back(Name, std::move(NewSection)); |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4215 | }; |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4216 | |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4217 | // Copy over entries for original allocatable sections using modified name. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4218 | for (const ELFShdrTy &Section : Sections) { |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4219 | // Always ignore this section. |
| 4220 | if (Section.sh_type == ELF::SHT_NULL) { |
Amir Ayupov | 9a88454 | 2021-05-08 01:43:25 | [diff] [blame] | 4221 | OutputSections.emplace_back("", Section); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4222 | continue; |
| 4223 | } |
| 4224 | |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4225 | if (!(Section.sh_flags & ELF::SHF_ALLOC)) |
| 4226 | continue; |
| 4227 | |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4228 | addSection(getOutputSectionName(Obj, Section), Section); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4229 | } |
| 4230 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4231 | for (const BinarySection &Section : BC->allocatableSections()) { |
Bill Nell | 0e4d86b | 2017-11-15 04:05:11 | [diff] [blame] | 4232 | if (!Section.isFinalized()) |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 4233 | continue; |
| 4234 | |
Maksim Panchenko | a07f1a2 | 2020-03-11 22:51:32 | [diff] [blame] | 4235 | if (Section.getName().startswith(getOrgSecPrefix()) || |
Maksim Panchenko | 1f3e351 | 2020-03-06 23:06:37 | [diff] [blame] | 4236 | Section.isAnonymous()) { |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4237 | if (opts::Verbosity) |
Maksim Panchenko | 297d1a4 | 2019-03-27 20:58:31 | [diff] [blame] | 4238 | outs() << "BOLT-INFO: not writing section header for section " |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4239 | << Section.getName() << '\n'; |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4240 | continue; |
| 4241 | } |
| 4242 | |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4243 | if (opts::Verbosity >= 1) |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4244 | outs() << "BOLT-INFO: writing section header for " << Section.getName() |
| 4245 | << '\n'; |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4246 | ELFShdrTy NewSection; |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4247 | NewSection.sh_type = ELF::SHT_PROGBITS; |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4248 | NewSection.sh_addr = Section.getOutputAddress(); |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 4249 | NewSection.sh_offset = Section.getOutputFileOffset(); |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4250 | NewSection.sh_size = Section.getOutputSize(); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4251 | NewSection.sh_entsize = 0; |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4252 | NewSection.sh_flags = Section.getELFFlags(); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4253 | NewSection.sh_link = 0; |
| 4254 | NewSection.sh_info = 0; |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4255 | NewSection.sh_addralign = Section.getAlignment(); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4256 | addSection(std::string(Section.getName()), NewSection); |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4257 | } |
| 4258 | |
| 4259 | // Sort all allocatable sections by their offset. |
Amir Ayupov | d2c8769 | 2022-06-24 05:15:47 | [diff] [blame^] | 4260 | llvm::stable_sort(OutputSections, |
| 4261 | [](const std::pair<std::string, ELFShdrTy> &A, |
| 4262 | const std::pair<std::string, ELFShdrTy> &B) { |
| 4263 | return A.second.sh_offset < B.second.sh_offset; |
| 4264 | }); |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4265 | |
| 4266 | // Fix section sizes to prevent overlapping. |
Maksim Panchenko | 225a8d7 | 2021-03-05 00:31:12 | [diff] [blame] | 4267 | ELFShdrTy *PrevSection = nullptr; |
| 4268 | StringRef PrevSectionName; |
| 4269 | for (auto &SectionKV : OutputSections) { |
| 4270 | ELFShdrTy &Section = SectionKV.second; |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4271 | |
Maksim Panchenko | 225a8d7 | 2021-03-05 00:31:12 | [diff] [blame] | 4272 | // TBSS section does not take file or memory space. Ignore it for layout |
| 4273 | // purposes. |
| 4274 | if (Section.sh_type == ELF::SHT_NOBITS && (Section.sh_flags & ELF::SHF_TLS)) |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4275 | continue; |
| 4276 | |
Maksim Panchenko | 225a8d7 | 2021-03-05 00:31:12 | [diff] [blame] | 4277 | if (PrevSection && |
| 4278 | PrevSection->sh_addr + PrevSection->sh_size > Section.sh_addr) { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 4279 | if (opts::Verbosity > 1) |
Maksim Panchenko | 225a8d7 | 2021-03-05 00:31:12 | [diff] [blame] | 4280 | outs() << "BOLT-INFO: adjusting size for section " << PrevSectionName |
| 4281 | << '\n'; |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4282 | PrevSection->sh_size = Section.sh_addr > PrevSection->sh_addr |
| 4283 | ? Section.sh_addr - PrevSection->sh_addr |
| 4284 | : 0; |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4285 | } |
Maksim Panchenko | 225a8d7 | 2021-03-05 00:31:12 | [diff] [blame] | 4286 | |
| 4287 | PrevSection = &Section; |
| 4288 | PrevSectionName = SectionKV.first; |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4289 | } |
| 4290 | |
| 4291 | uint64_t LastFileOffset = 0; |
| 4292 | |
| 4293 | // Copy over entries for non-allocatable sections performing necessary |
| 4294 | // adjustments. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4295 | for (const ELFShdrTy &Section : Sections) { |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4296 | if (Section.sh_type == ELF::SHT_NULL) |
| 4297 | continue; |
| 4298 | if (Section.sh_flags & ELF::SHF_ALLOC) |
| 4299 | continue; |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4300 | |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 4301 | StringRef SectionName = |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4302 | cantFail(Obj.getSectionName(Section), "cannot get section name"); |
Bill Nell | 729da2d | 2018-04-21 03:03:31 | [diff] [blame] | 4303 | |
Maksim Panchenko | 1ed3ac1 | 2019-10-29 21:49:49 | [diff] [blame] | 4304 | if (shouldStrip(Section, SectionName)) |
Maksim Panchenko | 2b15233 | 2019-04-26 22:30:12 | [diff] [blame] | 4305 | continue; |
| 4306 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4307 | ErrorOr<BinarySection &> BSec = BC->getUniqueSectionByName(SectionName); |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 4308 | assert(BSec && "missing section info for non-allocatable section"); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4309 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4310 | ELFShdrTy NewSection = Section; |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 4311 | NewSection.sh_offset = BSec->getOutputFileOffset(); |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 4312 | NewSection.sh_size = BSec->getOutputSize(); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4313 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 4314 | if (NewSection.sh_type == ELF::SHT_SYMTAB) |
Maksim Panchenko | 30fd960 | 2018-10-23 01:48:12 | [diff] [blame] | 4315 | NewSection.sh_info = NumLocalSymbols; |
Maksim Panchenko | 30fd960 | 2018-10-23 01:48:12 | [diff] [blame] | 4316 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4317 | addSection(std::string(SectionName), NewSection); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4318 | |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 4319 | LastFileOffset = BSec->getOutputFileOffset(); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4320 | } |
| 4321 | |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4322 | // Create entries for new non-allocatable sections. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4323 | for (BinarySection &Section : BC->nonAllocatableSections()) { |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 4324 | if (Section.getOutputFileOffset() <= LastFileOffset) |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4325 | continue; |
| 4326 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 4327 | if (opts::Verbosity >= 1) |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4328 | outs() << "BOLT-INFO: writing section header for " << Section.getName() |
| 4329 | << '\n'; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 4330 | |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4331 | ELFShdrTy NewSection; |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 4332 | NewSection.sh_type = Section.getELFType(); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4333 | NewSection.sh_addr = 0; |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 4334 | NewSection.sh_offset = Section.getOutputFileOffset(); |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 4335 | NewSection.sh_size = Section.getOutputSize(); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4336 | NewSection.sh_entsize = 0; |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 4337 | NewSection.sh_flags = Section.getELFFlags(); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4338 | NewSection.sh_link = 0; |
| 4339 | NewSection.sh_info = 0; |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 4340 | NewSection.sh_addralign = Section.getAlignment(); |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4341 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4342 | addSection(std::string(Section.getName()), NewSection); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4343 | } |
| 4344 | |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4345 | // Assign indices to sections. |
| 4346 | std::unordered_map<std::string, uint64_t> NameToIndex; |
| 4347 | for (uint32_t Index = 1; Index < OutputSections.size(); ++Index) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4348 | const std::string &SectionName = OutputSections[Index].first; |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4349 | NameToIndex[SectionName] = Index; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4350 | if (ErrorOr<BinarySection &> Section = |
| 4351 | BC->getUniqueSectionByName(SectionName)) |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4352 | Section->setIndex(Index); |
| 4353 | } |
| 4354 | |
| 4355 | // Update section index mapping |
| 4356 | NewSectionIndex.clear(); |
| 4357 | NewSectionIndex.resize(Sections.size(), 0); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4358 | for (const ELFShdrTy &Section : Sections) { |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4359 | if (Section.sh_type == ELF::SHT_NULL) |
| 4360 | continue; |
| 4361 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4362 | size_t OrgIndex = std::distance(Sections.begin(), &Section); |
| 4363 | std::string SectionName = getOutputSectionName(Obj, Section); |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4364 | |
| 4365 | // Some sections are stripped |
| 4366 | if (!NameToIndex.count(SectionName)) |
| 4367 | continue; |
| 4368 | |
| 4369 | NewSectionIndex[OrgIndex] = NameToIndex[SectionName]; |
| 4370 | } |
| 4371 | |
| 4372 | std::vector<ELFShdrTy> SectionsOnly(OutputSections.size()); |
Amir Ayupov | d2c8769 | 2022-06-24 05:15:47 | [diff] [blame^] | 4373 | llvm::transform(OutputSections, SectionsOnly.begin(), |
| 4374 | [](std::pair<std::string, ELFShdrTy> &SectionInfo) { |
| 4375 | return SectionInfo.second; |
| 4376 | }); |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4377 | |
| 4378 | return SectionsOnly; |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4379 | } |
| 4380 | |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 4381 | // Rewrite section header table inserting new entries as needed. The sections |
| 4382 | // header table size itself may affect the offsets of other sections, |
| 4383 | // so we are placing it at the end of the binary. |
| 4384 | // |
| 4385 | // As we rewrite entries we need to track how many sections were inserted |
Maksim Panchenko | 69b5863 | 2017-05-17 00:29:31 | [diff] [blame] | 4386 | // as it changes the sh_link value. We map old indices to new ones for |
| 4387 | // existing sections. |
Maksim Panchenko | 4464861 | 2016-09-16 22:54:32 | [diff] [blame] | 4388 | template <typename ELFT> |
| 4389 | void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile<ELFT> *File) { |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4390 | using ELFShdrTy = typename ELFObjectFile<ELFT>::Elf_Shdr; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4391 | using ELFEhdrTy = typename ELFObjectFile<ELFT>::Elf_Ehdr; |
| 4392 | raw_fd_ostream &OS = Out->os(); |
| 4393 | const ELFFile<ELFT> &Obj = File->getELFFile(); |
Maksim Panchenko | f9436bc | 2017-06-08 03:06:29 | [diff] [blame] | 4394 | |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 4395 | std::vector<uint32_t> NewSectionIndex; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4396 | std::vector<ELFShdrTy> OutputSections = |
| 4397 | getOutputSections(File, NewSectionIndex); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4398 | LLVM_DEBUG( |
Maksim Panchenko | f9436bc | 2017-06-08 03:06:29 | [diff] [blame] | 4399 | dbgs() << "BOLT-DEBUG: old to new section index mapping:\n"; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 4400 | for (uint64_t I = 0; I < NewSectionIndex.size(); ++I) |
Maksim Panchenko | f9436bc | 2017-06-08 03:06:29 | [diff] [blame] | 4401 | dbgs() << " " << I << " -> " << NewSectionIndex[I] << '\n'; |
Maksim Panchenko | f9436bc | 2017-06-08 03:06:29 | [diff] [blame] | 4402 | ); |
| 4403 | |
| 4404 | // Align starting address for section header table. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4405 | uint64_t SHTOffset = OS.tell(); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4406 | SHTOffset = appendPadding(OS, SHTOffset, sizeof(ELFShdrTy)); |
Maksim Panchenko | f9436bc | 2017-06-08 03:06:29 | [diff] [blame] | 4407 | |
| 4408 | // Write all section header entries while patching section references. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4409 | for (ELFShdrTy &Section : OutputSections) { |
Maksim Panchenko | f9436bc | 2017-06-08 03:06:29 | [diff] [blame] | 4410 | Section.sh_link = NewSectionIndex[Section.sh_link]; |
| 4411 | if (Section.sh_type == ELF::SHT_REL || Section.sh_type == ELF::SHT_RELA) { |
| 4412 | if (Section.sh_info) |
| 4413 | Section.sh_info = NewSectionIndex[Section.sh_info]; |
| 4414 | } |
| 4415 | OS.write(reinterpret_cast<const char *>(&Section), sizeof(Section)); |
Maksim Panchenko | 69b5863 | 2017-05-17 00:29:31 | [diff] [blame] | 4416 | } |
Maksim Panchenko | 88a4610 | 2017-02-22 19:29:52 | [diff] [blame] | 4417 | |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 4418 | // Fix ELF header. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4419 | ELFEhdrTy NewEhdr = Obj.getHeader(); |
Maksim Panchenko | 3f42fdf | 2017-05-09 05:51:36 | [diff] [blame] | 4420 | |
Maksim Panchenko | b6f7c68 | 2017-12-10 05:40:39 | [diff] [blame] | 4421 | if (BC->HasRelocations) { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 4422 | if (RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary()) |
Xun Li | 00892a5fd | 2020-05-21 21:28:47 | [diff] [blame] | 4423 | NewEhdr.e_entry = RtLibrary->getRuntimeStartAddress(); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 4424 | else |
Xun Li | 00892a5fd | 2020-05-21 21:28:47 | [diff] [blame] | 4425 | NewEhdr.e_entry = getNewFunctionAddress(NewEhdr.e_entry); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4426 | assert((NewEhdr.e_entry || !Obj.getHeader().e_entry) && |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 4427 | "cannot find new address for entry point"); |
Maksim Panchenko | 3f42fdf | 2017-05-09 05:51:36 | [diff] [blame] | 4428 | } |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 4429 | NewEhdr.e_phoff = PHDRTableOffset; |
| 4430 | NewEhdr.e_phnum = Phnum; |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 4431 | NewEhdr.e_shoff = SHTOffset; |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4432 | NewEhdr.e_shnum = OutputSections.size(); |
Maksim Panchenko | f9436bc | 2017-06-08 03:06:29 | [diff] [blame] | 4433 | NewEhdr.e_shstrndx = NewSectionIndex[NewEhdr.e_shstrndx]; |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 4434 | OS.pwrite(reinterpret_cast<const char *>(&NewEhdr), sizeof(NewEhdr), 0); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 4435 | } |
| 4436 | |
Amir Ayupov | 29fe14c | 2022-01-14 20:57:37 | [diff] [blame] | 4437 | template <typename ELFT, typename WriteFuncTy, typename StrTabFuncTy> |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4438 | void RewriteInstance::updateELFSymbolTable( |
Amir Ayupov | 29fe14c | 2022-01-14 20:57:37 | [diff] [blame] | 4439 | ELFObjectFile<ELFT> *File, bool IsDynSym, |
| 4440 | const typename object::ELFObjectFile<ELFT>::Elf_Shdr &SymTabSection, |
| 4441 | const std::vector<uint32_t> &NewSectionIndex, WriteFuncTy Write, |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4442 | StrTabFuncTy AddToStrTab) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4443 | const ELFFile<ELFT> &Obj = File->getELFFile(); |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4444 | using ELFSymTy = typename ELFObjectFile<ELFT>::Elf_Sym; |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4445 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4446 | StringRef StringSection = |
| 4447 | cantFail(Obj.getStringTableForSymtab(SymTabSection)); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4448 | |
| 4449 | unsigned NumHotTextSymsUpdated = 0; |
| 4450 | unsigned NumHotDataSymsUpdated = 0; |
| 4451 | |
| 4452 | std::map<const BinaryFunction *, uint64_t> IslandSizes; |
| 4453 | auto getConstantIslandSize = [&IslandSizes](const BinaryFunction &BF) { |
| 4454 | auto Itr = IslandSizes.find(&BF); |
| 4455 | if (Itr != IslandSizes.end()) |
| 4456 | return Itr->second; |
| 4457 | return IslandSizes[&BF] = BF.estimateConstantIslandSize(); |
| 4458 | }; |
| 4459 | |
| 4460 | // Symbols for the new symbol table. |
| 4461 | std::vector<ELFSymTy> Symbols; |
| 4462 | |
Maksim Panchenko | 6b185cc | 2020-10-22 23:35:29 | [diff] [blame] | 4463 | auto getNewSectionIndex = [&](uint32_t OldIndex) { |
| 4464 | assert(OldIndex < NewSectionIndex.size() && "section index out of bounds"); |
| 4465 | const uint32_t NewIndex = NewSectionIndex[OldIndex]; |
| 4466 | |
| 4467 | // We may have stripped the section that dynsym was referencing due to |
| 4468 | // the linker bug. In that case return the old index avoiding marking |
| 4469 | // the symbol as undefined. |
| 4470 | if (IsDynSym && NewIndex != OldIndex && NewIndex == ELF::SHN_UNDEF) |
| 4471 | return OldIndex; |
| 4472 | return NewIndex; |
| 4473 | }; |
| 4474 | |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 4475 | // Add extra symbols for the function. |
Maksim Panchenko | ffaba22 | 2020-06-24 19:36:15 | [diff] [blame] | 4476 | // |
| 4477 | // Note that addExtraSymbols() could be called multiple times for the same |
| 4478 | // function with different FunctionSymbol matching the main function entry |
| 4479 | // point. |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4480 | auto addExtraSymbols = [&](const BinaryFunction &Function, |
| 4481 | const ELFSymTy &FunctionSymbol) { |
Maksim Panchenko | abda7dc | 2020-04-05 03:12:38 | [diff] [blame] | 4482 | if (Function.isFolded()) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4483 | BinaryFunction *ICFParent = Function.getFoldedIntoFunction(); |
Maksim Panchenko | abda7dc | 2020-04-05 03:12:38 | [diff] [blame] | 4484 | while (ICFParent->isFolded()) |
| 4485 | ICFParent = ICFParent->getFoldedIntoFunction(); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4486 | ELFSymTy ICFSymbol = FunctionSymbol; |
Maksim Panchenko | abda7dc | 2020-04-05 03:12:38 | [diff] [blame] | 4487 | SmallVector<char, 256> Buf; |
| 4488 | ICFSymbol.st_name = |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4489 | AddToStrTab(Twine(cantFail(FunctionSymbol.getName(StringSection))) |
| 4490 | .concat(".icf.0") |
| 4491 | .toStringRef(Buf)); |
Maksim Panchenko | abda7dc | 2020-04-05 03:12:38 | [diff] [blame] | 4492 | ICFSymbol.st_value = ICFParent->getOutputAddress(); |
| 4493 | ICFSymbol.st_size = ICFParent->getOutputSize(); |
Maksim Panchenko | 2d524fd | 2020-06-10 02:12:06 | [diff] [blame] | 4494 | ICFSymbol.st_shndx = ICFParent->getCodeSection()->getIndex(); |
Maksim Panchenko | abda7dc | 2020-04-05 03:12:38 | [diff] [blame] | 4495 | Symbols.emplace_back(ICFSymbol); |
| 4496 | } |
| 4497 | if (Function.isSplit() && Function.cold().getAddress()) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4498 | ELFSymTy NewColdSym = FunctionSymbol; |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4499 | SmallVector<char, 256> Buf; |
| 4500 | NewColdSym.st_name = |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4501 | AddToStrTab(Twine(cantFail(FunctionSymbol.getName(StringSection))) |
| 4502 | .concat(".cold.0") |
| 4503 | .toStringRef(Buf)); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4504 | NewColdSym.st_shndx = Function.getColdCodeSection()->getIndex(); |
| 4505 | NewColdSym.st_value = Function.cold().getAddress(); |
| 4506 | NewColdSym.st_size = Function.cold().getImageSize(); |
| 4507 | NewColdSym.setBindingAndType(ELF::STB_LOCAL, ELF::STT_FUNC); |
| 4508 | Symbols.emplace_back(NewColdSym); |
| 4509 | } |
| 4510 | if (Function.hasConstantIsland()) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4511 | uint64_t DataMark = Function.getOutputDataAddress(); |
| 4512 | uint64_t CISize = getConstantIslandSize(Function); |
| 4513 | uint64_t CodeMark = DataMark + CISize; |
| 4514 | ELFSymTy DataMarkSym = FunctionSymbol; |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4515 | DataMarkSym.st_name = AddToStrTab("$d"); |
| 4516 | DataMarkSym.st_value = DataMark; |
| 4517 | DataMarkSym.st_size = 0; |
| 4518 | DataMarkSym.setType(ELF::STT_NOTYPE); |
| 4519 | DataMarkSym.setBinding(ELF::STB_LOCAL); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4520 | ELFSymTy CodeMarkSym = DataMarkSym; |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4521 | CodeMarkSym.st_name = AddToStrTab("$x"); |
| 4522 | CodeMarkSym.st_value = CodeMark; |
| 4523 | Symbols.emplace_back(DataMarkSym); |
| 4524 | Symbols.emplace_back(CodeMarkSym); |
| 4525 | } |
| 4526 | if (Function.hasConstantIsland() && Function.isSplit()) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4527 | uint64_t DataMark = Function.getOutputColdDataAddress(); |
| 4528 | uint64_t CISize = getConstantIslandSize(Function); |
| 4529 | uint64_t CodeMark = DataMark + CISize; |
| 4530 | ELFSymTy DataMarkSym = FunctionSymbol; |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4531 | DataMarkSym.st_name = AddToStrTab("$d"); |
| 4532 | DataMarkSym.st_value = DataMark; |
| 4533 | DataMarkSym.st_size = 0; |
| 4534 | DataMarkSym.setType(ELF::STT_NOTYPE); |
| 4535 | DataMarkSym.setBinding(ELF::STB_LOCAL); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4536 | ELFSymTy CodeMarkSym = DataMarkSym; |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4537 | CodeMarkSym.st_name = AddToStrTab("$x"); |
| 4538 | CodeMarkSym.st_value = CodeMark; |
| 4539 | Symbols.emplace_back(DataMarkSym); |
| 4540 | Symbols.emplace_back(CodeMarkSym); |
| 4541 | } |
| 4542 | }; |
| 4543 | |
| 4544 | // For regular (non-dynamic) symbol table, exclude symbols referring |
| 4545 | // to non-allocatable sections. |
| 4546 | auto shouldStrip = [&](const ELFSymTy &Symbol) { |
| 4547 | if (Symbol.isAbsolute() || !Symbol.isDefined()) |
| 4548 | return false; |
| 4549 | |
| 4550 | // If we cannot link the symbol to a section, leave it as is. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4551 | Expected<const typename ELFT::Shdr *> Section = |
| 4552 | Obj.getSection(Symbol.st_shndx); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4553 | if (!Section) |
| 4554 | return false; |
| 4555 | |
| 4556 | // Remove the section symbol iif the corresponding section was stripped. |
| 4557 | if (Symbol.getType() == ELF::STT_SECTION) { |
Maksim Panchenko | 6b185cc | 2020-10-22 23:35:29 | [diff] [blame] | 4558 | if (!getNewSectionIndex(Symbol.st_shndx)) |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4559 | return true; |
| 4560 | return false; |
| 4561 | } |
| 4562 | |
| 4563 | // Symbols in non-allocatable sections are typically remnants of relocations |
| 4564 | // emitted under "-emit-relocs" linker option. Delete those as we delete |
| 4565 | // relocations against non-allocatable sections. |
| 4566 | if (!((*Section)->sh_flags & ELF::SHF_ALLOC)) |
| 4567 | return true; |
| 4568 | |
| 4569 | return false; |
| 4570 | }; |
| 4571 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4572 | for (const ELFSymTy &Symbol : cantFail(Obj.symbols(&SymTabSection))) { |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4573 | // For regular (non-dynamic) symbol table strip unneeded symbols. |
Maksim Panchenko | 6b185cc | 2020-10-22 23:35:29 | [diff] [blame] | 4574 | if (!IsDynSym && shouldStrip(Symbol)) |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4575 | continue; |
| 4576 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4577 | const BinaryFunction *Function = |
| 4578 | BC->getBinaryFunctionAtAddress(Symbol.st_value); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4579 | // Ignore false function references, e.g. when the section address matches |
| 4580 | // the address of the function. |
| 4581 | if (Function && Symbol.getType() == ELF::STT_SECTION) |
| 4582 | Function = nullptr; |
| 4583 | |
| 4584 | // For non-dynamic symtab, make sure the symbol section matches that of |
| 4585 | // the function. It can mismatch e.g. if the symbol is a section marker |
| 4586 | // in which case we treat the symbol separately from the function. |
| 4587 | // For dynamic symbol table, the section index could be wrong on the input, |
| 4588 | // and its value is ignored by the runtime if it's different from |
| 4589 | // SHN_UNDEF and SHN_ABS. |
Maksim Panchenko | 6b185cc | 2020-10-22 23:35:29 | [diff] [blame] | 4590 | if (!IsDynSym && Function && |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 4591 | Symbol.st_shndx != |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4592 | Function->getOriginSection()->getSectionRef().getIndex()) |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4593 | Function = nullptr; |
| 4594 | |
| 4595 | // Create a new symbol based on the existing symbol. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4596 | ELFSymTy NewSymbol = Symbol; |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4597 | |
Maksim Panchenko | 10245b5 | 2020-04-16 07:05:01 | [diff] [blame] | 4598 | if (Function) { |
Maksim Panchenko | 2d524fd | 2020-06-10 02:12:06 | [diff] [blame] | 4599 | // If the symbol matched a function that was not emitted, update the |
| 4600 | // corresponding section index but otherwise leave it unchanged. |
Maksim Panchenko | 10245b5 | 2020-04-16 07:05:01 | [diff] [blame] | 4601 | if (Function->isEmitted()) { |
| 4602 | NewSymbol.st_value = Function->getOutputAddress(); |
| 4603 | NewSymbol.st_size = Function->getOutputSize(); |
| 4604 | NewSymbol.st_shndx = Function->getCodeSection()->getIndex(); |
Maksim Panchenko | 2d524fd | 2020-06-10 02:12:06 | [diff] [blame] | 4605 | } else if (Symbol.st_shndx < ELF::SHN_LORESERVE) { |
Maksim Panchenko | 6b185cc | 2020-10-22 23:35:29 | [diff] [blame] | 4606 | NewSymbol.st_shndx = getNewSectionIndex(Symbol.st_shndx); |
Maksim Panchenko | 10245b5 | 2020-04-16 07:05:01 | [diff] [blame] | 4607 | } |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4608 | |
| 4609 | // Add new symbols to the symbol table if necessary. |
Maksim Panchenko | 6b185cc | 2020-10-22 23:35:29 | [diff] [blame] | 4610 | if (!IsDynSym) |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4611 | addExtraSymbols(*Function, NewSymbol); |
Maksim Panchenko | 10245b5 | 2020-04-16 07:05:01 | [diff] [blame] | 4612 | } else { |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4613 | // Check if the function symbol matches address inside a function, i.e. |
| 4614 | // it marks a secondary entry point. |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4615 | Function = |
| 4616 | (Symbol.getType() == ELF::STT_FUNC) |
| 4617 | ? BC->getBinaryFunctionContainingAddress(Symbol.st_value, |
| 4618 | /*CheckPastEnd=*/false, |
| 4619 | /*UseMaxSize=*/true) |
| 4620 | : nullptr; |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4621 | |
| 4622 | if (Function && Function->isEmitted()) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4623 | const uint64_t OutputAddress = |
| 4624 | Function->translateInputToOutputAddress(Symbol.st_value); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4625 | |
| 4626 | NewSymbol.st_value = OutputAddress; |
| 4627 | // Force secondary entry points to have zero size. |
| 4628 | NewSymbol.st_size = 0; |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4629 | NewSymbol.st_shndx = |
| 4630 | OutputAddress >= Function->cold().getAddress() && |
| 4631 | OutputAddress < Function->cold().getImageSize() |
| 4632 | ? Function->getColdCodeSection()->getIndex() |
| 4633 | : Function->getCodeSection()->getIndex(); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4634 | } else { |
| 4635 | // Check if the symbol belongs to moved data object and update it. |
| 4636 | BinaryData *BD = opts::ReorderData.empty() |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4637 | ? nullptr |
| 4638 | : BC->getBinaryDataAtAddress(Symbol.st_value); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4639 | if (BD && BD->isMoved() && !BD->isJumpTable()) { |
| 4640 | assert((!BD->getSize() || !Symbol.st_size || |
| 4641 | Symbol.st_size == BD->getSize()) && |
| 4642 | "sizes must match"); |
| 4643 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4644 | BinarySection &OutputSection = BD->getOutputSection(); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4645 | assert(OutputSection.getIndex()); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4646 | LLVM_DEBUG(dbgs() |
| 4647 | << "BOLT-DEBUG: moving " << BD->getName() << " from " |
| 4648 | << *BC->getSectionNameForAddress(Symbol.st_value) << " (" |
| 4649 | << Symbol.st_shndx << ") to " << OutputSection.getName() |
| 4650 | << " (" << OutputSection.getIndex() << ")\n"); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4651 | NewSymbol.st_shndx = OutputSection.getIndex(); |
| 4652 | NewSymbol.st_value = BD->getOutputAddress(); |
| 4653 | } else { |
| 4654 | // Otherwise just update the section for the symbol. |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 4655 | if (Symbol.st_shndx < ELF::SHN_LORESERVE) |
Maksim Panchenko | 6b185cc | 2020-10-22 23:35:29 | [diff] [blame] | 4656 | NewSymbol.st_shndx = getNewSectionIndex(Symbol.st_shndx); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4657 | } |
| 4658 | |
| 4659 | // Detect local syms in the text section that we didn't update |
| 4660 | // and that were preserved by the linker to support relocations against |
| 4661 | // .text. Remove them from the symtab. |
| 4662 | if (Symbol.getType() == ELF::STT_NOTYPE && |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4663 | Symbol.getBinding() == ELF::STB_LOCAL && Symbol.st_size == 0) { |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4664 | if (BC->getBinaryFunctionContainingAddress(Symbol.st_value, |
| 4665 | /*CheckPastEnd=*/false, |
Maksim Panchenko | a82cff0 | 2020-09-14 22:48:32 | [diff] [blame] | 4666 | /*UseMaxSize=*/true)) { |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4667 | // Can only delete the symbol if not patching. Such symbols should |
| 4668 | // not exist in the dynamic symbol table. |
Maksim Panchenko | 6b185cc | 2020-10-22 23:35:29 | [diff] [blame] | 4669 | assert(!IsDynSym && "cannot delete symbol"); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4670 | continue; |
| 4671 | } |
| 4672 | } |
| 4673 | } |
| 4674 | } |
| 4675 | |
| 4676 | // Handle special symbols based on their name. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4677 | Expected<StringRef> SymbolName = Symbol.getName(StringSection); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4678 | assert(SymbolName && "cannot get symbol name"); |
| 4679 | |
| 4680 | auto updateSymbolValue = [&](const StringRef Name, unsigned &IsUpdated) { |
| 4681 | NewSymbol.st_value = getNewValueForSymbol(Name); |
| 4682 | NewSymbol.st_shndx = ELF::SHN_ABS; |
| 4683 | outs() << "BOLT-INFO: setting " << Name << " to 0x" |
| 4684 | << Twine::utohexstr(NewSymbol.st_value) << '\n'; |
| 4685 | ++IsUpdated; |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4686 | }; |
| 4687 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4688 | if (opts::HotText && |
| 4689 | (*SymbolName == "__hot_start" || *SymbolName == "__hot_end")) |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4690 | updateSymbolValue(*SymbolName, NumHotTextSymsUpdated); |
| 4691 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4692 | if (opts::HotData && |
| 4693 | (*SymbolName == "__hot_data_start" || *SymbolName == "__hot_data_end")) |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4694 | updateSymbolValue(*SymbolName, NumHotDataSymsUpdated); |
| 4695 | |
Maksim Panchenko | db4642d | 2020-06-18 18:10:41 | [diff] [blame] | 4696 | if (*SymbolName == "_end") { |
| 4697 | unsigned Ignored; |
| 4698 | updateSymbolValue(*SymbolName, Ignored); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4699 | } |
| 4700 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 4701 | if (IsDynSym) |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4702 | Write((&Symbol - cantFail(Obj.symbols(&SymTabSection)).begin()) * |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4703 | sizeof(ELFSymTy), |
| 4704 | NewSymbol); |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 4705 | else |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4706 | Symbols.emplace_back(NewSymbol); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4707 | } |
| 4708 | |
Maksim Panchenko | 6b185cc | 2020-10-22 23:35:29 | [diff] [blame] | 4709 | if (IsDynSym) { |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4710 | assert(Symbols.empty()); |
| 4711 | return; |
| 4712 | } |
| 4713 | |
| 4714 | // Add symbols of injected functions |
| 4715 | for (BinaryFunction *Function : BC->getInjectedBinaryFunctions()) { |
| 4716 | ELFSymTy NewSymbol; |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 4717 | BinarySection *OriginSection = Function->getOriginSection(); |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4718 | NewSymbol.st_shndx = |
| 4719 | OriginSection |
| 4720 | ? getNewSectionIndex(OriginSection->getSectionRef().getIndex()) |
| 4721 | : Function->getCodeSection()->getIndex(); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4722 | NewSymbol.st_value = Function->getOutputAddress(); |
| 4723 | NewSymbol.st_name = AddToStrTab(Function->getOneName()); |
| 4724 | NewSymbol.st_size = Function->getOutputSize(); |
| 4725 | NewSymbol.st_other = 0; |
| 4726 | NewSymbol.setBindingAndType(ELF::STB_LOCAL, ELF::STT_FUNC); |
| 4727 | Symbols.emplace_back(NewSymbol); |
| 4728 | |
| 4729 | if (Function->isSplit()) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4730 | ELFSymTy NewColdSym = NewSymbol; |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4731 | NewColdSym.setType(ELF::STT_NOTYPE); |
| 4732 | SmallVector<char, 256> Buf; |
| 4733 | NewColdSym.st_name = AddToStrTab( |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4734 | Twine(Function->getPrintName()).concat(".cold.0").toStringRef(Buf)); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4735 | NewColdSym.st_value = Function->cold().getAddress(); |
| 4736 | NewColdSym.st_size = Function->cold().getImageSize(); |
| 4737 | Symbols.emplace_back(NewColdSym); |
| 4738 | } |
| 4739 | } |
| 4740 | |
| 4741 | assert((!NumHotTextSymsUpdated || NumHotTextSymsUpdated == 2) && |
| 4742 | "either none or both __hot_start/__hot_end symbols were expected"); |
| 4743 | assert((!NumHotDataSymsUpdated || NumHotDataSymsUpdated == 2) && |
| 4744 | "either none or both __hot_data_start/__hot_data_end symbols were " |
| 4745 | "expected"); |
| 4746 | |
| 4747 | auto addSymbol = [&](const std::string &Name) { |
| 4748 | ELFSymTy Symbol; |
| 4749 | Symbol.st_value = getNewValueForSymbol(Name); |
| 4750 | Symbol.st_shndx = ELF::SHN_ABS; |
| 4751 | Symbol.st_name = AddToStrTab(Name); |
| 4752 | Symbol.st_size = 0; |
| 4753 | Symbol.st_other = 0; |
| 4754 | Symbol.setBindingAndType(ELF::STB_WEAK, ELF::STT_NOTYPE); |
| 4755 | |
| 4756 | outs() << "BOLT-INFO: setting " << Name << " to 0x" |
| 4757 | << Twine::utohexstr(Symbol.st_value) << '\n'; |
| 4758 | |
| 4759 | Symbols.emplace_back(Symbol); |
| 4760 | }; |
| 4761 | |
| 4762 | if (opts::HotText && !NumHotTextSymsUpdated) { |
| 4763 | addSymbol("__hot_start"); |
| 4764 | addSymbol("__hot_end"); |
| 4765 | } |
| 4766 | |
| 4767 | if (opts::HotData && !NumHotDataSymsUpdated) { |
| 4768 | addSymbol("__hot_data_start"); |
| 4769 | addSymbol("__hot_data_end"); |
| 4770 | } |
| 4771 | |
| 4772 | // Put local symbols at the beginning. |
Amir Ayupov | d2c8769 | 2022-06-24 05:15:47 | [diff] [blame^] | 4773 | llvm::stable_sort(Symbols, [](const ELFSymTy &A, const ELFSymTy &B) { |
| 4774 | if (A.getBinding() == ELF::STB_LOCAL && B.getBinding() != ELF::STB_LOCAL) |
| 4775 | return true; |
| 4776 | return false; |
| 4777 | }); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4778 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 4779 | for (const ELFSymTy &Symbol : Symbols) |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4780 | Write(0, Symbol); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4781 | } |
| 4782 | |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 4783 | template <typename ELFT> |
| 4784 | void RewriteInstance::patchELFSymTabs(ELFObjectFile<ELFT> *File) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4785 | const ELFFile<ELFT> &Obj = File->getELFFile(); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4786 | using ELFShdrTy = typename ELFObjectFile<ELFT>::Elf_Shdr; |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 4787 | using ELFSymTy = typename ELFObjectFile<ELFT>::Elf_Sym; |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4788 | |
| 4789 | // Compute a preview of how section indices will change after rewriting, so |
| 4790 | // we can properly update the symbol table based on new section indices. |
| 4791 | std::vector<uint32_t> NewSectionIndex; |
| 4792 | getOutputSections(File, NewSectionIndex); |
| 4793 | |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4794 | // Set pointer at the end of the output file, so we can pwrite old symbol |
| 4795 | // tables if we need to. |
| 4796 | uint64_t NextAvailableOffset = getFileOffsetForAddress(NextAvailableAddress); |
| 4797 | assert(NextAvailableOffset >= FirstNonAllocatableOffset && |
| 4798 | "next available offset calculation failure"); |
| 4799 | Out->os().seek(NextAvailableOffset); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 4800 | |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 4801 | // Update dynamic symbol table. |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4802 | const ELFShdrTy *DynSymSection = nullptr; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4803 | for (const ELFShdrTy &Section : cantFail(Obj.sections())) { |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 4804 | if (Section.sh_type == ELF::SHT_DYNSYM) { |
| 4805 | DynSymSection = &Section; |
| 4806 | break; |
| 4807 | } |
| 4808 | } |
Maksim Panchenko | 250ca40 | 2020-06-26 23:52:07 | [diff] [blame] | 4809 | assert((DynSymSection || BC->IsStaticExecutable) && |
| 4810 | "dynamic symbol table expected"); |
| 4811 | if (DynSymSection) { |
| 4812 | updateELFSymbolTable( |
| 4813 | File, |
Maksim Panchenko | 6b185cc | 2020-10-22 23:35:29 | [diff] [blame] | 4814 | /*IsDynSym=*/true, |
Maksim Panchenko | 250ca40 | 2020-06-26 23:52:07 | [diff] [blame] | 4815 | *DynSymSection, |
| 4816 | NewSectionIndex, |
| 4817 | [&](size_t Offset, const ELFSymTy &Sym) { |
| 4818 | Out->os().pwrite(reinterpret_cast<const char *>(&Sym), |
| 4819 | sizeof(ELFSymTy), |
| 4820 | DynSymSection->sh_offset + Offset); |
| 4821 | }, |
| 4822 | [](StringRef) -> size_t { return 0; }); |
| 4823 | } |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 4824 | |
Vladislav Khmelevsky | 95ee129 | 2021-10-16 14:02:45 | [diff] [blame] | 4825 | if (opts::RemoveSymtab) |
| 4826 | return; |
| 4827 | |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4828 | // (re)create regular symbol table. |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4829 | const ELFShdrTy *SymTabSection = nullptr; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4830 | for (const ELFShdrTy &Section : cantFail(Obj.sections())) { |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 4831 | if (Section.sh_type == ELF::SHT_SYMTAB) { |
| 4832 | SymTabSection = &Section; |
| 4833 | break; |
| 4834 | } |
| 4835 | } |
| 4836 | if (!SymTabSection) { |
| 4837 | errs() << "BOLT-WARNING: no symbol table found\n"; |
| 4838 | return; |
| 4839 | } |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4840 | |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4841 | const ELFShdrTy *StrTabSection = |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4842 | cantFail(Obj.getSection(SymTabSection->sh_link)); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4843 | std::string NewContents; |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4844 | std::string NewStrTab = std::string( |
| 4845 | File->getData().substr(StrTabSection->sh_offset, StrTabSection->sh_size)); |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4846 | StringRef SecName = cantFail(Obj.getSectionName(*SymTabSection)); |
| 4847 | StringRef StrSecName = cantFail(Obj.getSectionName(*StrTabSection)); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4848 | |
Maksim Panchenko | 30fd960 | 2018-10-23 01:48:12 | [diff] [blame] | 4849 | NumLocalSymbols = 0; |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4850 | updateELFSymbolTable( |
| 4851 | File, |
Maksim Panchenko | 6b185cc | 2020-10-22 23:35:29 | [diff] [blame] | 4852 | /*IsDynSym=*/false, |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4853 | *SymTabSection, |
| 4854 | NewSectionIndex, |
| 4855 | [&](size_t Offset, const ELFSymTy &Sym) { |
| 4856 | if (Sym.getBinding() == ELF::STB_LOCAL) |
| 4857 | ++NumLocalSymbols; |
| 4858 | NewContents.append(reinterpret_cast<const char *>(&Sym), |
| 4859 | sizeof(ELFSymTy)); |
| 4860 | }, |
| 4861 | [&](StringRef Str) { |
| 4862 | size_t Idx = NewStrTab.size(); |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 4863 | NewStrTab.append(NameResolver::restore(Str).str()); |
Maksim Panchenko | bbbf679 | 2020-02-27 04:43:18 | [diff] [blame] | 4864 | NewStrTab.append(1, '\0'); |
| 4865 | return Idx; |
| 4866 | }); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 4867 | |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 4868 | BC->registerOrUpdateNoteSection(SecName, |
| 4869 | copyByteArray(NewContents), |
| 4870 | NewContents.size(), |
| 4871 | /*Alignment=*/1, |
| 4872 | /*IsReadOnly=*/true, |
| 4873 | ELF::SHT_SYMTAB); |
| 4874 | |
| 4875 | BC->registerOrUpdateNoteSection(StrSecName, |
| 4876 | copyByteArray(NewStrTab), |
| 4877 | NewStrTab.size(), |
| 4878 | /*Alignment=*/1, |
| 4879 | /*IsReadOnly=*/true, |
| 4880 | ELF::SHT_STRTAB); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 4881 | } |
| 4882 | |
| 4883 | template <typename ELFT> |
Maksim Panchenko | 88bb145 | 2018-08-16 23:53:14 | [diff] [blame] | 4884 | void |
| 4885 | RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4886 | using Elf_Rela = typename ELFT::Rela; |
| 4887 | raw_fd_ostream &OS = Out->os(); |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 4888 | const ELFFile<ELFT> &EF = File->getELFFile(); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 4889 | |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 4890 | uint64_t RelDynOffset = 0, RelDynEndOffset = 0; |
| 4891 | uint64_t RelPltOffset = 0, RelPltEndOffset = 0; |
| 4892 | |
| 4893 | auto setSectionFileOffsets = [&](uint64_t Address, uint64_t &Start, |
| 4894 | uint64_t &End) { |
| 4895 | ErrorOr<BinarySection &> Section = BC->getSectionForAddress(Address); |
| 4896 | Start = Section->getInputFileOffset(); |
| 4897 | End = Start + Section->getSize(); |
| 4898 | }; |
| 4899 | |
| 4900 | if (!DynamicRelocationsAddress && !PLTRelocationsAddress) |
| 4901 | return; |
| 4902 | |
| 4903 | if (DynamicRelocationsAddress) |
| 4904 | setSectionFileOffsets(*DynamicRelocationsAddress, RelDynOffset, |
| 4905 | RelDynEndOffset); |
| 4906 | |
| 4907 | if (PLTRelocationsAddress) |
| 4908 | setSectionFileOffsets(*PLTRelocationsAddress, RelPltOffset, |
| 4909 | RelPltEndOffset); |
| 4910 | |
| 4911 | DynamicRelativeRelocationsCount = 0; |
| 4912 | |
| 4913 | auto writeRela = [&OS](const Elf_Rela *RelA, uint64_t &Offset) { |
| 4914 | OS.pwrite(reinterpret_cast<const char *>(RelA), sizeof(*RelA), Offset); |
| 4915 | Offset += sizeof(*RelA); |
| 4916 | }; |
| 4917 | |
| 4918 | auto writeRelocations = [&](bool PatchRelative) { |
| 4919 | for (BinarySection &Section : BC->allocatableSections()) { |
| 4920 | for (const Relocation &Rel : Section.dynamicRelocations()) { |
| 4921 | const bool IsRelative = Rel.isRelative(); |
| 4922 | if (PatchRelative != IsRelative) |
| 4923 | continue; |
| 4924 | |
| 4925 | if (IsRelative) |
| 4926 | ++DynamicRelativeRelocationsCount; |
| 4927 | |
| 4928 | Elf_Rela NewRelA; |
| 4929 | uint64_t SectionAddress = Section.getOutputAddress(); |
| 4930 | SectionAddress = |
| 4931 | SectionAddress == 0 ? Section.getAddress() : SectionAddress; |
| 4932 | MCSymbol *Symbol = Rel.Symbol; |
| 4933 | uint32_t SymbolIdx = 0; |
| 4934 | uint64_t Addend = Rel.Addend; |
| 4935 | |
| 4936 | if (Rel.Symbol) { |
| 4937 | SymbolIdx = getOutputDynamicSymbolIndex(Symbol); |
| 4938 | } else { |
| 4939 | // Usually this case is used for R_*_(I)RELATIVE relocations |
| 4940 | const uint64_t Address = getNewFunctionOrDataAddress(Addend); |
| 4941 | if (Address) |
| 4942 | Addend = Address; |
| 4943 | } |
| 4944 | |
| 4945 | NewRelA.setSymbolAndType(SymbolIdx, Rel.Type, EF.isMips64EL()); |
| 4946 | NewRelA.r_offset = SectionAddress + Rel.Offset; |
| 4947 | NewRelA.r_addend = Addend; |
| 4948 | |
| 4949 | const bool IsJmpRel = |
| 4950 | !!(IsJmpRelocation.find(Rel.Type) != IsJmpRelocation.end()); |
| 4951 | uint64_t &Offset = IsJmpRel ? RelPltOffset : RelDynOffset; |
| 4952 | const uint64_t &EndOffset = |
| 4953 | IsJmpRel ? RelPltEndOffset : RelDynEndOffset; |
| 4954 | if (!Offset || !EndOffset) { |
| 4955 | errs() << "BOLT-ERROR: Invalid offsets for dynamic relocation\n"; |
| 4956 | exit(1); |
| 4957 | } |
| 4958 | |
| 4959 | if (Offset + sizeof(NewRelA) > EndOffset) { |
| 4960 | errs() << "BOLT-ERROR: Offset overflow for dynamic relocation\n"; |
| 4961 | exit(1); |
| 4962 | } |
| 4963 | |
| 4964 | writeRela(&NewRelA, Offset); |
| 4965 | } |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 4966 | } |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 4967 | }; |
| 4968 | |
| 4969 | // The dynamic linker expects R_*_RELATIVE relocations to be emitted first |
| 4970 | writeRelocations(/* PatchRelative */ true); |
| 4971 | writeRelocations(/* PatchRelative */ false); |
| 4972 | |
| 4973 | auto fillNone = [&](uint64_t &Offset, uint64_t EndOffset) { |
| 4974 | if (!Offset) |
| 4975 | return; |
| 4976 | |
| 4977 | typename ELFObjectFile<ELFT>::Elf_Rela RelA; |
| 4978 | RelA.setSymbolAndType(0, Relocation::getNone(), EF.isMips64EL()); |
| 4979 | RelA.r_offset = 0; |
| 4980 | RelA.r_addend = 0; |
| 4981 | while (Offset < EndOffset) |
| 4982 | writeRela(&RelA, Offset); |
| 4983 | |
| 4984 | assert(Offset == EndOffset && "Unexpected section overflow"); |
| 4985 | }; |
| 4986 | |
| 4987 | // Fill the rest of the sections with R_*_NONE relocations |
| 4988 | fillNone(RelDynOffset, RelDynEndOffset); |
| 4989 | fillNone(RelPltOffset, RelPltEndOffset); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 4990 | } |
| 4991 | |
| 4992 | template <typename ELFT> |
| 4993 | void RewriteInstance::patchELFGOT(ELFObjectFile<ELFT> *File) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4994 | raw_fd_ostream &OS = Out->os(); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 4995 | |
| 4996 | SectionRef GOTSection; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 4997 | for (const SectionRef &Section : File->sections()) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 4998 | StringRef SectionName = cantFail(Section.getName()); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 4999 | if (SectionName == ".got") { |
| 5000 | GOTSection = Section; |
| 5001 | break; |
| 5002 | } |
| 5003 | } |
| 5004 | if (!GOTSection.getObject()) { |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 5005 | if (!BC->IsStaticExecutable) |
| 5006 | errs() << "BOLT-INFO: no .got section found\n"; |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5007 | return; |
| 5008 | } |
| 5009 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 5010 | StringRef GOTContents = cantFail(GOTSection.getContents()); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5011 | for (const uint64_t *GOTEntry = |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5012 | reinterpret_cast<const uint64_t *>(GOTContents.data()); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5013 | GOTEntry < reinterpret_cast<const uint64_t *>(GOTContents.data() + |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5014 | GOTContents.size()); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5015 | ++GOTEntry) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5016 | if (uint64_t NewAddress = getNewFunctionAddress(*GOTEntry)) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 5017 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: patching GOT entry 0x" |
| 5018 | << Twine::utohexstr(*GOTEntry) << " with 0x" |
| 5019 | << Twine::utohexstr(NewAddress) << '\n'); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5020 | OS.pwrite(reinterpret_cast<const char *>(&NewAddress), sizeof(NewAddress), |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5021 | reinterpret_cast<const char *>(GOTEntry) - |
| 5022 | File->getData().data()); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5023 | } |
| 5024 | } |
| 5025 | } |
| 5026 | |
| 5027 | template <typename ELFT> |
| 5028 | void RewriteInstance::patchELFDynamic(ELFObjectFile<ELFT> *File) { |
Maksim Panchenko | 250ca40 | 2020-06-26 23:52:07 | [diff] [blame] | 5029 | if (BC->IsStaticExecutable) |
| 5030 | return; |
| 5031 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5032 | const ELFFile<ELFT> &Obj = File->getELFFile(); |
| 5033 | raw_fd_ostream &OS = Out->os(); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5034 | |
| 5035 | using Elf_Phdr = typename ELFFile<ELFT>::Elf_Phdr; |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5036 | using Elf_Dyn = typename ELFFile<ELFT>::Elf_Dyn; |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5037 | |
| 5038 | // Locate DYNAMIC by looking through program headers. |
| 5039 | uint64_t DynamicOffset = 0; |
| 5040 | const Elf_Phdr *DynamicPhdr = 0; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5041 | for (const Elf_Phdr &Phdr : cantFail(Obj.program_headers())) { |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5042 | if (Phdr.p_type == ELF::PT_DYNAMIC) { |
| 5043 | DynamicOffset = Phdr.p_offset; |
| 5044 | DynamicPhdr = &Phdr; |
| 5045 | assert(Phdr.p_memsz == Phdr.p_filesz && "dynamic sizes should match"); |
| 5046 | break; |
| 5047 | } |
| 5048 | } |
| 5049 | assert(DynamicPhdr && "missing dynamic in ELF binary"); |
| 5050 | |
Maksim Panchenko | 49d1f56 | 2017-08-04 18:21:05 | [diff] [blame] | 5051 | bool ZNowSet = false; |
| 5052 | |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5053 | // Go through all dynamic entries and patch functions addresses with |
| 5054 | // new ones. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5055 | typename ELFT::DynRange DynamicEntries = |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 5056 | cantFail(Obj.dynamicEntries(), "error accessing dynamic table"); |
| 5057 | auto DTB = DynamicEntries.begin(); |
| 5058 | for (const Elf_Dyn &Dyn : DynamicEntries) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5059 | Elf_Dyn NewDE = Dyn; |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5060 | bool ShouldPatch = true; |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 5061 | switch (Dyn.d_tag) { |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5062 | default: |
| 5063 | ShouldPatch = false; |
| 5064 | break; |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 5065 | case ELF::DT_RELACOUNT: |
| 5066 | NewDE.d_un.d_val = DynamicRelativeRelocationsCount; |
| 5067 | break; |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5068 | case ELF::DT_INIT: |
Maksim Panchenko | df288e8 | 2021-12-28 21:46:45 | [diff] [blame] | 5069 | case ELF::DT_FINI: { |
Maksim Panchenko | b6f7c68 | 2017-12-10 05:40:39 | [diff] [blame] | 5070 | if (BC->HasRelocations) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5071 | if (uint64_t NewAddress = getNewFunctionAddress(Dyn.getPtr())) { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 5072 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: patching dynamic entry of type " |
| 5073 | << Dyn.getTag() << '\n'); |
Maksim Panchenko | 49d1f56 | 2017-08-04 18:21:05 | [diff] [blame] | 5074 | NewDE.d_un.d_ptr = NewAddress; |
| 5075 | } |
| 5076 | } |
Maksim Panchenko | df288e8 | 2021-12-28 21:46:45 | [diff] [blame] | 5077 | RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary(); |
| 5078 | if (RtLibrary && Dyn.getTag() == ELF::DT_FINI) { |
| 5079 | if (uint64_t Addr = RtLibrary->getRuntimeFiniAddress()) |
| 5080 | NewDE.d_un.d_ptr = Addr; |
Xun Li | 00892a5fd | 2020-05-21 21:28:47 | [diff] [blame] | 5081 | } |
Maksim Panchenko | df288e8 | 2021-12-28 21:46:45 | [diff] [blame] | 5082 | if (RtLibrary && Dyn.getTag() == ELF::DT_INIT && !BC->HasInterpHeader) { |
| 5083 | if (auto Addr = RtLibrary->getRuntimeStartAddress()) { |
| 5084 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Set DT_INIT to 0x" |
| 5085 | << Twine::utohexstr(Addr) << '\n'); |
| 5086 | NewDE.d_un.d_ptr = Addr; |
Vasily Leonenko | ad79d51 | 2021-06-18 20:08:35 | [diff] [blame] | 5087 | } |
| 5088 | } |
Maksim Panchenko | 49d1f56 | 2017-08-04 18:21:05 | [diff] [blame] | 5089 | break; |
Maksim Panchenko | df288e8 | 2021-12-28 21:46:45 | [diff] [blame] | 5090 | } |
Maksim Panchenko | 49d1f56 | 2017-08-04 18:21:05 | [diff] [blame] | 5091 | case ELF::DT_FLAGS: |
| 5092 | if (BC->RequiresZNow) { |
| 5093 | NewDE.d_un.d_val |= ELF::DF_BIND_NOW; |
| 5094 | ZNowSet = true; |
| 5095 | } |
| 5096 | break; |
| 5097 | case ELF::DT_FLAGS_1: |
| 5098 | if (BC->RequiresZNow) { |
| 5099 | NewDE.d_un.d_val |= ELF::DF_1_NOW; |
| 5100 | ZNowSet = true; |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5101 | } |
| 5102 | break; |
| 5103 | } |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 5104 | if (ShouldPatch) |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5105 | OS.pwrite(reinterpret_cast<const char *>(&NewDE), sizeof(NewDE), |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 5106 | DynamicOffset + (&Dyn - DTB) * sizeof(Dyn)); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5107 | } |
Maksim Panchenko | 49d1f56 | 2017-08-04 18:21:05 | [diff] [blame] | 5108 | |
| 5109 | if (BC->RequiresZNow && !ZNowSet) { |
| 5110 | errs() << "BOLT-ERROR: output binary requires immediate relocation " |
| 5111 | "processing which depends on DT_FLAGS or DT_FLAGS_1 presence in " |
| 5112 | ".dynamic. Please re-link the binary with -znow.\n"; |
| 5113 | exit(1); |
| 5114 | } |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5115 | } |
| 5116 | |
Rafael Auler | 16a497c | 2019-12-14 01:27:03 | [diff] [blame] | 5117 | template <typename ELFT> |
Amir Ayupov | 1e016c3 | 2022-03-08 17:17:41 | [diff] [blame] | 5118 | Error RewriteInstance::readELFDynamic(ELFObjectFile<ELFT> *File) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5119 | const ELFFile<ELFT> &Obj = File->getELFFile(); |
Rafael Auler | 16a497c | 2019-12-14 01:27:03 | [diff] [blame] | 5120 | |
| 5121 | using Elf_Phdr = typename ELFFile<ELFT>::Elf_Phdr; |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5122 | using Elf_Dyn = typename ELFFile<ELFT>::Elf_Dyn; |
Rafael Auler | 16a497c | 2019-12-14 01:27:03 | [diff] [blame] | 5123 | |
Rafael Auler | 16a497c | 2019-12-14 01:27:03 | [diff] [blame] | 5124 | // Locate DYNAMIC by looking through program headers. |
| 5125 | const Elf_Phdr *DynamicPhdr = 0; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5126 | for (const Elf_Phdr &Phdr : cantFail(Obj.program_headers())) { |
Rafael Auler | 16a497c | 2019-12-14 01:27:03 | [diff] [blame] | 5127 | if (Phdr.p_type == ELF::PT_DYNAMIC) { |
| 5128 | DynamicPhdr = &Phdr; |
Rafael Auler | 16a497c | 2019-12-14 01:27:03 | [diff] [blame] | 5129 | break; |
| 5130 | } |
| 5131 | } |
Rafael Auler | 16a497c | 2019-12-14 01:27:03 | [diff] [blame] | 5132 | |
Maksim Panchenko | 250ca40 | 2020-06-26 23:52:07 | [diff] [blame] | 5133 | if (!DynamicPhdr) { |
| 5134 | outs() << "BOLT-INFO: static input executable detected\n"; |
Vasily Leonenko | 9b39a82 | 2021-06-20 17:59:38 | [diff] [blame] | 5135 | // TODO: static PIE executable might have dynamic header |
Maksim Panchenko | 250ca40 | 2020-06-26 23:52:07 | [diff] [blame] | 5136 | BC->IsStaticExecutable = true; |
Amir Ayupov | 1e016c3 | 2022-03-08 17:17:41 | [diff] [blame] | 5137 | return Error::success(); |
Maksim Panchenko | 74a2777 | 2020-03-09 02:04:39 | [diff] [blame] | 5138 | } |
| 5139 | |
Amir Ayupov | 1e016c3 | 2022-03-08 17:17:41 | [diff] [blame] | 5140 | if (DynamicPhdr->p_memsz != DynamicPhdr->p_filesz) |
| 5141 | return createStringError(errc::executable_format_error, |
| 5142 | "dynamic section sizes should match"); |
Maksim Panchenko | 74a2777 | 2020-03-09 02:04:39 | [diff] [blame] | 5143 | |
| 5144 | // Go through all dynamic entries to locate entries of interest. |
Amir Ayupov | d16bbc5 | 2022-03-10 04:24:20 | [diff] [blame] | 5145 | auto DynamicEntriesOrErr = Obj.dynamicEntries(); |
| 5146 | if (!DynamicEntriesOrErr) |
| 5147 | return DynamicEntriesOrErr.takeError(); |
| 5148 | typename ELFT::DynRange DynamicEntries = DynamicEntriesOrErr.get(); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 5149 | |
| 5150 | for (const Elf_Dyn &Dyn : DynamicEntries) { |
| 5151 | switch (Dyn.d_tag) { |
Vasily Leonenko | ad79d51 | 2021-06-18 20:08:35 | [diff] [blame] | 5152 | case ELF::DT_INIT: |
| 5153 | if (!BC->HasInterpHeader) { |
| 5154 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Set start function address\n"); |
| 5155 | BC->StartFunctionAddress = Dyn.getPtr(); |
| 5156 | } |
| 5157 | break; |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 5158 | case ELF::DT_FINI: |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 5159 | BC->FiniFunctionAddress = Dyn.getPtr(); |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 5160 | break; |
| 5161 | case ELF::DT_RELA: |
Maksim Panchenko | 1de0746 | 2021-06-30 21:38:50 | [diff] [blame] | 5162 | DynamicRelocationsAddress = Dyn.getPtr(); |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 5163 | break; |
| 5164 | case ELF::DT_RELASZ: |
Maksim Panchenko | 1de0746 | 2021-06-30 21:38:50 | [diff] [blame] | 5165 | DynamicRelocationsSize = Dyn.getVal(); |
| 5166 | break; |
| 5167 | case ELF::DT_JMPREL: |
| 5168 | PLTRelocationsAddress = Dyn.getPtr(); |
| 5169 | break; |
| 5170 | case ELF::DT_PLTRELSZ: |
| 5171 | PLTRelocationsSize = Dyn.getVal(); |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 5172 | break; |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 5173 | case ELF::DT_RELACOUNT: |
| 5174 | DynamicRelativeRelocationsCount = Dyn.getVal(); |
| 5175 | break; |
Maksim Panchenko | 4aaa889 | 2020-06-23 19:22:58 | [diff] [blame] | 5176 | } |
Rafael Auler | 16a497c | 2019-12-14 01:27:03 | [diff] [blame] | 5177 | } |
Maksim Panchenko | 1de0746 | 2021-06-30 21:38:50 | [diff] [blame] | 5178 | |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 5179 | if (!DynamicRelocationsAddress || !DynamicRelocationsSize) { |
| 5180 | DynamicRelocationsAddress.reset(); |
Maksim Panchenko | 1de0746 | 2021-06-30 21:38:50 | [diff] [blame] | 5181 | DynamicRelocationsSize = 0; |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 5182 | } |
Maksim Panchenko | 1de0746 | 2021-06-30 21:38:50 | [diff] [blame] | 5183 | |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 5184 | if (!PLTRelocationsAddress || !PLTRelocationsSize) { |
| 5185 | PLTRelocationsAddress.reset(); |
Maksim Panchenko | 1de0746 | 2021-06-30 21:38:50 | [diff] [blame] | 5186 | PLTRelocationsSize = 0; |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 5187 | } |
Amir Ayupov | 1e016c3 | 2022-03-08 17:17:41 | [diff] [blame] | 5188 | return Error::success(); |
Rafael Auler | 16a497c | 2019-12-14 01:27:03 | [diff] [blame] | 5189 | } |
| 5190 | |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5191 | uint64_t RewriteInstance::getNewFunctionAddress(uint64_t OldAddress) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5192 | const BinaryFunction *Function = BC->getBinaryFunctionAtAddress(OldAddress); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5193 | if (!Function) |
| 5194 | return 0; |
Maksim Panchenko | a82cff0 | 2020-09-14 22:48:32 | [diff] [blame] | 5195 | |
Maksim Panchenko | 3f42fdf | 2017-05-09 05:51:36 | [diff] [blame] | 5196 | return Function->getOutputAddress(); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 5197 | } |
| 5198 | |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 5199 | uint64_t RewriteInstance::getNewFunctionOrDataAddress(uint64_t OldAddress) { |
| 5200 | if (uint64_t Function = getNewFunctionAddress(OldAddress)) |
| 5201 | return Function; |
| 5202 | |
| 5203 | const BinaryData *BD = BC->getBinaryDataAtAddress(OldAddress); |
| 5204 | if (BD && BD->isMoved()) |
| 5205 | return BD->getOutputAddress(); |
| 5206 | |
| 5207 | return 0; |
| 5208 | } |
| 5209 | |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 5210 | void RewriteInstance::rewriteFile() { |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 5211 | std::error_code EC; |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 5212 | Out = std::make_unique<ToolOutputFile>(opts::OutputFilename, EC, |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5213 | sys::fs::OF_None); |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 5214 | check_error(EC, "cannot create output executable file"); |
| 5215 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5216 | raw_fd_ostream &OS = Out->os(); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5217 | |
Maksim Panchenko | 8729171 | 2020-05-08 06:00:29 | [diff] [blame] | 5218 | // Copy allocatable part of the input. |
| 5219 | OS << InputFile->getData().substr(0, FirstNonAllocatableOffset); |
| 5220 | |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 5221 | // We obtain an asm-specific writer so that we can emit nops in an |
| 5222 | // architecture-specific way at the end of the function. |
Amir Ayupov | 12e9fec | 2021-04-01 18:43:00 | [diff] [blame] | 5223 | std::unique_ptr<MCAsmBackend> MAB( |
| 5224 | BC->TheTarget->createMCAsmBackend(*BC->STI, *BC->MRI, MCTargetOptions())); |
| 5225 | auto Streamer = BC->createStreamer(OS); |
Maksim Panchenko | 7f7d4af | 2016-02-13 03:01:53 | [diff] [blame] | 5226 | // Make sure output stream has enough reserved space, otherwise |
| 5227 | // pwrite() will fail. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5228 | uint64_t Offset = OS.seek(getFileOffsetForAddress(NextAvailableAddress)); |
Maksim Panchenko | 2428567 | 2017-05-25 17:29:38 | [diff] [blame] | 5229 | (void)Offset; |
Maksim Panchenko | 6ff1795 | 2017-01-17 23:49:59 | [diff] [blame] | 5230 | assert(Offset == getFileOffsetForAddress(NextAvailableAddress) && |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 5231 | "error resizing output file"); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 5232 | |
Rafael Auler | 7b779f8 | 2021-09-10 23:19:50 | [diff] [blame] | 5233 | // Overwrite functions with fixed output address. This is mostly used by |
| 5234 | // non-relocation mode, with one exception: injected functions are covered |
| 5235 | // here in both modes. |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5236 | uint64_t CountOverwrittenFunctions = 0; |
| 5237 | uint64_t OverwrittenScore = 0; |
| 5238 | for (BinaryFunction *Function : BC->getAllBinaryFunctions()) { |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5239 | if (Function->getImageAddress() == 0 || Function->getImageSize() == 0) |
| 5240 | continue; |
Gabriel Poesia | 784f6a8 | 2016-04-06 02:35:45 | [diff] [blame] | 5241 | |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5242 | if (Function->getImageSize() > Function->getMaxSize()) { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 5243 | if (opts::Verbosity >= 1) |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5244 | errs() << "BOLT-WARNING: new function size (0x" |
| 5245 | << Twine::utohexstr(Function->getImageSize()) |
| 5246 | << ") is larger than maximum allowed size (0x" |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5247 | << Twine::utohexstr(Function->getMaxSize()) << ") for function " |
| 5248 | << *Function << '\n'; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 5249 | |
Rafael Auler | 7b779f8 | 2021-09-10 23:19:50 | [diff] [blame] | 5250 | // Remove jump table sections that this function owns in non-reloc mode |
Maksim Panchenko | ba1f503 | 2021-09-29 18:40:16 | [diff] [blame] | 5251 | // because we don't want to write them anymore. |
Rafael Auler | 7b779f8 | 2021-09-10 23:19:50 | [diff] [blame] | 5252 | if (!BC->HasRelocations && opts::JumpTables == JTS_BASIC) { |
| 5253 | for (auto &JTI : Function->JumpTables) { |
| 5254 | JumpTable *JT = JTI.second; |
| 5255 | BinarySection &Section = JT->getOutputSection(); |
| 5256 | BC->deregisterSection(Section); |
| 5257 | } |
| 5258 | } |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5259 | continue; |
| 5260 | } |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 5261 | |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5262 | if (Function->isSplit() && (Function->cold().getImageAddress() == 0 || |
| 5263 | Function->cold().getImageSize() == 0)) |
| 5264 | continue; |
Maksim Panchenko | c4c518e | 2016-09-08 21:52:26 | [diff] [blame] | 5265 | |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5266 | OverwrittenScore += Function->getFunctionScore(); |
| 5267 | // Overwrite function in the output file. |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 5268 | if (opts::Verbosity >= 2) |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5269 | outs() << "BOLT: rewriting function \"" << *Function << "\"\n"; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 5270 | |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5271 | OS.pwrite(reinterpret_cast<char *>(Function->getImageAddress()), |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5272 | Function->getImageSize(), Function->getFileOffset()); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 5273 | |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5274 | // Write nops at the end of the function. |
| 5275 | if (Function->getMaxSize() != std::numeric_limits<uint64_t>::max()) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5276 | uint64_t Pos = OS.tell(); |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5277 | OS.seek(Function->getFileOffset() + Function->getImageSize()); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 5278 | MAB->writeNopData(OS, Function->getMaxSize() - Function->getImageSize(), |
| 5279 | &*BC->STI); |
| 5280 | |
Maksim Panchenko | 6ff1795 | 2017-01-17 23:49:59 | [diff] [blame] | 5281 | OS.seek(Pos); |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5282 | } |
Maksim Panchenko | 6ff1795 | 2017-01-17 23:49:59 | [diff] [blame] | 5283 | |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5284 | if (!Function->isSplit()) { |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 5285 | ++CountOverwrittenFunctions; |
| 5286 | if (opts::MaxFunctions && |
| 5287 | CountOverwrittenFunctions == opts::MaxFunctions) { |
Maksim Panchenko | a7d0251 | 2018-06-14 21:27:20 | [diff] [blame] | 5288 | outs() << "BOLT: maximum number of functions reached\n"; |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 5289 | break; |
| 5290 | } |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5291 | continue; |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 5292 | } |
| 5293 | |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5294 | // Write cold part |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 5295 | if (opts::Verbosity >= 2) |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5296 | outs() << "BOLT: rewriting function \"" << *Function |
| 5297 | << "\" (cold part)\n"; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 5298 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5299 | OS.pwrite(reinterpret_cast<char *>(Function->cold().getImageAddress()), |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5300 | Function->cold().getImageSize(), |
| 5301 | Function->cold().getFileOffset()); |
| 5302 | |
| 5303 | ++CountOverwrittenFunctions; |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5304 | if (opts::MaxFunctions && CountOverwrittenFunctions == opts::MaxFunctions) { |
Maksim Panchenko | 0465d95 | 2020-10-09 23:06:27 | [diff] [blame] | 5305 | outs() << "BOLT: maximum number of functions reached\n"; |
| 5306 | break; |
| 5307 | } |
| 5308 | } |
| 5309 | |
| 5310 | // Print function statistics for non-relocation mode. |
| 5311 | if (!BC->HasRelocations) { |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5312 | outs() << "BOLT: " << CountOverwrittenFunctions << " out of " |
| 5313 | << BC->getBinaryFunctions().size() |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5314 | << " functions were overwritten.\n"; |
Maksim Panchenko | d15b93b | 2017-11-28 17:57:21 | [diff] [blame] | 5315 | if (BC->TotalScore != 0) { |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5316 | double Coverage = OverwrittenScore / (double)BC->TotalScore * 100.0; |
Wenlei He | 615a318 | 2019-09-04 05:24:06 | [diff] [blame] | 5317 | outs() << format("BOLT-INFO: rewritten functions cover %.2lf", Coverage) |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5318 | << "% of the execution count of simple functions of " |
Wenlei He | 615a318 | 2019-09-04 05:24:06 | [diff] [blame] | 5319 | "this binary\n"; |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 5320 | } |
| 5321 | } |
Maksim Panchenko | c9b7e3e | 2015-12-19 01:00:46 | [diff] [blame] | 5322 | |
Maksim Panchenko | b6f7c68 | 2017-12-10 05:40:39 | [diff] [blame] | 5323 | if (BC->HasRelocations && opts::TrapOldCode) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5324 | uint64_t SavedPos = OS.tell(); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5325 | // Overwrite function body to make sure we never execute these instructions. |
Maksim Panchenko | 7fd4870 | 2019-04-03 22:52:01 | [diff] [blame] | 5326 | for (auto &BFI : BC->getBinaryFunctions()) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5327 | BinaryFunction &BF = BFI.second; |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 5328 | if (!BF.getFileOffset() || !BF.isEmitted()) |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5329 | continue; |
Maksim Panchenko | 6ff1795 | 2017-01-17 23:49:59 | [diff] [blame] | 5330 | OS.seek(BF.getFileOffset()); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5331 | for (unsigned I = 0; I < BF.getMaxSize(); ++I) |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 5332 | OS.write((unsigned char)BC->MIB->getTrapFillValue()); |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5333 | } |
Maksim Panchenko | 6ff1795 | 2017-01-17 23:49:59 | [diff] [blame] | 5334 | OS.seek(SavedPos); |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 5335 | } |
Maksim Panchenko | c9b7e3e | 2015-12-19 01:00:46 | [diff] [blame] | 5336 | |
Rafael Auler | 7b779f8 | 2021-09-10 23:19:50 | [diff] [blame] | 5337 | // Write all allocatable sections - reloc-mode text is written here as well |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5338 | for (BinarySection &Section : BC->allocatableSections()) { |
Maksim Panchenko | 9711286 | 2020-02-18 17:20:17 | [diff] [blame] | 5339 | if (!Section.isFinalized() || !Section.getOutputData()) |
Maksim Panchenko | c9b7e3e | 2015-12-19 01:00:46 | [diff] [blame] | 5340 | continue; |
Maksim Panchenko | 9711286 | 2020-02-18 17:20:17 | [diff] [blame] | 5341 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 5342 | if (opts::Verbosity >= 1) |
Maksim Panchenko | a7d0251 | 2018-06-14 21:27:20 | [diff] [blame] | 5343 | outs() << "BOLT: writing new section " << Section.getName() |
Maksim Panchenko | a62f4fd | 2018-03-20 01:32:12 | [diff] [blame] | 5344 | << "\n data at 0x" << Twine::utohexstr(Section.getAllocAddress()) |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5345 | << "\n of size " << Section.getOutputSize() << "\n at offset " |
| 5346 | << Section.getOutputFileOffset() << '\n'; |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5347 | OS.pwrite(reinterpret_cast<const char *>(Section.getOutputData()), |
| 5348 | Section.getOutputSize(), Section.getOutputFileOffset()); |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 5349 | } |
| 5350 | |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 5351 | for (BinarySection &Section : BC->allocatableSections()) |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5352 | Section.flushPendingRelocations(OS, [this](const MCSymbol *S) { |
| 5353 | return getNewValueForSymbol(S->getName()); |
| 5354 | }); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 5355 | |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 5356 | // If .eh_frame is present create .eh_frame_hdr. |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 5357 | if (EHFrameSection && EHFrameSection->isFinalized()) |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 5358 | writeEHFrameHeader(); |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 5359 | |
Rafael Auler | 21f4303 | 2019-04-13 00:33:46 | [diff] [blame] | 5360 | // Add BOLT Addresses Translation maps to allow profile collection to |
| 5361 | // happen in the output binary |
| 5362 | if (opts::EnableBAT) |
| 5363 | addBATSection(); |
| 5364 | |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 5365 | // Patch program header table. |
| 5366 | patchELFPHDRTable(); |
Maksim Panchenko | 50c895a | 2016-02-08 18:02:48 | [diff] [blame] | 5367 | |
Maksim Panchenko | 69b5863 | 2017-05-17 00:29:31 | [diff] [blame] | 5368 | // Finalize memory image of section string table. |
| 5369 | finalizeSectionStringTable(); |
| 5370 | |
Rafael Auler | 624b2d9 | 2017-09-20 17:43:01 | [diff] [blame] | 5371 | // Update symbol tables. |
| 5372 | patchELFSymTabs(); |
Rafael Auler | 4e29afe | 2017-06-27 23:25:59 | [diff] [blame] | 5373 | |
Rafael Auler | 9c4fcaf | 2018-08-09 00:55:24 | [diff] [blame] | 5374 | patchBuildID(); |
| 5375 | |
Rafael Auler | 21f4303 | 2019-04-13 00:33:46 | [diff] [blame] | 5376 | if (opts::EnableBAT) |
| 5377 | encodeBATSection(); |
| 5378 | |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 5379 | // Copy non-allocatable sections once allocatable part is finished. |
| 5380 | rewriteNoteSections(); |
| 5381 | |
Maksim Panchenko | b6f7c68 | 2017-12-10 05:40:39 | [diff] [blame] | 5382 | if (BC->HasRelocations) { |
Maksim Panchenko | 88bb145 | 2018-08-16 23:53:14 | [diff] [blame] | 5383 | patchELFAllocatableRelaSections(); |
Maksim Panchenko | 6ff1795 | 2017-01-17 23:49:59 | [diff] [blame] | 5384 | patchELFGOT(); |
| 5385 | } |
Maksim Panchenko | 55fc541 | 2016-09-28 02:09:38 | [diff] [blame] | 5386 | |
Vladislav Khmelevsky | 729d29e | 2022-02-16 15:13:44 | [diff] [blame] | 5387 | // Patch dynamic section/segment. |
| 5388 | patchELFDynamic(); |
| 5389 | |
Maksim Panchenko | d68b1c7b | 2016-03-03 18:13:11 | [diff] [blame] | 5390 | // Update ELF book-keeping info. |
| 5391 | patchELFSectionHeaderTable(); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 5392 | |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 5393 | if (opts::PrintSections) { |
| 5394 | outs() << "BOLT-INFO: Sections after processing:\n"; |
| 5395 | BC->printSections(outs()); |
| 5396 | } |
| 5397 | |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 5398 | Out->keep(); |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5399 | EC = sys::fs::setPermissions(opts::OutputFilename, sys::fs::perms::all_all); |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 5400 | check_error(EC, "cannot set permissions of output file"); |
Rafael Auler | c67a753 | 2015-11-24 01:54:18 | [diff] [blame] | 5401 | } |
Gabriel Poesia | 73c9f0a | 2016-03-03 02:40:10 | [diff] [blame] | 5402 | |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 5403 | void RewriteInstance::writeEHFrameHeader() { |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 5404 | DWARFDebugFrame NewEHFrame(BC->TheTriple->getArch(), true, |
| 5405 | EHFrameSection->getOutputAddress()); |
| 5406 | Error E = NewEHFrame.parse(DWARFDataExtractor( |
| 5407 | EHFrameSection->getOutputContents(), BC->AsmInfo->isLittleEndian(), |
| 5408 | BC->AsmInfo->getCodePointerSize())); |
| 5409 | check_error(std::move(E), "failed to parse EH frame"); |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 5410 | |
Maksim Panchenko | fe37f18 | 2021-05-13 17:50:47 | [diff] [blame] | 5411 | uint64_t OldEHFrameAddress = 0; |
Maksim Panchenko | 33e0b2a | 2020-04-19 19:55:43 | [diff] [blame] | 5412 | StringRef OldEHFrameContents; |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5413 | ErrorOr<BinarySection &> OldEHFrameSection = |
| 5414 | BC->getUniqueSectionByName(Twine(getOrgSecPrefix(), ".eh_frame").str()); |
Maksim Panchenko | 33e0b2a | 2020-04-19 19:55:43 | [diff] [blame] | 5415 | if (OldEHFrameSection) { |
| 5416 | OldEHFrameAddress = OldEHFrameSection->getOutputAddress(); |
| 5417 | OldEHFrameContents = OldEHFrameSection->getOutputContents(); |
| 5418 | } |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 5419 | DWARFDebugFrame OldEHFrame(BC->TheTriple->getArch(), true, OldEHFrameAddress); |
| 5420 | Error Er = OldEHFrame.parse( |
| 5421 | DWARFDataExtractor(OldEHFrameContents, BC->AsmInfo->isLittleEndian(), |
| 5422 | BC->AsmInfo->getCodePointerSize())); |
| 5423 | check_error(std::move(Er), "failed to parse EH frame"); |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 5424 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 5425 | LLVM_DEBUG(dbgs() << "BOLT: writing a new .eh_frame_hdr\n"); |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 5426 | |
Maksim Panchenko | 075f076 | 2017-04-06 17:49:59 | [diff] [blame] | 5427 | NextAvailableAddress = |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5428 | appendPadding(Out->os(), NextAvailableAddress, EHFrameHdrAlign); |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 5429 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5430 | const uint64_t EHFrameHdrOutputAddress = NextAvailableAddress; |
| 5431 | const uint64_t EHFrameHdrFileOffset = |
| 5432 | getFileOffsetForAddress(NextAvailableAddress); |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 5433 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5434 | std::vector<char> NewEHFrameHdr = CFIRdWrt->generateEHFrameHeader( |
| 5435 | OldEHFrame, NewEHFrame, EHFrameHdrOutputAddress, FailedAddresses); |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 5436 | |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 5437 | assert(Out->os().tell() == EHFrameHdrFileOffset && "offset mismatch"); |
| 5438 | Out->os().write(NewEHFrameHdr.data(), NewEHFrameHdr.size()); |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 5439 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5440 | const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/true, |
| 5441 | /*IsText=*/false, |
| 5442 | /*IsAllocatable=*/true); |
| 5443 | BinarySection &EHFrameHdrSec = BC->registerOrUpdateSection( |
| 5444 | ".eh_frame_hdr", ELF::SHT_PROGBITS, Flags, nullptr, NewEHFrameHdr.size(), |
| 5445 | /*Alignment=*/1); |
Maksim Panchenko | 0ce0bce | 2020-06-15 07:15:47 | [diff] [blame] | 5446 | EHFrameHdrSec.setOutputFileOffset(EHFrameHdrFileOffset); |
Maksim Panchenko | 163adbe | 2019-03-15 01:51:05 | [diff] [blame] | 5447 | EHFrameHdrSec.setOutputAddress(EHFrameHdrOutputAddress); |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 5448 | |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 5449 | NextAvailableAddress += EHFrameHdrSec.getOutputSize(); |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 5450 | |
Maksim Panchenko | af55312 | 2020-03-07 19:19:09 | [diff] [blame] | 5451 | // Merge new .eh_frame with original so that gdb can locate all FDEs. |
Maksim Panchenko | 33e0b2a | 2020-04-19 19:55:43 | [diff] [blame] | 5452 | if (OldEHFrameSection) { |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5453 | const uint64_t EHFrameSectionSize = (OldEHFrameSection->getOutputAddress() + |
| 5454 | OldEHFrameSection->getOutputSize() - |
| 5455 | EHFrameSection->getOutputAddress()); |
Maksim Panchenko | 33e0b2a | 2020-04-19 19:55:43 | [diff] [blame] | 5456 | EHFrameSection = |
| 5457 | BC->registerOrUpdateSection(".eh_frame", |
| 5458 | EHFrameSection->getELFType(), |
| 5459 | EHFrameSection->getELFFlags(), |
| 5460 | EHFrameSection->getOutputData(), |
| 5461 | EHFrameSectionSize, |
| 5462 | EHFrameSection->getAlignment()); |
| 5463 | BC->deregisterSection(*OldEHFrameSection); |
| 5464 | } |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 5465 | |
Amir Ayupov | 1c5d3a0 | 2020-12-02 00:29:39 | [diff] [blame] | 5466 | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: size of .eh_frame after merge is " |
| 5467 | << EHFrameSection->getOutputSize() << '\n'); |
Maksim Panchenko | a7fb610 | 2016-11-11 22:33:34 | [diff] [blame] | 5468 | } |
| 5469 | |
Maksim Panchenko | 4946b88 | 2020-06-22 23:16:08 | [diff] [blame] | 5470 | uint64_t RewriteInstance::getNewValueForSymbol(const StringRef Name) { |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5471 | uint64_t Value = RTDyld->getSymbol(Name).getAddress(); |
Maksim Panchenko | 4946b88 | 2020-06-22 23:16:08 | [diff] [blame] | 5472 | if (Value != 0) |
| 5473 | return Value; |
| 5474 | |
| 5475 | // Return the original value if we haven't emitted the symbol. |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5476 | BinaryData *BD = BC->getBinaryDataByName(Name); |
Maksim Panchenko | 4946b88 | 2020-06-22 23:16:08 | [diff] [blame] | 5477 | if (!BD) |
| 5478 | return 0; |
| 5479 | |
| 5480 | return BD->getAddress(); |
| 5481 | } |
| 5482 | |
Maksim Panchenko | 6ff1795 | 2017-01-17 23:49:59 | [diff] [blame] | 5483 | uint64_t RewriteInstance::getFileOffsetForAddress(uint64_t Address) const { |
| 5484 | // Check if it's possibly part of the new segment. |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 5485 | if (Address >= NewTextSegmentAddress) |
Maksim Panchenko | 6ff1795 | 2017-01-17 23:49:59 | [diff] [blame] | 5486 | return Address - NewTextSegmentAddress + NewTextSegmentOffset; |
Maksim Panchenko | 6ff1795 | 2017-01-17 23:49:59 | [diff] [blame] | 5487 | |
| 5488 | // Find an existing segment that matches the address. |
Maksim Panchenko | 250ca40 | 2020-06-26 23:52:07 | [diff] [blame] | 5489 | const auto SegmentInfoI = BC->SegmentMapInfo.upper_bound(Address); |
| 5490 | if (SegmentInfoI == BC->SegmentMapInfo.begin()) |
Maksim Panchenko | 6ff1795 | 2017-01-17 23:49:59 | [diff] [blame] | 5491 | return 0; |
| 5492 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5493 | const SegmentInfo &SegmentInfo = std::prev(SegmentInfoI)->second; |
Maksim Panchenko | 6ff1795 | 2017-01-17 23:49:59 | [diff] [blame] | 5494 | if (Address < SegmentInfo.Address || |
| 5495 | Address >= SegmentInfo.Address + SegmentInfo.FileSize) |
| 5496 | return 0; |
| 5497 | |
Maksim Panchenko | 40c2e0f | 2021-12-15 00:52:51 | [diff] [blame] | 5498 | return SegmentInfo.FileOffset + Address - SegmentInfo.Address; |
Maksim Panchenko | 6ff1795 | 2017-01-17 23:49:59 | [diff] [blame] | 5499 | } |
| 5500 | |
Maksim Panchenko | e212805 | 2017-02-07 20:20:46 | [diff] [blame] | 5501 | bool RewriteInstance::willOverwriteSection(StringRef SectionName) { |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 5502 | for (const char *const &OverwriteName : SectionsToOverwrite) |
Rafael Auler | 624b2d9 | 2017-09-20 17:43:01 | [diff] [blame] | 5503 | if (SectionName == OverwriteName) |
| 5504 | return true; |
Maksim Panchenko | ee0e9cc | 2021-12-23 20:38:33 | [diff] [blame] | 5505 | for (std::string &OverwriteName : DebugSectionsToOverwrite) |
Maksim Panchenko | 2b15233 | 2019-04-26 22:30:12 | [diff] [blame] | 5506 | if (SectionName == OverwriteName) |
| 5507 | return true; |
Rafael Auler | 21f4303 | 2019-04-13 00:33:46 | [diff] [blame] | 5508 | |
Amir Ayupov | c7306cc | 2021-04-08 07:19:26 | [diff] [blame] | 5509 | ErrorOr<BinarySection &> Section = BC->getUniqueSectionByName(SectionName); |
Bill Nell | ddefc77 | 2018-02-02 00:33:43 | [diff] [blame] | 5510 | return Section && Section->isAllocatable() && Section->isFinalized(); |
Maksim Panchenko | f047b9d | 2016-05-17 00:02:17 | [diff] [blame] | 5511 | } |
Maksim Panchenko | 2b15233 | 2019-04-26 22:30:12 | [diff] [blame] | 5512 | |
| 5513 | bool RewriteInstance::isDebugSection(StringRef SectionName) { |
Vladislav Khmelevsky | 95ee129 | 2021-10-16 14:02:45 | [diff] [blame] | 5514 | if (SectionName.startswith(".debug_") || SectionName.startswith(".zdebug_") || |
| 5515 | SectionName == ".gdb_index" || SectionName == ".stab" || |
| 5516 | SectionName == ".stabstr") |
Maksim Panchenko | 2b15233 | 2019-04-26 22:30:12 | [diff] [blame] | 5517 | return true; |
| 5518 | |
| 5519 | return false; |
| 5520 | } |
takh | 48b71ad | 2020-06-11 06:00:39 | [diff] [blame] | 5521 | |
| 5522 | bool RewriteInstance::isKSymtabSection(StringRef SectionName) { |
| 5523 | if (SectionName.startswith("__ksymtab")) |
| 5524 | return true; |
| 5525 | |
| 5526 | return false; |
| 5527 | } |