| author | |
| committer | |
| log | ffab950e0cce8b1be2755e070d0684d817138f15 |
| tree | 67b9e76445bdb6294d2a3c8c848635098737a47e |
| parent | 63ebd9d12e48765514777418e12f55576ff63509 |
| signature |
1556 files changed, 49295 insertions(+), 31778 deletions(-)
CMakeLists.txt+4-1| ... | ... | @@ -88,6 +88,7 @@ else() |
| 88 | 88 | set(EMBEDDED_LLD_LIB_SOURCES |
| 89 | 89 | "${CMAKE_SOURCE_DIR}/deps/lld/Common/Args.cpp" |
| 90 | 90 | "${CMAKE_SOURCE_DIR}/deps/lld/Common/ErrorHandler.cpp" |
| 91 | "${CMAKE_SOURCE_DIR}/deps/lld/Common/Filesystem.cpp" | |
| 91 | 92 | "${CMAKE_SOURCE_DIR}/deps/lld/Common/Memory.cpp" |
| 92 | 93 | "${CMAKE_SOURCE_DIR}/deps/lld/Common/Reproduce.cpp" |
| 93 | 94 | "${CMAKE_SOURCE_DIR}/deps/lld/Common/Strings.cpp" |
| ... | ... | @@ -148,7 +149,6 @@ else() |
| 148 | 149 | "${CMAKE_SOURCE_DIR}/deps/lld/ELF/Driver.cpp" |
| 149 | 150 | "${CMAKE_SOURCE_DIR}/deps/lld/ELF/DriverUtils.cpp" |
| 150 | 151 | "${CMAKE_SOURCE_DIR}/deps/lld/ELF/EhFrame.cpp" |
| 151 | "${CMAKE_SOURCE_DIR}/deps/lld/ELF/Filesystem.cpp" | |
| 152 | 152 | "${CMAKE_SOURCE_DIR}/deps/lld/ELF/ICF.cpp" |
| 153 | 153 | "${CMAKE_SOURCE_DIR}/deps/lld/ELF/InputFiles.cpp" |
| 154 | 154 | "${CMAKE_SOURCE_DIR}/deps/lld/ELF/InputSection.cpp" |
| ... | ... | @@ -171,6 +171,7 @@ else() |
| 171 | 171 | set(EMBEDDED_LLD_COFF_SOURCES |
| 172 | 172 | "${CMAKE_SOURCE_DIR}/deps/lld/COFF/Chunks.cpp" |
| 173 | 173 | "${CMAKE_SOURCE_DIR}/deps/lld/COFF/DLL.cpp" |
| 174 | "${CMAKE_SOURCE_DIR}/deps/lld/COFF/DebugTypes.cpp" | |
| 174 | 175 | "${CMAKE_SOURCE_DIR}/deps/lld/COFF/Driver.cpp" |
| 175 | 176 | "${CMAKE_SOURCE_DIR}/deps/lld/COFF/DriverUtils.cpp" |
| 176 | 177 | "${CMAKE_SOURCE_DIR}/deps/lld/COFF/ICF.cpp" |
| ... | ... | @@ -194,8 +195,10 @@ else() |
| 194 | 195 | "${CMAKE_SOURCE_DIR}/deps/lld/wasm/LTO.cpp" |
| 195 | 196 | "${CMAKE_SOURCE_DIR}/deps/lld/wasm/MarkLive.cpp" |
| 196 | 197 | "${CMAKE_SOURCE_DIR}/deps/lld/wasm/OutputSections.cpp" |
| 198 | "${CMAKE_SOURCE_DIR}/deps/lld/wasm/Relocations.cpp" | |
| 197 | 199 | "${CMAKE_SOURCE_DIR}/deps/lld/wasm/SymbolTable.cpp" |
| 198 | 200 | "${CMAKE_SOURCE_DIR}/deps/lld/wasm/Symbols.cpp" |
| 201 | "${CMAKE_SOURCE_DIR}/deps/lld/wasm/SyntheticSections.cpp" | |
| 199 | 202 | "${CMAKE_SOURCE_DIR}/deps/lld/wasm/Writer.cpp" |
| 200 | 203 | "${CMAKE_SOURCE_DIR}/deps/lld/wasm/WriterUtils.cpp" |
| 201 | 204 | ) |
deps/lld-prebuilt/COFF/Options.inc+41-10| ... | ... | @@ -13,9 +13,8 @@ |
| 13 | 13 | #define COMMA , |
| 14 | 14 | PREFIX(prefix_0, {nullptr}) |
| 15 | 15 | PREFIX(prefix_2, {"--" COMMA nullptr}) |
| 16 | PREFIX(prefix_3, {"/" COMMA "-" COMMA nullptr}) | |
| 17 | PREFIX(prefix_1, {"/" COMMA "-" COMMA "-?" COMMA nullptr}) | |
| 18 | PREFIX(prefix_4, {"/?" COMMA "-?" COMMA nullptr}) | |
| 16 | PREFIX(prefix_1, {"/" COMMA "-" COMMA "/?" COMMA "-?" COMMA nullptr}) | |
| 17 | PREFIX(prefix_3, {"/??" COMMA "-??" COMMA "/?" COMMA "-?" COMMA nullptr}) | |
| 19 | 18 | #undef COMMA |
| 20 | 19 | #endif // PREFIX |
| 21 | 20 | |
| ... | ... | @@ -61,13 +60,17 @@ OPTION(prefix_1, "debugtype:", debugtype, Joined, INVALID, INVALID, nullptr, 0, |
| 61 | 60 | "Debug Info Options", nullptr, nullptr) |
| 62 | 61 | OPTION(prefix_1, "debug", debug, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 63 | 62 | "Embed a symbol table in the image", nullptr, nullptr) |
| 64 | OPTION(prefix_3, "def:", deffile, Joined, INVALID, INVALID, nullptr, 0, 0, | |
| 63 | OPTION(prefix_1, "def:", deffile, Joined, INVALID, INVALID, nullptr, 0, 0, | |
| 65 | 64 | "Use module-definition file", nullptr, nullptr) |
| 66 | 65 | OPTION(prefix_1, "defaultlib:", defaultlib, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 67 | 66 | "Add the library to the list of input files", nullptr, nullptr) |
| 68 | 67 | OPTION(prefix_1, "delay:", delay, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 69 | 68 | OPTION(prefix_1, "delayload:", delayload, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 70 | 69 | "Delay loaded DLL name", nullptr, nullptr) |
| 70 | OPTION(prefix_1, "demangle:no", demangle_no, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 71 | "Do not demangle symbols in output", nullptr, nullptr) | |
| 72 | OPTION(prefix_1, "demangle", demangle, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 73 | "Demangle symbols in output (default)", nullptr, nullptr) | |
| 71 | 74 | OPTION(prefix_1, "disallowlib:", disallowlib, Joined, INVALID, nodefaultlib, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 72 | 75 | OPTION(prefix_1, "dll", dll, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 73 | 76 | "Create a DLL", nullptr, nullptr) |
| ... | ... | @@ -83,22 +86,29 @@ OPTION(prefix_1, "entry:", entry, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 83 | 86 | OPTION(prefix_1, "errorlimit:", errorlimit, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 84 | 87 | "Maximum number of errors to emit before stopping (0 = no limit)", nullptr, nullptr) |
| 85 | 88 | OPTION(prefix_1, "errorreport:", errorreport, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 89 | OPTION(prefix_1, "exclude-all-symbols", exclude_all_symbols, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 86 | 90 | OPTION(prefix_1, "export-all-symbols", export_all_symbols, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 87 | 91 | OPTION(prefix_1, "export:", export, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 88 | 92 | "Export a function", nullptr, nullptr) |
| 89 | 93 | OPTION(prefix_1, "failifmismatch:", failifmismatch, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 90 | 94 | "", nullptr, nullptr) |
| 91 | 95 | OPTION(prefix_1, "fastfail", fastfail, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 96 | OPTION(prefix_1, "filealign:", filealign, Joined, INVALID, INVALID, nullptr, 0, 0, | |
| 97 | "Section alignment in the output file", nullptr, nullptr) | |
| 92 | 98 | OPTION(prefix_1, "fixed:no", fixed_no, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 93 | 99 | "Enable base relocations (default)", nullptr, nullptr) |
| 94 | 100 | OPTION(prefix_1, "fixed", fixed, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 95 | 101 | "Disable base relocations", nullptr, nullptr) |
| 102 | OPTION(prefix_1, "force:multipleres", force_multipleres, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 103 | "Allow multiply defined resources when creating executables", nullptr, nullptr) | |
| 96 | 104 | OPTION(prefix_1, "force:multiple", force_multiple, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 97 | 105 | "Allow multiply defined symbols when creating executables", nullptr, nullptr) |
| 98 | 106 | OPTION(prefix_1, "force:unresolved", force_unresolved, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 99 | 107 | "Allow undefined symbols when creating executables", nullptr, nullptr) |
| 100 | 108 | OPTION(prefix_1, "force", force, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 101 | 109 | "Allow undefined and multiply defined symbols when creating executables", nullptr, nullptr) |
| 110 | OPTION(prefix_1, "functionpadmin:", functionpadmin_opt, Joined, INVALID, INVALID, nullptr, 0, 0, | |
| 111 | "Prepares an image for hotpatching", nullptr, nullptr) | |
| 102 | 112 | OPTION(prefix_1, "functionpadmin", functionpadmin, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 103 | 113 | OPTION(prefix_1, "guard:", guard, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 104 | 114 | "Control flow guard", nullptr, nullptr) |
| ... | ... | @@ -116,8 +126,10 @@ OPTION(prefix_1, "ignore:", ignore, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 116 | 126 | OPTION(prefix_1, "ignoreidl", ignoreidl, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 117 | 127 | OPTION(prefix_1, "implib:", implib, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 118 | 128 | "Import library name", nullptr, nullptr) |
| 119 | OPTION(prefix_3, "include:", incl, Joined, INVALID, INVALID, nullptr, 0, 0, | |
| 129 | OPTION(prefix_1, "include:", incl, Joined, INVALID, INVALID, nullptr, 0, 0, | |
| 120 | 130 | "Force symbol to be added to symbol table as undefined one", nullptr, nullptr) |
| 131 | OPTION(prefix_1, "includeoptional:", include_optional, Joined, INVALID, INVALID, nullptr, 0, 0, | |
| 132 | "Add symbol as undefined, but allow it to remain undefined", nullptr, nullptr) | |
| 121 | 133 | OPTION(prefix_1, "incremental:no", incremental_no, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 122 | 134 | "Overwrite import library even if contents are unchanged", nullptr, nullptr) |
| 123 | 135 | OPTION(prefix_1, "incremental", incremental, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -141,7 +153,7 @@ OPTION(prefix_1, "lldltocache:", lldltocache, Joined, INVALID, INVALID, nullptr, |
| 141 | 153 | "Path to ThinLTO cached object file directory", nullptr, nullptr) |
| 142 | 154 | OPTION(prefix_1, "lldltocachepolicy:", lldltocachepolicy, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 143 | 155 | "Pruning policy for the ThinLTO cache", nullptr, nullptr) |
| 144 | OPTION(prefix_3, "lldmap:", lldmap_file, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 156 | OPTION(prefix_1, "lldmap:", lldmap_file, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 145 | 157 | OPTION(prefix_1, "lldmap", lldmap, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 146 | 158 | OPTION(prefix_1, "lldmingw", lldmingw, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 147 | 159 | OPTION(prefix_1, "lldsavetemps", lldsavetemps, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -186,7 +198,7 @@ OPTION(prefix_1, "order:", order, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 186 | 198 | "Put functions in order", nullptr, nullptr) |
| 187 | 199 | OPTION(prefix_1, "out:", out, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 188 | 200 | "Path to file to write output", nullptr, nullptr) |
| 189 | OPTION(prefix_3, "output-def:", output_def, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 201 | OPTION(prefix_1, "output-def:", output_def, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 190 | 202 | OPTION(prefix_1, "pdb:", pdb, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 191 | 203 | "PDB file path", nullptr, nullptr) |
| 192 | 204 | OPTION(prefix_1, "pdbaltpath:", pdbaltpath, Joined, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -208,8 +220,27 @@ OPTION(prefix_1, "stub:", stub, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 208 | 220 | "Specify DOS stub file", nullptr, nullptr) |
| 209 | 221 | OPTION(prefix_1, "subsystem:", subsystem, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 210 | 222 | "Specify subsystem", nullptr, nullptr) |
| 211 | OPTION(prefix_1, "swaprun:cd", swaprun_cd, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 212 | OPTION(prefix_1, "swaprun:net", swaprun_net, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 223 | OPTION(prefix_1, "summary", summary, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 224 | OPTION(prefix_1, "swaprun:cd", swaprun_cd, Flag, INVALID, swaprun, "cd\0", 0, 0, | |
| 225 | "Make loader run output binary from swap instead of from CD", nullptr, nullptr) | |
| 226 | OPTION(prefix_1, "swaprun:net", swaprun_net, Flag, INVALID, swaprun, "net\0", 0, 0, | |
| 227 | "Make loader run output binary from swap instead of from network", nullptr, nullptr) | |
| 228 | OPTION(prefix_1, "swaprun:", swaprun, Joined, INVALID, INVALID, nullptr, 0, 0, | |
| 229 | "Comma-separated list of 'cd' or 'net'", nullptr, nullptr) | |
| 230 | OPTION(prefix_1, "thinlto-emit-imports-files", thinlto_emit_imports_files, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 231 | "Emit .imports files with -thinlto-index-only", nullptr, nullptr) | |
| 232 | OPTION(prefix_1, "thinlto-index-only:", thinlto_index_only_arg, Joined, INVALID, INVALID, nullptr, 0, 0, | |
| 233 | "-thinlto-index-only and also write native module names to file", nullptr, nullptr) | |
| 234 | OPTION(prefix_1, "thinlto-index-only", thinlto_index_only, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 235 | "Instead of linking, emit ThinLTO index files", nullptr, nullptr) | |
| 236 | OPTION(prefix_1, "thinlto-object-suffix-replace:", thinlto_object_suffix_replace, Joined, INVALID, INVALID, nullptr, 0, 0, | |
| 237 | "'old;new' replace old suffix with new suffix in ThinLTO index", nullptr, nullptr) | |
| 238 | OPTION(prefix_1, "thinlto-prefix-replace:", thinlto_prefix_replace, Joined, INVALID, INVALID, nullptr, 0, 0, | |
| 239 | "'old;new' replace old prefix with new prefix in ThinLTO outputs", nullptr, nullptr) | |
| 240 | OPTION(prefix_1, "threads:no", threads_no, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 241 | "Do not run the linker multi-threaded", nullptr, nullptr) | |
| 242 | OPTION(prefix_1, "threads", threads, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 243 | "Run the linker multi-threaded (default)", nullptr, nullptr) | |
| 213 | 244 | OPTION(prefix_1, "throwingnew", throwingnew, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 214 | 245 | OPTION(prefix_1, "timestamp:", timestamp, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 215 | 246 | "Specify the PE header timestamp", nullptr, nullptr) |
| ... | ... | @@ -233,7 +264,7 @@ OPTION(prefix_1, "WX:no", WX_no, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 233 | 264 | "Don't treat warnings as errors", nullptr, nullptr) |
| 234 | 265 | OPTION(prefix_1, "WX", WX, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 235 | 266 | "Treat warnings as errors", nullptr, nullptr) |
| 236 | OPTION(prefix_4, "", help_q, Flag, INVALID, help, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 267 | OPTION(prefix_3, "", help_q, Flag, INVALID, help, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 237 | 268 | #endif // OPTION |
| 238 | 269 | |
| 239 | 270 | #ifdef OPTTABLE_ARG_INIT |
deps/lld-prebuilt/ELF/Options.inc+91-51| ... | ... | @@ -29,13 +29,14 @@ PREFIX(prefix_2, {"--" COMMA "-" COMMA nullptr}) |
| 29 | 29 | |
| 30 | 30 | OPTION(prefix_0, "<input>", INPUT, Input, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 31 | 31 | OPTION(prefix_0, "<unknown>", UNKNOWN, Unknown, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 32 | OPTION(prefix_1, "(", anonymous_30, Flag, INVALID, start_group, nullptr, 0, 0, | |
| 32 | OPTION(prefix_1, "(", anonymous_31, Flag, INVALID, start_group, nullptr, 0, 0, | |
| 33 | 33 | "Alias for --start-group", nullptr, nullptr) |
| 34 | 34 | OPTION(prefix_1, ")", anonymous_12, Flag, INVALID, end_group, nullptr, 0, 0, |
| 35 | 35 | "Alias for --end-group", nullptr, nullptr) |
| 36 | 36 | OPTION(prefix_2, "allow-multiple-definition", allow_multiple_definition, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 37 | 37 | "Allow multiple definitions", nullptr, nullptr) |
| 38 | OPTION(prefix_2, "allow-shlib-undefined", anonymous_47, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 38 | OPTION(prefix_2, "allow-shlib-undefined", allow_shlib_undefined, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 39 | "Allow unresolved references in shared libraries (default when linking a shared library)", nullptr, nullptr) | |
| 39 | 40 | OPTION(prefix_2, "apply-dynamic-relocs", apply_dynamic_relocs, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 40 | 41 | "Apply link-time values for dynamic relocations", nullptr, nullptr) |
| 41 | 42 | OPTION(prefix_2, "as-needed", as_needed, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -45,7 +46,7 @@ OPTION(prefix_2, "auxiliary=", auxiliary_eq, Joined, INVALID, auxiliary, nullptr |
| 45 | 46 | OPTION(prefix_2, "auxiliary", auxiliary, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 46 | 47 | OPTION(prefix_2, "Bdynamic", Bdynamic, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 47 | 48 | "Link against shared libraries (default)", nullptr, nullptr) |
| 48 | OPTION(prefix_2, "Bshareable", anonymous_28, Flag, INVALID, shared, nullptr, 0, 0, | |
| 49 | OPTION(prefix_2, "Bshareable", anonymous_29, Flag, INVALID, shared, nullptr, 0, 0, | |
| 49 | 50 | "Alias for --shared", nullptr, nullptr) |
| 50 | 51 | OPTION(prefix_2, "Bstatic", Bstatic, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 51 | 52 | "Do not link against shared libraries", nullptr, nullptr) |
| ... | ... | @@ -87,7 +88,9 @@ OPTION(prefix_2, "defsym=", defsym_eq, Joined, INVALID, defsym, nullptr, 0, 0, |
| 87 | 88 | OPTION(prefix_2, "defsym", defsym, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, "<symbol>=<value>", nullptr) |
| 88 | 89 | OPTION(prefix_2, "demangle", demangle, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 89 | 90 | "Demangle symbol names (default)", nullptr, nullptr) |
| 90 | OPTION(prefix_2, "detect-odr-violations", anonymous_48, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 91 | OPTION(prefix_2, "dependent-libraries", dependent_libraries, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 92 | "Process dependent library specifiers from input files (default)", nullptr, nullptr) | |
| 93 | OPTION(prefix_2, "detect-odr-violations", anonymous_50, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 91 | 94 | OPTION(prefix_2, "disable-new-dtags", disable_new_dtags, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 92 | 95 | "Disable new dynamic tags", nullptr, nullptr) |
| 93 | 96 | OPTION(prefix_2, "disable-verify", disable_verify, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| ... | ... | @@ -111,10 +114,10 @@ OPTION(prefix_2, "dy", anonymous_2, Flag, INVALID, Bdynamic, nullptr, 0, 0, |
| 111 | 114 | "Alias for --Bdynamic", nullptr, nullptr) |
| 112 | 115 | OPTION(prefix_1, "d", anonymous_6, Flag, INVALID, define_common, nullptr, 0, 0, |
| 113 | 116 | "Alias for --define-common", nullptr, nullptr) |
| 114 | OPTION(prefix_2, "EB", anonymous_65, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 117 | OPTION(prefix_2, "EB", anonymous_69, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 115 | 118 | OPTION(prefix_2, "eh-frame-hdr", eh_frame_hdr, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 116 | 119 | "Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header", nullptr, nullptr) |
| 117 | OPTION(prefix_2, "EL", anonymous_66, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 120 | OPTION(prefix_2, "EL", anonymous_70, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 118 | 121 | OPTION(prefix_2, "emit-relocs", emit_relocs, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 119 | 122 | "Generate relocations in output", nullptr, nullptr) |
| 120 | 123 | OPTION(prefix_2, "enable-new-dtags", enable_new_dtags, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -155,6 +158,8 @@ OPTION(prefix_2, "fini=", fini_eq, Joined, INVALID, fini, nullptr, 0, 0, |
| 155 | 158 | OPTION(prefix_2, "fini", fini, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, "<symbol>", nullptr) |
| 156 | 159 | OPTION(prefix_2, "fix-cortex-a53-843419", fix_cortex_a53_843419, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 157 | 160 | "Apply fixes for AArch64 Cortex-A53 erratum 843419", nullptr, nullptr) |
| 161 | OPTION(prefix_2, "force-bti", force_bti, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 162 | "Force enable AArch64 BTI in PLT, warn if Input ELF file does not have GNU_PROPERTY_AARCH64_FEATURE_1_BTI property", nullptr, nullptr) | |
| 158 | 163 | OPTION(prefix_2, "format=", format_eq, Joined, INVALID, format, nullptr, 0, 0, |
| 159 | 164 | "Change the input format of the inputs following this option", "[default,elf,binary]", nullptr) |
| 160 | 165 | OPTION(prefix_2, "format", format, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, "[default,elf,binary]", nullptr) |
| ... | ... | @@ -168,14 +173,14 @@ OPTION(prefix_2, "gdb-index", gdb_index, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 168 | 173 | "Generate .gdb_index section", nullptr, nullptr) |
| 169 | 174 | OPTION(prefix_2, "gnu-unique", gnu_unique, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 170 | 175 | "Enable STB_GNU_UNIQUE symbol binding (default)", nullptr, nullptr) |
| 171 | OPTION(prefix_1, "G", anonymous_67, JoinedOrSeparate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 172 | OPTION(prefix_1, "g", anonymous_49, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 176 | OPTION(prefix_1, "G", anonymous_71, JoinedOrSeparate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 177 | OPTION(prefix_1, "g", anonymous_51, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 173 | 178 | OPTION(prefix_2, "hash-style=", hash_style_eq, Joined, INVALID, hash_style, nullptr, 0, 0, |
| 174 | 179 | "Specify hash style (sysv, gnu or both)", nullptr, nullptr) |
| 175 | 180 | OPTION(prefix_2, "hash-style", hash_style, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 176 | 181 | OPTION(prefix_2, "help", help, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 177 | 182 | "Print option help", nullptr, nullptr) |
| 178 | OPTION(prefix_1, "h", anonymous_29, JoinedOrSeparate, INVALID, soname, nullptr, 0, 0, | |
| 183 | OPTION(prefix_1, "h", anonymous_30, JoinedOrSeparate, INVALID, soname, nullptr, 0, 0, | |
| 179 | 184 | "Alias for --soname", nullptr, nullptr) |
| 180 | 185 | OPTION(prefix_2, "icf=all", icf_all, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 181 | 186 | "Enable identical code folding", nullptr, nullptr) |
| ... | ... | @@ -205,9 +210,13 @@ OPTION(prefix_2, "library-path", library_path, Separate, INVALID, INVALID, nullp |
| 205 | 210 | OPTION(prefix_2, "library=", library_eq, Joined, INVALID, library, nullptr, 0, 0, |
| 206 | 211 | "Root name of library to use", "<libName>", nullptr) |
| 207 | 212 | OPTION(prefix_2, "library", library, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, "<libName>", nullptr) |
| 208 | OPTION(prefix_2, "long-plt", anonymous_50, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 213 | OPTION(prefix_2, "long-plt", anonymous_52, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 209 | 214 | OPTION(prefix_2, "lto-aa-pipeline=", lto_aa_pipeline, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 210 | 215 | "AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes", nullptr, nullptr) |
| 216 | OPTION(prefix_2, "lto-cs-profile-file=", lto_cs_profile_file, Joined, INVALID, INVALID, nullptr, 0, 0, | |
| 217 | "Context sensitive profile file path", nullptr, nullptr) | |
| 218 | OPTION(prefix_2, "lto-cs-profile-generate", lto_cs_profile_generate, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 219 | "Perform context senstive PGO instrumentation", nullptr, nullptr) | |
| 211 | 220 | OPTION(prefix_2, "lto-debug-pass-manager", lto_debug_pass_manager, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 212 | 221 | "Debug new pass manager", nullptr, nullptr) |
| 213 | 222 | OPTION(prefix_2, "lto-new-pass-manager", lto_new_pass_manager, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -235,14 +244,17 @@ OPTION(prefix_2, "mips-got-size", mips_got_size, Separate, INVALID, INVALID, nul |
| 235 | 244 | OPTION(prefix_2, "mllvm=", mllvm_eq, Joined, INVALID, mllvm, nullptr, 0, 0, |
| 236 | 245 | "Additional arguments to forward to LLVM's option processing", nullptr, nullptr) |
| 237 | 246 | OPTION(prefix_2, "mllvm", mllvm, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 238 | OPTION(prefix_1, "M", anonymous_24, Flag, INVALID, print_map, nullptr, 0, 0, | |
| 247 | OPTION(prefix_1, "M", anonymous_25, Flag, INVALID, print_map, nullptr, 0, 0, | |
| 239 | 248 | "Alias for --print-map", nullptr, nullptr) |
| 240 | 249 | OPTION(prefix_1, "m", m, JoinedOrSeparate, INVALID, INVALID, nullptr, 0, 0, |
| 241 | 250 | "Set target emulation", nullptr, nullptr) |
| 242 | OPTION(prefix_2, "no-add-needed", anonymous_51, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 251 | OPTION(prefix_2, "nmagic", nmagic, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 252 | "Do not page align sections, link against static libraries.", "<magic>", nullptr) | |
| 253 | OPTION(prefix_2, "no-add-needed", anonymous_53, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 243 | 254 | OPTION(prefix_2, "no-allow-multiple-definition", no_allow_multiple_definition, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 244 | 255 | "Do not allow multiple definitions (default)", nullptr, nullptr) |
| 245 | OPTION(prefix_2, "no-allow-shlib-undefined", anonymous_52, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 256 | OPTION(prefix_2, "no-allow-shlib-undefined", no_allow_shlib_undefined, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 257 | "Do not allow unresolved references in shared libraries (default when linking an executable)", nullptr, nullptr) | |
| 246 | 258 | OPTION(prefix_2, "no-apply-dynamic-relocs", no_apply_dynamic_relocs, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 247 | 259 | "Do not apply link-time values for dynamic relocations (default)", nullptr, nullptr) |
| 248 | 260 | OPTION(prefix_2, "no-as-needed", no_as_needed, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -253,14 +265,16 @@ OPTION(prefix_2, "no-check-sections", no_check_sections, Flag, INVALID, INVALID, |
| 253 | 265 | "Do not check section addresses for overlaps", nullptr, nullptr) |
| 254 | 266 | OPTION(prefix_2, "no-color-diagnostics", no_color_diagnostics, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 255 | 267 | "Do not use colors in diagnostics", nullptr, nullptr) |
| 256 | OPTION(prefix_2, "no-copy-dt-needed-entries", anonymous_53, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 268 | OPTION(prefix_2, "no-copy-dt-needed-entries", anonymous_54, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 257 | 269 | OPTION(prefix_2, "no-cref", no_cref, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 258 | 270 | "Do not output cross reference table", nullptr, nullptr) |
| 259 | OPTION(prefix_2, "no-ctors-in-init-array", anonymous_54, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 271 | OPTION(prefix_2, "no-ctors-in-init-array", anonymous_55, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 260 | 272 | OPTION(prefix_2, "no-define-common", no_define_common, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 261 | 273 | "Do not assign space to common symbols", nullptr, nullptr) |
| 262 | 274 | OPTION(prefix_2, "no-demangle", no_demangle, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 263 | 275 | "Do not demangle symbol names", nullptr, nullptr) |
| 276 | OPTION(prefix_2, "no-dependent-libraries", no_dependent_libraries, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 277 | "Ignore dependent library specifiers from input files", nullptr, nullptr) | |
| 264 | 278 | OPTION(prefix_2, "no-dynamic-linker", no_dynamic_linker, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 265 | 279 | "Inhibit output of .interp section", nullptr, nullptr) |
| 266 | 280 | OPTION(prefix_2, "no-eh-frame-hdr", no_eh_frame_hdr, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -277,16 +291,19 @@ OPTION(prefix_2, "no-gdb-index", no_gdb_index, Flag, INVALID, INVALID, nullptr, |
| 277 | 291 | "Do not generate .gdb_index section (default)", nullptr, nullptr) |
| 278 | 292 | OPTION(prefix_2, "no-gnu-unique", no_gnu_unique, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 279 | 293 | "Disable STB_GNU_UNIQUE symbol binding", nullptr, nullptr) |
| 280 | OPTION(prefix_2, "no-keep-memory", anonymous_55, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 294 | OPTION(prefix_2, "no-keep-memory", anonymous_56, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 281 | 295 | OPTION(prefix_2, "no-merge-exidx-entries", no_merge_exidx_entries, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 282 | 296 | "Disable merging .ARM.exidx entries", nullptr, nullptr) |
| 283 | OPTION(prefix_2, "no-mmap-output-file", anonymous_56, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 297 | OPTION(prefix_2, "no-mmap-output-file", anonymous_57, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 298 | OPTION(prefix_2, "no-nmagic", no_nmagic, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 299 | "Page align sections (default)", "<magic>", nullptr) | |
| 284 | 300 | OPTION(prefix_2, "no-omagic", no_omagic, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 285 | "Do not set the text data sections to be writable", "<magic>", nullptr) | |
| 301 | "Do not set the text data sections to be writable, page align sections (default)", "<magic>", nullptr) | |
| 286 | 302 | OPTION(prefix_2, "no-pic-executable", anonymous_19, Flag, INVALID, no_pie, nullptr, 0, 0, |
| 287 | 303 | "Alias for --no-pie", nullptr, nullptr) |
| 288 | 304 | OPTION(prefix_2, "no-pie", no_pie, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 289 | 305 | "Do not create a position independent executable (default)", nullptr, nullptr) |
| 306 | OPTION(prefix_2, "no-pipeline-knowledge", anonymous_58, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 290 | 307 | OPTION(prefix_2, "no-print-gc-sections", no_print_gc_sections, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 291 | 308 | "Do not list removed unused sections (default)", nullptr, nullptr) |
| 292 | 309 | OPTION(prefix_2, "no-print-icf-sections", no_print_icf_sections, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -309,7 +326,7 @@ OPTION(prefix_2, "no-warn-common", no_warn_common, Flag, INVALID, INVALID, nullp |
| 309 | 326 | "Do not warn about duplicate common symbols (default)", nullptr, nullptr) |
| 310 | 327 | OPTION(prefix_2, "no-warn-ifunc-textrel", no_warn_ifunc_textrel, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 311 | 328 | "Do not warn about using ifunc symbols with text relocations (default)", nullptr, nullptr) |
| 312 | OPTION(prefix_2, "no-warn-mismatch", anonymous_57, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 329 | OPTION(prefix_2, "no-warn-mismatch", anonymous_59, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 313 | 330 | OPTION(prefix_2, "no-warn-symbol-ordering", no_warn_symbol_ordering, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 314 | 331 | "Do not warn about problems with the symbol ordering file", nullptr, nullptr) |
| 315 | 332 | OPTION(prefix_2, "no-whole-archive", no_whole_archive, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -320,31 +337,39 @@ OPTION(prefix_2, "non_shared", anonymous_4, Flag, INVALID, Bstatic, nullptr, 0, |
| 320 | 337 | "Alias for --Bstatic", nullptr, nullptr) |
| 321 | 338 | OPTION(prefix_2, "nostdlib", nostdlib, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 322 | 339 | "Only search directories specified on the command line", nullptr, nullptr) |
| 323 | OPTION(prefix_1, "N", anonymous_20, Flag, INVALID, omagic, nullptr, 0, 0, | |
| 340 | OPTION(prefix_1, "N", anonymous_21, Flag, INVALID, omagic, nullptr, 0, 0, | |
| 324 | 341 | "Alias for --omagic", nullptr, nullptr) |
| 342 | OPTION(prefix_1, "n", anonymous_20, Flag, INVALID, nmagic, nullptr, 0, 0, | |
| 343 | "Alias for --nmagic", nullptr, nullptr) | |
| 325 | 344 | OPTION(prefix_3, "oformat", oformat, Separate, INVALID, INVALID, nullptr, 0, 0, |
| 326 | 345 | "Specify the binary format for the output object file", "<format>", nullptr) |
| 327 | 346 | OPTION(prefix_3, "omagic", omagic, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 328 | "Set the text and data sections to be readable and writable", "<magic>", nullptr) | |
| 347 | "Set the text and data sections to be readable and writable, do not page align sections, link against static libraries", "<magic>", nullptr) | |
| 329 | 348 | OPTION(prefix_3, "opt-remarks-filename", opt_remarks_filename, Separate, INVALID, INVALID, nullptr, 0, 0, |
| 330 | 349 | "YAML output file for optimization remarks", nullptr, nullptr) |
| 350 | OPTION(prefix_3, "opt-remarks-format", opt_remarks_format, Separate, INVALID, INVALID, nullptr, 0, 0, | |
| 351 | "The format used for serializing remarks (default: YAML)", nullptr, nullptr) | |
| 352 | OPTION(prefix_3, "opt-remarks-passes", opt_remarks_passes, Separate, INVALID, INVALID, nullptr, 0, 0, | |
| 353 | "Regex for the passes that need to be serialized to the output file", nullptr, nullptr) | |
| 331 | 354 | OPTION(prefix_3, "opt-remarks-with-hotness", opt_remarks_with_hotness, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 332 | 355 | "Include hotness information in the optimization remarks file", nullptr, nullptr) |
| 333 | 356 | OPTION(prefix_2, "orphan-handling=", orphan_handling_eq, Joined, INVALID, orphan_handling, nullptr, 0, 0, |
| 334 | 357 | "Control how orphan sections are handled when linker script used", nullptr, nullptr) |
| 335 | 358 | OPTION(prefix_2, "orphan-handling", orphan_handling, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 336 | OPTION(prefix_3, "output=", anonymous_21, Joined, INVALID, o, nullptr, 0, 0, | |
| 359 | OPTION(prefix_3, "output=", anonymous_22, Joined, INVALID, o, nullptr, 0, 0, | |
| 337 | 360 | "Alias for -o", nullptr, nullptr) |
| 338 | OPTION(prefix_3, "output", anonymous_22, Separate, INVALID, o, nullptr, 0, 0, | |
| 361 | OPTION(prefix_3, "output", anonymous_23, Separate, INVALID, o, nullptr, 0, 0, | |
| 339 | 362 | "Alias for -o", nullptr, nullptr) |
| 340 | 363 | OPTION(prefix_1, "O", O, JoinedOrSeparate, INVALID, INVALID, nullptr, 0, 0, |
| 341 | 364 | "Optimize output file size", nullptr, nullptr) |
| 342 | 365 | OPTION(prefix_1, "o", o, JoinedOrSeparate, INVALID, INVALID, nullptr, 0, 0, |
| 343 | 366 | "Path to file to write output", "<path>", nullptr) |
| 367 | OPTION(prefix_2, "pac-plt", pac_plt, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 368 | "AArch64 only, use pointer authentication in PLT", nullptr, nullptr) | |
| 344 | 369 | OPTION(prefix_2, "pack-dyn-relocs=", pack_dyn_relocs_eq, Joined, INVALID, pack_dyn_relocs, nullptr, 0, 0, |
| 345 | 370 | "Pack dynamic relocations in the given format", "[none,android,relr,android+relr]", nullptr) |
| 346 | 371 | OPTION(prefix_2, "pack-dyn-relocs", pack_dyn_relocs, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, "[none,android,relr,android+relr]", nullptr) |
| 347 | OPTION(prefix_2, "pic-executable", anonymous_23, Flag, INVALID, pie, nullptr, 0, 0, | |
| 372 | OPTION(prefix_2, "pic-executable", anonymous_24, Flag, INVALID, pie, nullptr, 0, 0, | |
| 348 | 373 | "Alias for --pie", nullptr, nullptr) |
| 349 | 374 | OPTION(prefix_2, "pic-veneer", pic_veneer, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 350 | 375 | "Always generate position independent thunks (veneers)", nullptr, nullptr) |
| ... | ... | @@ -353,26 +378,30 @@ OPTION(prefix_2, "pie", pie, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 353 | 378 | OPTION(prefix_2, "plugin-opt=-fresolution=", plugin_opt_fresolution_eq, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 354 | 379 | OPTION(prefix_2, "plugin-opt=-pass-through=", plugin_opt_pass_through_eq, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 355 | 380 | OPTION(prefix_2, "plugin-opt=/", plugin_opt_slash, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 356 | OPTION(prefix_2, "plugin-opt=debug-pass-manager", anonymous_40, Flag, INVALID, lto_debug_pass_manager, nullptr, 0, 0, | |
| 381 | OPTION(prefix_2, "plugin-opt=cs-profile-generate", anonymous_46, Flag, INVALID, lto_cs_profile_generate, nullptr, 0, 0, | |
| 382 | "Alias for -lto-cs-profile-generate", nullptr, nullptr) | |
| 383 | OPTION(prefix_2, "plugin-opt=cs-profile-path=", anonymous_47, Joined, INVALID, lto_cs_profile_file, nullptr, 0, 0, | |
| 384 | "Alias for -lto-cs-profile-file", nullptr, nullptr) | |
| 385 | OPTION(prefix_2, "plugin-opt=debug-pass-manager", anonymous_41, Flag, INVALID, lto_debug_pass_manager, nullptr, 0, 0, | |
| 357 | 386 | "Alias for -lto-debug-pass-manager", nullptr, nullptr) |
| 358 | OPTION(prefix_2, "plugin-opt=disable-verify", anonymous_41, Flag, INVALID, disable_verify, nullptr, 0, 0, | |
| 387 | OPTION(prefix_2, "plugin-opt=disable-verify", anonymous_42, Flag, INVALID, disable_verify, nullptr, 0, 0, | |
| 359 | 388 | "Alias for -disable-verify", nullptr, nullptr) |
| 360 | 389 | OPTION(prefix_2, "plugin-opt=dwo_dir=", plugin_opt_dwo_dir_eq, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 361 | 390 | "Directory to store .dwo files when LTO and debug fission are used", nullptr, nullptr) |
| 362 | 391 | OPTION(prefix_2, "plugin-opt=emit-llvm", plugin_opt_emit_llvm, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 363 | OPTION(prefix_2, "plugin-opt=jobs=", anonymous_42, Joined, INVALID, thinlto_jobs, nullptr, 0, 0, | |
| 392 | OPTION(prefix_2, "plugin-opt=jobs=", anonymous_43, Joined, INVALID, thinlto_jobs, nullptr, 0, 0, | |
| 364 | 393 | "Alias for -thinlto-jobs", nullptr, nullptr) |
| 365 | OPTION(prefix_2, "plugin-opt=lto-partitions=", anonymous_43, Joined, INVALID, lto_partitions, nullptr, 0, 0, | |
| 394 | OPTION(prefix_2, "plugin-opt=lto-partitions=", anonymous_44, Joined, INVALID, lto_partitions, nullptr, 0, 0, | |
| 366 | 395 | "Alias for -lto-partitions", nullptr, nullptr) |
| 367 | 396 | OPTION(prefix_2, "plugin-opt=mcpu=", plugin_opt_mcpu_eq, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 368 | OPTION(prefix_2, "plugin-opt=new-pass-manager", anonymous_44, Flag, INVALID, lto_new_pass_manager, nullptr, 0, 0, | |
| 397 | OPTION(prefix_2, "plugin-opt=new-pass-manager", anonymous_45, Flag, INVALID, lto_new_pass_manager, nullptr, 0, 0, | |
| 369 | 398 | "Alias for -lto-new-pass-manager", nullptr, nullptr) |
| 370 | 399 | OPTION(prefix_2, "plugin-opt=obj-path=", plugin_opt_obj_path_eq, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 371 | OPTION(prefix_2, "plugin-opt=O", anonymous_39, Joined, INVALID, lto_O, nullptr, 0, 0, | |
| 400 | OPTION(prefix_2, "plugin-opt=O", anonymous_40, Joined, INVALID, lto_O, nullptr, 0, 0, | |
| 372 | 401 | "Alias for -lto-O", nullptr, nullptr) |
| 373 | OPTION(prefix_2, "plugin-opt=sample-profile=", anonymous_45, Joined, INVALID, lto_sample_profile, nullptr, 0, 0, | |
| 402 | OPTION(prefix_2, "plugin-opt=sample-profile=", anonymous_48, Joined, INVALID, lto_sample_profile, nullptr, 0, 0, | |
| 374 | 403 | "Alias for -lto-sample-profile", nullptr, nullptr) |
| 375 | OPTION(prefix_2, "plugin-opt=save-temps", anonymous_46, Flag, INVALID, save_temps, nullptr, 0, 0, | |
| 404 | OPTION(prefix_2, "plugin-opt=save-temps", anonymous_49, Flag, INVALID, save_temps, nullptr, 0, 0, | |
| 376 | 405 | "Alias for -save-temps", nullptr, nullptr) |
| 377 | 406 | OPTION(prefix_2, "plugin-opt=thinlto-emit-imports-files", plugin_opt_thinlto_emit_imports_files, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 378 | 407 | OPTION(prefix_2, "plugin-opt=thinlto-index-only=", plugin_opt_thinlto_index_only_eq, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| ... | ... | @@ -394,9 +423,13 @@ OPTION(prefix_2, "print-icf-sections", print_icf_sections, Flag, INVALID, INVALI |
| 394 | 423 | "List identical folded sections", nullptr, nullptr) |
| 395 | 424 | OPTION(prefix_2, "print-map", print_map, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 396 | 425 | "Print a link map to the standard output", nullptr, nullptr) |
| 426 | OPTION(prefix_2, "print-symbol-order=", print_symbol_order_eq, Joined, INVALID, print_symbol_order, nullptr, 0, 0, | |
| 427 | "Print a symbol order specified by --call-graph-ordering-file into the speficied file", nullptr, nullptr) | |
| 428 | OPTION(prefix_2, "print-symbol-order", print_symbol_order, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 397 | 429 | OPTION(prefix_2, "push-state", push_state, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 398 | 430 | "Save the current state of -as-needed, -static and -whole-archive", nullptr, nullptr) |
| 399 | OPTION(prefix_2, "Qy", anonymous_68, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 431 | OPTION(prefix_1, "p", anonymous_60, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 432 | OPTION(prefix_2, "Qy", anonymous_72, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 400 | 433 | OPTION(prefix_1, "q", anonymous_11, Flag, INVALID, emit_relocs, nullptr, 0, 0, |
| 401 | 434 | "Alias for --emit-relocs", nullptr, nullptr) |
| 402 | 435 | OPTION(prefix_2, "relocatable", relocatable, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -404,20 +437,21 @@ OPTION(prefix_2, "relocatable", relocatable, Flag, INVALID, INVALID, nullptr, 0, |
| 404 | 437 | OPTION(prefix_2, "reproduce=", reproduce_eq, Joined, INVALID, reproduce, nullptr, 0, 0, |
| 405 | 438 | "Dump linker invocation and input files for debugging", nullptr, nullptr) |
| 406 | 439 | OPTION(prefix_2, "reproduce", reproduce, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 440 | OPTION(prefix_2, "require-cet", require_cet, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 407 | 441 | OPTION(prefix_2, "retain-symbols-file=", retain_symbols_file_eq, Joined, INVALID, retain_symbols_file, nullptr, 0, 0, |
| 408 | 442 | "Retain only the symbols listed in the file", "<file>", nullptr) |
| 409 | 443 | OPTION(prefix_2, "retain-symbols-file", retain_symbols_file, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, "<file>", nullptr) |
| 410 | OPTION(prefix_2, "rpath-link=", anonymous_59, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 411 | OPTION(prefix_2, "rpath-link", anonymous_58, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 444 | OPTION(prefix_2, "rpath-link=", anonymous_62, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 445 | OPTION(prefix_2, "rpath-link", anonymous_61, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 412 | 446 | OPTION(prefix_2, "rpath=", rpath_eq, Joined, INVALID, rpath, nullptr, 0, 0, |
| 413 | 447 | "Add a DT_RUNPATH to the output", nullptr, nullptr) |
| 414 | 448 | OPTION(prefix_2, "rpath", rpath, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 415 | 449 | OPTION(prefix_2, "rsp-quoting=", rsp_quoting_eq, Joined, INVALID, rsp_quoting, nullptr, 0, 0, |
| 416 | 450 | "Quoting style for response files", "[posix,windows]", nullptr) |
| 417 | 451 | OPTION(prefix_2, "rsp-quoting", rsp_quoting, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, "[posix,windows]", nullptr) |
| 418 | OPTION(prefix_1, "R", anonymous_26, JoinedOrSeparate, INVALID, rpath, nullptr, 0, 0, | |
| 452 | OPTION(prefix_1, "R", anonymous_27, JoinedOrSeparate, INVALID, rpath, nullptr, 0, 0, | |
| 419 | 453 | "Alias for --rpath", nullptr, nullptr) |
| 420 | OPTION(prefix_1, "r", anonymous_25, Flag, INVALID, relocatable, nullptr, 0, 0, | |
| 454 | OPTION(prefix_1, "r", anonymous_26, Flag, INVALID, relocatable, nullptr, 0, 0, | |
| 421 | 455 | "Alias for --relocatable", nullptr, nullptr) |
| 422 | 456 | OPTION(prefix_2, "save-temps", save_temps, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 423 | 457 | OPTION(prefix_2, "script=", script_eq, Joined, INVALID, script, nullptr, 0, 0, |
| ... | ... | @@ -426,12 +460,13 @@ OPTION(prefix_2, "script", script, Separate, INVALID, INVALID, nullptr, 0, 0, nu |
| 426 | 460 | OPTION(prefix_2, "section-start=", section_start_eq, Joined, INVALID, section_start, nullptr, 0, 0, |
| 427 | 461 | "Set address of section", "<address>", nullptr) |
| 428 | 462 | OPTION(prefix_2, "section-start", section_start, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, "<address>", nullptr) |
| 463 | OPTION(prefix_2, "secure-plt", anonymous_63, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 429 | 464 | OPTION(prefix_2, "shared", shared, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 430 | 465 | "Build a shared object", nullptr, nullptr) |
| 431 | 466 | OPTION(prefix_2, "soname=", soname_eq, Joined, INVALID, soname, nullptr, 0, 0, |
| 432 | 467 | "Set DT_SONAME", nullptr, nullptr) |
| 433 | 468 | OPTION(prefix_2, "soname", soname, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 434 | OPTION(prefix_2, "sort-common", anonymous_60, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 469 | OPTION(prefix_2, "sort-common", anonymous_64, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 435 | 470 | OPTION(prefix_2, "sort-section=", sort_section_eq, Joined, INVALID, sort_section, nullptr, 0, 0, |
| 436 | 471 | "Specifies sections sorting rule when linkerscript is used", nullptr, nullptr) |
| 437 | 472 | OPTION(prefix_2, "sort-section", sort_section, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| ... | ... | @@ -444,7 +479,7 @@ OPTION(prefix_2, "start-lib", start_lib, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 444 | 479 | "Start a grouping of objects that should be treated as if they were together in an archive", nullptr, nullptr) |
| 445 | 480 | OPTION(prefix_2, "static", anonymous_5, Flag, INVALID, Bstatic, nullptr, 0, 0, |
| 446 | 481 | "Alias for --Bstatic", nullptr, nullptr) |
| 447 | OPTION(prefix_2, "stats", anonymous_61, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 482 | OPTION(prefix_2, "stats", anonymous_65, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 448 | 483 | OPTION(prefix_2, "strip-all", strip_all, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 449 | 484 | "Strip all symbols", nullptr, nullptr) |
| 450 | 485 | OPTION(prefix_2, "strip-debug", strip_debug, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -455,9 +490,9 @@ OPTION(prefix_2, "symbol-ordering-file", symbol_ordering_file, Separate, INVALID |
| 455 | 490 | OPTION(prefix_2, "sysroot=", sysroot_eq, Joined, INVALID, sysroot, nullptr, 0, 0, |
| 456 | 491 | "Set the system root", nullptr, nullptr) |
| 457 | 492 | OPTION(prefix_2, "sysroot", sysroot, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 458 | OPTION(prefix_1, "S", anonymous_32, Flag, INVALID, strip_debug, nullptr, 0, 0, | |
| 493 | OPTION(prefix_1, "S", anonymous_33, Flag, INVALID, strip_debug, nullptr, 0, 0, | |
| 459 | 494 | "Alias for --strip-debug", nullptr, nullptr) |
| 460 | OPTION(prefix_1, "s", anonymous_31, Flag, INVALID, strip_all, nullptr, 0, 0, | |
| 495 | OPTION(prefix_1, "s", anonymous_32, Flag, INVALID, strip_all, nullptr, 0, 0, | |
| 461 | 496 | "Alias for --strip-all", nullptr, nullptr) |
| 462 | 497 | OPTION(prefix_2, "target1-abs", target1_abs, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 463 | 498 | "Interpret R_ARM_TARGET1 as R_ARM_ABS32 (default)", nullptr, nullptr) |
| ... | ... | @@ -488,17 +523,20 @@ OPTION(prefix_2, "trace-symbol=", trace_symbol_eq, Joined, INVALID, trace_symbol |
| 488 | 523 | OPTION(prefix_2, "trace-symbol", trace_symbol, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 489 | 524 | OPTION(prefix_2, "trace", trace, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 490 | 525 | "Print the names of the input files", nullptr, nullptr) |
| 491 | OPTION(prefix_4, "Ttext-segment=", anonymous_36, Joined, INVALID, Ttext, nullptr, 0, 0, | |
| 526 | OPTION(prefix_4, "Ttext-segment=", anonymous_37, Joined, INVALID, Ttext, nullptr, 0, 0, | |
| 492 | 527 | "Alias for --Ttext", nullptr, nullptr) |
| 493 | OPTION(prefix_4, "Ttext-segment", anonymous_35, Separate, INVALID, Ttext, nullptr, 0, 0, | |
| 528 | OPTION(prefix_4, "Ttext-segment", anonymous_36, Separate, INVALID, Ttext, nullptr, 0, 0, | |
| 494 | 529 | "Alias for --Ttext", nullptr, nullptr) |
| 495 | 530 | OPTION(prefix_2, "Ttext=", Ttext_eq, Joined, INVALID, Ttext, nullptr, 0, 0, |
| 496 | 531 | "Same as --section-start with .text as the sectionname", nullptr, nullptr) |
| 497 | 532 | OPTION(prefix_2, "Ttext", Ttext, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 498 | OPTION(prefix_1, "T", anonymous_27, JoinedOrSeparate, INVALID, script, nullptr, 0, 0, | |
| 533 | OPTION(prefix_1, "T", anonymous_28, JoinedOrSeparate, INVALID, script, nullptr, 0, 0, | |
| 499 | 534 | "Alias for --script", nullptr, nullptr) |
| 500 | OPTION(prefix_1, "t", anonymous_33, Flag, INVALID, trace, nullptr, 0, 0, | |
| 535 | OPTION(prefix_1, "t", anonymous_34, Flag, INVALID, trace, nullptr, 0, 0, | |
| 501 | 536 | "Alias for --trace", nullptr, nullptr) |
| 537 | OPTION(prefix_2, "undefined-glob=", undefined_glob_eq, Joined, INVALID, undefined_glob, nullptr, 0, 0, | |
| 538 | "Force undefined symbol during linking", "<pattern>", nullptr) | |
| 539 | OPTION(prefix_2, "undefined-glob", undefined_glob, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, "<pattern>", nullptr) | |
| 502 | 540 | OPTION(prefix_2, "undefined-version", undefined_version, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 503 | 541 | "Allow unused version in version script (default)", nullptr, nullptr) |
| 504 | 542 | OPTION(prefix_2, "undefined=", undefined_eq, Joined, INVALID, undefined, nullptr, 0, 0, |
| ... | ... | @@ -509,7 +547,7 @@ OPTION(prefix_2, "unresolved-symbols=", unresolved_symbols_eq, Joined, INVALID, |
| 509 | 547 | OPTION(prefix_2, "unresolved-symbols", unresolved_symbols, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 510 | 548 | OPTION(prefix_2, "use-android-relr-tags", use_android_relr_tags, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 511 | 549 | "Use SHT_ANDROID_RELR / DT_ANDROID_RELR* tags instead of SHT_RELR / DT_RELR*", nullptr, nullptr) |
| 512 | OPTION(prefix_1, "u", anonymous_37, JoinedOrSeparate, INVALID, undefined, nullptr, 0, 0, | |
| 550 | OPTION(prefix_1, "u", anonymous_38, JoinedOrSeparate, INVALID, undefined, nullptr, 0, 0, | |
| 513 | 551 | "Alias for --undefined", nullptr, nullptr) |
| 514 | 552 | OPTION(prefix_2, "verbose", verbose, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 515 | 553 | "Verbose mode", nullptr, nullptr) |
| ... | ... | @@ -518,7 +556,9 @@ OPTION(prefix_2, "version-script=", version_script_eq, Joined, INVALID, version_ |
| 518 | 556 | OPTION(prefix_2, "version-script", version_script, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 519 | 557 | OPTION(prefix_2, "version", version, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 520 | 558 | "Display the version number and exit", nullptr, nullptr) |
| 521 | OPTION(prefix_1, "V", anonymous_38, Flag, INVALID, version, nullptr, 0, 0, | |
| 559 | OPTION(prefix_2, "vs-diagnostics", visual_studio_diagnostics_format, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 560 | "Format diagnostics for Visual Studio compatiblity", nullptr, nullptr) | |
| 561 | OPTION(prefix_1, "V", anonymous_39, Flag, INVALID, version, nullptr, 0, 0, | |
| 522 | 562 | "Alias for --version", nullptr, nullptr) |
| 523 | 563 | OPTION(prefix_1, "v", v, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 524 | 564 | "Display the version number", nullptr, nullptr) |
| ... | ... | @@ -526,11 +566,11 @@ OPTION(prefix_2, "warn-backrefs", warn_backrefs, Flag, INVALID, INVALID, nullptr |
| 526 | 566 | "Warn about backward symbol references to fetch archive members", nullptr, nullptr) |
| 527 | 567 | OPTION(prefix_2, "warn-common", warn_common, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 528 | 568 | "Warn about duplicate common symbols", nullptr, nullptr) |
| 529 | OPTION(prefix_2, "warn-execstack", anonymous_62, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 569 | OPTION(prefix_2, "warn-execstack", anonymous_66, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 530 | 570 | OPTION(prefix_2, "warn-ifunc-textrel", warn_ifunc_textrel, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 531 | 571 | "Warn about using ifunc symbols with text relocations", nullptr, nullptr) |
| 532 | OPTION(prefix_2, "warn-once", anonymous_63, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 533 | OPTION(prefix_2, "warn-shared-textrel", anonymous_64, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 572 | OPTION(prefix_2, "warn-once", anonymous_67, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 573 | OPTION(prefix_2, "warn-shared-textrel", anonymous_68, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 534 | 574 | OPTION(prefix_2, "warn-symbol-ordering", warn_symbol_ordering, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 535 | 575 | "Warn about problems with the symbol ordering file (default)", nullptr, nullptr) |
| 536 | 576 | OPTION(prefix_2, "warn-unresolved-symbols", warn_unresolved_symbols, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -544,7 +584,7 @@ OPTION(prefix_1, "X", anonymous_10, Flag, INVALID, discard_locals, nullptr, 0, 0 |
| 544 | 584 | "Alias for --discard-locals", nullptr, nullptr) |
| 545 | 585 | OPTION(prefix_1, "x", anonymous_9, Flag, INVALID, discard_all, nullptr, 0, 0, |
| 546 | 586 | "Alias for --discard-all", nullptr, nullptr) |
| 547 | OPTION(prefix_1, "y", anonymous_34, JoinedOrSeparate, INVALID, trace_symbol, nullptr, 0, 0, | |
| 587 | OPTION(prefix_1, "y", anonymous_35, JoinedOrSeparate, INVALID, trace_symbol, nullptr, 0, 0, | |
| 548 | 588 | "Alias for --trace-symbol", nullptr, nullptr) |
| 549 | 589 | OPTION(prefix_1, "z", z, JoinedOrSeparate, INVALID, INVALID, nullptr, 0, 0, |
| 550 | 590 | "Linker option extensions", "<option>", nullptr) |
deps/lld-prebuilt/MinGW/Options.inc+50-26| ... | ... | @@ -30,31 +30,39 @@ OPTION(prefix_0, "<input>", INPUT, Input, INVALID, INVALID, nullptr, 0, 0, nullp |
| 30 | 30 | OPTION(prefix_0, "<unknown>", UNKNOWN, Unknown, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 31 | 31 | OPTION(prefix_1, "###", _HASH_HASH_HASH, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 32 | 32 | "Print (but do not run) the commands to run for this compilation", nullptr, nullptr) |
| 33 | OPTION(prefix_2, "appcontainer", appcontainer, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 34 | "Set the appcontainer flag in the executable", nullptr, nullptr) | |
| 33 | 35 | OPTION(prefix_2, "Bdynamic", Bdynamic, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 34 | 36 | "Link against shared libraries", nullptr, nullptr) |
| 35 | 37 | OPTION(prefix_2, "Bstatic", Bstatic, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 36 | 38 | "Do not link against shared libraries", nullptr, nullptr) |
| 37 | OPTION(prefix_2, "build-id", build_id, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 38 | OPTION(prefix_2, "disable-auto-image-base", disable_auto_image_base, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 39 | OPTION(prefix_2, "build-id", anonymous_1, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 40 | OPTION(prefix_2, "disable-auto-image-base", anonymous_2, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 39 | 41 | OPTION(prefix_2, "dynamicbase", dynamicbase, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 40 | 42 | "Enable ASLR", nullptr, nullptr) |
| 41 | OPTION(prefix_2, "enable-auto-image-base", enable_auto_image_base, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 42 | OPTION(prefix_2, "enable-auto-import", enable_auto_import, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 43 | OPTION(prefix_2, "end-group", end_group, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 43 | OPTION(prefix_2, "enable-auto-image-base", anonymous_3, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 44 | OPTION(prefix_2, "enable-auto-import", anonymous_4, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 45 | "Ignored; listed for libtool compatibility", nullptr, nullptr) | |
| 46 | OPTION(prefix_2, "end-group", anonymous_5, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 44 | 47 | OPTION(prefix_2, "entry", entry, Separate, INVALID, INVALID, nullptr, 0, 0, |
| 45 | 48 | "Name of entry point symbol", "<entry>", nullptr) |
| 49 | OPTION(prefix_2, "exclude-all-symbols", exclude_all_symbols, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 50 | "Don't automatically export any symbols", nullptr, nullptr) | |
| 46 | 51 | OPTION(prefix_2, "export-all-symbols", export_all_symbols, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 47 | 52 | "Export all symbols even if a def file or dllexport attributes are used", nullptr, nullptr) |
| 48 | 53 | OPTION(prefix_1, "e", alias_entry_e, JoinedOrSeparate, INVALID, entry, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 49 | OPTION(prefix_3, "full-shutdown", full_shutdown, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 54 | OPTION(prefix_3, "full-shutdown", anonymous_6, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 50 | 55 | OPTION(prefix_2, "gc-sections", gc_sections, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 51 | 56 | "Remove unused sections", nullptr, nullptr) |
| 52 | OPTION(prefix_2, "high-entropy-va", high_entropy_va, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 53 | "Enable 64-bit ASLR", nullptr, nullptr) | |
| 57 | OPTION(prefix_2, "help", help, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 58 | "Print option help", nullptr, nullptr) | |
| 59 | OPTION(prefix_2, "high-entropy-va", anonymous_7, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 54 | 60 | OPTION(prefix_2, "icf=", icf, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 55 | 61 | "Identical code folding", nullptr, nullptr) |
| 56 | 62 | OPTION(prefix_2, "image-base", image_base, Separate, INVALID, INVALID, nullptr, 0, 0, |
| 57 | 63 | "Base address of the program", nullptr, nullptr) |
| 64 | OPTION(prefix_2, "insert-timestamp", insert_timestamp, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 65 | "Include PE header timestamp", nullptr, nullptr) | |
| 58 | 66 | OPTION(prefix_2, "kill-at", kill_at, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 59 | 67 | "Remove @n from exported symbols", nullptr, nullptr) |
| 60 | 68 | OPTION(prefix_3, "large-address-aware", large_address_aware, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -63,56 +71,72 @@ OPTION(prefix_1, "L", L, JoinedOrSeparate, INVALID, INVALID, nullptr, 0, 0, |
| 63 | 71 | "Add a directory to the library search path", "<dir>", nullptr) |
| 64 | 72 | OPTION(prefix_1, "l", l, JoinedOrSeparate, INVALID, INVALID, nullptr, 0, 0, |
| 65 | 73 | "Root name of library to use", "<libName>", nullptr) |
| 66 | OPTION(prefix_2, "major-image-version", major_image_version, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 74 | OPTION(prefix_2, "major-image-version", anonymous_8, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 75 | OPTION(prefix_3, "major-os-version=", major_os_version_eq, Joined, INVALID, major_os_version, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 76 | OPTION(prefix_3, "major-os-version", major_os_version, Separate, INVALID, INVALID, nullptr, 0, 0, | |
| 77 | "Set the OS and subsystem major version", nullptr, nullptr) | |
| 78 | OPTION(prefix_3, "major-subsystem-version=", major_subsystem_version_eq, Joined, INVALID, major_subsystem_version, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 79 | OPTION(prefix_3, "major-subsystem-version", major_subsystem_version, Separate, INVALID, INVALID, nullptr, 0, 0, | |
| 80 | "Set the OS and subsystem major version", nullptr, nullptr) | |
| 67 | 81 | OPTION(prefix_2, "Map=", map_eq, Joined, INVALID, map, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 68 | 82 | OPTION(prefix_2, "Map", map, Separate, INVALID, INVALID, nullptr, 0, 0, |
| 69 | 83 | "Output a linker map", nullptr, nullptr) |
| 70 | OPTION(prefix_2, "minor-image-version", minor_image_version, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 84 | OPTION(prefix_2, "minor-image-version", anonymous_9, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 85 | OPTION(prefix_3, "minor-os-version=", minor_os_version_eq, Joined, INVALID, minor_os_version, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 86 | OPTION(prefix_3, "minor-os-version", minor_os_version, Separate, INVALID, INVALID, nullptr, 0, 0, | |
| 87 | "Set the OS and subsystem minor version", nullptr, nullptr) | |
| 88 | OPTION(prefix_3, "minor-subsystem-version=", minor_subsystem_version_eq, Joined, INVALID, minor_subsystem_version, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 89 | OPTION(prefix_3, "minor-subsystem-version", minor_subsystem_version, Separate, INVALID, INVALID, nullptr, 0, 0, | |
| 90 | "Set the OS and subsystem minor version", nullptr, nullptr) | |
| 71 | 91 | OPTION(prefix_2, "mllvm", mllvm, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 72 | 92 | OPTION(prefix_1, "m", m, JoinedOrSeparate, INVALID, INVALID, nullptr, 0, 0, |
| 73 | 93 | "Set target emulation", nullptr, nullptr) |
| 74 | 94 | OPTION(prefix_2, "no-gc-sections", no_gc_sections, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 75 | 95 | "Don't remove unused sections", nullptr, nullptr) |
| 76 | OPTION(prefix_2, "no-seh", no_seh, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 96 | OPTION(prefix_2, "no-insert-timestamp", no_insert_timestamp, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 97 | "Don't include PE header timestamp", nullptr, nullptr) | |
| 98 | OPTION(prefix_2, "no-seh", anonymous_10, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 77 | 99 | OPTION(prefix_2, "no-whole-archive", no_whole_archive, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 78 | 100 | "No longer include all object files for following archives", nullptr, nullptr) |
| 79 | OPTION(prefix_2, "nxcompat", nxcompat, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 80 | "Enable data execution prevention", nullptr, nullptr) | |
| 101 | OPTION(prefix_2, "nxcompat", anonymous_11, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 81 | 102 | OPTION(prefix_3, "out-implib=", out_implib_eq, Joined, INVALID, out_implib, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 82 | 103 | OPTION(prefix_3, "out-implib", out_implib, Separate, INVALID, INVALID, nullptr, 0, 0, |
| 83 | 104 | "Import library name", nullptr, nullptr) |
| 84 | 105 | OPTION(prefix_2, "output-def", output_def, Separate, INVALID, INVALID, nullptr, 0, 0, |
| 85 | 106 | "Output def file", nullptr, nullptr) |
| 86 | OPTION(prefix_1, "O", O, Joined, INVALID, INVALID, nullptr, 0, 0, | |
| 87 | "Optimize output file size", nullptr, nullptr) | |
| 107 | OPTION(prefix_1, "O", anonymous_0, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 88 | 108 | OPTION(prefix_1, "o", o, JoinedOrSeparate, INVALID, INVALID, nullptr, 0, 0, |
| 89 | 109 | "Path to file to write output", "<path>", nullptr) |
| 110 | OPTION(prefix_2, "pdb=", pdb_eq, Joined, INVALID, pdb, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 90 | 111 | OPTION(prefix_2, "pdb", pdb, Separate, INVALID, INVALID, nullptr, 0, 0, |
| 91 | "Specify output PDB debug information file", nullptr, nullptr) | |
| 92 | OPTION(prefix_2, "pic-executable", pic_executable, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 93 | OPTION(prefix_2, "plugin-opt=", anonymous_3, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 94 | OPTION(prefix_2, "plugin-opt", anonymous_2, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 95 | OPTION(prefix_2, "plugin=", anonymous_1, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 96 | OPTION(prefix_2, "plugin", anonymous_0, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 112 | "Output PDB debug info file, chosen implicitly if the argument is empty", nullptr, nullptr) | |
| 113 | OPTION(prefix_2, "pic-executable", anonymous_12, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 114 | OPTION(prefix_2, "plugin-opt=", anonymous_16, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 115 | OPTION(prefix_2, "plugin-opt", anonymous_15, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 116 | OPTION(prefix_2, "plugin=", anonymous_14, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 117 | OPTION(prefix_2, "plugin", anonymous_13, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 97 | 118 | OPTION(prefix_2, "require-defined=", require_defined_eq, Joined, INVALID, require_defined, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 98 | 119 | OPTION(prefix_2, "require-defined", require_defined, Separate, INVALID, INVALID, nullptr, 0, 0, |
| 99 | 120 | "Force symbol to be added to symbol table as an undefined one", nullptr, nullptr) |
| 100 | 121 | OPTION(prefix_2, "shared", shared, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 101 | 122 | "Build a shared object", nullptr, nullptr) |
| 102 | 123 | OPTION(prefix_2, "stack", stack, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 103 | OPTION(prefix_2, "start-group", start_group, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 124 | OPTION(prefix_2, "start-group", anonymous_18, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 104 | 125 | OPTION(prefix_2, "strip-all", strip_all, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 105 | 126 | "Omit all symbol information from the output binary", nullptr, nullptr) |
| 106 | 127 | OPTION(prefix_2, "strip-debug", strip_debug, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 107 | 128 | "Omit all debug information, but keep symbol information", nullptr, nullptr) |
| 129 | OPTION(prefix_2, "subsystem=", subs_eq, Joined, INVALID, subs, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 108 | 130 | OPTION(prefix_2, "subsystem", subs, Separate, INVALID, INVALID, nullptr, 0, 0, |
| 109 | 131 | "Specify subsystem", nullptr, nullptr) |
| 110 | OPTION(prefix_2, "sysroot", sysroot, Joined, INVALID, INVALID, nullptr, 0, 0, | |
| 111 | "Sysroot", nullptr, nullptr) | |
| 132 | OPTION(prefix_2, "sysroot", anonymous_17, Joined, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 112 | 133 | OPTION(prefix_1, "S", alias_strip_S, Flag, INVALID, strip_debug, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 113 | 134 | OPTION(prefix_1, "s", alias_strip_s, Flag, INVALID, strip_all, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 114 | OPTION(prefix_2, "tsaware", tsaware, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 115 | "Create Terminal Server aware executable", nullptr, nullptr) | |
| 135 | OPTION(prefix_2, "tsaware", anonymous_19, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 136 | OPTION(prefix_2, "undefined=", undefined_eq, Joined, INVALID, undefined, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 137 | OPTION(prefix_2, "undefined", undefined_long, Separate, INVALID, undefined, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 138 | OPTION(prefix_2, "u", undefined, Separate, INVALID, INVALID, nullptr, 0, 0, | |
| 139 | "Include symbol in the link, if available", nullptr, nullptr) | |
| 116 | 140 | OPTION(prefix_2, "verbose", verbose, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 117 | 141 | "Verbose mode", nullptr, nullptr) |
| 118 | 142 | OPTION(prefix_2, "version", version, Flag, INVALID, INVALID, nullptr, 0, 0, |
deps/lld-prebuilt/lld/Common/Version.inc+3-3| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | #define LLD_VERSION 8.0.0 | |
| 2 | #define LLD_VERSION_STRING "8.0.0" | |
| 3 | #define LLD_VERSION_MAJOR 8 | |
| 1 | #define LLD_VERSION 9.0.0 | |
| 2 | #define LLD_VERSION_STRING "9.0.0" | |
| 3 | #define LLD_VERSION_MAJOR 9 | |
| 4 | 4 | #define LLD_VERSION_MINOR 0 |
| 5 | 5 | #define LLD_REVISION_STRING "" |
| 6 | 6 | #define LLD_REPOSITORY_STRING "" |
deps/lld-prebuilt/wasm/Options.inc+28-1| ... | ... | @@ -27,11 +27,15 @@ PREFIX(prefix_1, {"--" COMMA "-" COMMA nullptr}) |
| 27 | 27 | |
| 28 | 28 | OPTION(prefix_0, "<input>", INPUT, Input, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 29 | 29 | OPTION(prefix_0, "<unknown>", UNKNOWN, Unknown, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 30 | OPTION(prefix_1, "active-segments", active_segments, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 31 | "Force segments to be active (default with unshared memory)", nullptr, nullptr) | |
| 30 | 32 | OPTION(prefix_1, "allow-undefined-file=", allow_undefined_file, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 31 | 33 | "Allow symbols listed in <file> to be undefined in linked binary", nullptr, nullptr) |
| 32 | 34 | OPTION(prefix_2, "allow-undefined-file", allow_undefined_file_s, Separate, INVALID, allow_undefined_file, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 33 | 35 | OPTION(prefix_1, "allow-undefined", allow_undefined, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 34 | 36 | "Allow undefined symbols in linked binary", nullptr, nullptr) |
| 37 | OPTION(prefix_1, "check-features", check_features, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 38 | "Check feature compatibility of linked objects (default)", nullptr, nullptr) | |
| 35 | 39 | OPTION(prefix_1, "color-diagnostics=", color_diagnostics_eq, Joined, INVALID, INVALID, nullptr, 0, 0, |
| 36 | 40 | "Use colors in diagnostics; one of 'always', 'never', 'auto'", nullptr, nullptr) |
| 37 | 41 | OPTION(prefix_1, "color-diagnostics", color_diagnostics, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -41,6 +45,8 @@ OPTION(prefix_1, "compress-relocations", compress_relocations, Flag, INVALID, IN |
| 41 | 45 | OPTION(prefix_1, "demangle", demangle, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 42 | 46 | "Demangle symbol names", nullptr, nullptr) |
| 43 | 47 | OPTION(prefix_1, "disable-verify", disable_verify, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 48 | OPTION(prefix_1, "emit-relocs", emit_relocs, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 49 | "Generate relocations in output", nullptr, nullptr) | |
| 44 | 50 | OPTION(prefix_1, "entry=", anonymous_1, Joined, INVALID, entry, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 45 | 51 | OPTION(prefix_1, "entry", entry, Separate, INVALID, INVALID, nullptr, 0, 0, |
| 46 | 52 | "Name of entry point symbol", "<entry>", nullptr) |
| ... | ... | @@ -60,6 +66,8 @@ OPTION(prefix_2, "E", anonymous_2, Flag, INVALID, export_dynamic, nullptr, 0, 0, |
| 60 | 66 | OPTION(prefix_2, "e", anonymous_0, JoinedOrSeparate, INVALID, entry, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 61 | 67 | OPTION(prefix_1, "fatal-warnings", fatal_warnings, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 62 | 68 | "Treat warnings as errors", nullptr, nullptr) |
| 69 | OPTION(prefix_1, "features=", features, CommaJoined, INVALID, INVALID, nullptr, 0, 0, | |
| 70 | "Comma-separated used features, inferred from input objects by default.", nullptr, nullptr) | |
| 63 | 71 | OPTION(prefix_1, "gc-sections", gc_sections, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 64 | 72 | "Enable garbage collection of unused sections", nullptr, nullptr) |
| 65 | 73 | OPTION(prefix_1, "global-base=", global_base, Joined, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -88,6 +96,8 @@ OPTION(prefix_1, "merge-data-segments", merge_data_segments, Flag, INVALID, INVA |
| 88 | 96 | OPTION(prefix_1, "mllvm", mllvm, Separate, INVALID, INVALID, nullptr, 0, 0, |
| 89 | 97 | "Options to pass to LLVM", nullptr, nullptr) |
| 90 | 98 | OPTION(prefix_2, "m", anonymous_4, Flag, INVALID, max_memory, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 99 | OPTION(prefix_1, "no-check-features", no_check_features, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 100 | "Ignore feature compatibility of linked objects", nullptr, nullptr) | |
| 91 | 101 | OPTION(prefix_1, "no-color-diagnostics", no_color_diagnostics, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 92 | 102 | "Do not use colors in diagnostics", nullptr, nullptr) |
| 93 | 103 | OPTION(prefix_1, "no-demangle", no_demangle, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -113,12 +123,17 @@ OPTION(prefix_2, "O", O, JoinedOrSeparate, INVALID, INVALID, nullptr, 0, 0, |
| 113 | 123 | "Optimize output file size", nullptr, nullptr) |
| 114 | 124 | OPTION(prefix_2, "o", o, JoinedOrSeparate, INVALID, INVALID, nullptr, 0, 0, |
| 115 | 125 | "Path to file to write output", "<path>", nullptr) |
| 126 | OPTION(prefix_1, "passive-segments", passive_segments, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 127 | "Force segments to be passive (default with shared memory)", nullptr, nullptr) | |
| 116 | 128 | OPTION(prefix_1, "pie", pie, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 117 | 129 | "Create a position independent executable", nullptr, nullptr) |
| 118 | 130 | OPTION(prefix_1, "print-gc-sections", print_gc_sections, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 119 | 131 | "List removed unused sections", nullptr, nullptr) |
| 120 | 132 | OPTION(prefix_1, "relocatable", relocatable, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 121 | 133 | "Create relocatable object file", nullptr, nullptr) |
| 134 | OPTION(prefix_1, "reproduce=", reproduce_eq, Joined, INVALID, reproduce, nullptr, 0, 0, | |
| 135 | "Dump linker invocation and input files for debugging", nullptr, nullptr) | |
| 136 | OPTION(prefix_1, "reproduce", reproduce, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 122 | 137 | OPTION(prefix_2, "r", anonymous_5, Flag, INVALID, relocatable, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 123 | 138 | OPTION(prefix_1, "save-temps", save_temps, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 124 | 139 | OPTION(prefix_1, "shared-memory", shared_memory, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -144,10 +159,17 @@ OPTION(prefix_1, "thinlto-jobs=", thinlto_jobs, Joined, INVALID, INVALID, nullpt |
| 144 | 159 | "Number of ThinLTO jobs", nullptr, nullptr) |
| 145 | 160 | OPTION(prefix_1, "threads", threads, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 146 | 161 | "Run the linker multi-threaded", nullptr, nullptr) |
| 162 | OPTION(prefix_1, "trace-symbol=", trace_symbol_eq, Joined, INVALID, trace_symbol, nullptr, 0, 0, | |
| 163 | "Trace references to symbols", nullptr, nullptr) | |
| 164 | OPTION(prefix_1, "trace-symbol", trace_symbol, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 165 | OPTION(prefix_1, "trace", trace, Flag, INVALID, INVALID, nullptr, 0, 0, | |
| 166 | "Print the names of the input files", nullptr, nullptr) | |
| 167 | OPTION(prefix_2, "t", anonymous_8, Flag, INVALID, trace, nullptr, 0, 0, | |
| 168 | "Alias for --trace", nullptr, nullptr) | |
| 147 | 169 | OPTION(prefix_1, "undefined=", undefined_eq, Joined, INVALID, undefined, nullptr, 0, 0, |
| 148 | 170 | "Force undefined symbol during linking", nullptr, nullptr) |
| 149 | 171 | OPTION(prefix_1, "undefined", undefined, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) |
| 150 | OPTION(prefix_2, "u", anonymous_8, JoinedOrSeparate, INVALID, undefined, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 172 | OPTION(prefix_2, "u", anonymous_10, JoinedOrSeparate, INVALID, undefined, nullptr, 0, 0, nullptr, nullptr, nullptr) | |
| 151 | 173 | OPTION(prefix_1, "verbose", verbose, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 152 | 174 | "Verbose mode", nullptr, nullptr) |
| 153 | 175 | OPTION(prefix_1, "version", version, Flag, INVALID, INVALID, nullptr, 0, 0, |
| ... | ... | @@ -156,6 +178,11 @@ OPTION(prefix_2, "v", v, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 156 | 178 | "Display the version number", nullptr, nullptr) |
| 157 | 179 | OPTION(prefix_1, "whole-archive", whole_archive, Flag, INVALID, INVALID, nullptr, 0, 0, |
| 158 | 180 | "Force load of all members in a static library", nullptr, nullptr) |
| 181 | OPTION(prefix_1, "wrap=", wrap_eq, Joined, INVALID, wrap, nullptr, 0, 0, | |
| 182 | "Use wrapper functions for symbol", "<symbol>=<symbol>", nullptr) | |
| 183 | OPTION(prefix_1, "wrap", wrap, Separate, INVALID, INVALID, nullptr, 0, 0, nullptr, "<symbol>=<symbol>", nullptr) | |
| 184 | OPTION(prefix_2, "y", anonymous_9, JoinedOrSeparate, INVALID, trace_symbol, nullptr, 0, 0, | |
| 185 | "Alias for --trace-symbol", nullptr, nullptr) | |
| 159 | 186 | OPTION(prefix_2, "z", z, JoinedOrSeparate, INVALID, INVALID, nullptr, 0, 0, |
| 160 | 187 | "Linker option extensions", "<option>", nullptr) |
| 161 | 188 | #endif // OPTION |
deps/lld/COFF/CMakeLists.txt+1| ... | ... | @@ -8,6 +8,7 @@ endif() |
| 8 | 8 | |
| 9 | 9 | add_lld_library(lldCOFF |
| 10 | 10 | Chunks.cpp |
| 11 | DebugTypes.cpp | |
| 11 | 12 | DLL.cpp |
| 12 | 13 | Driver.cpp |
| 13 | 14 | DriverUtils.cpp |
deps/lld/COFF/Chunks.cpp+444-405| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Chunks.cpp ---------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -30,203 +29,201 @@ using llvm::support::ulittle32_t; |
| 30 | 29 | namespace lld { |
| 31 | 30 | namespace coff { |
| 32 | 31 | |
| 33 | SectionChunk::SectionChunk(ObjFile *F, const coff_section *H) | |
| 34 | : Chunk(SectionKind), Repl(this), Header(H), File(F), | |
| 35 | Relocs(File->getCOFFObj()->getRelocations(Header)) { | |
| 36 | // Initialize SectionName. | |
| 37 | File->getCOFFObj()->getSectionName(Header, SectionName); | |
| 32 | SectionChunk::SectionChunk(ObjFile *f, const coff_section *h) | |
| 33 | : Chunk(SectionKind), file(f), header(h), repl(this) { | |
| 34 | // Initialize relocs. | |
| 35 | setRelocs(file->getCOFFObj()->getRelocations(header)); | |
| 36 | ||
| 37 | // Initialize sectionName. | |
| 38 | StringRef sectionName; | |
| 39 | if (Expected<StringRef> e = file->getCOFFObj()->getSectionName(header)) | |
| 40 | sectionName = *e; | |
| 41 | sectionNameData = sectionName.data(); | |
| 42 | sectionNameSize = sectionName.size(); | |
| 43 | ||
| 44 | setAlignment(header->getAlignment()); | |
| 38 | 45 | |
| 39 | Alignment = Header->getAlignment(); | |
| 46 | hasData = !(header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA); | |
| 40 | 47 | |
| 41 | 48 | // If linker GC is disabled, every chunk starts out alive. If linker GC is |
| 42 | 49 | // enabled, treat non-comdat sections as roots. Generally optimized object |
| 43 | 50 | // files will be built with -ffunction-sections or /Gy, so most things worth |
| 44 | 51 | // stripping will be in a comdat. |
| 45 | Live = !Config->DoGC || !isCOMDAT(); | |
| 52 | live = !config->doGC || !isCOMDAT(); | |
| 46 | 53 | } |
| 47 | 54 | |
| 48 | // Initialize the RelocTargets vector, to allow redirecting certain relocations | |
| 49 | // to a thunk instead of the actual symbol the relocation's symbol table index | |
| 50 | // indicates. | |
| 51 | void SectionChunk::readRelocTargets() { | |
| 52 | assert(RelocTargets.empty()); | |
| 53 | RelocTargets.reserve(Relocs.size()); | |
| 54 | for (const coff_relocation &Rel : Relocs) | |
| 55 | RelocTargets.push_back(File->getSymbol(Rel.SymbolTableIndex)); | |
| 56 | } | |
| 57 | ||
| 58 | // Reset RelocTargets to their original targets before thunks were added. | |
| 59 | void SectionChunk::resetRelocTargets() { | |
| 60 | for (size_t I = 0, E = Relocs.size(); I < E; ++I) | |
| 61 | RelocTargets[I] = File->getSymbol(Relocs[I].SymbolTableIndex); | |
| 62 | } | |
| 55 | // SectionChunk is one of the most frequently allocated classes, so it is | |
| 56 | // important to keep it as compact as possible. As of this writing, the number | |
| 57 | // below is the size of this class on x64 platforms. | |
| 58 | static_assert(sizeof(SectionChunk) <= 88, "SectionChunk grew unexpectedly"); | |
| 63 | 59 | |
| 64 | static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); } | |
| 65 | static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); } | |
| 66 | static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); } | |
| 67 | static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); } | |
| 68 | static void or32(uint8_t *P, uint32_t V) { write32le(P, read32le(P) | V); } | |
| 60 | static void add16(uint8_t *p, int16_t v) { write16le(p, read16le(p) + v); } | |
| 61 | static void add32(uint8_t *p, int32_t v) { write32le(p, read32le(p) + v); } | |
| 62 | static void add64(uint8_t *p, int64_t v) { write64le(p, read64le(p) + v); } | |
| 63 | static void or16(uint8_t *p, uint16_t v) { write16le(p, read16le(p) | v); } | |
| 64 | static void or32(uint8_t *p, uint32_t v) { write32le(p, read32le(p) | v); } | |
| 69 | 65 | |
| 70 | 66 | // Verify that given sections are appropriate targets for SECREL |
| 71 | 67 | // relocations. This check is relaxed because unfortunately debug |
| 72 | 68 | // sections have section-relative relocations against absolute symbols. |
| 73 | static bool checkSecRel(const SectionChunk *Sec, OutputSection *OS) { | |
| 74 | if (OS) | |
| 69 | static bool checkSecRel(const SectionChunk *sec, OutputSection *os) { | |
| 70 | if (os) | |
| 75 | 71 | return true; |
| 76 | if (Sec->isCodeView()) | |
| 72 | if (sec->isCodeView()) | |
| 77 | 73 | return false; |
| 78 | 74 | error("SECREL relocation cannot be applied to absolute symbols"); |
| 79 | 75 | return false; |
| 80 | 76 | } |
| 81 | 77 | |
| 82 | static void applySecRel(const SectionChunk *Sec, uint8_t *Off, | |
| 83 | OutputSection *OS, uint64_t S) { | |
| 84 | if (!checkSecRel(Sec, OS)) | |
| 78 | static void applySecRel(const SectionChunk *sec, uint8_t *off, | |
| 79 | OutputSection *os, uint64_t s) { | |
| 80 | if (!checkSecRel(sec, os)) | |
| 85 | 81 | return; |
| 86 | uint64_t SecRel = S - OS->getRVA(); | |
| 87 | if (SecRel > UINT32_MAX) { | |
| 88 | error("overflow in SECREL relocation in section: " + Sec->getSectionName()); | |
| 82 | uint64_t secRel = s - os->getRVA(); | |
| 83 | if (secRel > UINT32_MAX) { | |
| 84 | error("overflow in SECREL relocation in section: " + sec->getSectionName()); | |
| 89 | 85 | return; |
| 90 | 86 | } |
| 91 | add32(Off, SecRel); | |
| 87 | add32(off, secRel); | |
| 92 | 88 | } |
| 93 | 89 | |
| 94 | static void applySecIdx(uint8_t *Off, OutputSection *OS) { | |
| 90 | static void applySecIdx(uint8_t *off, OutputSection *os) { | |
| 95 | 91 | // Absolute symbol doesn't have section index, but section index relocation |
| 96 | 92 | // against absolute symbol should be resolved to one plus the last output |
| 97 | 93 | // section index. This is required for compatibility with MSVC. |
| 98 | if (OS) | |
| 99 | add16(Off, OS->SectionIndex); | |
| 94 | if (os) | |
| 95 | add16(off, os->sectionIndex); | |
| 100 | 96 | else |
| 101 | add16(Off, DefinedAbsolute::NumOutputSections + 1); | |
| 102 | } | |
| 103 | ||
| 104 | void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, | |
| 105 | uint64_t S, uint64_t P) const { | |
| 106 | switch (Type) { | |
| 107 | case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->ImageBase); break; | |
| 108 | case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->ImageBase); break; | |
| 109 | case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break; | |
| 110 | case IMAGE_REL_AMD64_REL32: add32(Off, S - P - 4); break; | |
| 111 | case IMAGE_REL_AMD64_REL32_1: add32(Off, S - P - 5); break; | |
| 112 | case IMAGE_REL_AMD64_REL32_2: add32(Off, S - P - 6); break; | |
| 113 | case IMAGE_REL_AMD64_REL32_3: add32(Off, S - P - 7); break; | |
| 114 | case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break; | |
| 115 | case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break; | |
| 116 | case IMAGE_REL_AMD64_SECTION: applySecIdx(Off, OS); break; | |
| 117 | case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, OS, S); break; | |
| 97 | add16(off, DefinedAbsolute::numOutputSections + 1); | |
| 98 | } | |
| 99 | ||
| 100 | void SectionChunk::applyRelX64(uint8_t *off, uint16_t type, OutputSection *os, | |
| 101 | uint64_t s, uint64_t p) const { | |
| 102 | switch (type) { | |
| 103 | case IMAGE_REL_AMD64_ADDR32: add32(off, s + config->imageBase); break; | |
| 104 | case IMAGE_REL_AMD64_ADDR64: add64(off, s + config->imageBase); break; | |
| 105 | case IMAGE_REL_AMD64_ADDR32NB: add32(off, s); break; | |
| 106 | case IMAGE_REL_AMD64_REL32: add32(off, s - p - 4); break; | |
| 107 | case IMAGE_REL_AMD64_REL32_1: add32(off, s - p - 5); break; | |
| 108 | case IMAGE_REL_AMD64_REL32_2: add32(off, s - p - 6); break; | |
| 109 | case IMAGE_REL_AMD64_REL32_3: add32(off, s - p - 7); break; | |
| 110 | case IMAGE_REL_AMD64_REL32_4: add32(off, s - p - 8); break; | |
| 111 | case IMAGE_REL_AMD64_REL32_5: add32(off, s - p - 9); break; | |
| 112 | case IMAGE_REL_AMD64_SECTION: applySecIdx(off, os); break; | |
| 113 | case IMAGE_REL_AMD64_SECREL: applySecRel(this, off, os, s); break; | |
| 118 | 114 | default: |
| 119 | error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + | |
| 120 | toString(File)); | |
| 115 | error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " + | |
| 116 | toString(file)); | |
| 121 | 117 | } |
| 122 | 118 | } |
| 123 | 119 | |
| 124 | void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, | |
| 125 | uint64_t S, uint64_t P) const { | |
| 126 | switch (Type) { | |
| 120 | void SectionChunk::applyRelX86(uint8_t *off, uint16_t type, OutputSection *os, | |
| 121 | uint64_t s, uint64_t p) const { | |
| 122 | switch (type) { | |
| 127 | 123 | case IMAGE_REL_I386_ABSOLUTE: break; |
| 128 | case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break; | |
| 129 | case IMAGE_REL_I386_DIR32NB: add32(Off, S); break; | |
| 130 | case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break; | |
| 131 | case IMAGE_REL_I386_SECTION: applySecIdx(Off, OS); break; | |
| 132 | case IMAGE_REL_I386_SECREL: applySecRel(this, Off, OS, S); break; | |
| 124 | case IMAGE_REL_I386_DIR32: add32(off, s + config->imageBase); break; | |
| 125 | case IMAGE_REL_I386_DIR32NB: add32(off, s); break; | |
| 126 | case IMAGE_REL_I386_REL32: add32(off, s - p - 4); break; | |
| 127 | case IMAGE_REL_I386_SECTION: applySecIdx(off, os); break; | |
| 128 | case IMAGE_REL_I386_SECREL: applySecRel(this, off, os, s); break; | |
| 133 | 129 | default: |
| 134 | error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + | |
| 135 | toString(File)); | |
| 130 | error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " + | |
| 131 | toString(file)); | |
| 136 | 132 | } |
| 137 | 133 | } |
| 138 | 134 | |
| 139 | static void applyMOV(uint8_t *Off, uint16_t V) { | |
| 140 | write16le(Off, (read16le(Off) & 0xfbf0) | ((V & 0x800) >> 1) | ((V >> 12) & 0xf)); | |
| 141 | write16le(Off + 2, (read16le(Off + 2) & 0x8f00) | ((V & 0x700) << 4) | (V & 0xff)); | |
| 135 | static void applyMOV(uint8_t *off, uint16_t v) { | |
| 136 | write16le(off, (read16le(off) & 0xfbf0) | ((v & 0x800) >> 1) | ((v >> 12) & 0xf)); | |
| 137 | write16le(off + 2, (read16le(off + 2) & 0x8f00) | ((v & 0x700) << 4) | (v & 0xff)); | |
| 142 | 138 | } |
| 143 | 139 | |
| 144 | static uint16_t readMOV(uint8_t *Off, bool MOVT) { | |
| 145 | uint16_t Op1 = read16le(Off); | |
| 146 | if ((Op1 & 0xfbf0) != (MOVT ? 0xf2c0 : 0xf240)) | |
| 147 | error("unexpected instruction in " + Twine(MOVT ? "MOVT" : "MOVW") + | |
| 140 | static uint16_t readMOV(uint8_t *off, bool movt) { | |
| 141 | uint16_t op1 = read16le(off); | |
| 142 | if ((op1 & 0xfbf0) != (movt ? 0xf2c0 : 0xf240)) | |
| 143 | error("unexpected instruction in " + Twine(movt ? "MOVT" : "MOVW") + | |
| 148 | 144 | " instruction in MOV32T relocation"); |
| 149 | uint16_t Op2 = read16le(Off + 2); | |
| 150 | if ((Op2 & 0x8000) != 0) | |
| 151 | error("unexpected instruction in " + Twine(MOVT ? "MOVT" : "MOVW") + | |
| 145 | uint16_t op2 = read16le(off + 2); | |
| 146 | if ((op2 & 0x8000) != 0) | |
| 147 | error("unexpected instruction in " + Twine(movt ? "MOVT" : "MOVW") + | |
| 152 | 148 | " instruction in MOV32T relocation"); |
| 153 | return (Op2 & 0x00ff) | ((Op2 >> 4) & 0x0700) | ((Op1 << 1) & 0x0800) | | |
| 154 | ((Op1 & 0x000f) << 12); | |
| 149 | return (op2 & 0x00ff) | ((op2 >> 4) & 0x0700) | ((op1 << 1) & 0x0800) | | |
| 150 | ((op1 & 0x000f) << 12); | |
| 155 | 151 | } |
| 156 | 152 | |
| 157 | void applyMOV32T(uint8_t *Off, uint32_t V) { | |
| 158 | uint16_t ImmW = readMOV(Off, false); // read MOVW operand | |
| 159 | uint16_t ImmT = readMOV(Off + 4, true); // read MOVT operand | |
| 160 | uint32_t Imm = ImmW | (ImmT << 16); | |
| 161 | V += Imm; // add the immediate offset | |
| 162 | applyMOV(Off, V); // set MOVW operand | |
| 163 | applyMOV(Off + 4, V >> 16); // set MOVT operand | |
| 153 | void applyMOV32T(uint8_t *off, uint32_t v) { | |
| 154 | uint16_t immW = readMOV(off, false); // read MOVW operand | |
| 155 | uint16_t immT = readMOV(off + 4, true); // read MOVT operand | |
| 156 | uint32_t imm = immW | (immT << 16); | |
| 157 | v += imm; // add the immediate offset | |
| 158 | applyMOV(off, v); // set MOVW operand | |
| 159 | applyMOV(off + 4, v >> 16); // set MOVT operand | |
| 164 | 160 | } |
| 165 | 161 | |
| 166 | static void applyBranch20T(uint8_t *Off, int32_t V) { | |
| 167 | if (!isInt<21>(V)) | |
| 162 | static void applyBranch20T(uint8_t *off, int32_t v) { | |
| 163 | if (!isInt<21>(v)) | |
| 168 | 164 | error("relocation out of range"); |
| 169 | uint32_t S = V < 0 ? 1 : 0; | |
| 170 | uint32_t J1 = (V >> 19) & 1; | |
| 171 | uint32_t J2 = (V >> 18) & 1; | |
| 172 | or16(Off, (S << 10) | ((V >> 12) & 0x3f)); | |
| 173 | or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); | |
| 165 | uint32_t s = v < 0 ? 1 : 0; | |
| 166 | uint32_t j1 = (v >> 19) & 1; | |
| 167 | uint32_t j2 = (v >> 18) & 1; | |
| 168 | or16(off, (s << 10) | ((v >> 12) & 0x3f)); | |
| 169 | or16(off + 2, (j1 << 13) | (j2 << 11) | ((v >> 1) & 0x7ff)); | |
| 174 | 170 | } |
| 175 | 171 | |
| 176 | void applyBranch24T(uint8_t *Off, int32_t V) { | |
| 177 | if (!isInt<25>(V)) | |
| 172 | void applyBranch24T(uint8_t *off, int32_t v) { | |
| 173 | if (!isInt<25>(v)) | |
| 178 | 174 | error("relocation out of range"); |
| 179 | uint32_t S = V < 0 ? 1 : 0; | |
| 180 | uint32_t J1 = ((~V >> 23) & 1) ^ S; | |
| 181 | uint32_t J2 = ((~V >> 22) & 1) ^ S; | |
| 182 | or16(Off, (S << 10) | ((V >> 12) & 0x3ff)); | |
| 175 | uint32_t s = v < 0 ? 1 : 0; | |
| 176 | uint32_t j1 = ((~v >> 23) & 1) ^ s; | |
| 177 | uint32_t j2 = ((~v >> 22) & 1) ^ s; | |
| 178 | or16(off, (s << 10) | ((v >> 12) & 0x3ff)); | |
| 183 | 179 | // Clear out the J1 and J2 bits which may be set. |
| 184 | write16le(Off + 2, (read16le(Off + 2) & 0xd000) | (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); | |
| 180 | write16le(off + 2, (read16le(off + 2) & 0xd000) | (j1 << 13) | (j2 << 11) | ((v >> 1) & 0x7ff)); | |
| 185 | 181 | } |
| 186 | 182 | |
| 187 | void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, | |
| 188 | uint64_t S, uint64_t P) const { | |
| 183 | void SectionChunk::applyRelARM(uint8_t *off, uint16_t type, OutputSection *os, | |
| 184 | uint64_t s, uint64_t p) const { | |
| 189 | 185 | // Pointer to thumb code must have the LSB set. |
| 190 | uint64_t SX = S; | |
| 191 | if (OS && (OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)) | |
| 192 | SX |= 1; | |
| 193 | switch (Type) { | |
| 194 | case IMAGE_REL_ARM_ADDR32: add32(Off, SX + Config->ImageBase); break; | |
| 195 | case IMAGE_REL_ARM_ADDR32NB: add32(Off, SX); break; | |
| 196 | case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, SX + Config->ImageBase); break; | |
| 197 | case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, SX - P - 4); break; | |
| 198 | case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, SX - P - 4); break; | |
| 199 | case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, SX - P - 4); break; | |
| 200 | case IMAGE_REL_ARM_SECTION: applySecIdx(Off, OS); break; | |
| 201 | case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, OS, S); break; | |
| 186 | uint64_t sx = s; | |
| 187 | if (os && (os->header.Characteristics & IMAGE_SCN_MEM_EXECUTE)) | |
| 188 | sx |= 1; | |
| 189 | switch (type) { | |
| 190 | case IMAGE_REL_ARM_ADDR32: add32(off, sx + config->imageBase); break; | |
| 191 | case IMAGE_REL_ARM_ADDR32NB: add32(off, sx); break; | |
| 192 | case IMAGE_REL_ARM_MOV32T: applyMOV32T(off, sx + config->imageBase); break; | |
| 193 | case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(off, sx - p - 4); break; | |
| 194 | case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(off, sx - p - 4); break; | |
| 195 | case IMAGE_REL_ARM_BLX23T: applyBranch24T(off, sx - p - 4); break; | |
| 196 | case IMAGE_REL_ARM_SECTION: applySecIdx(off, os); break; | |
| 197 | case IMAGE_REL_ARM_SECREL: applySecRel(this, off, os, s); break; | |
| 198 | case IMAGE_REL_ARM_REL32: add32(off, sx - p - 4); break; | |
| 202 | 199 | default: |
| 203 | error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + | |
| 204 | toString(File)); | |
| 200 | error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " + | |
| 201 | toString(file)); | |
| 205 | 202 | } |
| 206 | 203 | } |
| 207 | 204 | |
| 208 | 205 | // Interpret the existing immediate value as a byte offset to the |
| 209 | 206 | // target symbol, then update the instruction with the immediate as |
| 210 | 207 | // the page offset from the current instruction to the target. |
| 211 | void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift) { | |
| 212 | uint32_t Orig = read32le(Off); | |
| 213 | uint64_t Imm = ((Orig >> 29) & 0x3) | ((Orig >> 3) & 0x1FFFFC); | |
| 214 | S += Imm; | |
| 215 | Imm = (S >> Shift) - (P >> Shift); | |
| 216 | uint32_t ImmLo = (Imm & 0x3) << 29; | |
| 217 | uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; | |
| 218 | uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); | |
| 219 | write32le(Off, (Orig & ~Mask) | ImmLo | ImmHi); | |
| 208 | void applyArm64Addr(uint8_t *off, uint64_t s, uint64_t p, int shift) { | |
| 209 | uint32_t orig = read32le(off); | |
| 210 | uint64_t imm = ((orig >> 29) & 0x3) | ((orig >> 3) & 0x1FFFFC); | |
| 211 | s += imm; | |
| 212 | imm = (s >> shift) - (p >> shift); | |
| 213 | uint32_t immLo = (imm & 0x3) << 29; | |
| 214 | uint32_t immHi = (imm & 0x1FFFFC) << 3; | |
| 215 | uint64_t mask = (0x3 << 29) | (0x1FFFFC << 3); | |
| 216 | write32le(off, (orig & ~mask) | immLo | immHi); | |
| 220 | 217 | } |
| 221 | 218 | |
| 222 | 219 | // Update the immediate field in a AARCH64 ldr, str, and add instruction. |
| 223 | 220 | // Optionally limit the range of the written immediate by one or more bits |
| 224 | // (RangeLimit). | |
| 225 | void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit) { | |
| 226 | uint32_t Orig = read32le(Off); | |
| 227 | Imm += (Orig >> 10) & 0xFFF; | |
| 228 | Orig &= ~(0xFFF << 10); | |
| 229 | write32le(Off, Orig | ((Imm & (0xFFF >> RangeLimit)) << 10)); | |
| 221 | // (rangeLimit). | |
| 222 | void applyArm64Imm(uint8_t *off, uint64_t imm, uint32_t rangeLimit) { | |
| 223 | uint32_t orig = read32le(off); | |
| 224 | imm += (orig >> 10) & 0xFFF; | |
| 225 | orig &= ~(0xFFF << 10); | |
| 226 | write32le(off, orig | ((imm & (0xFFF >> rangeLimit)) << 10)); | |
| 230 | 227 | } |
| 231 | 228 | |
| 232 | 229 | // Add the 12 bit page offset to the existing immediate. |
| ... | ... | @@ -237,171 +234,178 @@ void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit) { |
| 237 | 234 | // Even if larger loads/stores have a larger range, limit the |
| 238 | 235 | // effective offset to 12 bit, since it is intended to be a |
| 239 | 236 | // page offset. |
| 240 | static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) { | |
| 241 | uint32_t Orig = read32le(Off); | |
| 242 | uint32_t Size = Orig >> 30; | |
| 237 | static void applyArm64Ldr(uint8_t *off, uint64_t imm) { | |
| 238 | uint32_t orig = read32le(off); | |
| 239 | uint32_t size = orig >> 30; | |
| 243 | 240 | // 0x04000000 indicates SIMD/FP registers |
| 244 | 241 | // 0x00800000 indicates 128 bit |
| 245 | if ((Orig & 0x4800000) == 0x4800000) | |
| 246 | Size += 4; | |
| 247 | if ((Imm & ((1 << Size) - 1)) != 0) | |
| 242 | if ((orig & 0x4800000) == 0x4800000) | |
| 243 | size += 4; | |
| 244 | if ((imm & ((1 << size) - 1)) != 0) | |
| 248 | 245 | error("misaligned ldr/str offset"); |
| 249 | applyArm64Imm(Off, Imm >> Size, Size); | |
| 246 | applyArm64Imm(off, imm >> size, size); | |
| 250 | 247 | } |
| 251 | 248 | |
| 252 | static void applySecRelLow12A(const SectionChunk *Sec, uint8_t *Off, | |
| 253 | OutputSection *OS, uint64_t S) { | |
| 254 | if (checkSecRel(Sec, OS)) | |
| 255 | applyArm64Imm(Off, (S - OS->getRVA()) & 0xfff, 0); | |
| 249 | static void applySecRelLow12A(const SectionChunk *sec, uint8_t *off, | |
| 250 | OutputSection *os, uint64_t s) { | |
| 251 | if (checkSecRel(sec, os)) | |
| 252 | applyArm64Imm(off, (s - os->getRVA()) & 0xfff, 0); | |
| 256 | 253 | } |
| 257 | 254 | |
| 258 | static void applySecRelHigh12A(const SectionChunk *Sec, uint8_t *Off, | |
| 259 | OutputSection *OS, uint64_t S) { | |
| 260 | if (!checkSecRel(Sec, OS)) | |
| 255 | static void applySecRelHigh12A(const SectionChunk *sec, uint8_t *off, | |
| 256 | OutputSection *os, uint64_t s) { | |
| 257 | if (!checkSecRel(sec, os)) | |
| 261 | 258 | return; |
| 262 | uint64_t SecRel = (S - OS->getRVA()) >> 12; | |
| 263 | if (0xfff < SecRel) { | |
| 259 | uint64_t secRel = (s - os->getRVA()) >> 12; | |
| 260 | if (0xfff < secRel) { | |
| 264 | 261 | error("overflow in SECREL_HIGH12A relocation in section: " + |
| 265 | Sec->getSectionName()); | |
| 262 | sec->getSectionName()); | |
| 266 | 263 | return; |
| 267 | 264 | } |
| 268 | applyArm64Imm(Off, SecRel & 0xfff, 0); | |
| 265 | applyArm64Imm(off, secRel & 0xfff, 0); | |
| 269 | 266 | } |
| 270 | 267 | |
| 271 | static void applySecRelLdr(const SectionChunk *Sec, uint8_t *Off, | |
| 272 | OutputSection *OS, uint64_t S) { | |
| 273 | if (checkSecRel(Sec, OS)) | |
| 274 | applyArm64Ldr(Off, (S - OS->getRVA()) & 0xfff); | |
| 268 | static void applySecRelLdr(const SectionChunk *sec, uint8_t *off, | |
| 269 | OutputSection *os, uint64_t s) { | |
| 270 | if (checkSecRel(sec, os)) | |
| 271 | applyArm64Ldr(off, (s - os->getRVA()) & 0xfff); | |
| 275 | 272 | } |
| 276 | 273 | |
| 277 | void applyArm64Branch26(uint8_t *Off, int64_t V) { | |
| 278 | if (!isInt<28>(V)) | |
| 274 | void applyArm64Branch26(uint8_t *off, int64_t v) { | |
| 275 | if (!isInt<28>(v)) | |
| 279 | 276 | error("relocation out of range"); |
| 280 | or32(Off, (V & 0x0FFFFFFC) >> 2); | |
| 277 | or32(off, (v & 0x0FFFFFFC) >> 2); | |
| 281 | 278 | } |
| 282 | 279 | |
| 283 | static void applyArm64Branch19(uint8_t *Off, int64_t V) { | |
| 284 | if (!isInt<21>(V)) | |
| 280 | static void applyArm64Branch19(uint8_t *off, int64_t v) { | |
| 281 | if (!isInt<21>(v)) | |
| 285 | 282 | error("relocation out of range"); |
| 286 | or32(Off, (V & 0x001FFFFC) << 3); | |
| 283 | or32(off, (v & 0x001FFFFC) << 3); | |
| 287 | 284 | } |
| 288 | 285 | |
| 289 | static void applyArm64Branch14(uint8_t *Off, int64_t V) { | |
| 290 | if (!isInt<16>(V)) | |
| 286 | static void applyArm64Branch14(uint8_t *off, int64_t v) { | |
| 287 | if (!isInt<16>(v)) | |
| 291 | 288 | error("relocation out of range"); |
| 292 | or32(Off, (V & 0x0000FFFC) << 3); | |
| 293 | } | |
| 294 | ||
| 295 | void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, | |
| 296 | uint64_t S, uint64_t P) const { | |
| 297 | switch (Type) { | |
| 298 | case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P, 12); break; | |
| 299 | case IMAGE_REL_ARM64_REL21: applyArm64Addr(Off, S, P, 0); break; | |
| 300 | case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff, 0); break; | |
| 301 | case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break; | |
| 302 | case IMAGE_REL_ARM64_BRANCH26: applyArm64Branch26(Off, S - P); break; | |
| 303 | case IMAGE_REL_ARM64_BRANCH19: applyArm64Branch19(Off, S - P); break; | |
| 304 | case IMAGE_REL_ARM64_BRANCH14: applyArm64Branch14(Off, S - P); break; | |
| 305 | case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break; | |
| 306 | case IMAGE_REL_ARM64_ADDR32NB: add32(Off, S); break; | |
| 307 | case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break; | |
| 308 | case IMAGE_REL_ARM64_SECREL: applySecRel(this, Off, OS, S); break; | |
| 309 | case IMAGE_REL_ARM64_SECREL_LOW12A: applySecRelLow12A(this, Off, OS, S); break; | |
| 310 | case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, Off, OS, S); break; | |
| 311 | case IMAGE_REL_ARM64_SECREL_LOW12L: applySecRelLdr(this, Off, OS, S); break; | |
| 312 | case IMAGE_REL_ARM64_SECTION: applySecIdx(Off, OS); break; | |
| 289 | or32(off, (v & 0x0000FFFC) << 3); | |
| 290 | } | |
| 291 | ||
| 292 | void SectionChunk::applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os, | |
| 293 | uint64_t s, uint64_t p) const { | |
| 294 | switch (type) { | |
| 295 | case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(off, s, p, 12); break; | |
| 296 | case IMAGE_REL_ARM64_REL21: applyArm64Addr(off, s, p, 0); break; | |
| 297 | case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(off, s & 0xfff, 0); break; | |
| 298 | case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(off, s & 0xfff); break; | |
| 299 | case IMAGE_REL_ARM64_BRANCH26: applyArm64Branch26(off, s - p); break; | |
| 300 | case IMAGE_REL_ARM64_BRANCH19: applyArm64Branch19(off, s - p); break; | |
| 301 | case IMAGE_REL_ARM64_BRANCH14: applyArm64Branch14(off, s - p); break; | |
| 302 | case IMAGE_REL_ARM64_ADDR32: add32(off, s + config->imageBase); break; | |
| 303 | case IMAGE_REL_ARM64_ADDR32NB: add32(off, s); break; | |
| 304 | case IMAGE_REL_ARM64_ADDR64: add64(off, s + config->imageBase); break; | |
| 305 | case IMAGE_REL_ARM64_SECREL: applySecRel(this, off, os, s); break; | |
| 306 | case IMAGE_REL_ARM64_SECREL_LOW12A: applySecRelLow12A(this, off, os, s); break; | |
| 307 | case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, off, os, s); break; | |
| 308 | case IMAGE_REL_ARM64_SECREL_LOW12L: applySecRelLdr(this, off, os, s); break; | |
| 309 | case IMAGE_REL_ARM64_SECTION: applySecIdx(off, os); break; | |
| 310 | case IMAGE_REL_ARM64_REL32: add32(off, s - p - 4); break; | |
| 313 | 311 | default: |
| 314 | error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + | |
| 315 | toString(File)); | |
| 312 | error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " + | |
| 313 | toString(file)); | |
| 316 | 314 | } |
| 317 | 315 | } |
| 318 | 316 | |
| 319 | static void maybeReportRelocationToDiscarded(const SectionChunk *FromChunk, | |
| 320 | Defined *Sym, | |
| 321 | const coff_relocation &Rel) { | |
| 317 | static void maybeReportRelocationToDiscarded(const SectionChunk *fromChunk, | |
| 318 | Defined *sym, | |
| 319 | const coff_relocation &rel) { | |
| 322 | 320 | // Don't report these errors when the relocation comes from a debug info |
| 323 | 321 | // section or in mingw mode. MinGW mode object files (built by GCC) can |
| 324 | 322 | // have leftover sections with relocations against discarded comdat |
| 325 | 323 | // sections. Such sections are left as is, with relocations untouched. |
| 326 | if (FromChunk->isCodeView() || FromChunk->isDWARF() || Config->MinGW) | |
| 324 | if (fromChunk->isCodeView() || fromChunk->isDWARF() || config->mingw) | |
| 327 | 325 | return; |
| 328 | 326 | |
| 329 | 327 | // Get the name of the symbol. If it's null, it was discarded early, so we |
| 330 | 328 | // have to go back to the object file. |
| 331 | ObjFile *File = FromChunk->File; | |
| 332 | StringRef Name; | |
| 333 | if (Sym) { | |
| 334 | Name = Sym->getName(); | |
| 329 | ObjFile *file = fromChunk->file; | |
| 330 | StringRef name; | |
| 331 | if (sym) { | |
| 332 | name = sym->getName(); | |
| 335 | 333 | } else { |
| 336 | COFFSymbolRef COFFSym = | |
| 337 | check(File->getCOFFObj()->getSymbol(Rel.SymbolTableIndex)); | |
| 338 | File->getCOFFObj()->getSymbolName(COFFSym, Name); | |
| 334 | COFFSymbolRef coffSym = | |
| 335 | check(file->getCOFFObj()->getSymbol(rel.SymbolTableIndex)); | |
| 336 | file->getCOFFObj()->getSymbolName(coffSym, name); | |
| 339 | 337 | } |
| 340 | 338 | |
| 341 | error("relocation against symbol in discarded section: " + Name + | |
| 342 | getSymbolLocations(File, Rel.SymbolTableIndex)); | |
| 339 | std::vector<std::string> symbolLocations = | |
| 340 | getSymbolLocations(file, rel.SymbolTableIndex); | |
| 341 | ||
| 342 | std::string out; | |
| 343 | llvm::raw_string_ostream os(out); | |
| 344 | os << "relocation against symbol in discarded section: " + name; | |
| 345 | for (const std::string &s : symbolLocations) | |
| 346 | os << s; | |
| 347 | error(os.str()); | |
| 343 | 348 | } |
| 344 | 349 | |
| 345 | void SectionChunk::writeTo(uint8_t *Buf) const { | |
| 346 | if (!hasData()) | |
| 350 | void SectionChunk::writeTo(uint8_t *buf) const { | |
| 351 | if (!hasData) | |
| 347 | 352 | return; |
| 348 | 353 | // Copy section contents from source object file to output file. |
| 349 | ArrayRef<uint8_t> A = getContents(); | |
| 350 | if (!A.empty()) | |
| 351 | memcpy(Buf + OutputSectionOff, A.data(), A.size()); | |
| 354 | ArrayRef<uint8_t> a = getContents(); | |
| 355 | if (!a.empty()) | |
| 356 | memcpy(buf, a.data(), a.size()); | |
| 352 | 357 | |
| 353 | 358 | // Apply relocations. |
| 354 | size_t InputSize = getSize(); | |
| 355 | for (size_t I = 0, E = Relocs.size(); I < E; I++) { | |
| 356 | const coff_relocation &Rel = Relocs[I]; | |
| 359 | size_t inputSize = getSize(); | |
| 360 | for (size_t i = 0, e = relocsSize; i < e; i++) { | |
| 361 | const coff_relocation &rel = relocsData[i]; | |
| 357 | 362 | |
| 358 | 363 | // Check for an invalid relocation offset. This check isn't perfect, because |
| 359 | 364 | // we don't have the relocation size, which is only known after checking the |
| 360 | 365 | // machine and relocation type. As a result, a relocation may overwrite the |
| 361 | 366 | // beginning of the following input section. |
| 362 | if (Rel.VirtualAddress >= InputSize) { | |
| 367 | if (rel.VirtualAddress >= inputSize) { | |
| 363 | 368 | error("relocation points beyond the end of its parent section"); |
| 364 | 369 | continue; |
| 365 | 370 | } |
| 366 | 371 | |
| 367 | uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress; | |
| 372 | uint8_t *off = buf + rel.VirtualAddress; | |
| 368 | 373 | |
| 369 | // Use the potentially remapped Symbol instead of the one that the | |
| 370 | // relocation points to. | |
| 371 | auto *Sym = dyn_cast_or_null<Defined>(RelocTargets[I]); | |
| 374 | auto *sym = | |
| 375 | dyn_cast_or_null<Defined>(file->getSymbol(rel.SymbolTableIndex)); | |
| 372 | 376 | |
| 373 | 377 | // Get the output section of the symbol for this relocation. The output |
| 374 | 378 | // section is needed to compute SECREL and SECTION relocations used in debug |
| 375 | 379 | // info. |
| 376 | Chunk *C = Sym ? Sym->getChunk() : nullptr; | |
| 377 | OutputSection *OS = C ? C->getOutputSection() : nullptr; | |
| 380 | Chunk *c = sym ? sym->getChunk() : nullptr; | |
| 381 | OutputSection *os = c ? c->getOutputSection() : nullptr; | |
| 378 | 382 | |
| 379 | 383 | // Skip the relocation if it refers to a discarded section, and diagnose it |
| 380 | 384 | // as an error if appropriate. If a symbol was discarded early, it may be |
| 381 | 385 | // null. If it was discarded late, the output section will be null, unless |
| 382 | 386 | // it was an absolute or synthetic symbol. |
| 383 | if (!Sym || | |
| 384 | (!OS && !isa<DefinedAbsolute>(Sym) && !isa<DefinedSynthetic>(Sym))) { | |
| 385 | maybeReportRelocationToDiscarded(this, Sym, Rel); | |
| 387 | if (!sym || | |
| 388 | (!os && !isa<DefinedAbsolute>(sym) && !isa<DefinedSynthetic>(sym))) { | |
| 389 | maybeReportRelocationToDiscarded(this, sym, rel); | |
| 386 | 390 | continue; |
| 387 | 391 | } |
| 388 | 392 | |
| 389 | uint64_t S = Sym->getRVA(); | |
| 393 | uint64_t s = sym->getRVA(); | |
| 390 | 394 | |
| 391 | 395 | // Compute the RVA of the relocation for relative relocations. |
| 392 | uint64_t P = RVA + Rel.VirtualAddress; | |
| 393 | switch (Config->Machine) { | |
| 396 | uint64_t p = rva + rel.VirtualAddress; | |
| 397 | switch (config->machine) { | |
| 394 | 398 | case AMD64: |
| 395 | applyRelX64(Off, Rel.Type, OS, S, P); | |
| 399 | applyRelX64(off, rel.Type, os, s, p); | |
| 396 | 400 | break; |
| 397 | 401 | case I386: |
| 398 | applyRelX86(Off, Rel.Type, OS, S, P); | |
| 402 | applyRelX86(off, rel.Type, os, s, p); | |
| 399 | 403 | break; |
| 400 | 404 | case ARMNT: |
| 401 | applyRelARM(Off, Rel.Type, OS, S, P); | |
| 405 | applyRelARM(off, rel.Type, os, s, p); | |
| 402 | 406 | break; |
| 403 | 407 | case ARM64: |
| 404 | applyRelARM64(Off, Rel.Type, OS, S, P); | |
| 408 | applyRelARM64(off, rel.Type, os, s, p); | |
| 405 | 409 | break; |
| 406 | 410 | default: |
| 407 | 411 | llvm_unreachable("unknown machine type"); |
| ... | ... | @@ -409,28 +413,32 @@ void SectionChunk::writeTo(uint8_t *Buf) const { |
| 409 | 413 | } |
| 410 | 414 | } |
| 411 | 415 | |
| 412 | void SectionChunk::addAssociative(SectionChunk *Child) { | |
| 413 | AssocChildren.push_back(Child); | |
| 416 | void SectionChunk::addAssociative(SectionChunk *child) { | |
| 417 | // Insert this child at the head of the list. | |
| 418 | assert(child->assocChildren == nullptr && | |
| 419 | "associated sections cannot have their own associated children"); | |
| 420 | child->assocChildren = assocChildren; | |
| 421 | assocChildren = child; | |
| 414 | 422 | } |
| 415 | 423 | |
| 416 | static uint8_t getBaserelType(const coff_relocation &Rel) { | |
| 417 | switch (Config->Machine) { | |
| 424 | static uint8_t getBaserelType(const coff_relocation &rel) { | |
| 425 | switch (config->machine) { | |
| 418 | 426 | case AMD64: |
| 419 | if (Rel.Type == IMAGE_REL_AMD64_ADDR64) | |
| 427 | if (rel.Type == IMAGE_REL_AMD64_ADDR64) | |
| 420 | 428 | return IMAGE_REL_BASED_DIR64; |
| 421 | 429 | return IMAGE_REL_BASED_ABSOLUTE; |
| 422 | 430 | case I386: |
| 423 | if (Rel.Type == IMAGE_REL_I386_DIR32) | |
| 431 | if (rel.Type == IMAGE_REL_I386_DIR32) | |
| 424 | 432 | return IMAGE_REL_BASED_HIGHLOW; |
| 425 | 433 | return IMAGE_REL_BASED_ABSOLUTE; |
| 426 | 434 | case ARMNT: |
| 427 | if (Rel.Type == IMAGE_REL_ARM_ADDR32) | |
| 435 | if (rel.Type == IMAGE_REL_ARM_ADDR32) | |
| 428 | 436 | return IMAGE_REL_BASED_HIGHLOW; |
| 429 | if (Rel.Type == IMAGE_REL_ARM_MOV32T) | |
| 437 | if (rel.Type == IMAGE_REL_ARM_MOV32T) | |
| 430 | 438 | return IMAGE_REL_BASED_ARM_MOV32T; |
| 431 | 439 | return IMAGE_REL_BASED_ABSOLUTE; |
| 432 | 440 | case ARM64: |
| 433 | if (Rel.Type == IMAGE_REL_ARM64_ADDR64) | |
| 441 | if (rel.Type == IMAGE_REL_ARM64_ADDR64) | |
| 434 | 442 | return IMAGE_REL_BASED_DIR64; |
| 435 | 443 | return IMAGE_REL_BASED_ABSOLUTE; |
| 436 | 444 | default: |
| ... | ... | @@ -442,18 +450,16 @@ static uint8_t getBaserelType(const coff_relocation &Rel) { |
| 442 | 450 | // Collect all locations that contain absolute addresses, which need to be |
| 443 | 451 | // fixed by the loader if load-time relocation is needed. |
| 444 | 452 | // Only called when base relocation is enabled. |
| 445 | void SectionChunk::getBaserels(std::vector<Baserel> *Res) { | |
| 446 | for (size_t I = 0, E = Relocs.size(); I < E; I++) { | |
| 447 | const coff_relocation &Rel = Relocs[I]; | |
| 448 | uint8_t Ty = getBaserelType(Rel); | |
| 449 | if (Ty == IMAGE_REL_BASED_ABSOLUTE) | |
| 453 | void SectionChunk::getBaserels(std::vector<Baserel> *res) { | |
| 454 | for (size_t i = 0, e = relocsSize; i < e; i++) { | |
| 455 | const coff_relocation &rel = relocsData[i]; | |
| 456 | uint8_t ty = getBaserelType(rel); | |
| 457 | if (ty == IMAGE_REL_BASED_ABSOLUTE) | |
| 450 | 458 | continue; |
| 451 | // Use the potentially remapped Symbol instead of the one that the | |
| 452 | // relocation points to. | |
| 453 | Symbol *Target = RelocTargets[I]; | |
| 454 | if (!Target || isa<DefinedAbsolute>(Target)) | |
| 459 | Symbol *target = file->getSymbol(rel.SymbolTableIndex); | |
| 460 | if (!target || isa<DefinedAbsolute>(target)) | |
| 455 | 461 | continue; |
| 456 | Res->emplace_back(RVA + Rel.VirtualAddress, Ty); | |
| 462 | res->emplace_back(rva + rel.VirtualAddress, ty); | |
| 457 | 463 | } |
| 458 | 464 | } |
| 459 | 465 | |
| ... | ... | @@ -464,7 +470,7 @@ void SectionChunk::getBaserels(std::vector<Baserel> *Res) { |
| 464 | 470 | // another DLL) This returns the size the relocation is supposed to update, |
| 465 | 471 | // in bits, or 0 if the relocation cannot be handled as a runtime pseudo |
| 466 | 472 | // relocation. |
| 467 | static int getRuntimePseudoRelocSize(uint16_t Type) { | |
| 473 | static int getRuntimePseudoRelocSize(uint16_t type) { | |
| 468 | 474 | // Relocations that either contain an absolute address, or a plain |
| 469 | 475 | // relative offset, since the runtime pseudo reloc implementation |
| 470 | 476 | // adds 8/16/32/64 bit values to a memory address. |
| ... | ... | @@ -490,9 +496,9 @@ static int getRuntimePseudoRelocSize(uint16_t Type) { |
| 490 | 496 | // the image, or temporarily changed at runtime with VirtualProtect. |
| 491 | 497 | // Since this only operates on direct address values, it doesn't work for |
| 492 | 498 | // ARM/ARM64 relocations, other than the plain ADDR32/ADDR64 relocations. |
| 493 | switch (Config->Machine) { | |
| 499 | switch (config->machine) { | |
| 494 | 500 | case AMD64: |
| 495 | switch (Type) { | |
| 501 | switch (type) { | |
| 496 | 502 | case IMAGE_REL_AMD64_ADDR64: |
| 497 | 503 | return 64; |
| 498 | 504 | case IMAGE_REL_AMD64_ADDR32: |
| ... | ... | @@ -507,7 +513,7 @@ static int getRuntimePseudoRelocSize(uint16_t Type) { |
| 507 | 513 | return 0; |
| 508 | 514 | } |
| 509 | 515 | case I386: |
| 510 | switch (Type) { | |
| 516 | switch (type) { | |
| 511 | 517 | case IMAGE_REL_I386_DIR32: |
| 512 | 518 | case IMAGE_REL_I386_REL32: |
| 513 | 519 | return 32; |
| ... | ... | @@ -515,14 +521,14 @@ static int getRuntimePseudoRelocSize(uint16_t Type) { |
| 515 | 521 | return 0; |
| 516 | 522 | } |
| 517 | 523 | case ARMNT: |
| 518 | switch (Type) { | |
| 524 | switch (type) { | |
| 519 | 525 | case IMAGE_REL_ARM_ADDR32: |
| 520 | 526 | return 32; |
| 521 | 527 | default: |
| 522 | 528 | return 0; |
| 523 | 529 | } |
| 524 | 530 | case ARM64: |
| 525 | switch (Type) { | |
| 531 | switch (type) { | |
| 526 | 532 | case IMAGE_REL_ARM64_ADDR64: |
| 527 | 533 | return 64; |
| 528 | 534 | case IMAGE_REL_ARM64_ADDR32: |
| ... | ... | @@ -541,75 +547,106 @@ static int getRuntimePseudoRelocSize(uint16_t Type) { |
| 541 | 547 | // to a module local variable, which turned out to actually need to be |
| 542 | 548 | // imported from another DLL). |
| 543 | 549 | void SectionChunk::getRuntimePseudoRelocs( |
| 544 | std::vector<RuntimePseudoReloc> &Res) { | |
| 545 | for (const coff_relocation &Rel : Relocs) { | |
| 546 | auto *Target = | |
| 547 | dyn_cast_or_null<Defined>(File->getSymbol(Rel.SymbolTableIndex)); | |
| 548 | if (!Target || !Target->IsRuntimePseudoReloc) | |
| 550 | std::vector<RuntimePseudoReloc> &res) { | |
| 551 | for (const coff_relocation &rel : getRelocs()) { | |
| 552 | auto *target = | |
| 553 | dyn_cast_or_null<Defined>(file->getSymbol(rel.SymbolTableIndex)); | |
| 554 | if (!target || !target->isRuntimePseudoReloc) | |
| 549 | 555 | continue; |
| 550 | int SizeInBits = getRuntimePseudoRelocSize(Rel.Type); | |
| 551 | if (SizeInBits == 0) { | |
| 552 | error("unable to automatically import from " + Target->getName() + | |
| 556 | int sizeInBits = getRuntimePseudoRelocSize(rel.Type); | |
| 557 | if (sizeInBits == 0) { | |
| 558 | error("unable to automatically import from " + target->getName() + | |
| 553 | 559 | " with relocation type " + |
| 554 | File->getCOFFObj()->getRelocationTypeName(Rel.Type) + " in " + | |
| 555 | toString(File)); | |
| 560 | file->getCOFFObj()->getRelocationTypeName(rel.Type) + " in " + | |
| 561 | toString(file)); | |
| 556 | 562 | continue; |
| 557 | 563 | } |
| 558 | // SizeInBits is used to initialize the Flags field; currently no | |
| 564 | // sizeInBits is used to initialize the Flags field; currently no | |
| 559 | 565 | // other flags are defined. |
| 560 | Res.emplace_back( | |
| 561 | RuntimePseudoReloc(Target, this, Rel.VirtualAddress, SizeInBits)); | |
| 566 | res.emplace_back( | |
| 567 | RuntimePseudoReloc(target, this, rel.VirtualAddress, sizeInBits)); | |
| 562 | 568 | } |
| 563 | 569 | } |
| 564 | 570 | |
| 565 | bool SectionChunk::hasData() const { | |
| 566 | return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA); | |
| 567 | } | |
| 568 | ||
| 569 | uint32_t SectionChunk::getOutputCharacteristics() const { | |
| 570 | return Header->Characteristics & (PermMask | TypeMask); | |
| 571 | } | |
| 572 | ||
| 573 | 571 | bool SectionChunk::isCOMDAT() const { |
| 574 | return Header->Characteristics & IMAGE_SCN_LNK_COMDAT; | |
| 572 | return header->Characteristics & IMAGE_SCN_LNK_COMDAT; | |
| 575 | 573 | } |
| 576 | 574 | |
| 577 | 575 | void SectionChunk::printDiscardedMessage() const { |
| 578 | 576 | // Removed by dead-stripping. If it's removed by ICF, ICF already |
| 579 | 577 | // printed out the name, so don't repeat that here. |
| 580 | if (Sym && this == Repl) | |
| 581 | message("Discarded " + Sym->getName()); | |
| 578 | if (sym && this == repl) | |
| 579 | message("Discarded " + sym->getName()); | |
| 582 | 580 | } |
| 583 | 581 | |
| 584 | StringRef SectionChunk::getDebugName() { | |
| 585 | if (Sym) | |
| 586 | return Sym->getName(); | |
| 582 | StringRef SectionChunk::getDebugName() const { | |
| 583 | if (sym) | |
| 584 | return sym->getName(); | |
| 587 | 585 | return ""; |
| 588 | 586 | } |
| 589 | 587 | |
| 590 | 588 | ArrayRef<uint8_t> SectionChunk::getContents() const { |
| 591 | ArrayRef<uint8_t> A; | |
| 592 | File->getCOFFObj()->getSectionContents(Header, A); | |
| 593 | return A; | |
| 589 | ArrayRef<uint8_t> a; | |
| 590 | cantFail(file->getCOFFObj()->getSectionContents(header, a)); | |
| 591 | return a; | |
| 594 | 592 | } |
| 595 | 593 | |
| 596 | void SectionChunk::replace(SectionChunk *Other) { | |
| 597 | Alignment = std::max(Alignment, Other->Alignment); | |
| 598 | Other->Repl = Repl; | |
| 599 | Other->Live = false; | |
| 594 | ArrayRef<uint8_t> SectionChunk::consumeDebugMagic() { | |
| 595 | assert(isCodeView()); | |
| 596 | return consumeDebugMagic(getContents(), getSectionName()); | |
| 597 | } | |
| 598 | ||
| 599 | ArrayRef<uint8_t> SectionChunk::consumeDebugMagic(ArrayRef<uint8_t> data, | |
| 600 | StringRef sectionName) { | |
| 601 | if (data.empty()) | |
| 602 | return {}; | |
| 603 | ||
| 604 | // First 4 bytes are section magic. | |
| 605 | if (data.size() < 4) | |
| 606 | fatal("the section is too short: " + sectionName); | |
| 607 | ||
| 608 | if (!sectionName.startswith(".debug$")) | |
| 609 | fatal("invalid section: " + sectionName); | |
| 610 | ||
| 611 | uint32_t magic = support::endian::read32le(data.data()); | |
| 612 | uint32_t expectedMagic = sectionName == ".debug$H" | |
| 613 | ? DEBUG_HASHES_SECTION_MAGIC | |
| 614 | : DEBUG_SECTION_MAGIC; | |
| 615 | if (magic != expectedMagic) { | |
| 616 | warn("ignoring section " + sectionName + " with unrecognized magic 0x" + | |
| 617 | utohexstr(magic)); | |
| 618 | return {}; | |
| 619 | } | |
| 620 | return data.slice(4); | |
| 621 | } | |
| 622 | ||
| 623 | SectionChunk *SectionChunk::findByName(ArrayRef<SectionChunk *> sections, | |
| 624 | StringRef name) { | |
| 625 | for (SectionChunk *c : sections) | |
| 626 | if (c->getSectionName() == name) | |
| 627 | return c; | |
| 628 | return nullptr; | |
| 629 | } | |
| 630 | ||
| 631 | void SectionChunk::replace(SectionChunk *other) { | |
| 632 | p2Align = std::max(p2Align, other->p2Align); | |
| 633 | other->repl = repl; | |
| 634 | other->live = false; | |
| 600 | 635 | } |
| 601 | 636 | |
| 602 | 637 | uint32_t SectionChunk::getSectionNumber() const { |
| 603 | DataRefImpl R; | |
| 604 | R.p = reinterpret_cast<uintptr_t>(Header); | |
| 605 | SectionRef S(R, File->getCOFFObj()); | |
| 606 | return S.getIndex() + 1; | |
| 638 | DataRefImpl r; | |
| 639 | r.p = reinterpret_cast<uintptr_t>(header); | |
| 640 | SectionRef s(r, file->getCOFFObj()); | |
| 641 | return s.getIndex() + 1; | |
| 607 | 642 | } |
| 608 | 643 | |
| 609 | CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) { | |
| 610 | // Common symbols are aligned on natural boundaries up to 32 bytes. | |
| 644 | CommonChunk::CommonChunk(const COFFSymbolRef s) : sym(s) { | |
| 645 | // The value of a common symbol is its size. Align all common symbols smaller | |
| 646 | // than 32 bytes naturally, i.e. round the size up to the next power of two. | |
| 611 | 647 | // This is what MSVC link.exe does. |
| 612 | Alignment = std::min(uint64_t(32), PowerOf2Ceil(Sym.getValue())); | |
| 648 | setAlignment(std::min(32U, uint32_t(PowerOf2Ceil(sym.getValue())))); | |
| 649 | hasData = false; | |
| 613 | 650 | } |
| 614 | 651 | |
| 615 | 652 | uint32_t CommonChunk::getOutputCharacteristics() const { |
| ... | ... | @@ -617,139 +654,139 @@ uint32_t CommonChunk::getOutputCharacteristics() const { |
| 617 | 654 | IMAGE_SCN_MEM_WRITE; |
| 618 | 655 | } |
| 619 | 656 | |
| 620 | void StringChunk::writeTo(uint8_t *Buf) const { | |
| 621 | memcpy(Buf + OutputSectionOff, Str.data(), Str.size()); | |
| 622 | Buf[OutputSectionOff + Str.size()] = '\0'; | |
| 657 | void StringChunk::writeTo(uint8_t *buf) const { | |
| 658 | memcpy(buf, str.data(), str.size()); | |
| 659 | buf[str.size()] = '\0'; | |
| 623 | 660 | } |
| 624 | 661 | |
| 625 | ImportThunkChunkX64::ImportThunkChunkX64(Defined *S) : ImpSymbol(S) { | |
| 662 | ImportThunkChunkX64::ImportThunkChunkX64(Defined *s) : ImportThunkChunk(s) { | |
| 626 | 663 | // Intel Optimization Manual says that all branch targets |
| 627 | 664 | // should be 16-byte aligned. MSVC linker does this too. |
| 628 | Alignment = 16; | |
| 665 | setAlignment(16); | |
| 629 | 666 | } |
| 630 | 667 | |
| 631 | void ImportThunkChunkX64::writeTo(uint8_t *Buf) const { | |
| 632 | memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); | |
| 668 | void ImportThunkChunkX64::writeTo(uint8_t *buf) const { | |
| 669 | memcpy(buf, importThunkX86, sizeof(importThunkX86)); | |
| 633 | 670 | // The first two bytes is a JMP instruction. Fill its operand. |
| 634 | write32le(Buf + OutputSectionOff + 2, ImpSymbol->getRVA() - RVA - getSize()); | |
| 671 | write32le(buf + 2, impSymbol->getRVA() - rva - getSize()); | |
| 635 | 672 | } |
| 636 | 673 | |
| 637 | void ImportThunkChunkX86::getBaserels(std::vector<Baserel> *Res) { | |
| 638 | Res->emplace_back(getRVA() + 2); | |
| 674 | void ImportThunkChunkX86::getBaserels(std::vector<Baserel> *res) { | |
| 675 | res->emplace_back(getRVA() + 2); | |
| 639 | 676 | } |
| 640 | 677 | |
| 641 | void ImportThunkChunkX86::writeTo(uint8_t *Buf) const { | |
| 642 | memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); | |
| 678 | void ImportThunkChunkX86::writeTo(uint8_t *buf) const { | |
| 679 | memcpy(buf, importThunkX86, sizeof(importThunkX86)); | |
| 643 | 680 | // The first two bytes is a JMP instruction. Fill its operand. |
| 644 | write32le(Buf + OutputSectionOff + 2, | |
| 645 | ImpSymbol->getRVA() + Config->ImageBase); | |
| 681 | write32le(buf + 2, | |
| 682 | impSymbol->getRVA() + config->imageBase); | |
| 646 | 683 | } |
| 647 | 684 | |
| 648 | void ImportThunkChunkARM::getBaserels(std::vector<Baserel> *Res) { | |
| 649 | Res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T); | |
| 685 | void ImportThunkChunkARM::getBaserels(std::vector<Baserel> *res) { | |
| 686 | res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T); | |
| 650 | 687 | } |
| 651 | 688 | |
| 652 | void ImportThunkChunkARM::writeTo(uint8_t *Buf) const { | |
| 653 | memcpy(Buf + OutputSectionOff, ImportThunkARM, sizeof(ImportThunkARM)); | |
| 689 | void ImportThunkChunkARM::writeTo(uint8_t *buf) const { | |
| 690 | memcpy(buf, importThunkARM, sizeof(importThunkARM)); | |
| 654 | 691 | // Fix mov.w and mov.t operands. |
| 655 | applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase); | |
| 692 | applyMOV32T(buf, impSymbol->getRVA() + config->imageBase); | |
| 656 | 693 | } |
| 657 | 694 | |
| 658 | void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const { | |
| 659 | int64_t Off = ImpSymbol->getRVA() & 0xfff; | |
| 660 | memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64)); | |
| 661 | applyArm64Addr(Buf + OutputSectionOff, ImpSymbol->getRVA(), RVA, 12); | |
| 662 | applyArm64Ldr(Buf + OutputSectionOff + 4, Off); | |
| 695 | void ImportThunkChunkARM64::writeTo(uint8_t *buf) const { | |
| 696 | int64_t off = impSymbol->getRVA() & 0xfff; | |
| 697 | memcpy(buf, importThunkARM64, sizeof(importThunkARM64)); | |
| 698 | applyArm64Addr(buf, impSymbol->getRVA(), rva, 12); | |
| 699 | applyArm64Ldr(buf + 4, off); | |
| 663 | 700 | } |
| 664 | 701 | |
| 665 | 702 | // A Thumb2, PIC, non-interworking range extension thunk. |
| 666 | const uint8_t ArmThunk[] = { | |
| 703 | const uint8_t armThunk[] = { | |
| 667 | 704 | 0x40, 0xf2, 0x00, 0x0c, // P: movw ip,:lower16:S - (P + (L1-P) + 4) |
| 668 | 705 | 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4) |
| 669 | 706 | 0xe7, 0x44, // L1: add pc, ip |
| 670 | 707 | }; |
| 671 | 708 | |
| 672 | 709 | size_t RangeExtensionThunkARM::getSize() const { |
| 673 | assert(Config->Machine == ARMNT); | |
| 674 | return sizeof(ArmThunk); | |
| 710 | assert(config->machine == ARMNT); | |
| 711 | return sizeof(armThunk); | |
| 675 | 712 | } |
| 676 | 713 | |
| 677 | void RangeExtensionThunkARM::writeTo(uint8_t *Buf) const { | |
| 678 | assert(Config->Machine == ARMNT); | |
| 679 | uint64_t Offset = Target->getRVA() - RVA - 12; | |
| 680 | memcpy(Buf + OutputSectionOff, ArmThunk, sizeof(ArmThunk)); | |
| 681 | applyMOV32T(Buf + OutputSectionOff, uint32_t(Offset)); | |
| 714 | void RangeExtensionThunkARM::writeTo(uint8_t *buf) const { | |
| 715 | assert(config->machine == ARMNT); | |
| 716 | uint64_t offset = target->getRVA() - rva - 12; | |
| 717 | memcpy(buf, armThunk, sizeof(armThunk)); | |
| 718 | applyMOV32T(buf, uint32_t(offset)); | |
| 682 | 719 | } |
| 683 | 720 | |
| 684 | 721 | // A position independent ARM64 adrp+add thunk, with a maximum range of |
| 685 | 722 | // +/- 4 GB, which is enough for any PE-COFF. |
| 686 | const uint8_t Arm64Thunk[] = { | |
| 723 | const uint8_t arm64Thunk[] = { | |
| 687 | 724 | 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest |
| 688 | 725 | 0x10, 0x02, 0x00, 0x91, // add x16, x16, :lo12:Dest |
| 689 | 726 | 0x00, 0x02, 0x1f, 0xd6, // br x16 |
| 690 | 727 | }; |
| 691 | 728 | |
| 692 | 729 | size_t RangeExtensionThunkARM64::getSize() const { |
| 693 | assert(Config->Machine == ARM64); | |
| 694 | return sizeof(Arm64Thunk); | |
| 730 | assert(config->machine == ARM64); | |
| 731 | return sizeof(arm64Thunk); | |
| 695 | 732 | } |
| 696 | 733 | |
| 697 | void RangeExtensionThunkARM64::writeTo(uint8_t *Buf) const { | |
| 698 | assert(Config->Machine == ARM64); | |
| 699 | memcpy(Buf + OutputSectionOff, Arm64Thunk, sizeof(Arm64Thunk)); | |
| 700 | applyArm64Addr(Buf + OutputSectionOff + 0, Target->getRVA(), RVA, 12); | |
| 701 | applyArm64Imm(Buf + OutputSectionOff + 4, Target->getRVA() & 0xfff, 0); | |
| 734 | void RangeExtensionThunkARM64::writeTo(uint8_t *buf) const { | |
| 735 | assert(config->machine == ARM64); | |
| 736 | memcpy(buf, arm64Thunk, sizeof(arm64Thunk)); | |
| 737 | applyArm64Addr(buf + 0, target->getRVA(), rva, 12); | |
| 738 | applyArm64Imm(buf + 4, target->getRVA() & 0xfff, 0); | |
| 702 | 739 | } |
| 703 | 740 | |
| 704 | void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) { | |
| 705 | Res->emplace_back(getRVA()); | |
| 741 | void LocalImportChunk::getBaserels(std::vector<Baserel> *res) { | |
| 742 | res->emplace_back(getRVA()); | |
| 706 | 743 | } |
| 707 | 744 | |
| 708 | size_t LocalImportChunk::getSize() const { return Config->Wordsize; } | |
| 745 | size_t LocalImportChunk::getSize() const { return config->wordsize; } | |
| 709 | 746 | |
| 710 | void LocalImportChunk::writeTo(uint8_t *Buf) const { | |
| 711 | if (Config->is64()) { | |
| 712 | write64le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); | |
| 747 | void LocalImportChunk::writeTo(uint8_t *buf) const { | |
| 748 | if (config->is64()) { | |
| 749 | write64le(buf, sym->getRVA() + config->imageBase); | |
| 713 | 750 | } else { |
| 714 | write32le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); | |
| 751 | write32le(buf, sym->getRVA() + config->imageBase); | |
| 715 | 752 | } |
| 716 | 753 | } |
| 717 | 754 | |
| 718 | void RVATableChunk::writeTo(uint8_t *Buf) const { | |
| 719 | ulittle32_t *Begin = reinterpret_cast<ulittle32_t *>(Buf + OutputSectionOff); | |
| 720 | size_t Cnt = 0; | |
| 721 | for (const ChunkAndOffset &CO : Syms) | |
| 722 | Begin[Cnt++] = CO.InputChunk->getRVA() + CO.Offset; | |
| 723 | std::sort(Begin, Begin + Cnt); | |
| 724 | assert(std::unique(Begin, Begin + Cnt) == Begin + Cnt && | |
| 755 | void RVATableChunk::writeTo(uint8_t *buf) const { | |
| 756 | ulittle32_t *begin = reinterpret_cast<ulittle32_t *>(buf); | |
| 757 | size_t cnt = 0; | |
| 758 | for (const ChunkAndOffset &co : syms) | |
| 759 | begin[cnt++] = co.inputChunk->getRVA() + co.offset; | |
| 760 | std::sort(begin, begin + cnt); | |
| 761 | assert(std::unique(begin, begin + cnt) == begin + cnt && | |
| 725 | 762 | "RVA tables should be de-duplicated"); |
| 726 | 763 | } |
| 727 | 764 | |
| 728 | 765 | // MinGW specific, for the "automatic import of variables from DLLs" feature. |
| 729 | 766 | size_t PseudoRelocTableChunk::getSize() const { |
| 730 | if (Relocs.empty()) | |
| 767 | if (relocs.empty()) | |
| 731 | 768 | return 0; |
| 732 | return 12 + 12 * Relocs.size(); | |
| 769 | return 12 + 12 * relocs.size(); | |
| 733 | 770 | } |
| 734 | 771 | |
| 735 | 772 | // MinGW specific. |
| 736 | void PseudoRelocTableChunk::writeTo(uint8_t *Buf) const { | |
| 737 | if (Relocs.empty()) | |
| 773 | void PseudoRelocTableChunk::writeTo(uint8_t *buf) const { | |
| 774 | if (relocs.empty()) | |
| 738 | 775 | return; |
| 739 | 776 | |
| 740 | ulittle32_t *Table = reinterpret_cast<ulittle32_t *>(Buf + OutputSectionOff); | |
| 777 | ulittle32_t *table = reinterpret_cast<ulittle32_t *>(buf); | |
| 741 | 778 | // This is the list header, to signal the runtime pseudo relocation v2 |
| 742 | 779 | // format. |
| 743 | Table[0] = 0; | |
| 744 | Table[1] = 0; | |
| 745 | Table[2] = 1; | |
| 746 | ||
| 747 | size_t Idx = 3; | |
| 748 | for (const RuntimePseudoReloc &RPR : Relocs) { | |
| 749 | Table[Idx + 0] = RPR.Sym->getRVA(); | |
| 750 | Table[Idx + 1] = RPR.Target->getRVA() + RPR.TargetOffset; | |
| 751 | Table[Idx + 2] = RPR.Flags; | |
| 752 | Idx += 3; | |
| 780 | table[0] = 0; | |
| 781 | table[1] = 0; | |
| 782 | table[2] = 1; | |
| 783 | ||
| 784 | size_t idx = 3; | |
| 785 | for (const RuntimePseudoReloc &rpr : relocs) { | |
| 786 | table[idx + 0] = rpr.sym->getRVA(); | |
| 787 | table[idx + 1] = rpr.target->getRVA() + rpr.targetOffset; | |
| 788 | table[idx + 2] = rpr.flags; | |
| 789 | idx += 3; | |
| 753 | 790 | } |
| 754 | 791 | } |
| 755 | 792 | |
| ... | ... | @@ -792,26 +829,26 @@ void PseudoRelocTableChunk::writeTo(uint8_t *Buf) const { |
| 792 | 829 | // |
| 793 | 830 | // Usually we have a lot of relocations for each page, so the number of |
| 794 | 831 | // bytes for one .reloc entry is close to 2 bytes on average. |
| 795 | BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) { | |
| 832 | BaserelChunk::BaserelChunk(uint32_t page, Baserel *begin, Baserel *end) { | |
| 796 | 833 | // Block header consists of 4 byte page RVA and 4 byte block size. |
| 797 | 834 | // Each entry is 2 byte. Last entry may be padding. |
| 798 | Data.resize(alignTo((End - Begin) * 2 + 8, 4)); | |
| 799 | uint8_t *P = Data.data(); | |
| 800 | write32le(P, Page); | |
| 801 | write32le(P + 4, Data.size()); | |
| 802 | P += 8; | |
| 803 | for (Baserel *I = Begin; I != End; ++I) { | |
| 804 | write16le(P, (I->Type << 12) | (I->RVA - Page)); | |
| 805 | P += 2; | |
| 835 | data.resize(alignTo((end - begin) * 2 + 8, 4)); | |
| 836 | uint8_t *p = data.data(); | |
| 837 | write32le(p, page); | |
| 838 | write32le(p + 4, data.size()); | |
| 839 | p += 8; | |
| 840 | for (Baserel *i = begin; i != end; ++i) { | |
| 841 | write16le(p, (i->type << 12) | (i->rva - page)); | |
| 842 | p += 2; | |
| 806 | 843 | } |
| 807 | 844 | } |
| 808 | 845 | |
| 809 | void BaserelChunk::writeTo(uint8_t *Buf) const { | |
| 810 | memcpy(Buf + OutputSectionOff, Data.data(), Data.size()); | |
| 846 | void BaserelChunk::writeTo(uint8_t *buf) const { | |
| 847 | memcpy(buf, data.data(), data.size()); | |
| 811 | 848 | } |
| 812 | 849 | |
| 813 | 850 | uint8_t Baserel::getDefaultType() { |
| 814 | switch (Config->Machine) { | |
| 851 | switch (config->machine) { | |
| 815 | 852 | case AMD64: |
| 816 | 853 | case ARM64: |
| 817 | 854 | return IMAGE_REL_BASED_DIR64; |
| ... | ... | @@ -823,36 +860,38 @@ uint8_t Baserel::getDefaultType() { |
| 823 | 860 | } |
| 824 | 861 | } |
| 825 | 862 | |
| 826 | std::map<uint32_t, MergeChunk *> MergeChunk::Instances; | |
| 863 | MergeChunk *MergeChunk::instances[Log2MaxSectionAlignment + 1] = {}; | |
| 827 | 864 | |
| 828 | MergeChunk::MergeChunk(uint32_t Alignment) | |
| 829 | : Builder(StringTableBuilder::RAW, Alignment) { | |
| 830 | this->Alignment = Alignment; | |
| 865 | MergeChunk::MergeChunk(uint32_t alignment) | |
| 866 | : builder(StringTableBuilder::RAW, alignment) { | |
| 867 | setAlignment(alignment); | |
| 831 | 868 | } |
| 832 | 869 | |
| 833 | void MergeChunk::addSection(SectionChunk *C) { | |
| 834 | auto *&MC = Instances[C->Alignment]; | |
| 835 | if (!MC) | |
| 836 | MC = make<MergeChunk>(C->Alignment); | |
| 837 | MC->Sections.push_back(C); | |
| 870 | void MergeChunk::addSection(SectionChunk *c) { | |
| 871 | assert(isPowerOf2_32(c->getAlignment())); | |
| 872 | uint8_t p2Align = llvm::Log2_32(c->getAlignment()); | |
| 873 | assert(p2Align < array_lengthof(instances)); | |
| 874 | auto *&mc = instances[p2Align]; | |
| 875 | if (!mc) | |
| 876 | mc = make<MergeChunk>(c->getAlignment()); | |
| 877 | mc->sections.push_back(c); | |
| 838 | 878 | } |
| 839 | 879 | |
| 840 | 880 | void MergeChunk::finalizeContents() { |
| 841 | if (!Finalized) { | |
| 842 | for (SectionChunk *C : Sections) | |
| 843 | if (C->Live) | |
| 844 | Builder.add(toStringRef(C->getContents())); | |
| 845 | Builder.finalize(); | |
| 846 | Finalized = true; | |
| 847 | } | |
| 881 | assert(!finalized && "should only finalize once"); | |
| 882 | for (SectionChunk *c : sections) | |
| 883 | if (c->live) | |
| 884 | builder.add(toStringRef(c->getContents())); | |
| 885 | builder.finalize(); | |
| 886 | finalized = true; | |
| 887 | } | |
| 848 | 888 | |
| 849 | for (SectionChunk *C : Sections) { | |
| 850 | if (!C->Live) | |
| 889 | void MergeChunk::assignSubsectionRVAs() { | |
| 890 | for (SectionChunk *c : sections) { | |
| 891 | if (!c->live) | |
| 851 | 892 | continue; |
| 852 | size_t Off = Builder.getOffset(toStringRef(C->getContents())); | |
| 853 | C->setOutputSection(Out); | |
| 854 | C->setRVA(RVA + Off); | |
| 855 | C->OutputSectionOff = OutputSectionOff + Off; | |
| 893 | size_t off = builder.getOffset(toStringRef(c->getContents())); | |
| 894 | c->setRVA(rva + off); | |
| 856 | 895 | } |
| 857 | 896 | } |
| 858 | 897 | |
| ... | ... | @@ -861,21 +900,21 @@ uint32_t MergeChunk::getOutputCharacteristics() const { |
| 861 | 900 | } |
| 862 | 901 | |
| 863 | 902 | size_t MergeChunk::getSize() const { |
| 864 | return Builder.getSize(); | |
| 903 | return builder.getSize(); | |
| 865 | 904 | } |
| 866 | 905 | |
| 867 | void MergeChunk::writeTo(uint8_t *Buf) const { | |
| 868 | Builder.write(Buf + OutputSectionOff); | |
| 906 | void MergeChunk::writeTo(uint8_t *buf) const { | |
| 907 | builder.write(buf); | |
| 869 | 908 | } |
| 870 | 909 | |
| 871 | 910 | // MinGW specific. |
| 872 | size_t AbsolutePointerChunk::getSize() const { return Config->Wordsize; } | |
| 911 | size_t AbsolutePointerChunk::getSize() const { return config->wordsize; } | |
| 873 | 912 | |
| 874 | void AbsolutePointerChunk::writeTo(uint8_t *Buf) const { | |
| 875 | if (Config->is64()) { | |
| 876 | write64le(Buf + OutputSectionOff, Value); | |
| 913 | void AbsolutePointerChunk::writeTo(uint8_t *buf) const { | |
| 914 | if (config->is64()) { | |
| 915 | write64le(buf, value); | |
| 877 | 916 | } else { |
| 878 | write32le(Buf + OutputSectionOff, Value); | |
| 917 | write32le(buf, value); | |
| 879 | 918 | } |
| 880 | 919 | } |
| 881 | 920 |
deps/lld/COFF/Chunks.h+368-209| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Chunks.h -------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -14,6 +13,7 @@ |
| 14 | 13 | #include "InputFiles.h" |
| 15 | 14 | #include "lld/Common/LLVM.h" |
| 16 | 15 | #include "llvm/ADT/ArrayRef.h" |
| 16 | #include "llvm/ADT/PointerIntPair.h" | |
| 17 | 17 | #include "llvm/ADT/iterator.h" |
| 18 | 18 | #include "llvm/ADT/iterator_range.h" |
| 19 | 19 | #include "llvm/MC/StringTableBuilder.h" |
| ... | ... | @@ -40,10 +40,13 @@ class RuntimePseudoReloc; |
| 40 | 40 | class Symbol; |
| 41 | 41 | |
| 42 | 42 | // Mask for permissions (discardable, writable, readable, executable, etc). |
| 43 | const uint32_t PermMask = 0xFE000000; | |
| 43 | const uint32_t permMask = 0xFE000000; | |
| 44 | 44 | |
| 45 | 45 | // Mask for section types (code, data, bss). |
| 46 | const uint32_t TypeMask = 0x000000E0; | |
| 46 | const uint32_t typeMask = 0x000000E0; | |
| 47 | ||
| 48 | // The log base 2 of the largest section alignment, which is log2(8192), or 13. | |
| 49 | enum : unsigned { Log2MaxSectionAlignment = 13 }; | |
| 47 | 50 | |
| 48 | 51 | // A Chunk represents a chunk of data that will occupy space in the |
| 49 | 52 | // output (if the resolver chose that). It may or may not be backed by |
| ... | ... | @@ -51,81 +54,126 @@ const uint32_t TypeMask = 0x000000E0; |
| 51 | 54 | // doesn't even have actual data (if common or bss). |
| 52 | 55 | class Chunk { |
| 53 | 56 | public: |
| 54 | enum Kind { SectionKind, OtherKind }; | |
| 55 | Kind kind() const { return ChunkKind; } | |
| 56 | virtual ~Chunk() = default; | |
| 57 | enum Kind : uint8_t { SectionKind, OtherKind, ImportThunkKind }; | |
| 58 | Kind kind() const { return chunkKind; } | |
| 57 | 59 | |
| 58 | 60 | // Returns the size of this chunk (even if this is a common or BSS.) |
| 59 | virtual size_t getSize() const = 0; | |
| 61 | size_t getSize() const; | |
| 62 | ||
| 63 | // Returns chunk alignment in power of two form. Value values are powers of | |
| 64 | // two from 1 to 8192. | |
| 65 | uint32_t getAlignment() const { return 1U << p2Align; } | |
| 66 | ||
| 67 | // Update the chunk section alignment measured in bytes. Internally alignment | |
| 68 | // is stored in log2. | |
| 69 | void setAlignment(uint32_t align) { | |
| 70 | // Treat zero byte alignment as 1 byte alignment. | |
| 71 | align = align ? align : 1; | |
| 72 | assert(llvm::isPowerOf2_32(align) && "alignment is not a power of 2"); | |
| 73 | p2Align = llvm::Log2_32(align); | |
| 74 | assert(p2Align <= Log2MaxSectionAlignment && | |
| 75 | "impossible requested alignment"); | |
| 76 | } | |
| 60 | 77 | |
| 61 | 78 | // Write this chunk to a mmap'ed file, assuming Buf is pointing to |
| 62 | 79 | // beginning of the file. Because this function may use RVA values |
| 63 | 80 | // of other chunks for relocations, you need to set them properly |
| 64 | 81 | // before calling this function. |
| 65 | virtual void writeTo(uint8_t *Buf) const {} | |
| 82 | void writeTo(uint8_t *buf) const; | |
| 83 | ||
| 84 | // The writer sets and uses the addresses. In practice, PE images cannot be | |
| 85 | // larger than 2GB. Chunks are always laid as part of the image, so Chunk RVAs | |
| 86 | // can be stored with 32 bits. | |
| 87 | uint32_t getRVA() const { return rva; } | |
| 88 | void setRVA(uint64_t v) { | |
| 89 | rva = (uint32_t)v; | |
| 90 | assert(rva == v && "RVA truncated"); | |
| 91 | } | |
| 66 | 92 | |
| 67 | // Called by the writer once before assigning addresses and writing | |
| 68 | // the output. | |
| 69 | virtual void readRelocTargets() {} | |
| 93 | // Returns readable/writable/executable bits. | |
| 94 | uint32_t getOutputCharacteristics() const; | |
| 70 | 95 | |
| 71 | // Called if restarting thunk addition. | |
| 72 | virtual void resetRelocTargets() {} | |
| 96 | // Returns the section name if this is a section chunk. | |
| 97 | // It is illegal to call this function on non-section chunks. | |
| 98 | StringRef getSectionName() const; | |
| 73 | 99 | |
| 74 | // Called by the writer after an RVA is assigned, but before calling | |
| 75 | // getSize(). | |
| 76 | virtual void finalizeContents() {} | |
| 100 | // An output section has pointers to chunks in the section, and each | |
| 101 | // chunk has a back pointer to an output section. | |
| 102 | void setOutputSectionIdx(uint16_t o) { osidx = o; } | |
| 103 | uint16_t getOutputSectionIdx() const { return osidx; } | |
| 104 | OutputSection *getOutputSection() const; | |
| 77 | 105 | |
| 78 | // The writer sets and uses the addresses. | |
| 79 | uint64_t getRVA() const { return RVA; } | |
| 80 | void setRVA(uint64_t V) { RVA = V; } | |
| 106 | // Windows-specific. | |
| 107 | // Collect all locations that contain absolute addresses for base relocations. | |
| 108 | void getBaserels(std::vector<Baserel> *res); | |
| 81 | 109 | |
| 110 | // Returns a human-readable name of this chunk. Chunks are unnamed chunks of | |
| 111 | // bytes, so this is used only for logging or debugging. | |
| 112 | StringRef getDebugName() const; | |
| 113 | ||
| 114 | // Return true if this file has the hotpatch flag set to true in the | |
| 115 | // S_COMPILE3 record in codeview debug info. Also returns true for some thunks | |
| 116 | // synthesized by the linker. | |
| 117 | bool isHotPatchable() const; | |
| 118 | ||
| 119 | protected: | |
| 120 | Chunk(Kind k = OtherKind) : chunkKind(k), hasData(true), p2Align(0) {} | |
| 121 | ||
| 122 | const Kind chunkKind; | |
| 123 | ||
| 124 | public: | |
| 82 | 125 | // Returns true if this has non-zero data. BSS chunks return |
| 83 | 126 | // false. If false is returned, the space occupied by this chunk |
| 84 | // will be filled with zeros. | |
| 85 | virtual bool hasData() const { return true; } | |
| 127 | // will be filled with zeros. Corresponds to the | |
| 128 | // IMAGE_SCN_CNT_UNINITIALIZED_DATA section characteristic bit. | |
| 129 | uint8_t hasData : 1; | |
| 130 | ||
| 131 | public: | |
| 132 | // The alignment of this chunk, stored in log2 form. The writer uses the | |
| 133 | // value. | |
| 134 | uint8_t p2Align : 7; | |
| 135 | ||
| 136 | // The output section index for this chunk. The first valid section number is | |
| 137 | // one. | |
| 138 | uint16_t osidx = 0; | |
| 139 | ||
| 140 | // The RVA of this chunk in the output. The writer sets a value. | |
| 141 | uint32_t rva = 0; | |
| 142 | }; | |
| 143 | ||
| 144 | class NonSectionChunk : public Chunk { | |
| 145 | public: | |
| 146 | virtual ~NonSectionChunk() = default; | |
| 147 | ||
| 148 | // Returns the size of this chunk (even if this is a common or BSS.) | |
| 149 | virtual size_t getSize() const = 0; | |
| 86 | 150 | |
| 87 | // Returns readable/writable/executable bits. | |
| 88 | 151 | virtual uint32_t getOutputCharacteristics() const { return 0; } |
| 89 | 152 | |
| 153 | // Write this chunk to a mmap'ed file, assuming Buf is pointing to | |
| 154 | // beginning of the file. Because this function may use RVA values | |
| 155 | // of other chunks for relocations, you need to set them properly | |
| 156 | // before calling this function. | |
| 157 | virtual void writeTo(uint8_t *buf) const {} | |
| 158 | ||
| 90 | 159 | // Returns the section name if this is a section chunk. |
| 91 | 160 | // It is illegal to call this function on non-section chunks. |
| 92 | 161 | virtual StringRef getSectionName() const { |
| 93 | 162 | llvm_unreachable("unimplemented getSectionName"); |
| 94 | 163 | } |
| 95 | 164 | |
| 96 | // An output section has pointers to chunks in the section, and each | |
| 97 | // chunk has a back pointer to an output section. | |
| 98 | void setOutputSection(OutputSection *O) { Out = O; } | |
| 99 | OutputSection *getOutputSection() const { return Out; } | |
| 100 | ||
| 101 | 165 | // Windows-specific. |
| 102 | 166 | // Collect all locations that contain absolute addresses for base relocations. |
| 103 | virtual void getBaserels(std::vector<Baserel> *Res) {} | |
| 167 | virtual void getBaserels(std::vector<Baserel> *res) {} | |
| 104 | 168 | |
| 105 | 169 | // Returns a human-readable name of this chunk. Chunks are unnamed chunks of |
| 106 | 170 | // bytes, so this is used only for logging or debugging. |
| 107 | virtual StringRef getDebugName() { return ""; } | |
| 171 | virtual StringRef getDebugName() const { return ""; } | |
| 108 | 172 | |
| 109 | // The alignment of this chunk. The writer uses the value. | |
| 110 | uint32_t Alignment = 1; | |
| 173 | static bool classof(const Chunk *c) { return c->kind() != SectionKind; } | |
| 111 | 174 | |
| 112 | 175 | protected: |
| 113 | Chunk(Kind K = OtherKind) : ChunkKind(K) {} | |
| 114 | const Kind ChunkKind; | |
| 115 | ||
| 116 | // The RVA of this chunk in the output. The writer sets a value. | |
| 117 | uint64_t RVA = 0; | |
| 118 | ||
| 119 | // The output section for this chunk. | |
| 120 | OutputSection *Out = nullptr; | |
| 121 | ||
| 122 | public: | |
| 123 | // The offset from beginning of the output section. The writer sets a value. | |
| 124 | uint64_t OutputSectionOff = 0; | |
| 125 | ||
| 126 | // Whether this section needs to be kept distinct from other sections during | |
| 127 | // ICF. This is set by the driver using address-significance tables. | |
| 128 | bool KeepUnique = false; | |
| 176 | NonSectionChunk(Kind k = OtherKind) : Chunk(k) {} | |
| 129 | 177 | }; |
| 130 | 178 | |
| 131 | 179 | // A chunk corresponding a section of an input file. |
| ... | ... | @@ -139,39 +187,41 @@ public: |
| 139 | 187 | std::random_access_iterator_tag, Symbol *> { |
| 140 | 188 | friend SectionChunk; |
| 141 | 189 | |
| 142 | ObjFile *File; | |
| 190 | ObjFile *file; | |
| 143 | 191 | |
| 144 | symbol_iterator(ObjFile *File, const coff_relocation *I) | |
| 145 | : symbol_iterator::iterator_adaptor_base(I), File(File) {} | |
| 192 | symbol_iterator(ObjFile *file, const coff_relocation *i) | |
| 193 | : symbol_iterator::iterator_adaptor_base(i), file(file) {} | |
| 146 | 194 | |
| 147 | 195 | public: |
| 148 | 196 | symbol_iterator() = default; |
| 149 | 197 | |
| 150 | Symbol *operator*() const { return File->getSymbol(I->SymbolTableIndex); } | |
| 198 | Symbol *operator*() const { return file->getSymbol(I->SymbolTableIndex); } | |
| 151 | 199 | }; |
| 152 | 200 | |
| 153 | SectionChunk(ObjFile *File, const coff_section *Header); | |
| 154 | static bool classof(const Chunk *C) { return C->kind() == SectionKind; } | |
| 155 | void readRelocTargets() override; | |
| 156 | void resetRelocTargets() override; | |
| 157 | size_t getSize() const override { return Header->SizeOfRawData; } | |
| 201 | SectionChunk(ObjFile *file, const coff_section *header); | |
| 202 | static bool classof(const Chunk *c) { return c->kind() == SectionKind; } | |
| 203 | size_t getSize() const { return header->SizeOfRawData; } | |
| 158 | 204 | ArrayRef<uint8_t> getContents() const; |
| 159 | void writeTo(uint8_t *Buf) const override; | |
| 160 | bool hasData() const override; | |
| 161 | uint32_t getOutputCharacteristics() const override; | |
| 162 | StringRef getSectionName() const override { return SectionName; } | |
| 163 | void getBaserels(std::vector<Baserel> *Res) override; | |
| 205 | void writeTo(uint8_t *buf) const; | |
| 206 | ||
| 207 | uint32_t getOutputCharacteristics() const { | |
| 208 | return header->Characteristics & (permMask | typeMask); | |
| 209 | } | |
| 210 | StringRef getSectionName() const { | |
| 211 | return StringRef(sectionNameData, sectionNameSize); | |
| 212 | } | |
| 213 | void getBaserels(std::vector<Baserel> *res); | |
| 164 | 214 | bool isCOMDAT() const; |
| 165 | void applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, | |
| 166 | uint64_t P) const; | |
| 167 | void applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, | |
| 168 | uint64_t P) const; | |
| 169 | void applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, | |
| 170 | uint64_t P) const; | |
| 171 | void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, | |
| 172 | uint64_t P) const; | |
| 215 | void applyRelX64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s, | |
| 216 | uint64_t p) const; | |
| 217 | void applyRelX86(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s, | |
| 218 | uint64_t p) const; | |
| 219 | void applyRelARM(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s, | |
| 220 | uint64_t p) const; | |
| 221 | void applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s, | |
| 222 | uint64_t p) const; | |
| 173 | 223 | |
| 174 | void getRuntimePseudoRelocs(std::vector<RuntimePseudoReloc> &Res); | |
| 224 | void getRuntimePseudoRelocs(std::vector<RuntimePseudoReloc> &res); | |
| 175 | 225 | |
| 176 | 226 | // Called if the garbage collector decides to not include this chunk |
| 177 | 227 | // in a final output. It's supposed to print out a log message to stdout. |
| ... | ... | @@ -179,69 +229,169 @@ public: |
| 179 | 229 | |
| 180 | 230 | // Adds COMDAT associative sections to this COMDAT section. A chunk |
| 181 | 231 | // and its children are treated as a group by the garbage collector. |
| 182 | void addAssociative(SectionChunk *Child); | |
| 232 | void addAssociative(SectionChunk *child); | |
| 183 | 233 | |
| 184 | StringRef getDebugName() override; | |
| 234 | StringRef getDebugName() const; | |
| 185 | 235 | |
| 186 | 236 | // True if this is a codeview debug info chunk. These will not be laid out in |
| 187 | 237 | // the image. Instead they will end up in the PDB, if one is requested. |
| 188 | 238 | bool isCodeView() const { |
| 189 | return SectionName == ".debug" || SectionName.startswith(".debug$"); | |
| 239 | return getSectionName() == ".debug" || getSectionName().startswith(".debug$"); | |
| 190 | 240 | } |
| 191 | 241 | |
| 192 | 242 | // True if this is a DWARF debug info or exception handling chunk. |
| 193 | 243 | bool isDWARF() const { |
| 194 | return SectionName.startswith(".debug_") || SectionName == ".eh_frame"; | |
| 244 | return getSectionName().startswith(".debug_") || getSectionName() == ".eh_frame"; | |
| 195 | 245 | } |
| 196 | 246 | |
| 197 | 247 | // Allow iteration over the bodies of this chunk's relocated symbols. |
| 198 | 248 | llvm::iterator_range<symbol_iterator> symbols() const { |
| 199 | return llvm::make_range(symbol_iterator(File, Relocs.begin()), | |
| 200 | symbol_iterator(File, Relocs.end())); | |
| 249 | return llvm::make_range(symbol_iterator(file, relocsData), | |
| 250 | symbol_iterator(file, relocsData + relocsSize)); | |
| 251 | } | |
| 252 | ||
| 253 | ArrayRef<coff_relocation> getRelocs() const { | |
| 254 | return llvm::makeArrayRef(relocsData, relocsSize); | |
| 201 | 255 | } |
| 202 | 256 | |
| 257 | // Reloc setter used by ARM range extension thunk insertion. | |
| 258 | void setRelocs(ArrayRef<coff_relocation> newRelocs) { | |
| 259 | relocsData = newRelocs.data(); | |
| 260 | relocsSize = newRelocs.size(); | |
| 261 | assert(relocsSize == newRelocs.size() && "reloc size truncation"); | |
| 262 | } | |
| 263 | ||
| 264 | // Single linked list iterator for associated comdat children. | |
| 265 | class AssociatedIterator | |
| 266 | : public llvm::iterator_facade_base< | |
| 267 | AssociatedIterator, std::forward_iterator_tag, SectionChunk> { | |
| 268 | public: | |
| 269 | AssociatedIterator() = default; | |
| 270 | AssociatedIterator(SectionChunk *head) : cur(head) {} | |
| 271 | AssociatedIterator &operator=(const AssociatedIterator &r) { | |
| 272 | cur = r.cur; | |
| 273 | return *this; | |
| 274 | } | |
| 275 | bool operator==(const AssociatedIterator &r) const { return cur == r.cur; } | |
| 276 | const SectionChunk &operator*() const { return *cur; } | |
| 277 | SectionChunk &operator*() { return *cur; } | |
| 278 | AssociatedIterator &operator++() { | |
| 279 | cur = cur->assocChildren; | |
| 280 | return *this; | |
| 281 | } | |
| 282 | ||
| 283 | private: | |
| 284 | SectionChunk *cur = nullptr; | |
| 285 | }; | |
| 286 | ||
| 203 | 287 | // Allow iteration over the associated child chunks for this section. |
| 204 | ArrayRef<SectionChunk *> children() const { return AssocChildren; } | |
| 288 | llvm::iterator_range<AssociatedIterator> children() const { | |
| 289 | return llvm::make_range(AssociatedIterator(assocChildren), | |
| 290 | AssociatedIterator(nullptr)); | |
| 291 | } | |
| 205 | 292 | |
| 206 | 293 | // The section ID this chunk belongs to in its Obj. |
| 207 | 294 | uint32_t getSectionNumber() const; |
| 208 | 295 | |
| 209 | // A pointer pointing to a replacement for this chunk. | |
| 210 | // Initially it points to "this" object. If this chunk is merged | |
| 211 | // with other chunk by ICF, it points to another chunk, | |
| 212 | // and this chunk is considered as dead. | |
| 213 | SectionChunk *Repl; | |
| 296 | ArrayRef<uint8_t> consumeDebugMagic(); | |
| 214 | 297 | |
| 215 | // The CRC of the contents as described in the COFF spec 4.5.5. | |
| 216 | // Auxiliary Format 5: Section Definitions. Used for ICF. | |
| 217 | uint32_t Checksum = 0; | |
| 298 | static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> data, | |
| 299 | StringRef sectionName); | |
| 218 | 300 | |
| 219 | const coff_section *Header; | |
| 301 | static SectionChunk *findByName(ArrayRef<SectionChunk *> sections, | |
| 302 | StringRef name); | |
| 220 | 303 | |
| 221 | 304 | // The file that this chunk was created from. |
| 222 | ObjFile *File; | |
| 305 | ObjFile *file; | |
| 306 | ||
| 307 | // Pointer to the COFF section header in the input file. | |
| 308 | const coff_section *header; | |
| 223 | 309 | |
| 224 | 310 | // The COMDAT leader symbol if this is a COMDAT chunk. |
| 225 | DefinedRegular *Sym = nullptr; | |
| 311 | DefinedRegular *sym = nullptr; | |
| 226 | 312 | |
| 227 | ArrayRef<coff_relocation> Relocs; | |
| 313 | // The CRC of the contents as described in the COFF spec 4.5.5. | |
| 314 | // Auxiliary Format 5: Section Definitions. Used for ICF. | |
| 315 | uint32_t checksum = 0; | |
| 228 | 316 | |
| 229 | 317 | // Used by the garbage collector. |
| 230 | bool Live; | |
| 318 | bool live; | |
| 319 | ||
| 320 | // Whether this section needs to be kept distinct from other sections during | |
| 321 | // ICF. This is set by the driver using address-significance tables. | |
| 322 | bool keepUnique = false; | |
| 231 | 323 | |
| 232 | // When inserting a thunk, we need to adjust a relocation to point to | |
| 233 | // the thunk instead of the actual original target Symbol. | |
| 234 | std::vector<Symbol *> RelocTargets; | |
| 324 | // The COMDAT selection if this is a COMDAT chunk. | |
| 325 | llvm::COFF::COMDATType selection = (llvm::COFF::COMDATType)0; | |
| 326 | ||
| 327 | // A pointer pointing to a replacement for this chunk. | |
| 328 | // Initially it points to "this" object. If this chunk is merged | |
| 329 | // with other chunk by ICF, it points to another chunk, | |
| 330 | // and this chunk is considered as dead. | |
| 331 | SectionChunk *repl; | |
| 235 | 332 | |
| 236 | 333 | private: |
| 237 | StringRef SectionName; | |
| 238 | std::vector<SectionChunk *> AssocChildren; | |
| 334 | SectionChunk *assocChildren = nullptr; | |
| 239 | 335 | |
| 240 | 336 | // Used for ICF (Identical COMDAT Folding) |
| 241 | void replace(SectionChunk *Other); | |
| 242 | uint32_t Class[2] = {0, 0}; | |
| 337 | void replace(SectionChunk *other); | |
| 338 | uint32_t eqClass[2] = {0, 0}; | |
| 339 | ||
| 340 | // Relocations for this section. Size is stored below. | |
| 341 | const coff_relocation *relocsData; | |
| 342 | ||
| 343 | // Section name string. Size is stored below. | |
| 344 | const char *sectionNameData; | |
| 345 | ||
| 346 | uint32_t relocsSize = 0; | |
| 347 | uint32_t sectionNameSize = 0; | |
| 243 | 348 | }; |
| 244 | 349 | |
| 350 | // Inline methods to implement faux-virtual dispatch for SectionChunk. | |
| 351 | ||
| 352 | inline size_t Chunk::getSize() const { | |
| 353 | if (isa<SectionChunk>(this)) | |
| 354 | return static_cast<const SectionChunk *>(this)->getSize(); | |
| 355 | else | |
| 356 | return static_cast<const NonSectionChunk *>(this)->getSize(); | |
| 357 | } | |
| 358 | ||
| 359 | inline uint32_t Chunk::getOutputCharacteristics() const { | |
| 360 | if (isa<SectionChunk>(this)) | |
| 361 | return static_cast<const SectionChunk *>(this)->getOutputCharacteristics(); | |
| 362 | else | |
| 363 | return static_cast<const NonSectionChunk *>(this) | |
| 364 | ->getOutputCharacteristics(); | |
| 365 | } | |
| 366 | ||
| 367 | inline void Chunk::writeTo(uint8_t *buf) const { | |
| 368 | if (isa<SectionChunk>(this)) | |
| 369 | static_cast<const SectionChunk *>(this)->writeTo(buf); | |
| 370 | else | |
| 371 | static_cast<const NonSectionChunk *>(this)->writeTo(buf); | |
| 372 | } | |
| 373 | ||
| 374 | inline StringRef Chunk::getSectionName() const { | |
| 375 | if (isa<SectionChunk>(this)) | |
| 376 | return static_cast<const SectionChunk *>(this)->getSectionName(); | |
| 377 | else | |
| 378 | return static_cast<const NonSectionChunk *>(this)->getSectionName(); | |
| 379 | } | |
| 380 | ||
| 381 | inline void Chunk::getBaserels(std::vector<Baserel> *res) { | |
| 382 | if (isa<SectionChunk>(this)) | |
| 383 | static_cast<SectionChunk *>(this)->getBaserels(res); | |
| 384 | else | |
| 385 | static_cast<NonSectionChunk *>(this)->getBaserels(res); | |
| 386 | } | |
| 387 | ||
| 388 | inline StringRef Chunk::getDebugName() const { | |
| 389 | if (isa<SectionChunk>(this)) | |
| 390 | return static_cast<const SectionChunk *>(this)->getDebugName(); | |
| 391 | else | |
| 392 | return static_cast<const NonSectionChunk *>(this)->getDebugName(); | |
| 393 | } | |
| 394 | ||
| 245 | 395 | // This class is used to implement an lld-specific feature (not implemented in |
| 246 | 396 | // MSVC) that minimizes the output size by finding string literals sharing tail |
| 247 | 397 | // parts and merging them. |
| ... | ... | @@ -251,60 +401,60 @@ private: |
| 251 | 401 | // The MergeChunk then tail merges the strings using the StringTableBuilder |
| 252 | 402 | // class and assigns RVAs and section offsets to each of the member chunks based |
| 253 | 403 | // on the offsets assigned by the StringTableBuilder. |
| 254 | class MergeChunk : public Chunk { | |
| 404 | class MergeChunk : public NonSectionChunk { | |
| 255 | 405 | public: |
| 256 | MergeChunk(uint32_t Alignment); | |
| 257 | static void addSection(SectionChunk *C); | |
| 258 | void finalizeContents() override; | |
| 406 | MergeChunk(uint32_t alignment); | |
| 407 | static void addSection(SectionChunk *c); | |
| 408 | void finalizeContents(); | |
| 409 | void assignSubsectionRVAs(); | |
| 259 | 410 | |
| 260 | 411 | uint32_t getOutputCharacteristics() const override; |
| 261 | 412 | StringRef getSectionName() const override { return ".rdata"; } |
| 262 | 413 | size_t getSize() const override; |
| 263 | void writeTo(uint8_t *Buf) const override; | |
| 414 | void writeTo(uint8_t *buf) const override; | |
| 264 | 415 | |
| 265 | static std::map<uint32_t, MergeChunk *> Instances; | |
| 266 | std::vector<SectionChunk *> Sections; | |
| 416 | static MergeChunk *instances[Log2MaxSectionAlignment + 1]; | |
| 417 | std::vector<SectionChunk *> sections; | |
| 267 | 418 | |
| 268 | 419 | private: |
| 269 | llvm::StringTableBuilder Builder; | |
| 270 | bool Finalized = false; | |
| 420 | llvm::StringTableBuilder builder; | |
| 421 | bool finalized = false; | |
| 271 | 422 | }; |
| 272 | 423 | |
| 273 | 424 | // A chunk for common symbols. Common chunks don't have actual data. |
| 274 | class CommonChunk : public Chunk { | |
| 425 | class CommonChunk : public NonSectionChunk { | |
| 275 | 426 | public: |
| 276 | CommonChunk(const COFFSymbolRef Sym); | |
| 277 | size_t getSize() const override { return Sym.getValue(); } | |
| 278 | bool hasData() const override { return false; } | |
| 427 | CommonChunk(const COFFSymbolRef sym); | |
| 428 | size_t getSize() const override { return sym.getValue(); } | |
| 279 | 429 | uint32_t getOutputCharacteristics() const override; |
| 280 | 430 | StringRef getSectionName() const override { return ".bss"; } |
| 281 | 431 | |
| 282 | 432 | private: |
| 283 | const COFFSymbolRef Sym; | |
| 433 | const COFFSymbolRef sym; | |
| 284 | 434 | }; |
| 285 | 435 | |
| 286 | 436 | // A chunk for linker-created strings. |
| 287 | class StringChunk : public Chunk { | |
| 437 | class StringChunk : public NonSectionChunk { | |
| 288 | 438 | public: |
| 289 | explicit StringChunk(StringRef S) : Str(S) {} | |
| 290 | size_t getSize() const override { return Str.size() + 1; } | |
| 291 | void writeTo(uint8_t *Buf) const override; | |
| 439 | explicit StringChunk(StringRef s) : str(s) {} | |
| 440 | size_t getSize() const override { return str.size() + 1; } | |
| 441 | void writeTo(uint8_t *buf) const override; | |
| 292 | 442 | |
| 293 | 443 | private: |
| 294 | StringRef Str; | |
| 444 | StringRef str; | |
| 295 | 445 | }; |
| 296 | 446 | |
| 297 | static const uint8_t ImportThunkX86[] = { | |
| 447 | static const uint8_t importThunkX86[] = { | |
| 298 | 448 | 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0 |
| 299 | 449 | }; |
| 300 | 450 | |
| 301 | static const uint8_t ImportThunkARM[] = { | |
| 451 | static const uint8_t importThunkARM[] = { | |
| 302 | 452 | 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 |
| 303 | 453 | 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 |
| 304 | 454 | 0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip] |
| 305 | 455 | }; |
| 306 | 456 | |
| 307 | static const uint8_t ImportThunkARM64[] = { | |
| 457 | static const uint8_t importThunkARM64[] = { | |
| 308 | 458 | 0x10, 0x00, 0x00, 0x90, // adrp x16, #0 |
| 309 | 459 | 0x10, 0x02, 0x40, 0xf9, // ldr x16, [x16] |
| 310 | 460 | 0x00, 0x02, 0x1f, 0xd6, // br x16 |
| ... | ... | @@ -313,87 +463,85 @@ static const uint8_t ImportThunkARM64[] = { |
| 313 | 463 | // Windows-specific. |
| 314 | 464 | // A chunk for DLL import jump table entry. In a final output, its |
| 315 | 465 | // contents will be a JMP instruction to some __imp_ symbol. |
| 316 | class ImportThunkChunkX64 : public Chunk { | |
| 466 | class ImportThunkChunk : public NonSectionChunk { | |
| 317 | 467 | public: |
| 318 | explicit ImportThunkChunkX64(Defined *S); | |
| 319 | size_t getSize() const override { return sizeof(ImportThunkX86); } | |
| 320 | void writeTo(uint8_t *Buf) const override; | |
| 468 | ImportThunkChunk(Defined *s) | |
| 469 | : NonSectionChunk(ImportThunkKind), impSymbol(s) {} | |
| 470 | static bool classof(const Chunk *c) { return c->kind() == ImportThunkKind; } | |
| 321 | 471 | |
| 322 | private: | |
| 323 | Defined *ImpSymbol; | |
| 472 | protected: | |
| 473 | Defined *impSymbol; | |
| 324 | 474 | }; |
| 325 | 475 | |
| 326 | class ImportThunkChunkX86 : public Chunk { | |
| 476 | class ImportThunkChunkX64 : public ImportThunkChunk { | |
| 327 | 477 | public: |
| 328 | explicit ImportThunkChunkX86(Defined *S) : ImpSymbol(S) {} | |
| 329 | size_t getSize() const override { return sizeof(ImportThunkX86); } | |
| 330 | void getBaserels(std::vector<Baserel> *Res) override; | |
| 331 | void writeTo(uint8_t *Buf) const override; | |
| 332 | ||
| 333 | private: | |
| 334 | Defined *ImpSymbol; | |
| 478 | explicit ImportThunkChunkX64(Defined *s); | |
| 479 | size_t getSize() const override { return sizeof(importThunkX86); } | |
| 480 | void writeTo(uint8_t *buf) const override; | |
| 335 | 481 | }; |
| 336 | 482 | |
| 337 | class ImportThunkChunkARM : public Chunk { | |
| 483 | class ImportThunkChunkX86 : public ImportThunkChunk { | |
| 338 | 484 | public: |
| 339 | explicit ImportThunkChunkARM(Defined *S) : ImpSymbol(S) {} | |
| 340 | size_t getSize() const override { return sizeof(ImportThunkARM); } | |
| 341 | void getBaserels(std::vector<Baserel> *Res) override; | |
| 342 | void writeTo(uint8_t *Buf) const override; | |
| 343 | ||
| 344 | private: | |
| 345 | Defined *ImpSymbol; | |
| 485 | explicit ImportThunkChunkX86(Defined *s) : ImportThunkChunk(s) {} | |
| 486 | size_t getSize() const override { return sizeof(importThunkX86); } | |
| 487 | void getBaserels(std::vector<Baserel> *res) override; | |
| 488 | void writeTo(uint8_t *buf) const override; | |
| 346 | 489 | }; |
| 347 | 490 | |
| 348 | class ImportThunkChunkARM64 : public Chunk { | |
| 491 | class ImportThunkChunkARM : public ImportThunkChunk { | |
| 349 | 492 | public: |
| 350 | explicit ImportThunkChunkARM64(Defined *S) : ImpSymbol(S) {} | |
| 351 | size_t getSize() const override { return sizeof(ImportThunkARM64); } | |
| 352 | void writeTo(uint8_t *Buf) const override; | |
| 493 | explicit ImportThunkChunkARM(Defined *s) : ImportThunkChunk(s) {} | |
| 494 | size_t getSize() const override { return sizeof(importThunkARM); } | |
| 495 | void getBaserels(std::vector<Baserel> *res) override; | |
| 496 | void writeTo(uint8_t *buf) const override; | |
| 497 | }; | |
| 353 | 498 | |
| 354 | private: | |
| 355 | Defined *ImpSymbol; | |
| 499 | class ImportThunkChunkARM64 : public ImportThunkChunk { | |
| 500 | public: | |
| 501 | explicit ImportThunkChunkARM64(Defined *s) : ImportThunkChunk(s) {} | |
| 502 | size_t getSize() const override { return sizeof(importThunkARM64); } | |
| 503 | void writeTo(uint8_t *buf) const override; | |
| 356 | 504 | }; |
| 357 | 505 | |
| 358 | class RangeExtensionThunkARM : public Chunk { | |
| 506 | class RangeExtensionThunkARM : public NonSectionChunk { | |
| 359 | 507 | public: |
| 360 | explicit RangeExtensionThunkARM(Defined *T) : Target(T) {} | |
| 508 | explicit RangeExtensionThunkARM(Defined *t) : target(t) {} | |
| 361 | 509 | size_t getSize() const override; |
| 362 | void writeTo(uint8_t *Buf) const override; | |
| 510 | void writeTo(uint8_t *buf) const override; | |
| 363 | 511 | |
| 364 | Defined *Target; | |
| 512 | Defined *target; | |
| 365 | 513 | }; |
| 366 | 514 | |
| 367 | class RangeExtensionThunkARM64 : public Chunk { | |
| 515 | class RangeExtensionThunkARM64 : public NonSectionChunk { | |
| 368 | 516 | public: |
| 369 | explicit RangeExtensionThunkARM64(Defined *T) : Target(T) {} | |
| 517 | explicit RangeExtensionThunkARM64(Defined *t) : target(t) {} | |
| 370 | 518 | size_t getSize() const override; |
| 371 | void writeTo(uint8_t *Buf) const override; | |
| 519 | void writeTo(uint8_t *buf) const override; | |
| 372 | 520 | |
| 373 | Defined *Target; | |
| 521 | Defined *target; | |
| 374 | 522 | }; |
| 375 | 523 | |
| 376 | 524 | // Windows-specific. |
| 377 | 525 | // See comments for DefinedLocalImport class. |
| 378 | class LocalImportChunk : public Chunk { | |
| 526 | class LocalImportChunk : public NonSectionChunk { | |
| 379 | 527 | public: |
| 380 | explicit LocalImportChunk(Defined *S) : Sym(S) { | |
| 381 | Alignment = Config->Wordsize; | |
| 528 | explicit LocalImportChunk(Defined *s) : sym(s) { | |
| 529 | setAlignment(config->wordsize); | |
| 382 | 530 | } |
| 383 | 531 | size_t getSize() const override; |
| 384 | void getBaserels(std::vector<Baserel> *Res) override; | |
| 385 | void writeTo(uint8_t *Buf) const override; | |
| 532 | void getBaserels(std::vector<Baserel> *res) override; | |
| 533 | void writeTo(uint8_t *buf) const override; | |
| 386 | 534 | |
| 387 | 535 | private: |
| 388 | Defined *Sym; | |
| 536 | Defined *sym; | |
| 389 | 537 | }; |
| 390 | 538 | |
| 391 | 539 | // Duplicate RVAs are not allowed in RVA tables, so unique symbols by chunk and |
| 392 | 540 | // offset into the chunk. Order does not matter as the RVA table will be sorted |
| 393 | 541 | // later. |
| 394 | 542 | struct ChunkAndOffset { |
| 395 | Chunk *InputChunk; | |
| 396 | uint32_t Offset; | |
| 543 | Chunk *inputChunk; | |
| 544 | uint32_t offset; | |
| 397 | 545 | |
| 398 | 546 | struct DenseMapInfo { |
| 399 | 547 | static ChunkAndOffset getEmptyKey() { |
| ... | ... | @@ -402,12 +550,12 @@ struct ChunkAndOffset { |
| 402 | 550 | static ChunkAndOffset getTombstoneKey() { |
| 403 | 551 | return {llvm::DenseMapInfo<Chunk *>::getTombstoneKey(), 0}; |
| 404 | 552 | } |
| 405 | static unsigned getHashValue(const ChunkAndOffset &CO) { | |
| 553 | static unsigned getHashValue(const ChunkAndOffset &co) { | |
| 406 | 554 | return llvm::DenseMapInfo<std::pair<Chunk *, uint32_t>>::getHashValue( |
| 407 | {CO.InputChunk, CO.Offset}); | |
| 555 | {co.inputChunk, co.offset}); | |
| 408 | 556 | } |
| 409 | static bool isEqual(const ChunkAndOffset &LHS, const ChunkAndOffset &RHS) { | |
| 410 | return LHS.InputChunk == RHS.InputChunk && LHS.Offset == RHS.Offset; | |
| 557 | static bool isEqual(const ChunkAndOffset &lhs, const ChunkAndOffset &rhs) { | |
| 558 | return lhs.inputChunk == rhs.inputChunk && lhs.offset == rhs.offset; | |
| 411 | 559 | } |
| 412 | 560 | }; |
| 413 | 561 | }; |
| ... | ... | @@ -415,48 +563,48 @@ struct ChunkAndOffset { |
| 415 | 563 | using SymbolRVASet = llvm::DenseSet<ChunkAndOffset>; |
| 416 | 564 | |
| 417 | 565 | // Table which contains symbol RVAs. Used for /safeseh and /guard:cf. |
| 418 | class RVATableChunk : public Chunk { | |
| 566 | class RVATableChunk : public NonSectionChunk { | |
| 419 | 567 | public: |
| 420 | explicit RVATableChunk(SymbolRVASet S) : Syms(std::move(S)) {} | |
| 421 | size_t getSize() const override { return Syms.size() * 4; } | |
| 422 | void writeTo(uint8_t *Buf) const override; | |
| 568 | explicit RVATableChunk(SymbolRVASet s) : syms(std::move(s)) {} | |
| 569 | size_t getSize() const override { return syms.size() * 4; } | |
| 570 | void writeTo(uint8_t *buf) const override; | |
| 423 | 571 | |
| 424 | 572 | private: |
| 425 | SymbolRVASet Syms; | |
| 573 | SymbolRVASet syms; | |
| 426 | 574 | }; |
| 427 | 575 | |
| 428 | 576 | // Windows-specific. |
| 429 | 577 | // This class represents a block in .reloc section. |
| 430 | 578 | // See the PE/COFF spec 5.6 for details. |
| 431 | class BaserelChunk : public Chunk { | |
| 579 | class BaserelChunk : public NonSectionChunk { | |
| 432 | 580 | public: |
| 433 | BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End); | |
| 434 | size_t getSize() const override { return Data.size(); } | |
| 435 | void writeTo(uint8_t *Buf) const override; | |
| 581 | BaserelChunk(uint32_t page, Baserel *begin, Baserel *end); | |
| 582 | size_t getSize() const override { return data.size(); } | |
| 583 | void writeTo(uint8_t *buf) const override; | |
| 436 | 584 | |
| 437 | 585 | private: |
| 438 | std::vector<uint8_t> Data; | |
| 586 | std::vector<uint8_t> data; | |
| 439 | 587 | }; |
| 440 | 588 | |
| 441 | 589 | class Baserel { |
| 442 | 590 | public: |
| 443 | Baserel(uint32_t V, uint8_t Ty) : RVA(V), Type(Ty) {} | |
| 444 | explicit Baserel(uint32_t V) : Baserel(V, getDefaultType()) {} | |
| 591 | Baserel(uint32_t v, uint8_t ty) : rva(v), type(ty) {} | |
| 592 | explicit Baserel(uint32_t v) : Baserel(v, getDefaultType()) {} | |
| 445 | 593 | uint8_t getDefaultType(); |
| 446 | 594 | |
| 447 | uint32_t RVA; | |
| 448 | uint8_t Type; | |
| 595 | uint32_t rva; | |
| 596 | uint8_t type; | |
| 449 | 597 | }; |
| 450 | 598 | |
| 451 | 599 | // This is a placeholder Chunk, to allow attaching a DefinedSynthetic to a |
| 452 | 600 | // specific place in a section, without any data. This is used for the MinGW |
| 453 | 601 | // specific symbol __RUNTIME_PSEUDO_RELOC_LIST_END__, even though the concept |
| 454 | 602 | // of an empty chunk isn't MinGW specific. |
| 455 | class EmptyChunk : public Chunk { | |
| 603 | class EmptyChunk : public NonSectionChunk { | |
| 456 | 604 | public: |
| 457 | 605 | EmptyChunk() {} |
| 458 | 606 | size_t getSize() const override { return 0; } |
| 459 | void writeTo(uint8_t *Buf) const override {} | |
| 607 | void writeTo(uint8_t *buf) const override {} | |
| 460 | 608 | }; |
| 461 | 609 | |
| 462 | 610 | // MinGW specific, for the "automatic import of variables from DLLs" feature. |
| ... | ... | @@ -465,17 +613,17 @@ public: |
| 465 | 613 | // the reference didn't use the dllimport attribute. The MinGW runtime will |
| 466 | 614 | // process this table after loading, before handling control over to user |
| 467 | 615 | // code. |
| 468 | class PseudoRelocTableChunk : public Chunk { | |
| 616 | class PseudoRelocTableChunk : public NonSectionChunk { | |
| 469 | 617 | public: |
| 470 | PseudoRelocTableChunk(std::vector<RuntimePseudoReloc> &Relocs) | |
| 471 | : Relocs(std::move(Relocs)) { | |
| 472 | Alignment = 4; | |
| 618 | PseudoRelocTableChunk(std::vector<RuntimePseudoReloc> &relocs) | |
| 619 | : relocs(std::move(relocs)) { | |
| 620 | setAlignment(4); | |
| 473 | 621 | } |
| 474 | 622 | size_t getSize() const override; |
| 475 | void writeTo(uint8_t *Buf) const override; | |
| 623 | void writeTo(uint8_t *buf) const override; | |
| 476 | 624 | |
| 477 | 625 | private: |
| 478 | std::vector<RuntimePseudoReloc> Relocs; | |
| 626 | std::vector<RuntimePseudoReloc> relocs; | |
| 479 | 627 | }; |
| 480 | 628 | |
| 481 | 629 | // MinGW specific; information about one individual location in the image |
| ... | ... | @@ -483,37 +631,48 @@ private: |
| 483 | 631 | // one individual element in the PseudoRelocTableChunk table. |
| 484 | 632 | class RuntimePseudoReloc { |
| 485 | 633 | public: |
| 486 | RuntimePseudoReloc(Defined *Sym, SectionChunk *Target, uint32_t TargetOffset, | |
| 487 | int Flags) | |
| 488 | : Sym(Sym), Target(Target), TargetOffset(TargetOffset), Flags(Flags) {} | |
| 634 | RuntimePseudoReloc(Defined *sym, SectionChunk *target, uint32_t targetOffset, | |
| 635 | int flags) | |
| 636 | : sym(sym), target(target), targetOffset(targetOffset), flags(flags) {} | |
| 489 | 637 | |
| 490 | Defined *Sym; | |
| 491 | SectionChunk *Target; | |
| 492 | uint32_t TargetOffset; | |
| 638 | Defined *sym; | |
| 639 | SectionChunk *target; | |
| 640 | uint32_t targetOffset; | |
| 493 | 641 | // The Flags field contains the size of the relocation, in bits. No other |
| 494 | 642 | // flags are currently defined. |
| 495 | int Flags; | |
| 643 | int flags; | |
| 496 | 644 | }; |
| 497 | 645 | |
| 498 | 646 | // MinGW specific. A Chunk that contains one pointer-sized absolute value. |
| 499 | class AbsolutePointerChunk : public Chunk { | |
| 647 | class AbsolutePointerChunk : public NonSectionChunk { | |
| 500 | 648 | public: |
| 501 | AbsolutePointerChunk(uint64_t Value) : Value(Value) { | |
| 502 | Alignment = getSize(); | |
| 649 | AbsolutePointerChunk(uint64_t value) : value(value) { | |
| 650 | setAlignment(getSize()); | |
| 503 | 651 | } |
| 504 | 652 | size_t getSize() const override; |
| 505 | void writeTo(uint8_t *Buf) const override; | |
| 653 | void writeTo(uint8_t *buf) const override; | |
| 506 | 654 | |
| 507 | 655 | private: |
| 508 | uint64_t Value; | |
| 656 | uint64_t value; | |
| 509 | 657 | }; |
| 510 | 658 | |
| 511 | void applyMOV32T(uint8_t *Off, uint32_t V); | |
| 512 | void applyBranch24T(uint8_t *Off, int32_t V); | |
| 659 | // Return true if this file has the hotpatch flag set to true in the S_COMPILE3 | |
| 660 | // record in codeview debug info. Also returns true for some thunks synthesized | |
| 661 | // by the linker. | |
| 662 | inline bool Chunk::isHotPatchable() const { | |
| 663 | if (auto *sc = dyn_cast<SectionChunk>(this)) | |
| 664 | return sc->file->hotPatchable; | |
| 665 | else if (isa<ImportThunkChunk>(this)) | |
| 666 | return true; | |
| 667 | return false; | |
| 668 | } | |
| 669 | ||
| 670 | void applyMOV32T(uint8_t *off, uint32_t v); | |
| 671 | void applyBranch24T(uint8_t *off, int32_t v); | |
| 513 | 672 | |
| 514 | void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift); | |
| 515 | void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit); | |
| 516 | void applyArm64Branch26(uint8_t *Off, int64_t V); | |
| 673 | void applyArm64Addr(uint8_t *off, uint64_t s, uint64_t p, int shift); | |
| 674 | void applyArm64Imm(uint8_t *off, uint64_t imm, uint32_t rangeLimit); | |
| 675 | void applyArm64Branch26(uint8_t *off, int64_t v); | |
| 517 | 676 | |
| 518 | 677 | } // namespace coff |
| 519 | 678 | } // namespace lld |
deps/lld/COFF/Config.h+130-111| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Config.h -------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -29,6 +28,7 @@ class DefinedAbsolute; |
| 29 | 28 | class DefinedRelative; |
| 30 | 29 | class StringChunk; |
| 31 | 30 | class Symbol; |
| 31 | class InputFile; | |
| 32 | 32 | |
| 33 | 33 | // Short aliases. |
| 34 | 34 | static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64; |
| ... | ... | @@ -38,30 +38,30 @@ static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386; |
| 38 | 38 | |
| 39 | 39 | // Represents an /export option. |
| 40 | 40 | struct Export { |
| 41 | StringRef Name; // N in /export:N or /export:E=N | |
| 42 | StringRef ExtName; // E in /export:E=N | |
| 43 | Symbol *Sym = nullptr; | |
| 44 | uint16_t Ordinal = 0; | |
| 45 | bool Noname = false; | |
| 46 | bool Data = false; | |
| 47 | bool Private = false; | |
| 48 | bool Constant = false; | |
| 41 | StringRef name; // N in /export:N or /export:E=N | |
| 42 | StringRef extName; // E in /export:E=N | |
| 43 | Symbol *sym = nullptr; | |
| 44 | uint16_t ordinal = 0; | |
| 45 | bool noname = false; | |
| 46 | bool data = false; | |
| 47 | bool isPrivate = false; | |
| 48 | bool constant = false; | |
| 49 | 49 | |
| 50 | 50 | // If an export is a form of /export:foo=dllname.bar, that means |
| 51 | 51 | // that foo should be exported as an alias to bar in the DLL. |
| 52 | // ForwardTo is set to "dllname.bar" part. Usually empty. | |
| 53 | StringRef ForwardTo; | |
| 54 | StringChunk *ForwardChunk = nullptr; | |
| 52 | // forwardTo is set to "dllname.bar" part. Usually empty. | |
| 53 | StringRef forwardTo; | |
| 54 | StringChunk *forwardChunk = nullptr; | |
| 55 | 55 | |
| 56 | 56 | // True if this /export option was in .drectves section. |
| 57 | bool Directives = false; | |
| 58 | StringRef SymbolName; | |
| 59 | StringRef ExportName; // Name in DLL | |
| 60 | ||
| 61 | bool operator==(const Export &E) { | |
| 62 | return (Name == E.Name && ExtName == E.ExtName && | |
| 63 | Ordinal == E.Ordinal && Noname == E.Noname && | |
| 64 | Data == E.Data && Private == E.Private); | |
| 57 | bool directives = false; | |
| 58 | StringRef symbolName; | |
| 59 | StringRef exportName; // Name in DLL | |
| 60 | ||
| 61 | bool operator==(const Export &e) { | |
| 62 | return (name == e.name && extName == e.extName && | |
| 63 | ordinal == e.ordinal && noname == e.noname && | |
| 64 | data == e.data && isPrivate == e.isPrivate); | |
| 65 | 65 | } |
| 66 | 66 | }; |
| 67 | 67 | |
| ... | ... | @@ -81,130 +81,149 @@ enum class GuardCFLevel { |
| 81 | 81 | // Global configuration. |
| 82 | 82 | struct Configuration { |
| 83 | 83 | enum ManifestKind { SideBySide, Embed, No }; |
| 84 | bool is64() { return Machine == AMD64 || Machine == ARM64; } | |
| 85 | ||
| 86 | llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN; | |
| 87 | size_t Wordsize; | |
| 88 | bool Verbose = false; | |
| 89 | WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN; | |
| 90 | Symbol *Entry = nullptr; | |
| 91 | bool NoEntry = false; | |
| 92 | std::string OutputFile; | |
| 93 | std::string ImportName; | |
| 94 | bool DoGC = true; | |
| 95 | bool DoICF = true; | |
| 96 | bool TailMerge; | |
| 97 | bool Relocatable = true; | |
| 98 | bool ForceMultiple = false; | |
| 99 | bool ForceUnresolved = false; | |
| 100 | bool Debug = false; | |
| 101 | bool DebugDwarf = false; | |
| 102 | bool DebugGHashes = false; | |
| 103 | bool DebugSymtab = false; | |
| 104 | bool ShowTiming = false; | |
| 105 | unsigned DebugTypes = static_cast<unsigned>(DebugType::None); | |
| 106 | std::vector<std::string> NatvisFiles; | |
| 107 | llvm::SmallString<128> PDBAltPath; | |
| 108 | llvm::SmallString<128> PDBPath; | |
| 109 | llvm::SmallString<128> PDBSourcePath; | |
| 110 | std::vector<llvm::StringRef> Argv; | |
| 84 | bool is64() { return machine == AMD64 || machine == ARM64; } | |
| 85 | ||
| 86 | llvm::COFF::MachineTypes machine = IMAGE_FILE_MACHINE_UNKNOWN; | |
| 87 | size_t wordsize; | |
| 88 | bool verbose = false; | |
| 89 | WindowsSubsystem subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN; | |
| 90 | Symbol *entry = nullptr; | |
| 91 | bool noEntry = false; | |
| 92 | std::string outputFile; | |
| 93 | std::string importName; | |
| 94 | bool demangle = true; | |
| 95 | bool doGC = true; | |
| 96 | bool doICF = true; | |
| 97 | bool tailMerge; | |
| 98 | bool relocatable = true; | |
| 99 | bool forceMultiple = false; | |
| 100 | bool forceMultipleRes = false; | |
| 101 | bool forceUnresolved = false; | |
| 102 | bool debug = false; | |
| 103 | bool debugDwarf = false; | |
| 104 | bool debugGHashes = false; | |
| 105 | bool debugSymtab = false; | |
| 106 | bool showTiming = false; | |
| 107 | bool showSummary = false; | |
| 108 | unsigned debugTypes = static_cast<unsigned>(DebugType::None); | |
| 109 | std::vector<std::string> natvisFiles; | |
| 110 | llvm::SmallString<128> pdbAltPath; | |
| 111 | llvm::SmallString<128> pdbPath; | |
| 112 | llvm::SmallString<128> pdbSourcePath; | |
| 113 | std::vector<llvm::StringRef> argv; | |
| 111 | 114 | |
| 112 | 115 | // Symbols in this set are considered as live by the garbage collector. |
| 113 | std::vector<Symbol *> GCRoot; | |
| 116 | std::vector<Symbol *> gcroot; | |
| 114 | 117 | |
| 115 | std::set<StringRef> NoDefaultLibs; | |
| 116 | bool NoDefaultLibAll = false; | |
| 118 | std::set<std::string> noDefaultLibs; | |
| 119 | bool noDefaultLibAll = false; | |
| 117 | 120 | |
| 118 | 121 | // True if we are creating a DLL. |
| 119 | bool DLL = false; | |
| 120 | StringRef Implib; | |
| 121 | std::vector<Export> Exports; | |
| 122 | std::set<std::string> DelayLoads; | |
| 123 | std::map<std::string, int> DLLOrder; | |
| 124 | Symbol *DelayLoadHelper = nullptr; | |
| 122 | bool dll = false; | |
| 123 | StringRef implib; | |
| 124 | std::vector<Export> exports; | |
| 125 | std::set<std::string> delayLoads; | |
| 126 | std::map<std::string, int> dllOrder; | |
| 127 | Symbol *delayLoadHelper = nullptr; | |
| 125 | 128 | |
| 126 | bool SaveTemps = false; | |
| 129 | bool saveTemps = false; | |
| 127 | 130 | |
| 128 | 131 | // /guard:cf |
| 129 | GuardCFLevel GuardCF = GuardCFLevel::Off; | |
| 132 | GuardCFLevel guardCF = GuardCFLevel::Off; | |
| 130 | 133 | |
| 131 | 134 | // Used for SafeSEH. |
| 132 | Symbol *SEHTable = nullptr; | |
| 133 | Symbol *SEHCount = nullptr; | |
| 135 | bool safeSEH = false; | |
| 136 | Symbol *sehTable = nullptr; | |
| 137 | Symbol *sehCount = nullptr; | |
| 134 | 138 | |
| 135 | 139 | // Used for /opt:lldlto=N |
| 136 | unsigned LTOO = 2; | |
| 140 | unsigned ltoo = 2; | |
| 137 | 141 | |
| 138 | 142 | // Used for /opt:lldltojobs=N |
| 139 | unsigned ThinLTOJobs = 0; | |
| 143 | unsigned thinLTOJobs = 0; | |
| 140 | 144 | // Used for /opt:lldltopartitions=N |
| 141 | unsigned LTOPartitions = 1; | |
| 145 | unsigned ltoPartitions = 1; | |
| 142 | 146 | |
| 143 | 147 | // Used for /opt:lldltocache=path |
| 144 | StringRef LTOCache; | |
| 148 | StringRef ltoCache; | |
| 145 | 149 | // Used for /opt:lldltocachepolicy=policy |
| 146 | llvm::CachePruningPolicy LTOCachePolicy; | |
| 150 | llvm::CachePruningPolicy ltoCachePolicy; | |
| 147 | 151 | |
| 148 | 152 | // Used for /merge:from=to (e.g. /merge:.rdata=.text) |
| 149 | std::map<StringRef, StringRef> Merge; | |
| 153 | std::map<StringRef, StringRef> merge; | |
| 150 | 154 | |
| 151 | 155 | // Used for /section=.name,{DEKPRSW} to set section attributes. |
| 152 | std::map<StringRef, uint32_t> Section; | |
| 156 | std::map<StringRef, uint32_t> section; | |
| 153 | 157 | |
| 154 | 158 | // Options for manifest files. |
| 155 | ManifestKind Manifest = No; | |
| 156 | int ManifestID = 1; | |
| 157 | StringRef ManifestDependency; | |
| 158 | bool ManifestUAC = true; | |
| 159 | std::vector<std::string> ManifestInput; | |
| 160 | StringRef ManifestLevel = "'asInvoker'"; | |
| 161 | StringRef ManifestUIAccess = "'false'"; | |
| 162 | StringRef ManifestFile; | |
| 159 | ManifestKind manifest = No; | |
| 160 | int manifestID = 1; | |
| 161 | StringRef manifestDependency; | |
| 162 | bool manifestUAC = true; | |
| 163 | std::vector<std::string> manifestInput; | |
| 164 | StringRef manifestLevel = "'asInvoker'"; | |
| 165 | StringRef manifestUIAccess = "'false'"; | |
| 166 | StringRef manifestFile; | |
| 163 | 167 | |
| 164 | 168 | // Used for /aligncomm. |
| 165 | std::map<std::string, int> AlignComm; | |
| 169 | std::map<std::string, int> alignComm; | |
| 166 | 170 | |
| 167 | 171 | // Used for /failifmismatch. |
| 168 | std::map<StringRef, StringRef> MustMatch; | |
| 172 | std::map<StringRef, std::pair<StringRef, InputFile *>> mustMatch; | |
| 169 | 173 | |
| 170 | 174 | // Used for /alternatename. |
| 171 | std::map<StringRef, StringRef> AlternateNames; | |
| 175 | std::map<StringRef, StringRef> alternateNames; | |
| 172 | 176 | |
| 173 | 177 | // Used for /order. |
| 174 | llvm::StringMap<int> Order; | |
| 178 | llvm::StringMap<int> order; | |
| 175 | 179 | |
| 176 | 180 | // Used for /lldmap. |
| 177 | std::string MapFile; | |
| 178 | ||
| 179 | uint64_t ImageBase = -1; | |
| 180 | uint64_t StackReserve = 1024 * 1024; | |
| 181 | uint64_t StackCommit = 4096; | |
| 182 | uint64_t HeapReserve = 1024 * 1024; | |
| 183 | uint64_t HeapCommit = 4096; | |
| 184 | uint32_t MajorImageVersion = 0; | |
| 185 | uint32_t MinorImageVersion = 0; | |
| 186 | uint32_t MajorOSVersion = 6; | |
| 187 | uint32_t MinorOSVersion = 0; | |
| 188 | uint32_t Timestamp = 0; | |
| 189 | bool DynamicBase = true; | |
| 190 | bool AllowBind = true; | |
| 191 | bool NxCompat = true; | |
| 192 | bool AllowIsolation = true; | |
| 193 | bool TerminalServerAware = true; | |
| 194 | bool LargeAddressAware = false; | |
| 195 | bool HighEntropyVA = false; | |
| 196 | bool AppContainer = false; | |
| 197 | bool MinGW = false; | |
| 198 | bool WarnMissingOrderSymbol = true; | |
| 199 | bool WarnLocallyDefinedImported = true; | |
| 200 | bool WarnDebugInfoUnusable = true; | |
| 201 | bool Incremental = true; | |
| 202 | bool IntegrityCheck = false; | |
| 203 | bool KillAt = false; | |
| 204 | bool Repro = false; | |
| 181 | std::string mapFile; | |
| 182 | ||
| 183 | // Used for /thinlto-index-only: | |
| 184 | llvm::StringRef thinLTOIndexOnlyArg; | |
| 185 | ||
| 186 | // Used for /thinlto-object-prefix-replace: | |
| 187 | std::pair<llvm::StringRef, llvm::StringRef> thinLTOPrefixReplace; | |
| 188 | ||
| 189 | // Used for /thinlto-object-suffix-replace: | |
| 190 | std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace; | |
| 191 | ||
| 192 | uint64_t imageBase = -1; | |
| 193 | uint64_t fileAlign = 512; | |
| 194 | uint64_t stackReserve = 1024 * 1024; | |
| 195 | uint64_t stackCommit = 4096; | |
| 196 | uint64_t heapReserve = 1024 * 1024; | |
| 197 | uint64_t heapCommit = 4096; | |
| 198 | uint32_t majorImageVersion = 0; | |
| 199 | uint32_t minorImageVersion = 0; | |
| 200 | uint32_t majorOSVersion = 6; | |
| 201 | uint32_t minorOSVersion = 0; | |
| 202 | uint32_t timestamp = 0; | |
| 203 | uint32_t functionPadMin = 0; | |
| 204 | bool dynamicBase = true; | |
| 205 | bool allowBind = true; | |
| 206 | bool nxCompat = true; | |
| 207 | bool allowIsolation = true; | |
| 208 | bool terminalServerAware = true; | |
| 209 | bool largeAddressAware = false; | |
| 210 | bool highEntropyVA = false; | |
| 211 | bool appContainer = false; | |
| 212 | bool mingw = false; | |
| 213 | bool warnMissingOrderSymbol = true; | |
| 214 | bool warnLocallyDefinedImported = true; | |
| 215 | bool warnDebugInfoUnusable = true; | |
| 216 | bool incremental = true; | |
| 217 | bool integrityCheck = false; | |
| 218 | bool killAt = false; | |
| 219 | bool repro = false; | |
| 220 | bool swaprunCD = false; | |
| 221 | bool swaprunNet = false; | |
| 222 | bool thinLTOEmitImportsFiles; | |
| 223 | bool thinLTOIndexOnly; | |
| 205 | 224 | }; |
| 206 | 225 | |
| 207 | extern Configuration *Config; | |
| 226 | extern Configuration *config; | |
| 208 | 227 | |
| 209 | 228 | } // namespace coff |
| 210 | 229 | } // namespace lld |
deps/lld/COFF/DLL.cpp+399-308| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- DLL.cpp ------------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -36,161 +35,167 @@ namespace { |
| 36 | 35 | // Import table |
| 37 | 36 | |
| 38 | 37 | // A chunk for the import descriptor table. |
| 39 | class HintNameChunk : public Chunk { | |
| 38 | class HintNameChunk : public NonSectionChunk { | |
| 40 | 39 | public: |
| 41 | HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {} | |
| 40 | HintNameChunk(StringRef n, uint16_t h) : name(n), hint(h) {} | |
| 42 | 41 | |
| 43 | 42 | size_t getSize() const override { |
| 44 | 43 | // Starts with 2 byte Hint field, followed by a null-terminated string, |
| 45 | 44 | // ends with 0 or 1 byte padding. |
| 46 | return alignTo(Name.size() + 3, 2); | |
| 45 | return alignTo(name.size() + 3, 2); | |
| 47 | 46 | } |
| 48 | 47 | |
| 49 | void writeTo(uint8_t *Buf) const override { | |
| 50 | memset(Buf + OutputSectionOff, 0, getSize()); | |
| 51 | write16le(Buf + OutputSectionOff, Hint); | |
| 52 | memcpy(Buf + OutputSectionOff + 2, Name.data(), Name.size()); | |
| 48 | void writeTo(uint8_t *buf) const override { | |
| 49 | memset(buf, 0, getSize()); | |
| 50 | write16le(buf, hint); | |
| 51 | memcpy(buf + 2, name.data(), name.size()); | |
| 53 | 52 | } |
| 54 | 53 | |
| 55 | 54 | private: |
| 56 | StringRef Name; | |
| 57 | uint16_t Hint; | |
| 55 | StringRef name; | |
| 56 | uint16_t hint; | |
| 58 | 57 | }; |
| 59 | 58 | |
| 60 | 59 | // A chunk for the import descriptor table. |
| 61 | class LookupChunk : public Chunk { | |
| 60 | class LookupChunk : public NonSectionChunk { | |
| 62 | 61 | public: |
| 63 | explicit LookupChunk(Chunk *C) : HintName(C) { Alignment = Config->Wordsize; } | |
| 64 | size_t getSize() const override { return Config->Wordsize; } | |
| 62 | explicit LookupChunk(Chunk *c) : hintName(c) { | |
| 63 | setAlignment(config->wordsize); | |
| 64 | } | |
| 65 | size_t getSize() const override { return config->wordsize; } | |
| 65 | 66 | |
| 66 | void writeTo(uint8_t *Buf) const override { | |
| 67 | if (Config->is64()) | |
| 68 | write64le(Buf + OutputSectionOff, HintName->getRVA()); | |
| 67 | void writeTo(uint8_t *buf) const override { | |
| 68 | if (config->is64()) | |
| 69 | write64le(buf, hintName->getRVA()); | |
| 69 | 70 | else |
| 70 | write32le(Buf + OutputSectionOff, HintName->getRVA()); | |
| 71 | write32le(buf, hintName->getRVA()); | |
| 71 | 72 | } |
| 72 | 73 | |
| 73 | Chunk *HintName; | |
| 74 | Chunk *hintName; | |
| 74 | 75 | }; |
| 75 | 76 | |
| 76 | 77 | // A chunk for the import descriptor table. |
| 77 | 78 | // This chunk represent import-by-ordinal symbols. |
| 78 | 79 | // See Microsoft PE/COFF spec 7.1. Import Header for details. |
| 79 | class OrdinalOnlyChunk : public Chunk { | |
| 80 | class OrdinalOnlyChunk : public NonSectionChunk { | |
| 80 | 81 | public: |
| 81 | explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) { | |
| 82 | Alignment = Config->Wordsize; | |
| 82 | explicit OrdinalOnlyChunk(uint16_t v) : ordinal(v) { | |
| 83 | setAlignment(config->wordsize); | |
| 83 | 84 | } |
| 84 | size_t getSize() const override { return Config->Wordsize; } | |
| 85 | size_t getSize() const override { return config->wordsize; } | |
| 85 | 86 | |
| 86 | void writeTo(uint8_t *Buf) const override { | |
| 87 | void writeTo(uint8_t *buf) const override { | |
| 87 | 88 | // An import-by-ordinal slot has MSB 1 to indicate that |
| 88 | 89 | // this is import-by-ordinal (and not import-by-name). |
| 89 | if (Config->is64()) { | |
| 90 | write64le(Buf + OutputSectionOff, (1ULL << 63) | Ordinal); | |
| 90 | if (config->is64()) { | |
| 91 | write64le(buf, (1ULL << 63) | ordinal); | |
| 91 | 92 | } else { |
| 92 | write32le(Buf + OutputSectionOff, (1ULL << 31) | Ordinal); | |
| 93 | write32le(buf, (1ULL << 31) | ordinal); | |
| 93 | 94 | } |
| 94 | 95 | } |
| 95 | 96 | |
| 96 | uint16_t Ordinal; | |
| 97 | uint16_t ordinal; | |
| 97 | 98 | }; |
| 98 | 99 | |
| 99 | 100 | // A chunk for the import descriptor table. |
| 100 | class ImportDirectoryChunk : public Chunk { | |
| 101 | class ImportDirectoryChunk : public NonSectionChunk { | |
| 101 | 102 | public: |
| 102 | explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {} | |
| 103 | explicit ImportDirectoryChunk(Chunk *n) : dllName(n) {} | |
| 103 | 104 | size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); } |
| 104 | 105 | |
| 105 | void writeTo(uint8_t *Buf) const override { | |
| 106 | memset(Buf + OutputSectionOff, 0, getSize()); | |
| 106 | void writeTo(uint8_t *buf) const override { | |
| 107 | memset(buf, 0, getSize()); | |
| 107 | 108 | |
| 108 | auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff); | |
| 109 | E->ImportLookupTableRVA = LookupTab->getRVA(); | |
| 110 | E->NameRVA = DLLName->getRVA(); | |
| 111 | E->ImportAddressTableRVA = AddressTab->getRVA(); | |
| 109 | auto *e = (coff_import_directory_table_entry *)(buf); | |
| 110 | e->ImportLookupTableRVA = lookupTab->getRVA(); | |
| 111 | e->NameRVA = dllName->getRVA(); | |
| 112 | e->ImportAddressTableRVA = addressTab->getRVA(); | |
| 112 | 113 | } |
| 113 | 114 | |
| 114 | Chunk *DLLName; | |
| 115 | Chunk *LookupTab; | |
| 116 | Chunk *AddressTab; | |
| 115 | Chunk *dllName; | |
| 116 | Chunk *lookupTab; | |
| 117 | Chunk *addressTab; | |
| 117 | 118 | }; |
| 118 | 119 | |
| 119 | 120 | // A chunk representing null terminator in the import table. |
| 120 | 121 | // Contents of this chunk is always null bytes. |
| 121 | class NullChunk : public Chunk { | |
| 122 | class NullChunk : public NonSectionChunk { | |
| 122 | 123 | public: |
| 123 | explicit NullChunk(size_t N) : Size(N) {} | |
| 124 | bool hasData() const override { return false; } | |
| 125 | size_t getSize() const override { return Size; } | |
| 124 | explicit NullChunk(size_t n) : size(n) { hasData = false; } | |
| 125 | size_t getSize() const override { return size; } | |
| 126 | 126 | |
| 127 | void writeTo(uint8_t *Buf) const override { | |
| 128 | memset(Buf + OutputSectionOff, 0, Size); | |
| 127 | void writeTo(uint8_t *buf) const override { | |
| 128 | memset(buf, 0, size); | |
| 129 | 129 | } |
| 130 | 130 | |
| 131 | 131 | private: |
| 132 | size_t Size; | |
| 132 | size_t size; | |
| 133 | 133 | }; |
| 134 | 134 | |
| 135 | 135 | static std::vector<std::vector<DefinedImportData *>> |
| 136 | binImports(const std::vector<DefinedImportData *> &Imports) { | |
| 136 | binImports(const std::vector<DefinedImportData *> &imports) { | |
| 137 | 137 | // Group DLL-imported symbols by DLL name because that's how |
| 138 | 138 | // symbols are layed out in the import descriptor table. |
| 139 | auto Less = [](const std::string &A, const std::string &B) { | |
| 140 | return Config->DLLOrder[A] < Config->DLLOrder[B]; | |
| 139 | auto less = [](const std::string &a, const std::string &b) { | |
| 140 | return config->dllOrder[a] < config->dllOrder[b]; | |
| 141 | 141 | }; |
| 142 | 142 | std::map<std::string, std::vector<DefinedImportData *>, |
| 143 | bool(*)(const std::string &, const std::string &)> M(Less); | |
| 144 | for (DefinedImportData *Sym : Imports) | |
| 145 | M[Sym->getDLLName().lower()].push_back(Sym); | |
| 143 | bool(*)(const std::string &, const std::string &)> m(less); | |
| 144 | for (DefinedImportData *sym : imports) | |
| 145 | m[sym->getDLLName().lower()].push_back(sym); | |
| 146 | 146 | |
| 147 | std::vector<std::vector<DefinedImportData *>> V; | |
| 148 | for (auto &KV : M) { | |
| 147 | std::vector<std::vector<DefinedImportData *>> v; | |
| 148 | for (auto &kv : m) { | |
| 149 | 149 | // Sort symbols by name for each group. |
| 150 | std::vector<DefinedImportData *> &Syms = KV.second; | |
| 151 | std::sort(Syms.begin(), Syms.end(), | |
| 152 | [](DefinedImportData *A, DefinedImportData *B) { | |
| 153 | return A->getName() < B->getName(); | |
| 150 | std::vector<DefinedImportData *> &syms = kv.second; | |
| 151 | std::sort(syms.begin(), syms.end(), | |
| 152 | [](DefinedImportData *a, DefinedImportData *b) { | |
| 153 | return a->getName() < b->getName(); | |
| 154 | 154 | }); |
| 155 | V.push_back(std::move(Syms)); | |
| 155 | v.push_back(std::move(syms)); | |
| 156 | 156 | } |
| 157 | return V; | |
| 157 | return v; | |
| 158 | 158 | } |
| 159 | 159 | |
| 160 | 160 | // Export table |
| 161 | 161 | // See Microsoft PE/COFF spec 4.3 for details. |
| 162 | 162 | |
| 163 | 163 | // A chunk for the delay import descriptor table etnry. |
| 164 | class DelayDirectoryChunk : public Chunk { | |
| 164 | class DelayDirectoryChunk : public NonSectionChunk { | |
| 165 | 165 | public: |
| 166 | explicit DelayDirectoryChunk(Chunk *N) : DLLName(N) {} | |
| 166 | explicit DelayDirectoryChunk(Chunk *n) : dllName(n) {} | |
| 167 | 167 | |
| 168 | 168 | size_t getSize() const override { |
| 169 | 169 | return sizeof(delay_import_directory_table_entry); |
| 170 | 170 | } |
| 171 | 171 | |
| 172 | void writeTo(uint8_t *Buf) const override { | |
| 173 | memset(Buf + OutputSectionOff, 0, getSize()); | |
| 172 | void writeTo(uint8_t *buf) const override { | |
| 173 | memset(buf, 0, getSize()); | |
| 174 | 174 | |
| 175 | auto *E = (delay_import_directory_table_entry *)(Buf + OutputSectionOff); | |
| 176 | E->Attributes = 1; | |
| 177 | E->Name = DLLName->getRVA(); | |
| 178 | E->ModuleHandle = ModuleHandle->getRVA(); | |
| 179 | E->DelayImportAddressTable = AddressTab->getRVA(); | |
| 180 | E->DelayImportNameTable = NameTab->getRVA(); | |
| 175 | auto *e = (delay_import_directory_table_entry *)(buf); | |
| 176 | e->Attributes = 1; | |
| 177 | e->Name = dllName->getRVA(); | |
| 178 | e->ModuleHandle = moduleHandle->getRVA(); | |
| 179 | e->DelayImportAddressTable = addressTab->getRVA(); | |
| 180 | e->DelayImportNameTable = nameTab->getRVA(); | |
| 181 | 181 | } |
| 182 | 182 | |
| 183 | Chunk *DLLName; | |
| 184 | Chunk *ModuleHandle; | |
| 185 | Chunk *AddressTab; | |
| 186 | Chunk *NameTab; | |
| 183 | Chunk *dllName; | |
| 184 | Chunk *moduleHandle; | |
| 185 | Chunk *addressTab; | |
| 186 | Chunk *nameTab; | |
| 187 | 187 | }; |
| 188 | 188 | |
| 189 | 189 | // Initial contents for delay-loaded functions. |
| 190 | 190 | // This code calls __delayLoadHelper2 function to resolve a symbol |
| 191 | 191 | // and then overwrites its jump table slot with the result |
| 192 | 192 | // for subsequent function calls. |
| 193 | static const uint8_t ThunkX64[] = { | |
| 193 | static const uint8_t thunkX64[] = { | |
| 194 | 0x48, 0x8D, 0x05, 0, 0, 0, 0, // lea rax, [__imp_<FUNCNAME>] | |
| 195 | 0xE9, 0, 0, 0, 0, // jmp __tailMerge_<lib> | |
| 196 | }; | |
| 197 | ||
| 198 | static const uint8_t tailMergeX64[] = { | |
| 194 | 199 | 0x51, // push rcx |
| 195 | 200 | 0x52, // push rdx |
| 196 | 201 | 0x41, 0x50, // push r8 |
| ... | ... | @@ -200,7 +205,7 @@ static const uint8_t ThunkX64[] = { |
| 200 | 205 | 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1 |
| 201 | 206 | 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2 |
| 202 | 207 | 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3 |
| 203 | 0x48, 0x8D, 0x15, 0, 0, 0, 0, // lea rdx, [__imp_<FUNCNAME>] | |
| 208 | 0x48, 0x8B, 0xD0, // mov rdx, rax | |
| 204 | 209 | 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...] |
| 205 | 210 | 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2 |
| 206 | 211 | 0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp] |
| ... | ... | @@ -215,10 +220,15 @@ static const uint8_t ThunkX64[] = { |
| 215 | 220 | 0xFF, 0xE0, // jmp rax |
| 216 | 221 | }; |
| 217 | 222 | |
| 218 | static const uint8_t ThunkX86[] = { | |
| 223 | static const uint8_t thunkX86[] = { | |
| 224 | 0xB8, 0, 0, 0, 0, // mov eax, offset ___imp__<FUNCNAME> | |
| 225 | 0xE9, 0, 0, 0, 0, // jmp __tailMerge_<lib> | |
| 226 | }; | |
| 227 | ||
| 228 | static const uint8_t tailMergeX86[] = { | |
| 219 | 229 | 0x51, // push ecx |
| 220 | 230 | 0x52, // push edx |
| 221 | 0x68, 0, 0, 0, 0, // push offset ___imp__<FUNCNAME> | |
| 231 | 0x50, // push eax | |
| 222 | 232 | 0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR_<DLLNAME>_dll |
| 223 | 233 | 0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8 |
| 224 | 234 | 0x5A, // pop edx |
| ... | ... | @@ -226,9 +236,13 @@ static const uint8_t ThunkX86[] = { |
| 226 | 236 | 0xFF, 0xE0, // jmp eax |
| 227 | 237 | }; |
| 228 | 238 | |
| 229 | static const uint8_t ThunkARM[] = { | |
| 239 | static const uint8_t thunkARM[] = { | |
| 230 | 240 | 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 __imp_<FUNCNAME> |
| 231 | 241 | 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 __imp_<FUNCNAME> |
| 242 | 0x00, 0xf0, 0x00, 0xb8, // b.w __tailMerge_<lib> | |
| 243 | }; | |
| 244 | ||
| 245 | static const uint8_t tailMergeARM[] = { | |
| 232 | 246 | 0x2d, 0xe9, 0x0f, 0x48, // push.w {r0, r1, r2, r3, r11, lr} |
| 233 | 247 | 0x0d, 0xf2, 0x10, 0x0b, // addw r11, sp, #16 |
| 234 | 248 | 0x2d, 0xed, 0x10, 0x0b, // vpush {d0, d1, d2, d3, d4, d5, d6, d7} |
| ... | ... | @@ -242,9 +256,13 @@ static const uint8_t ThunkARM[] = { |
| 242 | 256 | 0x60, 0x47, // bx ip |
| 243 | 257 | }; |
| 244 | 258 | |
| 245 | static const uint8_t ThunkARM64[] = { | |
| 259 | static const uint8_t thunkARM64[] = { | |
| 246 | 260 | 0x11, 0x00, 0x00, 0x90, // adrp x17, #0 __imp_<FUNCNAME> |
| 247 | 261 | 0x31, 0x02, 0x00, 0x91, // add x17, x17, #0 :lo12:__imp_<FUNCNAME> |
| 262 | 0x00, 0x00, 0x00, 0x14, // b __tailMerge_<lib> | |
| 263 | }; | |
| 264 | ||
| 265 | static const uint8_t tailMergeARM64[] = { | |
| 248 | 266 | 0xfd, 0x7b, 0xb3, 0xa9, // stp x29, x30, [sp, #-208]! |
| 249 | 267 | 0xfd, 0x03, 0x00, 0x91, // mov x29, sp |
| 250 | 268 | 0xe0, 0x07, 0x01, 0xa9, // stp x0, x1, [sp, #16] |
| ... | ... | @@ -273,372 +291,445 @@ static const uint8_t ThunkARM64[] = { |
| 273 | 291 | }; |
| 274 | 292 | |
| 275 | 293 | // A chunk for the delay import thunk. |
| 276 | class ThunkChunkX64 : public Chunk { | |
| 294 | class ThunkChunkX64 : public NonSectionChunk { | |
| 295 | public: | |
| 296 | ThunkChunkX64(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {} | |
| 297 | ||
| 298 | size_t getSize() const override { return sizeof(thunkX64); } | |
| 299 | ||
| 300 | void writeTo(uint8_t *buf) const override { | |
| 301 | memcpy(buf, thunkX64, sizeof(thunkX64)); | |
| 302 | write32le(buf + 3, imp->getRVA() - rva - 7); | |
| 303 | write32le(buf + 8, tailMerge->getRVA() - rva - 12); | |
| 304 | } | |
| 305 | ||
| 306 | Defined *imp = nullptr; | |
| 307 | Chunk *tailMerge = nullptr; | |
| 308 | }; | |
| 309 | ||
| 310 | class TailMergeChunkX64 : public NonSectionChunk { | |
| 311 | public: | |
| 312 | TailMergeChunkX64(Chunk *d, Defined *h) : desc(d), helper(h) {} | |
| 313 | ||
| 314 | size_t getSize() const override { return sizeof(tailMergeX64); } | |
| 315 | ||
| 316 | void writeTo(uint8_t *buf) const override { | |
| 317 | memcpy(buf, tailMergeX64, sizeof(tailMergeX64)); | |
| 318 | write32le(buf + 39, desc->getRVA() - rva - 43); | |
| 319 | write32le(buf + 44, helper->getRVA() - rva - 48); | |
| 320 | } | |
| 321 | ||
| 322 | Chunk *desc = nullptr; | |
| 323 | Defined *helper = nullptr; | |
| 324 | }; | |
| 325 | ||
| 326 | class ThunkChunkX86 : public NonSectionChunk { | |
| 277 | 327 | public: |
| 278 | ThunkChunkX64(Defined *I, Chunk *D, Defined *H) | |
| 279 | : Imp(I), Desc(D), Helper(H) {} | |
| 328 | ThunkChunkX86(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {} | |
| 280 | 329 | |
| 281 | size_t getSize() const override { return sizeof(ThunkX64); } | |
| 330 | size_t getSize() const override { return sizeof(thunkX86); } | |
| 282 | 331 | |
| 283 | void writeTo(uint8_t *Buf) const override { | |
| 284 | memcpy(Buf + OutputSectionOff, ThunkX64, sizeof(ThunkX64)); | |
| 285 | write32le(Buf + OutputSectionOff + 36, Imp->getRVA() - RVA - 40); | |
| 286 | write32le(Buf + OutputSectionOff + 43, Desc->getRVA() - RVA - 47); | |
| 287 | write32le(Buf + OutputSectionOff + 48, Helper->getRVA() - RVA - 52); | |
| 332 | void writeTo(uint8_t *buf) const override { | |
| 333 | memcpy(buf, thunkX86, sizeof(thunkX86)); | |
| 334 | write32le(buf + 1, imp->getRVA() + config->imageBase); | |
| 335 | write32le(buf + 6, tailMerge->getRVA() - rva - 10); | |
| 288 | 336 | } |
| 289 | 337 | |
| 290 | Defined *Imp = nullptr; | |
| 291 | Chunk *Desc = nullptr; | |
| 292 | Defined *Helper = nullptr; | |
| 338 | void getBaserels(std::vector<Baserel> *res) override { | |
| 339 | res->emplace_back(rva + 1); | |
| 340 | } | |
| 341 | ||
| 342 | Defined *imp = nullptr; | |
| 343 | Chunk *tailMerge = nullptr; | |
| 293 | 344 | }; |
| 294 | 345 | |
| 295 | class ThunkChunkX86 : public Chunk { | |
| 346 | class TailMergeChunkX86 : public NonSectionChunk { | |
| 296 | 347 | public: |
| 297 | ThunkChunkX86(Defined *I, Chunk *D, Defined *H) | |
| 298 | : Imp(I), Desc(D), Helper(H) {} | |
| 348 | TailMergeChunkX86(Chunk *d, Defined *h) : desc(d), helper(h) {} | |
| 299 | 349 | |
| 300 | size_t getSize() const override { return sizeof(ThunkX86); } | |
| 350 | size_t getSize() const override { return sizeof(tailMergeX86); } | |
| 301 | 351 | |
| 302 | void writeTo(uint8_t *Buf) const override { | |
| 303 | memcpy(Buf + OutputSectionOff, ThunkX86, sizeof(ThunkX86)); | |
| 304 | write32le(Buf + OutputSectionOff + 3, Imp->getRVA() + Config->ImageBase); | |
| 305 | write32le(Buf + OutputSectionOff + 8, Desc->getRVA() + Config->ImageBase); | |
| 306 | write32le(Buf + OutputSectionOff + 13, Helper->getRVA() - RVA - 17); | |
| 352 | void writeTo(uint8_t *buf) const override { | |
| 353 | memcpy(buf, tailMergeX86, sizeof(tailMergeX86)); | |
| 354 | write32le(buf + 4, desc->getRVA() + config->imageBase); | |
| 355 | write32le(buf + 9, helper->getRVA() - rva - 13); | |
| 307 | 356 | } |
| 308 | 357 | |
| 309 | void getBaserels(std::vector<Baserel> *Res) override { | |
| 310 | Res->emplace_back(RVA + 3); | |
| 311 | Res->emplace_back(RVA + 8); | |
| 358 | void getBaserels(std::vector<Baserel> *res) override { | |
| 359 | res->emplace_back(rva + 4); | |
| 312 | 360 | } |
| 313 | 361 | |
| 314 | Defined *Imp = nullptr; | |
| 315 | Chunk *Desc = nullptr; | |
| 316 | Defined *Helper = nullptr; | |
| 362 | Chunk *desc = nullptr; | |
| 363 | Defined *helper = nullptr; | |
| 317 | 364 | }; |
| 318 | 365 | |
| 319 | class ThunkChunkARM : public Chunk { | |
| 366 | class ThunkChunkARM : public NonSectionChunk { | |
| 320 | 367 | public: |
| 321 | ThunkChunkARM(Defined *I, Chunk *D, Defined *H) | |
| 322 | : Imp(I), Desc(D), Helper(H) {} | |
| 368 | ThunkChunkARM(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {} | |
| 323 | 369 | |
| 324 | size_t getSize() const override { return sizeof(ThunkARM); } | |
| 370 | size_t getSize() const override { return sizeof(thunkARM); } | |
| 325 | 371 | |
| 326 | void writeTo(uint8_t *Buf) const override { | |
| 327 | memcpy(Buf + OutputSectionOff, ThunkARM, sizeof(ThunkARM)); | |
| 328 | applyMOV32T(Buf + OutputSectionOff + 0, Imp->getRVA() + Config->ImageBase); | |
| 329 | applyMOV32T(Buf + OutputSectionOff + 22, Desc->getRVA() + Config->ImageBase); | |
| 330 | applyBranch24T(Buf + OutputSectionOff + 30, Helper->getRVA() - RVA - 34); | |
| 372 | void writeTo(uint8_t *buf) const override { | |
| 373 | memcpy(buf, thunkARM, sizeof(thunkARM)); | |
| 374 | applyMOV32T(buf + 0, imp->getRVA() + config->imageBase); | |
| 375 | applyBranch24T(buf + 8, tailMerge->getRVA() - rva - 12); | |
| 331 | 376 | } |
| 332 | 377 | |
| 333 | void getBaserels(std::vector<Baserel> *Res) override { | |
| 334 | Res->emplace_back(RVA + 0, IMAGE_REL_BASED_ARM_MOV32T); | |
| 335 | Res->emplace_back(RVA + 22, IMAGE_REL_BASED_ARM_MOV32T); | |
| 378 | void getBaserels(std::vector<Baserel> *res) override { | |
| 379 | res->emplace_back(rva + 0, IMAGE_REL_BASED_ARM_MOV32T); | |
| 336 | 380 | } |
| 337 | 381 | |
| 338 | Defined *Imp = nullptr; | |
| 339 | Chunk *Desc = nullptr; | |
| 340 | Defined *Helper = nullptr; | |
| 382 | Defined *imp = nullptr; | |
| 383 | Chunk *tailMerge = nullptr; | |
| 341 | 384 | }; |
| 342 | 385 | |
| 343 | class ThunkChunkARM64 : public Chunk { | |
| 386 | class TailMergeChunkARM : public NonSectionChunk { | |
| 344 | 387 | public: |
| 345 | ThunkChunkARM64(Defined *I, Chunk *D, Defined *H) | |
| 346 | : Imp(I), Desc(D), Helper(H) {} | |
| 388 | TailMergeChunkARM(Chunk *d, Defined *h) : desc(d), helper(h) {} | |
| 389 | ||
| 390 | size_t getSize() const override { return sizeof(tailMergeARM); } | |
| 347 | 391 | |
| 348 | size_t getSize() const override { return sizeof(ThunkARM64); } | |
| 392 | void writeTo(uint8_t *buf) const override { | |
| 393 | memcpy(buf, tailMergeARM, sizeof(tailMergeARM)); | |
| 394 | applyMOV32T(buf + 14, desc->getRVA() + config->imageBase); | |
| 395 | applyBranch24T(buf + 22, helper->getRVA() - rva - 26); | |
| 396 | } | |
| 349 | 397 | |
| 350 | void writeTo(uint8_t *Buf) const override { | |
| 351 | memcpy(Buf + OutputSectionOff, ThunkARM64, sizeof(ThunkARM64)); | |
| 352 | applyArm64Addr(Buf + OutputSectionOff + 0, Imp->getRVA(), RVA + 0, 12); | |
| 353 | applyArm64Imm(Buf + OutputSectionOff + 4, Imp->getRVA() & 0xfff, 0); | |
| 354 | applyArm64Addr(Buf + OutputSectionOff + 52, Desc->getRVA(), RVA + 52, 12); | |
| 355 | applyArm64Imm(Buf + OutputSectionOff + 56, Desc->getRVA() & 0xfff, 0); | |
| 356 | applyArm64Branch26(Buf + OutputSectionOff + 60, | |
| 357 | Helper->getRVA() - RVA - 60); | |
| 398 | void getBaserels(std::vector<Baserel> *res) override { | |
| 399 | res->emplace_back(rva + 14, IMAGE_REL_BASED_ARM_MOV32T); | |
| 358 | 400 | } |
| 359 | 401 | |
| 360 | Defined *Imp = nullptr; | |
| 361 | Chunk *Desc = nullptr; | |
| 362 | Defined *Helper = nullptr; | |
| 402 | Chunk *desc = nullptr; | |
| 403 | Defined *helper = nullptr; | |
| 404 | }; | |
| 405 | ||
| 406 | class ThunkChunkARM64 : public NonSectionChunk { | |
| 407 | public: | |
| 408 | ThunkChunkARM64(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {} | |
| 409 | ||
| 410 | size_t getSize() const override { return sizeof(thunkARM64); } | |
| 411 | ||
| 412 | void writeTo(uint8_t *buf) const override { | |
| 413 | memcpy(buf, thunkARM64, sizeof(thunkARM64)); | |
| 414 | applyArm64Addr(buf + 0, imp->getRVA(), rva + 0, 12); | |
| 415 | applyArm64Imm(buf + 4, imp->getRVA() & 0xfff, 0); | |
| 416 | applyArm64Branch26(buf + 8, tailMerge->getRVA() - rva - 8); | |
| 417 | } | |
| 418 | ||
| 419 | Defined *imp = nullptr; | |
| 420 | Chunk *tailMerge = nullptr; | |
| 421 | }; | |
| 422 | ||
| 423 | class TailMergeChunkARM64 : public NonSectionChunk { | |
| 424 | public: | |
| 425 | TailMergeChunkARM64(Chunk *d, Defined *h) : desc(d), helper(h) {} | |
| 426 | ||
| 427 | size_t getSize() const override { return sizeof(tailMergeARM64); } | |
| 428 | ||
| 429 | void writeTo(uint8_t *buf) const override { | |
| 430 | memcpy(buf, tailMergeARM64, sizeof(tailMergeARM64)); | |
| 431 | applyArm64Addr(buf + 44, desc->getRVA(), rva + 44, 12); | |
| 432 | applyArm64Imm(buf + 48, desc->getRVA() & 0xfff, 0); | |
| 433 | applyArm64Branch26(buf + 52, helper->getRVA() - rva - 52); | |
| 434 | } | |
| 435 | ||
| 436 | Chunk *desc = nullptr; | |
| 437 | Defined *helper = nullptr; | |
| 363 | 438 | }; |
| 364 | 439 | |
| 365 | 440 | // A chunk for the import descriptor table. |
| 366 | class DelayAddressChunk : public Chunk { | |
| 441 | class DelayAddressChunk : public NonSectionChunk { | |
| 367 | 442 | public: |
| 368 | explicit DelayAddressChunk(Chunk *C) : Thunk(C) { | |
| 369 | Alignment = Config->Wordsize; | |
| 443 | explicit DelayAddressChunk(Chunk *c) : thunk(c) { | |
| 444 | setAlignment(config->wordsize); | |
| 370 | 445 | } |
| 371 | size_t getSize() const override { return Config->Wordsize; } | |
| 446 | size_t getSize() const override { return config->wordsize; } | |
| 372 | 447 | |
| 373 | void writeTo(uint8_t *Buf) const override { | |
| 374 | if (Config->is64()) { | |
| 375 | write64le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase); | |
| 448 | void writeTo(uint8_t *buf) const override { | |
| 449 | if (config->is64()) { | |
| 450 | write64le(buf, thunk->getRVA() + config->imageBase); | |
| 376 | 451 | } else { |
| 377 | uint32_t Bit = 0; | |
| 452 | uint32_t bit = 0; | |
| 378 | 453 | // Pointer to thumb code must have the LSB set, so adjust it. |
| 379 | if (Config->Machine == ARMNT) | |
| 380 | Bit = 1; | |
| 381 | write32le(Buf + OutputSectionOff, (Thunk->getRVA() + Config->ImageBase) | Bit); | |
| 454 | if (config->machine == ARMNT) | |
| 455 | bit = 1; | |
| 456 | write32le(buf, (thunk->getRVA() + config->imageBase) | bit); | |
| 382 | 457 | } |
| 383 | 458 | } |
| 384 | 459 | |
| 385 | void getBaserels(std::vector<Baserel> *Res) override { | |
| 386 | Res->emplace_back(RVA); | |
| 460 | void getBaserels(std::vector<Baserel> *res) override { | |
| 461 | res->emplace_back(rva); | |
| 387 | 462 | } |
| 388 | 463 | |
| 389 | Chunk *Thunk; | |
| 464 | Chunk *thunk; | |
| 390 | 465 | }; |
| 391 | 466 | |
| 392 | 467 | // Export table |
| 393 | 468 | // Read Microsoft PE/COFF spec 5.3 for details. |
| 394 | 469 | |
| 395 | 470 | // A chunk for the export descriptor table. |
| 396 | class ExportDirectoryChunk : public Chunk { | |
| 471 | class ExportDirectoryChunk : public NonSectionChunk { | |
| 397 | 472 | public: |
| 398 | ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O) | |
| 399 | : MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N), | |
| 400 | OrdinalTab(O) {} | |
| 473 | ExportDirectoryChunk(int i, int j, Chunk *d, Chunk *a, Chunk *n, Chunk *o) | |
| 474 | : maxOrdinal(i), nameTabSize(j), dllName(d), addressTab(a), nameTab(n), | |
| 475 | ordinalTab(o) {} | |
| 401 | 476 | |
| 402 | 477 | size_t getSize() const override { |
| 403 | 478 | return sizeof(export_directory_table_entry); |
| 404 | 479 | } |
| 405 | 480 | |
| 406 | void writeTo(uint8_t *Buf) const override { | |
| 407 | memset(Buf + OutputSectionOff, 0, getSize()); | |
| 408 | ||
| 409 | auto *E = (export_directory_table_entry *)(Buf + OutputSectionOff); | |
| 410 | E->NameRVA = DLLName->getRVA(); | |
| 411 | E->OrdinalBase = 0; | |
| 412 | E->AddressTableEntries = MaxOrdinal + 1; | |
| 413 | E->NumberOfNamePointers = NameTabSize; | |
| 414 | E->ExportAddressTableRVA = AddressTab->getRVA(); | |
| 415 | E->NamePointerRVA = NameTab->getRVA(); | |
| 416 | E->OrdinalTableRVA = OrdinalTab->getRVA(); | |
| 481 | void writeTo(uint8_t *buf) const override { | |
| 482 | memset(buf, 0, getSize()); | |
| 483 | ||
| 484 | auto *e = (export_directory_table_entry *)(buf); | |
| 485 | e->NameRVA = dllName->getRVA(); | |
| 486 | e->OrdinalBase = 0; | |
| 487 | e->AddressTableEntries = maxOrdinal + 1; | |
| 488 | e->NumberOfNamePointers = nameTabSize; | |
| 489 | e->ExportAddressTableRVA = addressTab->getRVA(); | |
| 490 | e->NamePointerRVA = nameTab->getRVA(); | |
| 491 | e->OrdinalTableRVA = ordinalTab->getRVA(); | |
| 417 | 492 | } |
| 418 | 493 | |
| 419 | uint16_t MaxOrdinal; | |
| 420 | uint16_t NameTabSize; | |
| 421 | Chunk *DLLName; | |
| 422 | Chunk *AddressTab; | |
| 423 | Chunk *NameTab; | |
| 424 | Chunk *OrdinalTab; | |
| 494 | uint16_t maxOrdinal; | |
| 495 | uint16_t nameTabSize; | |
| 496 | Chunk *dllName; | |
| 497 | Chunk *addressTab; | |
| 498 | Chunk *nameTab; | |
| 499 | Chunk *ordinalTab; | |
| 425 | 500 | }; |
| 426 | 501 | |
| 427 | class AddressTableChunk : public Chunk { | |
| 502 | class AddressTableChunk : public NonSectionChunk { | |
| 428 | 503 | public: |
| 429 | explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {} | |
| 430 | size_t getSize() const override { return Size * 4; } | |
| 504 | explicit AddressTableChunk(size_t maxOrdinal) : size(maxOrdinal + 1) {} | |
| 505 | size_t getSize() const override { return size * 4; } | |
| 431 | 506 | |
| 432 | void writeTo(uint8_t *Buf) const override { | |
| 433 | memset(Buf + OutputSectionOff, 0, getSize()); | |
| 507 | void writeTo(uint8_t *buf) const override { | |
| 508 | memset(buf, 0, getSize()); | |
| 434 | 509 | |
| 435 | for (const Export &E : Config->Exports) { | |
| 436 | uint8_t *P = Buf + OutputSectionOff + E.Ordinal * 4; | |
| 437 | uint32_t Bit = 0; | |
| 510 | for (const Export &e : config->exports) { | |
| 511 | uint8_t *p = buf + e.ordinal * 4; | |
| 512 | uint32_t bit = 0; | |
| 438 | 513 | // Pointer to thumb code must have the LSB set, so adjust it. |
| 439 | if (Config->Machine == ARMNT && !E.Data) | |
| 440 | Bit = 1; | |
| 441 | if (E.ForwardChunk) { | |
| 442 | write32le(P, E.ForwardChunk->getRVA() | Bit); | |
| 514 | if (config->machine == ARMNT && !e.data) | |
| 515 | bit = 1; | |
| 516 | if (e.forwardChunk) { | |
| 517 | write32le(p, e.forwardChunk->getRVA() | bit); | |
| 443 | 518 | } else { |
| 444 | write32le(P, cast<Defined>(E.Sym)->getRVA() | Bit); | |
| 519 | write32le(p, cast<Defined>(e.sym)->getRVA() | bit); | |
| 445 | 520 | } |
| 446 | 521 | } |
| 447 | 522 | } |
| 448 | 523 | |
| 449 | 524 | private: |
| 450 | size_t Size; | |
| 525 | size_t size; | |
| 451 | 526 | }; |
| 452 | 527 | |
| 453 | class NamePointersChunk : public Chunk { | |
| 528 | class NamePointersChunk : public NonSectionChunk { | |
| 454 | 529 | public: |
| 455 | explicit NamePointersChunk(std::vector<Chunk *> &V) : Chunks(V) {} | |
| 456 | size_t getSize() const override { return Chunks.size() * 4; } | |
| 457 | ||
| 458 | void writeTo(uint8_t *Buf) const override { | |
| 459 | uint8_t *P = Buf + OutputSectionOff; | |
| 460 | for (Chunk *C : Chunks) { | |
| 461 | write32le(P, C->getRVA()); | |
| 462 | P += 4; | |
| 530 | explicit NamePointersChunk(std::vector<Chunk *> &v) : chunks(v) {} | |
| 531 | size_t getSize() const override { return chunks.size() * 4; } | |
| 532 | ||
| 533 | void writeTo(uint8_t *buf) const override { | |
| 534 | for (Chunk *c : chunks) { | |
| 535 | write32le(buf, c->getRVA()); | |
| 536 | buf += 4; | |
| 463 | 537 | } |
| 464 | 538 | } |
| 465 | 539 | |
| 466 | 540 | private: |
| 467 | std::vector<Chunk *> Chunks; | |
| 541 | std::vector<Chunk *> chunks; | |
| 468 | 542 | }; |
| 469 | 543 | |
| 470 | class ExportOrdinalChunk : public Chunk { | |
| 544 | class ExportOrdinalChunk : public NonSectionChunk { | |
| 471 | 545 | public: |
| 472 | explicit ExportOrdinalChunk(size_t I) : Size(I) {} | |
| 473 | size_t getSize() const override { return Size * 2; } | |
| 546 | explicit ExportOrdinalChunk(size_t i) : size(i) {} | |
| 547 | size_t getSize() const override { return size * 2; } | |
| 474 | 548 | |
| 475 | void writeTo(uint8_t *Buf) const override { | |
| 476 | uint8_t *P = Buf + OutputSectionOff; | |
| 477 | for (Export &E : Config->Exports) { | |
| 478 | if (E.Noname) | |
| 549 | void writeTo(uint8_t *buf) const override { | |
| 550 | for (Export &e : config->exports) { | |
| 551 | if (e.noname) | |
| 479 | 552 | continue; |
| 480 | write16le(P, E.Ordinal); | |
| 481 | P += 2; | |
| 553 | write16le(buf, e.ordinal); | |
| 554 | buf += 2; | |
| 482 | 555 | } |
| 483 | 556 | } |
| 484 | 557 | |
| 485 | 558 | private: |
| 486 | size_t Size; | |
| 559 | size_t size; | |
| 487 | 560 | }; |
| 488 | 561 | |
| 489 | 562 | } // anonymous namespace |
| 490 | 563 | |
| 491 | 564 | void IdataContents::create() { |
| 492 | std::vector<std::vector<DefinedImportData *>> V = binImports(Imports); | |
| 565 | std::vector<std::vector<DefinedImportData *>> v = binImports(imports); | |
| 493 | 566 | |
| 494 | 567 | // Create .idata contents for each DLL. |
| 495 | for (std::vector<DefinedImportData *> &Syms : V) { | |
| 568 | for (std::vector<DefinedImportData *> &syms : v) { | |
| 496 | 569 | // Create lookup and address tables. If they have external names, |
| 497 | // we need to create HintName chunks to store the names. | |
| 570 | // we need to create hintName chunks to store the names. | |
| 498 | 571 | // If they don't (if they are import-by-ordinals), we store only |
| 499 | 572 | // ordinal values to the table. |
| 500 | size_t Base = Lookups.size(); | |
| 501 | for (DefinedImportData *S : Syms) { | |
| 502 | uint16_t Ord = S->getOrdinal(); | |
| 503 | if (S->getExternalName().empty()) { | |
| 504 | Lookups.push_back(make<OrdinalOnlyChunk>(Ord)); | |
| 505 | Addresses.push_back(make<OrdinalOnlyChunk>(Ord)); | |
| 573 | size_t base = lookups.size(); | |
| 574 | for (DefinedImportData *s : syms) { | |
| 575 | uint16_t ord = s->getOrdinal(); | |
| 576 | if (s->getExternalName().empty()) { | |
| 577 | lookups.push_back(make<OrdinalOnlyChunk>(ord)); | |
| 578 | addresses.push_back(make<OrdinalOnlyChunk>(ord)); | |
| 506 | 579 | continue; |
| 507 | 580 | } |
| 508 | auto *C = make<HintNameChunk>(S->getExternalName(), Ord); | |
| 509 | Lookups.push_back(make<LookupChunk>(C)); | |
| 510 | Addresses.push_back(make<LookupChunk>(C)); | |
| 511 | Hints.push_back(C); | |
| 581 | auto *c = make<HintNameChunk>(s->getExternalName(), ord); | |
| 582 | lookups.push_back(make<LookupChunk>(c)); | |
| 583 | addresses.push_back(make<LookupChunk>(c)); | |
| 584 | hints.push_back(c); | |
| 512 | 585 | } |
| 513 | 586 | // Terminate with null values. |
| 514 | Lookups.push_back(make<NullChunk>(Config->Wordsize)); | |
| 515 | Addresses.push_back(make<NullChunk>(Config->Wordsize)); | |
| 587 | lookups.push_back(make<NullChunk>(config->wordsize)); | |
| 588 | addresses.push_back(make<NullChunk>(config->wordsize)); | |
| 516 | 589 | |
| 517 | for (int I = 0, E = Syms.size(); I < E; ++I) | |
| 518 | Syms[I]->setLocation(Addresses[Base + I]); | |
| 590 | for (int i = 0, e = syms.size(); i < e; ++i) | |
| 591 | syms[i]->setLocation(addresses[base + i]); | |
| 519 | 592 | |
| 520 | 593 | // Create the import table header. |
| 521 | DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName())); | |
| 522 | auto *Dir = make<ImportDirectoryChunk>(DLLNames.back()); | |
| 523 | Dir->LookupTab = Lookups[Base]; | |
| 524 | Dir->AddressTab = Addresses[Base]; | |
| 525 | Dirs.push_back(Dir); | |
| 594 | dllNames.push_back(make<StringChunk>(syms[0]->getDLLName())); | |
| 595 | auto *dir = make<ImportDirectoryChunk>(dllNames.back()); | |
| 596 | dir->lookupTab = lookups[base]; | |
| 597 | dir->addressTab = addresses[base]; | |
| 598 | dirs.push_back(dir); | |
| 526 | 599 | } |
| 527 | 600 | // Add null terminator. |
| 528 | Dirs.push_back(make<NullChunk>(sizeof(ImportDirectoryTableEntry))); | |
| 601 | dirs.push_back(make<NullChunk>(sizeof(ImportDirectoryTableEntry))); | |
| 529 | 602 | } |
| 530 | 603 | |
| 531 | 604 | std::vector<Chunk *> DelayLoadContents::getChunks() { |
| 532 | std::vector<Chunk *> V; | |
| 533 | V.insert(V.end(), Dirs.begin(), Dirs.end()); | |
| 534 | V.insert(V.end(), Names.begin(), Names.end()); | |
| 535 | V.insert(V.end(), HintNames.begin(), HintNames.end()); | |
| 536 | V.insert(V.end(), DLLNames.begin(), DLLNames.end()); | |
| 537 | return V; | |
| 605 | std::vector<Chunk *> v; | |
| 606 | v.insert(v.end(), dirs.begin(), dirs.end()); | |
| 607 | v.insert(v.end(), names.begin(), names.end()); | |
| 608 | v.insert(v.end(), hintNames.begin(), hintNames.end()); | |
| 609 | v.insert(v.end(), dllNames.begin(), dllNames.end()); | |
| 610 | return v; | |
| 538 | 611 | } |
| 539 | 612 | |
| 540 | 613 | std::vector<Chunk *> DelayLoadContents::getDataChunks() { |
| 541 | std::vector<Chunk *> V; | |
| 542 | V.insert(V.end(), ModuleHandles.begin(), ModuleHandles.end()); | |
| 543 | V.insert(V.end(), Addresses.begin(), Addresses.end()); | |
| 544 | return V; | |
| 614 | std::vector<Chunk *> v; | |
| 615 | v.insert(v.end(), moduleHandles.begin(), moduleHandles.end()); | |
| 616 | v.insert(v.end(), addresses.begin(), addresses.end()); | |
| 617 | return v; | |
| 545 | 618 | } |
| 546 | 619 | |
| 547 | 620 | uint64_t DelayLoadContents::getDirSize() { |
| 548 | return Dirs.size() * sizeof(delay_import_directory_table_entry); | |
| 621 | return dirs.size() * sizeof(delay_import_directory_table_entry); | |
| 549 | 622 | } |
| 550 | 623 | |
| 551 | void DelayLoadContents::create(Defined *H) { | |
| 552 | Helper = H; | |
| 553 | std::vector<std::vector<DefinedImportData *>> V = binImports(Imports); | |
| 624 | void DelayLoadContents::create(Defined *h) { | |
| 625 | helper = h; | |
| 626 | std::vector<std::vector<DefinedImportData *>> v = binImports(imports); | |
| 554 | 627 | |
| 555 | 628 | // Create .didat contents for each DLL. |
| 556 | for (std::vector<DefinedImportData *> &Syms : V) { | |
| 629 | for (std::vector<DefinedImportData *> &syms : v) { | |
| 557 | 630 | // Create the delay import table header. |
| 558 | DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName())); | |
| 559 | auto *Dir = make<DelayDirectoryChunk>(DLLNames.back()); | |
| 560 | ||
| 561 | size_t Base = Addresses.size(); | |
| 562 | for (DefinedImportData *S : Syms) { | |
| 563 | Chunk *T = newThunkChunk(S, Dir); | |
| 564 | auto *A = make<DelayAddressChunk>(T); | |
| 565 | Addresses.push_back(A); | |
| 566 | Thunks.push_back(T); | |
| 567 | StringRef ExtName = S->getExternalName(); | |
| 568 | if (ExtName.empty()) { | |
| 569 | Names.push_back(make<OrdinalOnlyChunk>(S->getOrdinal())); | |
| 631 | dllNames.push_back(make<StringChunk>(syms[0]->getDLLName())); | |
| 632 | auto *dir = make<DelayDirectoryChunk>(dllNames.back()); | |
| 633 | ||
| 634 | size_t base = addresses.size(); | |
| 635 | Chunk *tm = newTailMergeChunk(dir); | |
| 636 | for (DefinedImportData *s : syms) { | |
| 637 | Chunk *t = newThunkChunk(s, tm); | |
| 638 | auto *a = make<DelayAddressChunk>(t); | |
| 639 | addresses.push_back(a); | |
| 640 | thunks.push_back(t); | |
| 641 | StringRef extName = s->getExternalName(); | |
| 642 | if (extName.empty()) { | |
| 643 | names.push_back(make<OrdinalOnlyChunk>(s->getOrdinal())); | |
| 570 | 644 | } else { |
| 571 | auto *C = make<HintNameChunk>(ExtName, 0); | |
| 572 | Names.push_back(make<LookupChunk>(C)); | |
| 573 | HintNames.push_back(C); | |
| 645 | auto *c = make<HintNameChunk>(extName, 0); | |
| 646 | names.push_back(make<LookupChunk>(c)); | |
| 647 | hintNames.push_back(c); | |
| 574 | 648 | } |
| 575 | 649 | } |
| 650 | thunks.push_back(tm); | |
| 576 | 651 | // Terminate with null values. |
| 577 | Addresses.push_back(make<NullChunk>(8)); | |
| 578 | Names.push_back(make<NullChunk>(8)); | |
| 652 | addresses.push_back(make<NullChunk>(8)); | |
| 653 | names.push_back(make<NullChunk>(8)); | |
| 579 | 654 | |
| 580 | for (int I = 0, E = Syms.size(); I < E; ++I) | |
| 581 | Syms[I]->setLocation(Addresses[Base + I]); | |
| 582 | auto *MH = make<NullChunk>(8); | |
| 583 | MH->Alignment = 8; | |
| 584 | ModuleHandles.push_back(MH); | |
| 655 | for (int i = 0, e = syms.size(); i < e; ++i) | |
| 656 | syms[i]->setLocation(addresses[base + i]); | |
| 657 | auto *mh = make<NullChunk>(8); | |
| 658 | mh->setAlignment(8); | |
| 659 | moduleHandles.push_back(mh); | |
| 585 | 660 | |
| 586 | 661 | // Fill the delay import table header fields. |
| 587 | Dir->ModuleHandle = MH; | |
| 588 | Dir->AddressTab = Addresses[Base]; | |
| 589 | Dir->NameTab = Names[Base]; | |
| 590 | Dirs.push_back(Dir); | |
| 662 | dir->moduleHandle = mh; | |
| 663 | dir->addressTab = addresses[base]; | |
| 664 | dir->nameTab = names[base]; | |
| 665 | dirs.push_back(dir); | |
| 591 | 666 | } |
| 592 | 667 | // Add null terminator. |
| 593 | Dirs.push_back(make<NullChunk>(sizeof(delay_import_directory_table_entry))); | |
| 668 | dirs.push_back(make<NullChunk>(sizeof(delay_import_directory_table_entry))); | |
| 594 | 669 | } |
| 595 | 670 | |
| 596 | Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) { | |
| 597 | switch (Config->Machine) { | |
| 671 | Chunk *DelayLoadContents::newTailMergeChunk(Chunk *dir) { | |
| 672 | switch (config->machine) { | |
| 598 | 673 | case AMD64: |
| 599 | return make<ThunkChunkX64>(S, Dir, Helper); | |
| 674 | return make<TailMergeChunkX64>(dir, helper); | |
| 600 | 675 | case I386: |
| 601 | return make<ThunkChunkX86>(S, Dir, Helper); | |
| 676 | return make<TailMergeChunkX86>(dir, helper); | |
| 602 | 677 | case ARMNT: |
| 603 | return make<ThunkChunkARM>(S, Dir, Helper); | |
| 678 | return make<TailMergeChunkARM>(dir, helper); | |
| 604 | 679 | case ARM64: |
| 605 | return make<ThunkChunkARM64>(S, Dir, Helper); | |
| 680 | return make<TailMergeChunkARM64>(dir, helper); | |
| 681 | default: | |
| 682 | llvm_unreachable("unsupported machine type"); | |
| 683 | } | |
| 684 | } | |
| 685 | ||
| 686 | Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *s, | |
| 687 | Chunk *tailMerge) { | |
| 688 | switch (config->machine) { | |
| 689 | case AMD64: | |
| 690 | return make<ThunkChunkX64>(s, tailMerge); | |
| 691 | case I386: | |
| 692 | return make<ThunkChunkX86>(s, tailMerge); | |
| 693 | case ARMNT: | |
| 694 | return make<ThunkChunkARM>(s, tailMerge); | |
| 695 | case ARM64: | |
| 696 | return make<ThunkChunkARM64>(s, tailMerge); | |
| 606 | 697 | default: |
| 607 | 698 | llvm_unreachable("unsupported machine type"); |
| 608 | 699 | } |
| 609 | 700 | } |
| 610 | 701 | |
| 611 | 702 | EdataContents::EdataContents() { |
| 612 | uint16_t MaxOrdinal = 0; | |
| 613 | for (Export &E : Config->Exports) | |
| 614 | MaxOrdinal = std::max(MaxOrdinal, E.Ordinal); | |
| 615 | ||
| 616 | auto *DLLName = make<StringChunk>(sys::path::filename(Config->OutputFile)); | |
| 617 | auto *AddressTab = make<AddressTableChunk>(MaxOrdinal); | |
| 618 | std::vector<Chunk *> Names; | |
| 619 | for (Export &E : Config->Exports) | |
| 620 | if (!E.Noname) | |
| 621 | Names.push_back(make<StringChunk>(E.ExportName)); | |
| 622 | ||
| 623 | std::vector<Chunk *> Forwards; | |
| 624 | for (Export &E : Config->Exports) { | |
| 625 | if (E.ForwardTo.empty()) | |
| 703 | uint16_t maxOrdinal = 0; | |
| 704 | for (Export &e : config->exports) | |
| 705 | maxOrdinal = std::max(maxOrdinal, e.ordinal); | |
| 706 | ||
| 707 | auto *dllName = make<StringChunk>(sys::path::filename(config->outputFile)); | |
| 708 | auto *addressTab = make<AddressTableChunk>(maxOrdinal); | |
| 709 | std::vector<Chunk *> names; | |
| 710 | for (Export &e : config->exports) | |
| 711 | if (!e.noname) | |
| 712 | names.push_back(make<StringChunk>(e.exportName)); | |
| 713 | ||
| 714 | std::vector<Chunk *> forwards; | |
| 715 | for (Export &e : config->exports) { | |
| 716 | if (e.forwardTo.empty()) | |
| 626 | 717 | continue; |
| 627 | E.ForwardChunk = make<StringChunk>(E.ForwardTo); | |
| 628 | Forwards.push_back(E.ForwardChunk); | |
| 629 | } | |
| 630 | ||
| 631 | auto *NameTab = make<NamePointersChunk>(Names); | |
| 632 | auto *OrdinalTab = make<ExportOrdinalChunk>(Names.size()); | |
| 633 | auto *Dir = make<ExportDirectoryChunk>(MaxOrdinal, Names.size(), DLLName, | |
| 634 | AddressTab, NameTab, OrdinalTab); | |
| 635 | Chunks.push_back(Dir); | |
| 636 | Chunks.push_back(DLLName); | |
| 637 | Chunks.push_back(AddressTab); | |
| 638 | Chunks.push_back(NameTab); | |
| 639 | Chunks.push_back(OrdinalTab); | |
| 640 | Chunks.insert(Chunks.end(), Names.begin(), Names.end()); | |
| 641 | Chunks.insert(Chunks.end(), Forwards.begin(), Forwards.end()); | |
| 718 | e.forwardChunk = make<StringChunk>(e.forwardTo); | |
| 719 | forwards.push_back(e.forwardChunk); | |
| 720 | } | |
| 721 | ||
| 722 | auto *nameTab = make<NamePointersChunk>(names); | |
| 723 | auto *ordinalTab = make<ExportOrdinalChunk>(names.size()); | |
| 724 | auto *dir = make<ExportDirectoryChunk>(maxOrdinal, names.size(), dllName, | |
| 725 | addressTab, nameTab, ordinalTab); | |
| 726 | chunks.push_back(dir); | |
| 727 | chunks.push_back(dllName); | |
| 728 | chunks.push_back(addressTab); | |
| 729 | chunks.push_back(nameTab); | |
| 730 | chunks.push_back(ordinalTab); | |
| 731 | chunks.insert(chunks.end(), names.begin(), names.end()); | |
| 732 | chunks.insert(chunks.end(), forwards.begin(), forwards.end()); | |
| 642 | 733 | } |
| 643 | 734 | |
| 644 | 735 | } // namespace coff |
deps/lld/COFF/DLL.h+30-30| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- DLL.h ----------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -22,45 +21,46 @@ namespace coff { |
| 22 | 21 | // call create() to populate the chunk vectors. |
| 23 | 22 | class IdataContents { |
| 24 | 23 | public: |
| 25 | void add(DefinedImportData *Sym) { Imports.push_back(Sym); } | |
| 26 | bool empty() { return Imports.empty(); } | |
| 24 | void add(DefinedImportData *sym) { imports.push_back(sym); } | |
| 25 | bool empty() { return imports.empty(); } | |
| 27 | 26 | |
| 28 | 27 | void create(); |
| 29 | 28 | |
| 30 | std::vector<DefinedImportData *> Imports; | |
| 31 | std::vector<Chunk *> Dirs; | |
| 32 | std::vector<Chunk *> Lookups; | |
| 33 | std::vector<Chunk *> Addresses; | |
| 34 | std::vector<Chunk *> Hints; | |
| 35 | std::vector<Chunk *> DLLNames; | |
| 29 | std::vector<DefinedImportData *> imports; | |
| 30 | std::vector<Chunk *> dirs; | |
| 31 | std::vector<Chunk *> lookups; | |
| 32 | std::vector<Chunk *> addresses; | |
| 33 | std::vector<Chunk *> hints; | |
| 34 | std::vector<Chunk *> dllNames; | |
| 36 | 35 | }; |
| 37 | 36 | |
| 38 | 37 | // Windows-specific. |
| 39 | 38 | // DelayLoadContents creates all chunks for the delay-load DLL import table. |
| 40 | 39 | class DelayLoadContents { |
| 41 | 40 | public: |
| 42 | void add(DefinedImportData *Sym) { Imports.push_back(Sym); } | |
| 43 | bool empty() { return Imports.empty(); } | |
| 44 | void create(Defined *Helper); | |
| 41 | void add(DefinedImportData *sym) { imports.push_back(sym); } | |
| 42 | bool empty() { return imports.empty(); } | |
| 43 | void create(Defined *helper); | |
| 45 | 44 | std::vector<Chunk *> getChunks(); |
| 46 | 45 | std::vector<Chunk *> getDataChunks(); |
| 47 | ArrayRef<Chunk *> getCodeChunks() { return Thunks; } | |
| 46 | ArrayRef<Chunk *> getCodeChunks() { return thunks; } | |
| 48 | 47 | |
| 49 | uint64_t getDirRVA() { return Dirs[0]->getRVA(); } | |
| 48 | uint64_t getDirRVA() { return dirs[0]->getRVA(); } | |
| 50 | 49 | uint64_t getDirSize(); |
| 51 | 50 | |
| 52 | 51 | private: |
| 53 | Chunk *newThunkChunk(DefinedImportData *S, Chunk *Dir); | |
| 52 | Chunk *newThunkChunk(DefinedImportData *s, Chunk *tailMerge); | |
| 53 | Chunk *newTailMergeChunk(Chunk *dir); | |
| 54 | 54 | |
| 55 | Defined *Helper; | |
| 56 | std::vector<DefinedImportData *> Imports; | |
| 57 | std::vector<Chunk *> Dirs; | |
| 58 | std::vector<Chunk *> ModuleHandles; | |
| 59 | std::vector<Chunk *> Addresses; | |
| 60 | std::vector<Chunk *> Names; | |
| 61 | std::vector<Chunk *> HintNames; | |
| 62 | std::vector<Chunk *> Thunks; | |
| 63 | std::vector<Chunk *> DLLNames; | |
| 55 | Defined *helper; | |
| 56 | std::vector<DefinedImportData *> imports; | |
| 57 | std::vector<Chunk *> dirs; | |
| 58 | std::vector<Chunk *> moduleHandles; | |
| 59 | std::vector<Chunk *> addresses; | |
| 60 | std::vector<Chunk *> names; | |
| 61 | std::vector<Chunk *> hintNames; | |
| 62 | std::vector<Chunk *> thunks; | |
| 63 | std::vector<Chunk *> dllNames; | |
| 64 | 64 | }; |
| 65 | 65 | |
| 66 | 66 | // Windows-specific. |
| ... | ... | @@ -68,11 +68,11 @@ private: |
| 68 | 68 | class EdataContents { |
| 69 | 69 | public: |
| 70 | 70 | EdataContents(); |
| 71 | std::vector<Chunk *> Chunks; | |
| 71 | std::vector<Chunk *> chunks; | |
| 72 | 72 | |
| 73 | uint64_t getRVA() { return Chunks[0]->getRVA(); } | |
| 73 | uint64_t getRVA() { return chunks[0]->getRVA(); } | |
| 74 | 74 | uint64_t getSize() { |
| 75 | return Chunks.back()->getRVA() + Chunks.back()->getSize() - getRVA(); | |
| 75 | return chunks.back()->getRVA() + chunks.back()->getSize() - getRVA(); | |
| 76 | 76 | } |
| 77 | 77 | }; |
| 78 | 78 |
deps/lld/COFF/DebugTypes.cpp created+268| ... | ... | @@ -0,0 +1,268 @@ |
| 1 | //===- DebugTypes.cpp -----------------------------------------------------===// | |
| 2 | // | |
| 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 | |
| 6 | // | |
| 7 | //===----------------------------------------------------------------------===// | |
| 8 | ||
| 9 | #include "DebugTypes.h" | |
| 10 | #include "Driver.h" | |
| 11 | #include "InputFiles.h" | |
| 12 | #include "lld/Common/ErrorHandler.h" | |
| 13 | #include "llvm/DebugInfo/CodeView/TypeRecord.h" | |
| 14 | #include "llvm/DebugInfo/PDB/GenericError.h" | |
| 15 | #include "llvm/DebugInfo/PDB/Native/InfoStream.h" | |
| 16 | #include "llvm/DebugInfo/PDB/Native/NativeSession.h" | |
| 17 | #include "llvm/DebugInfo/PDB/Native/PDBFile.h" | |
| 18 | #include "llvm/Support/Path.h" | |
| 19 | ||
| 20 | using namespace lld; | |
| 21 | using namespace lld::coff; | |
| 22 | using namespace llvm; | |
| 23 | using namespace llvm::codeview; | |
| 24 | ||
| 25 | namespace { | |
| 26 | // The TypeServerSource class represents a PDB type server, a file referenced by | |
| 27 | // OBJ files compiled with MSVC /Zi. A single PDB can be shared by several OBJ | |
| 28 | // files, therefore there must be only once instance per OBJ lot. The file path | |
| 29 | // is discovered from the dependent OBJ's debug type stream. The | |
| 30 | // TypeServerSource object is then queued and loaded by the COFF Driver. The | |
| 31 | // debug type stream for such PDB files will be merged first in the final PDB, | |
| 32 | // before any dependent OBJ. | |
| 33 | class TypeServerSource : public TpiSource { | |
| 34 | public: | |
| 35 | explicit TypeServerSource(MemoryBufferRef m, llvm::pdb::NativeSession *s) | |
| 36 | : TpiSource(PDB, nullptr), session(s), mb(m) {} | |
| 37 | ||
| 38 | // Queue a PDB type server for loading in the COFF Driver | |
| 39 | static void enqueue(const ObjFile *dependentFile, | |
| 40 | const TypeServer2Record &ts); | |
| 41 | ||
| 42 | // Create an instance | |
| 43 | static Expected<TypeServerSource *> getInstance(MemoryBufferRef m); | |
| 44 | ||
| 45 | // Fetch the PDB instance loaded for a corresponding dependent OBJ. | |
| 46 | static Expected<TypeServerSource *> | |
| 47 | findFromFile(const ObjFile *dependentFile); | |
| 48 | ||
| 49 | static std::map<std::string, std::pair<std::string, TypeServerSource *>> | |
| 50 | instances; | |
| 51 | ||
| 52 | // The interface to the PDB (if it was opened successfully) | |
| 53 | std::unique_ptr<llvm::pdb::NativeSession> session; | |
| 54 | ||
| 55 | private: | |
| 56 | MemoryBufferRef mb; | |
| 57 | }; | |
| 58 | ||
| 59 | // This class represents the debug type stream of an OBJ file that depends on a | |
| 60 | // PDB type server (see TypeServerSource). | |
| 61 | class UseTypeServerSource : public TpiSource { | |
| 62 | public: | |
| 63 | UseTypeServerSource(const ObjFile *f, const TypeServer2Record *ts) | |
| 64 | : TpiSource(UsingPDB, f), typeServerDependency(*ts) {} | |
| 65 | ||
| 66 | // Information about the PDB type server dependency, that needs to be loaded | |
| 67 | // in before merging this OBJ. | |
| 68 | TypeServer2Record typeServerDependency; | |
| 69 | }; | |
| 70 | ||
| 71 | // This class represents the debug type stream of a Microsoft precompiled | |
| 72 | // headers OBJ (PCH OBJ). This OBJ kind needs to be merged first in the output | |
| 73 | // PDB, before any other OBJs that depend on this. Note that only MSVC generate | |
| 74 | // such files, clang does not. | |
| 75 | class PrecompSource : public TpiSource { | |
| 76 | public: | |
| 77 | PrecompSource(const ObjFile *f) : TpiSource(PCH, f) {} | |
| 78 | }; | |
| 79 | ||
| 80 | // This class represents the debug type stream of an OBJ file that depends on a | |
| 81 | // Microsoft precompiled headers OBJ (see PrecompSource). | |
| 82 | class UsePrecompSource : public TpiSource { | |
| 83 | public: | |
| 84 | UsePrecompSource(const ObjFile *f, const PrecompRecord *precomp) | |
| 85 | : TpiSource(UsingPCH, f), precompDependency(*precomp) {} | |
| 86 | ||
| 87 | // Information about the Precomp OBJ dependency, that needs to be loaded in | |
| 88 | // before merging this OBJ. | |
| 89 | PrecompRecord precompDependency; | |
| 90 | }; | |
| 91 | } // namespace | |
| 92 | ||
| 93 | static std::vector<std::unique_ptr<TpiSource>> GC; | |
| 94 | ||
| 95 | TpiSource::TpiSource(TpiKind k, const ObjFile *f) : kind(k), file(f) { | |
| 96 | GC.push_back(std::unique_ptr<TpiSource>(this)); | |
| 97 | } | |
| 98 | ||
| 99 | TpiSource *lld::coff::makeTpiSource(const ObjFile *f) { | |
| 100 | return new TpiSource(TpiSource::Regular, f); | |
| 101 | } | |
| 102 | ||
| 103 | TpiSource *lld::coff::makeUseTypeServerSource(const ObjFile *f, | |
| 104 | const TypeServer2Record *ts) { | |
| 105 | TypeServerSource::enqueue(f, *ts); | |
| 106 | return new UseTypeServerSource(f, ts); | |
| 107 | } | |
| 108 | ||
| 109 | TpiSource *lld::coff::makePrecompSource(const ObjFile *f) { | |
| 110 | return new PrecompSource(f); | |
| 111 | } | |
| 112 | ||
| 113 | TpiSource *lld::coff::makeUsePrecompSource(const ObjFile *f, | |
| 114 | const PrecompRecord *precomp) { | |
| 115 | return new UsePrecompSource(f, precomp); | |
| 116 | } | |
| 117 | ||
| 118 | namespace lld { | |
| 119 | namespace coff { | |
| 120 | template <> | |
| 121 | const PrecompRecord &retrieveDependencyInfo(const TpiSource *source) { | |
| 122 | assert(source->kind == TpiSource::UsingPCH); | |
| 123 | return ((const UsePrecompSource *)source)->precompDependency; | |
| 124 | } | |
| 125 | ||
| 126 | template <> | |
| 127 | const TypeServer2Record &retrieveDependencyInfo(const TpiSource *source) { | |
| 128 | assert(source->kind == TpiSource::UsingPDB); | |
| 129 | return ((const UseTypeServerSource *)source)->typeServerDependency; | |
| 130 | } | |
| 131 | } // namespace coff | |
| 132 | } // namespace lld | |
| 133 | ||
| 134 | std::map<std::string, std::pair<std::string, TypeServerSource *>> | |
| 135 | TypeServerSource::instances; | |
| 136 | ||
| 137 | // Make a PDB path assuming the PDB is in the same folder as the OBJ | |
| 138 | static std::string getPdbBaseName(const ObjFile *file, StringRef tSPath) { | |
| 139 | StringRef localPath = | |
| 140 | !file->parentName.empty() ? file->parentName : file->getName(); | |
| 141 | SmallString<128> path = sys::path::parent_path(localPath); | |
| 142 | ||
| 143 | // Currently, type server PDBs are only created by MSVC cl, which only runs | |
| 144 | // on Windows, so we can assume type server paths are Windows style. | |
| 145 | sys::path::append(path, sys::path::filename(tSPath, sys::path::Style::windows)); | |
| 146 | return path.str(); | |
| 147 | } | |
| 148 | ||
| 149 | // The casing of the PDB path stamped in the OBJ can differ from the actual path | |
| 150 | // on disk. With this, we ensure to always use lowercase as a key for the | |
| 151 | // PDBInputFile::Instances map, at least on Windows. | |
| 152 | static std::string normalizePdbPath(StringRef path) { | |
| 153 | #if defined(_WIN32) | |
| 154 | return path.lower(); | |
| 155 | #else // LINUX | |
| 156 | return path; | |
| 157 | #endif | |
| 158 | } | |
| 159 | ||
| 160 | // If existing, return the actual PDB path on disk. | |
| 161 | static Optional<std::string> findPdbPath(StringRef pdbPath, | |
| 162 | const ObjFile *dependentFile) { | |
| 163 | // Ensure the file exists before anything else. In some cases, if the path | |
| 164 | // points to a removable device, Driver::enqueuePath() would fail with an | |
| 165 | // error (EAGAIN, "resource unavailable try again") which we want to skip | |
| 166 | // silently. | |
| 167 | if (llvm::sys::fs::exists(pdbPath)) | |
| 168 | return normalizePdbPath(pdbPath); | |
| 169 | std::string ret = getPdbBaseName(dependentFile, pdbPath); | |
| 170 | if (llvm::sys::fs::exists(ret)) | |
| 171 | return normalizePdbPath(ret); | |
| 172 | return None; | |
| 173 | } | |
| 174 | ||
| 175 | // Fetch the PDB instance that was already loaded by the COFF Driver. | |
| 176 | Expected<TypeServerSource *> | |
| 177 | TypeServerSource::findFromFile(const ObjFile *dependentFile) { | |
| 178 | const TypeServer2Record &ts = | |
| 179 | retrieveDependencyInfo<TypeServer2Record>(dependentFile->debugTypesObj); | |
| 180 | ||
| 181 | Optional<std::string> p = findPdbPath(ts.Name, dependentFile); | |
| 182 | if (!p) | |
| 183 | return createFileError(ts.Name, errorCodeToError(std::error_code( | |
| 184 | ENOENT, std::generic_category()))); | |
| 185 | ||
| 186 | auto it = TypeServerSource::instances.find(*p); | |
| 187 | // The PDB file exists on disk, at this point we expect it to have been | |
| 188 | // inserted in the map by TypeServerSource::loadPDB() | |
| 189 | assert(it != TypeServerSource::instances.end()); | |
| 190 | ||
| 191 | std::pair<std::string, TypeServerSource *> &pdb = it->second; | |
| 192 | ||
| 193 | if (!pdb.second) | |
| 194 | return createFileError( | |
| 195 | *p, createStringError(inconvertibleErrorCode(), pdb.first.c_str())); | |
| 196 | ||
| 197 | pdb::PDBFile &pdbFile = (pdb.second)->session->getPDBFile(); | |
| 198 | pdb::InfoStream &info = cantFail(pdbFile.getPDBInfoStream()); | |
| 199 | ||
| 200 | // Just because a file with a matching name was found doesn't mean it can be | |
| 201 | // used. The GUID must match between the PDB header and the OBJ | |
| 202 | // TypeServer2 record. The 'Age' is used by MSVC incremental compilation. | |
| 203 | if (info.getGuid() != ts.getGuid()) | |
| 204 | return createFileError( | |
| 205 | ts.Name, | |
| 206 | make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date)); | |
| 207 | ||
| 208 | return pdb.second; | |
| 209 | } | |
| 210 | ||
| 211 | // FIXME: Temporary interface until PDBLinker::maybeMergeTypeServerPDB() is | |
| 212 | // moved here. | |
| 213 | Expected<llvm::pdb::NativeSession *> | |
| 214 | lld::coff::findTypeServerSource(const ObjFile *f) { | |
| 215 | Expected<TypeServerSource *> ts = TypeServerSource::findFromFile(f); | |
| 216 | if (!ts) | |
| 217 | return ts.takeError(); | |
| 218 | return ts.get()->session.get(); | |
| 219 | } | |
| 220 | ||
| 221 | // Queue a PDB type server for loading in the COFF Driver | |
| 222 | void TypeServerSource::enqueue(const ObjFile *dependentFile, | |
| 223 | const TypeServer2Record &ts) { | |
| 224 | // Start by finding where the PDB is located (either the record path or next | |
| 225 | // to the OBJ file) | |
| 226 | Optional<std::string> p = findPdbPath(ts.Name, dependentFile); | |
| 227 | if (!p) | |
| 228 | return; | |
| 229 | auto it = TypeServerSource::instances.emplace( | |
| 230 | *p, std::pair<std::string, TypeServerSource *>{}); | |
| 231 | if (!it.second) | |
| 232 | return; // another OBJ already scheduled this PDB for load | |
| 233 | ||
| 234 | driver->enqueuePath(*p, false); | |
| 235 | } | |
| 236 | ||
| 237 | // Create an instance of TypeServerSource or an error string if the PDB couldn't | |
| 238 | // be loaded. The error message will be displayed later, when the referring OBJ | |
| 239 | // will be merged in. NOTE - a PDB load failure is not a link error: some | |
| 240 | // debug info will simply be missing from the final PDB - that is the default | |
| 241 | // accepted behavior. | |
| 242 | void lld::coff::loadTypeServerSource(llvm::MemoryBufferRef m) { | |
| 243 | std::string path = normalizePdbPath(m.getBufferIdentifier()); | |
| 244 | ||
| 245 | Expected<TypeServerSource *> ts = TypeServerSource::getInstance(m); | |
| 246 | if (!ts) | |
| 247 | TypeServerSource::instances[path] = {toString(ts.takeError()), nullptr}; | |
| 248 | else | |
| 249 | TypeServerSource::instances[path] = {{}, *ts}; | |
| 250 | } | |
| 251 | ||
| 252 | Expected<TypeServerSource *> TypeServerSource::getInstance(MemoryBufferRef m) { | |
| 253 | std::unique_ptr<llvm::pdb::IPDBSession> iSession; | |
| 254 | Error err = pdb::NativeSession::createFromPdb( | |
| 255 | MemoryBuffer::getMemBuffer(m, false), iSession); | |
| 256 | if (err) | |
| 257 | return std::move(err); | |
| 258 | ||
| 259 | std::unique_ptr<llvm::pdb::NativeSession> session( | |
| 260 | static_cast<pdb::NativeSession *>(iSession.release())); | |
| 261 | ||
| 262 | pdb::PDBFile &pdbFile = session->getPDBFile(); | |
| 263 | Expected<pdb::InfoStream &> info = pdbFile.getPDBInfoStream(); | |
| 264 | // All PDB Files should have an Info stream. | |
| 265 | if (!info) | |
| 266 | return info.takeError(); | |
| 267 | return new TypeServerSource(m, session.release()); | |
| 268 | } |
deps/lld/COFF/DebugTypes.h created+60| ... | ... | @@ -0,0 +1,60 @@ |
| 1 | //===- DebugTypes.h ---------------------------------------------*- C++ -*-===// | |
| 2 | // | |
| 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 | |
| 6 | // | |
| 7 | //===----------------------------------------------------------------------===// | |
| 8 | ||
| 9 | #ifndef LLD_COFF_DEBUGTYPES_H | |
| 10 | #define LLD_COFF_DEBUGTYPES_H | |
| 11 | ||
| 12 | #include "llvm/Support/Error.h" | |
| 13 | #include "llvm/Support/MemoryBuffer.h" | |
| 14 | ||
| 15 | namespace llvm { | |
| 16 | namespace codeview { | |
| 17 | class PrecompRecord; | |
| 18 | class TypeServer2Record; | |
| 19 | } // namespace codeview | |
| 20 | namespace pdb { | |
| 21 | class NativeSession; | |
| 22 | } | |
| 23 | } // namespace llvm | |
| 24 | ||
| 25 | namespace lld { | |
| 26 | namespace coff { | |
| 27 | ||
| 28 | class ObjFile; | |
| 29 | ||
| 30 | class TpiSource { | |
| 31 | public: | |
| 32 | enum TpiKind { Regular, PCH, UsingPCH, PDB, UsingPDB }; | |
| 33 | ||
| 34 | TpiSource(TpiKind k, const ObjFile *f); | |
| 35 | virtual ~TpiSource() {} | |
| 36 | ||
| 37 | const TpiKind kind; | |
| 38 | const ObjFile *file; | |
| 39 | }; | |
| 40 | ||
| 41 | TpiSource *makeTpiSource(const ObjFile *f); | |
| 42 | TpiSource *makeUseTypeServerSource(const ObjFile *f, | |
| 43 | const llvm::codeview::TypeServer2Record *ts); | |
| 44 | TpiSource *makePrecompSource(const ObjFile *f); | |
| 45 | TpiSource *makeUsePrecompSource(const ObjFile *f, | |
| 46 | const llvm::codeview::PrecompRecord *precomp); | |
| 47 | ||
| 48 | void loadTypeServerSource(llvm::MemoryBufferRef m); | |
| 49 | ||
| 50 | // Temporary interface to get the dependency | |
| 51 | template <typename T> const T &retrieveDependencyInfo(const TpiSource *source); | |
| 52 | ||
| 53 | // Temporary interface until we move PDBLinker::maybeMergeTypeServerPDB here | |
| 54 | llvm::Expected<llvm::pdb::NativeSession *> | |
| 55 | findTypeServerSource(const ObjFile *f); | |
| 56 | ||
| 57 | } // namespace coff | |
| 58 | } // namespace lld | |
| 59 | ||
| 60 | #endif | |
| \ No newline at end of file |
deps/lld/COFF/Driver.cpp+1066-856| ... | ... | @@ -1,14 +1,14 @@ |
| 1 | 1 | //===- Driver.cpp ---------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| 10 | 9 | #include "Driver.h" |
| 11 | 10 | #include "Config.h" |
| 11 | #include "DebugTypes.h" | |
| 12 | 12 | #include "ICF.h" |
| 13 | 13 | #include "InputFiles.h" |
| 14 | 14 | #include "MarkLive.h" |
| ... | ... | @@ -19,7 +19,9 @@ |
| 19 | 19 | #include "lld/Common/Args.h" |
| 20 | 20 | #include "lld/Common/Driver.h" |
| 21 | 21 | #include "lld/Common/ErrorHandler.h" |
| 22 | #include "lld/Common/Filesystem.h" | |
| 22 | 23 | #include "lld/Common/Memory.h" |
| 24 | #include "lld/Common/Threads.h" | |
| 23 | 25 | #include "lld/Common/Timer.h" |
| 24 | 26 | #include "lld/Common/Version.h" |
| 25 | 27 | #include "llvm/ADT/Optional.h" |
| ... | ... | @@ -28,6 +30,7 @@ |
| 28 | 30 | #include "llvm/Object/ArchiveWriter.h" |
| 29 | 31 | #include "llvm/Object/COFFImportFile.h" |
| 30 | 32 | #include "llvm/Object/COFFModuleDefinition.h" |
| 33 | #include "llvm/Object/WindowsMachineFlag.h" | |
| 31 | 34 | #include "llvm/Option/Arg.h" |
| 32 | 35 | #include "llvm/Option/ArgList.h" |
| 33 | 36 | #include "llvm/Option/Option.h" |
| ... | ... | @@ -51,43 +54,68 @@ using llvm::sys::Process; |
| 51 | 54 | namespace lld { |
| 52 | 55 | namespace coff { |
| 53 | 56 | |
| 54 | static Timer InputFileTimer("Input File Reading", Timer::root()); | |
| 57 | static Timer inputFileTimer("Input File Reading", Timer::root()); | |
| 55 | 58 | |
| 56 | Configuration *Config; | |
| 57 | LinkerDriver *Driver; | |
| 59 | Configuration *config; | |
| 60 | LinkerDriver *driver; | |
| 58 | 61 | |
| 59 | bool link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Diag) { | |
| 60 | errorHandler().LogName = args::getFilenameWithoutExe(Args[0]); | |
| 61 | errorHandler().ErrorOS = &Diag; | |
| 62 | errorHandler().ColorDiagnostics = Diag.has_colors(); | |
| 63 | errorHandler().ErrorLimitExceededMsg = | |
| 62 | bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &diag) { | |
| 63 | errorHandler().logName = args::getFilenameWithoutExe(args[0]); | |
| 64 | errorHandler().errorOS = &diag; | |
| 65 | errorHandler().colorDiagnostics = diag.has_colors(); | |
| 66 | errorHandler().errorLimitExceededMsg = | |
| 64 | 67 | "too many errors emitted, stopping now" |
| 65 | 68 | " (use /errorlimit:0 to see all errors)"; |
| 66 | errorHandler().ExitEarly = CanExitEarly; | |
| 67 | Config = make<Configuration>(); | |
| 69 | errorHandler().exitEarly = canExitEarly; | |
| 70 | config = make<Configuration>(); | |
| 68 | 71 | |
| 69 | Symtab = make<SymbolTable>(); | |
| 72 | symtab = make<SymbolTable>(); | |
| 70 | 73 | |
| 71 | Driver = make<LinkerDriver>(); | |
| 72 | Driver->link(Args); | |
| 74 | driver = make<LinkerDriver>(); | |
| 75 | driver->link(args); | |
| 73 | 76 | |
| 74 | 77 | // Call exit() if we can to avoid calling destructors. |
| 75 | if (CanExitEarly) | |
| 78 | if (canExitEarly) | |
| 76 | 79 | exitLld(errorCount() ? 1 : 0); |
| 77 | 80 | |
| 78 | 81 | freeArena(); |
| 79 | ObjFile::Instances.clear(); | |
| 80 | ImportFile::Instances.clear(); | |
| 81 | BitcodeFile::Instances.clear(); | |
| 82 | ObjFile::instances.clear(); | |
| 83 | ImportFile::instances.clear(); | |
| 84 | BitcodeFile::instances.clear(); | |
| 85 | memset(MergeChunk::instances, 0, sizeof(MergeChunk::instances)); | |
| 82 | 86 | return !errorCount(); |
| 83 | 87 | } |
| 84 | 88 | |
| 89 | // Parse options of the form "old;new". | |
| 90 | static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &args, | |
| 91 | unsigned id) { | |
| 92 | auto *arg = args.getLastArg(id); | |
| 93 | if (!arg) | |
| 94 | return {"", ""}; | |
| 95 | ||
| 96 | StringRef s = arg->getValue(); | |
| 97 | std::pair<StringRef, StringRef> ret = s.split(';'); | |
| 98 | if (ret.second.empty()) | |
| 99 | error(arg->getSpelling() + " expects 'old;new' format, but got " + s); | |
| 100 | return ret; | |
| 101 | } | |
| 102 | ||
| 85 | 103 | // Drop directory components and replace extension with ".exe" or ".dll". |
| 86 | static std::string getOutputPath(StringRef Path) { | |
| 87 | auto P = Path.find_last_of("\\/"); | |
| 88 | StringRef S = (P == StringRef::npos) ? Path : Path.substr(P + 1); | |
| 89 | const char* E = Config->DLL ? ".dll" : ".exe"; | |
| 90 | return (S.substr(0, S.rfind('.')) + E).str(); | |
| 104 | static std::string getOutputPath(StringRef path) { | |
| 105 | auto p = path.find_last_of("\\/"); | |
| 106 | StringRef s = (p == StringRef::npos) ? path : path.substr(p + 1); | |
| 107 | const char* e = config->dll ? ".dll" : ".exe"; | |
| 108 | return (s.substr(0, s.rfind('.')) + e).str(); | |
| 109 | } | |
| 110 | ||
| 111 | // Returns true if S matches /crtend.?\.o$/. | |
| 112 | static bool isCrtend(StringRef s) { | |
| 113 | if (!s.endswith(".o")) | |
| 114 | return false; | |
| 115 | s = s.drop_back(2); | |
| 116 | if (s.endswith("crtend")) | |
| 117 | return true; | |
| 118 | return !s.empty() && s.drop_back().endswith("crtend"); | |
| 91 | 119 | } |
| 92 | 120 | |
| 93 | 121 | // ErrorOr is not default constructible, so it cannot be used as the type |
| ... | ... | @@ -95,347 +123,401 @@ static std::string getOutputPath(StringRef Path) { |
| 95 | 123 | // FIXME: We could open the file in createFutureForFile and avoid needing to |
| 96 | 124 | // return an error here, but for the moment that would cost us a file descriptor |
| 97 | 125 | // (a limited resource on Windows) for the duration that the future is pending. |
| 98 | typedef std::pair<std::unique_ptr<MemoryBuffer>, std::error_code> MBErrPair; | |
| 126 | using MBErrPair = std::pair<std::unique_ptr<MemoryBuffer>, std::error_code>; | |
| 99 | 127 | |
| 100 | 128 | // Create a std::future that opens and maps a file using the best strategy for |
| 101 | 129 | // the host platform. |
| 102 | static std::future<MBErrPair> createFutureForFile(std::string Path) { | |
| 130 | static std::future<MBErrPair> createFutureForFile(std::string path) { | |
| 103 | 131 | #if _WIN32 |
| 104 | 132 | // On Windows, file I/O is relatively slow so it is best to do this |
| 105 | 133 | // asynchronously. |
| 106 | auto Strategy = std::launch::async; | |
| 134 | auto strategy = std::launch::async; | |
| 107 | 135 | #else |
| 108 | auto Strategy = std::launch::deferred; | |
| 136 | auto strategy = std::launch::deferred; | |
| 109 | 137 | #endif |
| 110 | return std::async(Strategy, [=]() { | |
| 111 | auto MBOrErr = MemoryBuffer::getFile(Path, | |
| 138 | return std::async(strategy, [=]() { | |
| 139 | auto mbOrErr = MemoryBuffer::getFile(path, | |
| 112 | 140 | /*FileSize*/ -1, |
| 113 | 141 | /*RequiresNullTerminator*/ false); |
| 114 | if (!MBOrErr) | |
| 115 | return MBErrPair{nullptr, MBOrErr.getError()}; | |
| 116 | return MBErrPair{std::move(*MBOrErr), std::error_code()}; | |
| 142 | if (!mbOrErr) | |
| 143 | return MBErrPair{nullptr, mbOrErr.getError()}; | |
| 144 | return MBErrPair{std::move(*mbOrErr), std::error_code()}; | |
| 117 | 145 | }); |
| 118 | 146 | } |
| 119 | 147 | |
| 120 | 148 | // Symbol names are mangled by prepending "_" on x86. |
| 121 | static StringRef mangle(StringRef Sym) { | |
| 122 | assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN); | |
| 123 | if (Config->Machine == I386) | |
| 124 | return Saver.save("_" + Sym); | |
| 125 | return Sym; | |
| 149 | static StringRef mangle(StringRef sym) { | |
| 150 | assert(config->machine != IMAGE_FILE_MACHINE_UNKNOWN); | |
| 151 | if (config->machine == I386) | |
| 152 | return saver.save("_" + sym); | |
| 153 | return sym; | |
| 126 | 154 | } |
| 127 | 155 | |
| 128 | static bool findUnderscoreMangle(StringRef Sym) { | |
| 129 | StringRef Entry = Symtab->findMangle(mangle(Sym)); | |
| 130 | return !Entry.empty() && !isa<Undefined>(Symtab->find(Entry)); | |
| 156 | static bool findUnderscoreMangle(StringRef sym) { | |
| 157 | Symbol *s = symtab->findMangle(mangle(sym)); | |
| 158 | return s && !isa<Undefined>(s); | |
| 131 | 159 | } |
| 132 | 160 | |
| 133 | MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> MB) { | |
| 134 | MemoryBufferRef MBRef = *MB; | |
| 135 | make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take ownership | |
| 161 | MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> mb) { | |
| 162 | MemoryBufferRef mbref = *mb; | |
| 163 | make<std::unique_ptr<MemoryBuffer>>(std::move(mb)); // take ownership | |
| 136 | 164 | |
| 137 | if (Driver->Tar) | |
| 138 | Driver->Tar->append(relativeToRoot(MBRef.getBufferIdentifier()), | |
| 139 | MBRef.getBuffer()); | |
| 140 | return MBRef; | |
| 165 | if (driver->tar) | |
| 166 | driver->tar->append(relativeToRoot(mbref.getBufferIdentifier()), | |
| 167 | mbref.getBuffer()); | |
| 168 | return mbref; | |
| 141 | 169 | } |
| 142 | 170 | |
| 143 | void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> MB, | |
| 144 | bool WholeArchive) { | |
| 145 | StringRef Filename = MB->getBufferIdentifier(); | |
| 171 | void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb, | |
| 172 | bool wholeArchive) { | |
| 173 | StringRef filename = mb->getBufferIdentifier(); | |
| 146 | 174 | |
| 147 | MemoryBufferRef MBRef = takeBuffer(std::move(MB)); | |
| 148 | FilePaths.push_back(Filename); | |
| 175 | MemoryBufferRef mbref = takeBuffer(std::move(mb)); | |
| 176 | filePaths.push_back(filename); | |
| 149 | 177 | |
| 150 | 178 | // File type is detected by contents, not by file extension. |
| 151 | switch (identify_magic(MBRef.getBuffer())) { | |
| 179 | switch (identify_magic(mbref.getBuffer())) { | |
| 152 | 180 | case file_magic::windows_resource: |
| 153 | Resources.push_back(MBRef); | |
| 181 | resources.push_back(mbref); | |
| 154 | 182 | break; |
| 155 | 183 | case file_magic::archive: |
| 156 | if (WholeArchive) { | |
| 157 | std::unique_ptr<Archive> File = | |
| 158 | CHECK(Archive::create(MBRef), Filename + ": failed to parse archive"); | |
| 184 | if (wholeArchive) { | |
| 185 | std::unique_ptr<Archive> file = | |
| 186 | CHECK(Archive::create(mbref), filename + ": failed to parse archive"); | |
| 159 | 187 | |
| 160 | for (MemoryBufferRef M : getArchiveMembers(File.get())) | |
| 161 | addArchiveBuffer(M, "<whole-archive>", Filename); | |
| 188 | for (MemoryBufferRef m : getArchiveMembers(file.get())) | |
| 189 | addArchiveBuffer(m, "<whole-archive>", filename, 0); | |
| 162 | 190 | return; |
| 163 | 191 | } |
| 164 | Symtab->addFile(make<ArchiveFile>(MBRef)); | |
| 192 | symtab->addFile(make<ArchiveFile>(mbref)); | |
| 165 | 193 | break; |
| 166 | 194 | case file_magic::bitcode: |
| 167 | Symtab->addFile(make<BitcodeFile>(MBRef)); | |
| 195 | symtab->addFile(make<BitcodeFile>(mbref, "", 0)); | |
| 168 | 196 | break; |
| 169 | 197 | case file_magic::coff_object: |
| 170 | 198 | case file_magic::coff_import_library: |
| 171 | Symtab->addFile(make<ObjFile>(MBRef)); | |
| 199 | symtab->addFile(make<ObjFile>(mbref)); | |
| 200 | break; | |
| 201 | case file_magic::pdb: | |
| 202 | loadTypeServerSource(mbref); | |
| 172 | 203 | break; |
| 173 | 204 | case file_magic::coff_cl_gl_object: |
| 174 | error(Filename + ": is not a native COFF file. Recompile without /GL"); | |
| 205 | error(filename + ": is not a native COFF file. Recompile without /GL"); | |
| 175 | 206 | break; |
| 176 | 207 | case file_magic::pecoff_executable: |
| 177 | if (Filename.endswith_lower(".dll")) { | |
| 178 | error(Filename + ": bad file type. Did you specify a DLL instead of an " | |
| 208 | if (filename.endswith_lower(".dll")) { | |
| 209 | error(filename + ": bad file type. Did you specify a DLL instead of an " | |
| 179 | 210 | "import library?"); |
| 180 | 211 | break; |
| 181 | 212 | } |
| 182 | 213 | LLVM_FALLTHROUGH; |
| 183 | 214 | default: |
| 184 | error(MBRef.getBufferIdentifier() + ": unknown file type"); | |
| 215 | error(mbref.getBufferIdentifier() + ": unknown file type"); | |
| 185 | 216 | break; |
| 186 | 217 | } |
| 187 | 218 | } |
| 188 | 219 | |
| 189 | void LinkerDriver::enqueuePath(StringRef Path, bool WholeArchive) { | |
| 190 | auto Future = | |
| 191 | std::make_shared<std::future<MBErrPair>>(createFutureForFile(Path)); | |
| 192 | std::string PathStr = Path; | |
| 220 | void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive) { | |
| 221 | auto future = | |
| 222 | std::make_shared<std::future<MBErrPair>>(createFutureForFile(path)); | |
| 223 | std::string pathStr = path; | |
| 193 | 224 | enqueueTask([=]() { |
| 194 | auto MBOrErr = Future->get(); | |
| 195 | if (MBOrErr.second) | |
| 196 | error("could not open " + PathStr + ": " + MBOrErr.second.message()); | |
| 197 | else | |
| 198 | Driver->addBuffer(std::move(MBOrErr.first), WholeArchive); | |
| 225 | auto mbOrErr = future->get(); | |
| 226 | if (mbOrErr.second) { | |
| 227 | std::string msg = | |
| 228 | "could not open '" + pathStr + "': " + mbOrErr.second.message(); | |
| 229 | // Check if the filename is a typo for an option flag. OptTable thinks | |
| 230 | // that all args that are not known options and that start with / are | |
| 231 | // filenames, but e.g. `/nodefaultlibs` is more likely a typo for | |
| 232 | // the option `/nodefaultlib` than a reference to a file in the root | |
| 233 | // directory. | |
| 234 | std::string nearest; | |
| 235 | if (COFFOptTable().findNearest(pathStr, nearest) > 1) | |
| 236 | error(msg); | |
| 237 | else | |
| 238 | error(msg + "; did you mean '" + nearest + "'"); | |
| 239 | } else | |
| 240 | driver->addBuffer(std::move(mbOrErr.first), wholeArchive); | |
| 199 | 241 | }); |
| 200 | 242 | } |
| 201 | 243 | |
| 202 | void LinkerDriver::addArchiveBuffer(MemoryBufferRef MB, StringRef SymName, | |
| 203 | StringRef ParentName) { | |
| 204 | file_magic Magic = identify_magic(MB.getBuffer()); | |
| 205 | if (Magic == file_magic::coff_import_library) { | |
| 206 | Symtab->addFile(make<ImportFile>(MB)); | |
| 244 | void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName, | |
| 245 | StringRef parentName, | |
| 246 | uint64_t offsetInArchive) { | |
| 247 | file_magic magic = identify_magic(mb.getBuffer()); | |
| 248 | if (magic == file_magic::coff_import_library) { | |
| 249 | InputFile *imp = make<ImportFile>(mb); | |
| 250 | imp->parentName = parentName; | |
| 251 | symtab->addFile(imp); | |
| 207 | 252 | return; |
| 208 | 253 | } |
| 209 | 254 | |
| 210 | InputFile *Obj; | |
| 211 | if (Magic == file_magic::coff_object) { | |
| 212 | Obj = make<ObjFile>(MB); | |
| 213 | } else if (Magic == file_magic::bitcode) { | |
| 214 | Obj = make<BitcodeFile>(MB); | |
| 255 | InputFile *obj; | |
| 256 | if (magic == file_magic::coff_object) { | |
| 257 | obj = make<ObjFile>(mb); | |
| 258 | } else if (magic == file_magic::bitcode) { | |
| 259 | obj = make<BitcodeFile>(mb, parentName, offsetInArchive); | |
| 215 | 260 | } else { |
| 216 | error("unknown file type: " + MB.getBufferIdentifier()); | |
| 261 | error("unknown file type: " + mb.getBufferIdentifier()); | |
| 217 | 262 | return; |
| 218 | 263 | } |
| 219 | 264 | |
| 220 | Obj->ParentName = ParentName; | |
| 221 | Symtab->addFile(Obj); | |
| 222 | log("Loaded " + toString(Obj) + " for " + SymName); | |
| 265 | obj->parentName = parentName; | |
| 266 | symtab->addFile(obj); | |
| 267 | log("Loaded " + toString(obj) + " for " + symName); | |
| 223 | 268 | } |
| 224 | 269 | |
| 225 | void LinkerDriver::enqueueArchiveMember(const Archive::Child &C, | |
| 226 | StringRef SymName, | |
| 227 | StringRef ParentName) { | |
| 228 | if (!C.getParent()->isThin()) { | |
| 229 | MemoryBufferRef MB = CHECK( | |
| 230 | C.getMemoryBufferRef(), | |
| 231 | "could not get the buffer for the member defining symbol " + SymName); | |
| 232 | enqueueTask([=]() { Driver->addArchiveBuffer(MB, SymName, ParentName); }); | |
| 270 | void LinkerDriver::enqueueArchiveMember(const Archive::Child &c, | |
| 271 | StringRef symName, | |
| 272 | StringRef parentName) { | |
| 273 | ||
| 274 | auto reportBufferError = [=](Error &&e, | |
| 275 | StringRef childName) { | |
| 276 | fatal("could not get the buffer for the member defining symbol " + | |
| 277 | symName + ": " + parentName + "(" + childName + "): " + | |
| 278 | toString(std::move(e))); | |
| 279 | }; | |
| 280 | ||
| 281 | if (!c.getParent()->isThin()) { | |
| 282 | uint64_t offsetInArchive = c.getChildOffset(); | |
| 283 | Expected<MemoryBufferRef> mbOrErr = c.getMemoryBufferRef(); | |
| 284 | if (!mbOrErr) | |
| 285 | reportBufferError(mbOrErr.takeError(), check(c.getFullName())); | |
| 286 | MemoryBufferRef mb = mbOrErr.get(); | |
| 287 | enqueueTask([=]() { | |
| 288 | driver->addArchiveBuffer(mb, symName, parentName, offsetInArchive); | |
| 289 | }); | |
| 233 | 290 | return; |
| 234 | 291 | } |
| 235 | 292 | |
| 236 | auto Future = std::make_shared<std::future<MBErrPair>>(createFutureForFile( | |
| 237 | CHECK(C.getFullName(), | |
| 238 | "could not get the filename for the member defining symbol " + | |
| 239 | SymName))); | |
| 293 | std::string childName = CHECK( | |
| 294 | c.getFullName(), | |
| 295 | "could not get the filename for the member defining symbol " + | |
| 296 | symName); | |
| 297 | auto future = std::make_shared<std::future<MBErrPair>>( | |
| 298 | createFutureForFile(childName)); | |
| 240 | 299 | enqueueTask([=]() { |
| 241 | auto MBOrErr = Future->get(); | |
| 242 | if (MBOrErr.second) | |
| 243 | fatal("could not get the buffer for the member defining " + SymName + | |
| 244 | ": " + MBOrErr.second.message()); | |
| 245 | Driver->addArchiveBuffer(takeBuffer(std::move(MBOrErr.first)), SymName, | |
| 246 | ParentName); | |
| 300 | auto mbOrErr = future->get(); | |
| 301 | if (mbOrErr.second) | |
| 302 | reportBufferError(errorCodeToError(mbOrErr.second), childName); | |
| 303 | driver->addArchiveBuffer(takeBuffer(std::move(mbOrErr.first)), symName, | |
| 304 | parentName, /* OffsetInArchive */ 0); | |
| 247 | 305 | }); |
| 248 | 306 | } |
| 249 | 307 | |
| 250 | static bool isDecorated(StringRef Sym) { | |
| 251 | return Sym.startswith("@") || Sym.contains("@@") || Sym.startswith("?") || | |
| 252 | (!Config->MinGW && Sym.contains('@')); | |
| 308 | static bool isDecorated(StringRef sym) { | |
| 309 | return sym.startswith("@") || sym.contains("@@") || sym.startswith("?") || | |
| 310 | (!config->mingw && sym.contains('@')); | |
| 253 | 311 | } |
| 254 | 312 | |
| 255 | 313 | // Parses .drectve section contents and returns a list of files |
| 256 | 314 | // specified by /defaultlib. |
| 257 | void LinkerDriver::parseDirectives(StringRef S) { | |
| 258 | ArgParser Parser; | |
| 315 | void LinkerDriver::parseDirectives(InputFile *file) { | |
| 316 | StringRef s = file->getDirectives(); | |
| 317 | if (s.empty()) | |
| 318 | return; | |
| 319 | ||
| 320 | log("Directives: " + toString(file) + ": " + s); | |
| 321 | ||
| 322 | ArgParser parser; | |
| 259 | 323 | // .drectve is always tokenized using Windows shell rules. |
| 260 | 324 | // /EXPORT: option can appear too many times, processing in fastpath. |
| 261 | opt::InputArgList Args; | |
| 262 | std::vector<StringRef> Exports; | |
| 263 | std::tie(Args, Exports) = Parser.parseDirectives(S); | |
| 325 | opt::InputArgList args; | |
| 326 | std::vector<StringRef> exports; | |
| 327 | std::tie(args, exports) = parser.parseDirectives(s); | |
| 264 | 328 | |
| 265 | for (StringRef E : Exports) { | |
| 329 | for (StringRef e : exports) { | |
| 266 | 330 | // If a common header file contains dllexported function |
| 267 | 331 | // declarations, many object files may end up with having the |
| 268 | 332 | // same /EXPORT options. In order to save cost of parsing them, |
| 269 | 333 | // we dedup them first. |
| 270 | if (!DirectivesExports.insert(E).second) | |
| 334 | if (!directivesExports.insert(e).second) | |
| 271 | 335 | continue; |
| 272 | 336 | |
| 273 | Export Exp = parseExport(E); | |
| 274 | if (Config->Machine == I386 && Config->MinGW) { | |
| 275 | if (!isDecorated(Exp.Name)) | |
| 276 | Exp.Name = Saver.save("_" + Exp.Name); | |
| 277 | if (!Exp.ExtName.empty() && !isDecorated(Exp.ExtName)) | |
| 278 | Exp.ExtName = Saver.save("_" + Exp.ExtName); | |
| 337 | Export exp = parseExport(e); | |
| 338 | if (config->machine == I386 && config->mingw) { | |
| 339 | if (!isDecorated(exp.name)) | |
| 340 | exp.name = saver.save("_" + exp.name); | |
| 341 | if (!exp.extName.empty() && !isDecorated(exp.extName)) | |
| 342 | exp.extName = saver.save("_" + exp.extName); | |
| 279 | 343 | } |
| 280 | Exp.Directives = true; | |
| 281 | Config->Exports.push_back(Exp); | |
| 344 | exp.directives = true; | |
| 345 | config->exports.push_back(exp); | |
| 282 | 346 | } |
| 283 | 347 | |
| 284 | for (auto *Arg : Args) { | |
| 285 | switch (Arg->getOption().getUnaliasedOption().getID()) { | |
| 348 | for (auto *arg : args) { | |
| 349 | switch (arg->getOption().getID()) { | |
| 286 | 350 | case OPT_aligncomm: |
| 287 | parseAligncomm(Arg->getValue()); | |
| 351 | parseAligncomm(arg->getValue()); | |
| 288 | 352 | break; |
| 289 | 353 | case OPT_alternatename: |
| 290 | parseAlternateName(Arg->getValue()); | |
| 354 | parseAlternateName(arg->getValue()); | |
| 291 | 355 | break; |
| 292 | 356 | case OPT_defaultlib: |
| 293 | if (Optional<StringRef> Path = findLib(Arg->getValue())) | |
| 294 | enqueuePath(*Path, false); | |
| 357 | if (Optional<StringRef> path = findLib(arg->getValue())) | |
| 358 | enqueuePath(*path, false); | |
| 295 | 359 | break; |
| 296 | 360 | case OPT_entry: |
| 297 | Config->Entry = addUndefined(mangle(Arg->getValue())); | |
| 361 | config->entry = addUndefined(mangle(arg->getValue())); | |
| 298 | 362 | break; |
| 299 | 363 | case OPT_failifmismatch: |
| 300 | checkFailIfMismatch(Arg->getValue()); | |
| 364 | checkFailIfMismatch(arg->getValue(), file); | |
| 301 | 365 | break; |
| 302 | 366 | case OPT_incl: |
| 303 | addUndefined(Arg->getValue()); | |
| 367 | addUndefined(arg->getValue()); | |
| 304 | 368 | break; |
| 305 | 369 | case OPT_merge: |
| 306 | parseMerge(Arg->getValue()); | |
| 370 | parseMerge(arg->getValue()); | |
| 307 | 371 | break; |
| 308 | 372 | case OPT_nodefaultlib: |
| 309 | Config->NoDefaultLibs.insert(doFindLib(Arg->getValue())); | |
| 373 | config->noDefaultLibs.insert(doFindLib(arg->getValue()).lower()); | |
| 310 | 374 | break; |
| 311 | 375 | case OPT_section: |
| 312 | parseSection(Arg->getValue()); | |
| 376 | parseSection(arg->getValue()); | |
| 313 | 377 | break; |
| 314 | 378 | case OPT_subsystem: |
| 315 | parseSubsystem(Arg->getValue(), &Config->Subsystem, | |
| 316 | &Config->MajorOSVersion, &Config->MinorOSVersion); | |
| 379 | parseSubsystem(arg->getValue(), &config->subsystem, | |
| 380 | &config->majorOSVersion, &config->minorOSVersion); | |
| 317 | 381 | break; |
| 382 | // Only add flags here that link.exe accepts in | |
| 383 | // `#pragma comment(linker, "/flag")`-generated sections. | |
| 318 | 384 | case OPT_editandcontinue: |
| 319 | case OPT_fastfail: | |
| 320 | 385 | case OPT_guardsym: |
| 321 | case OPT_natvis: | |
| 322 | 386 | case OPT_throwingnew: |
| 323 | 387 | break; |
| 324 | 388 | default: |
| 325 | error(Arg->getSpelling() + " is not allowed in .drectve"); | |
| 389 | error(arg->getSpelling() + " is not allowed in .drectve"); | |
| 326 | 390 | } |
| 327 | 391 | } |
| 328 | 392 | } |
| 329 | 393 | |
| 330 | 394 | // Find file from search paths. You can omit ".obj", this function takes |
| 331 | 395 | // care of that. Note that the returned path is not guaranteed to exist. |
| 332 | StringRef LinkerDriver::doFindFile(StringRef Filename) { | |
| 333 | bool HasPathSep = (Filename.find_first_of("/\\") != StringRef::npos); | |
| 334 | if (HasPathSep) | |
| 335 | return Filename; | |
| 336 | bool HasExt = Filename.contains('.'); | |
| 337 | for (StringRef Dir : SearchPaths) { | |
| 338 | SmallString<128> Path = Dir; | |
| 339 | sys::path::append(Path, Filename); | |
| 340 | if (sys::fs::exists(Path.str())) | |
| 341 | return Saver.save(Path.str()); | |
| 342 | if (!HasExt) { | |
| 343 | Path.append(".obj"); | |
| 344 | if (sys::fs::exists(Path.str())) | |
| 345 | return Saver.save(Path.str()); | |
| 396 | StringRef LinkerDriver::doFindFile(StringRef filename) { | |
| 397 | bool hasPathSep = (filename.find_first_of("/\\") != StringRef::npos); | |
| 398 | if (hasPathSep) | |
| 399 | return filename; | |
| 400 | bool hasExt = filename.contains('.'); | |
| 401 | for (StringRef dir : searchPaths) { | |
| 402 | SmallString<128> path = dir; | |
| 403 | sys::path::append(path, filename); | |
| 404 | if (sys::fs::exists(path.str())) | |
| 405 | return saver.save(path.str()); | |
| 406 | if (!hasExt) { | |
| 407 | path.append(".obj"); | |
| 408 | if (sys::fs::exists(path.str())) | |
| 409 | return saver.save(path.str()); | |
| 346 | 410 | } |
| 347 | 411 | } |
| 348 | return Filename; | |
| 412 | return filename; | |
| 349 | 413 | } |
| 350 | 414 | |
| 351 | static Optional<sys::fs::UniqueID> getUniqueID(StringRef Path) { | |
| 352 | sys::fs::UniqueID Ret; | |
| 353 | if (sys::fs::getUniqueID(Path, Ret)) | |
| 415 | static Optional<sys::fs::UniqueID> getUniqueID(StringRef path) { | |
| 416 | sys::fs::UniqueID ret; | |
| 417 | if (sys::fs::getUniqueID(path, ret)) | |
| 354 | 418 | return None; |
| 355 | return Ret; | |
| 419 | return ret; | |
| 356 | 420 | } |
| 357 | 421 | |
| 358 | 422 | // Resolves a file path. This never returns the same path |
| 359 | 423 | // (in that case, it returns None). |
| 360 | Optional<StringRef> LinkerDriver::findFile(StringRef Filename) { | |
| 361 | StringRef Path = doFindFile(Filename); | |
| 424 | Optional<StringRef> LinkerDriver::findFile(StringRef filename) { | |
| 425 | StringRef path = doFindFile(filename); | |
| 362 | 426 | |
| 363 | if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path)) { | |
| 364 | bool Seen = !VisitedFiles.insert(*ID).second; | |
| 365 | if (Seen) | |
| 427 | if (Optional<sys::fs::UniqueID> id = getUniqueID(path)) { | |
| 428 | bool seen = !visitedFiles.insert(*id).second; | |
| 429 | if (seen) | |
| 366 | 430 | return None; |
| 367 | 431 | } |
| 368 | 432 | |
| 369 | if (Path.endswith_lower(".lib")) | |
| 370 | VisitedLibs.insert(sys::path::filename(Path)); | |
| 371 | return Path; | |
| 433 | if (path.endswith_lower(".lib")) | |
| 434 | visitedLibs.insert(sys::path::filename(path)); | |
| 435 | return path; | |
| 372 | 436 | } |
| 373 | 437 | |
| 374 | 438 | // MinGW specific. If an embedded directive specified to link to |
| 375 | 439 | // foo.lib, but it isn't found, try libfoo.a instead. |
| 376 | StringRef LinkerDriver::doFindLibMinGW(StringRef Filename) { | |
| 377 | if (Filename.contains('/') || Filename.contains('\\')) | |
| 378 | return Filename; | |
| 379 | ||
| 380 | SmallString<128> S = Filename; | |
| 381 | sys::path::replace_extension(S, ".a"); | |
| 382 | StringRef LibName = Saver.save("lib" + S.str()); | |
| 383 | return doFindFile(LibName); | |
| 440 | StringRef LinkerDriver::doFindLibMinGW(StringRef filename) { | |
| 441 | if (filename.contains('/') || filename.contains('\\')) | |
| 442 | return filename; | |
| 443 | ||
| 444 | SmallString<128> s = filename; | |
| 445 | sys::path::replace_extension(s, ".a"); | |
| 446 | StringRef libName = saver.save("lib" + s.str()); | |
| 447 | return doFindFile(libName); | |
| 384 | 448 | } |
| 385 | 449 | |
| 386 | 450 | // Find library file from search path. |
| 387 | StringRef LinkerDriver::doFindLib(StringRef Filename) { | |
| 451 | StringRef LinkerDriver::doFindLib(StringRef filename) { | |
| 388 | 452 | // Add ".lib" to Filename if that has no file extension. |
| 389 | bool HasExt = Filename.contains('.'); | |
| 390 | if (!HasExt) | |
| 391 | Filename = Saver.save(Filename + ".lib"); | |
| 392 | StringRef Ret = doFindFile(Filename); | |
| 453 | bool hasExt = filename.contains('.'); | |
| 454 | if (!hasExt) | |
| 455 | filename = saver.save(filename + ".lib"); | |
| 456 | StringRef ret = doFindFile(filename); | |
| 393 | 457 | // For MinGW, if the find above didn't turn up anything, try |
| 394 | 458 | // looking for a MinGW formatted library name. |
| 395 | if (Config->MinGW && Ret == Filename) | |
| 396 | return doFindLibMinGW(Filename); | |
| 397 | return Ret; | |
| 459 | if (config->mingw && ret == filename) | |
| 460 | return doFindLibMinGW(filename); | |
| 461 | return ret; | |
| 398 | 462 | } |
| 399 | 463 | |
| 400 | 464 | // Resolves a library path. /nodefaultlib options are taken into |
| 401 | 465 | // consideration. This never returns the same path (in that case, |
| 402 | 466 | // it returns None). |
| 403 | Optional<StringRef> LinkerDriver::findLib(StringRef Filename) { | |
| 404 | if (Config->NoDefaultLibAll) | |
| 467 | Optional<StringRef> LinkerDriver::findLib(StringRef filename) { | |
| 468 | if (config->noDefaultLibAll) | |
| 405 | 469 | return None; |
| 406 | if (!VisitedLibs.insert(Filename.lower()).second) | |
| 470 | if (!visitedLibs.insert(filename.lower()).second) | |
| 407 | 471 | return None; |
| 408 | 472 | |
| 409 | StringRef Path = doFindLib(Filename); | |
| 410 | if (Config->NoDefaultLibs.count(Path)) | |
| 473 | StringRef path = doFindLib(filename); | |
| 474 | if (config->noDefaultLibs.count(path.lower())) | |
| 411 | 475 | return None; |
| 412 | 476 | |
| 413 | if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path)) | |
| 414 | if (!VisitedFiles.insert(*ID).second) | |
| 477 | if (Optional<sys::fs::UniqueID> id = getUniqueID(path)) | |
| 478 | if (!visitedFiles.insert(*id).second) | |
| 415 | 479 | return None; |
| 416 | return Path; | |
| 480 | return path; | |
| 417 | 481 | } |
| 418 | 482 | |
| 419 | 483 | // Parses LIB environment which contains a list of search paths. |
| 420 | 484 | void LinkerDriver::addLibSearchPaths() { |
| 421 | Optional<std::string> EnvOpt = Process::GetEnv("LIB"); | |
| 422 | if (!EnvOpt.hasValue()) | |
| 485 | Optional<std::string> envOpt = Process::GetEnv("LIB"); | |
| 486 | if (!envOpt.hasValue()) | |
| 423 | 487 | return; |
| 424 | StringRef Env = Saver.save(*EnvOpt); | |
| 425 | while (!Env.empty()) { | |
| 426 | StringRef Path; | |
| 427 | std::tie(Path, Env) = Env.split(';'); | |
| 428 | SearchPaths.push_back(Path); | |
| 488 | StringRef env = saver.save(*envOpt); | |
| 489 | while (!env.empty()) { | |
| 490 | StringRef path; | |
| 491 | std::tie(path, env) = env.split(';'); | |
| 492 | searchPaths.push_back(path); | |
| 429 | 493 | } |
| 430 | 494 | } |
| 431 | 495 | |
| 432 | Symbol *LinkerDriver::addUndefined(StringRef Name) { | |
| 433 | Symbol *B = Symtab->addUndefined(Name); | |
| 434 | if (!B->IsGCRoot) { | |
| 435 | B->IsGCRoot = true; | |
| 436 | Config->GCRoot.push_back(B); | |
| 496 | Symbol *LinkerDriver::addUndefined(StringRef name) { | |
| 497 | Symbol *b = symtab->addUndefined(name); | |
| 498 | if (!b->isGCRoot) { | |
| 499 | b->isGCRoot = true; | |
| 500 | config->gcroot.push_back(b); | |
| 437 | 501 | } |
| 438 | return B; | |
| 502 | return b; | |
| 503 | } | |
| 504 | ||
| 505 | StringRef LinkerDriver::mangleMaybe(Symbol *s) { | |
| 506 | // If the plain symbol name has already been resolved, do nothing. | |
| 507 | Undefined *unmangled = dyn_cast<Undefined>(s); | |
| 508 | if (!unmangled) | |
| 509 | return ""; | |
| 510 | ||
| 511 | // Otherwise, see if a similar, mangled symbol exists in the symbol table. | |
| 512 | Symbol *mangled = symtab->findMangle(unmangled->getName()); | |
| 513 | if (!mangled) | |
| 514 | return ""; | |
| 515 | ||
| 516 | // If we find a similar mangled symbol, make this an alias to it and return | |
| 517 | // its name. | |
| 518 | log(unmangled->getName() + " aliased to " + mangled->getName()); | |
| 519 | unmangled->weakAlias = symtab->addUndefined(mangled->getName()); | |
| 520 | return mangled->getName(); | |
| 439 | 521 | } |
| 440 | 522 | |
| 441 | 523 | // Windows specific -- find default entry point name. |
| ... | ... | @@ -444,15 +526,15 @@ Symbol *LinkerDriver::addUndefined(StringRef Name) { |
| 444 | 526 | // each of which corresponds to a user-defined "main" function. This function |
| 445 | 527 | // infers an entry point from a user-defined "main" function. |
| 446 | 528 | StringRef LinkerDriver::findDefaultEntry() { |
| 447 | assert(Config->Subsystem != IMAGE_SUBSYSTEM_UNKNOWN && | |
| 529 | assert(config->subsystem != IMAGE_SUBSYSTEM_UNKNOWN && | |
| 448 | 530 | "must handle /subsystem before calling this"); |
| 449 | 531 | |
| 450 | if (Config->MinGW) | |
| 451 | return mangle(Config->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI | |
| 532 | if (config->mingw) | |
| 533 | return mangle(config->subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI | |
| 452 | 534 | ? "WinMainCRTStartup" |
| 453 | 535 | : "mainCRTStartup"); |
| 454 | 536 | |
| 455 | if (Config->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) { | |
| 537 | if (config->subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) { | |
| 456 | 538 | if (findUnderscoreMangle("wWinMain")) { |
| 457 | 539 | if (!findUnderscoreMangle("WinMain")) |
| 458 | 540 | return mangle("wWinMainCRTStartup"); |
| ... | ... | @@ -469,44 +551,44 @@ StringRef LinkerDriver::findDefaultEntry() { |
| 469 | 551 | } |
| 470 | 552 | |
| 471 | 553 | WindowsSubsystem LinkerDriver::inferSubsystem() { |
| 472 | if (Config->DLL) | |
| 554 | if (config->dll) | |
| 473 | 555 | return IMAGE_SUBSYSTEM_WINDOWS_GUI; |
| 474 | if (Config->MinGW) | |
| 556 | if (config->mingw) | |
| 475 | 557 | return IMAGE_SUBSYSTEM_WINDOWS_CUI; |
| 476 | 558 | // Note that link.exe infers the subsystem from the presence of these |
| 477 | 559 | // functions even if /entry: or /nodefaultlib are passed which causes them |
| 478 | 560 | // to not be called. |
| 479 | bool HaveMain = findUnderscoreMangle("main"); | |
| 480 | bool HaveWMain = findUnderscoreMangle("wmain"); | |
| 481 | bool HaveWinMain = findUnderscoreMangle("WinMain"); | |
| 482 | bool HaveWWinMain = findUnderscoreMangle("wWinMain"); | |
| 483 | if (HaveMain || HaveWMain) { | |
| 484 | if (HaveWinMain || HaveWWinMain) { | |
| 485 | warn(std::string("found ") + (HaveMain ? "main" : "wmain") + " and " + | |
| 486 | (HaveWinMain ? "WinMain" : "wWinMain") + | |
| 561 | bool haveMain = findUnderscoreMangle("main"); | |
| 562 | bool haveWMain = findUnderscoreMangle("wmain"); | |
| 563 | bool haveWinMain = findUnderscoreMangle("WinMain"); | |
| 564 | bool haveWWinMain = findUnderscoreMangle("wWinMain"); | |
| 565 | if (haveMain || haveWMain) { | |
| 566 | if (haveWinMain || haveWWinMain) { | |
| 567 | warn(std::string("found ") + (haveMain ? "main" : "wmain") + " and " + | |
| 568 | (haveWinMain ? "WinMain" : "wWinMain") + | |
| 487 | 569 | "; defaulting to /subsystem:console"); |
| 488 | 570 | } |
| 489 | 571 | return IMAGE_SUBSYSTEM_WINDOWS_CUI; |
| 490 | 572 | } |
| 491 | if (HaveWinMain || HaveWWinMain) | |
| 573 | if (haveWinMain || haveWWinMain) | |
| 492 | 574 | return IMAGE_SUBSYSTEM_WINDOWS_GUI; |
| 493 | 575 | return IMAGE_SUBSYSTEM_UNKNOWN; |
| 494 | 576 | } |
| 495 | 577 | |
| 496 | 578 | static uint64_t getDefaultImageBase() { |
| 497 | if (Config->is64()) | |
| 498 | return Config->DLL ? 0x180000000 : 0x140000000; | |
| 499 | return Config->DLL ? 0x10000000 : 0x400000; | |
| 579 | if (config->is64()) | |
| 580 | return config->dll ? 0x180000000 : 0x140000000; | |
| 581 | return config->dll ? 0x10000000 : 0x400000; | |
| 500 | 582 | } |
| 501 | 583 | |
| 502 | static std::string createResponseFile(const opt::InputArgList &Args, | |
| 503 | ArrayRef<StringRef> FilePaths, | |
| 504 | ArrayRef<StringRef> SearchPaths) { | |
| 505 | SmallString<0> Data; | |
| 506 | raw_svector_ostream OS(Data); | |
| 584 | static std::string createResponseFile(const opt::InputArgList &args, | |
| 585 | ArrayRef<StringRef> filePaths, | |
| 586 | ArrayRef<StringRef> searchPaths) { | |
| 587 | SmallString<0> data; | |
| 588 | raw_svector_ostream os(data); | |
| 507 | 589 | |
| 508 | for (auto *Arg : Args) { | |
| 509 | switch (Arg->getOption().getID()) { | |
| 590 | for (auto *arg : args) { | |
| 591 | switch (arg->getOption().getID()) { | |
| 510 | 592 | case OPT_linkrepro: |
| 511 | 593 | case OPT_INPUT: |
| 512 | 594 | case OPT_defaultlib: |
| ... | ... | @@ -518,32 +600,37 @@ static std::string createResponseFile(const opt::InputArgList &Args, |
| 518 | 600 | case OPT_manifestinput: |
| 519 | 601 | case OPT_manifestuac: |
| 520 | 602 | break; |
| 603 | case OPT_implib: | |
| 604 | case OPT_pdb: | |
| 605 | case OPT_out: | |
| 606 | os << arg->getSpelling() << sys::path::filename(arg->getValue()) << "\n"; | |
| 607 | break; | |
| 521 | 608 | default: |
| 522 | OS << toString(*Arg) << "\n"; | |
| 609 | os << toString(*arg) << "\n"; | |
| 523 | 610 | } |
| 524 | 611 | } |
| 525 | 612 | |
| 526 | for (StringRef Path : SearchPaths) { | |
| 527 | std::string RelPath = relativeToRoot(Path); | |
| 528 | OS << "/libpath:" << quote(RelPath) << "\n"; | |
| 613 | for (StringRef path : searchPaths) { | |
| 614 | std::string relPath = relativeToRoot(path); | |
| 615 | os << "/libpath:" << quote(relPath) << "\n"; | |
| 529 | 616 | } |
| 530 | 617 | |
| 531 | for (StringRef Path : FilePaths) | |
| 532 | OS << quote(relativeToRoot(Path)) << "\n"; | |
| 618 | for (StringRef path : filePaths) | |
| 619 | os << quote(relativeToRoot(path)) << "\n"; | |
| 533 | 620 | |
| 534 | return Data.str(); | |
| 621 | return data.str(); | |
| 535 | 622 | } |
| 536 | 623 | |
| 537 | 624 | enum class DebugKind { Unknown, None, Full, FastLink, GHash, Dwarf, Symtab }; |
| 538 | 625 | |
| 539 | static DebugKind parseDebugKind(const opt::InputArgList &Args) { | |
| 540 | auto *A = Args.getLastArg(OPT_debug, OPT_debug_opt); | |
| 541 | if (!A) | |
| 626 | static DebugKind parseDebugKind(const opt::InputArgList &args) { | |
| 627 | auto *a = args.getLastArg(OPT_debug, OPT_debug_opt); | |
| 628 | if (!a) | |
| 542 | 629 | return DebugKind::None; |
| 543 | if (A->getNumValues() == 0) | |
| 630 | if (a->getNumValues() == 0) | |
| 544 | 631 | return DebugKind::Full; |
| 545 | 632 | |
| 546 | DebugKind Debug = StringSwitch<DebugKind>(A->getValue()) | |
| 633 | DebugKind debug = StringSwitch<DebugKind>(a->getValue()) | |
| 547 | 634 | .CaseLower("none", DebugKind::None) |
| 548 | 635 | .CaseLower("full", DebugKind::Full) |
| 549 | 636 | .CaseLower("fastlink", DebugKind::FastLink) |
| ... | ... | @@ -553,67 +640,68 @@ static DebugKind parseDebugKind(const opt::InputArgList &Args) { |
| 553 | 640 | .CaseLower("symtab", DebugKind::Symtab) |
| 554 | 641 | .Default(DebugKind::Unknown); |
| 555 | 642 | |
| 556 | if (Debug == DebugKind::FastLink) { | |
| 643 | if (debug == DebugKind::FastLink) { | |
| 557 | 644 | warn("/debug:fastlink unsupported; using /debug:full"); |
| 558 | 645 | return DebugKind::Full; |
| 559 | 646 | } |
| 560 | if (Debug == DebugKind::Unknown) { | |
| 561 | error("/debug: unknown option: " + Twine(A->getValue())); | |
| 647 | if (debug == DebugKind::Unknown) { | |
| 648 | error("/debug: unknown option: " + Twine(a->getValue())); | |
| 562 | 649 | return DebugKind::None; |
| 563 | 650 | } |
| 564 | return Debug; | |
| 651 | return debug; | |
| 565 | 652 | } |
| 566 | 653 | |
| 567 | static unsigned parseDebugTypes(const opt::InputArgList &Args) { | |
| 568 | unsigned DebugTypes = static_cast<unsigned>(DebugType::None); | |
| 654 | static unsigned parseDebugTypes(const opt::InputArgList &args) { | |
| 655 | unsigned debugTypes = static_cast<unsigned>(DebugType::None); | |
| 569 | 656 | |
| 570 | if (auto *A = Args.getLastArg(OPT_debugtype)) { | |
| 571 | SmallVector<StringRef, 3> Types; | |
| 572 | A->getSpelling().split(Types, ',', /*KeepEmpty=*/false); | |
| 657 | if (auto *a = args.getLastArg(OPT_debugtype)) { | |
| 658 | SmallVector<StringRef, 3> types; | |
| 659 | StringRef(a->getValue()) | |
| 660 | .split(types, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false); | |
| 573 | 661 | |
| 574 | for (StringRef Type : Types) { | |
| 575 | unsigned V = StringSwitch<unsigned>(Type.lower()) | |
| 662 | for (StringRef type : types) { | |
| 663 | unsigned v = StringSwitch<unsigned>(type.lower()) | |
| 576 | 664 | .Case("cv", static_cast<unsigned>(DebugType::CV)) |
| 577 | 665 | .Case("pdata", static_cast<unsigned>(DebugType::PData)) |
| 578 | 666 | .Case("fixup", static_cast<unsigned>(DebugType::Fixup)) |
| 579 | 667 | .Default(0); |
| 580 | if (V == 0) { | |
| 581 | warn("/debugtype: unknown option: " + Twine(A->getValue())); | |
| 668 | if (v == 0) { | |
| 669 | warn("/debugtype: unknown option '" + type + "'"); | |
| 582 | 670 | continue; |
| 583 | 671 | } |
| 584 | DebugTypes |= V; | |
| 672 | debugTypes |= v; | |
| 585 | 673 | } |
| 586 | return DebugTypes; | |
| 674 | return debugTypes; | |
| 587 | 675 | } |
| 588 | 676 | |
| 589 | 677 | // Default debug types |
| 590 | DebugTypes = static_cast<unsigned>(DebugType::CV); | |
| 591 | if (Args.hasArg(OPT_driver)) | |
| 592 | DebugTypes |= static_cast<unsigned>(DebugType::PData); | |
| 593 | if (Args.hasArg(OPT_profile)) | |
| 594 | DebugTypes |= static_cast<unsigned>(DebugType::Fixup); | |
| 678 | debugTypes = static_cast<unsigned>(DebugType::CV); | |
| 679 | if (args.hasArg(OPT_driver)) | |
| 680 | debugTypes |= static_cast<unsigned>(DebugType::PData); | |
| 681 | if (args.hasArg(OPT_profile)) | |
| 682 | debugTypes |= static_cast<unsigned>(DebugType::Fixup); | |
| 595 | 683 | |
| 596 | return DebugTypes; | |
| 684 | return debugTypes; | |
| 597 | 685 | } |
| 598 | 686 | |
| 599 | static std::string getMapFile(const opt::InputArgList &Args) { | |
| 600 | auto *Arg = Args.getLastArg(OPT_lldmap, OPT_lldmap_file); | |
| 601 | if (!Arg) | |
| 687 | static std::string getMapFile(const opt::InputArgList &args) { | |
| 688 | auto *arg = args.getLastArg(OPT_lldmap, OPT_lldmap_file); | |
| 689 | if (!arg) | |
| 602 | 690 | return ""; |
| 603 | if (Arg->getOption().getID() == OPT_lldmap_file) | |
| 604 | return Arg->getValue(); | |
| 691 | if (arg->getOption().getID() == OPT_lldmap_file) | |
| 692 | return arg->getValue(); | |
| 605 | 693 | |
| 606 | assert(Arg->getOption().getID() == OPT_lldmap); | |
| 607 | StringRef OutFile = Config->OutputFile; | |
| 608 | return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str(); | |
| 694 | assert(arg->getOption().getID() == OPT_lldmap); | |
| 695 | StringRef outFile = config->outputFile; | |
| 696 | return (outFile.substr(0, outFile.rfind('.')) + ".map").str(); | |
| 609 | 697 | } |
| 610 | 698 | |
| 611 | 699 | static std::string getImplibPath() { |
| 612 | if (!Config->Implib.empty()) | |
| 613 | return Config->Implib; | |
| 614 | SmallString<128> Out = StringRef(Config->OutputFile); | |
| 615 | sys::path::replace_extension(Out, ".lib"); | |
| 616 | return Out.str(); | |
| 700 | if (!config->implib.empty()) | |
| 701 | return config->implib; | |
| 702 | SmallString<128> out = StringRef(config->outputFile); | |
| 703 | sys::path::replace_extension(out, ".lib"); | |
| 704 | return out.str(); | |
| 617 | 705 | } |
| 618 | 706 | |
| 619 | 707 | // |
| ... | ... | @@ -624,289 +712,346 @@ static std::string getImplibPath() { |
| 624 | 712 | // LINK | {value} | {value}.{.dll/.exe} | {output name} |
| 625 | 713 | // LIB | {value} | {value}.dll | {output name}.dll |
| 626 | 714 | // |
| 627 | static std::string getImportName(bool AsLib) { | |
| 628 | SmallString<128> Out; | |
| 715 | static std::string getImportName(bool asLib) { | |
| 716 | SmallString<128> out; | |
| 629 | 717 | |
| 630 | if (Config->ImportName.empty()) { | |
| 631 | Out.assign(sys::path::filename(Config->OutputFile)); | |
| 632 | if (AsLib) | |
| 633 | sys::path::replace_extension(Out, ".dll"); | |
| 718 | if (config->importName.empty()) { | |
| 719 | out.assign(sys::path::filename(config->outputFile)); | |
| 720 | if (asLib) | |
| 721 | sys::path::replace_extension(out, ".dll"); | |
| 634 | 722 | } else { |
| 635 | Out.assign(Config->ImportName); | |
| 636 | if (!sys::path::has_extension(Out)) | |
| 637 | sys::path::replace_extension(Out, | |
| 638 | (Config->DLL || AsLib) ? ".dll" : ".exe"); | |
| 723 | out.assign(config->importName); | |
| 724 | if (!sys::path::has_extension(out)) | |
| 725 | sys::path::replace_extension(out, | |
| 726 | (config->dll || asLib) ? ".dll" : ".exe"); | |
| 639 | 727 | } |
| 640 | 728 | |
| 641 | return Out.str(); | |
| 729 | return out.str(); | |
| 642 | 730 | } |
| 643 | 731 | |
| 644 | static void createImportLibrary(bool AsLib) { | |
| 645 | std::vector<COFFShortExport> Exports; | |
| 646 | for (Export &E1 : Config->Exports) { | |
| 647 | COFFShortExport E2; | |
| 648 | E2.Name = E1.Name; | |
| 649 | E2.SymbolName = E1.SymbolName; | |
| 650 | E2.ExtName = E1.ExtName; | |
| 651 | E2.Ordinal = E1.Ordinal; | |
| 652 | E2.Noname = E1.Noname; | |
| 653 | E2.Data = E1.Data; | |
| 654 | E2.Private = E1.Private; | |
| 655 | E2.Constant = E1.Constant; | |
| 656 | Exports.push_back(E2); | |
| 657 | } | |
| 658 | ||
| 659 | auto HandleError = [](Error &&E) { | |
| 660 | handleAllErrors(std::move(E), | |
| 661 | [](ErrorInfoBase &EIB) { error(EIB.message()); }); | |
| 732 | static void createImportLibrary(bool asLib) { | |
| 733 | std::vector<COFFShortExport> exports; | |
| 734 | for (Export &e1 : config->exports) { | |
| 735 | COFFShortExport e2; | |
| 736 | e2.Name = e1.name; | |
| 737 | e2.SymbolName = e1.symbolName; | |
| 738 | e2.ExtName = e1.extName; | |
| 739 | e2.Ordinal = e1.ordinal; | |
| 740 | e2.Noname = e1.noname; | |
| 741 | e2.Data = e1.data; | |
| 742 | e2.Private = e1.isPrivate; | |
| 743 | e2.Constant = e1.constant; | |
| 744 | exports.push_back(e2); | |
| 745 | } | |
| 746 | ||
| 747 | auto handleError = [](Error &&e) { | |
| 748 | handleAllErrors(std::move(e), | |
| 749 | [](ErrorInfoBase &eib) { error(eib.message()); }); | |
| 662 | 750 | }; |
| 663 | std::string LibName = getImportName(AsLib); | |
| 664 | std::string Path = getImplibPath(); | |
| 751 | std::string libName = getImportName(asLib); | |
| 752 | std::string path = getImplibPath(); | |
| 665 | 753 | |
| 666 | if (!Config->Incremental) { | |
| 667 | HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine, | |
| 668 | Config->MinGW)); | |
| 754 | if (!config->incremental) { | |
| 755 | handleError(writeImportLibrary(libName, path, exports, config->machine, | |
| 756 | config->mingw)); | |
| 669 | 757 | return; |
| 670 | 758 | } |
| 671 | 759 | |
| 672 | 760 | // If the import library already exists, replace it only if the contents |
| 673 | 761 | // have changed. |
| 674 | ErrorOr<std::unique_ptr<MemoryBuffer>> OldBuf = MemoryBuffer::getFile( | |
| 675 | Path, /*FileSize*/ -1, /*RequiresNullTerminator*/ false); | |
| 676 | if (!OldBuf) { | |
| 677 | HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine, | |
| 678 | Config->MinGW)); | |
| 762 | ErrorOr<std::unique_ptr<MemoryBuffer>> oldBuf = MemoryBuffer::getFile( | |
| 763 | path, /*FileSize*/ -1, /*RequiresNullTerminator*/ false); | |
| 764 | if (!oldBuf) { | |
| 765 | handleError(writeImportLibrary(libName, path, exports, config->machine, | |
| 766 | config->mingw)); | |
| 679 | 767 | return; |
| 680 | 768 | } |
| 681 | 769 | |
| 682 | SmallString<128> TmpName; | |
| 683 | if (std::error_code EC = | |
| 684 | sys::fs::createUniqueFile(Path + ".tmp-%%%%%%%%.lib", TmpName)) | |
| 685 | fatal("cannot create temporary file for import library " + Path + ": " + | |
| 686 | EC.message()); | |
| 770 | SmallString<128> tmpName; | |
| 771 | if (std::error_code ec = | |
| 772 | sys::fs::createUniqueFile(path + ".tmp-%%%%%%%%.lib", tmpName)) | |
| 773 | fatal("cannot create temporary file for import library " + path + ": " + | |
| 774 | ec.message()); | |
| 687 | 775 | |
| 688 | if (Error E = writeImportLibrary(LibName, TmpName, Exports, Config->Machine, | |
| 689 | Config->MinGW)) { | |
| 690 | HandleError(std::move(E)); | |
| 776 | if (Error e = writeImportLibrary(libName, tmpName, exports, config->machine, | |
| 777 | config->mingw)) { | |
| 778 | handleError(std::move(e)); | |
| 691 | 779 | return; |
| 692 | 780 | } |
| 693 | 781 | |
| 694 | std::unique_ptr<MemoryBuffer> NewBuf = check(MemoryBuffer::getFile( | |
| 695 | TmpName, /*FileSize*/ -1, /*RequiresNullTerminator*/ false)); | |
| 696 | if ((*OldBuf)->getBuffer() != NewBuf->getBuffer()) { | |
| 697 | OldBuf->reset(); | |
| 698 | HandleError(errorCodeToError(sys::fs::rename(TmpName, Path))); | |
| 782 | std::unique_ptr<MemoryBuffer> newBuf = check(MemoryBuffer::getFile( | |
| 783 | tmpName, /*FileSize*/ -1, /*RequiresNullTerminator*/ false)); | |
| 784 | if ((*oldBuf)->getBuffer() != newBuf->getBuffer()) { | |
| 785 | oldBuf->reset(); | |
| 786 | handleError(errorCodeToError(sys::fs::rename(tmpName, path))); | |
| 699 | 787 | } else { |
| 700 | sys::fs::remove(TmpName); | |
| 788 | sys::fs::remove(tmpName); | |
| 701 | 789 | } |
| 702 | 790 | } |
| 703 | 791 | |
| 704 | static void parseModuleDefs(StringRef Path) { | |
| 705 | std::unique_ptr<MemoryBuffer> MB = CHECK( | |
| 706 | MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); | |
| 707 | COFFModuleDefinition M = check(parseCOFFModuleDefinition( | |
| 708 | MB->getMemBufferRef(), Config->Machine, Config->MinGW)); | |
| 709 | ||
| 710 | if (Config->OutputFile.empty()) | |
| 711 | Config->OutputFile = Saver.save(M.OutputFile); | |
| 712 | Config->ImportName = Saver.save(M.ImportName); | |
| 713 | if (M.ImageBase) | |
| 714 | Config->ImageBase = M.ImageBase; | |
| 715 | if (M.StackReserve) | |
| 716 | Config->StackReserve = M.StackReserve; | |
| 717 | if (M.StackCommit) | |
| 718 | Config->StackCommit = M.StackCommit; | |
| 719 | if (M.HeapReserve) | |
| 720 | Config->HeapReserve = M.HeapReserve; | |
| 721 | if (M.HeapCommit) | |
| 722 | Config->HeapCommit = M.HeapCommit; | |
| 723 | if (M.MajorImageVersion) | |
| 724 | Config->MajorImageVersion = M.MajorImageVersion; | |
| 725 | if (M.MinorImageVersion) | |
| 726 | Config->MinorImageVersion = M.MinorImageVersion; | |
| 727 | if (M.MajorOSVersion) | |
| 728 | Config->MajorOSVersion = M.MajorOSVersion; | |
| 729 | if (M.MinorOSVersion) | |
| 730 | Config->MinorOSVersion = M.MinorOSVersion; | |
| 731 | ||
| 732 | for (COFFShortExport E1 : M.Exports) { | |
| 733 | Export E2; | |
| 792 | static void parseModuleDefs(StringRef path) { | |
| 793 | std::unique_ptr<MemoryBuffer> mb = CHECK( | |
| 794 | MemoryBuffer::getFile(path, -1, false, true), "could not open " + path); | |
| 795 | COFFModuleDefinition m = check(parseCOFFModuleDefinition( | |
| 796 | mb->getMemBufferRef(), config->machine, config->mingw)); | |
| 797 | ||
| 798 | if (config->outputFile.empty()) | |
| 799 | config->outputFile = saver.save(m.OutputFile); | |
| 800 | config->importName = saver.save(m.ImportName); | |
| 801 | if (m.ImageBase) | |
| 802 | config->imageBase = m.ImageBase; | |
| 803 | if (m.StackReserve) | |
| 804 | config->stackReserve = m.StackReserve; | |
| 805 | if (m.StackCommit) | |
| 806 | config->stackCommit = m.StackCommit; | |
| 807 | if (m.HeapReserve) | |
| 808 | config->heapReserve = m.HeapReserve; | |
| 809 | if (m.HeapCommit) | |
| 810 | config->heapCommit = m.HeapCommit; | |
| 811 | if (m.MajorImageVersion) | |
| 812 | config->majorImageVersion = m.MajorImageVersion; | |
| 813 | if (m.MinorImageVersion) | |
| 814 | config->minorImageVersion = m.MinorImageVersion; | |
| 815 | if (m.MajorOSVersion) | |
| 816 | config->majorOSVersion = m.MajorOSVersion; | |
| 817 | if (m.MinorOSVersion) | |
| 818 | config->minorOSVersion = m.MinorOSVersion; | |
| 819 | ||
| 820 | for (COFFShortExport e1 : m.Exports) { | |
| 821 | Export e2; | |
| 734 | 822 | // In simple cases, only Name is set. Renamed exports are parsed |
| 735 | 823 | // and set as "ExtName = Name". If Name has the form "OtherDll.Func", |
| 736 | 824 | // it shouldn't be a normal exported function but a forward to another |
| 737 | 825 | // DLL instead. This is supported by both MS and GNU linkers. |
| 738 | if (E1.ExtName != E1.Name && StringRef(E1.Name).contains('.')) { | |
| 739 | E2.Name = Saver.save(E1.ExtName); | |
| 740 | E2.ForwardTo = Saver.save(E1.Name); | |
| 741 | Config->Exports.push_back(E2); | |
| 826 | if (e1.ExtName != e1.Name && StringRef(e1.Name).contains('.')) { | |
| 827 | e2.name = saver.save(e1.ExtName); | |
| 828 | e2.forwardTo = saver.save(e1.Name); | |
| 829 | config->exports.push_back(e2); | |
| 742 | 830 | continue; |
| 743 | 831 | } |
| 744 | E2.Name = Saver.save(E1.Name); | |
| 745 | E2.ExtName = Saver.save(E1.ExtName); | |
| 746 | E2.Ordinal = E1.Ordinal; | |
| 747 | E2.Noname = E1.Noname; | |
| 748 | E2.Data = E1.Data; | |
| 749 | E2.Private = E1.Private; | |
| 750 | E2.Constant = E1.Constant; | |
| 751 | Config->Exports.push_back(E2); | |
| 832 | e2.name = saver.save(e1.Name); | |
| 833 | e2.extName = saver.save(e1.ExtName); | |
| 834 | e2.ordinal = e1.Ordinal; | |
| 835 | e2.noname = e1.Noname; | |
| 836 | e2.data = e1.Data; | |
| 837 | e2.isPrivate = e1.Private; | |
| 838 | e2.constant = e1.Constant; | |
| 839 | config->exports.push_back(e2); | |
| 752 | 840 | } |
| 753 | 841 | } |
| 754 | 842 | |
| 755 | void LinkerDriver::enqueueTask(std::function<void()> Task) { | |
| 756 | TaskQueue.push_back(std::move(Task)); | |
| 843 | void LinkerDriver::enqueueTask(std::function<void()> task) { | |
| 844 | taskQueue.push_back(std::move(task)); | |
| 757 | 845 | } |
| 758 | 846 | |
| 759 | 847 | bool LinkerDriver::run() { |
| 760 | ScopedTimer T(InputFileTimer); | |
| 848 | ScopedTimer t(inputFileTimer); | |
| 761 | 849 | |
| 762 | bool DidWork = !TaskQueue.empty(); | |
| 763 | while (!TaskQueue.empty()) { | |
| 764 | TaskQueue.front()(); | |
| 765 | TaskQueue.pop_front(); | |
| 850 | bool didWork = !taskQueue.empty(); | |
| 851 | while (!taskQueue.empty()) { | |
| 852 | taskQueue.front()(); | |
| 853 | taskQueue.pop_front(); | |
| 766 | 854 | } |
| 767 | return DidWork; | |
| 855 | return didWork; | |
| 768 | 856 | } |
| 769 | 857 | |
| 770 | 858 | // Parse an /order file. If an option is given, the linker places |
| 771 | 859 | // COMDAT sections in the same order as their names appear in the |
| 772 | 860 | // given file. |
| 773 | static void parseOrderFile(StringRef Arg) { | |
| 861 | static void parseOrderFile(StringRef arg) { | |
| 774 | 862 | // For some reason, the MSVC linker requires a filename to be |
| 775 | 863 | // preceded by "@". |
| 776 | if (!Arg.startswith("@")) { | |
| 864 | if (!arg.startswith("@")) { | |
| 777 | 865 | error("malformed /order option: '@' missing"); |
| 778 | 866 | return; |
| 779 | 867 | } |
| 780 | 868 | |
| 781 | 869 | // Get a list of all comdat sections for error checking. |
| 782 | DenseSet<StringRef> Set; | |
| 783 | for (Chunk *C : Symtab->getChunks()) | |
| 784 | if (auto *Sec = dyn_cast<SectionChunk>(C)) | |
| 785 | if (Sec->Sym) | |
| 786 | Set.insert(Sec->Sym->getName()); | |
| 870 | DenseSet<StringRef> set; | |
| 871 | for (Chunk *c : symtab->getChunks()) | |
| 872 | if (auto *sec = dyn_cast<SectionChunk>(c)) | |
| 873 | if (sec->sym) | |
| 874 | set.insert(sec->sym->getName()); | |
| 787 | 875 | |
| 788 | 876 | // Open a file. |
| 789 | StringRef Path = Arg.substr(1); | |
| 790 | std::unique_ptr<MemoryBuffer> MB = CHECK( | |
| 791 | MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); | |
| 877 | StringRef path = arg.substr(1); | |
| 878 | std::unique_ptr<MemoryBuffer> mb = CHECK( | |
| 879 | MemoryBuffer::getFile(path, -1, false, true), "could not open " + path); | |
| 792 | 880 | |
| 793 | 881 | // Parse a file. An order file contains one symbol per line. |
| 794 | 882 | // All symbols that were not present in a given order file are |
| 795 | 883 | // considered to have the lowest priority 0 and are placed at |
| 796 | 884 | // end of an output section. |
| 797 | for (std::string S : args::getLines(MB->getMemBufferRef())) { | |
| 798 | if (Config->Machine == I386 && !isDecorated(S)) | |
| 799 | S = "_" + S; | |
| 885 | for (std::string s : args::getLines(mb->getMemBufferRef())) { | |
| 886 | if (config->machine == I386 && !isDecorated(s)) | |
| 887 | s = "_" + s; | |
| 800 | 888 | |
| 801 | if (Set.count(S) == 0) { | |
| 802 | if (Config->WarnMissingOrderSymbol) | |
| 803 | warn("/order:" + Arg + ": missing symbol: " + S + " [LNK4037]"); | |
| 889 | if (set.count(s) == 0) { | |
| 890 | if (config->warnMissingOrderSymbol) | |
| 891 | warn("/order:" + arg + ": missing symbol: " + s + " [LNK4037]"); | |
| 804 | 892 | } |
| 805 | 893 | else |
| 806 | Config->Order[S] = INT_MIN + Config->Order.size(); | |
| 894 | config->order[s] = INT_MIN + config->order.size(); | |
| 807 | 895 | } |
| 808 | 896 | } |
| 809 | 897 | |
| 810 | static void markAddrsig(Symbol *S) { | |
| 811 | if (auto *D = dyn_cast_or_null<Defined>(S)) | |
| 812 | if (Chunk *C = D->getChunk()) | |
| 813 | C->KeepUnique = true; | |
| 898 | static void markAddrsig(Symbol *s) { | |
| 899 | if (auto *d = dyn_cast_or_null<Defined>(s)) | |
| 900 | if (SectionChunk *c = dyn_cast_or_null<SectionChunk>(d->getChunk())) | |
| 901 | c->keepUnique = true; | |
| 814 | 902 | } |
| 815 | 903 | |
| 816 | 904 | static void findKeepUniqueSections() { |
| 817 | 905 | // Exported symbols could be address-significant in other executables or DSOs, |
| 818 | 906 | // so we conservatively mark them as address-significant. |
| 819 | for (Export &R : Config->Exports) | |
| 820 | markAddrsig(R.Sym); | |
| 907 | for (Export &r : config->exports) | |
| 908 | markAddrsig(r.sym); | |
| 821 | 909 | |
| 822 | 910 | // Visit the address-significance table in each object file and mark each |
| 823 | 911 | // referenced symbol as address-significant. |
| 824 | for (ObjFile *Obj : ObjFile::Instances) { | |
| 825 | ArrayRef<Symbol *> Syms = Obj->getSymbols(); | |
| 826 | if (Obj->AddrsigSec) { | |
| 827 | ArrayRef<uint8_t> Contents; | |
| 828 | Obj->getCOFFObj()->getSectionContents(Obj->AddrsigSec, Contents); | |
| 829 | const uint8_t *Cur = Contents.begin(); | |
| 830 | while (Cur != Contents.end()) { | |
| 831 | unsigned Size; | |
| 832 | const char *Err; | |
| 833 | uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err); | |
| 834 | if (Err) | |
| 835 | fatal(toString(Obj) + ": could not decode addrsig section: " + Err); | |
| 836 | if (SymIndex >= Syms.size()) | |
| 837 | fatal(toString(Obj) + ": invalid symbol index in addrsig section"); | |
| 838 | markAddrsig(Syms[SymIndex]); | |
| 839 | Cur += Size; | |
| 912 | for (ObjFile *obj : ObjFile::instances) { | |
| 913 | ArrayRef<Symbol *> syms = obj->getSymbols(); | |
| 914 | if (obj->addrsigSec) { | |
| 915 | ArrayRef<uint8_t> contents; | |
| 916 | cantFail( | |
| 917 | obj->getCOFFObj()->getSectionContents(obj->addrsigSec, contents)); | |
| 918 | const uint8_t *cur = contents.begin(); | |
| 919 | while (cur != contents.end()) { | |
| 920 | unsigned size; | |
| 921 | const char *err; | |
| 922 | uint64_t symIndex = decodeULEB128(cur, &size, contents.end(), &err); | |
| 923 | if (err) | |
| 924 | fatal(toString(obj) + ": could not decode addrsig section: " + err); | |
| 925 | if (symIndex >= syms.size()) | |
| 926 | fatal(toString(obj) + ": invalid symbol index in addrsig section"); | |
| 927 | markAddrsig(syms[symIndex]); | |
| 928 | cur += size; | |
| 840 | 929 | } |
| 841 | 930 | } else { |
| 842 | 931 | // If an object file does not have an address-significance table, |
| 843 | 932 | // conservatively mark all of its symbols as address-significant. |
| 844 | for (Symbol *S : Syms) | |
| 845 | markAddrsig(S); | |
| 933 | for (Symbol *s : syms) | |
| 934 | markAddrsig(s); | |
| 846 | 935 | } |
| 847 | 936 | } |
| 848 | 937 | } |
| 849 | 938 | |
| 850 | // link.exe replaces each %foo% in AltPath with the contents of environment | |
| 939 | // link.exe replaces each %foo% in altPath with the contents of environment | |
| 851 | 940 | // variable foo, and adds the two magic env vars _PDB (expands to the basename |
| 852 | 941 | // of pdb's output path) and _EXT (expands to the extension of the output |
| 853 | 942 | // binary). |
| 854 | 943 | // lld only supports %_PDB% and %_EXT% and warns on references to all other env |
| 855 | 944 | // vars. |
| 856 | static void parsePDBAltPath(StringRef AltPath) { | |
| 857 | SmallString<128> Buf; | |
| 858 | StringRef PDBBasename = | |
| 859 | sys::path::filename(Config->PDBPath, sys::path::Style::windows); | |
| 860 | StringRef BinaryExtension = | |
| 861 | sys::path::extension(Config->OutputFile, sys::path::Style::windows); | |
| 862 | if (!BinaryExtension.empty()) | |
| 863 | BinaryExtension = BinaryExtension.substr(1); // %_EXT% does not include '.'. | |
| 945 | static void parsePDBAltPath(StringRef altPath) { | |
| 946 | SmallString<128> buf; | |
| 947 | StringRef pdbBasename = | |
| 948 | sys::path::filename(config->pdbPath, sys::path::Style::windows); | |
| 949 | StringRef binaryExtension = | |
| 950 | sys::path::extension(config->outputFile, sys::path::Style::windows); | |
| 951 | if (!binaryExtension.empty()) | |
| 952 | binaryExtension = binaryExtension.substr(1); // %_EXT% does not include '.'. | |
| 864 | 953 | |
| 865 | 954 | // Invariant: |
| 866 | // +--------- Cursor ('a...' might be the empty string). | |
| 867 | // | +----- FirstMark | |
| 868 | // | | +- SecondMark | |
| 955 | // +--------- cursor ('a...' might be the empty string). | |
| 956 | // | +----- firstMark | |
| 957 | // | | +- secondMark | |
| 869 | 958 | // v v v |
| 870 | 959 | // a...%...%... |
| 871 | size_t Cursor = 0; | |
| 872 | while (Cursor < AltPath.size()) { | |
| 873 | size_t FirstMark, SecondMark; | |
| 874 | if ((FirstMark = AltPath.find('%', Cursor)) == StringRef::npos || | |
| 875 | (SecondMark = AltPath.find('%', FirstMark + 1)) == StringRef::npos) { | |
| 960 | size_t cursor = 0; | |
| 961 | while (cursor < altPath.size()) { | |
| 962 | size_t firstMark, secondMark; | |
| 963 | if ((firstMark = altPath.find('%', cursor)) == StringRef::npos || | |
| 964 | (secondMark = altPath.find('%', firstMark + 1)) == StringRef::npos) { | |
| 876 | 965 | // Didn't find another full fragment, treat rest of string as literal. |
| 877 | Buf.append(AltPath.substr(Cursor)); | |
| 966 | buf.append(altPath.substr(cursor)); | |
| 878 | 967 | break; |
| 879 | 968 | } |
| 880 | 969 | |
| 881 | 970 | // Found a full fragment. Append text in front of first %, and interpret |
| 882 | 971 | // text between first and second % as variable name. |
| 883 | Buf.append(AltPath.substr(Cursor, FirstMark - Cursor)); | |
| 884 | StringRef Var = AltPath.substr(FirstMark, SecondMark - FirstMark + 1); | |
| 885 | if (Var.equals_lower("%_pdb%")) | |
| 886 | Buf.append(PDBBasename); | |
| 887 | else if (Var.equals_lower("%_ext%")) | |
| 888 | Buf.append(BinaryExtension); | |
| 972 | buf.append(altPath.substr(cursor, firstMark - cursor)); | |
| 973 | StringRef var = altPath.substr(firstMark, secondMark - firstMark + 1); | |
| 974 | if (var.equals_lower("%_pdb%")) | |
| 975 | buf.append(pdbBasename); | |
| 976 | else if (var.equals_lower("%_ext%")) | |
| 977 | buf.append(binaryExtension); | |
| 889 | 978 | else { |
| 890 | 979 | warn("only %_PDB% and %_EXT% supported in /pdbaltpath:, keeping " + |
| 891 | Var + " as literal"); | |
| 892 | Buf.append(Var); | |
| 980 | var + " as literal"); | |
| 981 | buf.append(var); | |
| 893 | 982 | } |
| 894 | 983 | |
| 895 | Cursor = SecondMark + 1; | |
| 984 | cursor = secondMark + 1; | |
| 896 | 985 | } |
| 897 | 986 | |
| 898 | Config->PDBAltPath = Buf; | |
| 987 | config->pdbAltPath = buf; | |
| 899 | 988 | } |
| 900 | 989 | |
| 901 | void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { | |
| 902 | // If the first command line argument is "/lib", link.exe acts like lib.exe. | |
| 903 | // We call our own implementation of lib.exe that understands bitcode files. | |
| 904 | if (ArgsArr.size() > 1 && StringRef(ArgsArr[1]).equals_lower("/lib")) { | |
| 905 | if (llvm::libDriverMain(ArgsArr.slice(1)) != 0) | |
| 906 | fatal("lib failed"); | |
| 990 | /// Check that at most one resource obj file was used. | |
| 991 | /// Call after ObjFile::Instances is complete. | |
| 992 | static void diagnoseMultipleResourceObjFiles() { | |
| 993 | // The .rsrc$01 section in a resource obj file contains a tree description | |
| 994 | // of resources. Merging multiple resource obj files would require merging | |
| 995 | // the trees instead of using usual linker section merging semantics. | |
| 996 | // Since link.exe disallows linking more than one resource obj file with | |
| 997 | // LNK4078, mirror that. The normal use of resource files is to give the | |
| 998 | // linker many .res files, which are then converted to a single resource obj | |
| 999 | // file internally, so this is not a big restriction in practice. | |
| 1000 | ObjFile *resourceObjFile = nullptr; | |
| 1001 | for (ObjFile *f : ObjFile::instances) { | |
| 1002 | if (!f->isResourceObjFile) | |
| 1003 | continue; | |
| 1004 | ||
| 1005 | if (!resourceObjFile) { | |
| 1006 | resourceObjFile = f; | |
| 1007 | continue; | |
| 1008 | } | |
| 1009 | ||
| 1010 | error(toString(f) + | |
| 1011 | ": more than one resource obj file not allowed, already got " + | |
| 1012 | toString(resourceObjFile)); | |
| 1013 | } | |
| 1014 | } | |
| 1015 | ||
| 1016 | // In MinGW, if no symbols are chosen to be exported, then all symbols are | |
| 1017 | // automatically exported by default. This behavior can be forced by the | |
| 1018 | // -export-all-symbols option, so that it happens even when exports are | |
| 1019 | // explicitly specified. The automatic behavior can be disabled using the | |
| 1020 | // -exclude-all-symbols option, so that lld-link behaves like link.exe rather | |
| 1021 | // than MinGW in the case that nothing is explicitly exported. | |
| 1022 | void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) { | |
| 1023 | if (!config->dll) | |
| 907 | 1024 | return; |
| 1025 | ||
| 1026 | if (!args.hasArg(OPT_export_all_symbols)) { | |
| 1027 | if (!config->exports.empty()) | |
| 1028 | return; | |
| 1029 | if (args.hasArg(OPT_exclude_all_symbols)) | |
| 1030 | return; | |
| 908 | 1031 | } |
| 909 | 1032 | |
| 1033 | AutoExporter exporter; | |
| 1034 | ||
| 1035 | for (auto *arg : args.filtered(OPT_wholearchive_file)) | |
| 1036 | if (Optional<StringRef> path = doFindFile(arg->getValue())) | |
| 1037 | exporter.addWholeArchive(*path); | |
| 1038 | ||
| 1039 | symtab->forEachSymbol([&](Symbol *s) { | |
| 1040 | auto *def = dyn_cast<Defined>(s); | |
| 1041 | if (!exporter.shouldExport(def)) | |
| 1042 | return; | |
| 1043 | ||
| 1044 | Export e; | |
| 1045 | e.name = def->getName(); | |
| 1046 | e.sym = def; | |
| 1047 | if (Chunk *c = def->getChunk()) | |
| 1048 | if (!(c->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) | |
| 1049 | e.data = true; | |
| 1050 | config->exports.push_back(e); | |
| 1051 | }); | |
| 1052 | } | |
| 1053 | ||
| 1054 | void LinkerDriver::link(ArrayRef<const char *> argsArr) { | |
| 910 | 1055 | // Needed for LTO. |
| 911 | 1056 | InitializeAllTargetInfos(); |
| 912 | 1057 | InitializeAllTargets(); |
| ... | ... | @@ -914,279 +1059,308 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { |
| 914 | 1059 | InitializeAllAsmParsers(); |
| 915 | 1060 | InitializeAllAsmPrinters(); |
| 916 | 1061 | |
| 1062 | // If the first command line argument is "/lib", link.exe acts like lib.exe. | |
| 1063 | // We call our own implementation of lib.exe that understands bitcode files. | |
| 1064 | if (argsArr.size() > 1 && StringRef(argsArr[1]).equals_lower("/lib")) { | |
| 1065 | if (llvm::libDriverMain(argsArr.slice(1)) != 0) | |
| 1066 | fatal("lib failed"); | |
| 1067 | return; | |
| 1068 | } | |
| 1069 | ||
| 917 | 1070 | // Parse command line options. |
| 918 | ArgParser Parser; | |
| 919 | opt::InputArgList Args = Parser.parseLINK(ArgsArr); | |
| 1071 | ArgParser parser; | |
| 1072 | opt::InputArgList args = parser.parseLINK(argsArr); | |
| 920 | 1073 | |
| 921 | 1074 | // Parse and evaluate -mllvm options. |
| 922 | std::vector<const char *> V; | |
| 923 | V.push_back("lld-link (LLVM option parsing)"); | |
| 924 | for (auto *Arg : Args.filtered(OPT_mllvm)) | |
| 925 | V.push_back(Arg->getValue()); | |
| 926 | cl::ParseCommandLineOptions(V.size(), V.data()); | |
| 1075 | std::vector<const char *> v; | |
| 1076 | v.push_back("lld-link (LLVM option parsing)"); | |
| 1077 | for (auto *arg : args.filtered(OPT_mllvm)) | |
| 1078 | v.push_back(arg->getValue()); | |
| 1079 | cl::ParseCommandLineOptions(v.size(), v.data()); | |
| 927 | 1080 | |
| 928 | 1081 | // Handle /errorlimit early, because error() depends on it. |
| 929 | if (auto *Arg = Args.getLastArg(OPT_errorlimit)) { | |
| 930 | int N = 20; | |
| 931 | StringRef S = Arg->getValue(); | |
| 932 | if (S.getAsInteger(10, N)) | |
| 933 | error(Arg->getSpelling() + " number expected, but got " + S); | |
| 934 | errorHandler().ErrorLimit = N; | |
| 1082 | if (auto *arg = args.getLastArg(OPT_errorlimit)) { | |
| 1083 | int n = 20; | |
| 1084 | StringRef s = arg->getValue(); | |
| 1085 | if (s.getAsInteger(10, n)) | |
| 1086 | error(arg->getSpelling() + " number expected, but got " + s); | |
| 1087 | errorHandler().errorLimit = n; | |
| 935 | 1088 | } |
| 936 | 1089 | |
| 937 | 1090 | // Handle /help |
| 938 | if (Args.hasArg(OPT_help)) { | |
| 939 | printHelp(ArgsArr[0]); | |
| 1091 | if (args.hasArg(OPT_help)) { | |
| 1092 | printHelp(argsArr[0]); | |
| 940 | 1093 | return; |
| 941 | 1094 | } |
| 942 | 1095 | |
| 943 | if (Args.hasArg(OPT_show_timing)) | |
| 944 | Config->ShowTiming = true; | |
| 1096 | lld::threadsEnabled = args.hasFlag(OPT_threads, OPT_threads_no, true); | |
| 1097 | ||
| 1098 | if (args.hasArg(OPT_show_timing)) | |
| 1099 | config->showTiming = true; | |
| 945 | 1100 | |
| 946 | ScopedTimer T(Timer::root()); | |
| 1101 | config->showSummary = args.hasArg(OPT_summary); | |
| 1102 | ||
| 1103 | ScopedTimer t(Timer::root()); | |
| 947 | 1104 | // Handle --version, which is an lld extension. This option is a bit odd |
| 948 | 1105 | // because it doesn't start with "/", but we deliberately chose "--" to |
| 949 | 1106 | // avoid conflict with /version and for compatibility with clang-cl. |
| 950 | if (Args.hasArg(OPT_dash_dash_version)) { | |
| 1107 | if (args.hasArg(OPT_dash_dash_version)) { | |
| 951 | 1108 | outs() << getLLDVersion() << "\n"; |
| 952 | 1109 | return; |
| 953 | 1110 | } |
| 954 | 1111 | |
| 955 | 1112 | // Handle /lldmingw early, since it can potentially affect how other |
| 956 | 1113 | // options are handled. |
| 957 | Config->MinGW = Args.hasArg(OPT_lldmingw); | |
| 1114 | config->mingw = args.hasArg(OPT_lldmingw); | |
| 958 | 1115 | |
| 959 | if (auto *Arg = Args.getLastArg(OPT_linkrepro)) { | |
| 960 | SmallString<64> Path = StringRef(Arg->getValue()); | |
| 961 | sys::path::append(Path, "repro.tar"); | |
| 1116 | if (auto *arg = args.getLastArg(OPT_linkrepro)) { | |
| 1117 | SmallString<64> path = StringRef(arg->getValue()); | |
| 1118 | sys::path::append(path, "repro.tar"); | |
| 962 | 1119 | |
| 963 | Expected<std::unique_ptr<TarWriter>> ErrOrWriter = | |
| 964 | TarWriter::create(Path, "repro"); | |
| 1120 | Expected<std::unique_ptr<TarWriter>> errOrWriter = | |
| 1121 | TarWriter::create(path, "repro"); | |
| 965 | 1122 | |
| 966 | if (ErrOrWriter) { | |
| 967 | Tar = std::move(*ErrOrWriter); | |
| 1123 | if (errOrWriter) { | |
| 1124 | tar = std::move(*errOrWriter); | |
| 968 | 1125 | } else { |
| 969 | error("/linkrepro: failed to open " + Path + ": " + | |
| 970 | toString(ErrOrWriter.takeError())); | |
| 1126 | error("/linkrepro: failed to open " + path + ": " + | |
| 1127 | toString(errOrWriter.takeError())); | |
| 971 | 1128 | } |
| 972 | 1129 | } |
| 973 | 1130 | |
| 974 | if (!Args.hasArg(OPT_INPUT)) { | |
| 975 | if (Args.hasArg(OPT_deffile)) | |
| 976 | Config->NoEntry = true; | |
| 1131 | if (!args.hasArg(OPT_INPUT)) { | |
| 1132 | if (args.hasArg(OPT_deffile)) | |
| 1133 | config->noEntry = true; | |
| 977 | 1134 | else |
| 978 | 1135 | fatal("no input files"); |
| 979 | 1136 | } |
| 980 | 1137 | |
| 981 | 1138 | // Construct search path list. |
| 982 | SearchPaths.push_back(""); | |
| 983 | for (auto *Arg : Args.filtered(OPT_libpath)) | |
| 984 | SearchPaths.push_back(Arg->getValue()); | |
| 1139 | searchPaths.push_back(""); | |
| 1140 | for (auto *arg : args.filtered(OPT_libpath)) | |
| 1141 | searchPaths.push_back(arg->getValue()); | |
| 985 | 1142 | addLibSearchPaths(); |
| 986 | 1143 | |
| 987 | 1144 | // Handle /ignore |
| 988 | for (auto *Arg : Args.filtered(OPT_ignore)) { | |
| 989 | SmallVector<StringRef, 8> Vec; | |
| 990 | StringRef(Arg->getValue()).split(Vec, ','); | |
| 991 | for (StringRef S : Vec) { | |
| 992 | if (S == "4037") | |
| 993 | Config->WarnMissingOrderSymbol = false; | |
| 994 | else if (S == "4099") | |
| 995 | Config->WarnDebugInfoUnusable = false; | |
| 996 | else if (S == "4217") | |
| 997 | Config->WarnLocallyDefinedImported = false; | |
| 1145 | for (auto *arg : args.filtered(OPT_ignore)) { | |
| 1146 | SmallVector<StringRef, 8> vec; | |
| 1147 | StringRef(arg->getValue()).split(vec, ','); | |
| 1148 | for (StringRef s : vec) { | |
| 1149 | if (s == "4037") | |
| 1150 | config->warnMissingOrderSymbol = false; | |
| 1151 | else if (s == "4099") | |
| 1152 | config->warnDebugInfoUnusable = false; | |
| 1153 | else if (s == "4217") | |
| 1154 | config->warnLocallyDefinedImported = false; | |
| 998 | 1155 | // Other warning numbers are ignored. |
| 999 | 1156 | } |
| 1000 | 1157 | } |
| 1001 | 1158 | |
| 1002 | 1159 | // Handle /out |
| 1003 | if (auto *Arg = Args.getLastArg(OPT_out)) | |
| 1004 | Config->OutputFile = Arg->getValue(); | |
| 1160 | if (auto *arg = args.getLastArg(OPT_out)) | |
| 1161 | config->outputFile = arg->getValue(); | |
| 1005 | 1162 | |
| 1006 | 1163 | // Handle /verbose |
| 1007 | if (Args.hasArg(OPT_verbose)) | |
| 1008 | Config->Verbose = true; | |
| 1009 | errorHandler().Verbose = Config->Verbose; | |
| 1164 | if (args.hasArg(OPT_verbose)) | |
| 1165 | config->verbose = true; | |
| 1166 | errorHandler().verbose = config->verbose; | |
| 1010 | 1167 | |
| 1011 | 1168 | // Handle /force or /force:unresolved |
| 1012 | if (Args.hasArg(OPT_force, OPT_force_unresolved)) | |
| 1013 | Config->ForceUnresolved = true; | |
| 1169 | if (args.hasArg(OPT_force, OPT_force_unresolved)) | |
| 1170 | config->forceUnresolved = true; | |
| 1014 | 1171 | |
| 1015 | 1172 | // Handle /force or /force:multiple |
| 1016 | if (Args.hasArg(OPT_force, OPT_force_multiple)) | |
| 1017 | Config->ForceMultiple = true; | |
| 1173 | if (args.hasArg(OPT_force, OPT_force_multiple)) | |
| 1174 | config->forceMultiple = true; | |
| 1175 | ||
| 1176 | // Handle /force or /force:multipleres | |
| 1177 | if (args.hasArg(OPT_force, OPT_force_multipleres)) | |
| 1178 | config->forceMultipleRes = true; | |
| 1018 | 1179 | |
| 1019 | 1180 | // Handle /debug |
| 1020 | DebugKind Debug = parseDebugKind(Args); | |
| 1021 | if (Debug == DebugKind::Full || Debug == DebugKind::Dwarf || | |
| 1022 | Debug == DebugKind::GHash) { | |
| 1023 | Config->Debug = true; | |
| 1024 | Config->Incremental = true; | |
| 1181 | DebugKind debug = parseDebugKind(args); | |
| 1182 | if (debug == DebugKind::Full || debug == DebugKind::Dwarf || | |
| 1183 | debug == DebugKind::GHash) { | |
| 1184 | config->debug = true; | |
| 1185 | config->incremental = true; | |
| 1025 | 1186 | } |
| 1026 | 1187 | |
| 1188 | // Handle /demangle | |
| 1189 | config->demangle = args.hasFlag(OPT_demangle, OPT_demangle_no); | |
| 1190 | ||
| 1027 | 1191 | // Handle /debugtype |
| 1028 | Config->DebugTypes = parseDebugTypes(Args); | |
| 1192 | config->debugTypes = parseDebugTypes(args); | |
| 1029 | 1193 | |
| 1030 | 1194 | // Handle /pdb |
| 1031 | bool ShouldCreatePDB = | |
| 1032 | (Debug == DebugKind::Full || Debug == DebugKind::GHash); | |
| 1033 | if (ShouldCreatePDB) { | |
| 1034 | if (auto *Arg = Args.getLastArg(OPT_pdb)) | |
| 1035 | Config->PDBPath = Arg->getValue(); | |
| 1036 | if (auto *Arg = Args.getLastArg(OPT_pdbaltpath)) | |
| 1037 | Config->PDBAltPath = Arg->getValue(); | |
| 1038 | if (Args.hasArg(OPT_natvis)) | |
| 1039 | Config->NatvisFiles = Args.getAllArgValues(OPT_natvis); | |
| 1195 | bool shouldCreatePDB = | |
| 1196 | (debug == DebugKind::Full || debug == DebugKind::GHash); | |
| 1197 | if (shouldCreatePDB) { | |
| 1198 | if (auto *arg = args.getLastArg(OPT_pdb)) | |
| 1199 | config->pdbPath = arg->getValue(); | |
| 1200 | if (auto *arg = args.getLastArg(OPT_pdbaltpath)) | |
| 1201 | config->pdbAltPath = arg->getValue(); | |
| 1202 | if (args.hasArg(OPT_natvis)) | |
| 1203 | config->natvisFiles = args.getAllArgValues(OPT_natvis); | |
| 1040 | 1204 | |
| 1041 | if (auto *Arg = Args.getLastArg(OPT_pdb_source_path)) | |
| 1042 | Config->PDBSourcePath = Arg->getValue(); | |
| 1205 | if (auto *arg = args.getLastArg(OPT_pdb_source_path)) | |
| 1206 | config->pdbSourcePath = arg->getValue(); | |
| 1043 | 1207 | } |
| 1044 | 1208 | |
| 1045 | 1209 | // Handle /noentry |
| 1046 | if (Args.hasArg(OPT_noentry)) { | |
| 1047 | if (Args.hasArg(OPT_dll)) | |
| 1048 | Config->NoEntry = true; | |
| 1210 | if (args.hasArg(OPT_noentry)) { | |
| 1211 | if (args.hasArg(OPT_dll)) | |
| 1212 | config->noEntry = true; | |
| 1049 | 1213 | else |
| 1050 | 1214 | error("/noentry must be specified with /dll"); |
| 1051 | 1215 | } |
| 1052 | 1216 | |
| 1053 | 1217 | // Handle /dll |
| 1054 | if (Args.hasArg(OPT_dll)) { | |
| 1055 | Config->DLL = true; | |
| 1056 | Config->ManifestID = 2; | |
| 1218 | if (args.hasArg(OPT_dll)) { | |
| 1219 | config->dll = true; | |
| 1220 | config->manifestID = 2; | |
| 1057 | 1221 | } |
| 1058 | 1222 | |
| 1059 | 1223 | // Handle /dynamicbase and /fixed. We can't use hasFlag for /dynamicbase |
| 1060 | 1224 | // because we need to explicitly check whether that option or its inverse was |
| 1061 | 1225 | // present in the argument list in order to handle /fixed. |
| 1062 | auto *DynamicBaseArg = Args.getLastArg(OPT_dynamicbase, OPT_dynamicbase_no); | |
| 1063 | if (DynamicBaseArg && | |
| 1064 | DynamicBaseArg->getOption().getID() == OPT_dynamicbase_no) | |
| 1065 | Config->DynamicBase = false; | |
| 1226 | auto *dynamicBaseArg = args.getLastArg(OPT_dynamicbase, OPT_dynamicbase_no); | |
| 1227 | if (dynamicBaseArg && | |
| 1228 | dynamicBaseArg->getOption().getID() == OPT_dynamicbase_no) | |
| 1229 | config->dynamicBase = false; | |
| 1066 | 1230 | |
| 1067 | 1231 | // MSDN claims "/FIXED:NO is the default setting for a DLL, and /FIXED is the |
| 1068 | 1232 | // default setting for any other project type.", but link.exe defaults to |
| 1069 | 1233 | // /FIXED:NO for exe outputs as well. Match behavior, not docs. |
| 1070 | bool Fixed = Args.hasFlag(OPT_fixed, OPT_fixed_no, false); | |
| 1071 | if (Fixed) { | |
| 1072 | if (DynamicBaseArg && | |
| 1073 | DynamicBaseArg->getOption().getID() == OPT_dynamicbase) { | |
| 1234 | bool fixed = args.hasFlag(OPT_fixed, OPT_fixed_no, false); | |
| 1235 | if (fixed) { | |
| 1236 | if (dynamicBaseArg && | |
| 1237 | dynamicBaseArg->getOption().getID() == OPT_dynamicbase) { | |
| 1074 | 1238 | error("/fixed must not be specified with /dynamicbase"); |
| 1075 | 1239 | } else { |
| 1076 | Config->Relocatable = false; | |
| 1077 | Config->DynamicBase = false; | |
| 1240 | config->relocatable = false; | |
| 1241 | config->dynamicBase = false; | |
| 1078 | 1242 | } |
| 1079 | 1243 | } |
| 1080 | 1244 | |
| 1081 | 1245 | // Handle /appcontainer |
| 1082 | Config->AppContainer = | |
| 1083 | Args.hasFlag(OPT_appcontainer, OPT_appcontainer_no, false); | |
| 1246 | config->appContainer = | |
| 1247 | args.hasFlag(OPT_appcontainer, OPT_appcontainer_no, false); | |
| 1084 | 1248 | |
| 1085 | 1249 | // Handle /machine |
| 1086 | if (auto *Arg = Args.getLastArg(OPT_machine)) | |
| 1087 | Config->Machine = getMachineType(Arg->getValue()); | |
| 1250 | if (auto *arg = args.getLastArg(OPT_machine)) { | |
| 1251 | config->machine = getMachineType(arg->getValue()); | |
| 1252 | if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) | |
| 1253 | fatal(Twine("unknown /machine argument: ") + arg->getValue()); | |
| 1254 | } | |
| 1088 | 1255 | |
| 1089 | 1256 | // Handle /nodefaultlib:<filename> |
| 1090 | for (auto *Arg : Args.filtered(OPT_nodefaultlib)) | |
| 1091 | Config->NoDefaultLibs.insert(doFindLib(Arg->getValue())); | |
| 1257 | for (auto *arg : args.filtered(OPT_nodefaultlib)) | |
| 1258 | config->noDefaultLibs.insert(doFindLib(arg->getValue()).lower()); | |
| 1092 | 1259 | |
| 1093 | 1260 | // Handle /nodefaultlib |
| 1094 | if (Args.hasArg(OPT_nodefaultlib_all)) | |
| 1095 | Config->NoDefaultLibAll = true; | |
| 1261 | if (args.hasArg(OPT_nodefaultlib_all)) | |
| 1262 | config->noDefaultLibAll = true; | |
| 1096 | 1263 | |
| 1097 | 1264 | // Handle /base |
| 1098 | if (auto *Arg = Args.getLastArg(OPT_base)) | |
| 1099 | parseNumbers(Arg->getValue(), &Config->ImageBase); | |
| 1265 | if (auto *arg = args.getLastArg(OPT_base)) | |
| 1266 | parseNumbers(arg->getValue(), &config->imageBase); | |
| 1267 | ||
| 1268 | // Handle /filealign | |
| 1269 | if (auto *arg = args.getLastArg(OPT_filealign)) { | |
| 1270 | parseNumbers(arg->getValue(), &config->fileAlign); | |
| 1271 | if (!isPowerOf2_64(config->fileAlign)) | |
| 1272 | error("/filealign: not a power of two: " + Twine(config->fileAlign)); | |
| 1273 | } | |
| 1100 | 1274 | |
| 1101 | 1275 | // Handle /stack |
| 1102 | if (auto *Arg = Args.getLastArg(OPT_stack)) | |
| 1103 | parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit); | |
| 1276 | if (auto *arg = args.getLastArg(OPT_stack)) | |
| 1277 | parseNumbers(arg->getValue(), &config->stackReserve, &config->stackCommit); | |
| 1104 | 1278 | |
| 1105 | 1279 | // Handle /guard:cf |
| 1106 | if (auto *Arg = Args.getLastArg(OPT_guard)) | |
| 1107 | parseGuard(Arg->getValue()); | |
| 1280 | if (auto *arg = args.getLastArg(OPT_guard)) | |
| 1281 | parseGuard(arg->getValue()); | |
| 1108 | 1282 | |
| 1109 | 1283 | // Handle /heap |
| 1110 | if (auto *Arg = Args.getLastArg(OPT_heap)) | |
| 1111 | parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit); | |
| 1284 | if (auto *arg = args.getLastArg(OPT_heap)) | |
| 1285 | parseNumbers(arg->getValue(), &config->heapReserve, &config->heapCommit); | |
| 1112 | 1286 | |
| 1113 | 1287 | // Handle /version |
| 1114 | if (auto *Arg = Args.getLastArg(OPT_version)) | |
| 1115 | parseVersion(Arg->getValue(), &Config->MajorImageVersion, | |
| 1116 | &Config->MinorImageVersion); | |
| 1288 | if (auto *arg = args.getLastArg(OPT_version)) | |
| 1289 | parseVersion(arg->getValue(), &config->majorImageVersion, | |
| 1290 | &config->minorImageVersion); | |
| 1117 | 1291 | |
| 1118 | 1292 | // Handle /subsystem |
| 1119 | if (auto *Arg = Args.getLastArg(OPT_subsystem)) | |
| 1120 | parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion, | |
| 1121 | &Config->MinorOSVersion); | |
| 1293 | if (auto *arg = args.getLastArg(OPT_subsystem)) | |
| 1294 | parseSubsystem(arg->getValue(), &config->subsystem, &config->majorOSVersion, | |
| 1295 | &config->minorOSVersion); | |
| 1122 | 1296 | |
| 1123 | 1297 | // Handle /timestamp |
| 1124 | if (llvm::opt::Arg *Arg = Args.getLastArg(OPT_timestamp, OPT_repro)) { | |
| 1125 | if (Arg->getOption().getID() == OPT_repro) { | |
| 1126 | Config->Timestamp = 0; | |
| 1127 | Config->Repro = true; | |
| 1298 | if (llvm::opt::Arg *arg = args.getLastArg(OPT_timestamp, OPT_repro)) { | |
| 1299 | if (arg->getOption().getID() == OPT_repro) { | |
| 1300 | config->timestamp = 0; | |
| 1301 | config->repro = true; | |
| 1128 | 1302 | } else { |
| 1129 | Config->Repro = false; | |
| 1130 | StringRef Value(Arg->getValue()); | |
| 1131 | if (Value.getAsInteger(0, Config->Timestamp)) | |
| 1132 | fatal(Twine("invalid timestamp: ") + Value + | |
| 1303 | config->repro = false; | |
| 1304 | StringRef value(arg->getValue()); | |
| 1305 | if (value.getAsInteger(0, config->timestamp)) | |
| 1306 | fatal(Twine("invalid timestamp: ") + value + | |
| 1133 | 1307 | ". Expected 32-bit integer"); |
| 1134 | 1308 | } |
| 1135 | 1309 | } else { |
| 1136 | Config->Repro = false; | |
| 1137 | Config->Timestamp = time(nullptr); | |
| 1310 | config->repro = false; | |
| 1311 | config->timestamp = time(nullptr); | |
| 1138 | 1312 | } |
| 1139 | 1313 | |
| 1140 | 1314 | // Handle /alternatename |
| 1141 | for (auto *Arg : Args.filtered(OPT_alternatename)) | |
| 1142 | parseAlternateName(Arg->getValue()); | |
| 1315 | for (auto *arg : args.filtered(OPT_alternatename)) | |
| 1316 | parseAlternateName(arg->getValue()); | |
| 1143 | 1317 | |
| 1144 | 1318 | // Handle /include |
| 1145 | for (auto *Arg : Args.filtered(OPT_incl)) | |
| 1146 | addUndefined(Arg->getValue()); | |
| 1319 | for (auto *arg : args.filtered(OPT_incl)) | |
| 1320 | addUndefined(arg->getValue()); | |
| 1147 | 1321 | |
| 1148 | 1322 | // Handle /implib |
| 1149 | if (auto *Arg = Args.getLastArg(OPT_implib)) | |
| 1150 | Config->Implib = Arg->getValue(); | |
| 1323 | if (auto *arg = args.getLastArg(OPT_implib)) | |
| 1324 | config->implib = arg->getValue(); | |
| 1151 | 1325 | |
| 1152 | 1326 | // Handle /opt. |
| 1153 | bool DoGC = Debug == DebugKind::None || Args.hasArg(OPT_profile); | |
| 1154 | unsigned ICFLevel = | |
| 1155 | Args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on | |
| 1156 | unsigned TailMerge = 1; | |
| 1157 | for (auto *Arg : Args.filtered(OPT_opt)) { | |
| 1158 | std::string Str = StringRef(Arg->getValue()).lower(); | |
| 1159 | SmallVector<StringRef, 1> Vec; | |
| 1160 | StringRef(Str).split(Vec, ','); | |
| 1161 | for (StringRef S : Vec) { | |
| 1162 | if (S == "ref") { | |
| 1163 | DoGC = true; | |
| 1164 | } else if (S == "noref") { | |
| 1165 | DoGC = false; | |
| 1166 | } else if (S == "icf" || S.startswith("icf=")) { | |
| 1167 | ICFLevel = 2; | |
| 1168 | } else if (S == "noicf") { | |
| 1169 | ICFLevel = 0; | |
| 1170 | } else if (S == "lldtailmerge") { | |
| 1171 | TailMerge = 2; | |
| 1172 | } else if (S == "nolldtailmerge") { | |
| 1173 | TailMerge = 0; | |
| 1174 | } else if (S.startswith("lldlto=")) { | |
| 1175 | StringRef OptLevel = S.substr(7); | |
| 1176 | if (OptLevel.getAsInteger(10, Config->LTOO) || Config->LTOO > 3) | |
| 1177 | error("/opt:lldlto: invalid optimization level: " + OptLevel); | |
| 1178 | } else if (S.startswith("lldltojobs=")) { | |
| 1179 | StringRef Jobs = S.substr(11); | |
| 1180 | if (Jobs.getAsInteger(10, Config->ThinLTOJobs) || | |
| 1181 | Config->ThinLTOJobs == 0) | |
| 1182 | error("/opt:lldltojobs: invalid job count: " + Jobs); | |
| 1183 | } else if (S.startswith("lldltopartitions=")) { | |
| 1184 | StringRef N = S.substr(17); | |
| 1185 | if (N.getAsInteger(10, Config->LTOPartitions) || | |
| 1186 | Config->LTOPartitions == 0) | |
| 1187 | error("/opt:lldltopartitions: invalid partition count: " + N); | |
| 1188 | } else if (S != "lbr" && S != "nolbr") | |
| 1189 | error("/opt: unknown option: " + S); | |
| 1327 | bool doGC = debug == DebugKind::None || args.hasArg(OPT_profile); | |
| 1328 | unsigned icfLevel = | |
| 1329 | args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on | |
| 1330 | unsigned tailMerge = 1; | |
| 1331 | for (auto *arg : args.filtered(OPT_opt)) { | |
| 1332 | std::string str = StringRef(arg->getValue()).lower(); | |
| 1333 | SmallVector<StringRef, 1> vec; | |
| 1334 | StringRef(str).split(vec, ','); | |
| 1335 | for (StringRef s : vec) { | |
| 1336 | if (s == "ref") { | |
| 1337 | doGC = true; | |
| 1338 | } else if (s == "noref") { | |
| 1339 | doGC = false; | |
| 1340 | } else if (s == "icf" || s.startswith("icf=")) { | |
| 1341 | icfLevel = 2; | |
| 1342 | } else if (s == "noicf") { | |
| 1343 | icfLevel = 0; | |
| 1344 | } else if (s == "lldtailmerge") { | |
| 1345 | tailMerge = 2; | |
| 1346 | } else if (s == "nolldtailmerge") { | |
| 1347 | tailMerge = 0; | |
| 1348 | } else if (s.startswith("lldlto=")) { | |
| 1349 | StringRef optLevel = s.substr(7); | |
| 1350 | if (optLevel.getAsInteger(10, config->ltoo) || config->ltoo > 3) | |
| 1351 | error("/opt:lldlto: invalid optimization level: " + optLevel); | |
| 1352 | } else if (s.startswith("lldltojobs=")) { | |
| 1353 | StringRef jobs = s.substr(11); | |
| 1354 | if (jobs.getAsInteger(10, config->thinLTOJobs) || | |
| 1355 | config->thinLTOJobs == 0) | |
| 1356 | error("/opt:lldltojobs: invalid job count: " + jobs); | |
| 1357 | } else if (s.startswith("lldltopartitions=")) { | |
| 1358 | StringRef n = s.substr(17); | |
| 1359 | if (n.getAsInteger(10, config->ltoPartitions) || | |
| 1360 | config->ltoPartitions == 0) | |
| 1361 | error("/opt:lldltopartitions: invalid partition count: " + n); | |
| 1362 | } else if (s != "lbr" && s != "nolbr") | |
| 1363 | error("/opt: unknown option: " + s); | |
| 1190 | 1364 | } |
| 1191 | 1365 | } |
| 1192 | 1366 | |
| ... | ... | @@ -1195,37 +1369,37 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { |
| 1195 | 1369 | // FIXME: LLD only implements "limited" ICF, i.e. it only merges identical |
| 1196 | 1370 | // code. If the user passes /OPT:ICF explicitly, LLD should merge identical |
| 1197 | 1371 | // comdat readonly data. |
| 1198 | if (ICFLevel == 1 && !DoGC) | |
| 1199 | ICFLevel = 0; | |
| 1200 | Config->DoGC = DoGC; | |
| 1201 | Config->DoICF = ICFLevel > 0; | |
| 1202 | Config->TailMerge = (TailMerge == 1 && Config->DoICF) || TailMerge == 2; | |
| 1372 | if (icfLevel == 1 && !doGC) | |
| 1373 | icfLevel = 0; | |
| 1374 | config->doGC = doGC; | |
| 1375 | config->doICF = icfLevel > 0; | |
| 1376 | config->tailMerge = (tailMerge == 1 && config->doICF) || tailMerge == 2; | |
| 1203 | 1377 | |
| 1204 | 1378 | // Handle /lldsavetemps |
| 1205 | if (Args.hasArg(OPT_lldsavetemps)) | |
| 1206 | Config->SaveTemps = true; | |
| 1379 | if (args.hasArg(OPT_lldsavetemps)) | |
| 1380 | config->saveTemps = true; | |
| 1207 | 1381 | |
| 1208 | 1382 | // Handle /kill-at |
| 1209 | if (Args.hasArg(OPT_kill_at)) | |
| 1210 | Config->KillAt = true; | |
| 1383 | if (args.hasArg(OPT_kill_at)) | |
| 1384 | config->killAt = true; | |
| 1211 | 1385 | |
| 1212 | 1386 | // Handle /lldltocache |
| 1213 | if (auto *Arg = Args.getLastArg(OPT_lldltocache)) | |
| 1214 | Config->LTOCache = Arg->getValue(); | |
| 1387 | if (auto *arg = args.getLastArg(OPT_lldltocache)) | |
| 1388 | config->ltoCache = arg->getValue(); | |
| 1215 | 1389 | |
| 1216 | 1390 | // Handle /lldsavecachepolicy |
| 1217 | if (auto *Arg = Args.getLastArg(OPT_lldltocachepolicy)) | |
| 1218 | Config->LTOCachePolicy = CHECK( | |
| 1219 | parseCachePruningPolicy(Arg->getValue()), | |
| 1220 | Twine("/lldltocachepolicy: invalid cache policy: ") + Arg->getValue()); | |
| 1391 | if (auto *arg = args.getLastArg(OPT_lldltocachepolicy)) | |
| 1392 | config->ltoCachePolicy = CHECK( | |
| 1393 | parseCachePruningPolicy(arg->getValue()), | |
| 1394 | Twine("/lldltocachepolicy: invalid cache policy: ") + arg->getValue()); | |
| 1221 | 1395 | |
| 1222 | 1396 | // Handle /failifmismatch |
| 1223 | for (auto *Arg : Args.filtered(OPT_failifmismatch)) | |
| 1224 | checkFailIfMismatch(Arg->getValue()); | |
| 1397 | for (auto *arg : args.filtered(OPT_failifmismatch)) | |
| 1398 | checkFailIfMismatch(arg->getValue(), nullptr); | |
| 1225 | 1399 | |
| 1226 | 1400 | // Handle /merge |
| 1227 | for (auto *Arg : Args.filtered(OPT_merge)) | |
| 1228 | parseMerge(Arg->getValue()); | |
| 1401 | for (auto *arg : args.filtered(OPT_merge)) | |
| 1402 | parseMerge(arg->getValue()); | |
| 1229 | 1403 | |
| 1230 | 1404 | // Add default section merging rules after user rules. User rules take |
| 1231 | 1405 | // precedence, but we will emit a warning if there is a conflict. |
| ... | ... | @@ -1235,130 +1409,137 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { |
| 1235 | 1409 | parseMerge(".xdata=.rdata"); |
| 1236 | 1410 | parseMerge(".bss=.data"); |
| 1237 | 1411 | |
| 1238 | if (Config->MinGW) { | |
| 1412 | if (config->mingw) { | |
| 1239 | 1413 | parseMerge(".ctors=.rdata"); |
| 1240 | 1414 | parseMerge(".dtors=.rdata"); |
| 1241 | 1415 | parseMerge(".CRT=.rdata"); |
| 1242 | 1416 | } |
| 1243 | 1417 | |
| 1244 | 1418 | // Handle /section |
| 1245 | for (auto *Arg : Args.filtered(OPT_section)) | |
| 1246 | parseSection(Arg->getValue()); | |
| 1419 | for (auto *arg : args.filtered(OPT_section)) | |
| 1420 | parseSection(arg->getValue()); | |
| 1247 | 1421 | |
| 1248 | 1422 | // Handle /aligncomm |
| 1249 | for (auto *Arg : Args.filtered(OPT_aligncomm)) | |
| 1250 | parseAligncomm(Arg->getValue()); | |
| 1423 | for (auto *arg : args.filtered(OPT_aligncomm)) | |
| 1424 | parseAligncomm(arg->getValue()); | |
| 1251 | 1425 | |
| 1252 | 1426 | // Handle /manifestdependency. This enables /manifest unless /manifest:no is |
| 1253 | 1427 | // also passed. |
| 1254 | if (auto *Arg = Args.getLastArg(OPT_manifestdependency)) { | |
| 1255 | Config->ManifestDependency = Arg->getValue(); | |
| 1256 | Config->Manifest = Configuration::SideBySide; | |
| 1428 | if (auto *arg = args.getLastArg(OPT_manifestdependency)) { | |
| 1429 | config->manifestDependency = arg->getValue(); | |
| 1430 | config->manifest = Configuration::SideBySide; | |
| 1257 | 1431 | } |
| 1258 | 1432 | |
| 1259 | 1433 | // Handle /manifest and /manifest: |
| 1260 | if (auto *Arg = Args.getLastArg(OPT_manifest, OPT_manifest_colon)) { | |
| 1261 | if (Arg->getOption().getID() == OPT_manifest) | |
| 1262 | Config->Manifest = Configuration::SideBySide; | |
| 1434 | if (auto *arg = args.getLastArg(OPT_manifest, OPT_manifest_colon)) { | |
| 1435 | if (arg->getOption().getID() == OPT_manifest) | |
| 1436 | config->manifest = Configuration::SideBySide; | |
| 1263 | 1437 | else |
| 1264 | parseManifest(Arg->getValue()); | |
| 1438 | parseManifest(arg->getValue()); | |
| 1265 | 1439 | } |
| 1266 | 1440 | |
| 1267 | 1441 | // Handle /manifestuac |
| 1268 | if (auto *Arg = Args.getLastArg(OPT_manifestuac)) | |
| 1269 | parseManifestUAC(Arg->getValue()); | |
| 1442 | if (auto *arg = args.getLastArg(OPT_manifestuac)) | |
| 1443 | parseManifestUAC(arg->getValue()); | |
| 1270 | 1444 | |
| 1271 | 1445 | // Handle /manifestfile |
| 1272 | if (auto *Arg = Args.getLastArg(OPT_manifestfile)) | |
| 1273 | Config->ManifestFile = Arg->getValue(); | |
| 1446 | if (auto *arg = args.getLastArg(OPT_manifestfile)) | |
| 1447 | config->manifestFile = arg->getValue(); | |
| 1274 | 1448 | |
| 1275 | 1449 | // Handle /manifestinput |
| 1276 | for (auto *Arg : Args.filtered(OPT_manifestinput)) | |
| 1277 | Config->ManifestInput.push_back(Arg->getValue()); | |
| 1450 | for (auto *arg : args.filtered(OPT_manifestinput)) | |
| 1451 | config->manifestInput.push_back(arg->getValue()); | |
| 1278 | 1452 | |
| 1279 | if (!Config->ManifestInput.empty() && | |
| 1280 | Config->Manifest != Configuration::Embed) { | |
| 1453 | if (!config->manifestInput.empty() && | |
| 1454 | config->manifest != Configuration::Embed) { | |
| 1281 | 1455 | fatal("/manifestinput: requires /manifest:embed"); |
| 1282 | 1456 | } |
| 1283 | 1457 | |
| 1458 | config->thinLTOEmitImportsFiles = args.hasArg(OPT_thinlto_emit_imports_files); | |
| 1459 | config->thinLTOIndexOnly = args.hasArg(OPT_thinlto_index_only) || | |
| 1460 | args.hasArg(OPT_thinlto_index_only_arg); | |
| 1461 | config->thinLTOIndexOnlyArg = | |
| 1462 | args.getLastArgValue(OPT_thinlto_index_only_arg); | |
| 1463 | config->thinLTOPrefixReplace = | |
| 1464 | getOldNewOptions(args, OPT_thinlto_prefix_replace); | |
| 1465 | config->thinLTOObjectSuffixReplace = | |
| 1466 | getOldNewOptions(args, OPT_thinlto_object_suffix_replace); | |
| 1284 | 1467 | // Handle miscellaneous boolean flags. |
| 1285 | Config->AllowBind = Args.hasFlag(OPT_allowbind, OPT_allowbind_no, true); | |
| 1286 | Config->AllowIsolation = | |
| 1287 | Args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true); | |
| 1288 | Config->Incremental = | |
| 1289 | Args.hasFlag(OPT_incremental, OPT_incremental_no, | |
| 1290 | !Config->DoGC && !Config->DoICF && !Args.hasArg(OPT_order) && | |
| 1291 | !Args.hasArg(OPT_profile)); | |
| 1292 | Config->IntegrityCheck = | |
| 1293 | Args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false); | |
| 1294 | Config->NxCompat = Args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true); | |
| 1295 | Config->TerminalServerAware = | |
| 1296 | !Config->DLL && Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true); | |
| 1297 | Config->DebugDwarf = Debug == DebugKind::Dwarf; | |
| 1298 | Config->DebugGHashes = Debug == DebugKind::GHash; | |
| 1299 | Config->DebugSymtab = Debug == DebugKind::Symtab; | |
| 1300 | ||
| 1301 | Config->MapFile = getMapFile(Args); | |
| 1302 | ||
| 1303 | if (Config->Incremental && Args.hasArg(OPT_profile)) { | |
| 1468 | config->allowBind = args.hasFlag(OPT_allowbind, OPT_allowbind_no, true); | |
| 1469 | config->allowIsolation = | |
| 1470 | args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true); | |
| 1471 | config->incremental = | |
| 1472 | args.hasFlag(OPT_incremental, OPT_incremental_no, | |
| 1473 | !config->doGC && !config->doICF && !args.hasArg(OPT_order) && | |
| 1474 | !args.hasArg(OPT_profile)); | |
| 1475 | config->integrityCheck = | |
| 1476 | args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false); | |
| 1477 | config->nxCompat = args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true); | |
| 1478 | for (auto *arg : args.filtered(OPT_swaprun)) | |
| 1479 | parseSwaprun(arg->getValue()); | |
| 1480 | config->terminalServerAware = | |
| 1481 | !config->dll && args.hasFlag(OPT_tsaware, OPT_tsaware_no, true); | |
| 1482 | config->debugDwarf = debug == DebugKind::Dwarf; | |
| 1483 | config->debugGHashes = debug == DebugKind::GHash; | |
| 1484 | config->debugSymtab = debug == DebugKind::Symtab; | |
| 1485 | ||
| 1486 | config->mapFile = getMapFile(args); | |
| 1487 | ||
| 1488 | if (config->incremental && args.hasArg(OPT_profile)) { | |
| 1304 | 1489 | warn("ignoring '/incremental' due to '/profile' specification"); |
| 1305 | Config->Incremental = false; | |
| 1490 | config->incremental = false; | |
| 1306 | 1491 | } |
| 1307 | 1492 | |
| 1308 | if (Config->Incremental && Args.hasArg(OPT_order)) { | |
| 1493 | if (config->incremental && args.hasArg(OPT_order)) { | |
| 1309 | 1494 | warn("ignoring '/incremental' due to '/order' specification"); |
| 1310 | Config->Incremental = false; | |
| 1495 | config->incremental = false; | |
| 1311 | 1496 | } |
| 1312 | 1497 | |
| 1313 | if (Config->Incremental && Config->DoGC) { | |
| 1498 | if (config->incremental && config->doGC) { | |
| 1314 | 1499 | warn("ignoring '/incremental' because REF is enabled; use '/opt:noref' to " |
| 1315 | 1500 | "disable"); |
| 1316 | Config->Incremental = false; | |
| 1501 | config->incremental = false; | |
| 1317 | 1502 | } |
| 1318 | 1503 | |
| 1319 | if (Config->Incremental && Config->DoICF) { | |
| 1504 | if (config->incremental && config->doICF) { | |
| 1320 | 1505 | warn("ignoring '/incremental' because ICF is enabled; use '/opt:noicf' to " |
| 1321 | 1506 | "disable"); |
| 1322 | Config->Incremental = false; | |
| 1507 | config->incremental = false; | |
| 1323 | 1508 | } |
| 1324 | 1509 | |
| 1325 | 1510 | if (errorCount()) |
| 1326 | 1511 | return; |
| 1327 | 1512 | |
| 1328 | std::set<sys::fs::UniqueID> WholeArchives; | |
| 1329 | AutoExporter Exporter; | |
| 1330 | for (auto *Arg : Args.filtered(OPT_wholearchive_file)) { | |
| 1331 | if (Optional<StringRef> Path = doFindFile(Arg->getValue())) { | |
| 1332 | if (Optional<sys::fs::UniqueID> ID = getUniqueID(*Path)) | |
| 1333 | WholeArchives.insert(*ID); | |
| 1334 | Exporter.addWholeArchive(*Path); | |
| 1335 | } | |
| 1336 | } | |
| 1513 | std::set<sys::fs::UniqueID> wholeArchives; | |
| 1514 | for (auto *arg : args.filtered(OPT_wholearchive_file)) | |
| 1515 | if (Optional<StringRef> path = doFindFile(arg->getValue())) | |
| 1516 | if (Optional<sys::fs::UniqueID> id = getUniqueID(*path)) | |
| 1517 | wholeArchives.insert(*id); | |
| 1337 | 1518 | |
| 1338 | 1519 | // A predicate returning true if a given path is an argument for |
| 1339 | 1520 | // /wholearchive:, or /wholearchive is enabled globally. |
| 1340 | 1521 | // This function is a bit tricky because "foo.obj /wholearchive:././foo.obj" |
| 1341 | 1522 | // needs to be handled as "/wholearchive:foo.obj foo.obj". |
| 1342 | auto IsWholeArchive = [&](StringRef Path) -> bool { | |
| 1343 | if (Args.hasArg(OPT_wholearchive_flag)) | |
| 1523 | auto isWholeArchive = [&](StringRef path) -> bool { | |
| 1524 | if (args.hasArg(OPT_wholearchive_flag)) | |
| 1344 | 1525 | return true; |
| 1345 | if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path)) | |
| 1346 | return WholeArchives.count(*ID); | |
| 1526 | if (Optional<sys::fs::UniqueID> id = getUniqueID(path)) | |
| 1527 | return wholeArchives.count(*id); | |
| 1347 | 1528 | return false; |
| 1348 | 1529 | }; |
| 1349 | 1530 | |
| 1350 | 1531 | // Create a list of input files. Files can be given as arguments |
| 1351 | 1532 | // for /defaultlib option. |
| 1352 | for (auto *Arg : Args.filtered(OPT_INPUT, OPT_wholearchive_file)) | |
| 1353 | if (Optional<StringRef> Path = findFile(Arg->getValue())) | |
| 1354 | enqueuePath(*Path, IsWholeArchive(*Path)); | |
| 1533 | for (auto *arg : args.filtered(OPT_INPUT, OPT_wholearchive_file)) | |
| 1534 | if (Optional<StringRef> path = findFile(arg->getValue())) | |
| 1535 | enqueuePath(*path, isWholeArchive(*path)); | |
| 1355 | 1536 | |
| 1356 | for (auto *Arg : Args.filtered(OPT_defaultlib)) | |
| 1357 | if (Optional<StringRef> Path = findLib(Arg->getValue())) | |
| 1358 | enqueuePath(*Path, false); | |
| 1537 | for (auto *arg : args.filtered(OPT_defaultlib)) | |
| 1538 | if (Optional<StringRef> path = findLib(arg->getValue())) | |
| 1539 | enqueuePath(*path, false); | |
| 1359 | 1540 | |
| 1360 | 1541 | // Windows specific -- Create a resource file containing a manifest file. |
| 1361 | if (Config->Manifest == Configuration::Embed) | |
| 1542 | if (config->manifest == Configuration::Embed) | |
| 1362 | 1543 | addBuffer(createManifestRes(), false); |
| 1363 | 1544 | |
| 1364 | 1545 | // Read all input files given via the command line. |
| ... | ... | @@ -1369,154 +1550,169 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { |
| 1369 | 1550 | |
| 1370 | 1551 | // We should have inferred a machine type by now from the input files, but if |
| 1371 | 1552 | // not we assume x64. |
| 1372 | if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { | |
| 1553 | if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) { | |
| 1373 | 1554 | warn("/machine is not specified. x64 is assumed"); |
| 1374 | Config->Machine = AMD64; | |
| 1555 | config->machine = AMD64; | |
| 1375 | 1556 | } |
| 1376 | Config->Wordsize = Config->is64() ? 8 : 4; | |
| 1557 | config->wordsize = config->is64() ? 8 : 4; | |
| 1558 | ||
| 1559 | // Handle /safeseh, x86 only, on by default, except for mingw. | |
| 1560 | if (config->machine == I386 && | |
| 1561 | args.hasFlag(OPT_safeseh, OPT_safeseh_no, !config->mingw)) | |
| 1562 | config->safeSEH = true; | |
| 1563 | ||
| 1564 | // Handle /functionpadmin | |
| 1565 | for (auto *arg : args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt)) | |
| 1566 | parseFunctionPadMin(arg, config->machine); | |
| 1377 | 1567 | |
| 1378 | 1568 | // Input files can be Windows resource files (.res files). We use |
| 1379 | 1569 | // WindowsResource to convert resource files to a regular COFF file, |
| 1380 | 1570 | // then link the resulting file normally. |
| 1381 | if (!Resources.empty()) | |
| 1382 | Symtab->addFile(make<ObjFile>(convertResToCOFF(Resources))); | |
| 1571 | if (!resources.empty()) | |
| 1572 | symtab->addFile(make<ObjFile>(convertResToCOFF(resources))); | |
| 1383 | 1573 | |
| 1384 | if (Tar) | |
| 1385 | Tar->append("response.txt", | |
| 1386 | createResponseFile(Args, FilePaths, | |
| 1387 | ArrayRef<StringRef>(SearchPaths).slice(1))); | |
| 1574 | if (tar) | |
| 1575 | tar->append("response.txt", | |
| 1576 | createResponseFile(args, filePaths, | |
| 1577 | ArrayRef<StringRef>(searchPaths).slice(1))); | |
| 1388 | 1578 | |
| 1389 | 1579 | // Handle /largeaddressaware |
| 1390 | Config->LargeAddressAware = Args.hasFlag( | |
| 1391 | OPT_largeaddressaware, OPT_largeaddressaware_no, Config->is64()); | |
| 1580 | config->largeAddressAware = args.hasFlag( | |
| 1581 | OPT_largeaddressaware, OPT_largeaddressaware_no, config->is64()); | |
| 1392 | 1582 | |
| 1393 | 1583 | // Handle /highentropyva |
| 1394 | Config->HighEntropyVA = | |
| 1395 | Config->is64() && | |
| 1396 | Args.hasFlag(OPT_highentropyva, OPT_highentropyva_no, true); | |
| 1584 | config->highEntropyVA = | |
| 1585 | config->is64() && | |
| 1586 | args.hasFlag(OPT_highentropyva, OPT_highentropyva_no, true); | |
| 1397 | 1587 | |
| 1398 | if (!Config->DynamicBase && | |
| 1399 | (Config->Machine == ARMNT || Config->Machine == ARM64)) | |
| 1588 | if (!config->dynamicBase && | |
| 1589 | (config->machine == ARMNT || config->machine == ARM64)) | |
| 1400 | 1590 | error("/dynamicbase:no is not compatible with " + |
| 1401 | machineToStr(Config->Machine)); | |
| 1591 | machineToStr(config->machine)); | |
| 1402 | 1592 | |
| 1403 | 1593 | // Handle /export |
| 1404 | for (auto *Arg : Args.filtered(OPT_export)) { | |
| 1405 | Export E = parseExport(Arg->getValue()); | |
| 1406 | if (Config->Machine == I386) { | |
| 1407 | if (!isDecorated(E.Name)) | |
| 1408 | E.Name = Saver.save("_" + E.Name); | |
| 1409 | if (!E.ExtName.empty() && !isDecorated(E.ExtName)) | |
| 1410 | E.ExtName = Saver.save("_" + E.ExtName); | |
| 1594 | for (auto *arg : args.filtered(OPT_export)) { | |
| 1595 | Export e = parseExport(arg->getValue()); | |
| 1596 | if (config->machine == I386) { | |
| 1597 | if (!isDecorated(e.name)) | |
| 1598 | e.name = saver.save("_" + e.name); | |
| 1599 | if (!e.extName.empty() && !isDecorated(e.extName)) | |
| 1600 | e.extName = saver.save("_" + e.extName); | |
| 1411 | 1601 | } |
| 1412 | Config->Exports.push_back(E); | |
| 1602 | config->exports.push_back(e); | |
| 1413 | 1603 | } |
| 1414 | 1604 | |
| 1415 | 1605 | // Handle /def |
| 1416 | if (auto *Arg = Args.getLastArg(OPT_deffile)) { | |
| 1606 | if (auto *arg = args.getLastArg(OPT_deffile)) { | |
| 1417 | 1607 | // parseModuleDefs mutates Config object. |
| 1418 | parseModuleDefs(Arg->getValue()); | |
| 1608 | parseModuleDefs(arg->getValue()); | |
| 1419 | 1609 | } |
| 1420 | 1610 | |
| 1421 | 1611 | // Handle generation of import library from a def file. |
| 1422 | if (!Args.hasArg(OPT_INPUT)) { | |
| 1612 | if (!args.hasArg(OPT_INPUT)) { | |
| 1423 | 1613 | fixupExports(); |
| 1424 | createImportLibrary(/*AsLib=*/true); | |
| 1614 | createImportLibrary(/*asLib=*/true); | |
| 1425 | 1615 | return; |
| 1426 | 1616 | } |
| 1427 | 1617 | |
| 1428 | 1618 | // Windows specific -- if no /subsystem is given, we need to infer |
| 1429 | 1619 | // that from entry point name. Must happen before /entry handling, |
| 1430 | 1620 | // and after the early return when just writing an import library. |
| 1431 | if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { | |
| 1432 | Config->Subsystem = inferSubsystem(); | |
| 1433 | if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) | |
| 1621 | if (config->subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { | |
| 1622 | config->subsystem = inferSubsystem(); | |
| 1623 | if (config->subsystem == IMAGE_SUBSYSTEM_UNKNOWN) | |
| 1434 | 1624 | fatal("subsystem must be defined"); |
| 1435 | 1625 | } |
| 1436 | 1626 | |
| 1437 | 1627 | // Handle /entry and /dll |
| 1438 | if (auto *Arg = Args.getLastArg(OPT_entry)) { | |
| 1439 | Config->Entry = addUndefined(mangle(Arg->getValue())); | |
| 1440 | } else if (!Config->Entry && !Config->NoEntry) { | |
| 1441 | if (Args.hasArg(OPT_dll)) { | |
| 1442 | StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12" | |
| 1628 | if (auto *arg = args.getLastArg(OPT_entry)) { | |
| 1629 | config->entry = addUndefined(mangle(arg->getValue())); | |
| 1630 | } else if (!config->entry && !config->noEntry) { | |
| 1631 | if (args.hasArg(OPT_dll)) { | |
| 1632 | StringRef s = (config->machine == I386) ? "__DllMainCRTStartup@12" | |
| 1443 | 1633 | : "_DllMainCRTStartup"; |
| 1444 | Config->Entry = addUndefined(S); | |
| 1634 | config->entry = addUndefined(s); | |
| 1445 | 1635 | } else { |
| 1446 | 1636 | // Windows specific -- If entry point name is not given, we need to |
| 1447 | 1637 | // infer that from user-defined entry name. |
| 1448 | StringRef S = findDefaultEntry(); | |
| 1449 | if (S.empty()) | |
| 1638 | StringRef s = findDefaultEntry(); | |
| 1639 | if (s.empty()) | |
| 1450 | 1640 | fatal("entry point must be defined"); |
| 1451 | Config->Entry = addUndefined(S); | |
| 1452 | log("Entry name inferred: " + S); | |
| 1641 | config->entry = addUndefined(s); | |
| 1642 | log("Entry name inferred: " + s); | |
| 1453 | 1643 | } |
| 1454 | 1644 | } |
| 1455 | 1645 | |
| 1456 | 1646 | // Handle /delayload |
| 1457 | for (auto *Arg : Args.filtered(OPT_delayload)) { | |
| 1458 | Config->DelayLoads.insert(StringRef(Arg->getValue()).lower()); | |
| 1459 | if (Config->Machine == I386) { | |
| 1460 | Config->DelayLoadHelper = addUndefined("___delayLoadHelper2@8"); | |
| 1647 | for (auto *arg : args.filtered(OPT_delayload)) { | |
| 1648 | config->delayLoads.insert(StringRef(arg->getValue()).lower()); | |
| 1649 | if (config->machine == I386) { | |
| 1650 | config->delayLoadHelper = addUndefined("___delayLoadHelper2@8"); | |
| 1461 | 1651 | } else { |
| 1462 | Config->DelayLoadHelper = addUndefined("__delayLoadHelper2"); | |
| 1652 | config->delayLoadHelper = addUndefined("__delayLoadHelper2"); | |
| 1463 | 1653 | } |
| 1464 | 1654 | } |
| 1465 | 1655 | |
| 1466 | 1656 | // Set default image name if neither /out or /def set it. |
| 1467 | if (Config->OutputFile.empty()) { | |
| 1468 | Config->OutputFile = | |
| 1469 | getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue()); | |
| 1657 | if (config->outputFile.empty()) { | |
| 1658 | config->outputFile = | |
| 1659 | getOutputPath((*args.filtered(OPT_INPUT).begin())->getValue()); | |
| 1470 | 1660 | } |
| 1471 | 1661 | |
| 1472 | if (ShouldCreatePDB) { | |
| 1662 | // Fail early if an output file is not writable. | |
| 1663 | if (auto e = tryCreateFile(config->outputFile)) { | |
| 1664 | error("cannot open output file " + config->outputFile + ": " + e.message()); | |
| 1665 | return; | |
| 1666 | } | |
| 1667 | ||
| 1668 | if (shouldCreatePDB) { | |
| 1473 | 1669 | // Put the PDB next to the image if no /pdb flag was passed. |
| 1474 | if (Config->PDBPath.empty()) { | |
| 1475 | Config->PDBPath = Config->OutputFile; | |
| 1476 | sys::path::replace_extension(Config->PDBPath, ".pdb"); | |
| 1670 | if (config->pdbPath.empty()) { | |
| 1671 | config->pdbPath = config->outputFile; | |
| 1672 | sys::path::replace_extension(config->pdbPath, ".pdb"); | |
| 1477 | 1673 | } |
| 1478 | 1674 | |
| 1479 | 1675 | // The embedded PDB path should be the absolute path to the PDB if no |
| 1480 | 1676 | // /pdbaltpath flag was passed. |
| 1481 | if (Config->PDBAltPath.empty()) { | |
| 1482 | Config->PDBAltPath = Config->PDBPath; | |
| 1677 | if (config->pdbAltPath.empty()) { | |
| 1678 | config->pdbAltPath = config->pdbPath; | |
| 1483 | 1679 | |
| 1484 | 1680 | // It's important to make the path absolute and remove dots. This path |
| 1485 | 1681 | // will eventually be written into the PE header, and certain Microsoft |
| 1486 | 1682 | // tools won't work correctly if these assumptions are not held. |
| 1487 | sys::fs::make_absolute(Config->PDBAltPath); | |
| 1488 | sys::path::remove_dots(Config->PDBAltPath); | |
| 1683 | sys::fs::make_absolute(config->pdbAltPath); | |
| 1684 | sys::path::remove_dots(config->pdbAltPath); | |
| 1489 | 1685 | } else { |
| 1490 | 1686 | // Don't do this earlier, so that Config->OutputFile is ready. |
| 1491 | parsePDBAltPath(Config->PDBAltPath); | |
| 1687 | parsePDBAltPath(config->pdbAltPath); | |
| 1492 | 1688 | } |
| 1493 | 1689 | } |
| 1494 | 1690 | |
| 1495 | 1691 | // Set default image base if /base is not given. |
| 1496 | if (Config->ImageBase == uint64_t(-1)) | |
| 1497 | Config->ImageBase = getDefaultImageBase(); | |
| 1498 | ||
| 1499 | Symtab->addSynthetic(mangle("__ImageBase"), nullptr); | |
| 1500 | if (Config->Machine == I386) { | |
| 1501 | Symtab->addAbsolute("___safe_se_handler_table", 0); | |
| 1502 | Symtab->addAbsolute("___safe_se_handler_count", 0); | |
| 1503 | } | |
| 1504 | ||
| 1505 | Symtab->addAbsolute(mangle("__guard_fids_count"), 0); | |
| 1506 | Symtab->addAbsolute(mangle("__guard_fids_table"), 0); | |
| 1507 | Symtab->addAbsolute(mangle("__guard_flags"), 0); | |
| 1508 | Symtab->addAbsolute(mangle("__guard_iat_count"), 0); | |
| 1509 | Symtab->addAbsolute(mangle("__guard_iat_table"), 0); | |
| 1510 | Symtab->addAbsolute(mangle("__guard_longjmp_count"), 0); | |
| 1511 | Symtab->addAbsolute(mangle("__guard_longjmp_table"), 0); | |
| 1692 | if (config->imageBase == uint64_t(-1)) | |
| 1693 | config->imageBase = getDefaultImageBase(); | |
| 1694 | ||
| 1695 | symtab->addSynthetic(mangle("__ImageBase"), nullptr); | |
| 1696 | if (config->machine == I386) { | |
| 1697 | symtab->addAbsolute("___safe_se_handler_table", 0); | |
| 1698 | symtab->addAbsolute("___safe_se_handler_count", 0); | |
| 1699 | } | |
| 1700 | ||
| 1701 | symtab->addAbsolute(mangle("__guard_fids_count"), 0); | |
| 1702 | symtab->addAbsolute(mangle("__guard_fids_table"), 0); | |
| 1703 | symtab->addAbsolute(mangle("__guard_flags"), 0); | |
| 1704 | symtab->addAbsolute(mangle("__guard_iat_count"), 0); | |
| 1705 | symtab->addAbsolute(mangle("__guard_iat_table"), 0); | |
| 1706 | symtab->addAbsolute(mangle("__guard_longjmp_count"), 0); | |
| 1707 | symtab->addAbsolute(mangle("__guard_longjmp_table"), 0); | |
| 1512 | 1708 | // Needed for MSVC 2017 15.5 CRT. |
| 1513 | Symtab->addAbsolute(mangle("__enclave_config"), 0); | |
| 1709 | symtab->addAbsolute(mangle("__enclave_config"), 0); | |
| 1514 | 1710 | |
| 1515 | if (Config->MinGW) { | |
| 1516 | Symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0); | |
| 1517 | Symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0); | |
| 1518 | Symtab->addAbsolute(mangle("__CTOR_LIST__"), 0); | |
| 1519 | Symtab->addAbsolute(mangle("__DTOR_LIST__"), 0); | |
| 1711 | if (config->mingw) { | |
| 1712 | symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0); | |
| 1713 | symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0); | |
| 1714 | symtab->addAbsolute(mangle("__CTOR_LIST__"), 0); | |
| 1715 | symtab->addAbsolute(mangle("__DTOR_LIST__"), 0); | |
| 1520 | 1716 | } |
| 1521 | 1717 | |
| 1522 | 1718 | // This code may add new undefined symbols to the link, which may enqueue more |
| ... | ... | @@ -1525,33 +1721,33 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { |
| 1525 | 1721 | do { |
| 1526 | 1722 | // Windows specific -- if entry point is not found, |
| 1527 | 1723 | // search for its mangled names. |
| 1528 | if (Config->Entry) | |
| 1529 | Symtab->mangleMaybe(Config->Entry); | |
| 1724 | if (config->entry) | |
| 1725 | mangleMaybe(config->entry); | |
| 1530 | 1726 | |
| 1531 | 1727 | // Windows specific -- Make sure we resolve all dllexported symbols. |
| 1532 | for (Export &E : Config->Exports) { | |
| 1533 | if (!E.ForwardTo.empty()) | |
| 1728 | for (Export &e : config->exports) { | |
| 1729 | if (!e.forwardTo.empty()) | |
| 1534 | 1730 | continue; |
| 1535 | E.Sym = addUndefined(E.Name); | |
| 1536 | if (!E.Directives) | |
| 1537 | Symtab->mangleMaybe(E.Sym); | |
| 1731 | e.sym = addUndefined(e.name); | |
| 1732 | if (!e.directives) | |
| 1733 | e.symbolName = mangleMaybe(e.sym); | |
| 1538 | 1734 | } |
| 1539 | 1735 | |
| 1540 | 1736 | // Add weak aliases. Weak aliases is a mechanism to give remaining |
| 1541 | 1737 | // undefined symbols final chance to be resolved successfully. |
| 1542 | for (auto Pair : Config->AlternateNames) { | |
| 1543 | StringRef From = Pair.first; | |
| 1544 | StringRef To = Pair.second; | |
| 1545 | Symbol *Sym = Symtab->find(From); | |
| 1546 | if (!Sym) | |
| 1738 | for (auto pair : config->alternateNames) { | |
| 1739 | StringRef from = pair.first; | |
| 1740 | StringRef to = pair.second; | |
| 1741 | Symbol *sym = symtab->find(from); | |
| 1742 | if (!sym) | |
| 1547 | 1743 | continue; |
| 1548 | if (auto *U = dyn_cast<Undefined>(Sym)) | |
| 1549 | if (!U->WeakAlias) | |
| 1550 | U->WeakAlias = Symtab->addUndefined(To); | |
| 1744 | if (auto *u = dyn_cast<Undefined>(sym)) | |
| 1745 | if (!u->weakAlias) | |
| 1746 | u->weakAlias = symtab->addUndefined(to); | |
| 1551 | 1747 | } |
| 1552 | 1748 | |
| 1553 | 1749 | // Windows specific -- if __load_config_used can be resolved, resolve it. |
| 1554 | if (Symtab->findUnderscore("_load_config_used")) | |
| 1750 | if (symtab->findUnderscore("_load_config_used")) | |
| 1555 | 1751 | addUndefined(mangle("_load_config_used")); |
| 1556 | 1752 | } while (run()); |
| 1557 | 1753 | |
| ... | ... | @@ -1559,11 +1755,29 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { |
| 1559 | 1755 | return; |
| 1560 | 1756 | |
| 1561 | 1757 | // Do LTO by compiling bitcode input files to a set of native COFF files then |
| 1562 | // link those files. | |
| 1563 | Symtab->addCombinedLTOObjects(); | |
| 1758 | // link those files (unless -thinlto-index-only was given, in which case we | |
| 1759 | // resolve symbols and write indices, but don't generate native code or link). | |
| 1760 | symtab->addCombinedLTOObjects(); | |
| 1761 | ||
| 1762 | // If -thinlto-index-only is given, we should create only "index | |
| 1763 | // files" and not object files. Index file creation is already done | |
| 1764 | // in addCombinedLTOObject, so we are done if that's the case. | |
| 1765 | if (config->thinLTOIndexOnly) | |
| 1766 | return; | |
| 1767 | ||
| 1768 | // If we generated native object files from bitcode files, this resolves | |
| 1769 | // references to the symbols we use from them. | |
| 1564 | 1770 | run(); |
| 1565 | 1771 | |
| 1566 | if (Config->MinGW) { | |
| 1772 | if (args.hasArg(OPT_include_optional)) { | |
| 1773 | // Handle /includeoptional | |
| 1774 | for (auto *arg : args.filtered(OPT_include_optional)) | |
| 1775 | if (dyn_cast_or_null<Lazy>(symtab->find(arg->getValue()))) | |
| 1776 | addUndefined(arg->getValue()); | |
| 1777 | while (run()); | |
| 1778 | } | |
| 1779 | ||
| 1780 | if (config->mingw) { | |
| 1567 | 1781 | // Load any further object files that might be needed for doing automatic |
| 1568 | 1782 | // imports. |
| 1569 | 1783 | // |
| ... | ... | @@ -1577,95 +1791,91 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { |
| 1577 | 1791 | // normal object file as well (although that won't be used for the |
| 1578 | 1792 | // actual autoimport later on). If this pass adds new undefined references, |
| 1579 | 1793 | // we won't iterate further to resolve them. |
| 1580 | Symtab->loadMinGWAutomaticImports(); | |
| 1794 | symtab->loadMinGWAutomaticImports(); | |
| 1581 | 1795 | run(); |
| 1582 | 1796 | } |
| 1583 | 1797 | |
| 1584 | 1798 | // Make sure we have resolved all symbols. |
| 1585 | Symtab->reportRemainingUndefines(); | |
| 1799 | symtab->reportRemainingUndefines(); | |
| 1586 | 1800 | if (errorCount()) |
| 1587 | 1801 | return; |
| 1588 | 1802 | |
| 1589 | // Handle /safeseh. | |
| 1590 | if (Args.hasFlag(OPT_safeseh, OPT_safeseh_no, false)) { | |
| 1591 | for (ObjFile *File : ObjFile::Instances) | |
| 1592 | if (!File->hasSafeSEH()) | |
| 1593 | error("/safeseh: " + File->getName() + " is not compatible with SEH"); | |
| 1594 | if (errorCount()) | |
| 1595 | return; | |
| 1596 | } | |
| 1597 | ||
| 1598 | // In MinGW, all symbols are automatically exported if no symbols | |
| 1599 | // are chosen to be exported. | |
| 1600 | if (Config->DLL && ((Config->MinGW && Config->Exports.empty()) || | |
| 1601 | Args.hasArg(OPT_export_all_symbols))) { | |
| 1602 | Exporter.initSymbolExcludes(); | |
| 1603 | ||
| 1604 | Symtab->forEachSymbol([=](Symbol *S) { | |
| 1605 | auto *Def = dyn_cast<Defined>(S); | |
| 1606 | if (!Exporter.shouldExport(Def)) | |
| 1607 | return; | |
| 1608 | Export E; | |
| 1609 | E.Name = Def->getName(); | |
| 1610 | E.Sym = Def; | |
| 1611 | if (Def->getChunk() && | |
| 1612 | !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) | |
| 1613 | E.Data = true; | |
| 1614 | Config->Exports.push_back(E); | |
| 1615 | }); | |
| 1803 | if (config->mingw) { | |
| 1804 | // In MinGW, all symbols are automatically exported if no symbols | |
| 1805 | // are chosen to be exported. | |
| 1806 | maybeExportMinGWSymbols(args); | |
| 1807 | ||
| 1808 | // Make sure the crtend.o object is the last object file. This object | |
| 1809 | // file can contain terminating section chunks that need to be placed | |
| 1810 | // last. GNU ld processes files and static libraries explicitly in the | |
| 1811 | // order provided on the command line, while lld will pull in needed | |
| 1812 | // files from static libraries only after the last object file on the | |
| 1813 | // command line. | |
| 1814 | for (auto i = ObjFile::instances.begin(), e = ObjFile::instances.end(); | |
| 1815 | i != e; i++) { | |
| 1816 | ObjFile *file = *i; | |
| 1817 | if (isCrtend(file->getName())) { | |
| 1818 | ObjFile::instances.erase(i); | |
| 1819 | ObjFile::instances.push_back(file); | |
| 1820 | break; | |
| 1821 | } | |
| 1822 | } | |
| 1616 | 1823 | } |
| 1617 | 1824 | |
| 1618 | 1825 | // Windows specific -- when we are creating a .dll file, we also |
| 1619 | 1826 | // need to create a .lib file. |
| 1620 | if (!Config->Exports.empty() || Config->DLL) { | |
| 1827 | if (!config->exports.empty() || config->dll) { | |
| 1621 | 1828 | fixupExports(); |
| 1622 | createImportLibrary(/*AsLib=*/false); | |
| 1829 | createImportLibrary(/*asLib=*/false); | |
| 1623 | 1830 | assignExportOrdinals(); |
| 1624 | 1831 | } |
| 1625 | 1832 | |
| 1626 | 1833 | // Handle /output-def (MinGW specific). |
| 1627 | if (auto *Arg = Args.getLastArg(OPT_output_def)) | |
| 1628 | writeDefFile(Arg->getValue()); | |
| 1834 | if (auto *arg = args.getLastArg(OPT_output_def)) | |
| 1835 | writeDefFile(arg->getValue()); | |
| 1629 | 1836 | |
| 1630 | 1837 | // Set extra alignment for .comm symbols |
| 1631 | for (auto Pair : Config->AlignComm) { | |
| 1632 | StringRef Name = Pair.first; | |
| 1633 | uint32_t Alignment = Pair.second; | |
| 1838 | for (auto pair : config->alignComm) { | |
| 1839 | StringRef name = pair.first; | |
| 1840 | uint32_t alignment = pair.second; | |
| 1634 | 1841 | |
| 1635 | Symbol *Sym = Symtab->find(Name); | |
| 1636 | if (!Sym) { | |
| 1637 | warn("/aligncomm symbol " + Name + " not found"); | |
| 1842 | Symbol *sym = symtab->find(name); | |
| 1843 | if (!sym) { | |
| 1844 | warn("/aligncomm symbol " + name + " not found"); | |
| 1638 | 1845 | continue; |
| 1639 | 1846 | } |
| 1640 | 1847 | |
| 1641 | 1848 | // If the symbol isn't common, it must have been replaced with a regular |
| 1642 | 1849 | // symbol, which will carry its own alignment. |
| 1643 | auto *DC = dyn_cast<DefinedCommon>(Sym); | |
| 1644 | if (!DC) | |
| 1850 | auto *dc = dyn_cast<DefinedCommon>(sym); | |
| 1851 | if (!dc) | |
| 1645 | 1852 | continue; |
| 1646 | 1853 | |
| 1647 | CommonChunk *C = DC->getChunk(); | |
| 1648 | C->Alignment = std::max(C->Alignment, Alignment); | |
| 1854 | CommonChunk *c = dc->getChunk(); | |
| 1855 | c->setAlignment(std::max(c->getAlignment(), alignment)); | |
| 1649 | 1856 | } |
| 1650 | 1857 | |
| 1651 | 1858 | // Windows specific -- Create a side-by-side manifest file. |
| 1652 | if (Config->Manifest == Configuration::SideBySide) | |
| 1859 | if (config->manifest == Configuration::SideBySide) | |
| 1653 | 1860 | createSideBySideManifest(); |
| 1654 | 1861 | |
| 1655 | 1862 | // Handle /order. We want to do this at this moment because we |
| 1656 | 1863 | // need a complete list of comdat sections to warn on nonexistent |
| 1657 | 1864 | // functions. |
| 1658 | if (auto *Arg = Args.getLastArg(OPT_order)) | |
| 1659 | parseOrderFile(Arg->getValue()); | |
| 1865 | if (auto *arg = args.getLastArg(OPT_order)) | |
| 1866 | parseOrderFile(arg->getValue()); | |
| 1660 | 1867 | |
| 1661 | 1868 | // Identify unreferenced COMDAT sections. |
| 1662 | if (Config->DoGC) | |
| 1663 | markLive(Symtab->getChunks()); | |
| 1869 | if (config->doGC) | |
| 1870 | markLive(symtab->getChunks()); | |
| 1871 | ||
| 1872 | // Needs to happen after the last call to addFile(). | |
| 1873 | diagnoseMultipleResourceObjFiles(); | |
| 1664 | 1874 | |
| 1665 | 1875 | // Identify identical COMDAT sections to merge them. |
| 1666 | if (Config->DoICF) { | |
| 1876 | if (config->doICF) { | |
| 1667 | 1877 | findKeepUniqueSections(); |
| 1668 | doICF(Symtab->getChunks()); | |
| 1878 | doICF(symtab->getChunks()); | |
| 1669 | 1879 | } |
| 1670 | 1880 | |
| 1671 | 1881 | // Write the result. |
| ... | ... | @@ -1673,7 +1883,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { |
| 1673 | 1883 | |
| 1674 | 1884 | // Stop early so we can print the results. |
| 1675 | 1885 | Timer::root().stop(); |
| 1676 | if (Config->ShowTiming) | |
| 1886 | if (config->showTiming) | |
| 1677 | 1887 | Timer::root().print(); |
| 1678 | 1888 | } |
| 1679 | 1889 |
deps/lld/COFF/Driver.h+58-53| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Driver.h -------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -31,7 +30,7 @@ namespace lld { |
| 31 | 30 | namespace coff { |
| 32 | 31 | |
| 33 | 32 | class LinkerDriver; |
| 34 | extern LinkerDriver *Driver; | |
| 33 | extern LinkerDriver *driver; | |
| 35 | 34 | |
| 36 | 35 | using llvm::COFF::MachineTypes; |
| 37 | 36 | using llvm::COFF::WindowsSubsystem; |
| ... | ... | @@ -45,65 +44,71 @@ public: |
| 45 | 44 | class ArgParser { |
| 46 | 45 | public: |
| 47 | 46 | // Concatenate LINK environment variable and given arguments and parse them. |
| 48 | llvm::opt::InputArgList parseLINK(std::vector<const char *> Args); | |
| 47 | llvm::opt::InputArgList parseLINK(std::vector<const char *> args); | |
| 49 | 48 | |
| 50 | 49 | // Tokenizes a given string and then parses as command line options. |
| 51 | llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); } | |
| 50 | llvm::opt::InputArgList parse(StringRef s) { return parse(tokenize(s)); } | |
| 52 | 51 | |
| 53 | 52 | // Tokenizes a given string and then parses as command line options in |
| 54 | 53 | // .drectve section. /EXPORT options are returned in second element |
| 55 | 54 | // to be processed in fastpath. |
| 56 | 55 | std::pair<llvm::opt::InputArgList, std::vector<StringRef>> |
| 57 | parseDirectives(StringRef S); | |
| 56 | parseDirectives(StringRef s); | |
| 58 | 57 | |
| 59 | 58 | private: |
| 60 | 59 | // Parses command line options. |
| 61 | llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> Args); | |
| 60 | llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> args); | |
| 62 | 61 | |
| 63 | std::vector<const char *> tokenize(StringRef S); | |
| 62 | std::vector<const char *> tokenize(StringRef s); | |
| 64 | 63 | |
| 65 | COFFOptTable Table; | |
| 64 | COFFOptTable table; | |
| 66 | 65 | }; |
| 67 | 66 | |
| 68 | 67 | class LinkerDriver { |
| 69 | 68 | public: |
| 70 | void link(llvm::ArrayRef<const char *> Args); | |
| 69 | void link(llvm::ArrayRef<const char *> args); | |
| 71 | 70 | |
| 72 | 71 | // Used by the resolver to parse .drectve section contents. |
| 73 | void parseDirectives(StringRef S); | |
| 72 | void parseDirectives(InputFile *file); | |
| 74 | 73 | |
| 75 | 74 | // Used by ArchiveFile to enqueue members. |
| 76 | void enqueueArchiveMember(const Archive::Child &C, StringRef SymName, | |
| 77 | StringRef ParentName); | |
| 75 | void enqueueArchiveMember(const Archive::Child &c, StringRef symName, | |
| 76 | StringRef parentName); | |
| 77 | ||
| 78 | MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> mb); | |
| 78 | 79 | |
| 79 | MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> MB); | |
| 80 | void enqueuePath(StringRef path, bool wholeArchive); | |
| 80 | 81 | |
| 81 | 82 | private: |
| 82 | std::unique_ptr<llvm::TarWriter> Tar; // for /linkrepro | |
| 83 | std::unique_ptr<llvm::TarWriter> tar; // for /linkrepro | |
| 83 | 84 | |
| 84 | 85 | // Opens a file. Path has to be resolved already. |
| 85 | MemoryBufferRef openFile(StringRef Path); | |
| 86 | MemoryBufferRef openFile(StringRef path); | |
| 86 | 87 | |
| 87 | 88 | // Searches a file from search paths. |
| 88 | Optional<StringRef> findFile(StringRef Filename); | |
| 89 | Optional<StringRef> findLib(StringRef Filename); | |
| 90 | StringRef doFindFile(StringRef Filename); | |
| 91 | StringRef doFindLib(StringRef Filename); | |
| 92 | StringRef doFindLibMinGW(StringRef Filename); | |
| 89 | Optional<StringRef> findFile(StringRef filename); | |
| 90 | Optional<StringRef> findLib(StringRef filename); | |
| 91 | StringRef doFindFile(StringRef filename); | |
| 92 | StringRef doFindLib(StringRef filename); | |
| 93 | StringRef doFindLibMinGW(StringRef filename); | |
| 93 | 94 | |
| 94 | 95 | // Parses LIB environment which contains a list of search paths. |
| 95 | 96 | void addLibSearchPaths(); |
| 96 | 97 | |
| 97 | 98 | // Library search path. The first element is always "" (current directory). |
| 98 | std::vector<StringRef> SearchPaths; | |
| 99 | std::vector<StringRef> searchPaths; | |
| 100 | ||
| 101 | void maybeExportMinGWSymbols(const llvm::opt::InputArgList &args); | |
| 99 | 102 | |
| 100 | 103 | // We don't want to add the same file more than once. |
| 101 | 104 | // Files are uniquified by their filesystem and file number. |
| 102 | std::set<llvm::sys::fs::UniqueID> VisitedFiles; | |
| 105 | std::set<llvm::sys::fs::UniqueID> visitedFiles; | |
| 106 | ||
| 107 | std::set<std::string> visitedLibs; | |
| 103 | 108 | |
| 104 | std::set<std::string> VisitedLibs; | |
| 109 | Symbol *addUndefined(StringRef sym); | |
| 105 | 110 | |
| 106 | Symbol *addUndefined(StringRef Sym); | |
| 111 | StringRef mangleMaybe(Symbol *s); | |
| 107 | 112 | |
| 108 | 113 | // Windows specific -- "main" is not the only main function in Windows. |
| 109 | 114 | // You can choose one from these four -- {w,}{WinMain,main}. |
| ... | ... | @@ -115,60 +120,60 @@ private: |
| 115 | 120 | StringRef findDefaultEntry(); |
| 116 | 121 | WindowsSubsystem inferSubsystem(); |
| 117 | 122 | |
| 118 | void addBuffer(std::unique_ptr<MemoryBuffer> MB, bool WholeArchive); | |
| 119 | void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName, | |
| 120 | StringRef ParentName); | |
| 123 | void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive); | |
| 124 | void addArchiveBuffer(MemoryBufferRef mbref, StringRef symName, | |
| 125 | StringRef parentName, uint64_t offsetInArchive); | |
| 121 | 126 | |
| 122 | void enqueuePath(StringRef Path, bool WholeArchive); | |
| 123 | ||
| 124 | void enqueueTask(std::function<void()> Task); | |
| 127 | void enqueueTask(std::function<void()> task); | |
| 125 | 128 | bool run(); |
| 126 | 129 | |
| 127 | std::list<std::function<void()>> TaskQueue; | |
| 128 | std::vector<StringRef> FilePaths; | |
| 129 | std::vector<MemoryBufferRef> Resources; | |
| 130 | std::list<std::function<void()>> taskQueue; | |
| 131 | std::vector<StringRef> filePaths; | |
| 132 | std::vector<MemoryBufferRef> resources; | |
| 130 | 133 | |
| 131 | llvm::StringSet<> DirectivesExports; | |
| 134 | llvm::StringSet<> directivesExports; | |
| 132 | 135 | }; |
| 133 | 136 | |
| 134 | 137 | // Functions below this line are defined in DriverUtils.cpp. |
| 135 | 138 | |
| 136 | void printHelp(const char *Argv0); | |
| 137 | ||
| 138 | // For /machine option. | |
| 139 | MachineTypes getMachineType(StringRef Arg); | |
| 140 | StringRef machineToStr(MachineTypes MT); | |
| 139 | void printHelp(const char *argv0); | |
| 141 | 140 | |
| 142 | 141 | // Parses a string in the form of "<integer>[,<integer>]". |
| 143 | void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr); | |
| 142 | void parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size = nullptr); | |
| 144 | 143 | |
| 145 | void parseGuard(StringRef Arg); | |
| 144 | void parseGuard(StringRef arg); | |
| 146 | 145 | |
| 147 | 146 | // Parses a string in the form of "<integer>[.<integer>]". |
| 148 | 147 | // Minor's default value is 0. |
| 149 | void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor); | |
| 148 | void parseVersion(StringRef arg, uint32_t *major, uint32_t *minor); | |
| 150 | 149 | |
| 151 | 150 | // Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]". |
| 152 | void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, | |
| 153 | uint32_t *Minor); | |
| 151 | void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major, | |
| 152 | uint32_t *minor); | |
| 154 | 153 | |
| 155 | 154 | void parseAlternateName(StringRef); |
| 156 | 155 | void parseMerge(StringRef); |
| 157 | 156 | void parseSection(StringRef); |
| 158 | 157 | void parseAligncomm(StringRef); |
| 159 | 158 | |
| 159 | // Parses a string in the form of "[:<integer>]" | |
| 160 | void parseFunctionPadMin(llvm::opt::Arg *a, llvm::COFF::MachineTypes machine); | |
| 161 | ||
| 160 | 162 | // Parses a string in the form of "EMBED[,=<integer>]|NO". |
| 161 | void parseManifest(StringRef Arg); | |
| 163 | void parseManifest(StringRef arg); | |
| 162 | 164 | |
| 163 | 165 | // Parses a string in the form of "level=<string>|uiAccess=<string>" |
| 164 | void parseManifestUAC(StringRef Arg); | |
| 166 | void parseManifestUAC(StringRef arg); | |
| 167 | ||
| 168 | // Parses a string in the form of "cd|net[,(cd|net)]*" | |
| 169 | void parseSwaprun(StringRef arg); | |
| 165 | 170 | |
| 166 | 171 | // Create a resource file containing a manifest XML. |
| 167 | 172 | std::unique_ptr<MemoryBuffer> createManifestRes(); |
| 168 | 173 | void createSideBySideManifest(); |
| 169 | 174 | |
| 170 | 175 | // Used for dllexported symbols. |
| 171 | Export parseExport(StringRef Arg); | |
| 176 | Export parseExport(StringRef arg); | |
| 172 | 177 | void fixupExports(); |
| 173 | 178 | void assignExportOrdinals(); |
| 174 | 179 | |
| ... | ... | @@ -176,12 +181,12 @@ void assignExportOrdinals(); |
| 176 | 181 | // if value matches previous values for the key. |
| 177 | 182 | // This feature used in the directive section to reject |
| 178 | 183 | // incompatible objects. |
| 179 | void checkFailIfMismatch(StringRef Arg); | |
| 184 | void checkFailIfMismatch(StringRef arg, InputFile *source); | |
| 180 | 185 | |
| 181 | 186 | // Convert Windows resource files (.res files) to a .obj file. |
| 182 | MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> MBs); | |
| 187 | MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> mbs); | |
| 183 | 188 | |
| 184 | void runMSVCLinker(std::string Rsp, ArrayRef<StringRef> Objects); | |
| 189 | void runMSVCLinker(std::string rsp, ArrayRef<StringRef> objects); | |
| 185 | 190 | |
| 186 | 191 | // Create enum with OPT_xxx values for each option in Options.td |
| 187 | 192 | enum { |
deps/lld/COFF/DriverUtils.cpp+495-470| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- DriverUtils.cpp ----------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -48,104 +47,78 @@ const uint16_t RT_MANIFEST = 24; |
| 48 | 47 | |
| 49 | 48 | class Executor { |
| 50 | 49 | public: |
| 51 | explicit Executor(StringRef S) : Prog(Saver.save(S)) {} | |
| 52 | void add(StringRef S) { Args.push_back(Saver.save(S)); } | |
| 53 | void add(std::string &S) { Args.push_back(Saver.save(S)); } | |
| 54 | void add(Twine S) { Args.push_back(Saver.save(S)); } | |
| 55 | void add(const char *S) { Args.push_back(Saver.save(S)); } | |
| 50 | explicit Executor(StringRef s) : prog(saver.save(s)) {} | |
| 51 | void add(StringRef s) { args.push_back(saver.save(s)); } | |
| 52 | void add(std::string &s) { args.push_back(saver.save(s)); } | |
| 53 | void add(Twine s) { args.push_back(saver.save(s)); } | |
| 54 | void add(const char *s) { args.push_back(saver.save(s)); } | |
| 56 | 55 | |
| 57 | 56 | void run() { |
| 58 | ErrorOr<std::string> ExeOrErr = sys::findProgramByName(Prog); | |
| 59 | if (auto EC = ExeOrErr.getError()) | |
| 60 | fatal("unable to find " + Prog + " in PATH: " + EC.message()); | |
| 61 | StringRef Exe = Saver.save(*ExeOrErr); | |
| 62 | Args.insert(Args.begin(), Exe); | |
| 57 | ErrorOr<std::string> exeOrErr = sys::findProgramByName(prog); | |
| 58 | if (auto ec = exeOrErr.getError()) | |
| 59 | fatal("unable to find " + prog + " in PATH: " + ec.message()); | |
| 60 | StringRef exe = saver.save(*exeOrErr); | |
| 61 | args.insert(args.begin(), exe); | |
| 63 | 62 | |
| 64 | if (sys::ExecuteAndWait(Args[0], Args) != 0) | |
| 63 | if (sys::ExecuteAndWait(args[0], args) != 0) | |
| 65 | 64 | fatal("ExecuteAndWait failed: " + |
| 66 | llvm::join(Args.begin(), Args.end(), " ")); | |
| 65 | llvm::join(args.begin(), args.end(), " ")); | |
| 67 | 66 | } |
| 68 | 67 | |
| 69 | 68 | private: |
| 70 | StringRef Prog; | |
| 71 | std::vector<StringRef> Args; | |
| 69 | StringRef prog; | |
| 70 | std::vector<StringRef> args; | |
| 72 | 71 | }; |
| 73 | 72 | |
| 74 | 73 | } // anonymous namespace |
| 75 | 74 | |
| 76 | // Returns /machine's value. | |
| 77 | MachineTypes getMachineType(StringRef S) { | |
| 78 | MachineTypes MT = StringSwitch<MachineTypes>(S.lower()) | |
| 79 | .Cases("x64", "amd64", AMD64) | |
| 80 | .Cases("x86", "i386", I386) | |
| 81 | .Case("arm", ARMNT) | |
| 82 | .Case("arm64", ARM64) | |
| 83 | .Default(IMAGE_FILE_MACHINE_UNKNOWN); | |
| 84 | if (MT != IMAGE_FILE_MACHINE_UNKNOWN) | |
| 85 | return MT; | |
| 86 | fatal("unknown /machine argument: " + S); | |
| 87 | } | |
| 88 | ||
| 89 | StringRef machineToStr(MachineTypes MT) { | |
| 90 | switch (MT) { | |
| 91 | case ARMNT: | |
| 92 | return "arm"; | |
| 93 | case ARM64: | |
| 94 | return "arm64"; | |
| 95 | case AMD64: | |
| 96 | return "x64"; | |
| 97 | case I386: | |
| 98 | return "x86"; | |
| 99 | default: | |
| 100 | llvm_unreachable("unknown machine type"); | |
| 101 | } | |
| 102 | } | |
| 103 | ||
| 104 | 75 | // Parses a string in the form of "<integer>[,<integer>]". |
| 105 | void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) { | |
| 106 | StringRef S1, S2; | |
| 107 | std::tie(S1, S2) = Arg.split(','); | |
| 108 | if (S1.getAsInteger(0, *Addr)) | |
| 109 | fatal("invalid number: " + S1); | |
| 110 | if (Size && !S2.empty() && S2.getAsInteger(0, *Size)) | |
| 111 | fatal("invalid number: " + S2); | |
| 76 | void parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size) { | |
| 77 | StringRef s1, s2; | |
| 78 | std::tie(s1, s2) = arg.split(','); | |
| 79 | if (s1.getAsInteger(0, *addr)) | |
| 80 | fatal("invalid number: " + s1); | |
| 81 | if (size && !s2.empty() && s2.getAsInteger(0, *size)) | |
| 82 | fatal("invalid number: " + s2); | |
| 112 | 83 | } |
| 113 | 84 | |
| 114 | 85 | // Parses a string in the form of "<integer>[.<integer>]". |
| 115 | 86 | // If second number is not present, Minor is set to 0. |
| 116 | void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) { | |
| 117 | StringRef S1, S2; | |
| 118 | std::tie(S1, S2) = Arg.split('.'); | |
| 119 | if (S1.getAsInteger(0, *Major)) | |
| 120 | fatal("invalid number: " + S1); | |
| 121 | *Minor = 0; | |
| 122 | if (!S2.empty() && S2.getAsInteger(0, *Minor)) | |
| 123 | fatal("invalid number: " + S2); | |
| 124 | } | |
| 125 | ||
| 126 | void parseGuard(StringRef FullArg) { | |
| 127 | SmallVector<StringRef, 1> SplitArgs; | |
| 128 | FullArg.split(SplitArgs, ","); | |
| 129 | for (StringRef Arg : SplitArgs) { | |
| 130 | if (Arg.equals_lower("no")) | |
| 131 | Config->GuardCF = GuardCFLevel::Off; | |
| 132 | else if (Arg.equals_lower("nolongjmp")) | |
| 133 | Config->GuardCF = GuardCFLevel::NoLongJmp; | |
| 134 | else if (Arg.equals_lower("cf") || Arg.equals_lower("longjmp")) | |
| 135 | Config->GuardCF = GuardCFLevel::Full; | |
| 87 | void parseVersion(StringRef arg, uint32_t *major, uint32_t *minor) { | |
| 88 | StringRef s1, s2; | |
| 89 | std::tie(s1, s2) = arg.split('.'); | |
| 90 | if (s1.getAsInteger(0, *major)) | |
| 91 | fatal("invalid number: " + s1); | |
| 92 | *minor = 0; | |
| 93 | if (!s2.empty() && s2.getAsInteger(0, *minor)) | |
| 94 | fatal("invalid number: " + s2); | |
| 95 | } | |
| 96 | ||
| 97 | void parseGuard(StringRef fullArg) { | |
| 98 | SmallVector<StringRef, 1> splitArgs; | |
| 99 | fullArg.split(splitArgs, ","); | |
| 100 | for (StringRef arg : splitArgs) { | |
| 101 | if (arg.equals_lower("no")) | |
| 102 | config->guardCF = GuardCFLevel::Off; | |
| 103 | else if (arg.equals_lower("nolongjmp")) | |
| 104 | config->guardCF = GuardCFLevel::NoLongJmp; | |
| 105 | else if (arg.equals_lower("cf") || arg.equals_lower("longjmp")) | |
| 106 | config->guardCF = GuardCFLevel::Full; | |
| 136 | 107 | else |
| 137 | fatal("invalid argument to /guard: " + Arg); | |
| 108 | fatal("invalid argument to /guard: " + arg); | |
| 138 | 109 | } |
| 139 | 110 | } |
| 140 | 111 | |
| 141 | 112 | // Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]". |
| 142 | void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, | |
| 143 | uint32_t *Minor) { | |
| 144 | StringRef SysStr, Ver; | |
| 145 | std::tie(SysStr, Ver) = Arg.split(','); | |
| 146 | *Sys = StringSwitch<WindowsSubsystem>(SysStr.lower()) | |
| 113 | void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major, | |
| 114 | uint32_t *minor) { | |
| 115 | StringRef sysStr, ver; | |
| 116 | std::tie(sysStr, ver) = arg.split(','); | |
| 117 | std::string sysStrLower = sysStr.lower(); | |
| 118 | *sys = StringSwitch<WindowsSubsystem>(sysStrLower) | |
| 147 | 119 | .Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION) |
| 148 | 120 | .Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI) |
| 121 | .Case("default", IMAGE_SUBSYSTEM_UNKNOWN) | |
| 149 | 122 | .Case("efi_application", IMAGE_SUBSYSTEM_EFI_APPLICATION) |
| 150 | 123 | .Case("efi_boot_service_driver", IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) |
| 151 | 124 | .Case("efi_rom", IMAGE_SUBSYSTEM_EFI_ROM) |
| ... | ... | @@ -154,175 +127,217 @@ void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, |
| 154 | 127 | .Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI) |
| 155 | 128 | .Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI) |
| 156 | 129 | .Default(IMAGE_SUBSYSTEM_UNKNOWN); |
| 157 | if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN) | |
| 158 | fatal("unknown subsystem: " + SysStr); | |
| 159 | if (!Ver.empty()) | |
| 160 | parseVersion(Ver, Major, Minor); | |
| 130 | if (*sys == IMAGE_SUBSYSTEM_UNKNOWN && sysStrLower != "default") | |
| 131 | fatal("unknown subsystem: " + sysStr); | |
| 132 | if (!ver.empty()) | |
| 133 | parseVersion(ver, major, minor); | |
| 161 | 134 | } |
| 162 | 135 | |
| 163 | 136 | // Parse a string of the form of "<from>=<to>". |
| 164 | 137 | // Results are directly written to Config. |
| 165 | void parseAlternateName(StringRef S) { | |
| 166 | StringRef From, To; | |
| 167 | std::tie(From, To) = S.split('='); | |
| 168 | if (From.empty() || To.empty()) | |
| 169 | fatal("/alternatename: invalid argument: " + S); | |
| 170 | auto It = Config->AlternateNames.find(From); | |
| 171 | if (It != Config->AlternateNames.end() && It->second != To) | |
| 172 | fatal("/alternatename: conflicts: " + S); | |
| 173 | Config->AlternateNames.insert(It, std::make_pair(From, To)); | |
| 138 | void parseAlternateName(StringRef s) { | |
| 139 | StringRef from, to; | |
| 140 | std::tie(from, to) = s.split('='); | |
| 141 | if (from.empty() || to.empty()) | |
| 142 | fatal("/alternatename: invalid argument: " + s); | |
| 143 | auto it = config->alternateNames.find(from); | |
| 144 | if (it != config->alternateNames.end() && it->second != to) | |
| 145 | fatal("/alternatename: conflicts: " + s); | |
| 146 | config->alternateNames.insert(it, std::make_pair(from, to)); | |
| 174 | 147 | } |
| 175 | 148 | |
| 176 | 149 | // Parse a string of the form of "<from>=<to>". |
| 177 | 150 | // Results are directly written to Config. |
| 178 | void parseMerge(StringRef S) { | |
| 179 | StringRef From, To; | |
| 180 | std::tie(From, To) = S.split('='); | |
| 181 | if (From.empty() || To.empty()) | |
| 182 | fatal("/merge: invalid argument: " + S); | |
| 183 | if (From == ".rsrc" || To == ".rsrc") | |
| 151 | void parseMerge(StringRef s) { | |
| 152 | StringRef from, to; | |
| 153 | std::tie(from, to) = s.split('='); | |
| 154 | if (from.empty() || to.empty()) | |
| 155 | fatal("/merge: invalid argument: " + s); | |
| 156 | if (from == ".rsrc" || to == ".rsrc") | |
| 184 | 157 | fatal("/merge: cannot merge '.rsrc' with any section"); |
| 185 | if (From == ".reloc" || To == ".reloc") | |
| 158 | if (from == ".reloc" || to == ".reloc") | |
| 186 | 159 | fatal("/merge: cannot merge '.reloc' with any section"); |
| 187 | auto Pair = Config->Merge.insert(std::make_pair(From, To)); | |
| 188 | bool Inserted = Pair.second; | |
| 189 | if (!Inserted) { | |
| 190 | StringRef Existing = Pair.first->second; | |
| 191 | if (Existing != To) | |
| 192 | warn(S + ": already merged into " + Existing); | |
| 160 | auto pair = config->merge.insert(std::make_pair(from, to)); | |
| 161 | bool inserted = pair.second; | |
| 162 | if (!inserted) { | |
| 163 | StringRef existing = pair.first->second; | |
| 164 | if (existing != to) | |
| 165 | warn(s + ": already merged into " + existing); | |
| 193 | 166 | } |
| 194 | 167 | } |
| 195 | 168 | |
| 196 | static uint32_t parseSectionAttributes(StringRef S) { | |
| 197 | uint32_t Ret = 0; | |
| 198 | for (char C : S.lower()) { | |
| 199 | switch (C) { | |
| 169 | static uint32_t parseSectionAttributes(StringRef s) { | |
| 170 | uint32_t ret = 0; | |
| 171 | for (char c : s.lower()) { | |
| 172 | switch (c) { | |
| 200 | 173 | case 'd': |
| 201 | Ret |= IMAGE_SCN_MEM_DISCARDABLE; | |
| 174 | ret |= IMAGE_SCN_MEM_DISCARDABLE; | |
| 202 | 175 | break; |
| 203 | 176 | case 'e': |
| 204 | Ret |= IMAGE_SCN_MEM_EXECUTE; | |
| 177 | ret |= IMAGE_SCN_MEM_EXECUTE; | |
| 205 | 178 | break; |
| 206 | 179 | case 'k': |
| 207 | Ret |= IMAGE_SCN_MEM_NOT_CACHED; | |
| 180 | ret |= IMAGE_SCN_MEM_NOT_CACHED; | |
| 208 | 181 | break; |
| 209 | 182 | case 'p': |
| 210 | Ret |= IMAGE_SCN_MEM_NOT_PAGED; | |
| 183 | ret |= IMAGE_SCN_MEM_NOT_PAGED; | |
| 211 | 184 | break; |
| 212 | 185 | case 'r': |
| 213 | Ret |= IMAGE_SCN_MEM_READ; | |
| 186 | ret |= IMAGE_SCN_MEM_READ; | |
| 214 | 187 | break; |
| 215 | 188 | case 's': |
| 216 | Ret |= IMAGE_SCN_MEM_SHARED; | |
| 189 | ret |= IMAGE_SCN_MEM_SHARED; | |
| 217 | 190 | break; |
| 218 | 191 | case 'w': |
| 219 | Ret |= IMAGE_SCN_MEM_WRITE; | |
| 192 | ret |= IMAGE_SCN_MEM_WRITE; | |
| 220 | 193 | break; |
| 221 | 194 | default: |
| 222 | fatal("/section: invalid argument: " + S); | |
| 195 | fatal("/section: invalid argument: " + s); | |
| 223 | 196 | } |
| 224 | 197 | } |
| 225 | return Ret; | |
| 198 | return ret; | |
| 226 | 199 | } |
| 227 | 200 | |
| 228 | 201 | // Parses /section option argument. |
| 229 | void parseSection(StringRef S) { | |
| 230 | StringRef Name, Attrs; | |
| 231 | std::tie(Name, Attrs) = S.split(','); | |
| 232 | if (Name.empty() || Attrs.empty()) | |
| 233 | fatal("/section: invalid argument: " + S); | |
| 234 | Config->Section[Name] = parseSectionAttributes(Attrs); | |
| 202 | void parseSection(StringRef s) { | |
| 203 | StringRef name, attrs; | |
| 204 | std::tie(name, attrs) = s.split(','); | |
| 205 | if (name.empty() || attrs.empty()) | |
| 206 | fatal("/section: invalid argument: " + s); | |
| 207 | config->section[name] = parseSectionAttributes(attrs); | |
| 235 | 208 | } |
| 236 | 209 | |
| 237 | 210 | // Parses /aligncomm option argument. |
| 238 | void parseAligncomm(StringRef S) { | |
| 239 | StringRef Name, Align; | |
| 240 | std::tie(Name, Align) = S.split(','); | |
| 241 | if (Name.empty() || Align.empty()) { | |
| 242 | error("/aligncomm: invalid argument: " + S); | |
| 211 | void parseAligncomm(StringRef s) { | |
| 212 | StringRef name, align; | |
| 213 | std::tie(name, align) = s.split(','); | |
| 214 | if (name.empty() || align.empty()) { | |
| 215 | error("/aligncomm: invalid argument: " + s); | |
| 216 | return; | |
| 217 | } | |
| 218 | int v; | |
| 219 | if (align.getAsInteger(0, v)) { | |
| 220 | error("/aligncomm: invalid argument: " + s); | |
| 243 | 221 | return; |
| 244 | 222 | } |
| 245 | int V; | |
| 246 | if (Align.getAsInteger(0, V)) { | |
| 247 | error("/aligncomm: invalid argument: " + S); | |
| 223 | config->alignComm[name] = std::max(config->alignComm[name], 1 << v); | |
| 224 | } | |
| 225 | ||
| 226 | // Parses /functionpadmin option argument. | |
| 227 | void parseFunctionPadMin(llvm::opt::Arg *a, llvm::COFF::MachineTypes machine) { | |
| 228 | StringRef arg = a->getNumValues() ? a->getValue() : ""; | |
| 229 | if (!arg.empty()) { | |
| 230 | // Optional padding in bytes is given. | |
| 231 | if (arg.getAsInteger(0, config->functionPadMin)) | |
| 232 | error("/functionpadmin: invalid argument: " + arg); | |
| 248 | 233 | return; |
| 249 | 234 | } |
| 250 | Config->AlignComm[Name] = std::max(Config->AlignComm[Name], 1 << V); | |
| 235 | // No optional argument given. | |
| 236 | // Set default padding based on machine, similar to link.exe. | |
| 237 | // There is no default padding for ARM platforms. | |
| 238 | if (machine == I386) { | |
| 239 | config->functionPadMin = 5; | |
| 240 | } else if (machine == AMD64) { | |
| 241 | config->functionPadMin = 6; | |
| 242 | } else { | |
| 243 | error("/functionpadmin: invalid argument for this machine: " + arg); | |
| 244 | } | |
| 251 | 245 | } |
| 252 | 246 | |
| 253 | 247 | // Parses a string in the form of "EMBED[,=<integer>]|NO". |
| 254 | 248 | // Results are directly written to Config. |
| 255 | void parseManifest(StringRef Arg) { | |
| 256 | if (Arg.equals_lower("no")) { | |
| 257 | Config->Manifest = Configuration::No; | |
| 249 | void parseManifest(StringRef arg) { | |
| 250 | if (arg.equals_lower("no")) { | |
| 251 | config->manifest = Configuration::No; | |
| 258 | 252 | return; |
| 259 | 253 | } |
| 260 | if (!Arg.startswith_lower("embed")) | |
| 261 | fatal("invalid option " + Arg); | |
| 262 | Config->Manifest = Configuration::Embed; | |
| 263 | Arg = Arg.substr(strlen("embed")); | |
| 264 | if (Arg.empty()) | |
| 254 | if (!arg.startswith_lower("embed")) | |
| 255 | fatal("invalid option " + arg); | |
| 256 | config->manifest = Configuration::Embed; | |
| 257 | arg = arg.substr(strlen("embed")); | |
| 258 | if (arg.empty()) | |
| 265 | 259 | return; |
| 266 | if (!Arg.startswith_lower(",id=")) | |
| 267 | fatal("invalid option " + Arg); | |
| 268 | Arg = Arg.substr(strlen(",id=")); | |
| 269 | if (Arg.getAsInteger(0, Config->ManifestID)) | |
| 270 | fatal("invalid option " + Arg); | |
| 260 | if (!arg.startswith_lower(",id=")) | |
| 261 | fatal("invalid option " + arg); | |
| 262 | arg = arg.substr(strlen(",id=")); | |
| 263 | if (arg.getAsInteger(0, config->manifestID)) | |
| 264 | fatal("invalid option " + arg); | |
| 271 | 265 | } |
| 272 | 266 | |
| 273 | 267 | // Parses a string in the form of "level=<string>|uiAccess=<string>|NO". |
| 274 | 268 | // Results are directly written to Config. |
| 275 | void parseManifestUAC(StringRef Arg) { | |
| 276 | if (Arg.equals_lower("no")) { | |
| 277 | Config->ManifestUAC = false; | |
| 269 | void parseManifestUAC(StringRef arg) { | |
| 270 | if (arg.equals_lower("no")) { | |
| 271 | config->manifestUAC = false; | |
| 278 | 272 | return; |
| 279 | 273 | } |
| 280 | 274 | for (;;) { |
| 281 | Arg = Arg.ltrim(); | |
| 282 | if (Arg.empty()) | |
| 275 | arg = arg.ltrim(); | |
| 276 | if (arg.empty()) | |
| 283 | 277 | return; |
| 284 | if (Arg.startswith_lower("level=")) { | |
| 285 | Arg = Arg.substr(strlen("level=")); | |
| 286 | std::tie(Config->ManifestLevel, Arg) = Arg.split(" "); | |
| 278 | if (arg.startswith_lower("level=")) { | |
| 279 | arg = arg.substr(strlen("level=")); | |
| 280 | std::tie(config->manifestLevel, arg) = arg.split(" "); | |
| 287 | 281 | continue; |
| 288 | 282 | } |
| 289 | if (Arg.startswith_lower("uiaccess=")) { | |
| 290 | Arg = Arg.substr(strlen("uiaccess=")); | |
| 291 | std::tie(Config->ManifestUIAccess, Arg) = Arg.split(" "); | |
| 283 | if (arg.startswith_lower("uiaccess=")) { | |
| 284 | arg = arg.substr(strlen("uiaccess=")); | |
| 285 | std::tie(config->manifestUIAccess, arg) = arg.split(" "); | |
| 292 | 286 | continue; |
| 293 | 287 | } |
| 294 | fatal("invalid option " + Arg); | |
| 288 | fatal("invalid option " + arg); | |
| 295 | 289 | } |
| 296 | 290 | } |
| 297 | 291 | |
| 292 | // Parses a string in the form of "cd|net[,(cd|net)]*" | |
| 293 | // Results are directly written to Config. | |
| 294 | void parseSwaprun(StringRef arg) { | |
| 295 | do { | |
| 296 | StringRef swaprun, newArg; | |
| 297 | std::tie(swaprun, newArg) = arg.split(','); | |
| 298 | if (swaprun.equals_lower("cd")) | |
| 299 | config->swaprunCD = true; | |
| 300 | else if (swaprun.equals_lower("net")) | |
| 301 | config->swaprunNet = true; | |
| 302 | else if (swaprun.empty()) | |
| 303 | error("/swaprun: missing argument"); | |
| 304 | else | |
| 305 | error("/swaprun: invalid argument: " + swaprun); | |
| 306 | // To catch trailing commas, e.g. `/spawrun:cd,` | |
| 307 | if (newArg.empty() && arg.endswith(",")) | |
| 308 | error("/swaprun: missing argument"); | |
| 309 | arg = newArg; | |
| 310 | } while (!arg.empty()); | |
| 311 | } | |
| 312 | ||
| 298 | 313 | // An RAII temporary file class that automatically removes a temporary file. |
| 299 | 314 | namespace { |
| 300 | 315 | class TemporaryFile { |
| 301 | 316 | public: |
| 302 | TemporaryFile(StringRef Prefix, StringRef Extn, StringRef Contents = "") { | |
| 303 | SmallString<128> S; | |
| 304 | if (auto EC = sys::fs::createTemporaryFile("lld-" + Prefix, Extn, S)) | |
| 305 | fatal("cannot create a temporary file: " + EC.message()); | |
| 306 | Path = S.str(); | |
| 307 | ||
| 308 | if (!Contents.empty()) { | |
| 309 | std::error_code EC; | |
| 310 | raw_fd_ostream OS(Path, EC, sys::fs::F_None); | |
| 311 | if (EC) | |
| 312 | fatal("failed to open " + Path + ": " + EC.message()); | |
| 313 | OS << Contents; | |
| 317 | TemporaryFile(StringRef prefix, StringRef extn, StringRef contents = "") { | |
| 318 | SmallString<128> s; | |
| 319 | if (auto ec = sys::fs::createTemporaryFile("lld-" + prefix, extn, s)) | |
| 320 | fatal("cannot create a temporary file: " + ec.message()); | |
| 321 | path = s.str(); | |
| 322 | ||
| 323 | if (!contents.empty()) { | |
| 324 | std::error_code ec; | |
| 325 | raw_fd_ostream os(path, ec, sys::fs::F_None); | |
| 326 | if (ec) | |
| 327 | fatal("failed to open " + path + ": " + ec.message()); | |
| 328 | os << contents; | |
| 314 | 329 | } |
| 315 | 330 | } |
| 316 | 331 | |
| 317 | TemporaryFile(TemporaryFile &&Obj) { | |
| 318 | std::swap(Path, Obj.Path); | |
| 332 | TemporaryFile(TemporaryFile &&obj) { | |
| 333 | std::swap(path, obj.path); | |
| 319 | 334 | } |
| 320 | 335 | |
| 321 | 336 | ~TemporaryFile() { |
| 322 | if (Path.empty()) | |
| 337 | if (path.empty()) | |
| 323 | 338 | return; |
| 324 | if (sys::fs::remove(Path)) | |
| 325 | fatal("failed to remove " + Path); | |
| 339 | if (sys::fs::remove(path)) | |
| 340 | fatal("failed to remove " + path); | |
| 326 | 341 | } |
| 327 | 342 | |
| 328 | 343 | // Returns a memory buffer of this temporary file. |
| ... | ... | @@ -330,387 +345,390 @@ public: |
| 330 | 345 | // so it is safe to remove the file immediately after this function |
| 331 | 346 | // is called (you cannot remove an opened file on Windows.) |
| 332 | 347 | std::unique_ptr<MemoryBuffer> getMemoryBuffer() { |
| 333 | // IsVolatileSize=true forces MemoryBuffer to not use mmap(). | |
| 334 | return CHECK(MemoryBuffer::getFile(Path, /*FileSize=*/-1, | |
| 348 | // IsVolatile=true forces MemoryBuffer to not use mmap(). | |
| 349 | return CHECK(MemoryBuffer::getFile(path, /*FileSize=*/-1, | |
| 335 | 350 | /*RequiresNullTerminator=*/false, |
| 336 | /*IsVolatileSize=*/true), | |
| 337 | "could not open " + Path); | |
| 351 | /*IsVolatile=*/true), | |
| 352 | "could not open " + path); | |
| 338 | 353 | } |
| 339 | 354 | |
| 340 | std::string Path; | |
| 355 | std::string path; | |
| 341 | 356 | }; |
| 342 | 357 | } |
| 343 | 358 | |
| 344 | 359 | static std::string createDefaultXml() { |
| 345 | std::string Ret; | |
| 346 | raw_string_ostream OS(Ret); | |
| 360 | std::string ret; | |
| 361 | raw_string_ostream os(ret); | |
| 347 | 362 | |
| 348 | 363 | // Emit the XML. Note that we do *not* verify that the XML attributes are |
| 349 | 364 | // syntactically correct. This is intentional for link.exe compatibility. |
| 350 | OS << "<?xml version=\"1.0\" standalone=\"yes\"?>\n" | |
| 365 | os << "<?xml version=\"1.0\" standalone=\"yes\"?>\n" | |
| 351 | 366 | << "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\"\n" |
| 352 | 367 | << " manifestVersion=\"1.0\">\n"; |
| 353 | if (Config->ManifestUAC) { | |
| 354 | OS << " <trustInfo>\n" | |
| 368 | if (config->manifestUAC) { | |
| 369 | os << " <trustInfo>\n" | |
| 355 | 370 | << " <security>\n" |
| 356 | 371 | << " <requestedPrivileges>\n" |
| 357 | << " <requestedExecutionLevel level=" << Config->ManifestLevel | |
| 358 | << " uiAccess=" << Config->ManifestUIAccess << "/>\n" | |
| 372 | << " <requestedExecutionLevel level=" << config->manifestLevel | |
| 373 | << " uiAccess=" << config->manifestUIAccess << "/>\n" | |
| 359 | 374 | << " </requestedPrivileges>\n" |
| 360 | 375 | << " </security>\n" |
| 361 | 376 | << " </trustInfo>\n"; |
| 362 | 377 | } |
| 363 | if (!Config->ManifestDependency.empty()) { | |
| 364 | OS << " <dependency>\n" | |
| 378 | if (!config->manifestDependency.empty()) { | |
| 379 | os << " <dependency>\n" | |
| 365 | 380 | << " <dependentAssembly>\n" |
| 366 | << " <assemblyIdentity " << Config->ManifestDependency << " />\n" | |
| 381 | << " <assemblyIdentity " << config->manifestDependency << " />\n" | |
| 367 | 382 | << " </dependentAssembly>\n" |
| 368 | 383 | << " </dependency>\n"; |
| 369 | 384 | } |
| 370 | OS << "</assembly>\n"; | |
| 371 | return OS.str(); | |
| 385 | os << "</assembly>\n"; | |
| 386 | return os.str(); | |
| 372 | 387 | } |
| 373 | 388 | |
| 374 | static std::string createManifestXmlWithInternalMt(StringRef DefaultXml) { | |
| 375 | std::unique_ptr<MemoryBuffer> DefaultXmlCopy = | |
| 376 | MemoryBuffer::getMemBufferCopy(DefaultXml); | |
| 389 | static std::string createManifestXmlWithInternalMt(StringRef defaultXml) { | |
| 390 | std::unique_ptr<MemoryBuffer> defaultXmlCopy = | |
| 391 | MemoryBuffer::getMemBufferCopy(defaultXml); | |
| 377 | 392 | |
| 378 | windows_manifest::WindowsManifestMerger Merger; | |
| 379 | if (auto E = Merger.merge(*DefaultXmlCopy.get())) | |
| 393 | windows_manifest::WindowsManifestMerger merger; | |
| 394 | if (auto e = merger.merge(*defaultXmlCopy.get())) | |
| 380 | 395 | fatal("internal manifest tool failed on default xml: " + |
| 381 | toString(std::move(E))); | |
| 396 | toString(std::move(e))); | |
| 382 | 397 | |
| 383 | for (StringRef Filename : Config->ManifestInput) { | |
| 384 | std::unique_ptr<MemoryBuffer> Manifest = | |
| 385 | check(MemoryBuffer::getFile(Filename)); | |
| 386 | if (auto E = Merger.merge(*Manifest.get())) | |
| 387 | fatal("internal manifest tool failed on file " + Filename + ": " + | |
| 388 | toString(std::move(E))); | |
| 398 | for (StringRef filename : config->manifestInput) { | |
| 399 | std::unique_ptr<MemoryBuffer> manifest = | |
| 400 | check(MemoryBuffer::getFile(filename)); | |
| 401 | if (auto e = merger.merge(*manifest.get())) | |
| 402 | fatal("internal manifest tool failed on file " + filename + ": " + | |
| 403 | toString(std::move(e))); | |
| 389 | 404 | } |
| 390 | 405 | |
| 391 | return Merger.getMergedManifest().get()->getBuffer(); | |
| 406 | return merger.getMergedManifest().get()->getBuffer(); | |
| 392 | 407 | } |
| 393 | 408 | |
| 394 | static std::string createManifestXmlWithExternalMt(StringRef DefaultXml) { | |
| 409 | static std::string createManifestXmlWithExternalMt(StringRef defaultXml) { | |
| 395 | 410 | // Create the default manifest file as a temporary file. |
| 396 | 411 | TemporaryFile Default("defaultxml", "manifest"); |
| 397 | std::error_code EC; | |
| 398 | raw_fd_ostream OS(Default.Path, EC, sys::fs::F_Text); | |
| 399 | if (EC) | |
| 400 | fatal("failed to open " + Default.Path + ": " + EC.message()); | |
| 401 | OS << DefaultXml; | |
| 402 | OS.close(); | |
| 412 | std::error_code ec; | |
| 413 | raw_fd_ostream os(Default.path, ec, sys::fs::F_Text); | |
| 414 | if (ec) | |
| 415 | fatal("failed to open " + Default.path + ": " + ec.message()); | |
| 416 | os << defaultXml; | |
| 417 | os.close(); | |
| 403 | 418 | |
| 404 | 419 | // Merge user-supplied manifests if they are given. Since libxml2 is not |
| 405 | 420 | // enabled, we must shell out to Microsoft's mt.exe tool. |
| 406 | TemporaryFile User("user", "manifest"); | |
| 421 | TemporaryFile user("user", "manifest"); | |
| 407 | 422 | |
| 408 | Executor E("mt.exe"); | |
| 409 | E.add("/manifest"); | |
| 410 | E.add(Default.Path); | |
| 411 | for (StringRef Filename : Config->ManifestInput) { | |
| 412 | E.add("/manifest"); | |
| 413 | E.add(Filename); | |
| 423 | Executor e("mt.exe"); | |
| 424 | e.add("/manifest"); | |
| 425 | e.add(Default.path); | |
| 426 | for (StringRef filename : config->manifestInput) { | |
| 427 | e.add("/manifest"); | |
| 428 | e.add(filename); | |
| 414 | 429 | } |
| 415 | E.add("/nologo"); | |
| 416 | E.add("/out:" + StringRef(User.Path)); | |
| 417 | E.run(); | |
| 430 | e.add("/nologo"); | |
| 431 | e.add("/out:" + StringRef(user.path)); | |
| 432 | e.run(); | |
| 418 | 433 | |
| 419 | return CHECK(MemoryBuffer::getFile(User.Path), "could not open " + User.Path) | |
| 434 | return CHECK(MemoryBuffer::getFile(user.path), "could not open " + user.path) | |
| 420 | 435 | .get() |
| 421 | 436 | ->getBuffer(); |
| 422 | 437 | } |
| 423 | 438 | |
| 424 | 439 | static std::string createManifestXml() { |
| 425 | std::string DefaultXml = createDefaultXml(); | |
| 426 | if (Config->ManifestInput.empty()) | |
| 427 | return DefaultXml; | |
| 440 | std::string defaultXml = createDefaultXml(); | |
| 441 | if (config->manifestInput.empty()) | |
| 442 | return defaultXml; | |
| 428 | 443 | |
| 429 | 444 | if (windows_manifest::isAvailable()) |
| 430 | return createManifestXmlWithInternalMt(DefaultXml); | |
| 445 | return createManifestXmlWithInternalMt(defaultXml); | |
| 431 | 446 | |
| 432 | return createManifestXmlWithExternalMt(DefaultXml); | |
| 447 | return createManifestXmlWithExternalMt(defaultXml); | |
| 433 | 448 | } |
| 434 | 449 | |
| 435 | 450 | static std::unique_ptr<WritableMemoryBuffer> |
| 436 | createMemoryBufferForManifestRes(size_t ManifestSize) { | |
| 437 | size_t ResSize = alignTo( | |
| 451 | createMemoryBufferForManifestRes(size_t manifestSize) { | |
| 452 | size_t resSize = alignTo( | |
| 438 | 453 | object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE + |
| 439 | 454 | sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) + |
| 440 | sizeof(object::WinResHeaderSuffix) + ManifestSize, | |
| 455 | sizeof(object::WinResHeaderSuffix) + manifestSize, | |
| 441 | 456 | object::WIN_RES_DATA_ALIGNMENT); |
| 442 | return WritableMemoryBuffer::getNewMemBuffer(ResSize, Config->OutputFile + | |
| 457 | return WritableMemoryBuffer::getNewMemBuffer(resSize, config->outputFile + | |
| 443 | 458 | ".manifest.res"); |
| 444 | 459 | } |
| 445 | 460 | |
| 446 | static void writeResFileHeader(char *&Buf) { | |
| 447 | memcpy(Buf, COFF::WinResMagic, sizeof(COFF::WinResMagic)); | |
| 448 | Buf += sizeof(COFF::WinResMagic); | |
| 449 | memset(Buf, 0, object::WIN_RES_NULL_ENTRY_SIZE); | |
| 450 | Buf += object::WIN_RES_NULL_ENTRY_SIZE; | |
| 461 | static void writeResFileHeader(char *&buf) { | |
| 462 | memcpy(buf, COFF::WinResMagic, sizeof(COFF::WinResMagic)); | |
| 463 | buf += sizeof(COFF::WinResMagic); | |
| 464 | memset(buf, 0, object::WIN_RES_NULL_ENTRY_SIZE); | |
| 465 | buf += object::WIN_RES_NULL_ENTRY_SIZE; | |
| 451 | 466 | } |
| 452 | 467 | |
| 453 | static void writeResEntryHeader(char *&Buf, size_t ManifestSize) { | |
| 468 | static void writeResEntryHeader(char *&buf, size_t manifestSize) { | |
| 454 | 469 | // Write the prefix. |
| 455 | auto *Prefix = reinterpret_cast<object::WinResHeaderPrefix *>(Buf); | |
| 456 | Prefix->DataSize = ManifestSize; | |
| 457 | Prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) + | |
| 470 | auto *prefix = reinterpret_cast<object::WinResHeaderPrefix *>(buf); | |
| 471 | prefix->DataSize = manifestSize; | |
| 472 | prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) + | |
| 458 | 473 | sizeof(object::WinResIDs) + |
| 459 | 474 | sizeof(object::WinResHeaderSuffix); |
| 460 | Buf += sizeof(object::WinResHeaderPrefix); | |
| 475 | buf += sizeof(object::WinResHeaderPrefix); | |
| 461 | 476 | |
| 462 | 477 | // Write the Type/Name IDs. |
| 463 | auto *IDs = reinterpret_cast<object::WinResIDs *>(Buf); | |
| 464 | IDs->setType(RT_MANIFEST); | |
| 465 | IDs->setName(Config->ManifestID); | |
| 466 | Buf += sizeof(object::WinResIDs); | |
| 478 | auto *iDs = reinterpret_cast<object::WinResIDs *>(buf); | |
| 479 | iDs->setType(RT_MANIFEST); | |
| 480 | iDs->setName(config->manifestID); | |
| 481 | buf += sizeof(object::WinResIDs); | |
| 467 | 482 | |
| 468 | 483 | // Write the suffix. |
| 469 | auto *Suffix = reinterpret_cast<object::WinResHeaderSuffix *>(Buf); | |
| 470 | Suffix->DataVersion = 0; | |
| 471 | Suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE; | |
| 472 | Suffix->Language = SUBLANG_ENGLISH_US; | |
| 473 | Suffix->Version = 0; | |
| 474 | Suffix->Characteristics = 0; | |
| 475 | Buf += sizeof(object::WinResHeaderSuffix); | |
| 484 | auto *suffix = reinterpret_cast<object::WinResHeaderSuffix *>(buf); | |
| 485 | suffix->DataVersion = 0; | |
| 486 | suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE; | |
| 487 | suffix->Language = SUBLANG_ENGLISH_US; | |
| 488 | suffix->Version = 0; | |
| 489 | suffix->Characteristics = 0; | |
| 490 | buf += sizeof(object::WinResHeaderSuffix); | |
| 476 | 491 | } |
| 477 | 492 | |
| 478 | 493 | // Create a resource file containing a manifest XML. |
| 479 | 494 | std::unique_ptr<MemoryBuffer> createManifestRes() { |
| 480 | std::string Manifest = createManifestXml(); | |
| 495 | std::string manifest = createManifestXml(); | |
| 481 | 496 | |
| 482 | std::unique_ptr<WritableMemoryBuffer> Res = | |
| 483 | createMemoryBufferForManifestRes(Manifest.size()); | |
| 497 | std::unique_ptr<WritableMemoryBuffer> res = | |
| 498 | createMemoryBufferForManifestRes(manifest.size()); | |
| 484 | 499 | |
| 485 | char *Buf = Res->getBufferStart(); | |
| 486 | writeResFileHeader(Buf); | |
| 487 | writeResEntryHeader(Buf, Manifest.size()); | |
| 500 | char *buf = res->getBufferStart(); | |
| 501 | writeResFileHeader(buf); | |
| 502 | writeResEntryHeader(buf, manifest.size()); | |
| 488 | 503 | |
| 489 | 504 | // Copy the manifest data into the .res file. |
| 490 | std::copy(Manifest.begin(), Manifest.end(), Buf); | |
| 491 | return std::move(Res); | |
| 505 | std::copy(manifest.begin(), manifest.end(), buf); | |
| 506 | return std::move(res); | |
| 492 | 507 | } |
| 493 | 508 | |
| 494 | 509 | void createSideBySideManifest() { |
| 495 | std::string Path = Config->ManifestFile; | |
| 496 | if (Path == "") | |
| 497 | Path = Config->OutputFile + ".manifest"; | |
| 498 | std::error_code EC; | |
| 499 | raw_fd_ostream Out(Path, EC, sys::fs::F_Text); | |
| 500 | if (EC) | |
| 501 | fatal("failed to create manifest: " + EC.message()); | |
| 502 | Out << createManifestXml(); | |
| 510 | std::string path = config->manifestFile; | |
| 511 | if (path == "") | |
| 512 | path = config->outputFile + ".manifest"; | |
| 513 | std::error_code ec; | |
| 514 | raw_fd_ostream out(path, ec, sys::fs::F_Text); | |
| 515 | if (ec) | |
| 516 | fatal("failed to create manifest: " + ec.message()); | |
| 517 | out << createManifestXml(); | |
| 503 | 518 | } |
| 504 | 519 | |
| 505 | 520 | // Parse a string in the form of |
| 506 | 521 | // "<name>[=<internalname>][,@ordinal[,NONAME]][,DATA][,PRIVATE]" |
| 507 | 522 | // or "<name>=<dllname>.<name>". |
| 508 | 523 | // Used for parsing /export arguments. |
| 509 | Export parseExport(StringRef Arg) { | |
| 510 | Export E; | |
| 511 | StringRef Rest; | |
| 512 | std::tie(E.Name, Rest) = Arg.split(","); | |
| 513 | if (E.Name.empty()) | |
| 524 | Export parseExport(StringRef arg) { | |
| 525 | Export e; | |
| 526 | StringRef rest; | |
| 527 | std::tie(e.name, rest) = arg.split(","); | |
| 528 | if (e.name.empty()) | |
| 514 | 529 | goto err; |
| 515 | 530 | |
| 516 | if (E.Name.contains('=')) { | |
| 517 | StringRef X, Y; | |
| 518 | std::tie(X, Y) = E.Name.split("="); | |
| 531 | if (e.name.contains('=')) { | |
| 532 | StringRef x, y; | |
| 533 | std::tie(x, y) = e.name.split("="); | |
| 519 | 534 | |
| 520 | 535 | // If "<name>=<dllname>.<name>". |
| 521 | if (Y.contains(".")) { | |
| 522 | E.Name = X; | |
| 523 | E.ForwardTo = Y; | |
| 524 | return E; | |
| 536 | if (y.contains(".")) { | |
| 537 | e.name = x; | |
| 538 | e.forwardTo = y; | |
| 539 | return e; | |
| 525 | 540 | } |
| 526 | 541 | |
| 527 | E.ExtName = X; | |
| 528 | E.Name = Y; | |
| 529 | if (E.Name.empty()) | |
| 542 | e.extName = x; | |
| 543 | e.name = y; | |
| 544 | if (e.name.empty()) | |
| 530 | 545 | goto err; |
| 531 | 546 | } |
| 532 | 547 | |
| 533 | 548 | // If "<name>=<internalname>[,@ordinal[,NONAME]][,DATA][,PRIVATE]" |
| 534 | while (!Rest.empty()) { | |
| 535 | StringRef Tok; | |
| 536 | std::tie(Tok, Rest) = Rest.split(","); | |
| 537 | if (Tok.equals_lower("noname")) { | |
| 538 | if (E.Ordinal == 0) | |
| 549 | while (!rest.empty()) { | |
| 550 | StringRef tok; | |
| 551 | std::tie(tok, rest) = rest.split(","); | |
| 552 | if (tok.equals_lower("noname")) { | |
| 553 | if (e.ordinal == 0) | |
| 539 | 554 | goto err; |
| 540 | E.Noname = true; | |
| 555 | e.noname = true; | |
| 541 | 556 | continue; |
| 542 | 557 | } |
| 543 | if (Tok.equals_lower("data")) { | |
| 544 | E.Data = true; | |
| 558 | if (tok.equals_lower("data")) { | |
| 559 | e.data = true; | |
| 545 | 560 | continue; |
| 546 | 561 | } |
| 547 | if (Tok.equals_lower("constant")) { | |
| 548 | E.Constant = true; | |
| 562 | if (tok.equals_lower("constant")) { | |
| 563 | e.constant = true; | |
| 549 | 564 | continue; |
| 550 | 565 | } |
| 551 | if (Tok.equals_lower("private")) { | |
| 552 | E.Private = true; | |
| 566 | if (tok.equals_lower("private")) { | |
| 567 | e.isPrivate = true; | |
| 553 | 568 | continue; |
| 554 | 569 | } |
| 555 | if (Tok.startswith("@")) { | |
| 556 | int32_t Ord; | |
| 557 | if (Tok.substr(1).getAsInteger(0, Ord)) | |
| 570 | if (tok.startswith("@")) { | |
| 571 | int32_t ord; | |
| 572 | if (tok.substr(1).getAsInteger(0, ord)) | |
| 558 | 573 | goto err; |
| 559 | if (Ord <= 0 || 65535 < Ord) | |
| 574 | if (ord <= 0 || 65535 < ord) | |
| 560 | 575 | goto err; |
| 561 | E.Ordinal = Ord; | |
| 576 | e.ordinal = ord; | |
| 562 | 577 | continue; |
| 563 | 578 | } |
| 564 | 579 | goto err; |
| 565 | 580 | } |
| 566 | return E; | |
| 581 | return e; | |
| 567 | 582 | |
| 568 | 583 | err: |
| 569 | fatal("invalid /export: " + Arg); | |
| 584 | fatal("invalid /export: " + arg); | |
| 570 | 585 | } |
| 571 | 586 | |
| 572 | static StringRef undecorate(StringRef Sym) { | |
| 573 | if (Config->Machine != I386) | |
| 574 | return Sym; | |
| 587 | static StringRef undecorate(StringRef sym) { | |
| 588 | if (config->machine != I386) | |
| 589 | return sym; | |
| 575 | 590 | // In MSVC mode, a fully decorated stdcall function is exported |
| 576 | 591 | // as-is with the leading underscore (with type IMPORT_NAME). |
| 577 | 592 | // In MinGW mode, a decorated stdcall function gets the underscore |
| 578 | 593 | // removed, just like normal cdecl functions. |
| 579 | if (Sym.startswith("_") && Sym.contains('@') && !Config->MinGW) | |
| 580 | return Sym; | |
| 581 | return Sym.startswith("_") ? Sym.substr(1) : Sym; | |
| 594 | if (sym.startswith("_") && sym.contains('@') && !config->mingw) | |
| 595 | return sym; | |
| 596 | return sym.startswith("_") ? sym.substr(1) : sym; | |
| 582 | 597 | } |
| 583 | 598 | |
| 584 | 599 | // Convert stdcall/fastcall style symbols into unsuffixed symbols, |
| 585 | 600 | // with or without a leading underscore. (MinGW specific.) |
| 586 | static StringRef killAt(StringRef Sym, bool Prefix) { | |
| 587 | if (Sym.empty()) | |
| 588 | return Sym; | |
| 601 | static StringRef killAt(StringRef sym, bool prefix) { | |
| 602 | if (sym.empty()) | |
| 603 | return sym; | |
| 589 | 604 | // Strip any trailing stdcall suffix |
| 590 | Sym = Sym.substr(0, Sym.find('@', 1)); | |
| 591 | if (!Sym.startswith("@")) { | |
| 592 | if (Prefix && !Sym.startswith("_")) | |
| 593 | return Saver.save("_" + Sym); | |
| 594 | return Sym; | |
| 605 | sym = sym.substr(0, sym.find('@', 1)); | |
| 606 | if (!sym.startswith("@")) { | |
| 607 | if (prefix && !sym.startswith("_")) | |
| 608 | return saver.save("_" + sym); | |
| 609 | return sym; | |
| 595 | 610 | } |
| 596 | 611 | // For fastcall, remove the leading @ and replace it with an |
| 597 | 612 | // underscore, if prefixes are used. |
| 598 | Sym = Sym.substr(1); | |
| 599 | if (Prefix) | |
| 600 | Sym = Saver.save("_" + Sym); | |
| 601 | return Sym; | |
| 613 | sym = sym.substr(1); | |
| 614 | if (prefix) | |
| 615 | sym = saver.save("_" + sym); | |
| 616 | return sym; | |
| 602 | 617 | } |
| 603 | 618 | |
| 604 | 619 | // Performs error checking on all /export arguments. |
| 605 | 620 | // It also sets ordinals. |
| 606 | 621 | void fixupExports() { |
| 607 | 622 | // Symbol ordinals must be unique. |
| 608 | std::set<uint16_t> Ords; | |
| 609 | for (Export &E : Config->Exports) { | |
| 610 | if (E.Ordinal == 0) | |
| 623 | std::set<uint16_t> ords; | |
| 624 | for (Export &e : config->exports) { | |
| 625 | if (e.ordinal == 0) | |
| 611 | 626 | continue; |
| 612 | if (!Ords.insert(E.Ordinal).second) | |
| 613 | fatal("duplicate export ordinal: " + E.Name); | |
| 614 | } | |
| 615 | ||
| 616 | for (Export &E : Config->Exports) { | |
| 617 | Symbol *Sym = E.Sym; | |
| 618 | if (!E.ForwardTo.empty() || !Sym) { | |
| 619 | E.SymbolName = E.Name; | |
| 620 | } else { | |
| 621 | if (auto *U = dyn_cast<Undefined>(Sym)) | |
| 622 | if (U->WeakAlias) | |
| 623 | Sym = U->WeakAlias; | |
| 624 | E.SymbolName = Sym->getName(); | |
| 625 | } | |
| 627 | if (!ords.insert(e.ordinal).second) | |
| 628 | fatal("duplicate export ordinal: " + e.name); | |
| 626 | 629 | } |
| 627 | 630 | |
| 628 | for (Export &E : Config->Exports) { | |
| 629 | if (!E.ForwardTo.empty()) { | |
| 630 | E.ExportName = undecorate(E.Name); | |
| 631 | for (Export &e : config->exports) { | |
| 632 | if (!e.forwardTo.empty()) { | |
| 633 | e.exportName = undecorate(e.name); | |
| 631 | 634 | } else { |
| 632 | E.ExportName = undecorate(E.ExtName.empty() ? E.Name : E.ExtName); | |
| 635 | e.exportName = undecorate(e.extName.empty() ? e.name : e.extName); | |
| 633 | 636 | } |
| 634 | 637 | } |
| 635 | 638 | |
| 636 | if (Config->KillAt && Config->Machine == I386) { | |
| 637 | for (Export &E : Config->Exports) { | |
| 638 | E.Name = killAt(E.Name, true); | |
| 639 | E.ExportName = killAt(E.ExportName, false); | |
| 640 | E.ExtName = killAt(E.ExtName, true); | |
| 641 | E.SymbolName = killAt(E.SymbolName, true); | |
| 639 | if (config->killAt && config->machine == I386) { | |
| 640 | for (Export &e : config->exports) { | |
| 641 | e.name = killAt(e.name, true); | |
| 642 | e.exportName = killAt(e.exportName, false); | |
| 643 | e.extName = killAt(e.extName, true); | |
| 644 | e.symbolName = killAt(e.symbolName, true); | |
| 642 | 645 | } |
| 643 | 646 | } |
| 644 | 647 | |
| 645 | 648 | // Uniquefy by name. |
| 646 | DenseMap<StringRef, Export *> Map(Config->Exports.size()); | |
| 647 | std::vector<Export> V; | |
| 648 | for (Export &E : Config->Exports) { | |
| 649 | auto Pair = Map.insert(std::make_pair(E.ExportName, &E)); | |
| 650 | bool Inserted = Pair.second; | |
| 651 | if (Inserted) { | |
| 652 | V.push_back(E); | |
| 649 | DenseMap<StringRef, Export *> map(config->exports.size()); | |
| 650 | std::vector<Export> v; | |
| 651 | for (Export &e : config->exports) { | |
| 652 | auto pair = map.insert(std::make_pair(e.exportName, &e)); | |
| 653 | bool inserted = pair.second; | |
| 654 | if (inserted) { | |
| 655 | v.push_back(e); | |
| 653 | 656 | continue; |
| 654 | 657 | } |
| 655 | Export *Existing = Pair.first->second; | |
| 656 | if (E == *Existing || E.Name != Existing->Name) | |
| 658 | Export *existing = pair.first->second; | |
| 659 | if (e == *existing || e.name != existing->name) | |
| 657 | 660 | continue; |
| 658 | warn("duplicate /export option: " + E.Name); | |
| 661 | warn("duplicate /export option: " + e.name); | |
| 659 | 662 | } |
| 660 | Config->Exports = std::move(V); | |
| 663 | config->exports = std::move(v); | |
| 661 | 664 | |
| 662 | 665 | // Sort by name. |
| 663 | std::sort(Config->Exports.begin(), Config->Exports.end(), | |
| 664 | [](const Export &A, const Export &B) { | |
| 665 | return A.ExportName < B.ExportName; | |
| 666 | std::sort(config->exports.begin(), config->exports.end(), | |
| 667 | [](const Export &a, const Export &b) { | |
| 668 | return a.exportName < b.exportName; | |
| 666 | 669 | }); |
| 667 | 670 | } |
| 668 | 671 | |
| 669 | 672 | void assignExportOrdinals() { |
| 670 | 673 | // Assign unique ordinals if default (= 0). |
| 671 | uint16_t Max = 0; | |
| 672 | for (Export &E : Config->Exports) | |
| 673 | Max = std::max(Max, E.Ordinal); | |
| 674 | for (Export &E : Config->Exports) | |
| 675 | if (E.Ordinal == 0) | |
| 676 | E.Ordinal = ++Max; | |
| 674 | uint16_t max = 0; | |
| 675 | for (Export &e : config->exports) | |
| 676 | max = std::max(max, e.ordinal); | |
| 677 | for (Export &e : config->exports) | |
| 678 | if (e.ordinal == 0) | |
| 679 | e.ordinal = ++max; | |
| 677 | 680 | } |
| 678 | 681 | |
| 679 | 682 | // Parses a string in the form of "key=value" and check |
| 680 | 683 | // if value matches previous values for the same key. |
| 681 | void checkFailIfMismatch(StringRef Arg) { | |
| 682 | StringRef K, V; | |
| 683 | std::tie(K, V) = Arg.split('='); | |
| 684 | if (K.empty() || V.empty()) | |
| 685 | fatal("/failifmismatch: invalid argument: " + Arg); | |
| 686 | StringRef Existing = Config->MustMatch[K]; | |
| 687 | if (!Existing.empty() && V != Existing) | |
| 688 | fatal("/failifmismatch: mismatch detected: " + Existing + " and " + V + | |
| 689 | " for key " + K); | |
| 690 | Config->MustMatch[K] = V; | |
| 684 | void checkFailIfMismatch(StringRef arg, InputFile *source) { | |
| 685 | StringRef k, v; | |
| 686 | std::tie(k, v) = arg.split('='); | |
| 687 | if (k.empty() || v.empty()) | |
| 688 | fatal("/failifmismatch: invalid argument: " + arg); | |
| 689 | std::pair<StringRef, InputFile *> existing = config->mustMatch[k]; | |
| 690 | if (!existing.first.empty() && v != existing.first) { | |
| 691 | std::string sourceStr = source ? toString(source) : "cmd-line"; | |
| 692 | std::string existingStr = | |
| 693 | existing.second ? toString(existing.second) : "cmd-line"; | |
| 694 | fatal("/failifmismatch: mismatch detected for '" + k + "':\n>>> " + | |
| 695 | existingStr + " has value " + existing.first + "\n>>> " + sourceStr + | |
| 696 | " has value " + v); | |
| 697 | } | |
| 698 | config->mustMatch[k] = {v, source}; | |
| 691 | 699 | } |
| 692 | 700 | |
| 693 | 701 | // Convert Windows resource files (.res files) to a .obj file. |
| 694 | MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> MBs) { | |
| 695 | object::WindowsResourceParser Parser; | |
| 696 | ||
| 697 | for (MemoryBufferRef MB : MBs) { | |
| 698 | std::unique_ptr<object::Binary> Bin = check(object::createBinary(MB)); | |
| 699 | object::WindowsResource *RF = dyn_cast<object::WindowsResource>(Bin.get()); | |
| 700 | if (!RF) | |
| 702 | // Does what cvtres.exe does, but in-process and cross-platform. | |
| 703 | MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> mbs) { | |
| 704 | object::WindowsResourceParser parser; | |
| 705 | ||
| 706 | for (MemoryBufferRef mb : mbs) { | |
| 707 | std::unique_ptr<object::Binary> bin = check(object::createBinary(mb)); | |
| 708 | object::WindowsResource *rf = dyn_cast<object::WindowsResource>(bin.get()); | |
| 709 | if (!rf) | |
| 701 | 710 | fatal("cannot compile non-resource file as resource"); |
| 702 | if (auto EC = Parser.parse(RF)) | |
| 703 | fatal("failed to parse .res file: " + toString(std::move(EC))); | |
| 711 | ||
| 712 | std::vector<std::string> duplicates; | |
| 713 | if (auto ec = parser.parse(rf, duplicates)) | |
| 714 | fatal(toString(std::move(ec))); | |
| 715 | ||
| 716 | for (const auto &dupeDiag : duplicates) | |
| 717 | if (config->forceMultipleRes) | |
| 718 | warn(dupeDiag); | |
| 719 | else | |
| 720 | error(dupeDiag); | |
| 704 | 721 | } |
| 705 | 722 | |
| 706 | Expected<std::unique_ptr<MemoryBuffer>> E = | |
| 707 | llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser); | |
| 708 | if (!E) | |
| 709 | fatal("failed to write .res to COFF: " + toString(E.takeError())); | |
| 723 | Expected<std::unique_ptr<MemoryBuffer>> e = | |
| 724 | llvm::object::writeWindowsResourceCOFF(config->machine, parser, | |
| 725 | config->timestamp); | |
| 726 | if (!e) | |
| 727 | fatal("failed to write .res to COFF: " + toString(e.takeError())); | |
| 710 | 728 | |
| 711 | MemoryBufferRef MBRef = **E; | |
| 712 | make<std::unique_ptr<MemoryBuffer>>(std::move(*E)); // take ownership | |
| 713 | return MBRef; | |
| 729 | MemoryBufferRef mbref = **e; | |
| 730 | make<std::unique_ptr<MemoryBuffer>>(std::move(*e)); // take ownership | |
| 731 | return mbref; | |
| 714 | 732 | } |
| 715 | 733 | |
| 716 | 734 | // Create OptTable |
| ... | ... | @@ -721,7 +739,7 @@ MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> MBs) { |
| 721 | 739 | #undef PREFIX |
| 722 | 740 | |
| 723 | 741 | // Create table mapping all options defined in Options.td |
| 724 | static const llvm::opt::OptTable::Info InfoTable[] = { | |
| 742 | static const llvm::opt::OptTable::Info infoTable[] = { | |
| 725 | 743 | #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ |
| 726 | 744 | {X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \ |
| 727 | 745 | X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, |
| ... | ... | @@ -729,36 +747,36 @@ static const llvm::opt::OptTable::Info InfoTable[] = { |
| 729 | 747 | #undef OPTION |
| 730 | 748 | }; |
| 731 | 749 | |
| 732 | COFFOptTable::COFFOptTable() : OptTable(InfoTable, true) {} | |
| 750 | COFFOptTable::COFFOptTable() : OptTable(infoTable, true) {} | |
| 733 | 751 | |
| 734 | 752 | // Set color diagnostics according to --color-diagnostics={auto,always,never} |
| 735 | 753 | // or --no-color-diagnostics flags. |
| 736 | static void handleColorDiagnostics(opt::InputArgList &Args) { | |
| 737 | auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, | |
| 754 | static void handleColorDiagnostics(opt::InputArgList &args) { | |
| 755 | auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, | |
| 738 | 756 | OPT_no_color_diagnostics); |
| 739 | if (!Arg) | |
| 757 | if (!arg) | |
| 740 | 758 | return; |
| 741 | if (Arg->getOption().getID() == OPT_color_diagnostics) { | |
| 742 | errorHandler().ColorDiagnostics = true; | |
| 743 | } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) { | |
| 744 | errorHandler().ColorDiagnostics = false; | |
| 759 | if (arg->getOption().getID() == OPT_color_diagnostics) { | |
| 760 | errorHandler().colorDiagnostics = true; | |
| 761 | } else if (arg->getOption().getID() == OPT_no_color_diagnostics) { | |
| 762 | errorHandler().colorDiagnostics = false; | |
| 745 | 763 | } else { |
| 746 | StringRef S = Arg->getValue(); | |
| 747 | if (S == "always") | |
| 748 | errorHandler().ColorDiagnostics = true; | |
| 749 | else if (S == "never") | |
| 750 | errorHandler().ColorDiagnostics = false; | |
| 751 | else if (S != "auto") | |
| 752 | error("unknown option: --color-diagnostics=" + S); | |
| 753 | } | |
| 754 | } | |
| 755 | ||
| 756 | static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { | |
| 757 | if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) { | |
| 758 | StringRef S = Arg->getValue(); | |
| 759 | if (S != "windows" && S != "posix") | |
| 760 | error("invalid response file quoting: " + S); | |
| 761 | if (S == "windows") | |
| 764 | StringRef s = arg->getValue(); | |
| 765 | if (s == "always") | |
| 766 | errorHandler().colorDiagnostics = true; | |
| 767 | else if (s == "never") | |
| 768 | errorHandler().colorDiagnostics = false; | |
| 769 | else if (s != "auto") | |
| 770 | error("unknown option: --color-diagnostics=" + s); | |
| 771 | } | |
| 772 | } | |
| 773 | ||
| 774 | static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) { | |
| 775 | if (auto *arg = args.getLastArg(OPT_rsp_quoting)) { | |
| 776 | StringRef s = arg->getValue(); | |
| 777 | if (s != "windows" && s != "posix") | |
| 778 | error("invalid response file quoting: " + s); | |
| 779 | if (s == "windows") | |
| 762 | 780 | return cl::TokenizeWindowsCommandLine; |
| 763 | 781 | return cl::TokenizeGNUCommandLine; |
| 764 | 782 | } |
| ... | ... | @@ -767,104 +785,111 @@ static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { |
| 767 | 785 | } |
| 768 | 786 | |
| 769 | 787 | // Parses a given list of options. |
| 770 | opt::InputArgList ArgParser::parse(ArrayRef<const char *> Argv) { | |
| 788 | opt::InputArgList ArgParser::parse(ArrayRef<const char *> argv) { | |
| 771 | 789 | // Make InputArgList from string vectors. |
| 772 | unsigned MissingIndex; | |
| 773 | unsigned MissingCount; | |
| 790 | unsigned missingIndex; | |
| 791 | unsigned missingCount; | |
| 774 | 792 | |
| 775 | 793 | // We need to get the quoting style for response files before parsing all |
| 776 | 794 | // options so we parse here before and ignore all the options but |
| 777 | 795 | // --rsp-quoting. |
| 778 | opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount); | |
| 796 | opt::InputArgList args = table.ParseArgs(argv, missingIndex, missingCount); | |
| 779 | 797 | |
| 780 | 798 | // Expand response files (arguments in the form of @<filename>) |
| 781 | 799 | // and then parse the argument again. |
| 782 | SmallVector<const char *, 256> ExpandedArgv(Argv.data(), Argv.data() + Argv.size()); | |
| 783 | cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), ExpandedArgv); | |
| 784 | Args = Table.ParseArgs(makeArrayRef(ExpandedArgv).drop_front(), MissingIndex, | |
| 785 | MissingCount); | |
| 800 | SmallVector<const char *, 256> expandedArgv(argv.data(), | |
| 801 | argv.data() + argv.size()); | |
| 802 | cl::ExpandResponseFiles(saver, getQuotingStyle(args), expandedArgv); | |
| 803 | args = table.ParseArgs(makeArrayRef(expandedArgv).drop_front(), missingIndex, | |
| 804 | missingCount); | |
| 786 | 805 | |
| 787 | 806 | // Print the real command line if response files are expanded. |
| 788 | if (Args.hasArg(OPT_verbose) && Argv.size() != ExpandedArgv.size()) { | |
| 789 | std::string Msg = "Command line:"; | |
| 790 | for (const char *S : ExpandedArgv) | |
| 791 | Msg += " " + std::string(S); | |
| 792 | message(Msg); | |
| 807 | if (args.hasArg(OPT_verbose) && argv.size() != expandedArgv.size()) { | |
| 808 | std::string msg = "Command line:"; | |
| 809 | for (const char *s : expandedArgv) | |
| 810 | msg += " " + std::string(s); | |
| 811 | message(msg); | |
| 793 | 812 | } |
| 794 | 813 | |
| 795 | 814 | // Save the command line after response file expansion so we can write it to |
| 796 | 815 | // the PDB if necessary. |
| 797 | Config->Argv = {ExpandedArgv.begin(), ExpandedArgv.end()}; | |
| 816 | config->argv = {expandedArgv.begin(), expandedArgv.end()}; | |
| 798 | 817 | |
| 799 | 818 | // Handle /WX early since it converts missing argument warnings to errors. |
| 800 | errorHandler().FatalWarnings = Args.hasFlag(OPT_WX, OPT_WX_no, false); | |
| 819 | errorHandler().fatalWarnings = args.hasFlag(OPT_WX, OPT_WX_no, false); | |
| 801 | 820 | |
| 802 | if (MissingCount) | |
| 803 | fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); | |
| 821 | if (missingCount) | |
| 822 | fatal(Twine(args.getArgString(missingIndex)) + ": missing argument"); | |
| 804 | 823 | |
| 805 | handleColorDiagnostics(Args); | |
| 824 | handleColorDiagnostics(args); | |
| 806 | 825 | |
| 807 | for (auto *Arg : Args.filtered(OPT_UNKNOWN)) | |
| 808 | warn("ignoring unknown argument: " + Arg->getSpelling()); | |
| 826 | for (auto *arg : args.filtered(OPT_UNKNOWN)) { | |
| 827 | std::string nearest; | |
| 828 | if (table.findNearest(arg->getAsString(args), nearest) > 1) | |
| 829 | warn("ignoring unknown argument '" + arg->getAsString(args) + "'"); | |
| 830 | else | |
| 831 | warn("ignoring unknown argument '" + arg->getAsString(args) + | |
| 832 | "', did you mean '" + nearest + "'"); | |
| 833 | } | |
| 809 | 834 | |
| 810 | if (Args.hasArg(OPT_lib)) | |
| 835 | if (args.hasArg(OPT_lib)) | |
| 811 | 836 | warn("ignoring /lib since it's not the first argument"); |
| 812 | 837 | |
| 813 | return Args; | |
| 838 | return args; | |
| 814 | 839 | } |
| 815 | 840 | |
| 816 | 841 | // Tokenizes and parses a given string as command line in .drective section. |
| 817 | 842 | // /EXPORT options are processed in fastpath. |
| 818 | 843 | std::pair<opt::InputArgList, std::vector<StringRef>> |
| 819 | ArgParser::parseDirectives(StringRef S) { | |
| 820 | std::vector<StringRef> Exports; | |
| 821 | SmallVector<const char *, 16> Rest; | |
| 844 | ArgParser::parseDirectives(StringRef s) { | |
| 845 | std::vector<StringRef> exports; | |
| 846 | SmallVector<const char *, 16> rest; | |
| 822 | 847 | |
| 823 | for (StringRef Tok : tokenize(S)) { | |
| 824 | if (Tok.startswith_lower("/export:") || Tok.startswith_lower("-export:")) | |
| 825 | Exports.push_back(Tok.substr(strlen("/export:"))); | |
| 848 | for (StringRef tok : tokenize(s)) { | |
| 849 | if (tok.startswith_lower("/export:") || tok.startswith_lower("-export:")) | |
| 850 | exports.push_back(tok.substr(strlen("/export:"))); | |
| 826 | 851 | else |
| 827 | Rest.push_back(Tok.data()); | |
| 852 | rest.push_back(tok.data()); | |
| 828 | 853 | } |
| 829 | 854 | |
| 830 | 855 | // Make InputArgList from unparsed string vectors. |
| 831 | unsigned MissingIndex; | |
| 832 | unsigned MissingCount; | |
| 856 | unsigned missingIndex; | |
| 857 | unsigned missingCount; | |
| 833 | 858 | |
| 834 | opt::InputArgList Args = Table.ParseArgs(Rest, MissingIndex, MissingCount); | |
| 859 | opt::InputArgList args = table.ParseArgs(rest, missingIndex, missingCount); | |
| 835 | 860 | |
| 836 | if (MissingCount) | |
| 837 | fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); | |
| 838 | for (auto *Arg : Args.filtered(OPT_UNKNOWN)) | |
| 839 | warn("ignoring unknown argument: " + Arg->getSpelling()); | |
| 840 | return {std::move(Args), std::move(Exports)}; | |
| 861 | if (missingCount) | |
| 862 | fatal(Twine(args.getArgString(missingIndex)) + ": missing argument"); | |
| 863 | for (auto *arg : args.filtered(OPT_UNKNOWN)) | |
| 864 | warn("ignoring unknown argument: " + arg->getAsString(args)); | |
| 865 | return {std::move(args), std::move(exports)}; | |
| 841 | 866 | } |
| 842 | 867 | |
| 843 | 868 | // link.exe has an interesting feature. If LINK or _LINK_ environment |
| 844 | 869 | // variables exist, their contents are handled as command line strings. |
| 845 | 870 | // So you can pass extra arguments using them. |
| 846 | opt::InputArgList ArgParser::parseLINK(std::vector<const char *> Argv) { | |
| 871 | opt::InputArgList ArgParser::parseLINK(std::vector<const char *> argv) { | |
| 847 | 872 | // Concatenate LINK env and command line arguments, and then parse them. |
| 848 | if (Optional<std::string> S = Process::GetEnv("LINK")) { | |
| 849 | std::vector<const char *> V = tokenize(*S); | |
| 850 | Argv.insert(std::next(Argv.begin()), V.begin(), V.end()); | |
| 873 | if (Optional<std::string> s = Process::GetEnv("LINK")) { | |
| 874 | std::vector<const char *> v = tokenize(*s); | |
| 875 | argv.insert(std::next(argv.begin()), v.begin(), v.end()); | |
| 851 | 876 | } |
| 852 | if (Optional<std::string> S = Process::GetEnv("_LINK_")) { | |
| 853 | std::vector<const char *> V = tokenize(*S); | |
| 854 | Argv.insert(std::next(Argv.begin()), V.begin(), V.end()); | |
| 877 | if (Optional<std::string> s = Process::GetEnv("_LINK_")) { | |
| 878 | std::vector<const char *> v = tokenize(*s); | |
| 879 | argv.insert(std::next(argv.begin()), v.begin(), v.end()); | |
| 855 | 880 | } |
| 856 | return parse(Argv); | |
| 881 | return parse(argv); | |
| 857 | 882 | } |
| 858 | 883 | |
| 859 | std::vector<const char *> ArgParser::tokenize(StringRef S) { | |
| 860 | SmallVector<const char *, 16> Tokens; | |
| 861 | cl::TokenizeWindowsCommandLine(S, Saver, Tokens); | |
| 862 | return std::vector<const char *>(Tokens.begin(), Tokens.end()); | |
| 884 | std::vector<const char *> ArgParser::tokenize(StringRef s) { | |
| 885 | SmallVector<const char *, 16> tokens; | |
| 886 | cl::TokenizeWindowsCommandLine(s, saver, tokens); | |
| 887 | return std::vector<const char *>(tokens.begin(), tokens.end()); | |
| 863 | 888 | } |
| 864 | 889 | |
| 865 | void printHelp(const char *Argv0) { | |
| 890 | void printHelp(const char *argv0) { | |
| 866 | 891 | COFFOptTable().PrintHelp(outs(), |
| 867 | (std::string(Argv0) + " [options] file...").c_str(), | |
| 892 | (std::string(argv0) + " [options] file...").c_str(), | |
| 868 | 893 | "LLVM Linker", false); |
| 869 | 894 | } |
| 870 | 895 |
deps/lld/COFF/ICF.cpp+139-140| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- ICF.cpp ------------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -38,33 +37,32 @@ using namespace llvm; |
| 38 | 37 | namespace lld { |
| 39 | 38 | namespace coff { |
| 40 | 39 | |
| 41 | static Timer ICFTimer("ICF", Timer::root()); | |
| 40 | static Timer icfTimer("ICF", Timer::root()); | |
| 42 | 41 | |
| 43 | 42 | class ICF { |
| 44 | 43 | public: |
| 45 | void run(ArrayRef<Chunk *> V); | |
| 44 | void run(ArrayRef<Chunk *> v); | |
| 46 | 45 | |
| 47 | 46 | private: |
| 48 | void segregate(size_t Begin, size_t End, bool Constant); | |
| 47 | void segregate(size_t begin, size_t end, bool constant); | |
| 49 | 48 | |
| 50 | bool assocEquals(const SectionChunk *A, const SectionChunk *B); | |
| 49 | bool assocEquals(const SectionChunk *a, const SectionChunk *b); | |
| 51 | 50 | |
| 52 | bool equalsConstant(const SectionChunk *A, const SectionChunk *B); | |
| 53 | bool equalsVariable(const SectionChunk *A, const SectionChunk *B); | |
| 51 | bool equalsConstant(const SectionChunk *a, const SectionChunk *b); | |
| 52 | bool equalsVariable(const SectionChunk *a, const SectionChunk *b); | |
| 54 | 53 | |
| 55 | uint32_t getHash(SectionChunk *C); | |
| 56 | bool isEligible(SectionChunk *C); | |
| 54 | bool isEligible(SectionChunk *c); | |
| 57 | 55 | |
| 58 | size_t findBoundary(size_t Begin, size_t End); | |
| 56 | size_t findBoundary(size_t begin, size_t end); | |
| 59 | 57 | |
| 60 | void forEachClassRange(size_t Begin, size_t End, | |
| 61 | std::function<void(size_t, size_t)> Fn); | |
| 58 | void forEachClassRange(size_t begin, size_t end, | |
| 59 | std::function<void(size_t, size_t)> fn); | |
| 62 | 60 | |
| 63 | void forEachClass(std::function<void(size_t, size_t)> Fn); | |
| 61 | void forEachClass(std::function<void(size_t, size_t)> fn); | |
| 64 | 62 | |
| 65 | std::vector<SectionChunk *> Chunks; | |
| 66 | int Cnt = 0; | |
| 67 | std::atomic<bool> Repeat = {false}; | |
| 63 | std::vector<SectionChunk *> chunks; | |
| 64 | int cnt = 0; | |
| 65 | std::atomic<bool> repeat = {false}; | |
| 68 | 66 | }; |
| 69 | 67 | |
| 70 | 68 | // Returns true if section S is subject of ICF. |
| ... | ... | @@ -78,143 +76,144 @@ private: |
| 78 | 76 | // merge read-only sections in a couple of cases where the address of the |
| 79 | 77 | // section is insignificant to the user program and the behaviour matches that |
| 80 | 78 | // of the Visual C++ linker. |
| 81 | bool ICF::isEligible(SectionChunk *C) { | |
| 79 | bool ICF::isEligible(SectionChunk *c) { | |
| 82 | 80 | // Non-comdat chunks, dead chunks, and writable chunks are not elegible. |
| 83 | bool Writable = C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE; | |
| 84 | if (!C->isCOMDAT() || !C->Live || Writable) | |
| 81 | bool writable = c->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE; | |
| 82 | if (!c->isCOMDAT() || !c->live || writable) | |
| 85 | 83 | return false; |
| 86 | 84 | |
| 87 | 85 | // Code sections are eligible. |
| 88 | if (C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE) | |
| 86 | if (c->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE) | |
| 89 | 87 | return true; |
| 90 | 88 | |
| 91 | 89 | // .pdata and .xdata unwind info sections are eligible. |
| 92 | StringRef OutSecName = C->getSectionName().split('$').first; | |
| 93 | if (OutSecName == ".pdata" || OutSecName == ".xdata") | |
| 90 | StringRef outSecName = c->getSectionName().split('$').first; | |
| 91 | if (outSecName == ".pdata" || outSecName == ".xdata") | |
| 94 | 92 | return true; |
| 95 | 93 | |
| 96 | 94 | // So are vtables. |
| 97 | if (C->Sym && C->Sym->getName().startswith("??_7")) | |
| 95 | if (c->sym && c->sym->getName().startswith("??_7")) | |
| 98 | 96 | return true; |
| 99 | 97 | |
| 100 | 98 | // Anything else not in an address-significance table is eligible. |
| 101 | return !C->KeepUnique; | |
| 99 | return !c->keepUnique; | |
| 102 | 100 | } |
| 103 | 101 | |
| 104 | 102 | // Split an equivalence class into smaller classes. |
| 105 | void ICF::segregate(size_t Begin, size_t End, bool Constant) { | |
| 106 | while (Begin < End) { | |
| 103 | void ICF::segregate(size_t begin, size_t end, bool constant) { | |
| 104 | while (begin < end) { | |
| 107 | 105 | // Divide [Begin, End) into two. Let Mid be the start index of the |
| 108 | 106 | // second group. |
| 109 | auto Bound = std::stable_partition( | |
| 110 | Chunks.begin() + Begin + 1, Chunks.begin() + End, [&](SectionChunk *S) { | |
| 111 | if (Constant) | |
| 112 | return equalsConstant(Chunks[Begin], S); | |
| 113 | return equalsVariable(Chunks[Begin], S); | |
| 107 | auto bound = std::stable_partition( | |
| 108 | chunks.begin() + begin + 1, chunks.begin() + end, [&](SectionChunk *s) { | |
| 109 | if (constant) | |
| 110 | return equalsConstant(chunks[begin], s); | |
| 111 | return equalsVariable(chunks[begin], s); | |
| 114 | 112 | }); |
| 115 | size_t Mid = Bound - Chunks.begin(); | |
| 113 | size_t mid = bound - chunks.begin(); | |
| 116 | 114 | |
| 117 | 115 | // Split [Begin, End) into [Begin, Mid) and [Mid, End). We use Mid as an |
| 118 | 116 | // equivalence class ID because every group ends with a unique index. |
| 119 | for (size_t I = Begin; I < Mid; ++I) | |
| 120 | Chunks[I]->Class[(Cnt + 1) % 2] = Mid; | |
| 117 | for (size_t i = begin; i < mid; ++i) | |
| 118 | chunks[i]->eqClass[(cnt + 1) % 2] = mid; | |
| 121 | 119 | |
| 122 | 120 | // If we created a group, we need to iterate the main loop again. |
| 123 | if (Mid != End) | |
| 124 | Repeat = true; | |
| 121 | if (mid != end) | |
| 122 | repeat = true; | |
| 125 | 123 | |
| 126 | Begin = Mid; | |
| 124 | begin = mid; | |
| 127 | 125 | } |
| 128 | 126 | } |
| 129 | 127 | |
| 130 | 128 | // Returns true if two sections' associative children are equal. |
| 131 | bool ICF::assocEquals(const SectionChunk *A, const SectionChunk *B) { | |
| 132 | auto ChildClasses = [&](const SectionChunk *SC) { | |
| 133 | std::vector<uint32_t> Classes; | |
| 134 | for (const SectionChunk *C : SC->children()) | |
| 135 | if (!C->SectionName.startswith(".debug") && | |
| 136 | C->SectionName != ".gfids$y" && C->SectionName != ".gljmp$y") | |
| 137 | Classes.push_back(C->Class[Cnt % 2]); | |
| 138 | return Classes; | |
| 129 | bool ICF::assocEquals(const SectionChunk *a, const SectionChunk *b) { | |
| 130 | auto childClasses = [&](const SectionChunk *sc) { | |
| 131 | std::vector<uint32_t> classes; | |
| 132 | for (const SectionChunk &c : sc->children()) | |
| 133 | if (!c.getSectionName().startswith(".debug") && | |
| 134 | c.getSectionName() != ".gfids$y" && c.getSectionName() != ".gljmp$y") | |
| 135 | classes.push_back(c.eqClass[cnt % 2]); | |
| 136 | return classes; | |
| 139 | 137 | }; |
| 140 | return ChildClasses(A) == ChildClasses(B); | |
| 138 | return childClasses(a) == childClasses(b); | |
| 141 | 139 | } |
| 142 | 140 | |
| 143 | 141 | // Compare "non-moving" part of two sections, namely everything |
| 144 | 142 | // except relocation targets. |
| 145 | bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) { | |
| 146 | if (A->Relocs.size() != B->Relocs.size()) | |
| 143 | bool ICF::equalsConstant(const SectionChunk *a, const SectionChunk *b) { | |
| 144 | if (a->relocsSize != b->relocsSize) | |
| 147 | 145 | return false; |
| 148 | 146 | |
| 149 | 147 | // Compare relocations. |
| 150 | auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) { | |
| 151 | if (R1.Type != R2.Type || | |
| 152 | R1.VirtualAddress != R2.VirtualAddress) { | |
| 148 | auto eq = [&](const coff_relocation &r1, const coff_relocation &r2) { | |
| 149 | if (r1.Type != r2.Type || | |
| 150 | r1.VirtualAddress != r2.VirtualAddress) { | |
| 153 | 151 | return false; |
| 154 | 152 | } |
| 155 | Symbol *B1 = A->File->getSymbol(R1.SymbolTableIndex); | |
| 156 | Symbol *B2 = B->File->getSymbol(R2.SymbolTableIndex); | |
| 157 | if (B1 == B2) | |
| 153 | Symbol *b1 = a->file->getSymbol(r1.SymbolTableIndex); | |
| 154 | Symbol *b2 = b->file->getSymbol(r2.SymbolTableIndex); | |
| 155 | if (b1 == b2) | |
| 158 | 156 | return true; |
| 159 | if (auto *D1 = dyn_cast<DefinedRegular>(B1)) | |
| 160 | if (auto *D2 = dyn_cast<DefinedRegular>(B2)) | |
| 161 | return D1->getValue() == D2->getValue() && | |
| 162 | D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2]; | |
| 157 | if (auto *d1 = dyn_cast<DefinedRegular>(b1)) | |
| 158 | if (auto *d2 = dyn_cast<DefinedRegular>(b2)) | |
| 159 | return d1->getValue() == d2->getValue() && | |
| 160 | d1->getChunk()->eqClass[cnt % 2] == d2->getChunk()->eqClass[cnt % 2]; | |
| 163 | 161 | return false; |
| 164 | 162 | }; |
| 165 | if (!std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq)) | |
| 163 | if (!std::equal(a->getRelocs().begin(), a->getRelocs().end(), | |
| 164 | b->getRelocs().begin(), eq)) | |
| 166 | 165 | return false; |
| 167 | 166 | |
| 168 | 167 | // Compare section attributes and contents. |
| 169 | return A->getOutputCharacteristics() == B->getOutputCharacteristics() && | |
| 170 | A->SectionName == B->SectionName && | |
| 171 | A->Header->SizeOfRawData == B->Header->SizeOfRawData && | |
| 172 | A->Checksum == B->Checksum && A->getContents() == B->getContents() && | |
| 173 | assocEquals(A, B); | |
| 168 | return a->getOutputCharacteristics() == b->getOutputCharacteristics() && | |
| 169 | a->getSectionName() == b->getSectionName() && | |
| 170 | a->header->SizeOfRawData == b->header->SizeOfRawData && | |
| 171 | a->checksum == b->checksum && a->getContents() == b->getContents() && | |
| 172 | assocEquals(a, b); | |
| 174 | 173 | } |
| 175 | 174 | |
| 176 | 175 | // Compare "moving" part of two sections, namely relocation targets. |
| 177 | bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) { | |
| 176 | bool ICF::equalsVariable(const SectionChunk *a, const SectionChunk *b) { | |
| 178 | 177 | // Compare relocations. |
| 179 | auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) { | |
| 180 | Symbol *B1 = A->File->getSymbol(R1.SymbolTableIndex); | |
| 181 | Symbol *B2 = B->File->getSymbol(R2.SymbolTableIndex); | |
| 182 | if (B1 == B2) | |
| 178 | auto eq = [&](const coff_relocation &r1, const coff_relocation &r2) { | |
| 179 | Symbol *b1 = a->file->getSymbol(r1.SymbolTableIndex); | |
| 180 | Symbol *b2 = b->file->getSymbol(r2.SymbolTableIndex); | |
| 181 | if (b1 == b2) | |
| 183 | 182 | return true; |
| 184 | if (auto *D1 = dyn_cast<DefinedRegular>(B1)) | |
| 185 | if (auto *D2 = dyn_cast<DefinedRegular>(B2)) | |
| 186 | return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2]; | |
| 183 | if (auto *d1 = dyn_cast<DefinedRegular>(b1)) | |
| 184 | if (auto *d2 = dyn_cast<DefinedRegular>(b2)) | |
| 185 | return d1->getChunk()->eqClass[cnt % 2] == d2->getChunk()->eqClass[cnt % 2]; | |
| 187 | 186 | return false; |
| 188 | 187 | }; |
| 189 | return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), | |
| 190 | Eq) && | |
| 191 | assocEquals(A, B); | |
| 188 | return std::equal(a->getRelocs().begin(), a->getRelocs().end(), | |
| 189 | b->getRelocs().begin(), eq) && | |
| 190 | assocEquals(a, b); | |
| 192 | 191 | } |
| 193 | 192 | |
| 194 | 193 | // Find the first Chunk after Begin that has a different class from Begin. |
| 195 | size_t ICF::findBoundary(size_t Begin, size_t End) { | |
| 196 | for (size_t I = Begin + 1; I < End; ++I) | |
| 197 | if (Chunks[Begin]->Class[Cnt % 2] != Chunks[I]->Class[Cnt % 2]) | |
| 198 | return I; | |
| 199 | return End; | |
| 194 | size_t ICF::findBoundary(size_t begin, size_t end) { | |
| 195 | for (size_t i = begin + 1; i < end; ++i) | |
| 196 | if (chunks[begin]->eqClass[cnt % 2] != chunks[i]->eqClass[cnt % 2]) | |
| 197 | return i; | |
| 198 | return end; | |
| 200 | 199 | } |
| 201 | 200 | |
| 202 | void ICF::forEachClassRange(size_t Begin, size_t End, | |
| 203 | std::function<void(size_t, size_t)> Fn) { | |
| 204 | while (Begin < End) { | |
| 205 | size_t Mid = findBoundary(Begin, End); | |
| 206 | Fn(Begin, Mid); | |
| 207 | Begin = Mid; | |
| 201 | void ICF::forEachClassRange(size_t begin, size_t end, | |
| 202 | std::function<void(size_t, size_t)> fn) { | |
| 203 | while (begin < end) { | |
| 204 | size_t mid = findBoundary(begin, end); | |
| 205 | fn(begin, mid); | |
| 206 | begin = mid; | |
| 208 | 207 | } |
| 209 | 208 | } |
| 210 | 209 | |
| 211 | 210 | // Call Fn on each class group. |
| 212 | void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) { | |
| 211 | void ICF::forEachClass(std::function<void(size_t, size_t)> fn) { | |
| 213 | 212 | // If the number of sections are too small to use threading, |
| 214 | 213 | // call Fn sequentially. |
| 215 | if (Chunks.size() < 1024) { | |
| 216 | forEachClassRange(0, Chunks.size(), Fn); | |
| 217 | ++Cnt; | |
| 214 | if (chunks.size() < 1024) { | |
| 215 | forEachClassRange(0, chunks.size(), fn); | |
| 216 | ++cnt; | |
| 218 | 217 | return; |
| 219 | 218 | } |
| 220 | 219 | |
| ... | ... | @@ -222,97 +221,97 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) { |
| 222 | 221 | // The sharding must be completed before any calls to Fn are made |
| 223 | 222 | // so that Fn can modify the Chunks in its shard without causing data |
| 224 | 223 | // races. |
| 225 | const size_t NumShards = 256; | |
| 226 | size_t Step = Chunks.size() / NumShards; | |
| 227 | size_t Boundaries[NumShards + 1]; | |
| 228 | Boundaries[0] = 0; | |
| 229 | Boundaries[NumShards] = Chunks.size(); | |
| 230 | parallelForEachN(1, NumShards, [&](size_t I) { | |
| 231 | Boundaries[I] = findBoundary((I - 1) * Step, Chunks.size()); | |
| 224 | const size_t numShards = 256; | |
| 225 | size_t step = chunks.size() / numShards; | |
| 226 | size_t boundaries[numShards + 1]; | |
| 227 | boundaries[0] = 0; | |
| 228 | boundaries[numShards] = chunks.size(); | |
| 229 | parallelForEachN(1, numShards, [&](size_t i) { | |
| 230 | boundaries[i] = findBoundary((i - 1) * step, chunks.size()); | |
| 232 | 231 | }); |
| 233 | parallelForEachN(1, NumShards + 1, [&](size_t I) { | |
| 234 | if (Boundaries[I - 1] < Boundaries[I]) { | |
| 235 | forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn); | |
| 232 | parallelForEachN(1, numShards + 1, [&](size_t i) { | |
| 233 | if (boundaries[i - 1] < boundaries[i]) { | |
| 234 | forEachClassRange(boundaries[i - 1], boundaries[i], fn); | |
| 236 | 235 | } |
| 237 | 236 | }); |
| 238 | ++Cnt; | |
| 237 | ++cnt; | |
| 239 | 238 | } |
| 240 | 239 | |
| 241 | 240 | // Merge identical COMDAT sections. |
| 242 | 241 | // Two sections are considered the same if their section headers, |
| 243 | 242 | // contents and relocations are all the same. |
| 244 | void ICF::run(ArrayRef<Chunk *> Vec) { | |
| 245 | ScopedTimer T(ICFTimer); | |
| 243 | void ICF::run(ArrayRef<Chunk *> vec) { | |
| 244 | ScopedTimer t(icfTimer); | |
| 246 | 245 | |
| 247 | 246 | // Collect only mergeable sections and group by hash value. |
| 248 | uint32_t NextId = 1; | |
| 249 | for (Chunk *C : Vec) { | |
| 250 | if (auto *SC = dyn_cast<SectionChunk>(C)) { | |
| 251 | if (isEligible(SC)) | |
| 252 | Chunks.push_back(SC); | |
| 247 | uint32_t nextId = 1; | |
| 248 | for (Chunk *c : vec) { | |
| 249 | if (auto *sc = dyn_cast<SectionChunk>(c)) { | |
| 250 | if (isEligible(sc)) | |
| 251 | chunks.push_back(sc); | |
| 253 | 252 | else |
| 254 | SC->Class[0] = NextId++; | |
| 253 | sc->eqClass[0] = nextId++; | |
| 255 | 254 | } |
| 256 | 255 | } |
| 257 | 256 | |
| 258 | 257 | // Make sure that ICF doesn't merge sections that are being handled by string |
| 259 | 258 | // tail merging. |
| 260 | for (auto &P : MergeChunk::Instances) | |
| 261 | for (SectionChunk *SC : P.second->Sections) | |
| 262 | SC->Class[0] = NextId++; | |
| 259 | for (MergeChunk *mc : MergeChunk::instances) | |
| 260 | if (mc) | |
| 261 | for (SectionChunk *sc : mc->sections) | |
| 262 | sc->eqClass[0] = nextId++; | |
| 263 | 263 | |
| 264 | 264 | // Initially, we use hash values to partition sections. |
| 265 | parallelForEach(Chunks, [&](SectionChunk *SC) { | |
| 266 | SC->Class[0] = xxHash64(SC->getContents()); | |
| 265 | parallelForEach(chunks, [&](SectionChunk *sc) { | |
| 266 | sc->eqClass[0] = xxHash64(sc->getContents()); | |
| 267 | 267 | }); |
| 268 | 268 | |
| 269 | 269 | // Combine the hashes of the sections referenced by each section into its |
| 270 | 270 | // hash. |
| 271 | for (unsigned Cnt = 0; Cnt != 2; ++Cnt) { | |
| 272 | parallelForEach(Chunks, [&](SectionChunk *SC) { | |
| 273 | uint32_t Hash = SC->Class[Cnt % 2]; | |
| 274 | for (Symbol *B : SC->symbols()) | |
| 275 | if (auto *Sym = dyn_cast_or_null<DefinedRegular>(B)) | |
| 276 | Hash += Sym->getChunk()->Class[Cnt % 2]; | |
| 271 | for (unsigned cnt = 0; cnt != 2; ++cnt) { | |
| 272 | parallelForEach(chunks, [&](SectionChunk *sc) { | |
| 273 | uint32_t hash = sc->eqClass[cnt % 2]; | |
| 274 | for (Symbol *b : sc->symbols()) | |
| 275 | if (auto *sym = dyn_cast_or_null<DefinedRegular>(b)) | |
| 276 | hash += sym->getChunk()->eqClass[cnt % 2]; | |
| 277 | 277 | // Set MSB to 1 to avoid collisions with non-hash classs. |
| 278 | SC->Class[(Cnt + 1) % 2] = Hash | (1U << 31); | |
| 278 | sc->eqClass[(cnt + 1) % 2] = hash | (1U << 31); | |
| 279 | 279 | }); |
| 280 | 280 | } |
| 281 | 281 | |
| 282 | 282 | // From now on, sections in Chunks are ordered so that sections in |
| 283 | 283 | // the same group are consecutive in the vector. |
| 284 | std::stable_sort(Chunks.begin(), Chunks.end(), | |
| 285 | [](SectionChunk *A, SectionChunk *B) { | |
| 286 | return A->Class[0] < B->Class[0]; | |
| 287 | }); | |
| 284 | llvm::stable_sort(chunks, [](const SectionChunk *a, const SectionChunk *b) { | |
| 285 | return a->eqClass[0] < b->eqClass[0]; | |
| 286 | }); | |
| 288 | 287 | |
| 289 | 288 | // Compare static contents and assign unique IDs for each static content. |
| 290 | forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); }); | |
| 289 | forEachClass([&](size_t begin, size_t end) { segregate(begin, end, true); }); | |
| 291 | 290 | |
| 292 | 291 | // Split groups by comparing relocations until convergence is obtained. |
| 293 | 292 | do { |
| 294 | Repeat = false; | |
| 293 | repeat = false; | |
| 295 | 294 | forEachClass( |
| 296 | [&](size_t Begin, size_t End) { segregate(Begin, End, false); }); | |
| 297 | } while (Repeat); | |
| 295 | [&](size_t begin, size_t end) { segregate(begin, end, false); }); | |
| 296 | } while (repeat); | |
| 298 | 297 | |
| 299 | log("ICF needed " + Twine(Cnt) + " iterations"); | |
| 298 | log("ICF needed " + Twine(cnt) + " iterations"); | |
| 300 | 299 | |
| 301 | 300 | // Merge sections in the same classs. |
| 302 | forEachClass([&](size_t Begin, size_t End) { | |
| 303 | if (End - Begin == 1) | |
| 301 | forEachClass([&](size_t begin, size_t end) { | |
| 302 | if (end - begin == 1) | |
| 304 | 303 | return; |
| 305 | 304 | |
| 306 | log("Selected " + Chunks[Begin]->getDebugName()); | |
| 307 | for (size_t I = Begin + 1; I < End; ++I) { | |
| 308 | log(" Removed " + Chunks[I]->getDebugName()); | |
| 309 | Chunks[Begin]->replace(Chunks[I]); | |
| 305 | log("Selected " + chunks[begin]->getDebugName()); | |
| 306 | for (size_t i = begin + 1; i < end; ++i) { | |
| 307 | log(" Removed " + chunks[i]->getDebugName()); | |
| 308 | chunks[begin]->replace(chunks[i]); | |
| 310 | 309 | } |
| 311 | 310 | }); |
| 312 | 311 | } |
| 313 | 312 | |
| 314 | 313 | // Entry point to ICF. |
| 315 | void doICF(ArrayRef<Chunk *> Chunks) { ICF().run(Chunks); } | |
| 314 | void doICF(ArrayRef<Chunk *> chunks) { ICF().run(chunks); } | |
| 316 | 315 | |
| 317 | 316 | } // namespace coff |
| 318 | 317 | } // namespace lld |
deps/lld/COFF/ICF.h+4-5| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- ICF.h --------------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -18,7 +17,7 @@ namespace coff { |
| 18 | 17 | |
| 19 | 18 | class Chunk; |
| 20 | 19 | |
| 21 | void doICF(ArrayRef<Chunk *> Chunks); | |
| 20 | void doICF(ArrayRef<Chunk *> chunks); | |
| 22 | 21 | |
| 23 | 22 | } // namespace coff |
| 24 | 23 | } // namespace lld |
deps/lld/COFF/InputFiles.cpp+603-312| ... | ... | @@ -1,15 +1,15 @@ |
| 1 | 1 | //===- InputFiles.cpp -----------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| 10 | 9 | #include "InputFiles.h" |
| 11 | 10 | #include "Chunks.h" |
| 12 | 11 | #include "Config.h" |
| 12 | #include "DebugTypes.h" | |
| 13 | 13 | #include "Driver.h" |
| 14 | 14 | #include "SymbolTable.h" |
| 15 | 15 | #include "Symbols.h" |
| ... | ... | @@ -20,6 +20,10 @@ |
| 20 | 20 | #include "llvm/ADT/Triple.h" |
| 21 | 21 | #include "llvm/ADT/Twine.h" |
| 22 | 22 | #include "llvm/BinaryFormat/COFF.h" |
| 23 | #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" | |
| 24 | #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" | |
| 25 | #include "llvm/DebugInfo/CodeView/SymbolRecord.h" | |
| 26 | #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" | |
| 23 | 27 | #include "llvm/Object/Binary.h" |
| 24 | 28 | #include "llvm/Object/COFF.h" |
| 25 | 29 | #include "llvm/Support/Casting.h" |
| ... | ... | @@ -35,6 +39,7 @@ |
| 35 | 39 | |
| 36 | 40 | using namespace llvm; |
| 37 | 41 | using namespace llvm::COFF; |
| 42 | using namespace llvm::codeview; | |
| 38 | 43 | using namespace llvm::object; |
| 39 | 44 | using namespace llvm::support::endian; |
| 40 | 45 | |
| ... | ... | @@ -44,80 +49,80 @@ using llvm::support::ulittle32_t; |
| 44 | 49 | namespace lld { |
| 45 | 50 | namespace coff { |
| 46 | 51 | |
| 47 | std::vector<ObjFile *> ObjFile::Instances; | |
| 48 | std::vector<ImportFile *> ImportFile::Instances; | |
| 49 | std::vector<BitcodeFile *> BitcodeFile::Instances; | |
| 52 | std::vector<ObjFile *> ObjFile::instances; | |
| 53 | std::vector<ImportFile *> ImportFile::instances; | |
| 54 | std::vector<BitcodeFile *> BitcodeFile::instances; | |
| 50 | 55 | |
| 51 | 56 | /// Checks that Source is compatible with being a weak alias to Target. |
| 52 | 57 | /// If Source is Undefined and has no weak alias set, makes it a weak |
| 53 | 58 | /// alias to Target. |
| 54 | static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F, | |
| 55 | Symbol *Source, Symbol *Target) { | |
| 56 | if (auto *U = dyn_cast<Undefined>(Source)) { | |
| 57 | if (U->WeakAlias && U->WeakAlias != Target) { | |
| 59 | static void checkAndSetWeakAlias(SymbolTable *symtab, InputFile *f, | |
| 60 | Symbol *source, Symbol *target) { | |
| 61 | if (auto *u = dyn_cast<Undefined>(source)) { | |
| 62 | if (u->weakAlias && u->weakAlias != target) { | |
| 58 | 63 | // Weak aliases as produced by GCC are named in the form |
| 59 | 64 | // .weak.<weaksymbol>.<othersymbol>, where <othersymbol> is the name |
| 60 | 65 | // of another symbol emitted near the weak symbol. |
| 61 | 66 | // Just use the definition from the first object file that defined |
| 62 | 67 | // this weak symbol. |
| 63 | if (Config->MinGW) | |
| 68 | if (config->mingw) | |
| 64 | 69 | return; |
| 65 | Symtab->reportDuplicate(Source, F); | |
| 70 | symtab->reportDuplicate(source, f); | |
| 66 | 71 | } |
| 67 | U->WeakAlias = Target; | |
| 72 | u->weakAlias = target; | |
| 68 | 73 | } |
| 69 | 74 | } |
| 70 | 75 | |
| 71 | ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} | |
| 76 | ArchiveFile::ArchiveFile(MemoryBufferRef m) : InputFile(ArchiveKind, m) {} | |
| 72 | 77 | |
| 73 | 78 | void ArchiveFile::parse() { |
| 74 | 79 | // Parse a MemoryBufferRef as an archive file. |
| 75 | File = CHECK(Archive::create(MB), this); | |
| 80 | file = CHECK(Archive::create(mb), this); | |
| 76 | 81 | |
| 77 | 82 | // Read the symbol table to construct Lazy objects. |
| 78 | for (const Archive::Symbol &Sym : File->symbols()) | |
| 79 | Symtab->addLazy(this, Sym); | |
| 83 | for (const Archive::Symbol &sym : file->symbols()) | |
| 84 | symtab->addLazy(this, sym); | |
| 80 | 85 | } |
| 81 | 86 | |
| 82 | 87 | // Returns a buffer pointing to a member file containing a given symbol. |
| 83 | void ArchiveFile::addMember(const Archive::Symbol *Sym) { | |
| 84 | const Archive::Child &C = | |
| 85 | CHECK(Sym->getMember(), | |
| 86 | "could not get the member for symbol " + Sym->getName()); | |
| 88 | void ArchiveFile::addMember(const Archive::Symbol *sym) { | |
| 89 | const Archive::Child &c = | |
| 90 | CHECK(sym->getMember(), | |
| 91 | "could not get the member for symbol " + sym->getName()); | |
| 87 | 92 | |
| 88 | 93 | // Return an empty buffer if we have already returned the same buffer. |
| 89 | if (!Seen.insert(C.getChildOffset()).second) | |
| 94 | if (!seen.insert(c.getChildOffset()).second) | |
| 90 | 95 | return; |
| 91 | 96 | |
| 92 | Driver->enqueueArchiveMember(C, Sym->getName(), getName()); | |
| 97 | driver->enqueueArchiveMember(c, sym->getName(), getName()); | |
| 93 | 98 | } |
| 94 | 99 | |
| 95 | std::vector<MemoryBufferRef> getArchiveMembers(Archive *File) { | |
| 96 | std::vector<MemoryBufferRef> V; | |
| 97 | Error Err = Error::success(); | |
| 98 | for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) { | |
| 99 | Archive::Child C = | |
| 100 | CHECK(COrErr, | |
| 101 | File->getFileName() + ": could not get the child of the archive"); | |
| 102 | MemoryBufferRef MBRef = | |
| 103 | CHECK(C.getMemoryBufferRef(), | |
| 104 | File->getFileName() + | |
| 100 | std::vector<MemoryBufferRef> getArchiveMembers(Archive *file) { | |
| 101 | std::vector<MemoryBufferRef> v; | |
| 102 | Error err = Error::success(); | |
| 103 | for (const ErrorOr<Archive::Child> &cOrErr : file->children(err)) { | |
| 104 | Archive::Child c = | |
| 105 | CHECK(cOrErr, | |
| 106 | file->getFileName() + ": could not get the child of the archive"); | |
| 107 | MemoryBufferRef mbref = | |
| 108 | CHECK(c.getMemoryBufferRef(), | |
| 109 | file->getFileName() + | |
| 105 | 110 | ": could not get the buffer for a child of the archive"); |
| 106 | V.push_back(MBRef); | |
| 111 | v.push_back(mbref); | |
| 107 | 112 | } |
| 108 | if (Err) | |
| 109 | fatal(File->getFileName() + | |
| 110 | ": Archive::children failed: " + toString(std::move(Err))); | |
| 111 | return V; | |
| 113 | if (err) | |
| 114 | fatal(file->getFileName() + | |
| 115 | ": Archive::children failed: " + toString(std::move(err))); | |
| 116 | return v; | |
| 112 | 117 | } |
| 113 | 118 | |
| 114 | 119 | void ObjFile::parse() { |
| 115 | 120 | // Parse a memory buffer as a COFF file. |
| 116 | std::unique_ptr<Binary> Bin = CHECK(createBinary(MB), this); | |
| 121 | std::unique_ptr<Binary> bin = CHECK(createBinary(mb), this); | |
| 117 | 122 | |
| 118 | if (auto *Obj = dyn_cast<COFFObjectFile>(Bin.get())) { | |
| 119 | Bin.release(); | |
| 120 | COFFObj.reset(Obj); | |
| 123 | if (auto *obj = dyn_cast<COFFObjectFile>(bin.get())) { | |
| 124 | bin.release(); | |
| 125 | coffObj.reset(obj); | |
| 121 | 126 | } else { |
| 122 | 127 | fatal(toString(this) + " is not a COFF file"); |
| 123 | 128 | } |
| ... | ... | @@ -125,6 +130,15 @@ void ObjFile::parse() { |
| 125 | 130 | // Read section and symbol tables. |
| 126 | 131 | initializeChunks(); |
| 127 | 132 | initializeSymbols(); |
| 133 | initializeFlags(); | |
| 134 | initializeDependencies(); | |
| 135 | } | |
| 136 | ||
| 137 | const coff_section* ObjFile::getSection(uint32_t i) { | |
| 138 | const coff_section *sec; | |
| 139 | if (auto ec = coffObj->getSection(i, sec)) | |
| 140 | fatal("getSection failed: #" + Twine(i) + ": " + ec.message()); | |
| 141 | return sec; | |
| 128 | 142 | } |
| 129 | 143 | |
| 130 | 144 | // We set SectionChunk pointers in the SparseChunks vector to this value |
| ... | ... | @@ -133,45 +147,42 @@ void ObjFile::parse() { |
| 133 | 147 | // an associative section definition together with the parent comdat's leader, |
| 134 | 148 | // we set the pointer to either nullptr (to mark the section as discarded) or a |
| 135 | 149 | // valid SectionChunk for that section. |
| 136 | static SectionChunk *const PendingComdat = reinterpret_cast<SectionChunk *>(1); | |
| 150 | static SectionChunk *const pendingComdat = reinterpret_cast<SectionChunk *>(1); | |
| 137 | 151 | |
| 138 | 152 | void ObjFile::initializeChunks() { |
| 139 | uint32_t NumSections = COFFObj->getNumberOfSections(); | |
| 140 | Chunks.reserve(NumSections); | |
| 141 | SparseChunks.resize(NumSections + 1); | |
| 142 | for (uint32_t I = 1; I < NumSections + 1; ++I) { | |
| 143 | const coff_section *Sec; | |
| 144 | if (auto EC = COFFObj->getSection(I, Sec)) | |
| 145 | fatal("getSection failed: #" + Twine(I) + ": " + EC.message()); | |
| 146 | ||
| 147 | if (Sec->Characteristics & IMAGE_SCN_LNK_COMDAT) | |
| 148 | SparseChunks[I] = PendingComdat; | |
| 153 | uint32_t numSections = coffObj->getNumberOfSections(); | |
| 154 | chunks.reserve(numSections); | |
| 155 | sparseChunks.resize(numSections + 1); | |
| 156 | for (uint32_t i = 1; i < numSections + 1; ++i) { | |
| 157 | const coff_section *sec = getSection(i); | |
| 158 | if (sec->Characteristics & IMAGE_SCN_LNK_COMDAT) | |
| 159 | sparseChunks[i] = pendingComdat; | |
| 149 | 160 | else |
| 150 | SparseChunks[I] = readSection(I, nullptr, ""); | |
| 161 | sparseChunks[i] = readSection(i, nullptr, ""); | |
| 151 | 162 | } |
| 152 | 163 | } |
| 153 | 164 | |
| 154 | SectionChunk *ObjFile::readSection(uint32_t SectionNumber, | |
| 155 | const coff_aux_section_definition *Def, | |
| 156 | StringRef LeaderName) { | |
| 157 | const coff_section *Sec; | |
| 158 | if (auto EC = COFFObj->getSection(SectionNumber, Sec)) | |
| 159 | fatal("getSection failed: #" + Twine(SectionNumber) + ": " + EC.message()); | |
| 160 | ||
| 161 | StringRef Name; | |
| 162 | if (auto EC = COFFObj->getSectionName(Sec, Name)) | |
| 163 | fatal("getSectionName failed: #" + Twine(SectionNumber) + ": " + | |
| 164 | EC.message()); | |
| 165 | ||
| 166 | if (Name == ".drectve") { | |
| 167 | ArrayRef<uint8_t> Data; | |
| 168 | COFFObj->getSectionContents(Sec, Data); | |
| 169 | Directives = std::string((const char *)Data.data(), Data.size()); | |
| 165 | SectionChunk *ObjFile::readSection(uint32_t sectionNumber, | |
| 166 | const coff_aux_section_definition *def, | |
| 167 | StringRef leaderName) { | |
| 168 | const coff_section *sec = getSection(sectionNumber); | |
| 169 | ||
| 170 | StringRef name; | |
| 171 | if (Expected<StringRef> e = coffObj->getSectionName(sec)) | |
| 172 | name = *e; | |
| 173 | else | |
| 174 | fatal("getSectionName failed: #" + Twine(sectionNumber) + ": " + | |
| 175 | toString(e.takeError())); | |
| 176 | ||
| 177 | if (name == ".drectve") { | |
| 178 | ArrayRef<uint8_t> data; | |
| 179 | cantFail(coffObj->getSectionContents(sec, data)); | |
| 180 | directives = StringRef((const char *)data.data(), data.size()); | |
| 170 | 181 | return nullptr; |
| 171 | 182 | } |
| 172 | 183 | |
| 173 | if (Name == ".llvm_addrsig") { | |
| 174 | AddrsigSec = Sec; | |
| 184 | if (name == ".llvm_addrsig") { | |
| 185 | addrsigSec = sec; | |
| 175 | 186 | return nullptr; |
| 176 | 187 | } |
| 177 | 188 | |
| ... | ... | @@ -186,377 +197,648 @@ SectionChunk *ObjFile::readSection(uint32_t SectionNumber, |
| 186 | 197 | // and then write it to a separate .pdb file. |
| 187 | 198 | |
| 188 | 199 | // Ignore DWARF debug info unless /debug is given. |
| 189 | if (!Config->Debug && Name.startswith(".debug_")) | |
| 200 | if (!config->debug && name.startswith(".debug_")) | |
| 190 | 201 | return nullptr; |
| 191 | 202 | |
| 192 | if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) | |
| 203 | if (sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) | |
| 193 | 204 | return nullptr; |
| 194 | auto *C = make<SectionChunk>(this, Sec); | |
| 195 | if (Def) | |
| 196 | C->Checksum = Def->CheckSum; | |
| 205 | auto *c = make<SectionChunk>(this, sec); | |
| 206 | if (def) | |
| 207 | c->checksum = def->CheckSum; | |
| 208 | ||
| 209 | // link.exe uses the presence of .rsrc$01 for LNK4078, so match that. | |
| 210 | if (name == ".rsrc$01") | |
| 211 | isResourceObjFile = true; | |
| 197 | 212 | |
| 198 | 213 | // CodeView sections are stored to a different vector because they are not |
| 199 | 214 | // linked in the regular manner. |
| 200 | if (C->isCodeView()) | |
| 201 | DebugChunks.push_back(C); | |
| 202 | else if (Config->GuardCF != GuardCFLevel::Off && Name == ".gfids$y") | |
| 203 | GuardFidChunks.push_back(C); | |
| 204 | else if (Config->GuardCF != GuardCFLevel::Off && Name == ".gljmp$y") | |
| 205 | GuardLJmpChunks.push_back(C); | |
| 206 | else if (Name == ".sxdata") | |
| 207 | SXDataChunks.push_back(C); | |
| 208 | else if (Config->TailMerge && Sec->NumberOfRelocations == 0 && | |
| 209 | Name == ".rdata" && LeaderName.startswith("??_C@")) | |
| 215 | if (c->isCodeView()) | |
| 216 | debugChunks.push_back(c); | |
| 217 | else if (name == ".gfids$y") | |
| 218 | guardFidChunks.push_back(c); | |
| 219 | else if (name == ".gljmp$y") | |
| 220 | guardLJmpChunks.push_back(c); | |
| 221 | else if (name == ".sxdata") | |
| 222 | sXDataChunks.push_back(c); | |
| 223 | else if (config->tailMerge && sec->NumberOfRelocations == 0 && | |
| 224 | name == ".rdata" && leaderName.startswith("??_C@")) | |
| 210 | 225 | // COFF sections that look like string literal sections (i.e. no |
| 211 | 226 | // relocations, in .rdata, leader symbol name matches the MSVC name mangling |
| 212 | 227 | // for string literals) are subject to string tail merging. |
| 213 | MergeChunk::addSection(C); | |
| 228 | MergeChunk::addSection(c); | |
| 214 | 229 | else |
| 215 | Chunks.push_back(C); | |
| 230 | chunks.push_back(c); | |
| 216 | 231 | |
| 217 | return C; | |
| 232 | return c; | |
| 218 | 233 | } |
| 219 | 234 | |
| 220 | 235 | void ObjFile::readAssociativeDefinition( |
| 221 | COFFSymbolRef Sym, const coff_aux_section_definition *Def) { | |
| 222 | readAssociativeDefinition(Sym, Def, Def->getNumber(Sym.isBigObj())); | |
| 236 | COFFSymbolRef sym, const coff_aux_section_definition *def) { | |
| 237 | readAssociativeDefinition(sym, def, def->getNumber(sym.isBigObj())); | |
| 223 | 238 | } |
| 224 | 239 | |
| 225 | void ObjFile::readAssociativeDefinition(COFFSymbolRef Sym, | |
| 226 | const coff_aux_section_definition *Def, | |
| 227 | uint32_t ParentSection) { | |
| 228 | SectionChunk *Parent = SparseChunks[ParentSection]; | |
| 240 | void ObjFile::readAssociativeDefinition(COFFSymbolRef sym, | |
| 241 | const coff_aux_section_definition *def, | |
| 242 | uint32_t parentIndex) { | |
| 243 | SectionChunk *parent = sparseChunks[parentIndex]; | |
| 244 | int32_t sectionNumber = sym.getSectionNumber(); | |
| 245 | ||
| 246 | auto diag = [&]() { | |
| 247 | StringRef name, parentName; | |
| 248 | coffObj->getSymbolName(sym, name); | |
| 249 | ||
| 250 | const coff_section *parentSec = getSection(parentIndex); | |
| 251 | if (Expected<StringRef> e = coffObj->getSectionName(parentSec)) | |
| 252 | parentName = *e; | |
| 253 | error(toString(this) + ": associative comdat " + name + " (sec " + | |
| 254 | Twine(sectionNumber) + ") has invalid reference to section " + | |
| 255 | parentName + " (sec " + Twine(parentIndex) + ")"); | |
| 256 | }; | |
| 229 | 257 | |
| 230 | // If the parent is pending, it probably means that its section definition | |
| 231 | // appears after us in the symbol table. Leave the associated section as | |
| 232 | // pending; we will handle it during the second pass in initializeSymbols(). | |
| 233 | if (Parent == PendingComdat) | |
| 258 | if (parent == pendingComdat) { | |
| 259 | // This can happen if an associative comdat refers to another associative | |
| 260 | // comdat that appears after it (invalid per COFF spec) or to a section | |
| 261 | // without any symbols. | |
| 262 | diag(); | |
| 234 | 263 | return; |
| 264 | } | |
| 235 | 265 | |
| 236 | 266 | // Check whether the parent is prevailing. If it is, so are we, and we read |
| 237 | 267 | // the section; otherwise mark it as discarded. |
| 238 | int32_t SectionNumber = Sym.getSectionNumber(); | |
| 239 | if (Parent) { | |
| 240 | SparseChunks[SectionNumber] = readSection(SectionNumber, Def, ""); | |
| 241 | if (SparseChunks[SectionNumber]) | |
| 242 | Parent->addAssociative(SparseChunks[SectionNumber]); | |
| 268 | if (parent) { | |
| 269 | SectionChunk *c = readSection(sectionNumber, def, ""); | |
| 270 | sparseChunks[sectionNumber] = c; | |
| 271 | if (c) { | |
| 272 | c->selection = IMAGE_COMDAT_SELECT_ASSOCIATIVE; | |
| 273 | parent->addAssociative(c); | |
| 274 | } | |
| 243 | 275 | } else { |
| 244 | SparseChunks[SectionNumber] = nullptr; | |
| 276 | sparseChunks[sectionNumber] = nullptr; | |
| 245 | 277 | } |
| 246 | 278 | } |
| 247 | 279 | |
| 248 | 280 | void ObjFile::recordPrevailingSymbolForMingw( |
| 249 | COFFSymbolRef Sym, DenseMap<StringRef, uint32_t> &PrevailingSectionMap) { | |
| 281 | COFFSymbolRef sym, DenseMap<StringRef, uint32_t> &prevailingSectionMap) { | |
| 250 | 282 | // For comdat symbols in executable sections, where this is the copy |
| 251 | 283 | // of the section chunk we actually include instead of discarding it, |
| 252 | 284 | // add the symbol to a map to allow using it for implicitly |
| 253 | 285 | // associating .[px]data$<func> sections to it. |
| 254 | int32_t SectionNumber = Sym.getSectionNumber(); | |
| 255 | SectionChunk *SC = SparseChunks[SectionNumber]; | |
| 256 | if (SC && SC->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) { | |
| 257 | StringRef Name; | |
| 258 | COFFObj->getSymbolName(Sym, Name); | |
| 259 | PrevailingSectionMap[Name] = SectionNumber; | |
| 286 | int32_t sectionNumber = sym.getSectionNumber(); | |
| 287 | SectionChunk *sc = sparseChunks[sectionNumber]; | |
| 288 | if (sc && sc->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) { | |
| 289 | StringRef name; | |
| 290 | coffObj->getSymbolName(sym, name); | |
| 291 | if (getMachineType() == I386) | |
| 292 | name.consume_front("_"); | |
| 293 | prevailingSectionMap[name] = sectionNumber; | |
| 260 | 294 | } |
| 261 | 295 | } |
| 262 | 296 | |
| 263 | 297 | void ObjFile::maybeAssociateSEHForMingw( |
| 264 | COFFSymbolRef Sym, const coff_aux_section_definition *Def, | |
| 265 | const DenseMap<StringRef, uint32_t> &PrevailingSectionMap) { | |
| 266 | StringRef Name; | |
| 267 | COFFObj->getSymbolName(Sym, Name); | |
| 268 | if (Name.consume_front(".pdata$") || Name.consume_front(".xdata$")) { | |
| 269 | // For MinGW, treat .[px]data$<func> as implicitly associative to | |
| 270 | // the symbol <func>. | |
| 271 | auto ParentSym = PrevailingSectionMap.find(Name); | |
| 272 | if (ParentSym != PrevailingSectionMap.end()) | |
| 273 | readAssociativeDefinition(Sym, Def, ParentSym->second); | |
| 298 | COFFSymbolRef sym, const coff_aux_section_definition *def, | |
| 299 | const DenseMap<StringRef, uint32_t> &prevailingSectionMap) { | |
| 300 | StringRef name; | |
| 301 | coffObj->getSymbolName(sym, name); | |
| 302 | if (name.consume_front(".pdata$") || name.consume_front(".xdata$") || | |
| 303 | name.consume_front(".eh_frame$")) { | |
| 304 | // For MinGW, treat .[px]data$<func> and .eh_frame$<func> as implicitly | |
| 305 | // associative to the symbol <func>. | |
| 306 | auto parentSym = prevailingSectionMap.find(name); | |
| 307 | if (parentSym != prevailingSectionMap.end()) | |
| 308 | readAssociativeDefinition(sym, def, parentSym->second); | |
| 274 | 309 | } |
| 275 | 310 | } |
| 276 | 311 | |
| 277 | Symbol *ObjFile::createRegular(COFFSymbolRef Sym) { | |
| 278 | SectionChunk *SC = SparseChunks[Sym.getSectionNumber()]; | |
| 279 | if (Sym.isExternal()) { | |
| 280 | StringRef Name; | |
| 281 | COFFObj->getSymbolName(Sym, Name); | |
| 282 | if (SC) | |
| 283 | return Symtab->addRegular(this, Name, Sym.getGeneric(), SC); | |
| 312 | Symbol *ObjFile::createRegular(COFFSymbolRef sym) { | |
| 313 | SectionChunk *sc = sparseChunks[sym.getSectionNumber()]; | |
| 314 | if (sym.isExternal()) { | |
| 315 | StringRef name; | |
| 316 | coffObj->getSymbolName(sym, name); | |
| 317 | if (sc) | |
| 318 | return symtab->addRegular(this, name, sym.getGeneric(), sc); | |
| 284 | 319 | // For MinGW symbols named .weak.* that point to a discarded section, |
| 285 | 320 | // don't create an Undefined symbol. If nothing ever refers to the symbol, |
| 286 | 321 | // everything should be fine. If something actually refers to the symbol |
| 287 | 322 | // (e.g. the undefined weak alias), linking will fail due to undefined |
| 288 | 323 | // references at the end. |
| 289 | if (Config->MinGW && Name.startswith(".weak.")) | |
| 324 | if (config->mingw && name.startswith(".weak.")) | |
| 290 | 325 | return nullptr; |
| 291 | return Symtab->addUndefined(Name, this, false); | |
| 326 | return symtab->addUndefined(name, this, false); | |
| 292 | 327 | } |
| 293 | if (SC) | |
| 328 | if (sc) | |
| 294 | 329 | return make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false, |
| 295 | /*IsExternal*/ false, Sym.getGeneric(), SC); | |
| 330 | /*IsExternal*/ false, sym.getGeneric(), sc); | |
| 296 | 331 | return nullptr; |
| 297 | 332 | } |
| 298 | 333 | |
| 299 | 334 | void ObjFile::initializeSymbols() { |
| 300 | uint32_t NumSymbols = COFFObj->getNumberOfSymbols(); | |
| 301 | Symbols.resize(NumSymbols); | |
| 302 | ||
| 303 | SmallVector<std::pair<Symbol *, uint32_t>, 8> WeakAliases; | |
| 304 | std::vector<uint32_t> PendingIndexes; | |
| 305 | PendingIndexes.reserve(NumSymbols); | |
| 306 | ||
| 307 | DenseMap<StringRef, uint32_t> PrevailingSectionMap; | |
| 308 | std::vector<const coff_aux_section_definition *> ComdatDefs( | |
| 309 | COFFObj->getNumberOfSections() + 1); | |
| 310 | ||
| 311 | for (uint32_t I = 0; I < NumSymbols; ++I) { | |
| 312 | COFFSymbolRef COFFSym = check(COFFObj->getSymbol(I)); | |
| 313 | bool PrevailingComdat; | |
| 314 | if (COFFSym.isUndefined()) { | |
| 315 | Symbols[I] = createUndefined(COFFSym); | |
| 316 | } else if (COFFSym.isWeakExternal()) { | |
| 317 | Symbols[I] = createUndefined(COFFSym); | |
| 318 | uint32_t TagIndex = COFFSym.getAux<coff_aux_weak_external>()->TagIndex; | |
| 319 | WeakAliases.emplace_back(Symbols[I], TagIndex); | |
| 320 | } else if (Optional<Symbol *> OptSym = | |
| 321 | createDefined(COFFSym, ComdatDefs, PrevailingComdat)) { | |
| 322 | Symbols[I] = *OptSym; | |
| 323 | if (Config->MinGW && PrevailingComdat) | |
| 324 | recordPrevailingSymbolForMingw(COFFSym, PrevailingSectionMap); | |
| 335 | uint32_t numSymbols = coffObj->getNumberOfSymbols(); | |
| 336 | symbols.resize(numSymbols); | |
| 337 | ||
| 338 | SmallVector<std::pair<Symbol *, uint32_t>, 8> weakAliases; | |
| 339 | std::vector<uint32_t> pendingIndexes; | |
| 340 | pendingIndexes.reserve(numSymbols); | |
| 341 | ||
| 342 | DenseMap<StringRef, uint32_t> prevailingSectionMap; | |
| 343 | std::vector<const coff_aux_section_definition *> comdatDefs( | |
| 344 | coffObj->getNumberOfSections() + 1); | |
| 345 | ||
| 346 | for (uint32_t i = 0; i < numSymbols; ++i) { | |
| 347 | COFFSymbolRef coffSym = check(coffObj->getSymbol(i)); | |
| 348 | bool prevailingComdat; | |
| 349 | if (coffSym.isUndefined()) { | |
| 350 | symbols[i] = createUndefined(coffSym); | |
| 351 | } else if (coffSym.isWeakExternal()) { | |
| 352 | symbols[i] = createUndefined(coffSym); | |
| 353 | uint32_t tagIndex = coffSym.getAux<coff_aux_weak_external>()->TagIndex; | |
| 354 | weakAliases.emplace_back(symbols[i], tagIndex); | |
| 355 | } else if (Optional<Symbol *> optSym = | |
| 356 | createDefined(coffSym, comdatDefs, prevailingComdat)) { | |
| 357 | symbols[i] = *optSym; | |
| 358 | if (config->mingw && prevailingComdat) | |
| 359 | recordPrevailingSymbolForMingw(coffSym, prevailingSectionMap); | |
| 325 | 360 | } else { |
| 326 | 361 | // createDefined() returns None if a symbol belongs to a section that |
| 327 | 362 | // was pending at the point when the symbol was read. This can happen in |
| 328 | 363 | // two cases: |
| 329 | 364 | // 1) section definition symbol for a comdat leader; |
| 330 | // 2) symbol belongs to a comdat section associated with a section whose | |
| 331 | // section definition symbol appears later in the symbol table. | |
| 365 | // 2) symbol belongs to a comdat section associated with another section. | |
| 332 | 366 | // In both of these cases, we can expect the section to be resolved by |
| 333 | 367 | // the time we finish visiting the remaining symbols in the symbol |
| 334 | 368 | // table. So we postpone the handling of this symbol until that time. |
| 335 | PendingIndexes.push_back(I); | |
| 369 | pendingIndexes.push_back(i); | |
| 336 | 370 | } |
| 337 | I += COFFSym.getNumberOfAuxSymbols(); | |
| 371 | i += coffSym.getNumberOfAuxSymbols(); | |
| 338 | 372 | } |
| 339 | 373 | |
| 340 | for (uint32_t I : PendingIndexes) { | |
| 341 | COFFSymbolRef Sym = check(COFFObj->getSymbol(I)); | |
| 342 | if (const coff_aux_section_definition *Def = Sym.getSectionDefinition()) { | |
| 343 | if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) | |
| 344 | readAssociativeDefinition(Sym, Def); | |
| 345 | else if (Config->MinGW) | |
| 346 | maybeAssociateSEHForMingw(Sym, Def, PrevailingSectionMap); | |
| 374 | for (uint32_t i : pendingIndexes) { | |
| 375 | COFFSymbolRef sym = check(coffObj->getSymbol(i)); | |
| 376 | if (const coff_aux_section_definition *def = sym.getSectionDefinition()) { | |
| 377 | if (def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) | |
| 378 | readAssociativeDefinition(sym, def); | |
| 379 | else if (config->mingw) | |
| 380 | maybeAssociateSEHForMingw(sym, def, prevailingSectionMap); | |
| 347 | 381 | } |
| 348 | if (SparseChunks[Sym.getSectionNumber()] == PendingComdat) { | |
| 349 | StringRef Name; | |
| 350 | COFFObj->getSymbolName(Sym, Name); | |
| 351 | log("comdat section " + Name + | |
| 382 | if (sparseChunks[sym.getSectionNumber()] == pendingComdat) { | |
| 383 | StringRef name; | |
| 384 | coffObj->getSymbolName(sym, name); | |
| 385 | log("comdat section " + name + | |
| 352 | 386 | " without leader and unassociated, discarding"); |
| 353 | 387 | continue; |
| 354 | 388 | } |
| 355 | Symbols[I] = createRegular(Sym); | |
| 389 | symbols[i] = createRegular(sym); | |
| 356 | 390 | } |
| 357 | 391 | |
| 358 | for (auto &KV : WeakAliases) { | |
| 359 | Symbol *Sym = KV.first; | |
| 360 | uint32_t Idx = KV.second; | |
| 361 | checkAndSetWeakAlias(Symtab, this, Sym, Symbols[Idx]); | |
| 392 | for (auto &kv : weakAliases) { | |
| 393 | Symbol *sym = kv.first; | |
| 394 | uint32_t idx = kv.second; | |
| 395 | checkAndSetWeakAlias(symtab, this, sym, symbols[idx]); | |
| 362 | 396 | } |
| 363 | 397 | } |
| 364 | 398 | |
| 365 | Symbol *ObjFile::createUndefined(COFFSymbolRef Sym) { | |
| 366 | StringRef Name; | |
| 367 | COFFObj->getSymbolName(Sym, Name); | |
| 368 | return Symtab->addUndefined(Name, this, Sym.isWeakExternal()); | |
| 399 | Symbol *ObjFile::createUndefined(COFFSymbolRef sym) { | |
| 400 | StringRef name; | |
| 401 | coffObj->getSymbolName(sym, name); | |
| 402 | return symtab->addUndefined(name, this, sym.isWeakExternal()); | |
| 403 | } | |
| 404 | ||
| 405 | void ObjFile::handleComdatSelection(COFFSymbolRef sym, COMDATType &selection, | |
| 406 | bool &prevailing, DefinedRegular *leader) { | |
| 407 | if (prevailing) | |
| 408 | return; | |
| 409 | // There's already an existing comdat for this symbol: `Leader`. | |
| 410 | // Use the comdats's selection field to determine if the new | |
| 411 | // symbol in `Sym` should be discarded, produce a duplicate symbol | |
| 412 | // error, etc. | |
| 413 | ||
| 414 | SectionChunk *leaderChunk = nullptr; | |
| 415 | COMDATType leaderSelection = IMAGE_COMDAT_SELECT_ANY; | |
| 416 | ||
| 417 | if (leader->data) { | |
| 418 | leaderChunk = leader->getChunk(); | |
| 419 | leaderSelection = leaderChunk->selection; | |
| 420 | } else { | |
| 421 | // FIXME: comdats from LTO files don't know their selection; treat them | |
| 422 | // as "any". | |
| 423 | selection = leaderSelection; | |
| 424 | } | |
| 425 | ||
| 426 | if ((selection == IMAGE_COMDAT_SELECT_ANY && | |
| 427 | leaderSelection == IMAGE_COMDAT_SELECT_LARGEST) || | |
| 428 | (selection == IMAGE_COMDAT_SELECT_LARGEST && | |
| 429 | leaderSelection == IMAGE_COMDAT_SELECT_ANY)) { | |
| 430 | // cl.exe picks "any" for vftables when building with /GR- and | |
| 431 | // "largest" when building with /GR. To be able to link object files | |
| 432 | // compiled with each flag, "any" and "largest" are merged as "largest". | |
| 433 | leaderSelection = selection = IMAGE_COMDAT_SELECT_LARGEST; | |
| 434 | } | |
| 435 | ||
| 436 | // Other than that, comdat selections must match. This is a bit more | |
| 437 | // strict than link.exe which allows merging "any" and "largest" if "any" | |
| 438 | // is the first symbol the linker sees, and it allows merging "largest" | |
| 439 | // with everything (!) if "largest" is the first symbol the linker sees. | |
| 440 | // Making this symmetric independent of which selection is seen first | |
| 441 | // seems better though. | |
| 442 | // (This behavior matches ModuleLinker::getComdatResult().) | |
| 443 | if (selection != leaderSelection) { | |
| 444 | log(("conflicting comdat type for " + toString(*leader) + ": " + | |
| 445 | Twine((int)leaderSelection) + " in " + toString(leader->getFile()) + | |
| 446 | " and " + Twine((int)selection) + " in " + toString(this)) | |
| 447 | .str()); | |
| 448 | symtab->reportDuplicate(leader, this); | |
| 449 | return; | |
| 450 | } | |
| 451 | ||
| 452 | switch (selection) { | |
| 453 | case IMAGE_COMDAT_SELECT_NODUPLICATES: | |
| 454 | symtab->reportDuplicate(leader, this); | |
| 455 | break; | |
| 456 | ||
| 457 | case IMAGE_COMDAT_SELECT_ANY: | |
| 458 | // Nothing to do. | |
| 459 | break; | |
| 460 | ||
| 461 | case IMAGE_COMDAT_SELECT_SAME_SIZE: | |
| 462 | if (leaderChunk->getSize() != getSection(sym)->SizeOfRawData) | |
| 463 | symtab->reportDuplicate(leader, this); | |
| 464 | break; | |
| 465 | ||
| 466 | case IMAGE_COMDAT_SELECT_EXACT_MATCH: { | |
| 467 | SectionChunk newChunk(this, getSection(sym)); | |
| 468 | // link.exe only compares section contents here and doesn't complain | |
| 469 | // if the two comdat sections have e.g. different alignment. | |
| 470 | // Match that. | |
| 471 | if (leaderChunk->getContents() != newChunk.getContents()) | |
| 472 | symtab->reportDuplicate(leader, this); | |
| 473 | break; | |
| 474 | } | |
| 475 | ||
| 476 | case IMAGE_COMDAT_SELECT_ASSOCIATIVE: | |
| 477 | // createDefined() is never called for IMAGE_COMDAT_SELECT_ASSOCIATIVE. | |
| 478 | // (This means lld-link doesn't produce duplicate symbol errors for | |
| 479 | // associative comdats while link.exe does, but associate comdats | |
| 480 | // are never extern in practice.) | |
| 481 | llvm_unreachable("createDefined not called for associative comdats"); | |
| 482 | ||
| 483 | case IMAGE_COMDAT_SELECT_LARGEST: | |
| 484 | if (leaderChunk->getSize() < getSection(sym)->SizeOfRawData) { | |
| 485 | // Replace the existing comdat symbol with the new one. | |
| 486 | StringRef name; | |
| 487 | coffObj->getSymbolName(sym, name); | |
| 488 | // FIXME: This is incorrect: With /opt:noref, the previous sections | |
| 489 | // make it into the final executable as well. Correct handling would | |
| 490 | // be to undo reading of the whole old section that's being replaced, | |
| 491 | // or doing one pass that determines what the final largest comdat | |
| 492 | // is for all IMAGE_COMDAT_SELECT_LARGEST comdats and then reading | |
| 493 | // only the largest one. | |
| 494 | replaceSymbol<DefinedRegular>(leader, this, name, /*IsCOMDAT*/ true, | |
| 495 | /*IsExternal*/ true, sym.getGeneric(), | |
| 496 | nullptr); | |
| 497 | prevailing = true; | |
| 498 | } | |
| 499 | break; | |
| 500 | ||
| 501 | case IMAGE_COMDAT_SELECT_NEWEST: | |
| 502 | llvm_unreachable("should have been rejected earlier"); | |
| 503 | } | |
| 369 | 504 | } |
| 370 | 505 | |
| 371 | 506 | Optional<Symbol *> ObjFile::createDefined( |
| 372 | COFFSymbolRef Sym, | |
| 373 | std::vector<const coff_aux_section_definition *> &ComdatDefs, | |
| 374 | bool &Prevailing) { | |
| 375 | Prevailing = false; | |
| 376 | auto GetName = [&]() { | |
| 377 | StringRef S; | |
| 378 | COFFObj->getSymbolName(Sym, S); | |
| 379 | return S; | |
| 507 | COFFSymbolRef sym, | |
| 508 | std::vector<const coff_aux_section_definition *> &comdatDefs, | |
| 509 | bool &prevailing) { | |
| 510 | prevailing = false; | |
| 511 | auto getName = [&]() { | |
| 512 | StringRef s; | |
| 513 | coffObj->getSymbolName(sym, s); | |
| 514 | return s; | |
| 380 | 515 | }; |
| 381 | 516 | |
| 382 | if (Sym.isCommon()) { | |
| 383 | auto *C = make<CommonChunk>(Sym); | |
| 384 | Chunks.push_back(C); | |
| 385 | return Symtab->addCommon(this, GetName(), Sym.getValue(), Sym.getGeneric(), | |
| 386 | C); | |
| 517 | if (sym.isCommon()) { | |
| 518 | auto *c = make<CommonChunk>(sym); | |
| 519 | chunks.push_back(c); | |
| 520 | return symtab->addCommon(this, getName(), sym.getValue(), sym.getGeneric(), | |
| 521 | c); | |
| 387 | 522 | } |
| 388 | 523 | |
| 389 | if (Sym.isAbsolute()) { | |
| 390 | StringRef Name = GetName(); | |
| 524 | if (sym.isAbsolute()) { | |
| 525 | StringRef name = getName(); | |
| 391 | 526 | |
| 392 | 527 | // Skip special symbols. |
| 393 | if (Name == "@comp.id") | |
| 528 | if (name == "@comp.id") | |
| 394 | 529 | return nullptr; |
| 395 | if (Name == "@feat.00") { | |
| 396 | Feat00Flags = Sym.getValue(); | |
| 530 | if (name == "@feat.00") { | |
| 531 | feat00Flags = sym.getValue(); | |
| 397 | 532 | return nullptr; |
| 398 | 533 | } |
| 399 | 534 | |
| 400 | if (Sym.isExternal()) | |
| 401 | return Symtab->addAbsolute(Name, Sym); | |
| 402 | return make<DefinedAbsolute>(Name, Sym); | |
| 535 | if (sym.isExternal()) | |
| 536 | return symtab->addAbsolute(name, sym); | |
| 537 | return make<DefinedAbsolute>(name, sym); | |
| 403 | 538 | } |
| 404 | 539 | |
| 405 | int32_t SectionNumber = Sym.getSectionNumber(); | |
| 406 | if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG) | |
| 540 | int32_t sectionNumber = sym.getSectionNumber(); | |
| 541 | if (sectionNumber == llvm::COFF::IMAGE_SYM_DEBUG) | |
| 407 | 542 | return nullptr; |
| 408 | 543 | |
| 409 | if (llvm::COFF::isReservedSectionNumber(SectionNumber)) | |
| 410 | fatal(toString(this) + ": " + GetName() + | |
| 411 | " should not refer to special section " + Twine(SectionNumber)); | |
| 412 | ||
| 413 | if ((uint32_t)SectionNumber >= SparseChunks.size()) | |
| 414 | fatal(toString(this) + ": " + GetName() + | |
| 415 | " should not refer to non-existent section " + Twine(SectionNumber)); | |
| 416 | ||
| 417 | // Handle comdat leader symbols. | |
| 418 | if (const coff_aux_section_definition *Def = ComdatDefs[SectionNumber]) { | |
| 419 | ComdatDefs[SectionNumber] = nullptr; | |
| 420 | Symbol *Leader; | |
| 421 | if (Sym.isExternal()) { | |
| 422 | std::tie(Leader, Prevailing) = | |
| 423 | Symtab->addComdat(this, GetName(), Sym.getGeneric()); | |
| 544 | if (llvm::COFF::isReservedSectionNumber(sectionNumber)) | |
| 545 | fatal(toString(this) + ": " + getName() + | |
| 546 | " should not refer to special section " + Twine(sectionNumber)); | |
| 547 | ||
| 548 | if ((uint32_t)sectionNumber >= sparseChunks.size()) | |
| 549 | fatal(toString(this) + ": " + getName() + | |
| 550 | " should not refer to non-existent section " + Twine(sectionNumber)); | |
| 551 | ||
| 552 | // Comdat handling. | |
| 553 | // A comdat symbol consists of two symbol table entries. | |
| 554 | // The first symbol entry has the name of the section (e.g. .text), fixed | |
| 555 | // values for the other fields, and one auxilliary record. | |
| 556 | // The second symbol entry has the name of the comdat symbol, called the | |
| 557 | // "comdat leader". | |
| 558 | // When this function is called for the first symbol entry of a comdat, | |
| 559 | // it sets comdatDefs and returns None, and when it's called for the second | |
| 560 | // symbol entry it reads comdatDefs and then sets it back to nullptr. | |
| 561 | ||
| 562 | // Handle comdat leader. | |
| 563 | if (const coff_aux_section_definition *def = comdatDefs[sectionNumber]) { | |
| 564 | comdatDefs[sectionNumber] = nullptr; | |
| 565 | DefinedRegular *leader; | |
| 566 | ||
| 567 | if (sym.isExternal()) { | |
| 568 | std::tie(leader, prevailing) = | |
| 569 | symtab->addComdat(this, getName(), sym.getGeneric()); | |
| 424 | 570 | } else { |
| 425 | Leader = make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false, | |
| 426 | /*IsExternal*/ false, Sym.getGeneric()); | |
| 427 | Prevailing = true; | |
| 571 | leader = make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false, | |
| 572 | /*IsExternal*/ false, sym.getGeneric()); | |
| 573 | prevailing = true; | |
| 428 | 574 | } |
| 429 | 575 | |
| 430 | if (Prevailing) { | |
| 431 | SectionChunk *C = readSection(SectionNumber, Def, GetName()); | |
| 432 | SparseChunks[SectionNumber] = C; | |
| 433 | C->Sym = cast<DefinedRegular>(Leader); | |
| 434 | cast<DefinedRegular>(Leader)->Data = &C->Repl; | |
| 435 | } else { | |
| 436 | SparseChunks[SectionNumber] = nullptr; | |
| 576 | if (def->Selection < (int)IMAGE_COMDAT_SELECT_NODUPLICATES || | |
| 577 | // Intentionally ends at IMAGE_COMDAT_SELECT_LARGEST: link.exe | |
| 578 | // doesn't understand IMAGE_COMDAT_SELECT_NEWEST either. | |
| 579 | def->Selection > (int)IMAGE_COMDAT_SELECT_LARGEST) { | |
| 580 | fatal("unknown comdat type " + std::to_string((int)def->Selection) + | |
| 581 | " for " + getName() + " in " + toString(this)); | |
| 437 | 582 | } |
| 438 | return Leader; | |
| 439 | } | |
| 583 | COMDATType selection = (COMDATType)def->Selection; | |
| 440 | 584 | |
| 441 | // Read associative section definitions and prepare to handle the comdat | |
| 442 | // leader symbol by setting the section's ComdatDefs pointer if we encounter a | |
| 443 | // non-associative comdat. | |
| 444 | if (SparseChunks[SectionNumber] == PendingComdat) { | |
| 445 | if (const coff_aux_section_definition *Def = Sym.getSectionDefinition()) { | |
| 446 | if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) | |
| 447 | readAssociativeDefinition(Sym, Def); | |
| 448 | else | |
| 449 | ComdatDefs[SectionNumber] = Def; | |
| 585 | if (leader->isCOMDAT) | |
| 586 | handleComdatSelection(sym, selection, prevailing, leader); | |
| 587 | ||
| 588 | if (prevailing) { | |
| 589 | SectionChunk *c = readSection(sectionNumber, def, getName()); | |
| 590 | sparseChunks[sectionNumber] = c; | |
| 591 | c->sym = cast<DefinedRegular>(leader); | |
| 592 | c->selection = selection; | |
| 593 | cast<DefinedRegular>(leader)->data = &c->repl; | |
| 594 | } else { | |
| 595 | sparseChunks[sectionNumber] = nullptr; | |
| 450 | 596 | } |
| 597 | return leader; | |
| 451 | 598 | } |
| 452 | 599 | |
| 453 | // readAssociativeDefinition() writes to SparseChunks, so need to check again. | |
| 454 | if (SparseChunks[SectionNumber] == PendingComdat) | |
| 600 | // Prepare to handle the comdat leader symbol by setting the section's | |
| 601 | // ComdatDefs pointer if we encounter a non-associative comdat. | |
| 602 | if (sparseChunks[sectionNumber] == pendingComdat) { | |
| 603 | if (const coff_aux_section_definition *def = sym.getSectionDefinition()) { | |
| 604 | if (def->Selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE) | |
| 605 | comdatDefs[sectionNumber] = def; | |
| 606 | } | |
| 455 | 607 | return None; |
| 608 | } | |
| 456 | 609 | |
| 457 | return createRegular(Sym); | |
| 610 | return createRegular(sym); | |
| 458 | 611 | } |
| 459 | 612 | |
| 460 | 613 | MachineTypes ObjFile::getMachineType() { |
| 461 | if (COFFObj) | |
| 462 | return static_cast<MachineTypes>(COFFObj->getMachine()); | |
| 614 | if (coffObj) | |
| 615 | return static_cast<MachineTypes>(coffObj->getMachine()); | |
| 463 | 616 | return IMAGE_FILE_MACHINE_UNKNOWN; |
| 464 | 617 | } |
| 465 | 618 | |
| 466 | StringRef ltrim1(StringRef S, const char *Chars) { | |
| 467 | if (!S.empty() && strchr(Chars, S[0])) | |
| 468 | return S.substr(1); | |
| 469 | return S; | |
| 619 | ArrayRef<uint8_t> ObjFile::getDebugSection(StringRef secName) { | |
| 620 | if (SectionChunk *sec = SectionChunk::findByName(debugChunks, secName)) | |
| 621 | return sec->consumeDebugMagic(); | |
| 622 | return {}; | |
| 623 | } | |
| 624 | ||
| 625 | // OBJ files systematically store critical informations in a .debug$S stream, | |
| 626 | // even if the TU was compiled with no debug info. At least two records are | |
| 627 | // always there. S_OBJNAME stores a 32-bit signature, which is loaded into the | |
| 628 | // PCHSignature member. S_COMPILE3 stores compile-time cmd-line flags. This is | |
| 629 | // currently used to initialize the hotPatchable member. | |
| 630 | void ObjFile::initializeFlags() { | |
| 631 | ArrayRef<uint8_t> data = getDebugSection(".debug$S"); | |
| 632 | if (data.empty()) | |
| 633 | return; | |
| 634 | ||
| 635 | DebugSubsectionArray subsections; | |
| 636 | ||
| 637 | BinaryStreamReader reader(data, support::little); | |
| 638 | ExitOnError exitOnErr; | |
| 639 | exitOnErr(reader.readArray(subsections, data.size())); | |
| 640 | ||
| 641 | for (const DebugSubsectionRecord &ss : subsections) { | |
| 642 | if (ss.kind() != DebugSubsectionKind::Symbols) | |
| 643 | continue; | |
| 644 | ||
| 645 | unsigned offset = 0; | |
| 646 | ||
| 647 | // Only parse the first two records. We are only looking for S_OBJNAME | |
| 648 | // and S_COMPILE3, and they usually appear at the beginning of the | |
| 649 | // stream. | |
| 650 | for (unsigned i = 0; i < 2; ++i) { | |
| 651 | Expected<CVSymbol> sym = readSymbolFromStream(ss.getRecordData(), offset); | |
| 652 | if (!sym) { | |
| 653 | consumeError(sym.takeError()); | |
| 654 | return; | |
| 655 | } | |
| 656 | if (sym->kind() == SymbolKind::S_COMPILE3) { | |
| 657 | auto cs = | |
| 658 | cantFail(SymbolDeserializer::deserializeAs<Compile3Sym>(sym.get())); | |
| 659 | hotPatchable = | |
| 660 | (cs.Flags & CompileSym3Flags::HotPatch) != CompileSym3Flags::None; | |
| 661 | } | |
| 662 | if (sym->kind() == SymbolKind::S_OBJNAME) { | |
| 663 | auto objName = cantFail(SymbolDeserializer::deserializeAs<ObjNameSym>( | |
| 664 | sym.get())); | |
| 665 | pchSignature = objName.Signature; | |
| 666 | } | |
| 667 | offset += sym->length(); | |
| 668 | } | |
| 669 | } | |
| 670 | } | |
| 671 | ||
| 672 | // Depending on the compilation flags, OBJs can refer to external files, | |
| 673 | // necessary to merge this OBJ into the final PDB. We currently support two | |
| 674 | // types of external files: Precomp/PCH OBJs, when compiling with /Yc and /Yu. | |
| 675 | // And PDB type servers, when compiling with /Zi. This function extracts these | |
| 676 | // dependencies and makes them available as a TpiSource interface (see | |
| 677 | // DebugTypes.h). Both cases only happen with cl.exe: clang-cl produces regular | |
| 678 | // output even with /Yc and /Yu and with /Zi. | |
| 679 | void ObjFile::initializeDependencies() { | |
| 680 | if (!config->debug) | |
| 681 | return; | |
| 682 | ||
| 683 | bool isPCH = false; | |
| 684 | ||
| 685 | ArrayRef<uint8_t> data = getDebugSection(".debug$P"); | |
| 686 | if (!data.empty()) | |
| 687 | isPCH = true; | |
| 688 | else | |
| 689 | data = getDebugSection(".debug$T"); | |
| 690 | ||
| 691 | if (data.empty()) | |
| 692 | return; | |
| 693 | ||
| 694 | CVTypeArray types; | |
| 695 | BinaryStreamReader reader(data, support::little); | |
| 696 | cantFail(reader.readArray(types, reader.getLength())); | |
| 697 | ||
| 698 | CVTypeArray::Iterator firstType = types.begin(); | |
| 699 | if (firstType == types.end()) | |
| 700 | return; | |
| 701 | ||
| 702 | debugTypes.emplace(types); | |
| 703 | ||
| 704 | if (isPCH) { | |
| 705 | debugTypesObj = makePrecompSource(this); | |
| 706 | return; | |
| 707 | } | |
| 708 | ||
| 709 | if (firstType->kind() == LF_TYPESERVER2) { | |
| 710 | TypeServer2Record ts = cantFail( | |
| 711 | TypeDeserializer::deserializeAs<TypeServer2Record>(firstType->data())); | |
| 712 | debugTypesObj = makeUseTypeServerSource(this, &ts); | |
| 713 | return; | |
| 714 | } | |
| 715 | ||
| 716 | if (firstType->kind() == LF_PRECOMP) { | |
| 717 | PrecompRecord precomp = cantFail( | |
| 718 | TypeDeserializer::deserializeAs<PrecompRecord>(firstType->data())); | |
| 719 | debugTypesObj = makeUsePrecompSource(this, &precomp); | |
| 720 | return; | |
| 721 | } | |
| 722 | ||
| 723 | debugTypesObj = makeTpiSource(this); | |
| 724 | } | |
| 725 | ||
| 726 | StringRef ltrim1(StringRef s, const char *chars) { | |
| 727 | if (!s.empty() && strchr(chars, s[0])) | |
| 728 | return s.substr(1); | |
| 729 | return s; | |
| 470 | 730 | } |
| 471 | 731 | |
| 472 | 732 | void ImportFile::parse() { |
| 473 | const char *Buf = MB.getBufferStart(); | |
| 474 | const char *End = MB.getBufferEnd(); | |
| 475 | const auto *Hdr = reinterpret_cast<const coff_import_header *>(Buf); | |
| 733 | const char *buf = mb.getBufferStart(); | |
| 734 | const auto *hdr = reinterpret_cast<const coff_import_header *>(buf); | |
| 476 | 735 | |
| 477 | 736 | // Check if the total size is valid. |
| 478 | if ((size_t)(End - Buf) != (sizeof(*Hdr) + Hdr->SizeOfData)) | |
| 737 | if (mb.getBufferSize() != sizeof(*hdr) + hdr->SizeOfData) | |
| 479 | 738 | fatal("broken import library"); |
| 480 | 739 | |
| 481 | 740 | // Read names and create an __imp_ symbol. |
| 482 | StringRef Name = Saver.save(StringRef(Buf + sizeof(*Hdr))); | |
| 483 | StringRef ImpName = Saver.save("__imp_" + Name); | |
| 484 | const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1; | |
| 485 | DLLName = StringRef(NameStart); | |
| 486 | StringRef ExtName; | |
| 487 | switch (Hdr->getNameType()) { | |
| 741 | StringRef name = saver.save(StringRef(buf + sizeof(*hdr))); | |
| 742 | StringRef impName = saver.save("__imp_" + name); | |
| 743 | const char *nameStart = buf + sizeof(coff_import_header) + name.size() + 1; | |
| 744 | dllName = StringRef(nameStart); | |
| 745 | StringRef extName; | |
| 746 | switch (hdr->getNameType()) { | |
| 488 | 747 | case IMPORT_ORDINAL: |
| 489 | ExtName = ""; | |
| 748 | extName = ""; | |
| 490 | 749 | break; |
| 491 | 750 | case IMPORT_NAME: |
| 492 | ExtName = Name; | |
| 751 | extName = name; | |
| 493 | 752 | break; |
| 494 | 753 | case IMPORT_NAME_NOPREFIX: |
| 495 | ExtName = ltrim1(Name, "?@_"); | |
| 754 | extName = ltrim1(name, "?@_"); | |
| 496 | 755 | break; |
| 497 | 756 | case IMPORT_NAME_UNDECORATE: |
| 498 | ExtName = ltrim1(Name, "?@_"); | |
| 499 | ExtName = ExtName.substr(0, ExtName.find('@')); | |
| 757 | extName = ltrim1(name, "?@_"); | |
| 758 | extName = extName.substr(0, extName.find('@')); | |
| 500 | 759 | break; |
| 501 | 760 | } |
| 502 | 761 | |
| 503 | this->Hdr = Hdr; | |
| 504 | ExternalName = ExtName; | |
| 762 | this->hdr = hdr; | |
| 763 | externalName = extName; | |
| 505 | 764 | |
| 506 | ImpSym = Symtab->addImportData(ImpName, this); | |
| 765 | impSym = symtab->addImportData(impName, this); | |
| 507 | 766 | // If this was a duplicate, we logged an error but may continue; |
| 508 | // in this case, ImpSym is nullptr. | |
| 509 | if (!ImpSym) | |
| 767 | // in this case, impSym is nullptr. | |
| 768 | if (!impSym) | |
| 510 | 769 | return; |
| 511 | 770 | |
| 512 | if (Hdr->getType() == llvm::COFF::IMPORT_CONST) | |
| 513 | static_cast<void>(Symtab->addImportData(Name, this)); | |
| 771 | if (hdr->getType() == llvm::COFF::IMPORT_CONST) | |
| 772 | static_cast<void>(symtab->addImportData(name, this)); | |
| 514 | 773 | |
| 515 | 774 | // If type is function, we need to create a thunk which jump to an |
| 516 | 775 | // address pointed by the __imp_ symbol. (This allows you to call |
| 517 | 776 | // DLL functions just like regular non-DLL functions.) |
| 518 | if (Hdr->getType() == llvm::COFF::IMPORT_CODE) | |
| 519 | ThunkSym = Symtab->addImportThunk( | |
| 520 | Name, cast_or_null<DefinedImportData>(ImpSym), Hdr->Machine); | |
| 777 | if (hdr->getType() == llvm::COFF::IMPORT_CODE) | |
| 778 | thunkSym = symtab->addImportThunk( | |
| 779 | name, cast_or_null<DefinedImportData>(impSym), hdr->Machine); | |
| 780 | } | |
| 781 | ||
| 782 | BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName, | |
| 783 | uint64_t offsetInArchive) | |
| 784 | : InputFile(BitcodeKind, mb) { | |
| 785 | std::string path = mb.getBufferIdentifier().str(); | |
| 786 | if (config->thinLTOIndexOnly) | |
| 787 | path = replaceThinLTOSuffix(mb.getBufferIdentifier()); | |
| 788 | ||
| 789 | // ThinLTO assumes that all MemoryBufferRefs given to it have a unique | |
| 790 | // name. If two archives define two members with the same name, this | |
| 791 | // causes a collision which result in only one of the objects being taken | |
| 792 | // into consideration at LTO time (which very likely causes undefined | |
| 793 | // symbols later in the link stage). So we append file offset to make | |
| 794 | // filename unique. | |
| 795 | MemoryBufferRef mbref( | |
| 796 | mb.getBuffer(), | |
| 797 | saver.save(archiveName + path + | |
| 798 | (archiveName.empty() ? "" : utostr(offsetInArchive)))); | |
| 799 | ||
| 800 | obj = check(lto::InputFile::create(mbref)); | |
| 521 | 801 | } |
| 522 | 802 | |
| 523 | 803 | void BitcodeFile::parse() { |
| 524 | Obj = check(lto::InputFile::create(MemoryBufferRef( | |
| 525 | MB.getBuffer(), Saver.save(ParentName + MB.getBufferIdentifier())))); | |
| 526 | std::vector<std::pair<Symbol *, bool>> Comdat(Obj->getComdatTable().size()); | |
| 527 | for (size_t I = 0; I != Obj->getComdatTable().size(); ++I) | |
| 528 | Comdat[I] = Symtab->addComdat(this, Saver.save(Obj->getComdatTable()[I])); | |
| 529 | for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) { | |
| 530 | StringRef SymName = Saver.save(ObjSym.getName()); | |
| 531 | int ComdatIndex = ObjSym.getComdatIndex(); | |
| 532 | Symbol *Sym; | |
| 533 | if (ObjSym.isUndefined()) { | |
| 534 | Sym = Symtab->addUndefined(SymName, this, false); | |
| 535 | } else if (ObjSym.isCommon()) { | |
| 536 | Sym = Symtab->addCommon(this, SymName, ObjSym.getCommonSize()); | |
| 537 | } else if (ObjSym.isWeak() && ObjSym.isIndirect()) { | |
| 804 | std::vector<std::pair<Symbol *, bool>> comdat(obj->getComdatTable().size()); | |
| 805 | for (size_t i = 0; i != obj->getComdatTable().size(); ++i) | |
| 806 | // FIXME: lto::InputFile doesn't keep enough data to do correct comdat | |
| 807 | // selection handling. | |
| 808 | comdat[i] = symtab->addComdat(this, saver.save(obj->getComdatTable()[i])); | |
| 809 | for (const lto::InputFile::Symbol &objSym : obj->symbols()) { | |
| 810 | StringRef symName = saver.save(objSym.getName()); | |
| 811 | int comdatIndex = objSym.getComdatIndex(); | |
| 812 | Symbol *sym; | |
| 813 | if (objSym.isUndefined()) { | |
| 814 | sym = symtab->addUndefined(symName, this, false); | |
| 815 | } else if (objSym.isCommon()) { | |
| 816 | sym = symtab->addCommon(this, symName, objSym.getCommonSize()); | |
| 817 | } else if (objSym.isWeak() && objSym.isIndirect()) { | |
| 538 | 818 | // Weak external. |
| 539 | Sym = Symtab->addUndefined(SymName, this, true); | |
| 540 | std::string Fallback = ObjSym.getCOFFWeakExternalFallback(); | |
| 541 | Symbol *Alias = Symtab->addUndefined(Saver.save(Fallback)); | |
| 542 | checkAndSetWeakAlias(Symtab, this, Sym, Alias); | |
| 543 | } else if (ComdatIndex != -1) { | |
| 544 | if (SymName == Obj->getComdatTable()[ComdatIndex]) | |
| 545 | Sym = Comdat[ComdatIndex].first; | |
| 546 | else if (Comdat[ComdatIndex].second) | |
| 547 | Sym = Symtab->addRegular(this, SymName); | |
| 819 | sym = symtab->addUndefined(symName, this, true); | |
| 820 | std::string fallback = objSym.getCOFFWeakExternalFallback(); | |
| 821 | Symbol *alias = symtab->addUndefined(saver.save(fallback)); | |
| 822 | checkAndSetWeakAlias(symtab, this, sym, alias); | |
| 823 | } else if (comdatIndex != -1) { | |
| 824 | if (symName == obj->getComdatTable()[comdatIndex]) | |
| 825 | sym = comdat[comdatIndex].first; | |
| 826 | else if (comdat[comdatIndex].second) | |
| 827 | sym = symtab->addRegular(this, symName); | |
| 548 | 828 | else |
| 549 | Sym = Symtab->addUndefined(SymName, this, false); | |
| 829 | sym = symtab->addUndefined(symName, this, false); | |
| 550 | 830 | } else { |
| 551 | Sym = Symtab->addRegular(this, SymName); | |
| 831 | sym = symtab->addRegular(this, symName); | |
| 552 | 832 | } |
| 553 | Symbols.push_back(Sym); | |
| 833 | symbols.push_back(sym); | |
| 834 | if (objSym.isUsed()) | |
| 835 | config->gcroot.push_back(sym); | |
| 554 | 836 | } |
| 555 | Directives = Obj->getCOFFLinkerOpts(); | |
| 837 | directives = obj->getCOFFLinkerOpts(); | |
| 556 | 838 | } |
| 557 | 839 | |
| 558 | 840 | MachineTypes BitcodeFile::getMachineType() { |
| 559 | switch (Triple(Obj->getTargetTriple()).getArch()) { | |
| 841 | switch (Triple(obj->getTargetTriple()).getArch()) { | |
| 560 | 842 | case Triple::x86_64: |
| 561 | 843 | return AMD64; |
| 562 | 844 | case Triple::x86: |
| ... | ... | @@ -569,22 +851,31 @@ MachineTypes BitcodeFile::getMachineType() { |
| 569 | 851 | return IMAGE_FILE_MACHINE_UNKNOWN; |
| 570 | 852 | } |
| 571 | 853 | } |
| 854 | ||
| 855 | std::string replaceThinLTOSuffix(StringRef path) { | |
| 856 | StringRef suffix = config->thinLTOObjectSuffixReplace.first; | |
| 857 | StringRef repl = config->thinLTOObjectSuffixReplace.second; | |
| 858 | ||
| 859 | if (path.consume_back(suffix)) | |
| 860 | return (path + repl).str(); | |
| 861 | return path; | |
| 862 | } | |
| 572 | 863 | } // namespace coff |
| 573 | 864 | } // namespace lld |
| 574 | 865 | |
| 575 | 866 | // Returns the last element of a path, which is supposed to be a filename. |
| 576 | static StringRef getBasename(StringRef Path) { | |
| 577 | return sys::path::filename(Path, sys::path::Style::windows); | |
| 867 | static StringRef getBasename(StringRef path) { | |
| 868 | return sys::path::filename(path, sys::path::Style::windows); | |
| 578 | 869 | } |
| 579 | 870 | |
| 580 | 871 | // Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)". |
| 581 | std::string lld::toString(const coff::InputFile *File) { | |
| 582 | if (!File) | |
| 872 | std::string lld::toString(const coff::InputFile *file) { | |
| 873 | if (!file) | |
| 583 | 874 | return "<internal>"; |
| 584 | if (File->ParentName.empty()) | |
| 585 | return File->getName(); | |
| 875 | if (file->parentName.empty() || file->kind() == coff::InputFile::ImportKind) | |
| 876 | return file->getName(); | |
| 586 | 877 | |
| 587 | return (getBasename(File->ParentName) + "(" + getBasename(File->getName()) + | |
| 878 | return (getBasename(file->parentName) + "(" + getBasename(file->getName()) + | |
| 588 | 879 | ")") |
| 589 | 880 | .str(); |
| 590 | 881 | } |
deps/lld/COFF/InputFiles.h+125-84| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- InputFiles.h ---------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -33,7 +32,7 @@ class DbiModuleDescriptorBuilder; |
| 33 | 32 | namespace lld { |
| 34 | 33 | namespace coff { |
| 35 | 34 | |
| 36 | std::vector<MemoryBufferRef> getArchiveMembers(llvm::object::Archive *File); | |
| 35 | std::vector<MemoryBufferRef> getArchiveMembers(llvm::object::Archive *file); | |
| 37 | 36 | |
| 38 | 37 | using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN; |
| 39 | 38 | using llvm::COFF::MachineTypes; |
| ... | ... | @@ -47,20 +46,22 @@ class Chunk; |
| 47 | 46 | class Defined; |
| 48 | 47 | class DefinedImportData; |
| 49 | 48 | class DefinedImportThunk; |
| 49 | class DefinedRegular; | |
| 50 | 50 | class Lazy; |
| 51 | 51 | class SectionChunk; |
| 52 | 52 | class Symbol; |
| 53 | 53 | class Undefined; |
| 54 | class TpiSource; | |
| 54 | 55 | |
| 55 | 56 | // The root class of input files. |
| 56 | 57 | class InputFile { |
| 57 | 58 | public: |
| 58 | 59 | enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind }; |
| 59 | Kind kind() const { return FileKind; } | |
| 60 | Kind kind() const { return fileKind; } | |
| 60 | 61 | virtual ~InputFile() {} |
| 61 | 62 | |
| 62 | 63 | // Returns the filename. |
| 63 | StringRef getName() const { return MB.getBufferIdentifier(); } | |
| 64 | StringRef getName() const { return mb.getBufferIdentifier(); } | |
| 64 | 65 | |
| 65 | 66 | // Reads a file (the constructor doesn't do that). |
| 66 | 67 | virtual void parse() = 0; |
| ... | ... | @@ -68,158 +69,195 @@ public: |
| 68 | 69 | // Returns the CPU type this file was compiled to. |
| 69 | 70 | virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; } |
| 70 | 71 | |
| 71 | MemoryBufferRef MB; | |
| 72 | MemoryBufferRef mb; | |
| 72 | 73 | |
| 73 | 74 | // An archive file name if this file is created from an archive. |
| 74 | StringRef ParentName; | |
| 75 | StringRef parentName; | |
| 75 | 76 | |
| 76 | 77 | // Returns .drectve section contents if exist. |
| 77 | StringRef getDirectives() { return StringRef(Directives).trim(); } | |
| 78 | StringRef getDirectives() { return directives; } | |
| 78 | 79 | |
| 79 | 80 | protected: |
| 80 | InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} | |
| 81 | InputFile(Kind k, MemoryBufferRef m) : mb(m), fileKind(k) {} | |
| 81 | 82 | |
| 82 | std::string Directives; | |
| 83 | StringRef directives; | |
| 83 | 84 | |
| 84 | 85 | private: |
| 85 | const Kind FileKind; | |
| 86 | const Kind fileKind; | |
| 86 | 87 | }; |
| 87 | 88 | |
| 88 | 89 | // .lib or .a file. |
| 89 | 90 | class ArchiveFile : public InputFile { |
| 90 | 91 | public: |
| 91 | explicit ArchiveFile(MemoryBufferRef M); | |
| 92 | static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } | |
| 92 | explicit ArchiveFile(MemoryBufferRef m); | |
| 93 | static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; } | |
| 93 | 94 | void parse() override; |
| 94 | 95 | |
| 95 | 96 | // Enqueues an archive member load for the given symbol. If we've already |
| 96 | 97 | // enqueued a load for the same archive member, this function does nothing, |
| 97 | 98 | // which ensures that we don't load the same member more than once. |
| 98 | void addMember(const Archive::Symbol *Sym); | |
| 99 | void addMember(const Archive::Symbol *sym); | |
| 99 | 100 | |
| 100 | 101 | private: |
| 101 | std::unique_ptr<Archive> File; | |
| 102 | std::string Filename; | |
| 103 | llvm::DenseSet<uint64_t> Seen; | |
| 102 | std::unique_ptr<Archive> file; | |
| 103 | llvm::DenseSet<uint64_t> seen; | |
| 104 | 104 | }; |
| 105 | 105 | |
| 106 | 106 | // .obj or .o file. This may be a member of an archive file. |
| 107 | 107 | class ObjFile : public InputFile { |
| 108 | 108 | public: |
| 109 | explicit ObjFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {} | |
| 110 | static bool classof(const InputFile *F) { return F->kind() == ObjectKind; } | |
| 109 | explicit ObjFile(MemoryBufferRef m) : InputFile(ObjectKind, m) {} | |
| 110 | static bool classof(const InputFile *f) { return f->kind() == ObjectKind; } | |
| 111 | 111 | void parse() override; |
| 112 | 112 | MachineTypes getMachineType() override; |
| 113 | ArrayRef<Chunk *> getChunks() { return Chunks; } | |
| 114 | ArrayRef<SectionChunk *> getDebugChunks() { return DebugChunks; } | |
| 115 | ArrayRef<SectionChunk *> getSXDataChunks() { return SXDataChunks; } | |
| 116 | ArrayRef<SectionChunk *> getGuardFidChunks() { return GuardFidChunks; } | |
| 117 | ArrayRef<SectionChunk *> getGuardLJmpChunks() { return GuardLJmpChunks; } | |
| 118 | ArrayRef<Symbol *> getSymbols() { return Symbols; } | |
| 119 | ||
| 120 | // Returns a Symbol object for the SymbolIndex'th symbol in the | |
| 113 | ArrayRef<Chunk *> getChunks() { return chunks; } | |
| 114 | ArrayRef<SectionChunk *> getDebugChunks() { return debugChunks; } | |
| 115 | ArrayRef<SectionChunk *> getSXDataChunks() { return sXDataChunks; } | |
| 116 | ArrayRef<SectionChunk *> getGuardFidChunks() { return guardFidChunks; } | |
| 117 | ArrayRef<SectionChunk *> getGuardLJmpChunks() { return guardLJmpChunks; } | |
| 118 | ArrayRef<Symbol *> getSymbols() { return symbols; } | |
| 119 | ||
| 120 | ArrayRef<uint8_t> getDebugSection(StringRef secName); | |
| 121 | ||
| 122 | // Returns a Symbol object for the symbolIndex'th symbol in the | |
| 121 | 123 | // underlying object file. |
| 122 | Symbol *getSymbol(uint32_t SymbolIndex) { | |
| 123 | return Symbols[SymbolIndex]; | |
| 124 | Symbol *getSymbol(uint32_t symbolIndex) { | |
| 125 | return symbols[symbolIndex]; | |
| 124 | 126 | } |
| 125 | 127 | |
| 126 | 128 | // Returns the underlying COFF file. |
| 127 | COFFObjectFile *getCOFFObj() { return COFFObj.get(); } | |
| 129 | COFFObjectFile *getCOFFObj() { return coffObj.get(); } | |
| 128 | 130 | |
| 129 | // Whether the object was already merged into the final PDB or not | |
| 130 | bool wasProcessedForPDB() const { return !!ModuleDBI; } | |
| 131 | // Add a symbol for a range extension thunk. Return the new symbol table | |
| 132 | // index. This index can be used to modify a relocation. | |
| 133 | uint32_t addRangeThunkSymbol(Symbol *thunk) { | |
| 134 | symbols.push_back(thunk); | |
| 135 | return symbols.size() - 1; | |
| 136 | } | |
| 131 | 137 | |
| 132 | static std::vector<ObjFile *> Instances; | |
| 138 | static std::vector<ObjFile *> instances; | |
| 133 | 139 | |
| 134 | 140 | // Flags in the absolute @feat.00 symbol if it is present. These usually |
| 135 | 141 | // indicate if an object was compiled with certain security features enabled |
| 136 | 142 | // like stack guard, safeseh, /guard:cf, or other things. |
| 137 | uint32_t Feat00Flags = 0; | |
| 143 | uint32_t feat00Flags = 0; | |
| 138 | 144 | |
| 139 | 145 | // True if this object file is compatible with SEH. COFF-specific and |
| 140 | 146 | // x86-only. COFF spec 5.10.1. The .sxdata section. |
| 141 | bool hasSafeSEH() { return Feat00Flags & 0x1; } | |
| 147 | bool hasSafeSEH() { return feat00Flags & 0x1; } | |
| 142 | 148 | |
| 143 | 149 | // True if this file was compiled with /guard:cf. |
| 144 | bool hasGuardCF() { return Feat00Flags & 0x800; } | |
| 150 | bool hasGuardCF() { return feat00Flags & 0x800; } | |
| 145 | 151 | |
| 146 | 152 | // Pointer to the PDB module descriptor builder. Various debug info records |
| 147 | 153 | // will reference object files by "module index", which is here. Things like |
| 148 | 154 | // source files and section contributions are also recorded here. Will be null |
| 149 | 155 | // if we are not producing a PDB. |
| 150 | llvm::pdb::DbiModuleDescriptorBuilder *ModuleDBI = nullptr; | |
| 156 | llvm::pdb::DbiModuleDescriptorBuilder *moduleDBI = nullptr; | |
| 151 | 157 | |
| 152 | const coff_section *AddrsigSec = nullptr; | |
| 158 | const coff_section *addrsigSec = nullptr; | |
| 153 | 159 | |
| 154 | 160 | // When using Microsoft precompiled headers, this is the PCH's key. |
| 155 | 161 | // The same key is used by both the precompiled object, and objects using the |
| 156 | 162 | // precompiled object. Any difference indicates out-of-date objects. |
| 157 | llvm::Optional<uint32_t> PCHSignature; | |
| 163 | llvm::Optional<uint32_t> pchSignature; | |
| 164 | ||
| 165 | // Whether this is an object file created from .res files. | |
| 166 | bool isResourceObjFile = false; | |
| 167 | ||
| 168 | // Whether this file was compiled with /hotpatch. | |
| 169 | bool hotPatchable = false; | |
| 170 | ||
| 171 | // Whether the object was already merged into the final PDB. | |
| 172 | bool mergedIntoPDB = false; | |
| 173 | ||
| 174 | // If the OBJ has a .debug$T stream, this tells how it will be handled. | |
| 175 | TpiSource *debugTypesObj = nullptr; | |
| 176 | ||
| 177 | // The .debug$T stream if there's one. | |
| 178 | llvm::Optional<llvm::codeview::CVTypeArray> debugTypes; | |
| 158 | 179 | |
| 159 | 180 | private: |
| 181 | const coff_section* getSection(uint32_t i); | |
| 182 | const coff_section *getSection(COFFSymbolRef sym) { | |
| 183 | return getSection(sym.getSectionNumber()); | |
| 184 | } | |
| 185 | ||
| 160 | 186 | void initializeChunks(); |
| 161 | 187 | void initializeSymbols(); |
| 188 | void initializeFlags(); | |
| 189 | void initializeDependencies(); | |
| 162 | 190 | |
| 163 | 191 | SectionChunk * |
| 164 | readSection(uint32_t SectionNumber, | |
| 165 | const llvm::object::coff_aux_section_definition *Def, | |
| 166 | StringRef LeaderName); | |
| 192 | readSection(uint32_t sectionNumber, | |
| 193 | const llvm::object::coff_aux_section_definition *def, | |
| 194 | StringRef leaderName); | |
| 167 | 195 | |
| 168 | 196 | void readAssociativeDefinition( |
| 169 | COFFSymbolRef COFFSym, | |
| 170 | const llvm::object::coff_aux_section_definition *Def); | |
| 197 | COFFSymbolRef coffSym, | |
| 198 | const llvm::object::coff_aux_section_definition *def); | |
| 171 | 199 | |
| 172 | 200 | void readAssociativeDefinition( |
| 173 | COFFSymbolRef COFFSym, | |
| 174 | const llvm::object::coff_aux_section_definition *Def, | |
| 175 | uint32_t ParentSection); | |
| 201 | COFFSymbolRef coffSym, | |
| 202 | const llvm::object::coff_aux_section_definition *def, | |
| 203 | uint32_t parentSection); | |
| 176 | 204 | |
| 177 | 205 | void recordPrevailingSymbolForMingw( |
| 178 | COFFSymbolRef COFFSym, | |
| 179 | llvm::DenseMap<StringRef, uint32_t> &PrevailingSectionMap); | |
| 206 | COFFSymbolRef coffSym, | |
| 207 | llvm::DenseMap<StringRef, uint32_t> &prevailingSectionMap); | |
| 180 | 208 | |
| 181 | 209 | void maybeAssociateSEHForMingw( |
| 182 | COFFSymbolRef Sym, const llvm::object::coff_aux_section_definition *Def, | |
| 183 | const llvm::DenseMap<StringRef, uint32_t> &PrevailingSectionMap); | |
| 210 | COFFSymbolRef sym, const llvm::object::coff_aux_section_definition *def, | |
| 211 | const llvm::DenseMap<StringRef, uint32_t> &prevailingSectionMap); | |
| 212 | ||
| 213 | // Given a new symbol Sym with comdat selection Selection, if the new | |
| 214 | // symbol is not (yet) Prevailing and the existing comdat leader set to | |
| 215 | // Leader, emits a diagnostic if the new symbol and its selection doesn't | |
| 216 | // match the existing symbol and its selection. If either old or new | |
| 217 | // symbol have selection IMAGE_COMDAT_SELECT_LARGEST, Sym might replace | |
| 218 | // the existing leader. In that case, Prevailing is set to true. | |
| 219 | void handleComdatSelection(COFFSymbolRef sym, | |
| 220 | llvm::COFF::COMDATType &selection, | |
| 221 | bool &prevailing, DefinedRegular *leader); | |
| 184 | 222 | |
| 185 | 223 | llvm::Optional<Symbol *> |
| 186 | createDefined(COFFSymbolRef Sym, | |
| 224 | createDefined(COFFSymbolRef sym, | |
| 187 | 225 | std::vector<const llvm::object::coff_aux_section_definition *> |
| 188 | &ComdatDefs, | |
| 189 | bool &PrevailingComdat); | |
| 190 | Symbol *createRegular(COFFSymbolRef Sym); | |
| 191 | Symbol *createUndefined(COFFSymbolRef Sym); | |
| 226 | &comdatDefs, | |
| 227 | bool &prevailingComdat); | |
| 228 | Symbol *createRegular(COFFSymbolRef sym); | |
| 229 | Symbol *createUndefined(COFFSymbolRef sym); | |
| 192 | 230 | |
| 193 | std::unique_ptr<COFFObjectFile> COFFObj; | |
| 231 | std::unique_ptr<COFFObjectFile> coffObj; | |
| 194 | 232 | |
| 195 | 233 | // List of all chunks defined by this file. This includes both section |
| 196 | 234 | // chunks and non-section chunks for common symbols. |
| 197 | std::vector<Chunk *> Chunks; | |
| 235 | std::vector<Chunk *> chunks; | |
| 198 | 236 | |
| 199 | 237 | // CodeView debug info sections. |
| 200 | std::vector<SectionChunk *> DebugChunks; | |
| 238 | std::vector<SectionChunk *> debugChunks; | |
| 201 | 239 | |
| 202 | 240 | // Chunks containing symbol table indices of exception handlers. Only used for |
| 203 | 241 | // 32-bit x86. |
| 204 | std::vector<SectionChunk *> SXDataChunks; | |
| 242 | std::vector<SectionChunk *> sXDataChunks; | |
| 205 | 243 | |
| 206 | 244 | // Chunks containing symbol table indices of address taken symbols and longjmp |
| 207 | 245 | // targets. These are not linked into the final binary when /guard:cf is set. |
| 208 | std::vector<SectionChunk *> GuardFidChunks; | |
| 209 | std::vector<SectionChunk *> GuardLJmpChunks; | |
| 246 | std::vector<SectionChunk *> guardFidChunks; | |
| 247 | std::vector<SectionChunk *> guardLJmpChunks; | |
| 210 | 248 | |
| 211 | 249 | // This vector contains the same chunks as Chunks, but they are |
| 212 | 250 | // indexed such that you can get a SectionChunk by section index. |
| 213 | 251 | // Nonexistent section indices are filled with null pointers. |
| 214 | 252 | // (Because section number is 1-based, the first slot is always a |
| 215 | 253 | // null pointer.) |
| 216 | std::vector<SectionChunk *> SparseChunks; | |
| 254 | std::vector<SectionChunk *> sparseChunks; | |
| 217 | 255 | |
| 218 | 256 | // This vector contains a list of all symbols defined or referenced by this |
| 219 | 257 | // file. They are indexed such that you can get a Symbol by symbol |
| 220 | 258 | // index. Nonexistent indices (which are occupied by auxiliary |
| 221 | 259 | // symbols in the real symbol table) are filled with null pointers. |
| 222 | std::vector<Symbol *> Symbols; | |
| 260 | std::vector<Symbol *> symbols; | |
| 223 | 261 | }; |
| 224 | 262 | |
| 225 | 263 | // This type represents import library members that contain DLL names |
| ... | ... | @@ -227,23 +265,23 @@ private: |
| 227 | 265 | // for details about the format. |
| 228 | 266 | class ImportFile : public InputFile { |
| 229 | 267 | public: |
| 230 | explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {} | |
| 268 | explicit ImportFile(MemoryBufferRef m) : InputFile(ImportKind, m) {} | |
| 231 | 269 | |
| 232 | static bool classof(const InputFile *F) { return F->kind() == ImportKind; } | |
| 270 | static bool classof(const InputFile *f) { return f->kind() == ImportKind; } | |
| 233 | 271 | |
| 234 | static std::vector<ImportFile *> Instances; | |
| 272 | static std::vector<ImportFile *> instances; | |
| 235 | 273 | |
| 236 | Symbol *ImpSym = nullptr; | |
| 237 | Symbol *ThunkSym = nullptr; | |
| 238 | std::string DLLName; | |
| 274 | Symbol *impSym = nullptr; | |
| 275 | Symbol *thunkSym = nullptr; | |
| 276 | std::string dllName; | |
| 239 | 277 | |
| 240 | 278 | private: |
| 241 | 279 | void parse() override; |
| 242 | 280 | |
| 243 | 281 | public: |
| 244 | StringRef ExternalName; | |
| 245 | const coff_import_header *Hdr; | |
| 246 | Chunk *Location = nullptr; | |
| 282 | StringRef externalName; | |
| 283 | const coff_import_header *hdr; | |
| 284 | Chunk *location = nullptr; | |
| 247 | 285 | |
| 248 | 286 | // We want to eliminate dllimported symbols if no one actually refers them. |
| 249 | 287 | // These "Live" bits are used to keep track of which import library members |
| ... | ... | @@ -253,28 +291,31 @@ public: |
| 253 | 291 | // symbols provided by this import library member. We also track whether the |
| 254 | 292 | // imported symbol is used separately from whether the thunk is used in order |
| 255 | 293 | // to avoid creating unnecessary thunks. |
| 256 | bool Live = !Config->DoGC; | |
| 257 | bool ThunkLive = !Config->DoGC; | |
| 294 | bool live = !config->doGC; | |
| 295 | bool thunkLive = !config->doGC; | |
| 258 | 296 | }; |
| 259 | 297 | |
| 260 | 298 | // Used for LTO. |
| 261 | 299 | class BitcodeFile : public InputFile { |
| 262 | 300 | public: |
| 263 | explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {} | |
| 264 | static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } | |
| 265 | ArrayRef<Symbol *> getSymbols() { return Symbols; } | |
| 301 | BitcodeFile(MemoryBufferRef mb, StringRef archiveName, | |
| 302 | uint64_t offsetInArchive); | |
| 303 | static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; } | |
| 304 | ArrayRef<Symbol *> getSymbols() { return symbols; } | |
| 266 | 305 | MachineTypes getMachineType() override; |
| 267 | static std::vector<BitcodeFile *> Instances; | |
| 268 | std::unique_ptr<llvm::lto::InputFile> Obj; | |
| 306 | static std::vector<BitcodeFile *> instances; | |
| 307 | std::unique_ptr<llvm::lto::InputFile> obj; | |
| 269 | 308 | |
| 270 | 309 | private: |
| 271 | 310 | void parse() override; |
| 272 | 311 | |
| 273 | std::vector<Symbol *> Symbols; | |
| 312 | std::vector<Symbol *> symbols; | |
| 274 | 313 | }; |
| 314 | ||
| 315 | std::string replaceThinLTOSuffix(StringRef path); | |
| 275 | 316 | } // namespace coff |
| 276 | 317 | |
| 277 | std::string toString(const coff::InputFile *File); | |
| 318 | std::string toString(const coff::InputFile *file); | |
| 278 | 319 | } // namespace lld |
| 279 | 320 | |
| 280 | 321 | #endif |
deps/lld/COFF/LTO.cpp+121-67| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- LTO.cpp ------------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -11,6 +10,7 @@ |
| 11 | 10 | #include "Config.h" |
| 12 | 11 | #include "InputFiles.h" |
| 13 | 12 | #include "Symbols.h" |
| 13 | #include "lld/Common/Args.h" | |
| 14 | 14 | #include "lld/Common/ErrorHandler.h" |
| 15 | 15 | #include "lld/Common/Strings.h" |
| 16 | 16 | #include "lld/Common/TargetOptionsCommandFlags.h" |
| ... | ... | @@ -18,6 +18,7 @@ |
| 18 | 18 | #include "llvm/ADT/SmallString.h" |
| 19 | 19 | #include "llvm/ADT/StringRef.h" |
| 20 | 20 | #include "llvm/ADT/Twine.h" |
| 21 | #include "llvm/Bitcode/BitcodeWriter.h" | |
| 21 | 22 | #include "llvm/IR/DiagnosticPrinter.h" |
| 22 | 23 | #include "llvm/LTO/Caching.h" |
| 23 | 24 | #include "llvm/LTO/Config.h" |
| ... | ... | @@ -41,112 +42,165 @@ using namespace llvm::object; |
| 41 | 42 | using namespace lld; |
| 42 | 43 | using namespace lld::coff; |
| 43 | 44 | |
| 44 | static std::unique_ptr<lto::LTO> createLTO() { | |
| 45 | lto::Config C; | |
| 46 | C.Options = InitTargetOptionsFromCodeGenFlags(); | |
| 45 | // Creates an empty file to and returns a raw_fd_ostream to write to it. | |
| 46 | static std::unique_ptr<raw_fd_ostream> openFile(StringRef file) { | |
| 47 | std::error_code ec; | |
| 48 | auto ret = | |
| 49 | llvm::make_unique<raw_fd_ostream>(file, ec, sys::fs::OpenFlags::F_None); | |
| 50 | if (ec) { | |
| 51 | error("cannot open " + file + ": " + ec.message()); | |
| 52 | return nullptr; | |
| 53 | } | |
| 54 | return ret; | |
| 55 | } | |
| 56 | ||
| 57 | static std::string getThinLTOOutputFile(StringRef path) { | |
| 58 | return lto::getThinLTOOutputFile(path, | |
| 59 | config->thinLTOPrefixReplace.first, | |
| 60 | config->thinLTOPrefixReplace.second); | |
| 61 | } | |
| 62 | ||
| 63 | static lto::Config createConfig() { | |
| 64 | lto::Config c; | |
| 65 | c.Options = initTargetOptionsFromCodeGenFlags(); | |
| 47 | 66 | |
| 48 | 67 | // Always emit a section per function/datum with LTO. LLVM LTO should get most |
| 49 | 68 | // of the benefit of linker GC, but there are still opportunities for ICF. |
| 50 | C.Options.FunctionSections = true; | |
| 51 | C.Options.DataSections = true; | |
| 69 | c.Options.FunctionSections = true; | |
| 70 | c.Options.DataSections = true; | |
| 52 | 71 | |
| 53 | 72 | // Use static reloc model on 32-bit x86 because it usually results in more |
| 54 | 73 | // compact code, and because there are also known code generation bugs when |
| 55 | 74 | // using the PIC model (see PR34306). |
| 56 | if (Config->Machine == COFF::IMAGE_FILE_MACHINE_I386) | |
| 57 | C.RelocModel = Reloc::Static; | |
| 75 | if (config->machine == COFF::IMAGE_FILE_MACHINE_I386) | |
| 76 | c.RelocModel = Reloc::Static; | |
| 58 | 77 | else |
| 59 | C.RelocModel = Reloc::PIC_; | |
| 60 | C.DisableVerify = true; | |
| 61 | C.DiagHandler = diagnosticHandler; | |
| 62 | C.OptLevel = Config->LTOO; | |
| 63 | C.CPU = GetCPUStr(); | |
| 64 | C.MAttrs = GetMAttrs(); | |
| 65 | ||
| 66 | if (Config->SaveTemps) | |
| 67 | checkError(C.addSaveTemps(std::string(Config->OutputFile) + ".", | |
| 78 | c.RelocModel = Reloc::PIC_; | |
| 79 | c.DisableVerify = true; | |
| 80 | c.DiagHandler = diagnosticHandler; | |
| 81 | c.OptLevel = config->ltoo; | |
| 82 | c.CPU = getCPUStr(); | |
| 83 | c.MAttrs = getMAttrs(); | |
| 84 | c.CGOptLevel = args::getCGOptLevel(config->ltoo); | |
| 85 | ||
| 86 | if (config->saveTemps) | |
| 87 | checkError(c.addSaveTemps(std::string(config->outputFile) + ".", | |
| 68 | 88 | /*UseInputModulePath*/ true)); |
| 69 | lto::ThinBackend Backend; | |
| 70 | if (Config->ThinLTOJobs != 0) | |
| 71 | Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs); | |
| 72 | return llvm::make_unique<lto::LTO>(std::move(C), Backend, | |
| 73 | Config->LTOPartitions); | |
| 89 | return c; | |
| 74 | 90 | } |
| 75 | 91 | |
| 76 | BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {} | |
| 92 | BitcodeCompiler::BitcodeCompiler() { | |
| 93 | // Initialize indexFile. | |
| 94 | if (!config->thinLTOIndexOnlyArg.empty()) | |
| 95 | indexFile = openFile(config->thinLTOIndexOnlyArg); | |
| 96 | ||
| 97 | // Initialize ltoObj. | |
| 98 | lto::ThinBackend backend; | |
| 99 | if (config->thinLTOIndexOnly) { | |
| 100 | auto OnIndexWrite = [&](StringRef S) { thinIndices.erase(S); }; | |
| 101 | backend = lto::createWriteIndexesThinBackend( | |
| 102 | config->thinLTOPrefixReplace.first, config->thinLTOPrefixReplace.second, | |
| 103 | config->thinLTOEmitImportsFiles, indexFile.get(), OnIndexWrite); | |
| 104 | } else if (config->thinLTOJobs != 0) { | |
| 105 | backend = lto::createInProcessThinBackend(config->thinLTOJobs); | |
| 106 | } | |
| 107 | ||
| 108 | ltoObj = llvm::make_unique<lto::LTO>(createConfig(), backend, | |
| 109 | config->ltoPartitions); | |
| 110 | } | |
| 77 | 111 | |
| 78 | 112 | BitcodeCompiler::~BitcodeCompiler() = default; |
| 79 | 113 | |
| 80 | static void undefine(Symbol *S) { replaceSymbol<Undefined>(S, S->getName()); } | |
| 114 | static void undefine(Symbol *s) { replaceSymbol<Undefined>(s, s->getName()); } | |
| 115 | ||
| 116 | void BitcodeCompiler::add(BitcodeFile &f) { | |
| 117 | lto::InputFile &obj = *f.obj; | |
| 118 | unsigned symNum = 0; | |
| 119 | std::vector<Symbol *> symBodies = f.getSymbols(); | |
| 120 | std::vector<lto::SymbolResolution> resols(symBodies.size()); | |
| 81 | 121 | |
| 82 | void BitcodeCompiler::add(BitcodeFile &F) { | |
| 83 | lto::InputFile &Obj = *F.Obj; | |
| 84 | unsigned SymNum = 0; | |
| 85 | std::vector<Symbol *> SymBodies = F.getSymbols(); | |
| 86 | std::vector<lto::SymbolResolution> Resols(SymBodies.size()); | |
| 122 | if (config->thinLTOIndexOnly) | |
| 123 | thinIndices.insert(obj.getName()); | |
| 87 | 124 | |
| 88 | 125 | // Provide a resolution to the LTO API for each symbol. |
| 89 | for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) { | |
| 90 | Symbol *Sym = SymBodies[SymNum]; | |
| 91 | lto::SymbolResolution &R = Resols[SymNum]; | |
| 92 | ++SymNum; | |
| 126 | for (const lto::InputFile::Symbol &objSym : obj.symbols()) { | |
| 127 | Symbol *sym = symBodies[symNum]; | |
| 128 | lto::SymbolResolution &r = resols[symNum]; | |
| 129 | ++symNum; | |
| 93 | 130 | |
| 94 | 131 | // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile |
| 95 | 132 | // reports two symbols for module ASM defined. Without this check, lld |
| 96 | 133 | // flags an undefined in IR with a definition in ASM as prevailing. |
| 97 | 134 | // Once IRObjectFile is fixed to report only one symbol this hack can |
| 98 | 135 | // be removed. |
| 99 | R.Prevailing = !ObjSym.isUndefined() && Sym->getFile() == &F; | |
| 100 | R.VisibleToRegularObj = Sym->IsUsedInRegularObj; | |
| 101 | if (R.Prevailing) | |
| 102 | undefine(Sym); | |
| 136 | r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f; | |
| 137 | r.VisibleToRegularObj = sym->isUsedInRegularObj; | |
| 138 | if (r.Prevailing) | |
| 139 | undefine(sym); | |
| 103 | 140 | } |
| 104 | checkError(LTOObj->add(std::move(F.Obj), Resols)); | |
| 141 | checkError(ltoObj->add(std::move(f.obj), resols)); | |
| 105 | 142 | } |
| 106 | 143 | |
| 107 | 144 | // Merge all the bitcode files we have seen, codegen the result |
| 108 | 145 | // and return the resulting objects. |
| 109 | 146 | std::vector<StringRef> BitcodeCompiler::compile() { |
| 110 | unsigned MaxTasks = LTOObj->getMaxTasks(); | |
| 111 | Buf.resize(MaxTasks); | |
| 112 | Files.resize(MaxTasks); | |
| 147 | unsigned maxTasks = ltoObj->getMaxTasks(); | |
| 148 | buf.resize(maxTasks); | |
| 149 | files.resize(maxTasks); | |
| 113 | 150 | |
| 114 | 151 | // The /lldltocache option specifies the path to a directory in which to cache |
| 115 | 152 | // native object files for ThinLTO incremental builds. If a path was |
| 116 | 153 | // specified, configure LTO to use it as the cache directory. |
| 117 | lto::NativeObjectCache Cache; | |
| 118 | if (!Config->LTOCache.empty()) | |
| 119 | Cache = check(lto::localCache( | |
| 120 | Config->LTOCache, [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) { | |
| 121 | Files[Task] = std::move(MB); | |
| 154 | lto::NativeObjectCache cache; | |
| 155 | if (!config->ltoCache.empty()) | |
| 156 | cache = check(lto::localCache( | |
| 157 | config->ltoCache, [&](size_t task, std::unique_ptr<MemoryBuffer> mb) { | |
| 158 | files[task] = std::move(mb); | |
| 122 | 159 | })); |
| 123 | 160 | |
| 124 | checkError(LTOObj->run( | |
| 125 | [&](size_t Task) { | |
| 161 | checkError(ltoObj->run( | |
| 162 | [&](size_t task) { | |
| 126 | 163 | return llvm::make_unique<lto::NativeObjectStream>( |
| 127 | llvm::make_unique<raw_svector_ostream>(Buf[Task])); | |
| 164 | llvm::make_unique<raw_svector_ostream>(buf[task])); | |
| 128 | 165 | }, |
| 129 | Cache)); | |
| 166 | cache)); | |
| 167 | ||
| 168 | // Emit empty index files for non-indexed files | |
| 169 | for (StringRef s : thinIndices) { | |
| 170 | std::string path = getThinLTOOutputFile(s); | |
| 171 | openFile(path + ".thinlto.bc"); | |
| 172 | if (config->thinLTOEmitImportsFiles) | |
| 173 | openFile(path + ".imports"); | |
| 174 | } | |
| 175 | ||
| 176 | // ThinLTO with index only option is required to generate only the index | |
| 177 | // files. After that, we exit from linker and ThinLTO backend runs in a | |
| 178 | // distributed environment. | |
| 179 | if (config->thinLTOIndexOnly) { | |
| 180 | if (indexFile) | |
| 181 | indexFile->close(); | |
| 182 | return {}; | |
| 183 | } | |
| 130 | 184 | |
| 131 | if (!Config->LTOCache.empty()) | |
| 132 | pruneCache(Config->LTOCache, Config->LTOCachePolicy); | |
| 185 | if (!config->ltoCache.empty()) | |
| 186 | pruneCache(config->ltoCache, config->ltoCachePolicy); | |
| 133 | 187 | |
| 134 | std::vector<StringRef> Ret; | |
| 135 | for (unsigned I = 0; I != MaxTasks; ++I) { | |
| 136 | if (Buf[I].empty()) | |
| 188 | std::vector<StringRef> ret; | |
| 189 | for (unsigned i = 0; i != maxTasks; ++i) { | |
| 190 | if (buf[i].empty()) | |
| 137 | 191 | continue; |
| 138 | if (Config->SaveTemps) { | |
| 139 | if (I == 0) | |
| 140 | saveBuffer(Buf[I], Config->OutputFile + ".lto.obj"); | |
| 192 | if (config->saveTemps) { | |
| 193 | if (i == 0) | |
| 194 | saveBuffer(buf[i], config->outputFile + ".lto.obj"); | |
| 141 | 195 | else |
| 142 | saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.obj"); | |
| 196 | saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.obj"); | |
| 143 | 197 | } |
| 144 | Ret.emplace_back(Buf[I].data(), Buf[I].size()); | |
| 198 | ret.emplace_back(buf[i].data(), buf[i].size()); | |
| 145 | 199 | } |
| 146 | 200 | |
| 147 | for (std::unique_ptr<MemoryBuffer> &File : Files) | |
| 148 | if (File) | |
| 149 | Ret.push_back(File->getBuffer()); | |
| 201 | for (std::unique_ptr<MemoryBuffer> &file : files) | |
| 202 | if (file) | |
| 203 | ret.push_back(file->getBuffer()); | |
| 150 | 204 | |
| 151 | return Ret; | |
| 205 | return ret; | |
| 152 | 206 | } |
deps/lld/COFF/LTO.h+11-8| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- LTO.h ----------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -22,7 +21,9 @@ |
| 22 | 21 | #define LLD_COFF_LTO_H |
| 23 | 22 | |
| 24 | 23 | #include "lld/Common/LLVM.h" |
| 24 | #include "llvm/ADT/DenseSet.h" | |
| 25 | 25 | #include "llvm/ADT/SmallString.h" |
| 26 | #include "llvm/Support/raw_ostream.h" | |
| 26 | 27 | #include <memory> |
| 27 | 28 | #include <vector> |
| 28 | 29 | |
| ... | ... | @@ -43,13 +44,15 @@ public: |
| 43 | 44 | BitcodeCompiler(); |
| 44 | 45 | ~BitcodeCompiler(); |
| 45 | 46 | |
| 46 | void add(BitcodeFile &F); | |
| 47 | void add(BitcodeFile &f); | |
| 47 | 48 | std::vector<StringRef> compile(); |
| 48 | 49 | |
| 49 | 50 | private: |
| 50 | std::unique_ptr<llvm::lto::LTO> LTOObj; | |
| 51 | std::vector<SmallString<0>> Buf; | |
| 52 | std::vector<std::unique_ptr<MemoryBuffer>> Files; | |
| 51 | std::unique_ptr<llvm::lto::LTO> ltoObj; | |
| 52 | std::vector<SmallString<0>> buf; | |
| 53 | std::vector<std::unique_ptr<MemoryBuffer>> files; | |
| 54 | std::unique_ptr<llvm::raw_fd_ostream> indexFile; | |
| 55 | llvm::DenseSet<StringRef> thinIndices; | |
| 53 | 56 | }; |
| 54 | 57 | } |
| 55 | 58 | } |
deps/lld/COFF/MapFile.cpp+57-58| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- MapFile.cpp --------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -24,7 +23,7 @@ |
| 24 | 23 | #include "Symbols.h" |
| 25 | 24 | #include "Writer.h" |
| 26 | 25 | #include "lld/Common/ErrorHandler.h" |
| 27 | #include "llvm/Support/Parallel.h" | |
| 26 | #include "lld/Common/Threads.h" | |
| 28 | 27 | #include "llvm/Support/raw_ostream.h" |
| 29 | 28 | |
| 30 | 29 | using namespace llvm; |
| ... | ... | @@ -33,93 +32,93 @@ using namespace llvm::object; |
| 33 | 32 | using namespace lld; |
| 34 | 33 | using namespace lld::coff; |
| 35 | 34 | |
| 36 | typedef DenseMap<const SectionChunk *, SmallVector<DefinedRegular *, 4>> | |
| 37 | SymbolMapTy; | |
| 35 | using SymbolMapTy = | |
| 36 | DenseMap<const SectionChunk *, SmallVector<DefinedRegular *, 4>>; | |
| 38 | 37 | |
| 39 | static const std::string Indent8 = " "; // 8 spaces | |
| 40 | static const std::string Indent16 = " "; // 16 spaces | |
| 38 | static const std::string indent8 = " "; // 8 spaces | |
| 39 | static const std::string indent16 = " "; // 16 spaces | |
| 41 | 40 | |
| 42 | 41 | // Print out the first three columns of a line. |
| 43 | static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size, | |
| 44 | uint64_t Align) { | |
| 45 | OS << format("%08llx %08llx %5lld ", Addr, Size, Align); | |
| 42 | static void writeHeader(raw_ostream &os, uint64_t addr, uint64_t size, | |
| 43 | uint64_t align) { | |
| 44 | os << format("%08llx %08llx %5lld ", addr, size, align); | |
| 46 | 45 | } |
| 47 | 46 | |
| 48 | 47 | // Returns a list of all symbols that we want to print out. |
| 49 | 48 | static std::vector<DefinedRegular *> getSymbols() { |
| 50 | std::vector<DefinedRegular *> V; | |
| 51 | for (ObjFile *File : ObjFile::Instances) | |
| 52 | for (Symbol *B : File->getSymbols()) | |
| 53 | if (auto *Sym = dyn_cast_or_null<DefinedRegular>(B)) | |
| 54 | if (Sym && !Sym->getCOFFSymbol().isSectionDefinition()) | |
| 55 | V.push_back(Sym); | |
| 56 | return V; | |
| 49 | std::vector<DefinedRegular *> v; | |
| 50 | for (ObjFile *file : ObjFile::instances) | |
| 51 | for (Symbol *b : file->getSymbols()) | |
| 52 | if (auto *sym = dyn_cast_or_null<DefinedRegular>(b)) | |
| 53 | if (sym && !sym->getCOFFSymbol().isSectionDefinition()) | |
| 54 | v.push_back(sym); | |
| 55 | return v; | |
| 57 | 56 | } |
| 58 | 57 | |
| 59 | 58 | // Returns a map from sections to their symbols. |
| 60 | static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> Syms) { | |
| 61 | SymbolMapTy Ret; | |
| 62 | for (DefinedRegular *S : Syms) | |
| 63 | Ret[S->getChunk()].push_back(S); | |
| 59 | static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> syms) { | |
| 60 | SymbolMapTy ret; | |
| 61 | for (DefinedRegular *s : syms) | |
| 62 | ret[s->getChunk()].push_back(s); | |
| 64 | 63 | |
| 65 | 64 | // Sort symbols by address. |
| 66 | for (auto &It : Ret) { | |
| 67 | SmallVectorImpl<DefinedRegular *> &V = It.second; | |
| 68 | std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) { | |
| 69 | return A->getRVA() < B->getRVA(); | |
| 65 | for (auto &it : ret) { | |
| 66 | SmallVectorImpl<DefinedRegular *> &v = it.second; | |
| 67 | std::sort(v.begin(), v.end(), [](DefinedRegular *a, DefinedRegular *b) { | |
| 68 | return a->getRVA() < b->getRVA(); | |
| 70 | 69 | }); |
| 71 | 70 | } |
| 72 | return Ret; | |
| 71 | return ret; | |
| 73 | 72 | } |
| 74 | 73 | |
| 75 | 74 | // Construct a map from symbols to their stringified representations. |
| 76 | 75 | static DenseMap<DefinedRegular *, std::string> |
| 77 | getSymbolStrings(ArrayRef<DefinedRegular *> Syms) { | |
| 78 | std::vector<std::string> Str(Syms.size()); | |
| 79 | for_each_n(parallel::par, (size_t)0, Syms.size(), [&](size_t I) { | |
| 80 | raw_string_ostream OS(Str[I]); | |
| 81 | writeHeader(OS, Syms[I]->getRVA(), 0, 0); | |
| 82 | OS << Indent16 << toString(*Syms[I]); | |
| 76 | getSymbolStrings(ArrayRef<DefinedRegular *> syms) { | |
| 77 | std::vector<std::string> str(syms.size()); | |
| 78 | parallelForEachN((size_t)0, syms.size(), [&](size_t i) { | |
| 79 | raw_string_ostream os(str[i]); | |
| 80 | writeHeader(os, syms[i]->getRVA(), 0, 0); | |
| 81 | os << indent16 << toString(*syms[i]); | |
| 83 | 82 | }); |
| 84 | 83 | |
| 85 | DenseMap<DefinedRegular *, std::string> Ret; | |
| 86 | for (size_t I = 0, E = Syms.size(); I < E; ++I) | |
| 87 | Ret[Syms[I]] = std::move(Str[I]); | |
| 88 | return Ret; | |
| 84 | DenseMap<DefinedRegular *, std::string> ret; | |
| 85 | for (size_t i = 0, e = syms.size(); i < e; ++i) | |
| 86 | ret[syms[i]] = std::move(str[i]); | |
| 87 | return ret; | |
| 89 | 88 | } |
| 90 | 89 | |
| 91 | void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) { | |
| 92 | if (Config->MapFile.empty()) | |
| 90 | void coff::writeMapFile(ArrayRef<OutputSection *> outputSections) { | |
| 91 | if (config->mapFile.empty()) | |
| 93 | 92 | return; |
| 94 | 93 | |
| 95 | std::error_code EC; | |
| 96 | raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None); | |
| 97 | if (EC) | |
| 98 | fatal("cannot open " + Config->MapFile + ": " + EC.message()); | |
| 94 | std::error_code ec; | |
| 95 | raw_fd_ostream os(config->mapFile, ec, sys::fs::F_None); | |
| 96 | if (ec) | |
| 97 | fatal("cannot open " + config->mapFile + ": " + ec.message()); | |
| 99 | 98 | |
| 100 | 99 | // Collect symbol info that we want to print out. |
| 101 | std::vector<DefinedRegular *> Syms = getSymbols(); | |
| 102 | SymbolMapTy SectionSyms = getSectionSyms(Syms); | |
| 103 | DenseMap<DefinedRegular *, std::string> SymStr = getSymbolStrings(Syms); | |
| 100 | std::vector<DefinedRegular *> syms = getSymbols(); | |
| 101 | SymbolMapTy sectionSyms = getSectionSyms(syms); | |
| 102 | DenseMap<DefinedRegular *, std::string> symStr = getSymbolStrings(syms); | |
| 104 | 103 | |
| 105 | 104 | // Print out the header line. |
| 106 | OS << "Address Size Align Out In Symbol\n"; | |
| 105 | os << "Address Size Align Out In Symbol\n"; | |
| 107 | 106 | |
| 108 | 107 | // Print out file contents. |
| 109 | for (OutputSection *Sec : OutputSections) { | |
| 110 | writeHeader(OS, Sec->getRVA(), Sec->getVirtualSize(), /*Align=*/PageSize); | |
| 111 | OS << Sec->Name << '\n'; | |
| 108 | for (OutputSection *sec : outputSections) { | |
| 109 | writeHeader(os, sec->getRVA(), sec->getVirtualSize(), /*align=*/pageSize); | |
| 110 | os << sec->name << '\n'; | |
| 112 | 111 | |
| 113 | for (Chunk *C : Sec->Chunks) { | |
| 114 | auto *SC = dyn_cast<SectionChunk>(C); | |
| 115 | if (!SC) | |
| 112 | for (Chunk *c : sec->chunks) { | |
| 113 | auto *sc = dyn_cast<SectionChunk>(c); | |
| 114 | if (!sc) | |
| 116 | 115 | continue; |
| 117 | 116 | |
| 118 | writeHeader(OS, SC->getRVA(), SC->getSize(), SC->Alignment); | |
| 119 | OS << Indent8 << SC->File->getName() << ":(" << SC->getSectionName() | |
| 117 | writeHeader(os, sc->getRVA(), sc->getSize(), sc->getAlignment()); | |
| 118 | os << indent8 << sc->file->getName() << ":(" << sc->getSectionName() | |
| 120 | 119 | << ")\n"; |
| 121 | for (DefinedRegular *Sym : SectionSyms[SC]) | |
| 122 | OS << SymStr[Sym] << '\n'; | |
| 120 | for (DefinedRegular *sym : sectionSyms[sc]) | |
| 121 | os << symStr[sym] << '\n'; | |
| 123 | 122 | } |
| 124 | 123 | } |
| 125 | 124 | } |
deps/lld/COFF/MapFile.h+4-5| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- MapFile.h ------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -15,7 +14,7 @@ |
| 15 | 14 | namespace lld { |
| 16 | 15 | namespace coff { |
| 17 | 16 | class OutputSection; |
| 18 | void writeMapFile(llvm::ArrayRef<OutputSection *> OutputSections); | |
| 17 | void writeMapFile(llvm::ArrayRef<OutputSection *> outputSections); | |
| 19 | 18 | } |
| 20 | 19 | } |
| 21 | 20 |
deps/lld/COFF/MarkLive.cpp+32-33| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- MarkLive.cpp -------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -16,57 +15,57 @@ |
| 16 | 15 | namespace lld { |
| 17 | 16 | namespace coff { |
| 18 | 17 | |
| 19 | static Timer GCTimer("GC", Timer::root()); | |
| 18 | static Timer gctimer("GC", Timer::root()); | |
| 20 | 19 | |
| 21 | 20 | // Set live bit on for each reachable chunk. Unmarked (unreachable) |
| 22 | 21 | // COMDAT chunks will be ignored by Writer, so they will be excluded |
| 23 | 22 | // from the final output. |
| 24 | void markLive(ArrayRef<Chunk *> Chunks) { | |
| 25 | ScopedTimer T(GCTimer); | |
| 23 | void markLive(ArrayRef<Chunk *> chunks) { | |
| 24 | ScopedTimer t(gctimer); | |
| 26 | 25 | |
| 27 | 26 | // We build up a worklist of sections which have been marked as live. We only |
| 28 | 27 | // push into the worklist when we discover an unmarked section, and we mark |
| 29 | 28 | // as we push, so sections never appear twice in the list. |
| 30 | SmallVector<SectionChunk *, 256> Worklist; | |
| 29 | SmallVector<SectionChunk *, 256> worklist; | |
| 31 | 30 | |
| 32 | 31 | // COMDAT section chunks are dead by default. Add non-COMDAT chunks. |
| 33 | for (Chunk *C : Chunks) | |
| 34 | if (auto *SC = dyn_cast<SectionChunk>(C)) | |
| 35 | if (SC->Live) | |
| 36 | Worklist.push_back(SC); | |
| 32 | for (Chunk *c : chunks) | |
| 33 | if (auto *sc = dyn_cast<SectionChunk>(c)) | |
| 34 | if (sc->live) | |
| 35 | worklist.push_back(sc); | |
| 37 | 36 | |
| 38 | auto Enqueue = [&](SectionChunk *C) { | |
| 39 | if (C->Live) | |
| 37 | auto enqueue = [&](SectionChunk *c) { | |
| 38 | if (c->live) | |
| 40 | 39 | return; |
| 41 | C->Live = true; | |
| 42 | Worklist.push_back(C); | |
| 40 | c->live = true; | |
| 41 | worklist.push_back(c); | |
| 43 | 42 | }; |
| 44 | 43 | |
| 45 | auto AddSym = [&](Symbol *B) { | |
| 46 | if (auto *Sym = dyn_cast<DefinedRegular>(B)) | |
| 47 | Enqueue(Sym->getChunk()); | |
| 48 | else if (auto *Sym = dyn_cast<DefinedImportData>(B)) | |
| 49 | Sym->File->Live = true; | |
| 50 | else if (auto *Sym = dyn_cast<DefinedImportThunk>(B)) | |
| 51 | Sym->WrappedSym->File->Live = Sym->WrappedSym->File->ThunkLive = true; | |
| 44 | auto addSym = [&](Symbol *b) { | |
| 45 | if (auto *sym = dyn_cast<DefinedRegular>(b)) | |
| 46 | enqueue(sym->getChunk()); | |
| 47 | else if (auto *sym = dyn_cast<DefinedImportData>(b)) | |
| 48 | sym->file->live = true; | |
| 49 | else if (auto *sym = dyn_cast<DefinedImportThunk>(b)) | |
| 50 | sym->wrappedSym->file->live = sym->wrappedSym->file->thunkLive = true; | |
| 52 | 51 | }; |
| 53 | 52 | |
| 54 | 53 | // Add GC root chunks. |
| 55 | for (Symbol *B : Config->GCRoot) | |
| 56 | AddSym(B); | |
| 54 | for (Symbol *b : config->gcroot) | |
| 55 | addSym(b); | |
| 57 | 56 | |
| 58 | while (!Worklist.empty()) { | |
| 59 | SectionChunk *SC = Worklist.pop_back_val(); | |
| 60 | assert(SC->Live && "We mark as live when pushing onto the worklist!"); | |
| 57 | while (!worklist.empty()) { | |
| 58 | SectionChunk *sc = worklist.pop_back_val(); | |
| 59 | assert(sc->live && "We mark as live when pushing onto the worklist!"); | |
| 61 | 60 | |
| 62 | 61 | // Mark all symbols listed in the relocation table for this section. |
| 63 | for (Symbol *B : SC->symbols()) | |
| 64 | if (B) | |
| 65 | AddSym(B); | |
| 62 | for (Symbol *b : sc->symbols()) | |
| 63 | if (b) | |
| 64 | addSym(b); | |
| 66 | 65 | |
| 67 | 66 | // Mark associative sections if any. |
| 68 | for (SectionChunk *C : SC->children()) | |
| 69 | Enqueue(C); | |
| 67 | for (SectionChunk &c : sc->children()) | |
| 68 | enqueue(&c); | |
| 70 | 69 | } |
| 71 | 70 | } |
| 72 | 71 |
deps/lld/COFF/MarkLive.h+6-5| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- MarkLive.h -----------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -16,7 +15,9 @@ |
| 16 | 15 | namespace lld { |
| 17 | 16 | namespace coff { |
| 18 | 17 | |
| 19 | void markLive(ArrayRef<Chunk *> Chunks); | |
| 18 | class Chunk; | |
| 19 | ||
| 20 | void markLive(ArrayRef<Chunk *> chunks); | |
| 20 | 21 | |
| 21 | 22 | } // namespace coff |
| 22 | 23 | } // namespace lld |
deps/lld/COFF/MinGW.cpp+75-85| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- MinGW.cpp ----------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -19,8 +18,35 @@ using namespace lld::coff; |
| 19 | 18 | using namespace llvm; |
| 20 | 19 | using namespace llvm::COFF; |
| 21 | 20 | |
| 22 | void AutoExporter::initSymbolExcludes() { | |
| 23 | ExcludeSymbolPrefixes = { | |
| 21 | AutoExporter::AutoExporter() { | |
| 22 | excludeLibs = { | |
| 23 | "libgcc", | |
| 24 | "libgcc_s", | |
| 25 | "libstdc++", | |
| 26 | "libmingw32", | |
| 27 | "libmingwex", | |
| 28 | "libg2c", | |
| 29 | "libsupc++", | |
| 30 | "libobjc", | |
| 31 | "libgcj", | |
| 32 | "libclang_rt.builtins", | |
| 33 | "libclang_rt.builtins-aarch64", | |
| 34 | "libclang_rt.builtins-arm", | |
| 35 | "libclang_rt.builtins-i386", | |
| 36 | "libclang_rt.builtins-x86_64", | |
| 37 | "libc++", | |
| 38 | "libc++abi", | |
| 39 | "libunwind", | |
| 40 | "libmsvcrt", | |
| 41 | "libucrtbase", | |
| 42 | }; | |
| 43 | ||
| 44 | excludeObjects = { | |
| 45 | "crt0.o", "crt1.o", "crt1u.o", "crt2.o", "crt2u.o", "dllcrt1.o", | |
| 46 | "dllcrt2.o", "gcrt0.o", "gcrt1.o", "gcrt2.o", "crtbegin.o", "crtend.o", | |
| 47 | }; | |
| 48 | ||
| 49 | excludeSymbolPrefixes = { | |
| 24 | 50 | // Import symbols |
| 25 | 51 | "__imp_", |
| 26 | 52 | "__IMPORT_DESCRIPTOR_", |
| ... | ... | @@ -32,12 +58,14 @@ void AutoExporter::initSymbolExcludes() { |
| 32 | 58 | // Artifical symbols such as .refptr |
| 33 | 59 | ".", |
| 34 | 60 | }; |
| 35 | ExcludeSymbolSuffixes = { | |
| 61 | ||
| 62 | excludeSymbolSuffixes = { | |
| 36 | 63 | "_iname", |
| 37 | 64 | "_NULL_THUNK_DATA", |
| 38 | 65 | }; |
| 39 | if (Config->Machine == I386) { | |
| 40 | ExcludeSymbols = { | |
| 66 | ||
| 67 | if (config->machine == I386) { | |
| 68 | excludeSymbols = { | |
| 41 | 69 | "__NULL_IMPORT_DESCRIPTOR", |
| 42 | 70 | "__pei386_runtime_relocator", |
| 43 | 71 | "_do_pseudo_reloc", |
| ... | ... | @@ -52,9 +80,9 @@ void AutoExporter::initSymbolExcludes() { |
| 52 | 80 | "_DllEntryPoint@12", |
| 53 | 81 | "_DllMainCRTStartup@12", |
| 54 | 82 | }; |
| 55 | ExcludeSymbolPrefixes.insert("__head_"); | |
| 83 | excludeSymbolPrefixes.insert("__head_"); | |
| 56 | 84 | } else { |
| 57 | ExcludeSymbols = { | |
| 85 | excludeSymbols = { | |
| 58 | 86 | "__NULL_IMPORT_DESCRIPTOR", |
| 59 | 87 | "_pei386_runtime_relocator", |
| 60 | 88 | "do_pseudo_reloc", |
| ... | ... | @@ -69,108 +97,70 @@ void AutoExporter::initSymbolExcludes() { |
| 69 | 97 | "DllEntryPoint", |
| 70 | 98 | "DllMainCRTStartup", |
| 71 | 99 | }; |
| 72 | ExcludeSymbolPrefixes.insert("_head_"); | |
| 100 | excludeSymbolPrefixes.insert("_head_"); | |
| 73 | 101 | } |
| 74 | 102 | } |
| 75 | 103 | |
| 76 | AutoExporter::AutoExporter() { | |
| 77 | ExcludeLibs = { | |
| 78 | "libgcc", | |
| 79 | "libgcc_s", | |
| 80 | "libstdc++", | |
| 81 | "libmingw32", | |
| 82 | "libmingwex", | |
| 83 | "libg2c", | |
| 84 | "libsupc++", | |
| 85 | "libobjc", | |
| 86 | "libgcj", | |
| 87 | "libclang_rt.builtins", | |
| 88 | "libclang_rt.builtins-aarch64", | |
| 89 | "libclang_rt.builtins-arm", | |
| 90 | "libclang_rt.builtins-i386", | |
| 91 | "libclang_rt.builtins-x86_64", | |
| 92 | "libc++", | |
| 93 | "libc++abi", | |
| 94 | "libunwind", | |
| 95 | "libmsvcrt", | |
| 96 | "libucrtbase", | |
| 97 | }; | |
| 98 | ExcludeObjects = { | |
| 99 | "crt0.o", | |
| 100 | "crt1.o", | |
| 101 | "crt1u.o", | |
| 102 | "crt2.o", | |
| 103 | "crt2u.o", | |
| 104 | "dllcrt1.o", | |
| 105 | "dllcrt2.o", | |
| 106 | "gcrt0.o", | |
| 107 | "gcrt1.o", | |
| 108 | "gcrt2.o", | |
| 109 | "crtbegin.o", | |
| 110 | "crtend.o", | |
| 111 | }; | |
| 112 | } | |
| 113 | ||
| 114 | void AutoExporter::addWholeArchive(StringRef Path) { | |
| 115 | StringRef LibName = sys::path::filename(Path); | |
| 104 | void AutoExporter::addWholeArchive(StringRef path) { | |
| 105 | StringRef libName = sys::path::filename(path); | |
| 116 | 106 | // Drop the file extension, to match the processing below. |
| 117 | LibName = LibName.substr(0, LibName.rfind('.')); | |
| 118 | ExcludeLibs.erase(LibName); | |
| 107 | libName = libName.substr(0, libName.rfind('.')); | |
| 108 | excludeLibs.erase(libName); | |
| 119 | 109 | } |
| 120 | 110 | |
| 121 | bool AutoExporter::shouldExport(Defined *Sym) const { | |
| 122 | if (!Sym || !Sym->isLive() || !Sym->getChunk()) | |
| 111 | bool AutoExporter::shouldExport(Defined *sym) const { | |
| 112 | if (!sym || !sym->isLive() || !sym->getChunk()) | |
| 123 | 113 | return false; |
| 124 | 114 | |
| 125 | 115 | // Only allow the symbol kinds that make sense to export; in particular, |
| 126 | 116 | // disallow import symbols. |
| 127 | if (!isa<DefinedRegular>(Sym) && !isa<DefinedCommon>(Sym)) | |
| 117 | if (!isa<DefinedRegular>(sym) && !isa<DefinedCommon>(sym)) | |
| 128 | 118 | return false; |
| 129 | if (ExcludeSymbols.count(Sym->getName())) | |
| 119 | if (excludeSymbols.count(sym->getName())) | |
| 130 | 120 | return false; |
| 131 | 121 | |
| 132 | for (StringRef Prefix : ExcludeSymbolPrefixes.keys()) | |
| 133 | if (Sym->getName().startswith(Prefix)) | |
| 122 | for (StringRef prefix : excludeSymbolPrefixes.keys()) | |
| 123 | if (sym->getName().startswith(prefix)) | |
| 134 | 124 | return false; |
| 135 | for (StringRef Suffix : ExcludeSymbolSuffixes.keys()) | |
| 136 | if (Sym->getName().endswith(Suffix)) | |
| 125 | for (StringRef suffix : excludeSymbolSuffixes.keys()) | |
| 126 | if (sym->getName().endswith(suffix)) | |
| 137 | 127 | return false; |
| 138 | 128 | |
| 139 | 129 | // If a corresponding __imp_ symbol exists and is defined, don't export it. |
| 140 | if (Symtab->find(("__imp_" + Sym->getName()).str())) | |
| 130 | if (symtab->find(("__imp_" + sym->getName()).str())) | |
| 141 | 131 | return false; |
| 142 | 132 | |
| 143 | 133 | // Check that file is non-null before dereferencing it, symbols not |
| 144 | 134 | // originating in regular object files probably shouldn't be exported. |
| 145 | if (!Sym->getFile()) | |
| 135 | if (!sym->getFile()) | |
| 146 | 136 | return false; |
| 147 | 137 | |
| 148 | StringRef LibName = sys::path::filename(Sym->getFile()->ParentName); | |
| 138 | StringRef libName = sys::path::filename(sym->getFile()->parentName); | |
| 149 | 139 | |
| 150 | 140 | // Drop the file extension. |
| 151 | LibName = LibName.substr(0, LibName.rfind('.')); | |
| 152 | if (!LibName.empty()) | |
| 153 | return !ExcludeLibs.count(LibName); | |
| 141 | libName = libName.substr(0, libName.rfind('.')); | |
| 142 | if (!libName.empty()) | |
| 143 | return !excludeLibs.count(libName); | |
| 154 | 144 | |
| 155 | StringRef FileName = sys::path::filename(Sym->getFile()->getName()); | |
| 156 | return !ExcludeObjects.count(FileName); | |
| 145 | StringRef fileName = sys::path::filename(sym->getFile()->getName()); | |
| 146 | return !excludeObjects.count(fileName); | |
| 157 | 147 | } |
| 158 | 148 | |
| 159 | void coff::writeDefFile(StringRef Name) { | |
| 160 | std::error_code EC; | |
| 161 | raw_fd_ostream OS(Name, EC, sys::fs::F_None); | |
| 162 | if (EC) | |
| 163 | fatal("cannot open " + Name + ": " + EC.message()); | |
| 164 | ||
| 165 | OS << "EXPORTS\n"; | |
| 166 | for (Export &E : Config->Exports) { | |
| 167 | OS << " " << E.ExportName << " " | |
| 168 | << "@" << E.Ordinal; | |
| 169 | if (auto *Def = dyn_cast_or_null<Defined>(E.Sym)) { | |
| 170 | if (Def && Def->getChunk() && | |
| 171 | !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) | |
| 172 | OS << " DATA"; | |
| 149 | void coff::writeDefFile(StringRef name) { | |
| 150 | std::error_code ec; | |
| 151 | raw_fd_ostream os(name, ec, sys::fs::F_None); | |
| 152 | if (ec) | |
| 153 | fatal("cannot open " + name + ": " + ec.message()); | |
| 154 | ||
| 155 | os << "EXPORTS\n"; | |
| 156 | for (Export &e : config->exports) { | |
| 157 | os << " " << e.exportName << " " | |
| 158 | << "@" << e.ordinal; | |
| 159 | if (auto *def = dyn_cast_or_null<Defined>(e.sym)) { | |
| 160 | if (def && def->getChunk() && | |
| 161 | !(def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) | |
| 162 | os << " DATA"; | |
| 173 | 163 | } |
| 174 | OS << "\n"; | |
| 164 | os << "\n"; | |
| 175 | 165 | } |
| 176 | 166 | } |
deps/lld/COFF/MinGW.h+11-14| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- MinGW.h --------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -23,20 +22,18 @@ class AutoExporter { |
| 23 | 22 | public: |
| 24 | 23 | AutoExporter(); |
| 25 | 24 | |
| 26 | void initSymbolExcludes(); | |
| 27 | ||
| 28 | void addWholeArchive(StringRef Path); | |
| 25 | void addWholeArchive(StringRef path); | |
| 29 | 26 | |
| 30 | llvm::StringSet<> ExcludeSymbols; | |
| 31 | llvm::StringSet<> ExcludeSymbolPrefixes; | |
| 32 | llvm::StringSet<> ExcludeSymbolSuffixes; | |
| 33 | llvm::StringSet<> ExcludeLibs; | |
| 34 | llvm::StringSet<> ExcludeObjects; | |
| 27 | llvm::StringSet<> excludeSymbols; | |
| 28 | llvm::StringSet<> excludeSymbolPrefixes; | |
| 29 | llvm::StringSet<> excludeSymbolSuffixes; | |
| 30 | llvm::StringSet<> excludeLibs; | |
| 31 | llvm::StringSet<> excludeObjects; | |
| 35 | 32 | |
| 36 | bool shouldExport(Defined *Sym) const; | |
| 33 | bool shouldExport(Defined *sym) const; | |
| 37 | 34 | }; |
| 38 | 35 | |
| 39 | void writeDefFile(StringRef Name); | |
| 36 | void writeDefFile(StringRef name); | |
| 40 | 37 | |
| 41 | 38 | } // namespace coff |
| 42 | 39 | } // namespace lld |
deps/lld/COFF/Options.td+48-17| ... | ... | @@ -3,11 +3,11 @@ include "llvm/Option/OptParser.td" |
| 3 | 3 | // link.exe accepts options starting with either a dash or a slash. |
| 4 | 4 | |
| 5 | 5 | // Flag that takes no arguments. |
| 6 | class F<string name> : Flag<["/", "-", "-?"], name>; | |
| 6 | class F<string name> : Flag<["/", "-", "/?", "-?"], name>; | |
| 7 | 7 | |
| 8 | 8 | // Flag that takes one argument after ":". |
| 9 | 9 | class P<string name, string help> : |
| 10 | Joined<["/", "-", "-?"], name#":">, HelpText<help>; | |
| 10 | Joined<["/", "-", "/?", "-?"], name#":">, HelpText<help>; | |
| 11 | 11 | |
| 12 | 12 | // Boolean flag which can be suffixed by ":no". Using it unsuffixed turns the |
| 13 | 13 | // flag on and using it suffixed by ":no" turns it off. |
| ... | ... | @@ -32,6 +32,9 @@ def errorlimit : P<"errorlimit", |
| 32 | 32 | def export : P<"export", "Export a function">; |
| 33 | 33 | // No help text because /failifmismatch is not intended to be used by the user. |
| 34 | 34 | def failifmismatch : P<"failifmismatch", "">; |
| 35 | def filealign : P<"filealign", "Section alignment in the output file">; | |
| 36 | def functionpadmin : F<"functionpadmin">; | |
| 37 | def functionpadmin_opt : P<"functionpadmin", "Prepares an image for hotpatching">; | |
| 35 | 38 | def guard : P<"guard", "Control flow guard">; |
| 36 | 39 | def heap : P<"heap", "Size of the heap">; |
| 37 | 40 | def ignore : P<"ignore", "Specify warning codes to ignore">; |
| ... | ... | @@ -64,7 +67,8 @@ def timestamp : P<"timestamp", "Specify the PE header timestamp">; |
| 64 | 67 | def version : P<"version", "Specify a version number in the PE header">; |
| 65 | 68 | def wholearchive_file : P<"wholearchive", "Include all object files from this archive">; |
| 66 | 69 | |
| 67 | def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias<nodefaultlib>; | |
| 70 | def disallowlib : Joined<["/", "-", "/?", "-?"], "disallowlib:">, | |
| 71 | Alias<nodefaultlib>; | |
| 68 | 72 | |
| 69 | 73 | def manifest : F<"manifest">, HelpText<"Create .manifest file">; |
| 70 | 74 | def manifest_colon : P< |
| ... | ... | @@ -82,11 +86,11 @@ def manifestinput : P< |
| 82 | 86 | // We cannot use multiclass P because class name "incl" is different |
| 83 | 87 | // from its command line option name. We do this because "include" is |
| 84 | 88 | // a reserved keyword in tablegen. |
| 85 | def incl : Joined<["/", "-"], "include:">, | |
| 89 | def incl : Joined<["/", "-", "/?", "-?"], "include:">, | |
| 86 | 90 | HelpText<"Force symbol to be added to symbol table as undefined one">; |
| 87 | 91 | |
| 88 | 92 | // "def" is also a keyword. |
| 89 | def deffile : Joined<["/", "-"], "def:">, | |
| 93 | def deffile : Joined<["/", "-", "/?", "-?"], "def:">, | |
| 90 | 94 | HelpText<"Use module-definition file">; |
| 91 | 95 | |
| 92 | 96 | def debug : F<"debug">, HelpText<"Embed a symbol table in the image">; |
| ... | ... | @@ -101,8 +105,12 @@ def noentry : F<"noentry">, |
| 101 | 105 | def profile : F<"profile">; |
| 102 | 106 | def repro : F<"Brepro">, |
| 103 | 107 | HelpText<"Use a hash of the executable as the PE header timestamp">; |
| 104 | def swaprun_cd : F<"swaprun:cd">; | |
| 105 | def swaprun_net : F<"swaprun:net">; | |
| 108 | def swaprun : P<"swaprun", | |
| 109 | "Comma-separated list of 'cd' or 'net'">; | |
| 110 | def swaprun_cd : F<"swaprun:cd">, Alias<swaprun>, AliasArgs<["cd"]>, | |
| 111 | HelpText<"Make loader run output binary from swap instead of from CD">; | |
| 112 | def swaprun_net : F<"swaprun:net">, Alias<swaprun>, AliasArgs<["net"]>, | |
| 113 | HelpText<"Make loader run output binary from swap instead of from network">; | |
| 106 | 114 | def verbose : F<"verbose">; |
| 107 | 115 | def wholearchive_flag : F<"wholearchive">; |
| 108 | 116 | |
| ... | ... | @@ -112,6 +120,8 @@ def force_unresolved : F<"force:unresolved">, |
| 112 | 120 | HelpText<"Allow undefined symbols when creating executables">; |
| 113 | 121 | def force_multiple : F<"force:multiple">, |
| 114 | 122 | HelpText<"Allow multiply defined symbols when creating executables">; |
| 123 | def force_multipleres : F<"force:multipleres">, | |
| 124 | HelpText<"Allow multiply defined resources when creating executables">; | |
| 115 | 125 | defm WX : B<"WX", "Treat warnings as errors", "Don't treat warnings as errors">; |
| 116 | 126 | |
| 117 | 127 | defm allowbind : B<"allowbind", "Enable DLL binding (default)", |
| ... | ... | @@ -147,37 +157,58 @@ defm tsaware : B<"tsaware", |
| 147 | 157 | "Create non-Terminal Server aware executable">; |
| 148 | 158 | |
| 149 | 159 | def help : F<"help">; |
| 150 | def help_q : Flag<["/?", "-?"], "">, Alias<help>; | |
| 160 | ||
| 161 | // /?? and -?? must be before /? and -? to not confuse lib/Options. | |
| 162 | def help_q : Flag<["/??", "-??", "/?", "-?"], "">, Alias<help>; | |
| 151 | 163 | |
| 152 | 164 | // LLD extensions |
| 165 | def exclude_all_symbols : F<"exclude-all-symbols">; | |
| 153 | 166 | def export_all_symbols : F<"export-all-symbols">; |
| 167 | defm demangle : B<"demangle", | |
| 168 | "Demangle symbols in output (default)", | |
| 169 | "Do not demangle symbols in output">; | |
| 170 | def include_optional : Joined<["/", "-", "/?", "-?"], "includeoptional:">, | |
| 171 | HelpText<"Add symbol as undefined, but allow it to remain undefined">; | |
| 154 | 172 | def kill_at : F<"kill-at">; |
| 155 | 173 | def lldmingw : F<"lldmingw">; |
| 156 | def output_def : Joined<["/", "-"], "output-def:">; | |
| 174 | def output_def : Joined<["/", "-", "/?", "-?"], "output-def:">; | |
| 157 | 175 | def pdb_source_path : P<"pdbsourcepath", |
| 158 | 176 | "Base path used to make relative source file path absolute in PDB">; |
| 159 | 177 | def rsp_quoting : Joined<["--"], "rsp-quoting=">, |
| 160 | 178 | HelpText<"Quoting style for response files, 'windows' (default) or 'posix'">; |
| 179 | def thinlto_emit_imports_files : | |
| 180 | F<"thinlto-emit-imports-files">, | |
| 181 | HelpText<"Emit .imports files with -thinlto-index-only">; | |
| 182 | def thinlto_index_only : | |
| 183 | F<"thinlto-index-only">, | |
| 184 | HelpText<"Instead of linking, emit ThinLTO index files">; | |
| 185 | def thinlto_index_only_arg : P< | |
| 186 | "thinlto-index-only", | |
| 187 | "-thinlto-index-only and also write native module names to file">; | |
| 188 | def thinlto_object_suffix_replace : P< | |
| 189 | "thinlto-object-suffix-replace", | |
| 190 | "'old;new' replace old suffix with new suffix in ThinLTO index">; | |
| 191 | def thinlto_prefix_replace: P< | |
| 192 | "thinlto-prefix-replace", | |
| 193 | "'old;new' replace old prefix with new prefix in ThinLTO outputs">; | |
| 161 | 194 | def dash_dash_version : Flag<["--"], "version">, |
| 162 | 195 | HelpText<"Print version information">; |
| 196 | defm threads: B<"threads", | |
| 197 | "Run the linker multi-threaded (default)", | |
| 198 | "Do not run the linker multi-threaded">; | |
| 163 | 199 | |
| 164 | 200 | // Flags for debugging |
| 165 | 201 | def lldmap : F<"lldmap">; |
| 166 | def lldmap_file : Joined<["/", "-"], "lldmap:">; | |
| 202 | def lldmap_file : Joined<["/", "-", "/?", "-?"], "lldmap:">; | |
| 167 | 203 | def show_timing : F<"time">; |
| 204 | def summary : F<"summary">; | |
| 168 | 205 | |
| 169 | 206 | //============================================================================== |
| 170 | 207 | // The flags below do nothing. They are defined only for link.exe compatibility. |
| 171 | 208 | //============================================================================== |
| 172 | 209 | |
| 173 | class QF<string name> : Joined<["/", "-", "-?"], name#":">; | |
| 210 | class QF<string name> : Joined<["/", "-", "/?", "-?"], name#":">; | |
| 174 | 211 | |
| 175 | multiclass QB<string name> { | |
| 176 | def "" : F<name>; | |
| 177 | def _no : F<name#":no">; | |
| 178 | } | |
| 179 | ||
| 180 | def functionpadmin : F<"functionpadmin">; | |
| 181 | 212 | def ignoreidl : F<"ignoreidl">; |
| 182 | 213 | def nologo : F<"nologo">; |
| 183 | 214 | def throwingnew : F<"throwingnew">; |
deps/lld/COFF/PDB.cpp+1046-981| ... | ... | @@ -1,21 +1,23 @@ |
| 1 | 1 | //===- PDB.cpp ------------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| 10 | 9 | #include "PDB.h" |
| 11 | 10 | #include "Chunks.h" |
| 12 | 11 | #include "Config.h" |
| 12 | #include "DebugTypes.h" | |
| 13 | 13 | #include "Driver.h" |
| 14 | 14 | #include "SymbolTable.h" |
| 15 | 15 | #include "Symbols.h" |
| 16 | #include "TypeMerger.h" | |
| 16 | 17 | #include "Writer.h" |
| 17 | 18 | #include "lld/Common/ErrorHandler.h" |
| 18 | 19 | #include "lld/Common/Timer.h" |
| 20 | #include "lld/Common/Threads.h" | |
| 19 | 21 | #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" |
| 20 | 22 | #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" |
| 21 | 23 | #include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h" |
| ... | ... | @@ -53,7 +55,6 @@ |
| 53 | 55 | #include "llvm/Support/Errc.h" |
| 54 | 56 | #include "llvm/Support/FormatVariadic.h" |
| 55 | 57 | #include "llvm/Support/JamCRC.h" |
| 56 | #include "llvm/Support/Parallel.h" | |
| 57 | 58 | #include "llvm/Support/Path.h" |
| 58 | 59 | #include "llvm/Support/ScopedPrinter.h" |
| 59 | 60 | #include <memory> |
| ... | ... | @@ -65,44 +66,34 @@ using namespace llvm::codeview; |
| 65 | 66 | |
| 66 | 67 | using llvm::object::coff_section; |
| 67 | 68 | |
| 68 | static ExitOnError ExitOnErr; | |
| 69 | static ExitOnError exitOnErr; | |
| 69 | 70 | |
| 70 | static Timer TotalPdbLinkTimer("PDB Emission (Cumulative)", Timer::root()); | |
| 71 | static Timer totalPdbLinkTimer("PDB Emission (Cumulative)", Timer::root()); | |
| 71 | 72 | |
| 72 | static Timer AddObjectsTimer("Add Objects", TotalPdbLinkTimer); | |
| 73 | static Timer TypeMergingTimer("Type Merging", AddObjectsTimer); | |
| 74 | static Timer SymbolMergingTimer("Symbol Merging", AddObjectsTimer); | |
| 75 | static Timer GlobalsLayoutTimer("Globals Stream Layout", TotalPdbLinkTimer); | |
| 76 | static Timer TpiStreamLayoutTimer("TPI Stream Layout", TotalPdbLinkTimer); | |
| 77 | static Timer DiskCommitTimer("Commit to Disk", TotalPdbLinkTimer); | |
| 73 | static Timer addObjectsTimer("Add Objects", totalPdbLinkTimer); | |
| 74 | static Timer typeMergingTimer("Type Merging", addObjectsTimer); | |
| 75 | static Timer symbolMergingTimer("Symbol Merging", addObjectsTimer); | |
| 76 | static Timer globalsLayoutTimer("Globals Stream Layout", totalPdbLinkTimer); | |
| 77 | static Timer tpiStreamLayoutTimer("TPI Stream Layout", totalPdbLinkTimer); | |
| 78 | static Timer diskCommitTimer("Commit to Disk", totalPdbLinkTimer); | |
| 78 | 79 | |
| 79 | 80 | namespace { |
| 80 | /// Map from type index and item index in a type server PDB to the | |
| 81 | /// corresponding index in the destination PDB. | |
| 82 | struct CVIndexMap { | |
| 83 | SmallVector<TypeIndex, 0> TPIMap; | |
| 84 | SmallVector<TypeIndex, 0> IPIMap; | |
| 85 | bool IsTypeServerMap = false; | |
| 86 | bool IsPrecompiledTypeMap = false; | |
| 87 | }; | |
| 88 | ||
| 89 | 81 | class DebugSHandler; |
| 90 | 82 | |
| 91 | 83 | class PDBLinker { |
| 92 | 84 | friend DebugSHandler; |
| 93 | 85 | |
| 94 | 86 | public: |
| 95 | PDBLinker(SymbolTable *Symtab) | |
| 96 | : Alloc(), Symtab(Symtab), Builder(Alloc), TypeTable(Alloc), | |
| 97 | IDTable(Alloc), GlobalTypeTable(Alloc), GlobalIDTable(Alloc) { | |
| 87 | PDBLinker(SymbolTable *symtab) | |
| 88 | : alloc(), symtab(symtab), builder(alloc), tMerger(alloc) { | |
| 98 | 89 | // This isn't strictly necessary, but link.exe usually puts an empty string |
| 99 | 90 | // as the first "valid" string in the string table, so we do the same in |
| 100 | 91 | // order to maintain as much byte-for-byte compatibility as possible. |
| 101 | PDBStrTab.insert(""); | |
| 92 | pdbStrTab.insert(""); | |
| 102 | 93 | } |
| 103 | 94 | |
| 104 | 95 | /// Emit the basic PDB structure: initial streams, headers, etc. |
| 105 | void initialize(llvm::codeview::DebugInfo *BuildId); | |
| 96 | void initialize(llvm::codeview::DebugInfo *buildId); | |
| 106 | 97 | |
| 107 | 98 | /// Add natvis files specified on the command line. |
| 108 | 99 | void addNatvisFiles(); |
| ... | ... | @@ -110,10 +101,13 @@ public: |
| 110 | 101 | /// Link CodeView from each object file in the symbol table into the PDB. |
| 111 | 102 | void addObjectsToPDB(); |
| 112 | 103 | |
| 104 | /// Link info for each import file in the symbol table into the PDB. | |
| 105 | void addImportFilesToPDB(ArrayRef<OutputSection *> outputSections); | |
| 106 | ||
| 113 | 107 | /// Link CodeView from a single object file into the target (output) PDB. |
| 114 | 108 | /// When a precompiled headers object is linked, its TPI map might be provided |
| 115 | 109 | /// externally. |
| 116 | void addObjFile(ObjFile *File, CVIndexMap *ExternIndexMap = nullptr); | |
| 110 | void addObjFile(ObjFile *file, CVIndexMap *externIndexMap = nullptr); | |
| 117 | 111 | |
| 118 | 112 | /// Produce a mapping from the type and item indices used in the object |
| 119 | 113 | /// file to those in the destination PDB. |
| ... | ... | @@ -125,20 +119,17 @@ public: |
| 125 | 119 | /// |
| 126 | 120 | /// If the object does not use a type server PDB (compiled with /Z7), we merge |
| 127 | 121 | /// all the type and item records from the .debug$S stream and fill in the |
| 128 | /// caller-provided ObjectIndexMap. | |
| 129 | Expected<const CVIndexMap &> mergeDebugT(ObjFile *File, | |
| 130 | CVIndexMap *ObjectIndexMap); | |
| 122 | /// caller-provided objectIndexMap. | |
| 123 | Expected<const CVIndexMap &> mergeDebugT(ObjFile *file, | |
| 124 | CVIndexMap *objectIndexMap); | |
| 131 | 125 | |
| 132 | 126 | /// Reads and makes available a PDB. |
| 133 | Expected<const CVIndexMap &> maybeMergeTypeServerPDB(ObjFile *File, | |
| 134 | const CVType &FirstType); | |
| 127 | Expected<const CVIndexMap &> maybeMergeTypeServerPDB(ObjFile *file); | |
| 135 | 128 | |
| 136 | 129 | /// Merges a precompiled headers TPI map into the current TPI map. The |
| 137 | 130 | /// precompiled headers object will also be loaded and remapped in the |
| 138 | 131 | /// process. |
| 139 | Expected<const CVIndexMap &> | |
| 140 | mergeInPrecompHeaderObj(ObjFile *File, const CVType &FirstType, | |
| 141 | CVIndexMap *ObjectIndexMap); | |
| 132 | Error mergeInPrecompHeaderObj(ObjFile *file, CVIndexMap *objectIndexMap); | |
| 142 | 133 | |
| 143 | 134 | /// Reads and makes available a precompiled headers object. |
| 144 | 135 | /// |
| ... | ... | @@ -149,109 +140,87 @@ public: |
| 149 | 140 | /// |
| 150 | 141 | /// If the precompiled headers object was already loaded, this function will |
| 151 | 142 | /// simply return its (remapped) TPI map. |
| 152 | Expected<const CVIndexMap &> aquirePrecompObj(ObjFile *File, | |
| 153 | PrecompRecord Precomp); | |
| 143 | Expected<const CVIndexMap &> aquirePrecompObj(ObjFile *file); | |
| 154 | 144 | |
| 155 | 145 | /// Adds a precompiled headers object signature -> TPI mapping. |
| 156 | 146 | std::pair<CVIndexMap &, bool /*already there*/> |
| 157 | registerPrecompiledHeaders(uint32_t Signature); | |
| 147 | registerPrecompiledHeaders(uint32_t signature); | |
| 158 | 148 | |
| 159 | void mergeSymbolRecords(ObjFile *File, const CVIndexMap &IndexMap, | |
| 160 | std::vector<ulittle32_t *> &StringTableRefs, | |
| 161 | BinaryStreamRef SymData); | |
| 149 | void mergeSymbolRecords(ObjFile *file, const CVIndexMap &indexMap, | |
| 150 | std::vector<ulittle32_t *> &stringTableRefs, | |
| 151 | BinaryStreamRef symData); | |
| 162 | 152 | |
| 163 | 153 | /// Add the section map and section contributions to the PDB. |
| 164 | void addSections(ArrayRef<OutputSection *> OutputSections, | |
| 165 | ArrayRef<uint8_t> SectionTable); | |
| 166 | ||
| 167 | /// Get the type table or the global type table if /DEBUG:GHASH is enabled. | |
| 168 | TypeCollection &getTypeTable() { | |
| 169 | if (Config->DebugGHashes) | |
| 170 | return GlobalTypeTable; | |
| 171 | return TypeTable; | |
| 172 | } | |
| 173 | ||
| 174 | /// Get the ID table or the global ID table if /DEBUG:GHASH is enabled. | |
| 175 | TypeCollection &getIDTable() { | |
| 176 | if (Config->DebugGHashes) | |
| 177 | return GlobalIDTable; | |
| 178 | return IDTable; | |
| 179 | } | |
| 154 | void addSections(ArrayRef<OutputSection *> outputSections, | |
| 155 | ArrayRef<uint8_t> sectionTable); | |
| 180 | 156 | |
| 181 | 157 | /// Write the PDB to disk and store the Guid generated for it in *Guid. |
| 182 | void commit(codeview::GUID *Guid); | |
| 183 | ||
| 184 | private: | |
| 185 | BumpPtrAllocator Alloc; | |
| 186 | ||
| 187 | SymbolTable *Symtab; | |
| 158 | void commit(codeview::GUID *guid); | |
| 188 | 159 | |
| 189 | pdb::PDBFileBuilder Builder; | |
| 160 | // Print statistics regarding the final PDB | |
| 161 | void printStats(); | |
| 190 | 162 | |
| 191 | /// Type records that will go into the PDB TPI stream. | |
| 192 | MergingTypeTableBuilder TypeTable; | |
| 163 | private: | |
| 164 | BumpPtrAllocator alloc; | |
| 193 | 165 | |
| 194 | /// Item records that will go into the PDB IPI stream. | |
| 195 | MergingTypeTableBuilder IDTable; | |
| 166 | SymbolTable *symtab; | |
| 196 | 167 | |
| 197 | /// Type records that will go into the PDB TPI stream (for /DEBUG:GHASH) | |
| 198 | GlobalTypeTableBuilder GlobalTypeTable; | |
| 168 | pdb::PDBFileBuilder builder; | |
| 199 | 169 | |
| 200 | /// Item records that will go into the PDB IPI stream (for /DEBUG:GHASH) | |
| 201 | GlobalTypeTableBuilder GlobalIDTable; | |
| 170 | TypeMerger tMerger; | |
| 202 | 171 | |
| 203 | 172 | /// PDBs use a single global string table for filenames in the file checksum |
| 204 | 173 | /// table. |
| 205 | DebugStringTableSubsection PDBStrTab; | |
| 206 | ||
| 207 | llvm::SmallString<128> NativePath; | |
| 174 | DebugStringTableSubsection pdbStrTab; | |
| 208 | 175 | |
| 209 | /// A list of other PDBs which are loaded during the linking process and which | |
| 210 | /// we need to keep around since the linking operation may reference pointers | |
| 211 | /// inside of these PDBs. | |
| 212 | llvm::SmallVector<std::unique_ptr<pdb::NativeSession>, 2> LoadedPDBs; | |
| 176 | llvm::SmallString<128> nativePath; | |
| 213 | 177 | |
| 214 | std::vector<pdb::SecMapEntry> SectionMap; | |
| 178 | std::vector<pdb::SecMapEntry> sectionMap; | |
| 215 | 179 | |
| 216 | 180 | /// Type index mappings of type server PDBs that we've loaded so far. |
| 217 | std::map<codeview::GUID, CVIndexMap> TypeServerIndexMappings; | |
| 181 | std::map<codeview::GUID, CVIndexMap> typeServerIndexMappings; | |
| 218 | 182 | |
| 219 | 183 | /// Type index mappings of precompiled objects type map that we've loaded so |
| 220 | 184 | /// far. |
| 221 | std::map<uint32_t, CVIndexMap> PrecompTypeIndexMappings; | |
| 185 | std::map<uint32_t, CVIndexMap> precompTypeIndexMappings; | |
| 222 | 186 | |
| 223 | /// List of TypeServer PDBs which cannot be loaded. | |
| 224 | /// Cached to prevent repeated load attempts. | |
| 225 | std::map<codeview::GUID, std::string> MissingTypeServerPDBs; | |
| 187 | // For statistics | |
| 188 | uint64_t globalSymbols = 0; | |
| 189 | uint64_t moduleSymbols = 0; | |
| 190 | uint64_t publicSymbols = 0; | |
| 226 | 191 | }; |
| 227 | 192 | |
| 228 | 193 | class DebugSHandler { |
| 229 | PDBLinker &Linker; | |
| 194 | PDBLinker &linker; | |
| 230 | 195 | |
| 231 | 196 | /// The object file whose .debug$S sections we're processing. |
| 232 | ObjFile &File; | |
| 197 | ObjFile &file; | |
| 233 | 198 | |
| 234 | 199 | /// The result of merging type indices. |
| 235 | const CVIndexMap &IndexMap; | |
| 200 | const CVIndexMap &indexMap; | |
| 236 | 201 | |
| 237 | 202 | /// The DEBUG_S_STRINGTABLE subsection. These strings are referred to by |
| 238 | 203 | /// index from other records in the .debug$S section. All of these strings |
| 239 | 204 | /// need to be added to the global PDB string table, and all references to |
| 240 | 205 | /// these strings need to have their indices re-written to refer to the |
| 241 | 206 | /// global PDB string table. |
| 242 | DebugStringTableSubsectionRef CVStrTab; | |
| 207 | DebugStringTableSubsectionRef cVStrTab; | |
| 243 | 208 | |
| 244 | 209 | /// The DEBUG_S_FILECHKSMS subsection. As above, these are referred to |
| 245 | 210 | /// by other records in the .debug$S section and need to be merged into the |
| 246 | 211 | /// PDB. |
| 247 | DebugChecksumsSubsectionRef Checksums; | |
| 212 | DebugChecksumsSubsectionRef checksums; | |
| 213 | ||
| 214 | /// The DEBUG_S_INLINEELINES subsection. There can be only one of these per | |
| 215 | /// object file. | |
| 216 | DebugInlineeLinesSubsectionRef inlineeLines; | |
| 248 | 217 | |
| 249 | 218 | /// The DEBUG_S_FRAMEDATA subsection(s). There can be more than one of |
| 250 | 219 | /// these and they need not appear in any specific order. However, they |
| 251 | 220 | /// contain string table references which need to be re-written, so we |
| 252 | 221 | /// collect them all here and re-write them after all subsections have been |
| 253 | 222 | /// discovered and processed. |
| 254 | std::vector<DebugFrameDataSubsectionRef> NewFpoFrames; | |
| 223 | std::vector<DebugFrameDataSubsectionRef> newFpoFrames; | |
| 255 | 224 | |
| 256 | 225 | /// Pointers to raw memory that we determine have string table references |
| 257 | 226 | /// that need to be re-written. We first process all .debug$S subsections |
| ... | ... | @@ -259,13 +228,17 @@ class DebugSHandler { |
| 259 | 228 | /// up this list as we go. At the end, we use the string table (which must |
| 260 | 229 | /// have been discovered by now else it is an error) to re-write these |
| 261 | 230 | /// references. |
| 262 | std::vector<ulittle32_t *> StringTableReferences; | |
| 231 | std::vector<ulittle32_t *> stringTableReferences; | |
| 263 | 232 | |
| 264 | 233 | public: |
| 265 | DebugSHandler(PDBLinker &Linker, ObjFile &File, const CVIndexMap &IndexMap) | |
| 266 | : Linker(Linker), File(File), IndexMap(IndexMap) {} | |
| 234 | DebugSHandler(PDBLinker &linker, ObjFile &file, const CVIndexMap &indexMap) | |
| 235 | : linker(linker), file(file), indexMap(indexMap) {} | |
| 236 | ||
| 237 | void handleDebugS(lld::coff::SectionChunk &debugS); | |
| 238 | ||
| 239 | std::shared_ptr<DebugInlineeLinesSubsection> | |
| 240 | mergeInlineeLines(DebugChecksumsSubsection *newChecksums); | |
| 267 | 241 | |
| 268 | void handleDebugS(lld::coff::SectionChunk &DebugS); | |
| 269 | 242 | void finish(); |
| 270 | 243 | }; |
| 271 | 244 | } |
| ... | ... | @@ -273,7 +246,7 @@ public: |
| 273 | 246 | // Visual Studio's debugger requires absolute paths in various places in the |
| 274 | 247 | // PDB to work without additional configuration: |
| 275 | 248 | // https://docs.microsoft.com/en-us/visualstudio/debugger/debug-source-files-common-properties-solution-property-pages-dialog-box |
| 276 | static void pdbMakeAbsolute(SmallVectorImpl<char> &FileName) { | |
| 249 | static void pdbMakeAbsolute(SmallVectorImpl<char> &fileName) { | |
| 277 | 250 | // The default behavior is to produce paths that are valid within the context |
| 278 | 251 | // of the machine that you perform the link on. If the linker is running on |
| 279 | 252 | // a POSIX system, we will output absolute POSIX paths. If the linker is |
| ... | ... | @@ -281,16 +254,16 @@ static void pdbMakeAbsolute(SmallVectorImpl<char> &FileName) { |
| 281 | 254 | // user desires any other kind of behavior, they should explicitly pass |
| 282 | 255 | // /pdbsourcepath, in which case we will treat the exact string the user |
| 283 | 256 | // passed in as the gospel and not normalize, canonicalize it. |
| 284 | if (sys::path::is_absolute(FileName, sys::path::Style::windows) || | |
| 285 | sys::path::is_absolute(FileName, sys::path::Style::posix)) | |
| 257 | if (sys::path::is_absolute(fileName, sys::path::Style::windows) || | |
| 258 | sys::path::is_absolute(fileName, sys::path::Style::posix)) | |
| 286 | 259 | return; |
| 287 | 260 | |
| 288 | 261 | // It's not absolute in any path syntax. Relative paths necessarily refer to |
| 289 | 262 | // the local file system, so we can make it native without ending up with a |
| 290 | 263 | // nonsensical path. |
| 291 | if (Config->PDBSourcePath.empty()) { | |
| 292 | sys::path::native(FileName); | |
| 293 | sys::fs::make_absolute(FileName); | |
| 264 | if (config->pdbSourcePath.empty()) { | |
| 265 | sys::path::native(fileName); | |
| 266 | sys::fs::make_absolute(fileName); | |
| 294 | 267 | return; |
| 295 | 268 | } |
| 296 | 269 | |
| ... | ... | @@ -298,397 +271,239 @@ static void pdbMakeAbsolute(SmallVectorImpl<char> &FileName) { |
| 298 | 271 | // Since PDB's are more of a Windows thing, we make this conservative and only |
| 299 | 272 | // decide that it's a unix path if we're fairly certain. Specifically, if |
| 300 | 273 | // it starts with a forward slash. |
| 301 | SmallString<128> AbsoluteFileName = Config->PDBSourcePath; | |
| 302 | sys::path::Style GuessedStyle = AbsoluteFileName.startswith("/") | |
| 274 | SmallString<128> absoluteFileName = config->pdbSourcePath; | |
| 275 | sys::path::Style guessedStyle = absoluteFileName.startswith("/") | |
| 303 | 276 | ? sys::path::Style::posix |
| 304 | 277 | : sys::path::Style::windows; |
| 305 | sys::path::append(AbsoluteFileName, GuessedStyle, FileName); | |
| 306 | sys::path::native(AbsoluteFileName, GuessedStyle); | |
| 307 | sys::path::remove_dots(AbsoluteFileName, true, GuessedStyle); | |
| 278 | sys::path::append(absoluteFileName, guessedStyle, fileName); | |
| 279 | sys::path::native(absoluteFileName, guessedStyle); | |
| 280 | sys::path::remove_dots(absoluteFileName, true, guessedStyle); | |
| 308 | 281 | |
| 309 | FileName = std::move(AbsoluteFileName); | |
| 310 | } | |
| 311 | ||
| 312 | static SectionChunk *findByName(ArrayRef<SectionChunk *> Sections, | |
| 313 | StringRef Name) { | |
| 314 | for (SectionChunk *C : Sections) | |
| 315 | if (C->getSectionName() == Name) | |
| 316 | return C; | |
| 317 | return nullptr; | |
| 318 | } | |
| 319 | ||
| 320 | static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> Data, | |
| 321 | StringRef SecName) { | |
| 322 | // First 4 bytes are section magic. | |
| 323 | if (Data.size() < 4) | |
| 324 | fatal(SecName + " too short"); | |
| 325 | if (support::endian::read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC) | |
| 326 | fatal(SecName + " has an invalid magic"); | |
| 327 | return Data.slice(4); | |
| 328 | } | |
| 329 | ||
| 330 | static ArrayRef<uint8_t> getDebugSection(ObjFile *File, StringRef SecName) { | |
| 331 | if (SectionChunk *Sec = findByName(File->getDebugChunks(), SecName)) | |
| 332 | return consumeDebugMagic(Sec->getContents(), SecName); | |
| 333 | return {}; | |
| 282 | fileName = std::move(absoluteFileName); | |
| 334 | 283 | } |
| 335 | 284 | |
| 336 | 285 | // A COFF .debug$H section is currently a clang extension. This function checks |
| 337 | 286 | // if a .debug$H section is in a format that we expect / understand, so that we |
| 338 | 287 | // can ignore any sections which are coincidentally also named .debug$H but do |
| 339 | 288 | // not contain a format we recognize. |
| 340 | static bool canUseDebugH(ArrayRef<uint8_t> DebugH) { | |
| 341 | if (DebugH.size() < sizeof(object::debug_h_header)) | |
| 289 | static bool canUseDebugH(ArrayRef<uint8_t> debugH) { | |
| 290 | if (debugH.size() < sizeof(object::debug_h_header)) | |
| 342 | 291 | return false; |
| 343 | auto *Header = | |
| 344 | reinterpret_cast<const object::debug_h_header *>(DebugH.data()); | |
| 345 | DebugH = DebugH.drop_front(sizeof(object::debug_h_header)); | |
| 346 | return Header->Magic == COFF::DEBUG_HASHES_SECTION_MAGIC && | |
| 347 | Header->Version == 0 && | |
| 348 | Header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1_8) && | |
| 349 | (DebugH.size() % 8 == 0); | |
| 292 | auto *header = | |
| 293 | reinterpret_cast<const object::debug_h_header *>(debugH.data()); | |
| 294 | debugH = debugH.drop_front(sizeof(object::debug_h_header)); | |
| 295 | return header->Magic == COFF::DEBUG_HASHES_SECTION_MAGIC && | |
| 296 | header->Version == 0 && | |
| 297 | header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1_8) && | |
| 298 | (debugH.size() % 8 == 0); | |
| 350 | 299 | } |
| 351 | 300 | |
| 352 | static Optional<ArrayRef<uint8_t>> getDebugH(ObjFile *File) { | |
| 353 | SectionChunk *Sec = findByName(File->getDebugChunks(), ".debug$H"); | |
| 354 | if (!Sec) | |
| 301 | static Optional<ArrayRef<uint8_t>> getDebugH(ObjFile *file) { | |
| 302 | SectionChunk *sec = | |
| 303 | SectionChunk::findByName(file->getDebugChunks(), ".debug$H"); | |
| 304 | if (!sec) | |
| 355 | 305 | return llvm::None; |
| 356 | ArrayRef<uint8_t> Contents = Sec->getContents(); | |
| 357 | if (!canUseDebugH(Contents)) | |
| 306 | ArrayRef<uint8_t> contents = sec->getContents(); | |
| 307 | if (!canUseDebugH(contents)) | |
| 358 | 308 | return None; |
| 359 | return Contents; | |
| 309 | return contents; | |
| 360 | 310 | } |
| 361 | 311 | |
| 362 | 312 | static ArrayRef<GloballyHashedType> |
| 363 | getHashesFromDebugH(ArrayRef<uint8_t> DebugH) { | |
| 364 | assert(canUseDebugH(DebugH)); | |
| 313 | getHashesFromDebugH(ArrayRef<uint8_t> debugH) { | |
| 314 | assert(canUseDebugH(debugH)); | |
| 365 | 315 | |
| 366 | DebugH = DebugH.drop_front(sizeof(object::debug_h_header)); | |
| 367 | uint32_t Count = DebugH.size() / sizeof(GloballyHashedType); | |
| 368 | return {reinterpret_cast<const GloballyHashedType *>(DebugH.data()), Count}; | |
| 316 | debugH = debugH.drop_front(sizeof(object::debug_h_header)); | |
| 317 | uint32_t count = debugH.size() / sizeof(GloballyHashedType); | |
| 318 | return {reinterpret_cast<const GloballyHashedType *>(debugH.data()), count}; | |
| 369 | 319 | } |
| 370 | 320 | |
| 371 | static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder, | |
| 372 | TypeCollection &TypeTable) { | |
| 321 | static void addTypeInfo(pdb::TpiStreamBuilder &tpiBuilder, | |
| 322 | TypeCollection &typeTable) { | |
| 373 | 323 | // Start the TPI or IPI stream header. |
| 374 | TpiBuilder.setVersionHeader(pdb::PdbTpiV80); | |
| 324 | tpiBuilder.setVersionHeader(pdb::PdbTpiV80); | |
| 375 | 325 | |
| 376 | 326 | // Flatten the in memory type table and hash each type. |
| 377 | TypeTable.ForEachRecord([&](TypeIndex TI, const CVType &Type) { | |
| 378 | auto Hash = pdb::hashTypeRecord(Type); | |
| 379 | if (auto E = Hash.takeError()) | |
| 327 | typeTable.ForEachRecord([&](TypeIndex ti, const CVType &type) { | |
| 328 | auto hash = pdb::hashTypeRecord(type); | |
| 329 | if (auto e = hash.takeError()) | |
| 380 | 330 | fatal("type hashing error"); |
| 381 | TpiBuilder.addTypeRecord(Type.RecordData, *Hash); | |
| 331 | tpiBuilder.addTypeRecord(type.RecordData, *hash); | |
| 382 | 332 | }); |
| 383 | 333 | } |
| 384 | 334 | |
| 385 | // OBJs usually start their symbol stream with a S_OBJNAME record. This record | |
| 386 | // also contains the signature/key of the current PCH session. The signature | |
| 387 | // must be same for all objects which depend on the precompiled object. | |
| 388 | // Recompiling the precompiled headers will generate a new PCH key and thus | |
| 389 | // invalidate all the dependent objects. | |
| 390 | static uint32_t extractPCHSignature(ObjFile *File) { | |
| 391 | auto DbgIt = find_if(File->getDebugChunks(), [](SectionChunk *C) { | |
| 392 | return C->getSectionName() == ".debug$S"; | |
| 393 | }); | |
| 394 | if (!DbgIt) | |
| 395 | return 0; | |
| 396 | ||
| 397 | ArrayRef<uint8_t> Contents = | |
| 398 | consumeDebugMagic((*DbgIt)->getContents(), ".debug$S"); | |
| 399 | DebugSubsectionArray Subsections; | |
| 400 | BinaryStreamReader Reader(Contents, support::little); | |
| 401 | ExitOnErr(Reader.readArray(Subsections, Contents.size())); | |
| 402 | ||
| 403 | for (const DebugSubsectionRecord &SS : Subsections) { | |
| 404 | if (SS.kind() != DebugSubsectionKind::Symbols) | |
| 405 | continue; | |
| 406 | ||
| 407 | // If it's there, the S_OBJNAME record shall come first in the stream. | |
| 408 | Expected<CVSymbol> Sym = readSymbolFromStream(SS.getRecordData(), 0); | |
| 409 | if (!Sym) { | |
| 410 | consumeError(Sym.takeError()); | |
| 411 | continue; | |
| 412 | } | |
| 413 | if (auto ObjName = SymbolDeserializer::deserializeAs<ObjNameSym>(Sym.get())) | |
| 414 | return ObjName->Signature; | |
| 415 | } | |
| 416 | return 0; | |
| 417 | } | |
| 418 | ||
| 419 | 335 | Expected<const CVIndexMap &> |
| 420 | PDBLinker::mergeDebugT(ObjFile *File, CVIndexMap *ObjectIndexMap) { | |
| 421 | ScopedTimer T(TypeMergingTimer); | |
| 336 | PDBLinker::mergeDebugT(ObjFile *file, CVIndexMap *objectIndexMap) { | |
| 337 | ScopedTimer t(typeMergingTimer); | |
| 422 | 338 | |
| 423 | bool IsPrecompiledHeader = false; | |
| 424 | ||
| 425 | ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T"); | |
| 426 | if (Data.empty()) { | |
| 427 | // Try again, Microsoft precompiled headers use .debug$P instead of | |
| 428 | // .debug$T | |
| 429 | Data = getDebugSection(File, ".debug$P"); | |
| 430 | IsPrecompiledHeader = true; | |
| 431 | } | |
| 432 | if (Data.empty()) | |
| 433 | return *ObjectIndexMap; // no debug info | |
| 339 | if (!file->debugTypesObj) | |
| 340 | return *objectIndexMap; // no Types stream | |
| 434 | 341 | |
| 435 | 342 | // Precompiled headers objects need to save the index map for further |
| 436 | 343 | // reference by other objects which use the precompiled headers. |
| 437 | if (IsPrecompiledHeader) { | |
| 438 | uint32_t PCHSignature = extractPCHSignature(File); | |
| 439 | if (PCHSignature == 0) | |
| 344 | if (file->debugTypesObj->kind == TpiSource::PCH) { | |
| 345 | uint32_t pchSignature = file->pchSignature.getValueOr(0); | |
| 346 | if (pchSignature == 0) | |
| 440 | 347 | fatal("No signature found for the precompiled headers OBJ (" + |
| 441 | File->getName() + ")"); | |
| 348 | file->getName() + ")"); | |
| 442 | 349 | |
| 443 | 350 | // When a precompiled headers object comes first on the command-line, we |
| 444 | 351 | // update the mapping here. Otherwise, if an object referencing the |
| 445 | 352 | // precompiled headers object comes first, the mapping is created in |
| 446 | 353 | // aquirePrecompObj(), thus we would skip this block. |
| 447 | if (!ObjectIndexMap->IsPrecompiledTypeMap) { | |
| 448 | auto R = registerPrecompiledHeaders(PCHSignature); | |
| 449 | if (R.second) | |
| 354 | if (!objectIndexMap->isPrecompiledTypeMap) { | |
| 355 | auto r = registerPrecompiledHeaders(pchSignature); | |
| 356 | if (r.second) | |
| 450 | 357 | fatal( |
| 451 | 358 | "A precompiled headers OBJ with the same signature was already " |
| 452 | 359 | "provided! (" + |
| 453 | File->getName() + ")"); | |
| 360 | file->getName() + ")"); | |
| 454 | 361 | |
| 455 | ObjectIndexMap = &R.first; | |
| 362 | objectIndexMap = &r.first; | |
| 456 | 363 | } |
| 457 | 364 | } |
| 458 | 365 | |
| 459 | BinaryByteStream Stream(Data, support::little); | |
| 460 | CVTypeArray Types; | |
| 461 | BinaryStreamReader Reader(Stream); | |
| 462 | if (auto EC = Reader.readArray(Types, Reader.getLength())) | |
| 463 | fatal("Reader::readArray failed: " + toString(std::move(EC))); | |
| 464 | ||
| 465 | auto FirstType = Types.begin(); | |
| 466 | if (FirstType == Types.end()) | |
| 467 | return *ObjectIndexMap; | |
| 468 | ||
| 469 | if (FirstType->kind() == LF_TYPESERVER2) { | |
| 366 | if (file->debugTypesObj->kind == TpiSource::UsingPDB) { | |
| 470 | 367 | // Look through type servers. If we've already seen this type server, |
| 471 | 368 | // don't merge any type information. |
| 472 | return maybeMergeTypeServerPDB(File, *FirstType); | |
| 473 | } else if (FirstType->kind() == LF_PRECOMP) { | |
| 369 | return maybeMergeTypeServerPDB(file); | |
| 370 | } | |
| 371 | ||
| 372 | CVTypeArray &types = *file->debugTypes; | |
| 373 | ||
| 374 | if (file->debugTypesObj->kind == TpiSource::UsingPCH) { | |
| 474 | 375 | // This object was compiled with /Yu, so process the corresponding |
| 475 | 376 | // precompiled headers object (/Yc) first. Some type indices in the current |
| 476 | 377 | // object are referencing data in the precompiled headers object, so we need |
| 477 | 378 | // both to be loaded. |
| 478 | auto E = mergeInPrecompHeaderObj(File, *FirstType, ObjectIndexMap); | |
| 479 | if (!E) | |
| 480 | return E.takeError(); | |
| 481 | ||
| 482 | // Drop LF_PRECOMP record from the input stream, as it needs to be replaced | |
| 483 | // with the precompiled headers object type stream. | |
| 484 | // Note that we can't just call Types.drop_front(), as we explicitly want to | |
| 485 | // rebase the stream. | |
| 486 | Types.setUnderlyingStream( | |
| 487 | Types.getUnderlyingStream().drop_front(FirstType->RecordData.size())); | |
| 379 | Error e = mergeInPrecompHeaderObj(file, objectIndexMap); | |
| 380 | if (e) | |
| 381 | return std::move(e); | |
| 382 | ||
| 383 | // Drop LF_PRECOMP record from the input stream, as it has been replaced | |
| 384 | // with the precompiled headers Type stream in the mergeInPrecompHeaderObj() | |
| 385 | // call above. Note that we can't just call Types.drop_front(), as we | |
| 386 | // explicitly want to rebase the stream. | |
| 387 | CVTypeArray::Iterator firstType = types.begin(); | |
| 388 | types.setUnderlyingStream( | |
| 389 | types.getUnderlyingStream().drop_front(firstType->RecordData.size())); | |
| 488 | 390 | } |
| 489 | 391 | |
| 490 | 392 | // Fill in the temporary, caller-provided ObjectIndexMap. |
| 491 | if (Config->DebugGHashes) { | |
| 492 | ArrayRef<GloballyHashedType> Hashes; | |
| 493 | std::vector<GloballyHashedType> OwnedHashes; | |
| 494 | if (Optional<ArrayRef<uint8_t>> DebugH = getDebugH(File)) | |
| 495 | Hashes = getHashesFromDebugH(*DebugH); | |
| 393 | if (config->debugGHashes) { | |
| 394 | ArrayRef<GloballyHashedType> hashes; | |
| 395 | std::vector<GloballyHashedType> ownedHashes; | |
| 396 | if (Optional<ArrayRef<uint8_t>> debugH = getDebugH(file)) | |
| 397 | hashes = getHashesFromDebugH(*debugH); | |
| 496 | 398 | else { |
| 497 | OwnedHashes = GloballyHashedType::hashTypes(Types); | |
| 498 | Hashes = OwnedHashes; | |
| 399 | ownedHashes = GloballyHashedType::hashTypes(types); | |
| 400 | hashes = ownedHashes; | |
| 499 | 401 | } |
| 500 | 402 | |
| 501 | if (auto Err = mergeTypeAndIdRecords(GlobalIDTable, GlobalTypeTable, | |
| 502 | ObjectIndexMap->TPIMap, Types, Hashes, | |
| 503 | File->PCHSignature)) | |
| 403 | if (auto err = mergeTypeAndIdRecords( | |
| 404 | tMerger.globalIDTable, tMerger.globalTypeTable, | |
| 405 | objectIndexMap->tpiMap, types, hashes, file->pchSignature)) | |
| 504 | 406 | fatal("codeview::mergeTypeAndIdRecords failed: " + |
| 505 | toString(std::move(Err))); | |
| 407 | toString(std::move(err))); | |
| 506 | 408 | } else { |
| 507 | if (auto Err = | |
| 508 | mergeTypeAndIdRecords(IDTable, TypeTable, ObjectIndexMap->TPIMap, | |
| 509 | Types, File->PCHSignature)) | |
| 409 | if (auto err = mergeTypeAndIdRecords(tMerger.iDTable, tMerger.typeTable, | |
| 410 | objectIndexMap->tpiMap, types, | |
| 411 | file->pchSignature)) | |
| 510 | 412 | fatal("codeview::mergeTypeAndIdRecords failed: " + |
| 511 | toString(std::move(Err))); | |
| 413 | toString(std::move(err))); | |
| 512 | 414 | } |
| 513 | return *ObjectIndexMap; | |
| 415 | return *objectIndexMap; | |
| 514 | 416 | } |
| 515 | 417 | |
| 516 | static Expected<std::unique_ptr<pdb::NativeSession>> | |
| 517 | tryToLoadPDB(const codeview::GUID &GuidFromObj, StringRef TSPath) { | |
| 518 | // Ensure the file exists before anything else. We want to return ENOENT, | |
| 519 | // "file not found", even if the path points to a removable device (in which | |
| 520 | // case the return message would be EAGAIN, "resource unavailable try again") | |
| 521 | if (!llvm::sys::fs::exists(TSPath)) | |
| 522 | return errorCodeToError(std::error_code(ENOENT, std::generic_category())); | |
| 523 | ||
| 524 | ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = MemoryBuffer::getFile( | |
| 525 | TSPath, /*FileSize=*/-1, /*RequiresNullTerminator=*/false); | |
| 526 | if (!MBOrErr) | |
| 527 | return errorCodeToError(MBOrErr.getError()); | |
| 528 | ||
| 529 | std::unique_ptr<pdb::IPDBSession> ThisSession; | |
| 530 | if (auto EC = pdb::NativeSession::createFromPdb( | |
| 531 | MemoryBuffer::getMemBuffer(Driver->takeBuffer(std::move(*MBOrErr)), | |
| 532 | /*RequiresNullTerminator=*/false), | |
| 533 | ThisSession)) | |
| 534 | return std::move(EC); | |
| 535 | ||
| 536 | std::unique_ptr<pdb::NativeSession> NS( | |
| 537 | static_cast<pdb::NativeSession *>(ThisSession.release())); | |
| 538 | pdb::PDBFile &File = NS->getPDBFile(); | |
| 539 | auto ExpectedInfo = File.getPDBInfoStream(); | |
| 540 | // All PDB Files should have an Info stream. | |
| 541 | if (!ExpectedInfo) | |
| 542 | return ExpectedInfo.takeError(); | |
| 543 | ||
| 544 | // Just because a file with a matching name was found and it was an actual | |
| 545 | // PDB file doesn't mean it matches. For it to match the InfoStream's GUID | |
| 546 | // must match the GUID specified in the TypeServer2 record. | |
| 547 | if (ExpectedInfo->getGuid() != GuidFromObj) | |
| 548 | return make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date); | |
| 549 | ||
| 550 | return std::move(NS); | |
| 551 | } | |
| 418 | Expected<const CVIndexMap &> PDBLinker::maybeMergeTypeServerPDB(ObjFile *file) { | |
| 419 | Expected<llvm::pdb::NativeSession *> pdbSession = findTypeServerSource(file); | |
| 420 | if (!pdbSession) | |
| 421 | return pdbSession.takeError(); | |
| 552 | 422 | |
| 553 | Expected<const CVIndexMap &> | |
| 554 | PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, const CVType &FirstType) { | |
| 555 | TypeServer2Record TS; | |
| 556 | if (auto EC = | |
| 557 | TypeDeserializer::deserializeAs(const_cast<CVType &>(FirstType), TS)) | |
| 558 | fatal("error reading record: " + toString(std::move(EC))); | |
| 559 | ||
| 560 | const codeview::GUID &TSId = TS.getGuid(); | |
| 561 | StringRef TSPath = TS.getName(); | |
| 562 | ||
| 563 | // First, check if the PDB has previously failed to load. | |
| 564 | auto PrevErr = MissingTypeServerPDBs.find(TSId); | |
| 565 | if (PrevErr != MissingTypeServerPDBs.end()) | |
| 566 | return createFileError( | |
| 567 | TSPath, | |
| 568 | make_error<StringError>(PrevErr->second, inconvertibleErrorCode())); | |
| 423 | pdb::PDBFile &pdbFile = pdbSession.get()->getPDBFile(); | |
| 424 | pdb::InfoStream &info = cantFail(pdbFile.getPDBInfoStream()); | |
| 569 | 425 | |
| 570 | // Second, check if we already loaded a PDB with this GUID. Return the type | |
| 571 | // index mapping if we have it. | |
| 572 | auto Insertion = TypeServerIndexMappings.insert({TSId, CVIndexMap()}); | |
| 573 | CVIndexMap &IndexMap = Insertion.first->second; | |
| 574 | if (!Insertion.second) | |
| 575 | return IndexMap; | |
| 426 | auto it = typeServerIndexMappings.emplace(info.getGuid(), CVIndexMap()); | |
| 427 | CVIndexMap &indexMap = it.first->second; | |
| 428 | if (!it.second) | |
| 429 | return indexMap; // already merged | |
| 576 | 430 | |
| 577 | 431 | // Mark this map as a type server map. |
| 578 | IndexMap.IsTypeServerMap = true; | |
| 579 | ||
| 580 | // Check for a PDB at: | |
| 581 | // 1. The given file path | |
| 582 | // 2. Next to the object file or archive file | |
| 583 | auto ExpectedSession = handleExpected( | |
| 584 | tryToLoadPDB(TSId, TSPath), | |
| 585 | [&]() { | |
| 586 | StringRef LocalPath = | |
| 587 | !File->ParentName.empty() ? File->ParentName : File->getName(); | |
| 588 | SmallString<128> Path = sys::path::parent_path(LocalPath); | |
| 589 | // Currently, type server PDBs are only created by cl, which only runs | |
| 590 | // on Windows, so we can assume type server paths are Windows style. | |
| 591 | sys::path::append( | |
| 592 | Path, sys::path::filename(TSPath, sys::path::Style::windows)); | |
| 593 | return tryToLoadPDB(TSId, Path); | |
| 594 | }, | |
| 595 | [&](std::unique_ptr<ECError> EC) -> Error { | |
| 596 | auto SysErr = EC->convertToErrorCode(); | |
| 597 | // Only re-try loading if the previous error was "No such file or | |
| 598 | // directory" | |
| 599 | if (SysErr.category() == std::generic_category() && | |
| 600 | SysErr.value() == ENOENT) | |
| 601 | return Error::success(); | |
| 602 | return Error(std::move(EC)); | |
| 603 | }); | |
| 604 | ||
| 605 | if (auto E = ExpectedSession.takeError()) { | |
| 606 | TypeServerIndexMappings.erase(TSId); | |
| 607 | ||
| 608 | // Flatten the error to a string, for later display, if the error occurs | |
| 609 | // again on the same PDB. | |
| 610 | std::string ErrMsg; | |
| 611 | raw_string_ostream S(ErrMsg); | |
| 612 | S << E; | |
| 613 | MissingTypeServerPDBs.emplace(TSId, S.str()); | |
| 614 | ||
| 615 | return createFileError(TSPath, std::move(E)); | |
| 432 | indexMap.isTypeServerMap = true; | |
| 433 | ||
| 434 | Expected<pdb::TpiStream &> expectedTpi = pdbFile.getPDBTpiStream(); | |
| 435 | if (auto e = expectedTpi.takeError()) | |
| 436 | fatal("Type server does not have TPI stream: " + toString(std::move(e))); | |
| 437 | pdb::TpiStream *maybeIpi = nullptr; | |
| 438 | if (pdbFile.hasPDBIpiStream()) { | |
| 439 | Expected<pdb::TpiStream &> expectedIpi = pdbFile.getPDBIpiStream(); | |
| 440 | if (auto e = expectedIpi.takeError()) | |
| 441 | fatal("Error getting type server IPI stream: " + toString(std::move(e))); | |
| 442 | maybeIpi = &*expectedIpi; | |
| 616 | 443 | } |
| 617 | 444 | |
| 618 | pdb::NativeSession *Session = ExpectedSession->get(); | |
| 619 | ||
| 620 | // Keep a strong reference to this PDB, so that it's safe to hold pointers | |
| 621 | // into the file. | |
| 622 | LoadedPDBs.push_back(std::move(*ExpectedSession)); | |
| 623 | ||
| 624 | auto ExpectedTpi = Session->getPDBFile().getPDBTpiStream(); | |
| 625 | if (auto E = ExpectedTpi.takeError()) | |
| 626 | fatal("Type server does not have TPI stream: " + toString(std::move(E))); | |
| 627 | auto ExpectedIpi = Session->getPDBFile().getPDBIpiStream(); | |
| 628 | if (auto E = ExpectedIpi.takeError()) | |
| 629 | fatal("Type server does not have TPI stream: " + toString(std::move(E))); | |
| 630 | ||
| 631 | if (Config->DebugGHashes) { | |
| 445 | if (config->debugGHashes) { | |
| 632 | 446 | // PDBs do not actually store global hashes, so when merging a type server |
| 633 | 447 | // PDB we have to synthesize global hashes. To do this, we first synthesize |
| 634 | 448 | // global hashes for the TPI stream, since it is independent, then we |
| 635 | 449 | // synthesize hashes for the IPI stream, using the hashes for the TPI stream |
| 636 | 450 | // as inputs. |
| 637 | auto TpiHashes = GloballyHashedType::hashTypes(ExpectedTpi->typeArray()); | |
| 638 | auto IpiHashes = | |
| 639 | GloballyHashedType::hashIds(ExpectedIpi->typeArray(), TpiHashes); | |
| 640 | ||
| 641 | Optional<uint32_t> EndPrecomp; | |
| 451 | auto tpiHashes = GloballyHashedType::hashTypes(expectedTpi->typeArray()); | |
| 452 | Optional<uint32_t> endPrecomp; | |
| 642 | 453 | // Merge TPI first, because the IPI stream will reference type indices. |
| 643 | if (auto Err = mergeTypeRecords(GlobalTypeTable, IndexMap.TPIMap, | |
| 644 | ExpectedTpi->typeArray(), TpiHashes, EndPrecomp)) | |
| 645 | fatal("codeview::mergeTypeRecords failed: " + toString(std::move(Err))); | |
| 454 | if (auto err = | |
| 455 | mergeTypeRecords(tMerger.globalTypeTable, indexMap.tpiMap, | |
| 456 | expectedTpi->typeArray(), tpiHashes, endPrecomp)) | |
| 457 | fatal("codeview::mergeTypeRecords failed: " + toString(std::move(err))); | |
| 646 | 458 | |
| 647 | 459 | // Merge IPI. |
| 648 | if (auto Err = | |
| 649 | mergeIdRecords(GlobalIDTable, IndexMap.TPIMap, IndexMap.IPIMap, | |
| 650 | ExpectedIpi->typeArray(), IpiHashes)) | |
| 651 | fatal("codeview::mergeIdRecords failed: " + toString(std::move(Err))); | |
| 460 | if (maybeIpi) { | |
| 461 | auto ipiHashes = | |
| 462 | GloballyHashedType::hashIds(maybeIpi->typeArray(), tpiHashes); | |
| 463 | if (auto err = | |
| 464 | mergeIdRecords(tMerger.globalIDTable, indexMap.tpiMap, | |
| 465 | indexMap.ipiMap, maybeIpi->typeArray(), ipiHashes)) | |
| 466 | fatal("codeview::mergeIdRecords failed: " + toString(std::move(err))); | |
| 467 | } | |
| 652 | 468 | } else { |
| 653 | 469 | // Merge TPI first, because the IPI stream will reference type indices. |
| 654 | if (auto Err = mergeTypeRecords(TypeTable, IndexMap.TPIMap, | |
| 655 | ExpectedTpi->typeArray())) | |
| 656 | fatal("codeview::mergeTypeRecords failed: " + toString(std::move(Err))); | |
| 470 | if (auto err = mergeTypeRecords(tMerger.typeTable, indexMap.tpiMap, | |
| 471 | expectedTpi->typeArray())) | |
| 472 | fatal("codeview::mergeTypeRecords failed: " + toString(std::move(err))); | |
| 657 | 473 | |
| 658 | 474 | // Merge IPI. |
| 659 | if (auto Err = mergeIdRecords(IDTable, IndexMap.TPIMap, IndexMap.IPIMap, | |
| 660 | ExpectedIpi->typeArray())) | |
| 661 | fatal("codeview::mergeIdRecords failed: " + toString(std::move(Err))); | |
| 475 | if (maybeIpi) { | |
| 476 | if (auto err = mergeIdRecords(tMerger.iDTable, indexMap.tpiMap, | |
| 477 | indexMap.ipiMap, maybeIpi->typeArray())) | |
| 478 | fatal("codeview::mergeIdRecords failed: " + toString(std::move(err))); | |
| 479 | } | |
| 662 | 480 | } |
| 663 | 481 | |
| 664 | return IndexMap; | |
| 482 | return indexMap; | |
| 665 | 483 | } |
| 666 | 484 | |
| 667 | Expected<const CVIndexMap &> | |
| 668 | PDBLinker::mergeInPrecompHeaderObj(ObjFile *File, const CVType &FirstType, | |
| 669 | CVIndexMap *ObjectIndexMap) { | |
| 670 | PrecompRecord Precomp; | |
| 671 | if (auto EC = TypeDeserializer::deserializeAs(const_cast<CVType &>(FirstType), | |
| 672 | Precomp)) | |
| 673 | fatal("error reading record: " + toString(std::move(EC))); | |
| 485 | Error PDBLinker::mergeInPrecompHeaderObj(ObjFile *file, | |
| 486 | CVIndexMap *objectIndexMap) { | |
| 487 | const PrecompRecord &precomp = | |
| 488 | retrieveDependencyInfo<PrecompRecord>(file->debugTypesObj); | |
| 674 | 489 | |
| 675 | auto E = aquirePrecompObj(File, Precomp); | |
| 676 | if (!E) | |
| 677 | return E.takeError(); | |
| 490 | Expected<const CVIndexMap &> e = aquirePrecompObj(file); | |
| 491 | if (!e) | |
| 492 | return e.takeError(); | |
| 678 | 493 | |
| 679 | const CVIndexMap &PrecompIndexMap = *E; | |
| 680 | assert(PrecompIndexMap.IsPrecompiledTypeMap); | |
| 494 | const CVIndexMap &precompIndexMap = *e; | |
| 495 | assert(precompIndexMap.isPrecompiledTypeMap); | |
| 681 | 496 | |
| 682 | if (PrecompIndexMap.TPIMap.empty()) | |
| 683 | return PrecompIndexMap; | |
| 497 | if (precompIndexMap.tpiMap.empty()) | |
| 498 | return Error::success(); | |
| 684 | 499 | |
| 685 | assert(Precomp.getStartTypeIndex() == TypeIndex::FirstNonSimpleIndex); | |
| 686 | assert(Precomp.getTypesCount() <= PrecompIndexMap.TPIMap.size()); | |
| 500 | assert(precomp.getStartTypeIndex() == TypeIndex::FirstNonSimpleIndex); | |
| 501 | assert(precomp.getTypesCount() <= precompIndexMap.tpiMap.size()); | |
| 687 | 502 | // Use the previously remapped index map from the precompiled headers. |
| 688 | ObjectIndexMap->TPIMap.append(PrecompIndexMap.TPIMap.begin(), | |
| 689 | PrecompIndexMap.TPIMap.begin() + | |
| 690 | Precomp.getTypesCount()); | |
| 691 | return *ObjectIndexMap; | |
| 503 | objectIndexMap->tpiMap.append(precompIndexMap.tpiMap.begin(), | |
| 504 | precompIndexMap.tpiMap.begin() + | |
| 505 | precomp.getTypesCount()); | |
| 506 | return Error::success(); | |
| 692 | 507 | } |
| 693 | 508 | |
| 694 | 509 | static bool equals_path(StringRef path1, StringRef path2) { |
| ... | ... | @@ -700,101 +515,103 @@ static bool equals_path(StringRef path1, StringRef path2) { |
| 700 | 515 | } |
| 701 | 516 | |
| 702 | 517 | // Find by name an OBJ provided on the command line |
| 703 | static ObjFile *findObjByName(StringRef FileNameOnly) { | |
| 704 | SmallString<128> CurrentPath; | |
| 518 | static ObjFile *findObjByName(StringRef fileNameOnly) { | |
| 519 | SmallString<128> currentPath; | |
| 705 | 520 | |
| 706 | for (ObjFile *F : ObjFile::Instances) { | |
| 707 | StringRef CurrentFileName = sys::path::filename(F->getName()); | |
| 521 | for (ObjFile *f : ObjFile::instances) { | |
| 522 | StringRef currentFileName = sys::path::filename(f->getName()); | |
| 708 | 523 | |
| 709 | 524 | // Compare based solely on the file name (link.exe behavior) |
| 710 | if (equals_path(CurrentFileName, FileNameOnly)) | |
| 711 | return F; | |
| 525 | if (equals_path(currentFileName, fileNameOnly)) | |
| 526 | return f; | |
| 712 | 527 | } |
| 713 | 528 | return nullptr; |
| 714 | 529 | } |
| 715 | 530 | |
| 716 | 531 | std::pair<CVIndexMap &, bool /*already there*/> |
| 717 | PDBLinker::registerPrecompiledHeaders(uint32_t Signature) { | |
| 718 | auto Insertion = PrecompTypeIndexMappings.insert({Signature, CVIndexMap()}); | |
| 719 | CVIndexMap &IndexMap = Insertion.first->second; | |
| 720 | if (!Insertion.second) | |
| 721 | return {IndexMap, true}; | |
| 532 | PDBLinker::registerPrecompiledHeaders(uint32_t signature) { | |
| 533 | auto insertion = precompTypeIndexMappings.insert({signature, CVIndexMap()}); | |
| 534 | CVIndexMap &indexMap = insertion.first->second; | |
| 535 | if (!insertion.second) | |
| 536 | return {indexMap, true}; | |
| 722 | 537 | // Mark this map as a precompiled types map. |
| 723 | IndexMap.IsPrecompiledTypeMap = true; | |
| 724 | return {IndexMap, false}; | |
| 538 | indexMap.isPrecompiledTypeMap = true; | |
| 539 | return {indexMap, false}; | |
| 725 | 540 | } |
| 726 | 541 | |
| 727 | Expected<const CVIndexMap &> | |
| 728 | PDBLinker::aquirePrecompObj(ObjFile *File, PrecompRecord Precomp) { | |
| 542 | Expected<const CVIndexMap &> PDBLinker::aquirePrecompObj(ObjFile *file) { | |
| 543 | const PrecompRecord &precomp = | |
| 544 | retrieveDependencyInfo<PrecompRecord>(file->debugTypesObj); | |
| 545 | ||
| 729 | 546 | // First, check if we already loaded the precompiled headers object with this |
| 730 | 547 | // signature. Return the type index mapping if we've already seen it. |
| 731 | auto R = registerPrecompiledHeaders(Precomp.getSignature()); | |
| 732 | if (R.second) | |
| 733 | return R.first; | |
| 548 | auto r = registerPrecompiledHeaders(precomp.getSignature()); | |
| 549 | if (r.second) | |
| 550 | return r.first; | |
| 734 | 551 | |
| 735 | CVIndexMap &IndexMap = R.first; | |
| 552 | CVIndexMap &indexMap = r.first; | |
| 736 | 553 | |
| 737 | 554 | // Cross-compile warning: given that Clang doesn't generate LF_PRECOMP |
| 738 | 555 | // records, we assume the OBJ comes from a Windows build of cl.exe. Thusly, |
| 739 | 556 | // the paths embedded in the OBJs are in the Windows format. |
| 740 | SmallString<128> PrecompFileName = sys::path::filename( | |
| 741 | Precomp.getPrecompFilePath(), sys::path::Style::windows); | |
| 557 | SmallString<128> precompFileName = sys::path::filename( | |
| 558 | precomp.getPrecompFilePath(), sys::path::Style::windows); | |
| 742 | 559 | |
| 743 | 560 | // link.exe requires that a precompiled headers object must always be provided |
| 744 | 561 | // on the command-line, even if that's not necessary. |
| 745 | auto PrecompFile = findObjByName(PrecompFileName); | |
| 746 | if (!PrecompFile) | |
| 562 | auto precompFile = findObjByName(precompFileName); | |
| 563 | if (!precompFile) | |
| 747 | 564 | return createFileError( |
| 748 | PrecompFileName.str(), | |
| 565 | precompFileName.str(), | |
| 749 | 566 | make_error<pdb::PDBError>(pdb::pdb_error_code::external_cmdline_ref)); |
| 750 | 567 | |
| 751 | addObjFile(PrecompFile, &IndexMap); | |
| 568 | addObjFile(precompFile, &indexMap); | |
| 752 | 569 | |
| 753 | if (!PrecompFile->PCHSignature) | |
| 754 | fatal(PrecompFile->getName() + " is not a precompiled headers object"); | |
| 570 | if (!precompFile->pchSignature) | |
| 571 | fatal(precompFile->getName() + " is not a precompiled headers object"); | |
| 755 | 572 | |
| 756 | if (Precomp.getSignature() != PrecompFile->PCHSignature.getValueOr(0)) | |
| 573 | if (precomp.getSignature() != precompFile->pchSignature.getValueOr(0)) | |
| 757 | 574 | return createFileError( |
| 758 | Precomp.getPrecompFilePath().str(), | |
| 575 | precomp.getPrecompFilePath().str(), | |
| 759 | 576 | make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date)); |
| 760 | 577 | |
| 761 | return IndexMap; | |
| 578 | return indexMap; | |
| 762 | 579 | } |
| 763 | 580 | |
| 764 | static bool remapTypeIndex(TypeIndex &TI, ArrayRef<TypeIndex> TypeIndexMap) { | |
| 765 | if (TI.isSimple()) | |
| 581 | static bool remapTypeIndex(TypeIndex &ti, ArrayRef<TypeIndex> typeIndexMap) { | |
| 582 | if (ti.isSimple()) | |
| 766 | 583 | return true; |
| 767 | if (TI.toArrayIndex() >= TypeIndexMap.size()) | |
| 584 | if (ti.toArrayIndex() >= typeIndexMap.size()) | |
| 768 | 585 | return false; |
| 769 | TI = TypeIndexMap[TI.toArrayIndex()]; | |
| 586 | ti = typeIndexMap[ti.toArrayIndex()]; | |
| 770 | 587 | return true; |
| 771 | 588 | } |
| 772 | 589 | |
| 773 | static void remapTypesInSymbolRecord(ObjFile *File, SymbolKind SymKind, | |
| 774 | MutableArrayRef<uint8_t> RecordBytes, | |
| 775 | const CVIndexMap &IndexMap, | |
| 776 | ArrayRef<TiReference> TypeRefs) { | |
| 777 | MutableArrayRef<uint8_t> Contents = | |
| 778 | RecordBytes.drop_front(sizeof(RecordPrefix)); | |
| 779 | for (const TiReference &Ref : TypeRefs) { | |
| 780 | unsigned ByteSize = Ref.Count * sizeof(TypeIndex); | |
| 781 | if (Contents.size() < Ref.Offset + ByteSize) | |
| 590 | static void remapTypesInSymbolRecord(ObjFile *file, SymbolKind symKind, | |
| 591 | MutableArrayRef<uint8_t> recordBytes, | |
| 592 | const CVIndexMap &indexMap, | |
| 593 | ArrayRef<TiReference> typeRefs) { | |
| 594 | MutableArrayRef<uint8_t> contents = | |
| 595 | recordBytes.drop_front(sizeof(RecordPrefix)); | |
| 596 | for (const TiReference &ref : typeRefs) { | |
| 597 | unsigned byteSize = ref.Count * sizeof(TypeIndex); | |
| 598 | if (contents.size() < ref.Offset + byteSize) | |
| 782 | 599 | fatal("symbol record too short"); |
| 783 | 600 | |
| 784 | 601 | // This can be an item index or a type index. Choose the appropriate map. |
| 785 | ArrayRef<TypeIndex> TypeOrItemMap = IndexMap.TPIMap; | |
| 786 | bool IsItemIndex = Ref.Kind == TiRefKind::IndexRef; | |
| 787 | if (IsItemIndex && IndexMap.IsTypeServerMap) | |
| 788 | TypeOrItemMap = IndexMap.IPIMap; | |
| 789 | ||
| 790 | MutableArrayRef<TypeIndex> TIs( | |
| 791 | reinterpret_cast<TypeIndex *>(Contents.data() + Ref.Offset), Ref.Count); | |
| 792 | for (TypeIndex &TI : TIs) { | |
| 793 | if (!remapTypeIndex(TI, TypeOrItemMap)) { | |
| 794 | log("ignoring symbol record of kind 0x" + utohexstr(SymKind) + " in " + | |
| 795 | File->getName() + " with bad " + (IsItemIndex ? "item" : "type") + | |
| 796 | " index 0x" + utohexstr(TI.getIndex())); | |
| 797 | TI = TypeIndex(SimpleTypeKind::NotTranslated); | |
| 602 | ArrayRef<TypeIndex> typeOrItemMap = indexMap.tpiMap; | |
| 603 | bool isItemIndex = ref.Kind == TiRefKind::IndexRef; | |
| 604 | if (isItemIndex && indexMap.isTypeServerMap) | |
| 605 | typeOrItemMap = indexMap.ipiMap; | |
| 606 | ||
| 607 | MutableArrayRef<TypeIndex> tIs( | |
| 608 | reinterpret_cast<TypeIndex *>(contents.data() + ref.Offset), ref.Count); | |
| 609 | for (TypeIndex &ti : tIs) { | |
| 610 | if (!remapTypeIndex(ti, typeOrItemMap)) { | |
| 611 | log("ignoring symbol record of kind 0x" + utohexstr(symKind) + " in " + | |
| 612 | file->getName() + " with bad " + (isItemIndex ? "item" : "type") + | |
| 613 | " index 0x" + utohexstr(ti.getIndex())); | |
| 614 | ti = TypeIndex(SimpleTypeKind::NotTranslated); | |
| 798 | 615 | continue; |
| 799 | 616 | } |
| 800 | 617 | } |
| ... | ... | @@ -802,26 +619,26 @@ static void remapTypesInSymbolRecord(ObjFile *File, SymbolKind SymKind, |
| 802 | 619 | } |
| 803 | 620 | |
| 804 | 621 | static void |
| 805 | recordStringTableReferenceAtOffset(MutableArrayRef<uint8_t> Contents, | |
| 806 | uint32_t Offset, | |
| 807 | std::vector<ulittle32_t *> &StrTableRefs) { | |
| 808 | Contents = | |
| 809 | Contents.drop_front(Offset).take_front(sizeof(support::ulittle32_t)); | |
| 810 | ulittle32_t *Index = reinterpret_cast<ulittle32_t *>(Contents.data()); | |
| 811 | StrTableRefs.push_back(Index); | |
| 622 | recordStringTableReferenceAtOffset(MutableArrayRef<uint8_t> contents, | |
| 623 | uint32_t offset, | |
| 624 | std::vector<ulittle32_t *> &strTableRefs) { | |
| 625 | contents = | |
| 626 | contents.drop_front(offset).take_front(sizeof(support::ulittle32_t)); | |
| 627 | ulittle32_t *index = reinterpret_cast<ulittle32_t *>(contents.data()); | |
| 628 | strTableRefs.push_back(index); | |
| 812 | 629 | } |
| 813 | 630 | |
| 814 | 631 | static void |
| 815 | recordStringTableReferences(SymbolKind Kind, MutableArrayRef<uint8_t> Contents, | |
| 816 | std::vector<ulittle32_t *> &StrTableRefs) { | |
| 632 | recordStringTableReferences(SymbolKind kind, MutableArrayRef<uint8_t> contents, | |
| 633 | std::vector<ulittle32_t *> &strTableRefs) { | |
| 817 | 634 | // For now we only handle S_FILESTATIC, but we may need the same logic for |
| 818 | 635 | // S_DEFRANGE and S_DEFRANGE_SUBFIELD. However, I cannot seem to generate any |
| 819 | 636 | // PDBs that contain these types of records, so because of the uncertainty |
| 820 | 637 | // they are omitted here until we can prove that it's necessary. |
| 821 | switch (Kind) { | |
| 638 | switch (kind) { | |
| 822 | 639 | case SymbolKind::S_FILESTATIC: |
| 823 | 640 | // FileStaticSym::ModFileOffset |
| 824 | recordStringTableReferenceAtOffset(Contents, 8, StrTableRefs); | |
| 641 | recordStringTableReferenceAtOffset(contents, 8, strTableRefs); | |
| 825 | 642 | break; |
| 826 | 643 | case SymbolKind::S_DEFRANGE: |
| 827 | 644 | case SymbolKind::S_DEFRANGE_SUBFIELD: |
| ... | ... | @@ -833,21 +650,21 @@ recordStringTableReferences(SymbolKind Kind, MutableArrayRef<uint8_t> Contents, |
| 833 | 650 | } |
| 834 | 651 | } |
| 835 | 652 | |
| 836 | static SymbolKind symbolKind(ArrayRef<uint8_t> RecordData) { | |
| 837 | const RecordPrefix *Prefix = | |
| 838 | reinterpret_cast<const RecordPrefix *>(RecordData.data()); | |
| 839 | return static_cast<SymbolKind>(uint16_t(Prefix->RecordKind)); | |
| 653 | static SymbolKind symbolKind(ArrayRef<uint8_t> recordData) { | |
| 654 | const RecordPrefix *prefix = | |
| 655 | reinterpret_cast<const RecordPrefix *>(recordData.data()); | |
| 656 | return static_cast<SymbolKind>(uint16_t(prefix->RecordKind)); | |
| 840 | 657 | } |
| 841 | 658 | |
| 842 | 659 | /// MSVC translates S_PROC_ID_END to S_END, and S_[LG]PROC32_ID to S_[LG]PROC32 |
| 843 | static void translateIdSymbols(MutableArrayRef<uint8_t> &RecordData, | |
| 844 | TypeCollection &IDTable) { | |
| 845 | RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(RecordData.data()); | |
| 660 | static void translateIdSymbols(MutableArrayRef<uint8_t> &recordData, | |
| 661 | TypeCollection &iDTable) { | |
| 662 | RecordPrefix *prefix = reinterpret_cast<RecordPrefix *>(recordData.data()); | |
| 846 | 663 | |
| 847 | SymbolKind Kind = symbolKind(RecordData); | |
| 664 | SymbolKind kind = symbolKind(recordData); | |
| 848 | 665 | |
| 849 | if (Kind == SymbolKind::S_PROC_ID_END) { | |
| 850 | Prefix->RecordKind = SymbolKind::S_END; | |
| 666 | if (kind == SymbolKind::S_PROC_ID_END) { | |
| 667 | prefix->RecordKind = SymbolKind::S_END; | |
| 851 | 668 | return; |
| 852 | 669 | } |
| 853 | 670 | |
| ... | ... | @@ -856,89 +673,89 @@ static void translateIdSymbols(MutableArrayRef<uint8_t> &RecordData, |
| 856 | 673 | // to the PDB file's ID stream index space, but we need to convert this to a |
| 857 | 674 | // symbol that refers to the type stream index space. So we remap again from |
| 858 | 675 | // ID index space to type index space. |
| 859 | if (Kind == SymbolKind::S_GPROC32_ID || Kind == SymbolKind::S_LPROC32_ID) { | |
| 860 | SmallVector<TiReference, 1> Refs; | |
| 861 | auto Content = RecordData.drop_front(sizeof(RecordPrefix)); | |
| 862 | CVSymbol Sym(Kind, RecordData); | |
| 863 | discoverTypeIndicesInSymbol(Sym, Refs); | |
| 864 | assert(Refs.size() == 1); | |
| 865 | assert(Refs.front().Count == 1); | |
| 866 | ||
| 867 | TypeIndex *TI = | |
| 868 | reinterpret_cast<TypeIndex *>(Content.data() + Refs[0].Offset); | |
| 869 | // `TI` is the index of a FuncIdRecord or MemberFuncIdRecord which lives in | |
| 676 | if (kind == SymbolKind::S_GPROC32_ID || kind == SymbolKind::S_LPROC32_ID) { | |
| 677 | SmallVector<TiReference, 1> refs; | |
| 678 | auto content = recordData.drop_front(sizeof(RecordPrefix)); | |
| 679 | CVSymbol sym(recordData); | |
| 680 | discoverTypeIndicesInSymbol(sym, refs); | |
| 681 | assert(refs.size() == 1); | |
| 682 | assert(refs.front().Count == 1); | |
| 683 | ||
| 684 | TypeIndex *ti = | |
| 685 | reinterpret_cast<TypeIndex *>(content.data() + refs[0].Offset); | |
| 686 | // `ti` is the index of a FuncIdRecord or MemberFuncIdRecord which lives in | |
| 870 | 687 | // the IPI stream, whose `FunctionType` member refers to the TPI stream. |
| 871 | 688 | // Note that LF_FUNC_ID and LF_MEMFUNC_ID have the same record layout, and |
| 872 | 689 | // in both cases we just need the second type index. |
| 873 | if (!TI->isSimple() && !TI->isNoneType()) { | |
| 874 | CVType FuncIdData = IDTable.getType(*TI); | |
| 875 | SmallVector<TypeIndex, 2> Indices; | |
| 876 | discoverTypeIndices(FuncIdData, Indices); | |
| 877 | assert(Indices.size() == 2); | |
| 878 | *TI = Indices[1]; | |
| 690 | if (!ti->isSimple() && !ti->isNoneType()) { | |
| 691 | CVType funcIdData = iDTable.getType(*ti); | |
| 692 | SmallVector<TypeIndex, 2> indices; | |
| 693 | discoverTypeIndices(funcIdData, indices); | |
| 694 | assert(indices.size() == 2); | |
| 695 | *ti = indices[1]; | |
| 879 | 696 | } |
| 880 | 697 | |
| 881 | Kind = (Kind == SymbolKind::S_GPROC32_ID) ? SymbolKind::S_GPROC32 | |
| 698 | kind = (kind == SymbolKind::S_GPROC32_ID) ? SymbolKind::S_GPROC32 | |
| 882 | 699 | : SymbolKind::S_LPROC32; |
| 883 | Prefix->RecordKind = uint16_t(Kind); | |
| 700 | prefix->RecordKind = uint16_t(kind); | |
| 884 | 701 | } |
| 885 | 702 | } |
| 886 | 703 | |
| 887 | 704 | /// Copy the symbol record. In a PDB, symbol records must be 4 byte aligned. |
| 888 | 705 | /// The object file may not be aligned. |
| 889 | 706 | static MutableArrayRef<uint8_t> |
| 890 | copyAndAlignSymbol(const CVSymbol &Sym, MutableArrayRef<uint8_t> &AlignedMem) { | |
| 891 | size_t Size = alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb)); | |
| 892 | assert(Size >= 4 && "record too short"); | |
| 893 | assert(Size <= MaxRecordLength && "record too long"); | |
| 894 | assert(AlignedMem.size() >= Size && "didn't preallocate enough"); | |
| 707 | copyAndAlignSymbol(const CVSymbol &sym, MutableArrayRef<uint8_t> &alignedMem) { | |
| 708 | size_t size = alignTo(sym.length(), alignOf(CodeViewContainer::Pdb)); | |
| 709 | assert(size >= 4 && "record too short"); | |
| 710 | assert(size <= MaxRecordLength && "record too long"); | |
| 711 | assert(alignedMem.size() >= size && "didn't preallocate enough"); | |
| 895 | 712 | |
| 896 | 713 | // Copy the symbol record and zero out any padding bytes. |
| 897 | MutableArrayRef<uint8_t> NewData = AlignedMem.take_front(Size); | |
| 898 | AlignedMem = AlignedMem.drop_front(Size); | |
| 899 | memcpy(NewData.data(), Sym.data().data(), Sym.length()); | |
| 900 | memset(NewData.data() + Sym.length(), 0, Size - Sym.length()); | |
| 714 | MutableArrayRef<uint8_t> newData = alignedMem.take_front(size); | |
| 715 | alignedMem = alignedMem.drop_front(size); | |
| 716 | memcpy(newData.data(), sym.data().data(), sym.length()); | |
| 717 | memset(newData.data() + sym.length(), 0, size - sym.length()); | |
| 901 | 718 | |
| 902 | 719 | // Update the record prefix length. It should point to the beginning of the |
| 903 | 720 | // next record. |
| 904 | auto *Prefix = reinterpret_cast<RecordPrefix *>(NewData.data()); | |
| 905 | Prefix->RecordLen = Size - 2; | |
| 906 | return NewData; | |
| 721 | auto *prefix = reinterpret_cast<RecordPrefix *>(newData.data()); | |
| 722 | prefix->RecordLen = size - 2; | |
| 723 | return newData; | |
| 907 | 724 | } |
| 908 | 725 | |
| 909 | 726 | struct ScopeRecord { |
| 910 | ulittle32_t PtrParent; | |
| 911 | ulittle32_t PtrEnd; | |
| 727 | ulittle32_t ptrParent; | |
| 728 | ulittle32_t ptrEnd; | |
| 912 | 729 | }; |
| 913 | 730 | |
| 914 | 731 | struct SymbolScope { |
| 915 | ScopeRecord *OpeningRecord; | |
| 916 | uint32_t ScopeOffset; | |
| 732 | ScopeRecord *openingRecord; | |
| 733 | uint32_t scopeOffset; | |
| 917 | 734 | }; |
| 918 | 735 | |
| 919 | static void scopeStackOpen(SmallVectorImpl<SymbolScope> &Stack, | |
| 920 | uint32_t CurOffset, CVSymbol &Sym) { | |
| 921 | assert(symbolOpensScope(Sym.kind())); | |
| 922 | SymbolScope S; | |
| 923 | S.ScopeOffset = CurOffset; | |
| 924 | S.OpeningRecord = const_cast<ScopeRecord *>( | |
| 925 | reinterpret_cast<const ScopeRecord *>(Sym.content().data())); | |
| 926 | S.OpeningRecord->PtrParent = Stack.empty() ? 0 : Stack.back().ScopeOffset; | |
| 927 | Stack.push_back(S); | |
| 736 | static void scopeStackOpen(SmallVectorImpl<SymbolScope> &stack, | |
| 737 | uint32_t curOffset, CVSymbol &sym) { | |
| 738 | assert(symbolOpensScope(sym.kind())); | |
| 739 | SymbolScope s; | |
| 740 | s.scopeOffset = curOffset; | |
| 741 | s.openingRecord = const_cast<ScopeRecord *>( | |
| 742 | reinterpret_cast<const ScopeRecord *>(sym.content().data())); | |
| 743 | s.openingRecord->ptrParent = stack.empty() ? 0 : stack.back().scopeOffset; | |
| 744 | stack.push_back(s); | |
| 928 | 745 | } |
| 929 | 746 | |
| 930 | static void scopeStackClose(SmallVectorImpl<SymbolScope> &Stack, | |
| 931 | uint32_t CurOffset, ObjFile *File) { | |
| 932 | if (Stack.empty()) { | |
| 933 | warn("symbol scopes are not balanced in " + File->getName()); | |
| 747 | static void scopeStackClose(SmallVectorImpl<SymbolScope> &stack, | |
| 748 | uint32_t curOffset, InputFile *file) { | |
| 749 | if (stack.empty()) { | |
| 750 | warn("symbol scopes are not balanced in " + file->getName()); | |
| 934 | 751 | return; |
| 935 | 752 | } |
| 936 | SymbolScope S = Stack.pop_back_val(); | |
| 937 | S.OpeningRecord->PtrEnd = CurOffset; | |
| 753 | SymbolScope s = stack.pop_back_val(); | |
| 754 | s.openingRecord->ptrEnd = curOffset; | |
| 938 | 755 | } |
| 939 | 756 | |
| 940 | static bool symbolGoesInModuleStream(const CVSymbol &Sym, bool IsGlobalScope) { | |
| 941 | switch (Sym.kind()) { | |
| 757 | static bool symbolGoesInModuleStream(const CVSymbol &sym, bool isGlobalScope) { | |
| 758 | switch (sym.kind()) { | |
| 942 | 759 | case SymbolKind::S_GDATA32: |
| 943 | 760 | case SymbolKind::S_CONSTANT: |
| 944 | 761 | // We really should not be seeing S_PROCREF and S_LPROCREF in the first place |
| ... | ... | @@ -950,7 +767,7 @@ static bool symbolGoesInModuleStream(const CVSymbol &Sym, bool IsGlobalScope) { |
| 950 | 767 | return false; |
| 951 | 768 | // S_UDT records go in the module stream if it is not a global S_UDT. |
| 952 | 769 | case SymbolKind::S_UDT: |
| 953 | return !IsGlobalScope; | |
| 770 | return !isGlobalScope; | |
| 954 | 771 | // S_GDATA32 does not go in the module stream, but S_LDATA32 does. |
| 955 | 772 | case SymbolKind::S_LDATA32: |
| 956 | 773 | default: |
| ... | ... | @@ -958,8 +775,8 @@ static bool symbolGoesInModuleStream(const CVSymbol &Sym, bool IsGlobalScope) { |
| 958 | 775 | } |
| 959 | 776 | } |
| 960 | 777 | |
| 961 | static bool symbolGoesInGlobalsStream(const CVSymbol &Sym, bool IsGlobalScope) { | |
| 962 | switch (Sym.kind()) { | |
| 778 | static bool symbolGoesInGlobalsStream(const CVSymbol &sym, bool isGlobalScope) { | |
| 779 | switch (sym.kind()) { | |
| 963 | 780 | case SymbolKind::S_CONSTANT: |
| 964 | 781 | case SymbolKind::S_GDATA32: |
| 965 | 782 | // S_LDATA32 goes in both the module stream and the globals stream. |
| ... | ... | @@ -974,36 +791,36 @@ static bool symbolGoesInGlobalsStream(const CVSymbol &Sym, bool IsGlobalScope) { |
| 974 | 791 | return true; |
| 975 | 792 | // S_UDT records go in the globals stream if it is a global S_UDT. |
| 976 | 793 | case SymbolKind::S_UDT: |
| 977 | return IsGlobalScope; | |
| 794 | return isGlobalScope; | |
| 978 | 795 | default: |
| 979 | 796 | return false; |
| 980 | 797 | } |
| 981 | 798 | } |
| 982 | 799 | |
| 983 | static void addGlobalSymbol(pdb::GSIStreamBuilder &Builder, uint16_t ModIndex, | |
| 984 | unsigned SymOffset, const CVSymbol &Sym) { | |
| 985 | switch (Sym.kind()) { | |
| 800 | static void addGlobalSymbol(pdb::GSIStreamBuilder &builder, uint16_t modIndex, | |
| 801 | unsigned symOffset, const CVSymbol &sym) { | |
| 802 | switch (sym.kind()) { | |
| 986 | 803 | case SymbolKind::S_CONSTANT: |
| 987 | 804 | case SymbolKind::S_UDT: |
| 988 | 805 | case SymbolKind::S_GDATA32: |
| 989 | 806 | case SymbolKind::S_LDATA32: |
| 990 | 807 | case SymbolKind::S_PROCREF: |
| 991 | 808 | case SymbolKind::S_LPROCREF: |
| 992 | Builder.addGlobalSymbol(Sym); | |
| 809 | builder.addGlobalSymbol(sym); | |
| 993 | 810 | break; |
| 994 | 811 | case SymbolKind::S_GPROC32: |
| 995 | 812 | case SymbolKind::S_LPROC32: { |
| 996 | SymbolRecordKind K = SymbolRecordKind::ProcRefSym; | |
| 997 | if (Sym.kind() == SymbolKind::S_LPROC32) | |
| 998 | K = SymbolRecordKind::LocalProcRef; | |
| 999 | ProcRefSym PS(K); | |
| 1000 | PS.Module = ModIndex; | |
| 813 | SymbolRecordKind k = SymbolRecordKind::ProcRefSym; | |
| 814 | if (sym.kind() == SymbolKind::S_LPROC32) | |
| 815 | k = SymbolRecordKind::LocalProcRef; | |
| 816 | ProcRefSym ps(k); | |
| 817 | ps.Module = modIndex; | |
| 1001 | 818 | // For some reason, MSVC seems to add one to this value. |
| 1002 | ++PS.Module; | |
| 1003 | PS.Name = getSymbolName(Sym); | |
| 1004 | PS.SumName = 0; | |
| 1005 | PS.SymOffset = SymOffset; | |
| 1006 | Builder.addGlobalSymbol(PS); | |
| 819 | ++ps.Module; | |
| 820 | ps.Name = getSymbolName(sym); | |
| 821 | ps.SumName = 0; | |
| 822 | ps.SymOffset = symOffset; | |
| 823 | builder.addGlobalSymbol(ps); | |
| 1007 | 824 | break; |
| 1008 | 825 | } |
| 1009 | 826 | default: |
| ... | ... | @@ -1011,229 +828,304 @@ static void addGlobalSymbol(pdb::GSIStreamBuilder &Builder, uint16_t ModIndex, |
| 1011 | 828 | } |
| 1012 | 829 | } |
| 1013 | 830 | |
| 1014 | void PDBLinker::mergeSymbolRecords(ObjFile *File, const CVIndexMap &IndexMap, | |
| 1015 | std::vector<ulittle32_t *> &StringTableRefs, | |
| 1016 | BinaryStreamRef SymData) { | |
| 1017 | ArrayRef<uint8_t> SymsBuffer; | |
| 1018 | cantFail(SymData.readBytes(0, SymData.getLength(), SymsBuffer)); | |
| 1019 | SmallVector<SymbolScope, 4> Scopes; | |
| 831 | void PDBLinker::mergeSymbolRecords(ObjFile *file, const CVIndexMap &indexMap, | |
| 832 | std::vector<ulittle32_t *> &stringTableRefs, | |
| 833 | BinaryStreamRef symData) { | |
| 834 | ArrayRef<uint8_t> symsBuffer; | |
| 835 | cantFail(symData.readBytes(0, symData.getLength(), symsBuffer)); | |
| 836 | SmallVector<SymbolScope, 4> scopes; | |
| 1020 | 837 | |
| 1021 | 838 | // Iterate every symbol to check if any need to be realigned, and if so, how |
| 1022 | 839 | // much space we need to allocate for them. |
| 1023 | bool NeedsRealignment = false; | |
| 1024 | unsigned TotalRealignedSize = 0; | |
| 1025 | auto EC = forEachCodeViewRecord<CVSymbol>( | |
| 1026 | SymsBuffer, [&](CVSymbol Sym) -> llvm::Error { | |
| 1027 | unsigned RealignedSize = | |
| 1028 | alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb)); | |
| 1029 | NeedsRealignment |= RealignedSize != Sym.length(); | |
| 1030 | TotalRealignedSize += RealignedSize; | |
| 840 | bool needsRealignment = false; | |
| 841 | unsigned totalRealignedSize = 0; | |
| 842 | auto ec = forEachCodeViewRecord<CVSymbol>( | |
| 843 | symsBuffer, [&](CVSymbol sym) -> llvm::Error { | |
| 844 | unsigned realignedSize = | |
| 845 | alignTo(sym.length(), alignOf(CodeViewContainer::Pdb)); | |
| 846 | needsRealignment |= realignedSize != sym.length(); | |
| 847 | totalRealignedSize += realignedSize; | |
| 1031 | 848 | return Error::success(); |
| 1032 | 849 | }); |
| 1033 | 850 | |
| 1034 | 851 | // If any of the symbol record lengths was corrupt, ignore them all, warn |
| 1035 | 852 | // about it, and move on. |
| 1036 | if (EC) { | |
| 1037 | warn("corrupt symbol records in " + File->getName()); | |
| 1038 | consumeError(std::move(EC)); | |
| 853 | if (ec) { | |
| 854 | warn("corrupt symbol records in " + file->getName()); | |
| 855 | consumeError(std::move(ec)); | |
| 1039 | 856 | return; |
| 1040 | 857 | } |
| 1041 | 858 | |
| 1042 | 859 | // If any symbol needed realignment, allocate enough contiguous memory for |
| 1043 | 860 | // them all. Typically symbol subsections are small enough that this will not |
| 1044 | 861 | // cause fragmentation. |
| 1045 | MutableArrayRef<uint8_t> AlignedSymbolMem; | |
| 1046 | if (NeedsRealignment) { | |
| 1047 | void *AlignedData = | |
| 1048 | Alloc.Allocate(TotalRealignedSize, alignOf(CodeViewContainer::Pdb)); | |
| 1049 | AlignedSymbolMem = makeMutableArrayRef( | |
| 1050 | reinterpret_cast<uint8_t *>(AlignedData), TotalRealignedSize); | |
| 862 | MutableArrayRef<uint8_t> alignedSymbolMem; | |
| 863 | if (needsRealignment) { | |
| 864 | void *alignedData = | |
| 865 | alloc.Allocate(totalRealignedSize, alignOf(CodeViewContainer::Pdb)); | |
| 866 | alignedSymbolMem = makeMutableArrayRef( | |
| 867 | reinterpret_cast<uint8_t *>(alignedData), totalRealignedSize); | |
| 1051 | 868 | } |
| 1052 | 869 | |
| 1053 | 870 | // Iterate again, this time doing the real work. |
| 1054 | unsigned CurSymOffset = File->ModuleDBI->getNextSymbolOffset(); | |
| 1055 | ArrayRef<uint8_t> BulkSymbols; | |
| 871 | unsigned curSymOffset = file->moduleDBI->getNextSymbolOffset(); | |
| 872 | ArrayRef<uint8_t> bulkSymbols; | |
| 1056 | 873 | cantFail(forEachCodeViewRecord<CVSymbol>( |
| 1057 | SymsBuffer, [&](CVSymbol Sym) -> llvm::Error { | |
| 874 | symsBuffer, [&](CVSymbol sym) -> llvm::Error { | |
| 1058 | 875 | // Align the record if required. |
| 1059 | MutableArrayRef<uint8_t> RecordBytes; | |
| 1060 | if (NeedsRealignment) { | |
| 1061 | RecordBytes = copyAndAlignSymbol(Sym, AlignedSymbolMem); | |
| 1062 | Sym = CVSymbol(Sym.kind(), RecordBytes); | |
| 876 | MutableArrayRef<uint8_t> recordBytes; | |
| 877 | if (needsRealignment) { | |
| 878 | recordBytes = copyAndAlignSymbol(sym, alignedSymbolMem); | |
| 879 | sym = CVSymbol(recordBytes); | |
| 1063 | 880 | } else { |
| 1064 | 881 | // Otherwise, we can actually mutate the symbol directly, since we |
| 1065 | 882 | // copied it to apply relocations. |
| 1066 | RecordBytes = makeMutableArrayRef( | |
| 1067 | const_cast<uint8_t *>(Sym.data().data()), Sym.length()); | |
| 883 | recordBytes = makeMutableArrayRef( | |
| 884 | const_cast<uint8_t *>(sym.data().data()), sym.length()); | |
| 1068 | 885 | } |
| 1069 | 886 | |
| 1070 | 887 | // Discover type index references in the record. Skip it if we don't |
| 1071 | 888 | // know where they are. |
| 1072 | SmallVector<TiReference, 32> TypeRefs; | |
| 1073 | if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) { | |
| 889 | SmallVector<TiReference, 32> typeRefs; | |
| 890 | if (!discoverTypeIndicesInSymbol(sym, typeRefs)) { | |
| 1074 | 891 | log("ignoring unknown symbol record with kind 0x" + |
| 1075 | utohexstr(Sym.kind())); | |
| 892 | utohexstr(sym.kind())); | |
| 1076 | 893 | return Error::success(); |
| 1077 | 894 | } |
| 1078 | 895 | |
| 1079 | 896 | // Re-map all the type index references. |
| 1080 | remapTypesInSymbolRecord(File, Sym.kind(), RecordBytes, IndexMap, | |
| 1081 | TypeRefs); | |
| 897 | remapTypesInSymbolRecord(file, sym.kind(), recordBytes, indexMap, | |
| 898 | typeRefs); | |
| 1082 | 899 | |
| 1083 | 900 | // An object file may have S_xxx_ID symbols, but these get converted to |
| 1084 | 901 | // "real" symbols in a PDB. |
| 1085 | translateIdSymbols(RecordBytes, getIDTable()); | |
| 1086 | Sym = CVSymbol(symbolKind(RecordBytes), RecordBytes); | |
| 902 | translateIdSymbols(recordBytes, tMerger.getIDTable()); | |
| 903 | sym = CVSymbol(recordBytes); | |
| 1087 | 904 | |
| 1088 | 905 | // If this record refers to an offset in the object file's string table, |
| 1089 | 906 | // add that item to the global PDB string table and re-write the index. |
| 1090 | recordStringTableReferences(Sym.kind(), RecordBytes, StringTableRefs); | |
| 907 | recordStringTableReferences(sym.kind(), recordBytes, stringTableRefs); | |
| 1091 | 908 | |
| 1092 | 909 | // Fill in "Parent" and "End" fields by maintaining a stack of scopes. |
| 1093 | if (symbolOpensScope(Sym.kind())) | |
| 1094 | scopeStackOpen(Scopes, CurSymOffset, Sym); | |
| 1095 | else if (symbolEndsScope(Sym.kind())) | |
| 1096 | scopeStackClose(Scopes, CurSymOffset, File); | |
| 910 | if (symbolOpensScope(sym.kind())) | |
| 911 | scopeStackOpen(scopes, curSymOffset, sym); | |
| 912 | else if (symbolEndsScope(sym.kind())) | |
| 913 | scopeStackClose(scopes, curSymOffset, file); | |
| 1097 | 914 | |
| 1098 | 915 | // Add the symbol to the globals stream if necessary. Do this before |
| 1099 | 916 | // adding the symbol to the module since we may need to get the next |
| 1100 | 917 | // symbol offset, and writing to the module's symbol stream will update |
| 1101 | 918 | // that offset. |
| 1102 | if (symbolGoesInGlobalsStream(Sym, Scopes.empty())) | |
| 1103 | addGlobalSymbol(Builder.getGsiBuilder(), | |
| 1104 | File->ModuleDBI->getModuleIndex(), CurSymOffset, Sym); | |
| 919 | if (symbolGoesInGlobalsStream(sym, scopes.empty())) { | |
| 920 | addGlobalSymbol(builder.getGsiBuilder(), | |
| 921 | file->moduleDBI->getModuleIndex(), curSymOffset, sym); | |
| 922 | ++globalSymbols; | |
| 923 | } | |
| 1105 | 924 | |
| 1106 | if (symbolGoesInModuleStream(Sym, Scopes.empty())) { | |
| 925 | if (symbolGoesInModuleStream(sym, scopes.empty())) { | |
| 1107 | 926 | // Add symbols to the module in bulk. If this symbol is contiguous |
| 1108 | 927 | // with the previous run of symbols to add, combine the ranges. If |
| 1109 | 928 | // not, close the previous range of symbols and start a new one. |
| 1110 | if (Sym.data().data() == BulkSymbols.end()) { | |
| 1111 | BulkSymbols = makeArrayRef(BulkSymbols.data(), | |
| 1112 | BulkSymbols.size() + Sym.length()); | |
| 929 | if (sym.data().data() == bulkSymbols.end()) { | |
| 930 | bulkSymbols = makeArrayRef(bulkSymbols.data(), | |
| 931 | bulkSymbols.size() + sym.length()); | |
| 1113 | 932 | } else { |
| 1114 | File->ModuleDBI->addSymbolsInBulk(BulkSymbols); | |
| 1115 | BulkSymbols = RecordBytes; | |
| 933 | file->moduleDBI->addSymbolsInBulk(bulkSymbols); | |
| 934 | bulkSymbols = recordBytes; | |
| 1116 | 935 | } |
| 1117 | CurSymOffset += Sym.length(); | |
| 936 | curSymOffset += sym.length(); | |
| 937 | ++moduleSymbols; | |
| 1118 | 938 | } |
| 1119 | 939 | return Error::success(); |
| 1120 | 940 | })); |
| 1121 | 941 | |
| 1122 | 942 | // Add any remaining symbols we've accumulated. |
| 1123 | File->ModuleDBI->addSymbolsInBulk(BulkSymbols); | |
| 943 | file->moduleDBI->addSymbolsInBulk(bulkSymbols); | |
| 1124 | 944 | } |
| 1125 | 945 | |
| 1126 | 946 | // Allocate memory for a .debug$S / .debug$F section and relocate it. |
| 1127 | static ArrayRef<uint8_t> relocateDebugChunk(BumpPtrAllocator &Alloc, | |
| 1128 | SectionChunk &DebugChunk) { | |
| 1129 | uint8_t *Buffer = Alloc.Allocate<uint8_t>(DebugChunk.getSize()); | |
| 1130 | assert(DebugChunk.OutputSectionOff == 0 && | |
| 947 | static ArrayRef<uint8_t> relocateDebugChunk(BumpPtrAllocator &alloc, | |
| 948 | SectionChunk &debugChunk) { | |
| 949 | uint8_t *buffer = alloc.Allocate<uint8_t>(debugChunk.getSize()); | |
| 950 | assert(debugChunk.getOutputSectionIdx() == 0 && | |
| 1131 | 951 | "debug sections should not be in output sections"); |
| 1132 | DebugChunk.readRelocTargets(); | |
| 1133 | DebugChunk.writeTo(Buffer); | |
| 1134 | return makeArrayRef(Buffer, DebugChunk.getSize()); | |
| 952 | debugChunk.writeTo(buffer); | |
| 953 | return makeArrayRef(buffer, debugChunk.getSize()); | |
| 1135 | 954 | } |
| 1136 | 955 | |
| 1137 | static pdb::SectionContrib createSectionContrib(const Chunk *C, uint32_t Modi) { | |
| 1138 | OutputSection *OS = C->getOutputSection(); | |
| 1139 | pdb::SectionContrib SC; | |
| 1140 | memset(&SC, 0, sizeof(SC)); | |
| 1141 | SC.ISect = OS->SectionIndex; | |
| 1142 | SC.Off = C->getRVA() - OS->getRVA(); | |
| 1143 | SC.Size = C->getSize(); | |
| 1144 | if (auto *SecChunk = dyn_cast<SectionChunk>(C)) { | |
| 1145 | SC.Characteristics = SecChunk->Header->Characteristics; | |
| 1146 | SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex(); | |
| 1147 | ArrayRef<uint8_t> Contents = SecChunk->getContents(); | |
| 1148 | JamCRC CRC(0); | |
| 1149 | ArrayRef<char> CharContents = makeArrayRef( | |
| 1150 | reinterpret_cast<const char *>(Contents.data()), Contents.size()); | |
| 1151 | CRC.update(CharContents); | |
| 1152 | SC.DataCrc = CRC.getCRC(); | |
| 956 | static pdb::SectionContrib createSectionContrib(const Chunk *c, uint32_t modi) { | |
| 957 | OutputSection *os = c ? c->getOutputSection() : nullptr; | |
| 958 | pdb::SectionContrib sc; | |
| 959 | memset(&sc, 0, sizeof(sc)); | |
| 960 | sc.ISect = os ? os->sectionIndex : llvm::pdb::kInvalidStreamIndex; | |
| 961 | sc.Off = c && os ? c->getRVA() - os->getRVA() : 0; | |
| 962 | sc.Size = c ? c->getSize() : -1; | |
| 963 | if (auto *secChunk = dyn_cast_or_null<SectionChunk>(c)) { | |
| 964 | sc.Characteristics = secChunk->header->Characteristics; | |
| 965 | sc.Imod = secChunk->file->moduleDBI->getModuleIndex(); | |
| 966 | ArrayRef<uint8_t> contents = secChunk->getContents(); | |
| 967 | JamCRC crc(0); | |
| 968 | ArrayRef<char> charContents = makeArrayRef( | |
| 969 | reinterpret_cast<const char *>(contents.data()), contents.size()); | |
| 970 | crc.update(charContents); | |
| 971 | sc.DataCrc = crc.getCRC(); | |
| 1153 | 972 | } else { |
| 1154 | SC.Characteristics = OS->Header.Characteristics; | |
| 1155 | // FIXME: When we start creating DBI for import libraries, use those here. | |
| 1156 | SC.Imod = Modi; | |
| 973 | sc.Characteristics = os ? os->header.Characteristics : 0; | |
| 974 | sc.Imod = modi; | |
| 1157 | 975 | } |
| 1158 | SC.RelocCrc = 0; // FIXME | |
| 976 | sc.RelocCrc = 0; // FIXME | |
| 1159 | 977 | |
| 1160 | return SC; | |
| 978 | return sc; | |
| 1161 | 979 | } |
| 1162 | 980 | |
| 1163 | 981 | static uint32_t |
| 1164 | translateStringTableIndex(uint32_t ObjIndex, | |
| 1165 | const DebugStringTableSubsectionRef &ObjStrTable, | |
| 1166 | DebugStringTableSubsection &PdbStrTable) { | |
| 1167 | auto ExpectedString = ObjStrTable.getString(ObjIndex); | |
| 1168 | if (!ExpectedString) { | |
| 982 | translateStringTableIndex(uint32_t objIndex, | |
| 983 | const DebugStringTableSubsectionRef &objStrTable, | |
| 984 | DebugStringTableSubsection &pdbStrTable) { | |
| 985 | auto expectedString = objStrTable.getString(objIndex); | |
| 986 | if (!expectedString) { | |
| 1169 | 987 | warn("Invalid string table reference"); |
| 1170 | consumeError(ExpectedString.takeError()); | |
| 988 | consumeError(expectedString.takeError()); | |
| 1171 | 989 | return 0; |
| 1172 | 990 | } |
| 1173 | 991 | |
| 1174 | return PdbStrTable.insert(*ExpectedString); | |
| 992 | return pdbStrTable.insert(*expectedString); | |
| 1175 | 993 | } |
| 1176 | 994 | |
| 1177 | void DebugSHandler::handleDebugS(lld::coff::SectionChunk &DebugS) { | |
| 1178 | DebugSubsectionArray Subsections; | |
| 995 | void DebugSHandler::handleDebugS(lld::coff::SectionChunk &debugS) { | |
| 996 | DebugSubsectionArray subsections; | |
| 997 | ||
| 998 | ArrayRef<uint8_t> relocatedDebugContents = SectionChunk::consumeDebugMagic( | |
| 999 | relocateDebugChunk(linker.alloc, debugS), debugS.getSectionName()); | |
| 1179 | 1000 | |
| 1180 | ArrayRef<uint8_t> RelocatedDebugContents = consumeDebugMagic( | |
| 1181 | relocateDebugChunk(Linker.Alloc, DebugS), DebugS.getSectionName()); | |
| 1001 | BinaryStreamReader reader(relocatedDebugContents, support::little); | |
| 1002 | exitOnErr(reader.readArray(subsections, relocatedDebugContents.size())); | |
| 1182 | 1003 | |
| 1183 | BinaryStreamReader Reader(RelocatedDebugContents, support::little); | |
| 1184 | ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size())); | |
| 1004 | for (const DebugSubsectionRecord &ss : subsections) { | |
| 1005 | // Ignore subsections with the 'ignore' bit. Some versions of the Visual C++ | |
| 1006 | // runtime have subsections with this bit set. | |
| 1007 | if (uint32_t(ss.kind()) & codeview::SubsectionIgnoreFlag) | |
| 1008 | continue; | |
| 1185 | 1009 | |
| 1186 | for (const DebugSubsectionRecord &SS : Subsections) { | |
| 1187 | switch (SS.kind()) { | |
| 1010 | switch (ss.kind()) { | |
| 1188 | 1011 | case DebugSubsectionKind::StringTable: { |
| 1189 | assert(!CVStrTab.valid() && | |
| 1012 | assert(!cVStrTab.valid() && | |
| 1190 | 1013 | "Encountered multiple string table subsections!"); |
| 1191 | ExitOnErr(CVStrTab.initialize(SS.getRecordData())); | |
| 1014 | exitOnErr(cVStrTab.initialize(ss.getRecordData())); | |
| 1192 | 1015 | break; |
| 1193 | 1016 | } |
| 1194 | 1017 | case DebugSubsectionKind::FileChecksums: |
| 1195 | assert(!Checksums.valid() && | |
| 1018 | assert(!checksums.valid() && | |
| 1196 | 1019 | "Encountered multiple checksum subsections!"); |
| 1197 | ExitOnErr(Checksums.initialize(SS.getRecordData())); | |
| 1020 | exitOnErr(checksums.initialize(ss.getRecordData())); | |
| 1198 | 1021 | break; |
| 1199 | 1022 | case DebugSubsectionKind::Lines: |
| 1200 | 1023 | // We can add the relocated line table directly to the PDB without |
| 1201 | 1024 | // modification because the file checksum offsets will stay the same. |
| 1202 | File.ModuleDBI->addDebugSubsection(SS); | |
| 1025 | file.moduleDBI->addDebugSubsection(ss); | |
| 1026 | break; | |
| 1027 | case DebugSubsectionKind::InlineeLines: | |
| 1028 | assert(!inlineeLines.valid() && | |
| 1029 | "Encountered multiple inlinee lines subsections!"); | |
| 1030 | exitOnErr(inlineeLines.initialize(ss.getRecordData())); | |
| 1203 | 1031 | break; |
| 1204 | 1032 | case DebugSubsectionKind::FrameData: { |
| 1205 | 1033 | // We need to re-write string table indices here, so save off all |
| 1206 | 1034 | // frame data subsections until we've processed the entire list of |
| 1207 | 1035 | // subsections so that we can be sure we have the string table. |
| 1208 | DebugFrameDataSubsectionRef FDS; | |
| 1209 | ExitOnErr(FDS.initialize(SS.getRecordData())); | |
| 1210 | NewFpoFrames.push_back(std::move(FDS)); | |
| 1036 | DebugFrameDataSubsectionRef fds; | |
| 1037 | exitOnErr(fds.initialize(ss.getRecordData())); | |
| 1038 | newFpoFrames.push_back(std::move(fds)); | |
| 1211 | 1039 | break; |
| 1212 | 1040 | } |
| 1213 | 1041 | case DebugSubsectionKind::Symbols: { |
| 1214 | Linker.mergeSymbolRecords(&File, IndexMap, StringTableReferences, | |
| 1215 | SS.getRecordData()); | |
| 1042 | linker.mergeSymbolRecords(&file, indexMap, stringTableReferences, | |
| 1043 | ss.getRecordData()); | |
| 1216 | 1044 | break; |
| 1217 | 1045 | } |
| 1046 | ||
| 1047 | case DebugSubsectionKind::CrossScopeImports: | |
| 1048 | case DebugSubsectionKind::CrossScopeExports: | |
| 1049 | // These appear to relate to cross-module optimization, so we might use | |
| 1050 | // these for ThinLTO. | |
| 1051 | break; | |
| 1052 | ||
| 1053 | case DebugSubsectionKind::ILLines: | |
| 1054 | case DebugSubsectionKind::FuncMDTokenMap: | |
| 1055 | case DebugSubsectionKind::TypeMDTokenMap: | |
| 1056 | case DebugSubsectionKind::MergedAssemblyInput: | |
| 1057 | // These appear to relate to .Net assembly info. | |
| 1058 | break; | |
| 1059 | ||
| 1060 | case DebugSubsectionKind::CoffSymbolRVA: | |
| 1061 | // Unclear what this is for. | |
| 1062 | break; | |
| 1063 | ||
| 1218 | 1064 | default: |
| 1219 | // FIXME: Process the rest of the subsections. | |
| 1065 | warn("ignoring unknown debug$S subsection kind 0x" + | |
| 1066 | utohexstr(uint32_t(ss.kind())) + " in file " + toString(&file)); | |
| 1220 | 1067 | break; |
| 1221 | 1068 | } |
| 1222 | 1069 | } |
| 1223 | 1070 | } |
| 1224 | 1071 | |
| 1072 | static Expected<StringRef> | |
| 1073 | getFileName(const DebugStringTableSubsectionRef &strings, | |
| 1074 | const DebugChecksumsSubsectionRef &checksums, uint32_t fileID) { | |
| 1075 | auto iter = checksums.getArray().at(fileID); | |
| 1076 | if (iter == checksums.getArray().end()) | |
| 1077 | return make_error<CodeViewError>(cv_error_code::no_records); | |
| 1078 | uint32_t offset = iter->FileNameOffset; | |
| 1079 | return strings.getString(offset); | |
| 1080 | } | |
| 1081 | ||
| 1082 | std::shared_ptr<DebugInlineeLinesSubsection> | |
| 1083 | DebugSHandler::mergeInlineeLines(DebugChecksumsSubsection *newChecksums) { | |
| 1084 | auto newInlineeLines = std::make_shared<DebugInlineeLinesSubsection>( | |
| 1085 | *newChecksums, inlineeLines.hasExtraFiles()); | |
| 1086 | ||
| 1087 | for (const InlineeSourceLine &line : inlineeLines) { | |
| 1088 | TypeIndex inlinee = line.Header->Inlinee; | |
| 1089 | uint32_t fileID = line.Header->FileID; | |
| 1090 | uint32_t sourceLine = line.Header->SourceLineNum; | |
| 1091 | ||
| 1092 | ArrayRef<TypeIndex> typeOrItemMap = | |
| 1093 | indexMap.isTypeServerMap ? indexMap.ipiMap : indexMap.tpiMap; | |
| 1094 | if (!remapTypeIndex(inlinee, typeOrItemMap)) { | |
| 1095 | log("ignoring inlinee line record in " + file.getName() + | |
| 1096 | " with bad inlinee index 0x" + utohexstr(inlinee.getIndex())); | |
| 1097 | continue; | |
| 1098 | } | |
| 1099 | ||
| 1100 | SmallString<128> filename = | |
| 1101 | exitOnErr(getFileName(cVStrTab, checksums, fileID)); | |
| 1102 | pdbMakeAbsolute(filename); | |
| 1103 | newInlineeLines->addInlineSite(inlinee, filename, sourceLine); | |
| 1104 | ||
| 1105 | if (inlineeLines.hasExtraFiles()) { | |
| 1106 | for (uint32_t extraFileId : line.ExtraFiles) { | |
| 1107 | filename = exitOnErr(getFileName(cVStrTab, checksums, extraFileId)); | |
| 1108 | pdbMakeAbsolute(filename); | |
| 1109 | newInlineeLines->addExtraFile(filename); | |
| 1110 | } | |
| 1111 | } | |
| 1112 | } | |
| 1113 | ||
| 1114 | return newInlineeLines; | |
| 1115 | } | |
| 1116 | ||
| 1225 | 1117 | void DebugSHandler::finish() { |
| 1226 | pdb::DbiStreamBuilder &DbiBuilder = Linker.Builder.getDbiBuilder(); | |
| 1118 | pdb::DbiStreamBuilder &dbiBuilder = linker.builder.getDbiBuilder(); | |
| 1227 | 1119 | |
| 1228 | 1120 | // We should have seen all debug subsections across the entire object file now |
| 1229 | 1121 | // which means that if a StringTable subsection and Checksums subsection were |
| 1230 | 1122 | // present, now is the time to handle them. |
| 1231 | if (!CVStrTab.valid()) { | |
| 1232 | if (Checksums.valid()) | |
| 1123 | if (!cVStrTab.valid()) { | |
| 1124 | if (checksums.valid()) | |
| 1233 | 1125 | fatal(".debug$S sections with a checksums subsection must also contain a " |
| 1234 | 1126 | "string table subsection"); |
| 1235 | 1127 | |
| 1236 | if (!StringTableReferences.empty()) | |
| 1128 | if (!stringTableReferences.empty()) | |
| 1237 | 1129 | warn("No StringTable subsection was encountered, but there are string " |
| 1238 | 1130 | "table references"); |
| 1239 | 1131 | return; |
| ... | ... | @@ -1241,186 +1133,231 @@ void DebugSHandler::finish() { |
| 1241 | 1133 | |
| 1242 | 1134 | // Rewrite string table indices in the Fpo Data and symbol records to refer to |
| 1243 | 1135 | // the global PDB string table instead of the object file string table. |
| 1244 | for (DebugFrameDataSubsectionRef &FDS : NewFpoFrames) { | |
| 1245 | const ulittle32_t *Reloc = FDS.getRelocPtr(); | |
| 1246 | for (codeview::FrameData FD : FDS) { | |
| 1247 | FD.RvaStart += *Reloc; | |
| 1248 | FD.FrameFunc = | |
| 1249 | translateStringTableIndex(FD.FrameFunc, CVStrTab, Linker.PDBStrTab); | |
| 1250 | DbiBuilder.addNewFpoData(FD); | |
| 1136 | for (DebugFrameDataSubsectionRef &fds : newFpoFrames) { | |
| 1137 | const ulittle32_t *reloc = fds.getRelocPtr(); | |
| 1138 | for (codeview::FrameData fd : fds) { | |
| 1139 | fd.RvaStart += *reloc; | |
| 1140 | fd.FrameFunc = | |
| 1141 | translateStringTableIndex(fd.FrameFunc, cVStrTab, linker.pdbStrTab); | |
| 1142 | dbiBuilder.addNewFpoData(fd); | |
| 1251 | 1143 | } |
| 1252 | 1144 | } |
| 1253 | 1145 | |
| 1254 | for (ulittle32_t *Ref : StringTableReferences) | |
| 1255 | *Ref = translateStringTableIndex(*Ref, CVStrTab, Linker.PDBStrTab); | |
| 1146 | for (ulittle32_t *ref : stringTableReferences) | |
| 1147 | *ref = translateStringTableIndex(*ref, cVStrTab, linker.pdbStrTab); | |
| 1256 | 1148 | |
| 1257 | 1149 | // Make a new file checksum table that refers to offsets in the PDB-wide |
| 1258 | 1150 | // string table. Generally the string table subsection appears after the |
| 1259 | 1151 | // checksum table, so we have to do this after looping over all the |
| 1260 | 1152 | // subsections. |
| 1261 | auto NewChecksums = make_unique<DebugChecksumsSubsection>(Linker.PDBStrTab); | |
| 1262 | for (FileChecksumEntry &FC : Checksums) { | |
| 1263 | SmallString<128> FileName = | |
| 1264 | ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); | |
| 1265 | pdbMakeAbsolute(FileName); | |
| 1266 | ExitOnErr(Linker.Builder.getDbiBuilder().addModuleSourceFile( | |
| 1267 | *File.ModuleDBI, FileName)); | |
| 1268 | NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum); | |
| 1153 | auto newChecksums = make_unique<DebugChecksumsSubsection>(linker.pdbStrTab); | |
| 1154 | for (FileChecksumEntry &fc : checksums) { | |
| 1155 | SmallString<128> filename = | |
| 1156 | exitOnErr(cVStrTab.getString(fc.FileNameOffset)); | |
| 1157 | pdbMakeAbsolute(filename); | |
| 1158 | exitOnErr(dbiBuilder.addModuleSourceFile(*file.moduleDBI, filename)); | |
| 1159 | newChecksums->addChecksum(filename, fc.Kind, fc.Checksum); | |
| 1269 | 1160 | } |
| 1270 | File.ModuleDBI->addDebugSubsection(std::move(NewChecksums)); | |
| 1161 | ||
| 1162 | // Rewrite inlinee item indices if present. | |
| 1163 | if (inlineeLines.valid()) | |
| 1164 | file.moduleDBI->addDebugSubsection(mergeInlineeLines(newChecksums.get())); | |
| 1165 | ||
| 1166 | file.moduleDBI->addDebugSubsection(std::move(newChecksums)); | |
| 1271 | 1167 | } |
| 1272 | 1168 | |
| 1273 | void PDBLinker::addObjFile(ObjFile *File, CVIndexMap *ExternIndexMap) { | |
| 1274 | if (File->wasProcessedForPDB()) | |
| 1169 | void PDBLinker::addObjFile(ObjFile *file, CVIndexMap *externIndexMap) { | |
| 1170 | if (file->mergedIntoPDB) | |
| 1275 | 1171 | return; |
| 1276 | // Add a module descriptor for every object file. We need to put an absolute | |
| 1277 | // path to the object into the PDB. If this is a plain object, we make its | |
| 1278 | // path absolute. If it's an object in an archive, we make the archive path | |
| 1279 | // absolute. | |
| 1280 | bool InArchive = !File->ParentName.empty(); | |
| 1281 | SmallString<128> Path = InArchive ? File->ParentName : File->getName(); | |
| 1282 | pdbMakeAbsolute(Path); | |
| 1283 | StringRef Name = InArchive ? File->getName() : StringRef(Path); | |
| 1284 | ||
| 1285 | pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); | |
| 1286 | File->ModuleDBI = &ExitOnErr(DbiBuilder.addModuleInfo(Name)); | |
| 1287 | File->ModuleDBI->setObjFileName(Path); | |
| 1288 | ||
| 1289 | auto Chunks = File->getChunks(); | |
| 1290 | uint32_t Modi = File->ModuleDBI->getModuleIndex(); | |
| 1291 | for (Chunk *C : Chunks) { | |
| 1292 | auto *SecChunk = dyn_cast<SectionChunk>(C); | |
| 1293 | if (!SecChunk || !SecChunk->Live) | |
| 1294 | continue; | |
| 1295 | pdb::SectionContrib SC = createSectionContrib(SecChunk, Modi); | |
| 1296 | File->ModuleDBI->setFirstSectionContrib(SC); | |
| 1297 | break; | |
| 1298 | } | |
| 1172 | file->mergedIntoPDB = true; | |
| 1299 | 1173 | |
| 1300 | 1174 | // Before we can process symbol substreams from .debug$S, we need to process |
| 1301 | 1175 | // type information, file checksums, and the string table. Add type info to |
| 1302 | 1176 | // the PDB first, so that we can get the map from object file type and item |
| 1303 | 1177 | // indices to PDB type and item indices. |
| 1304 | CVIndexMap ObjectIndexMap; | |
| 1305 | auto IndexMapResult = | |
| 1306 | mergeDebugT(File, ExternIndexMap ? ExternIndexMap : &ObjectIndexMap); | |
| 1178 | CVIndexMap objectIndexMap; | |
| 1179 | auto indexMapResult = | |
| 1180 | mergeDebugT(file, externIndexMap ? externIndexMap : &objectIndexMap); | |
| 1307 | 1181 | |
| 1308 | 1182 | // If the .debug$T sections fail to merge, assume there is no debug info. |
| 1309 | if (!IndexMapResult) { | |
| 1310 | if (!Config->WarnDebugInfoUnusable) { | |
| 1311 | consumeError(IndexMapResult.takeError()); | |
| 1183 | if (!indexMapResult) { | |
| 1184 | if (!config->warnDebugInfoUnusable) { | |
| 1185 | consumeError(indexMapResult.takeError()); | |
| 1312 | 1186 | return; |
| 1313 | 1187 | } |
| 1314 | StringRef FileName = sys::path::filename(Path); | |
| 1315 | warn("Cannot use debug info for '" + FileName + "' [LNK4099]\n" + | |
| 1188 | warn("Cannot use debug info for '" + toString(file) + "' [LNK4099]\n" + | |
| 1316 | 1189 | ">>> failed to load reference " + |
| 1317 | StringRef(toString(IndexMapResult.takeError()))); | |
| 1190 | StringRef(toString(indexMapResult.takeError()))); | |
| 1318 | 1191 | return; |
| 1319 | 1192 | } |
| 1320 | 1193 | |
| 1321 | ScopedTimer T(SymbolMergingTimer); | |
| 1194 | ScopedTimer t(symbolMergingTimer); | |
| 1322 | 1195 | |
| 1323 | DebugSHandler DSH(*this, *File, *IndexMapResult); | |
| 1196 | pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder(); | |
| 1197 | DebugSHandler dsh(*this, *file, *indexMapResult); | |
| 1324 | 1198 | // Now do all live .debug$S and .debug$F sections. |
| 1325 | for (SectionChunk *DebugChunk : File->getDebugChunks()) { | |
| 1326 | if (!DebugChunk->Live || DebugChunk->getSize() == 0) | |
| 1199 | for (SectionChunk *debugChunk : file->getDebugChunks()) { | |
| 1200 | if (!debugChunk->live || debugChunk->getSize() == 0) | |
| 1327 | 1201 | continue; |
| 1328 | 1202 | |
| 1329 | if (DebugChunk->getSectionName() == ".debug$S") { | |
| 1330 | DSH.handleDebugS(*DebugChunk); | |
| 1203 | if (debugChunk->getSectionName() == ".debug$S") { | |
| 1204 | dsh.handleDebugS(*debugChunk); | |
| 1331 | 1205 | continue; |
| 1332 | 1206 | } |
| 1333 | 1207 | |
| 1334 | if (DebugChunk->getSectionName() == ".debug$F") { | |
| 1335 | ArrayRef<uint8_t> RelocatedDebugContents = | |
| 1336 | relocateDebugChunk(Alloc, *DebugChunk); | |
| 1208 | if (debugChunk->getSectionName() == ".debug$F") { | |
| 1209 | ArrayRef<uint8_t> relocatedDebugContents = | |
| 1210 | relocateDebugChunk(alloc, *debugChunk); | |
| 1337 | 1211 | |
| 1338 | FixedStreamArray<object::FpoData> FpoRecords; | |
| 1339 | BinaryStreamReader Reader(RelocatedDebugContents, support::little); | |
| 1340 | uint32_t Count = RelocatedDebugContents.size() / sizeof(object::FpoData); | |
| 1341 | ExitOnErr(Reader.readArray(FpoRecords, Count)); | |
| 1212 | FixedStreamArray<object::FpoData> fpoRecords; | |
| 1213 | BinaryStreamReader reader(relocatedDebugContents, support::little); | |
| 1214 | uint32_t count = relocatedDebugContents.size() / sizeof(object::FpoData); | |
| 1215 | exitOnErr(reader.readArray(fpoRecords, count)); | |
| 1342 | 1216 | |
| 1343 | 1217 | // These are already relocated and don't refer to the string table, so we |
| 1344 | 1218 | // can just copy it. |
| 1345 | for (const object::FpoData &FD : FpoRecords) | |
| 1346 | DbiBuilder.addOldFpoData(FD); | |
| 1219 | for (const object::FpoData &fd : fpoRecords) | |
| 1220 | dbiBuilder.addOldFpoData(fd); | |
| 1347 | 1221 | continue; |
| 1348 | 1222 | } |
| 1349 | 1223 | } |
| 1350 | 1224 | |
| 1351 | 1225 | // Do any post-processing now that all .debug$S sections have been processed. |
| 1352 | DSH.finish(); | |
| 1226 | dsh.finish(); | |
| 1353 | 1227 | } |
| 1354 | 1228 | |
| 1355 | static PublicSym32 createPublic(Defined *Def) { | |
| 1356 | PublicSym32 Pub(SymbolKind::S_PUB32); | |
| 1357 | Pub.Name = Def->getName(); | |
| 1358 | if (auto *D = dyn_cast<DefinedCOFF>(Def)) { | |
| 1359 | if (D->getCOFFSymbol().isFunctionDefinition()) | |
| 1360 | Pub.Flags = PublicSymFlags::Function; | |
| 1361 | } else if (isa<DefinedImportThunk>(Def)) { | |
| 1362 | Pub.Flags = PublicSymFlags::Function; | |
| 1229 | // Add a module descriptor for every object file. We need to put an absolute | |
| 1230 | // path to the object into the PDB. If this is a plain object, we make its | |
| 1231 | // path absolute. If it's an object in an archive, we make the archive path | |
| 1232 | // absolute. | |
| 1233 | static void createModuleDBI(pdb::PDBFileBuilder &builder) { | |
| 1234 | pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder(); | |
| 1235 | SmallString<128> objName; | |
| 1236 | ||
| 1237 | for (ObjFile *file : ObjFile::instances) { | |
| 1238 | ||
| 1239 | bool inArchive = !file->parentName.empty(); | |
| 1240 | objName = inArchive ? file->parentName : file->getName(); | |
| 1241 | pdbMakeAbsolute(objName); | |
| 1242 | StringRef modName = inArchive ? file->getName() : StringRef(objName); | |
| 1243 | ||
| 1244 | file->moduleDBI = &exitOnErr(dbiBuilder.addModuleInfo(modName)); | |
| 1245 | file->moduleDBI->setObjFileName(objName); | |
| 1246 | ||
| 1247 | ArrayRef<Chunk *> chunks = file->getChunks(); | |
| 1248 | uint32_t modi = file->moduleDBI->getModuleIndex(); | |
| 1249 | ||
| 1250 | for (Chunk *c : chunks) { | |
| 1251 | auto *secChunk = dyn_cast<SectionChunk>(c); | |
| 1252 | if (!secChunk || !secChunk->live) | |
| 1253 | continue; | |
| 1254 | pdb::SectionContrib sc = createSectionContrib(secChunk, modi); | |
| 1255 | file->moduleDBI->setFirstSectionContrib(sc); | |
| 1256 | break; | |
| 1257 | } | |
| 1363 | 1258 | } |
| 1259 | } | |
| 1364 | 1260 | |
| 1365 | OutputSection *OS = Def->getChunk()->getOutputSection(); | |
| 1366 | assert(OS && "all publics should be in final image"); | |
| 1367 | Pub.Offset = Def->getRVA() - OS->getRVA(); | |
| 1368 | Pub.Segment = OS->SectionIndex; | |
| 1369 | return Pub; | |
| 1261 | static PublicSym32 createPublic(Defined *def) { | |
| 1262 | PublicSym32 pub(SymbolKind::S_PUB32); | |
| 1263 | pub.Name = def->getName(); | |
| 1264 | if (auto *d = dyn_cast<DefinedCOFF>(def)) { | |
| 1265 | if (d->getCOFFSymbol().isFunctionDefinition()) | |
| 1266 | pub.Flags = PublicSymFlags::Function; | |
| 1267 | } else if (isa<DefinedImportThunk>(def)) { | |
| 1268 | pub.Flags = PublicSymFlags::Function; | |
| 1269 | } | |
| 1270 | ||
| 1271 | OutputSection *os = def->getChunk()->getOutputSection(); | |
| 1272 | assert(os && "all publics should be in final image"); | |
| 1273 | pub.Offset = def->getRVA() - os->getRVA(); | |
| 1274 | pub.Segment = os->sectionIndex; | |
| 1275 | return pub; | |
| 1370 | 1276 | } |
| 1371 | 1277 | |
| 1372 | 1278 | // Add all object files to the PDB. Merge .debug$T sections into IpiData and |
| 1373 | 1279 | // TpiData. |
| 1374 | 1280 | void PDBLinker::addObjectsToPDB() { |
| 1375 | ScopedTimer T1(AddObjectsTimer); | |
| 1376 | for (ObjFile *File : ObjFile::Instances) | |
| 1377 | addObjFile(File); | |
| 1281 | ScopedTimer t1(addObjectsTimer); | |
| 1282 | ||
| 1283 | createModuleDBI(builder); | |
| 1378 | 1284 | |
| 1379 | Builder.getStringTableBuilder().setStrings(PDBStrTab); | |
| 1380 | T1.stop(); | |
| 1285 | for (ObjFile *file : ObjFile::instances) | |
| 1286 | addObjFile(file); | |
| 1287 | ||
| 1288 | builder.getStringTableBuilder().setStrings(pdbStrTab); | |
| 1289 | t1.stop(); | |
| 1381 | 1290 | |
| 1382 | 1291 | // Construct TPI and IPI stream contents. |
| 1383 | ScopedTimer T2(TpiStreamLayoutTimer); | |
| 1384 | addTypeInfo(Builder.getTpiBuilder(), getTypeTable()); | |
| 1385 | addTypeInfo(Builder.getIpiBuilder(), getIDTable()); | |
| 1386 | T2.stop(); | |
| 1292 | ScopedTimer t2(tpiStreamLayoutTimer); | |
| 1293 | addTypeInfo(builder.getTpiBuilder(), tMerger.getTypeTable()); | |
| 1294 | addTypeInfo(builder.getIpiBuilder(), tMerger.getIDTable()); | |
| 1295 | t2.stop(); | |
| 1387 | 1296 | |
| 1388 | ScopedTimer T3(GlobalsLayoutTimer); | |
| 1297 | ScopedTimer t3(globalsLayoutTimer); | |
| 1389 | 1298 | // Compute the public and global symbols. |
| 1390 | auto &GsiBuilder = Builder.getGsiBuilder(); | |
| 1391 | std::vector<PublicSym32> Publics; | |
| 1392 | Symtab->forEachSymbol([&Publics](Symbol *S) { | |
| 1299 | auto &gsiBuilder = builder.getGsiBuilder(); | |
| 1300 | std::vector<PublicSym32> publics; | |
| 1301 | symtab->forEachSymbol([&publics](Symbol *s) { | |
| 1393 | 1302 | // Only emit defined, live symbols that have a chunk. |
| 1394 | auto *Def = dyn_cast<Defined>(S); | |
| 1395 | if (Def && Def->isLive() && Def->getChunk()) | |
| 1396 | Publics.push_back(createPublic(Def)); | |
| 1303 | auto *def = dyn_cast<Defined>(s); | |
| 1304 | if (def && def->isLive() && def->getChunk()) | |
| 1305 | publics.push_back(createPublic(def)); | |
| 1397 | 1306 | }); |
| 1398 | 1307 | |
| 1399 | if (!Publics.empty()) { | |
| 1308 | if (!publics.empty()) { | |
| 1309 | publicSymbols = publics.size(); | |
| 1400 | 1310 | // Sort the public symbols and add them to the stream. |
| 1401 | sort(parallel::par, Publics.begin(), Publics.end(), | |
| 1402 | [](const PublicSym32 &L, const PublicSym32 &R) { | |
| 1403 | return L.Name < R.Name; | |
| 1404 | }); | |
| 1405 | for (const PublicSym32 &Pub : Publics) | |
| 1406 | GsiBuilder.addPublicSymbol(Pub); | |
| 1311 | parallelSort(publics, [](const PublicSym32 &l, const PublicSym32 &r) { | |
| 1312 | return l.Name < r.Name; | |
| 1313 | }); | |
| 1314 | for (const PublicSym32 &pub : publics) | |
| 1315 | gsiBuilder.addPublicSymbol(pub); | |
| 1407 | 1316 | } |
| 1408 | 1317 | } |
| 1409 | 1318 | |
| 1319 | void PDBLinker::printStats() { | |
| 1320 | if (!config->showSummary) | |
| 1321 | return; | |
| 1322 | ||
| 1323 | SmallString<256> buffer; | |
| 1324 | raw_svector_ostream stream(buffer); | |
| 1325 | ||
| 1326 | stream << center_justify("Summary", 80) << '\n' | |
| 1327 | << std::string(80, '-') << '\n'; | |
| 1328 | ||
| 1329 | auto print = [&](uint64_t v, StringRef s) { | |
| 1330 | stream << format_decimal(v, 15) << " " << s << '\n'; | |
| 1331 | }; | |
| 1332 | ||
| 1333 | print(ObjFile::instances.size(), | |
| 1334 | "Input OBJ files (expanded from all cmd-line inputs)"); | |
| 1335 | print(typeServerIndexMappings.size(), "PDB type server dependencies"); | |
| 1336 | print(precompTypeIndexMappings.size(), "Precomp OBJ dependencies"); | |
| 1337 | print(tMerger.getTypeTable().size() + tMerger.getIDTable().size(), | |
| 1338 | "Merged TPI records"); | |
| 1339 | print(pdbStrTab.size(), "Output PDB strings"); | |
| 1340 | print(globalSymbols, "Global symbol records"); | |
| 1341 | print(moduleSymbols, "Module symbol records"); | |
| 1342 | print(publicSymbols, "Public symbol records"); | |
| 1343 | ||
| 1344 | message(buffer); | |
| 1345 | } | |
| 1346 | ||
| 1410 | 1347 | void PDBLinker::addNatvisFiles() { |
| 1411 | for (StringRef File : Config->NatvisFiles) { | |
| 1412 | ErrorOr<std::unique_ptr<MemoryBuffer>> DataOrErr = | |
| 1413 | MemoryBuffer::getFile(File); | |
| 1414 | if (!DataOrErr) { | |
| 1415 | warn("Cannot open input file: " + File); | |
| 1348 | for (StringRef file : config->natvisFiles) { | |
| 1349 | ErrorOr<std::unique_ptr<MemoryBuffer>> dataOrErr = | |
| 1350 | MemoryBuffer::getFile(file); | |
| 1351 | if (!dataOrErr) { | |
| 1352 | warn("Cannot open input file: " + file); | |
| 1416 | 1353 | continue; |
| 1417 | 1354 | } |
| 1418 | Builder.addInjectedSource(File, std::move(*DataOrErr)); | |
| 1355 | builder.addInjectedSource(file, std::move(*dataOrErr)); | |
| 1419 | 1356 | } |
| 1420 | 1357 | } |
| 1421 | 1358 | |
| 1422 | static codeview::CPUType toCodeViewMachine(COFF::MachineTypes Machine) { | |
| 1423 | switch (Machine) { | |
| 1359 | static codeview::CPUType toCodeViewMachine(COFF::MachineTypes machine) { | |
| 1360 | switch (machine) { | |
| 1424 | 1361 | case COFF::IMAGE_FILE_MACHINE_AMD64: |
| 1425 | 1362 | return codeview::CPUType::X64; |
| 1426 | 1363 | case COFF::IMAGE_FILE_MACHINE_ARM: |
| ... | ... | @@ -1439,201 +1376,329 @@ static codeview::CPUType toCodeViewMachine(COFF::MachineTypes Machine) { |
| 1439 | 1376 | // Mimic MSVC which surrounds arguments containing whitespace with quotes. |
| 1440 | 1377 | // Double double-quotes are handled, so that the resulting string can be |
| 1441 | 1378 | // executed again on the cmd-line. |
| 1442 | static std::string quote(ArrayRef<StringRef> Args) { | |
| 1443 | std::string R; | |
| 1444 | R.reserve(256); | |
| 1445 | for (StringRef A : Args) { | |
| 1446 | if (!R.empty()) | |
| 1447 | R.push_back(' '); | |
| 1448 | bool HasWS = A.find(' ') != StringRef::npos; | |
| 1449 | bool HasQ = A.find('"') != StringRef::npos; | |
| 1450 | if (HasWS || HasQ) | |
| 1451 | R.push_back('"'); | |
| 1452 | if (HasQ) { | |
| 1453 | SmallVector<StringRef, 4> S; | |
| 1454 | A.split(S, '"'); | |
| 1455 | R.append(join(S, "\"\"")); | |
| 1379 | static std::string quote(ArrayRef<StringRef> args) { | |
| 1380 | std::string r; | |
| 1381 | r.reserve(256); | |
| 1382 | for (StringRef a : args) { | |
| 1383 | if (!r.empty()) | |
| 1384 | r.push_back(' '); | |
| 1385 | bool hasWS = a.find(' ') != StringRef::npos; | |
| 1386 | bool hasQ = a.find('"') != StringRef::npos; | |
| 1387 | if (hasWS || hasQ) | |
| 1388 | r.push_back('"'); | |
| 1389 | if (hasQ) { | |
| 1390 | SmallVector<StringRef, 4> s; | |
| 1391 | a.split(s, '"'); | |
| 1392 | r.append(join(s, "\"\"")); | |
| 1456 | 1393 | } else { |
| 1457 | R.append(A); | |
| 1394 | r.append(a); | |
| 1458 | 1395 | } |
| 1459 | if (HasWS || HasQ) | |
| 1460 | R.push_back('"'); | |
| 1396 | if (hasWS || hasQ) | |
| 1397 | r.push_back('"'); | |
| 1461 | 1398 | } |
| 1462 | return R; | |
| 1399 | return r; | |
| 1463 | 1400 | } |
| 1464 | 1401 | |
| 1465 | static void addCommonLinkerModuleSymbols(StringRef Path, | |
| 1466 | pdb::DbiModuleDescriptorBuilder &Mod, | |
| 1467 | BumpPtrAllocator &Allocator) { | |
| 1468 | ObjNameSym ONS(SymbolRecordKind::ObjNameSym); | |
| 1469 | Compile3Sym CS(SymbolRecordKind::Compile3Sym); | |
| 1470 | EnvBlockSym EBS(SymbolRecordKind::EnvBlockSym); | |
| 1471 | ||
| 1472 | ONS.Name = "* Linker *"; | |
| 1473 | ONS.Signature = 0; | |
| 1474 | ||
| 1475 | CS.Machine = toCodeViewMachine(Config->Machine); | |
| 1402 | static void fillLinkerVerRecord(Compile3Sym &cs) { | |
| 1403 | cs.Machine = toCodeViewMachine(config->machine); | |
| 1476 | 1404 | // Interestingly, if we set the string to 0.0.0.0, then when trying to view |
| 1477 | 1405 | // local variables WinDbg emits an error that private symbols are not present. |
| 1478 | 1406 | // By setting this to a valid MSVC linker version string, local variables are |
| 1479 | 1407 | // displayed properly. As such, even though it is not representative of |
| 1480 | 1408 | // LLVM's version information, we need this for compatibility. |
| 1481 | CS.Flags = CompileSym3Flags::None; | |
| 1482 | CS.VersionBackendBuild = 25019; | |
| 1483 | CS.VersionBackendMajor = 14; | |
| 1484 | CS.VersionBackendMinor = 10; | |
| 1485 | CS.VersionBackendQFE = 0; | |
| 1409 | cs.Flags = CompileSym3Flags::None; | |
| 1410 | cs.VersionBackendBuild = 25019; | |
| 1411 | cs.VersionBackendMajor = 14; | |
| 1412 | cs.VersionBackendMinor = 10; | |
| 1413 | cs.VersionBackendQFE = 0; | |
| 1486 | 1414 | |
| 1487 | 1415 | // MSVC also sets the frontend to 0.0.0.0 since this is specifically for the |
| 1488 | 1416 | // linker module (which is by definition a backend), so we don't need to do |
| 1489 | 1417 | // anything here. Also, it seems we can use "LLVM Linker" for the linker name |
| 1490 | 1418 | // without any problems. Only the backend version has to be hardcoded to a |
| 1491 | 1419 | // magic number. |
| 1492 | CS.VersionFrontendBuild = 0; | |
| 1493 | CS.VersionFrontendMajor = 0; | |
| 1494 | CS.VersionFrontendMinor = 0; | |
| 1495 | CS.VersionFrontendQFE = 0; | |
| 1496 | CS.Version = "LLVM Linker"; | |
| 1497 | CS.setLanguage(SourceLanguage::Link); | |
| 1498 | ||
| 1499 | ArrayRef<StringRef> Args = makeArrayRef(Config->Argv).drop_front(); | |
| 1500 | std::string ArgStr = quote(Args); | |
| 1501 | EBS.Fields.push_back("cwd"); | |
| 1420 | cs.VersionFrontendBuild = 0; | |
| 1421 | cs.VersionFrontendMajor = 0; | |
| 1422 | cs.VersionFrontendMinor = 0; | |
| 1423 | cs.VersionFrontendQFE = 0; | |
| 1424 | cs.Version = "LLVM Linker"; | |
| 1425 | cs.setLanguage(SourceLanguage::Link); | |
| 1426 | } | |
| 1427 | ||
| 1428 | static void addCommonLinkerModuleSymbols(StringRef path, | |
| 1429 | pdb::DbiModuleDescriptorBuilder &mod, | |
| 1430 | BumpPtrAllocator &allocator) { | |
| 1431 | ObjNameSym ons(SymbolRecordKind::ObjNameSym); | |
| 1432 | EnvBlockSym ebs(SymbolRecordKind::EnvBlockSym); | |
| 1433 | Compile3Sym cs(SymbolRecordKind::Compile3Sym); | |
| 1434 | fillLinkerVerRecord(cs); | |
| 1435 | ||
| 1436 | ons.Name = "* Linker *"; | |
| 1437 | ons.Signature = 0; | |
| 1438 | ||
| 1439 | ArrayRef<StringRef> args = makeArrayRef(config->argv).drop_front(); | |
| 1440 | std::string argStr = quote(args); | |
| 1441 | ebs.Fields.push_back("cwd"); | |
| 1502 | 1442 | SmallString<64> cwd; |
| 1503 | if (Config->PDBSourcePath.empty()) | |
| 1443 | if (config->pdbSourcePath.empty()) | |
| 1504 | 1444 | sys::fs::current_path(cwd); |
| 1505 | 1445 | else |
| 1506 | cwd = Config->PDBSourcePath; | |
| 1507 | EBS.Fields.push_back(cwd); | |
| 1508 | EBS.Fields.push_back("exe"); | |
| 1509 | SmallString<64> exe = Config->Argv[0]; | |
| 1446 | cwd = config->pdbSourcePath; | |
| 1447 | ebs.Fields.push_back(cwd); | |
| 1448 | ebs.Fields.push_back("exe"); | |
| 1449 | SmallString<64> exe = config->argv[0]; | |
| 1510 | 1450 | pdbMakeAbsolute(exe); |
| 1511 | EBS.Fields.push_back(exe); | |
| 1512 | EBS.Fields.push_back("pdb"); | |
| 1513 | EBS.Fields.push_back(Path); | |
| 1514 | EBS.Fields.push_back("cmd"); | |
| 1515 | EBS.Fields.push_back(ArgStr); | |
| 1516 | Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( | |
| 1517 | ONS, Allocator, CodeViewContainer::Pdb)); | |
| 1518 | Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( | |
| 1519 | CS, Allocator, CodeViewContainer::Pdb)); | |
| 1520 | Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( | |
| 1521 | EBS, Allocator, CodeViewContainer::Pdb)); | |
| 1451 | ebs.Fields.push_back(exe); | |
| 1452 | ebs.Fields.push_back("pdb"); | |
| 1453 | ebs.Fields.push_back(path); | |
| 1454 | ebs.Fields.push_back("cmd"); | |
| 1455 | ebs.Fields.push_back(argStr); | |
| 1456 | mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( | |
| 1457 | ons, allocator, CodeViewContainer::Pdb)); | |
| 1458 | mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( | |
| 1459 | cs, allocator, CodeViewContainer::Pdb)); | |
| 1460 | mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( | |
| 1461 | ebs, allocator, CodeViewContainer::Pdb)); | |
| 1462 | } | |
| 1463 | ||
| 1464 | static void addLinkerModuleCoffGroup(PartialSection *sec, | |
| 1465 | pdb::DbiModuleDescriptorBuilder &mod, | |
| 1466 | OutputSection &os, | |
| 1467 | BumpPtrAllocator &allocator) { | |
| 1468 | // If there's a section, there's at least one chunk | |
| 1469 | assert(!sec->chunks.empty()); | |
| 1470 | const Chunk *firstChunk = *sec->chunks.begin(); | |
| 1471 | const Chunk *lastChunk = *sec->chunks.rbegin(); | |
| 1472 | ||
| 1473 | // Emit COFF group | |
| 1474 | CoffGroupSym cgs(SymbolRecordKind::CoffGroupSym); | |
| 1475 | cgs.Name = sec->name; | |
| 1476 | cgs.Segment = os.sectionIndex; | |
| 1477 | cgs.Offset = firstChunk->getRVA() - os.getRVA(); | |
| 1478 | cgs.Size = lastChunk->getRVA() + lastChunk->getSize() - firstChunk->getRVA(); | |
| 1479 | cgs.Characteristics = sec->characteristics; | |
| 1480 | ||
| 1481 | // Somehow .idata sections & sections groups in the debug symbol stream have | |
| 1482 | // the "write" flag set. However the section header for the corresponding | |
| 1483 | // .idata section doesn't have it. | |
| 1484 | if (cgs.Name.startswith(".idata")) | |
| 1485 | cgs.Characteristics |= llvm::COFF::IMAGE_SCN_MEM_WRITE; | |
| 1486 | ||
| 1487 | mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( | |
| 1488 | cgs, allocator, CodeViewContainer::Pdb)); | |
| 1489 | } | |
| 1490 | ||
| 1491 | static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &mod, | |
| 1492 | OutputSection &os, | |
| 1493 | BumpPtrAllocator &allocator) { | |
| 1494 | SectionSym sym(SymbolRecordKind::SectionSym); | |
| 1495 | sym.Alignment = 12; // 2^12 = 4KB | |
| 1496 | sym.Characteristics = os.header.Characteristics; | |
| 1497 | sym.Length = os.getVirtualSize(); | |
| 1498 | sym.Name = os.name; | |
| 1499 | sym.Rva = os.getRVA(); | |
| 1500 | sym.SectionNumber = os.sectionIndex; | |
| 1501 | mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( | |
| 1502 | sym, allocator, CodeViewContainer::Pdb)); | |
| 1503 | ||
| 1504 | // Skip COFF groups in MinGW because it adds a significant footprint to the | |
| 1505 | // PDB, due to each function being in its own section | |
| 1506 | if (config->mingw) | |
| 1507 | return; | |
| 1508 | ||
| 1509 | // Output COFF groups for individual chunks of this section. | |
| 1510 | for (PartialSection *sec : os.contribSections) { | |
| 1511 | addLinkerModuleCoffGroup(sec, mod, os, allocator); | |
| 1512 | } | |
| 1522 | 1513 | } |
| 1523 | 1514 | |
| 1524 | static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &Mod, | |
| 1525 | OutputSection &OS, | |
| 1526 | BumpPtrAllocator &Allocator) { | |
| 1527 | SectionSym Sym(SymbolRecordKind::SectionSym); | |
| 1528 | Sym.Alignment = 12; // 2^12 = 4KB | |
| 1529 | Sym.Characteristics = OS.Header.Characteristics; | |
| 1530 | Sym.Length = OS.getVirtualSize(); | |
| 1531 | Sym.Name = OS.Name; | |
| 1532 | Sym.Rva = OS.getRVA(); | |
| 1533 | Sym.SectionNumber = OS.SectionIndex; | |
| 1534 | Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( | |
| 1535 | Sym, Allocator, CodeViewContainer::Pdb)); | |
| 1515 | // Add all import files as modules to the PDB. | |
| 1516 | void PDBLinker::addImportFilesToPDB(ArrayRef<OutputSection *> outputSections) { | |
| 1517 | if (ImportFile::instances.empty()) | |
| 1518 | return; | |
| 1519 | ||
| 1520 | std::map<std::string, llvm::pdb::DbiModuleDescriptorBuilder *> dllToModuleDbi; | |
| 1521 | ||
| 1522 | for (ImportFile *file : ImportFile::instances) { | |
| 1523 | if (!file->live) | |
| 1524 | continue; | |
| 1525 | ||
| 1526 | if (!file->thunkSym) | |
| 1527 | continue; | |
| 1528 | ||
| 1529 | if (!file->thunkLive) | |
| 1530 | continue; | |
| 1531 | ||
| 1532 | std::string dll = StringRef(file->dllName).lower(); | |
| 1533 | llvm::pdb::DbiModuleDescriptorBuilder *&mod = dllToModuleDbi[dll]; | |
| 1534 | if (!mod) { | |
| 1535 | pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder(); | |
| 1536 | SmallString<128> libPath = file->parentName; | |
| 1537 | pdbMakeAbsolute(libPath); | |
| 1538 | sys::path::native(libPath); | |
| 1539 | ||
| 1540 | // Name modules similar to MSVC's link.exe. | |
| 1541 | // The first module is the simple dll filename | |
| 1542 | llvm::pdb::DbiModuleDescriptorBuilder &firstMod = | |
| 1543 | exitOnErr(dbiBuilder.addModuleInfo(file->dllName)); | |
| 1544 | firstMod.setObjFileName(libPath); | |
| 1545 | pdb::SectionContrib sc = | |
| 1546 | createSectionContrib(nullptr, llvm::pdb::kInvalidStreamIndex); | |
| 1547 | firstMod.setFirstSectionContrib(sc); | |
| 1548 | ||
| 1549 | // The second module is where the import stream goes. | |
| 1550 | mod = &exitOnErr(dbiBuilder.addModuleInfo("Import:" + file->dllName)); | |
| 1551 | mod->setObjFileName(libPath); | |
| 1552 | } | |
| 1553 | ||
| 1554 | DefinedImportThunk *thunk = cast<DefinedImportThunk>(file->thunkSym); | |
| 1555 | Chunk *thunkChunk = thunk->getChunk(); | |
| 1556 | OutputSection *thunkOS = thunkChunk->getOutputSection(); | |
| 1557 | ||
| 1558 | ObjNameSym ons(SymbolRecordKind::ObjNameSym); | |
| 1559 | Compile3Sym cs(SymbolRecordKind::Compile3Sym); | |
| 1560 | Thunk32Sym ts(SymbolRecordKind::Thunk32Sym); | |
| 1561 | ScopeEndSym es(SymbolRecordKind::ScopeEndSym); | |
| 1562 | ||
| 1563 | ons.Name = file->dllName; | |
| 1564 | ons.Signature = 0; | |
| 1565 | ||
| 1566 | fillLinkerVerRecord(cs); | |
| 1567 | ||
| 1568 | ts.Name = thunk->getName(); | |
| 1569 | ts.Parent = 0; | |
| 1570 | ts.End = 0; | |
| 1571 | ts.Next = 0; | |
| 1572 | ts.Thunk = ThunkOrdinal::Standard; | |
| 1573 | ts.Length = thunkChunk->getSize(); | |
| 1574 | ts.Segment = thunkOS->sectionIndex; | |
| 1575 | ts.Offset = thunkChunk->getRVA() - thunkOS->getRVA(); | |
| 1576 | ||
| 1577 | mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol( | |
| 1578 | ons, alloc, CodeViewContainer::Pdb)); | |
| 1579 | mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol( | |
| 1580 | cs, alloc, CodeViewContainer::Pdb)); | |
| 1581 | ||
| 1582 | SmallVector<SymbolScope, 4> scopes; | |
| 1583 | CVSymbol newSym = codeview::SymbolSerializer::writeOneSymbol( | |
| 1584 | ts, alloc, CodeViewContainer::Pdb); | |
| 1585 | scopeStackOpen(scopes, mod->getNextSymbolOffset(), newSym); | |
| 1586 | ||
| 1587 | mod->addSymbol(newSym); | |
| 1588 | ||
| 1589 | newSym = codeview::SymbolSerializer::writeOneSymbol(es, alloc, | |
| 1590 | CodeViewContainer::Pdb); | |
| 1591 | scopeStackClose(scopes, mod->getNextSymbolOffset(), file); | |
| 1592 | ||
| 1593 | mod->addSymbol(newSym); | |
| 1594 | ||
| 1595 | pdb::SectionContrib sc = | |
| 1596 | createSectionContrib(thunk->getChunk(), mod->getModuleIndex()); | |
| 1597 | mod->setFirstSectionContrib(sc); | |
| 1598 | } | |
| 1536 | 1599 | } |
| 1537 | 1600 | |
| 1538 | 1601 | // Creates a PDB file. |
| 1539 | void coff::createPDB(SymbolTable *Symtab, | |
| 1540 | ArrayRef<OutputSection *> OutputSections, | |
| 1541 | ArrayRef<uint8_t> SectionTable, | |
| 1542 | llvm::codeview::DebugInfo *BuildId) { | |
| 1543 | ScopedTimer T1(TotalPdbLinkTimer); | |
| 1544 | PDBLinker PDB(Symtab); | |
| 1545 | ||
| 1546 | PDB.initialize(BuildId); | |
| 1547 | PDB.addObjectsToPDB(); | |
| 1548 | PDB.addSections(OutputSections, SectionTable); | |
| 1549 | PDB.addNatvisFiles(); | |
| 1550 | ||
| 1551 | ScopedTimer T2(DiskCommitTimer); | |
| 1552 | codeview::GUID Guid; | |
| 1553 | PDB.commit(&Guid); | |
| 1554 | memcpy(&BuildId->PDB70.Signature, &Guid, 16); | |
| 1602 | void coff::createPDB(SymbolTable *symtab, | |
| 1603 | ArrayRef<OutputSection *> outputSections, | |
| 1604 | ArrayRef<uint8_t> sectionTable, | |
| 1605 | llvm::codeview::DebugInfo *buildId) { | |
| 1606 | ScopedTimer t1(totalPdbLinkTimer); | |
| 1607 | PDBLinker pdb(symtab); | |
| 1608 | ||
| 1609 | pdb.initialize(buildId); | |
| 1610 | pdb.addObjectsToPDB(); | |
| 1611 | pdb.addImportFilesToPDB(outputSections); | |
| 1612 | pdb.addSections(outputSections, sectionTable); | |
| 1613 | pdb.addNatvisFiles(); | |
| 1614 | ||
| 1615 | ScopedTimer t2(diskCommitTimer); | |
| 1616 | codeview::GUID guid; | |
| 1617 | pdb.commit(&guid); | |
| 1618 | memcpy(&buildId->PDB70.Signature, &guid, 16); | |
| 1619 | ||
| 1620 | t2.stop(); | |
| 1621 | t1.stop(); | |
| 1622 | pdb.printStats(); | |
| 1555 | 1623 | } |
| 1556 | 1624 | |
| 1557 | void PDBLinker::initialize(llvm::codeview::DebugInfo *BuildId) { | |
| 1558 | ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize | |
| 1625 | void PDBLinker::initialize(llvm::codeview::DebugInfo *buildId) { | |
| 1626 | exitOnErr(builder.initialize(4096)); // 4096 is blocksize | |
| 1559 | 1627 | |
| 1560 | BuildId->Signature.CVSignature = OMF::Signature::PDB70; | |
| 1628 | buildId->Signature.CVSignature = OMF::Signature::PDB70; | |
| 1561 | 1629 | // Signature is set to a hash of the PDB contents when the PDB is done. |
| 1562 | memset(BuildId->PDB70.Signature, 0, 16); | |
| 1563 | BuildId->PDB70.Age = 1; | |
| 1630 | memset(buildId->PDB70.Signature, 0, 16); | |
| 1631 | buildId->PDB70.Age = 1; | |
| 1564 | 1632 | |
| 1565 | 1633 | // Create streams in MSF for predefined streams, namely |
| 1566 | 1634 | // PDB, TPI, DBI and IPI. |
| 1567 | for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I) | |
| 1568 | ExitOnErr(Builder.getMsfBuilder().addStream(0)); | |
| 1635 | for (int i = 0; i < (int)pdb::kSpecialStreamCount; ++i) | |
| 1636 | exitOnErr(builder.getMsfBuilder().addStream(0)); | |
| 1569 | 1637 | |
| 1570 | 1638 | // Add an Info stream. |
| 1571 | auto &InfoBuilder = Builder.getInfoBuilder(); | |
| 1572 | InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); | |
| 1573 | InfoBuilder.setHashPDBContentsToGUID(true); | |
| 1639 | auto &infoBuilder = builder.getInfoBuilder(); | |
| 1640 | infoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); | |
| 1641 | infoBuilder.setHashPDBContentsToGUID(true); | |
| 1574 | 1642 | |
| 1575 | 1643 | // Add an empty DBI stream. |
| 1576 | pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); | |
| 1577 | DbiBuilder.setAge(BuildId->PDB70.Age); | |
| 1578 | DbiBuilder.setVersionHeader(pdb::PdbDbiV70); | |
| 1579 | DbiBuilder.setMachineType(Config->Machine); | |
| 1644 | pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder(); | |
| 1645 | dbiBuilder.setAge(buildId->PDB70.Age); | |
| 1646 | dbiBuilder.setVersionHeader(pdb::PdbDbiV70); | |
| 1647 | dbiBuilder.setMachineType(config->machine); | |
| 1580 | 1648 | // Technically we are not link.exe 14.11, but there are known cases where |
| 1581 | 1649 | // debugging tools on Windows expect Microsoft-specific version numbers or |
| 1582 | 1650 | // they fail to work at all. Since we know we produce PDBs that are |
| 1583 | 1651 | // compatible with LINK 14.11, we set that version number here. |
| 1584 | DbiBuilder.setBuildNumber(14, 11); | |
| 1652 | dbiBuilder.setBuildNumber(14, 11); | |
| 1585 | 1653 | } |
| 1586 | 1654 | |
| 1587 | void PDBLinker::addSections(ArrayRef<OutputSection *> OutputSections, | |
| 1588 | ArrayRef<uint8_t> SectionTable) { | |
| 1655 | void PDBLinker::addSections(ArrayRef<OutputSection *> outputSections, | |
| 1656 | ArrayRef<uint8_t> sectionTable) { | |
| 1589 | 1657 | // It's not entirely clear what this is, but the * Linker * module uses it. |
| 1590 | pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); | |
| 1591 | NativePath = Config->PDBPath; | |
| 1592 | pdbMakeAbsolute(NativePath); | |
| 1593 | uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath); | |
| 1594 | auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *")); | |
| 1595 | LinkerModule.setPdbFilePathNI(PdbFilePathNI); | |
| 1596 | addCommonLinkerModuleSymbols(NativePath, LinkerModule, Alloc); | |
| 1658 | pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder(); | |
| 1659 | nativePath = config->pdbPath; | |
| 1660 | pdbMakeAbsolute(nativePath); | |
| 1661 | uint32_t pdbFilePathNI = dbiBuilder.addECName(nativePath); | |
| 1662 | auto &linkerModule = exitOnErr(dbiBuilder.addModuleInfo("* Linker *")); | |
| 1663 | linkerModule.setPdbFilePathNI(pdbFilePathNI); | |
| 1664 | addCommonLinkerModuleSymbols(nativePath, linkerModule, alloc); | |
| 1597 | 1665 | |
| 1598 | 1666 | // Add section contributions. They must be ordered by ascending RVA. |
| 1599 | for (OutputSection *OS : OutputSections) { | |
| 1600 | addLinkerModuleSectionSymbol(LinkerModule, *OS, Alloc); | |
| 1601 | for (Chunk *C : OS->Chunks) { | |
| 1602 | pdb::SectionContrib SC = | |
| 1603 | createSectionContrib(C, LinkerModule.getModuleIndex()); | |
| 1604 | Builder.getDbiBuilder().addSectionContrib(SC); | |
| 1667 | for (OutputSection *os : outputSections) { | |
| 1668 | addLinkerModuleSectionSymbol(linkerModule, *os, alloc); | |
| 1669 | for (Chunk *c : os->chunks) { | |
| 1670 | pdb::SectionContrib sc = | |
| 1671 | createSectionContrib(c, linkerModule.getModuleIndex()); | |
| 1672 | builder.getDbiBuilder().addSectionContrib(sc); | |
| 1605 | 1673 | } |
| 1606 | 1674 | } |
| 1607 | 1675 | |
| 1676 | // The * Linker * first section contrib is only used along with /INCREMENTAL, | |
| 1677 | // to provide trampolines thunks for incremental function patching. Set this | |
| 1678 | // as "unused" because LLD doesn't support /INCREMENTAL link. | |
| 1679 | pdb::SectionContrib sc = | |
| 1680 | createSectionContrib(nullptr, llvm::pdb::kInvalidStreamIndex); | |
| 1681 | linkerModule.setFirstSectionContrib(sc); | |
| 1682 | ||
| 1608 | 1683 | // Add Section Map stream. |
| 1609 | ArrayRef<object::coff_section> Sections = { | |
| 1610 | (const object::coff_section *)SectionTable.data(), | |
| 1611 | SectionTable.size() / sizeof(object::coff_section)}; | |
| 1612 | SectionMap = pdb::DbiStreamBuilder::createSectionMap(Sections); | |
| 1613 | DbiBuilder.setSectionMap(SectionMap); | |
| 1684 | ArrayRef<object::coff_section> sections = { | |
| 1685 | (const object::coff_section *)sectionTable.data(), | |
| 1686 | sectionTable.size() / sizeof(object::coff_section)}; | |
| 1687 | sectionMap = pdb::DbiStreamBuilder::createSectionMap(sections); | |
| 1688 | dbiBuilder.setSectionMap(sectionMap); | |
| 1614 | 1689 | |
| 1615 | 1690 | // Add COFF section header stream. |
| 1616 | ExitOnErr( | |
| 1617 | DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable)); | |
| 1691 | exitOnErr( | |
| 1692 | dbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, sectionTable)); | |
| 1618 | 1693 | } |
| 1619 | 1694 | |
| 1620 | void PDBLinker::commit(codeview::GUID *Guid) { | |
| 1695 | void PDBLinker::commit(codeview::GUID *guid) { | |
| 1621 | 1696 | // Write to a file. |
| 1622 | ExitOnErr(Builder.commit(Config->PDBPath, Guid)); | |
| 1623 | } | |
| 1624 | ||
| 1625 | static Expected<StringRef> | |
| 1626 | getFileName(const DebugStringTableSubsectionRef &Strings, | |
| 1627 | const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID) { | |
| 1628 | auto Iter = Checksums.getArray().at(FileID); | |
| 1629 | if (Iter == Checksums.getArray().end()) | |
| 1630 | return make_error<CodeViewError>(cv_error_code::no_records); | |
| 1631 | uint32_t Offset = Iter->FileNameOffset; | |
| 1632 | return Strings.getString(Offset); | |
| 1697 | exitOnErr(builder.commit(config->pdbPath, guid)); | |
| 1633 | 1698 | } |
| 1634 | 1699 | |
| 1635 | 1700 | static uint32_t getSecrelReloc() { |
| 1636 | switch (Config->Machine) { | |
| 1701 | switch (config->machine) { | |
| 1637 | 1702 | case AMD64: |
| 1638 | 1703 | return COFF::IMAGE_REL_AMD64_SECREL; |
| 1639 | 1704 | case I386: |
| ... | ... | @@ -1652,78 +1717,78 @@ static uint32_t getSecrelReloc() { |
| 1652 | 1717 | // that are used to interpret the line table, and the offset of Addr in the line |
| 1653 | 1718 | // table are stored in the output arguments. Returns whether a line table was |
| 1654 | 1719 | // found. |
| 1655 | static bool findLineTable(const SectionChunk *C, uint32_t Addr, | |
| 1656 | DebugStringTableSubsectionRef &CVStrTab, | |
| 1657 | DebugChecksumsSubsectionRef &Checksums, | |
| 1658 | DebugLinesSubsectionRef &Lines, | |
| 1659 | uint32_t &OffsetInLinetable) { | |
| 1660 | ExitOnError ExitOnErr; | |
| 1661 | uint32_t SecrelReloc = getSecrelReloc(); | |
| 1662 | ||
| 1663 | for (SectionChunk *DbgC : C->File->getDebugChunks()) { | |
| 1664 | if (DbgC->getSectionName() != ".debug$S") | |
| 1720 | static bool findLineTable(const SectionChunk *c, uint32_t addr, | |
| 1721 | DebugStringTableSubsectionRef &cVStrTab, | |
| 1722 | DebugChecksumsSubsectionRef &checksums, | |
| 1723 | DebugLinesSubsectionRef &lines, | |
| 1724 | uint32_t &offsetInLinetable) { | |
| 1725 | ExitOnError exitOnErr; | |
| 1726 | uint32_t secrelReloc = getSecrelReloc(); | |
| 1727 | ||
| 1728 | for (SectionChunk *dbgC : c->file->getDebugChunks()) { | |
| 1729 | if (dbgC->getSectionName() != ".debug$S") | |
| 1665 | 1730 | continue; |
| 1666 | 1731 | |
| 1667 | // Build a mapping of SECREL relocations in DbgC that refer to C. | |
| 1668 | DenseMap<uint32_t, uint32_t> Secrels; | |
| 1669 | for (const coff_relocation &R : DbgC->Relocs) { | |
| 1670 | if (R.Type != SecrelReloc) | |
| 1732 | // Build a mapping of SECREL relocations in dbgC that refer to `c`. | |
| 1733 | DenseMap<uint32_t, uint32_t> secrels; | |
| 1734 | for (const coff_relocation &r : dbgC->getRelocs()) { | |
| 1735 | if (r.Type != secrelReloc) | |
| 1671 | 1736 | continue; |
| 1672 | 1737 | |
| 1673 | if (auto *S = dyn_cast_or_null<DefinedRegular>( | |
| 1674 | C->File->getSymbols()[R.SymbolTableIndex])) | |
| 1675 | if (S->getChunk() == C) | |
| 1676 | Secrels[R.VirtualAddress] = S->getValue(); | |
| 1738 | if (auto *s = dyn_cast_or_null<DefinedRegular>( | |
| 1739 | c->file->getSymbols()[r.SymbolTableIndex])) | |
| 1740 | if (s->getChunk() == c) | |
| 1741 | secrels[r.VirtualAddress] = s->getValue(); | |
| 1677 | 1742 | } |
| 1678 | 1743 | |
| 1679 | ArrayRef<uint8_t> Contents = | |
| 1680 | consumeDebugMagic(DbgC->getContents(), ".debug$S"); | |
| 1681 | DebugSubsectionArray Subsections; | |
| 1682 | BinaryStreamReader Reader(Contents, support::little); | |
| 1683 | ExitOnErr(Reader.readArray(Subsections, Contents.size())); | |
| 1744 | ArrayRef<uint8_t> contents = | |
| 1745 | SectionChunk::consumeDebugMagic(dbgC->getContents(), ".debug$S"); | |
| 1746 | DebugSubsectionArray subsections; | |
| 1747 | BinaryStreamReader reader(contents, support::little); | |
| 1748 | exitOnErr(reader.readArray(subsections, contents.size())); | |
| 1684 | 1749 | |
| 1685 | for (const DebugSubsectionRecord &SS : Subsections) { | |
| 1686 | switch (SS.kind()) { | |
| 1750 | for (const DebugSubsectionRecord &ss : subsections) { | |
| 1751 | switch (ss.kind()) { | |
| 1687 | 1752 | case DebugSubsectionKind::StringTable: { |
| 1688 | assert(!CVStrTab.valid() && | |
| 1753 | assert(!cVStrTab.valid() && | |
| 1689 | 1754 | "Encountered multiple string table subsections!"); |
| 1690 | ExitOnErr(CVStrTab.initialize(SS.getRecordData())); | |
| 1755 | exitOnErr(cVStrTab.initialize(ss.getRecordData())); | |
| 1691 | 1756 | break; |
| 1692 | 1757 | } |
| 1693 | 1758 | case DebugSubsectionKind::FileChecksums: |
| 1694 | assert(!Checksums.valid() && | |
| 1759 | assert(!checksums.valid() && | |
| 1695 | 1760 | "Encountered multiple checksum subsections!"); |
| 1696 | ExitOnErr(Checksums.initialize(SS.getRecordData())); | |
| 1761 | exitOnErr(checksums.initialize(ss.getRecordData())); | |
| 1697 | 1762 | break; |
| 1698 | 1763 | case DebugSubsectionKind::Lines: { |
| 1699 | ArrayRef<uint8_t> Bytes; | |
| 1700 | auto Ref = SS.getRecordData(); | |
| 1701 | ExitOnErr(Ref.readLongestContiguousChunk(0, Bytes)); | |
| 1702 | size_t OffsetInDbgC = Bytes.data() - DbgC->getContents().data(); | |
| 1764 | ArrayRef<uint8_t> bytes; | |
| 1765 | auto ref = ss.getRecordData(); | |
| 1766 | exitOnErr(ref.readLongestContiguousChunk(0, bytes)); | |
| 1767 | size_t offsetInDbgC = bytes.data() - dbgC->getContents().data(); | |
| 1703 | 1768 | |
| 1704 | 1769 | // Check whether this line table refers to C. |
| 1705 | auto I = Secrels.find(OffsetInDbgC); | |
| 1706 | if (I == Secrels.end()) | |
| 1770 | auto i = secrels.find(offsetInDbgC); | |
| 1771 | if (i == secrels.end()) | |
| 1707 | 1772 | break; |
| 1708 | 1773 | |
| 1709 | 1774 | // Check whether this line table covers Addr in C. |
| 1710 | DebugLinesSubsectionRef LinesTmp; | |
| 1711 | ExitOnErr(LinesTmp.initialize(BinaryStreamReader(Ref))); | |
| 1712 | uint32_t OffsetInC = I->second + LinesTmp.header()->RelocOffset; | |
| 1713 | if (Addr < OffsetInC || Addr >= OffsetInC + LinesTmp.header()->CodeSize) | |
| 1775 | DebugLinesSubsectionRef linesTmp; | |
| 1776 | exitOnErr(linesTmp.initialize(BinaryStreamReader(ref))); | |
| 1777 | uint32_t offsetInC = i->second + linesTmp.header()->RelocOffset; | |
| 1778 | if (addr < offsetInC || addr >= offsetInC + linesTmp.header()->CodeSize) | |
| 1714 | 1779 | break; |
| 1715 | 1780 | |
| 1716 | assert(!Lines.header() && | |
| 1781 | assert(!lines.header() && | |
| 1717 | 1782 | "Encountered multiple line tables for function!"); |
| 1718 | ExitOnErr(Lines.initialize(BinaryStreamReader(Ref))); | |
| 1719 | OffsetInLinetable = Addr - OffsetInC; | |
| 1783 | exitOnErr(lines.initialize(BinaryStreamReader(ref))); | |
| 1784 | offsetInLinetable = addr - offsetInC; | |
| 1720 | 1785 | break; |
| 1721 | 1786 | } |
| 1722 | 1787 | default: |
| 1723 | 1788 | break; |
| 1724 | 1789 | } |
| 1725 | 1790 | |
| 1726 | if (CVStrTab.valid() && Checksums.valid() && Lines.header()) | |
| 1791 | if (cVStrTab.valid() && checksums.valid() && lines.header()) | |
| 1727 | 1792 | return true; |
| 1728 | 1793 | } |
| 1729 | 1794 | } |
| ... | ... | @@ -1734,38 +1799,38 @@ static bool findLineTable(const SectionChunk *C, uint32_t Addr, |
| 1734 | 1799 | // Use CodeView line tables to resolve a file and line number for the given |
| 1735 | 1800 | // offset into the given chunk and return them, or {"", 0} if a line table was |
| 1736 | 1801 | // not found. |
| 1737 | std::pair<StringRef, uint32_t> coff::getFileLine(const SectionChunk *C, | |
| 1738 | uint32_t Addr) { | |
| 1739 | ExitOnError ExitOnErr; | |
| 1802 | std::pair<StringRef, uint32_t> coff::getFileLine(const SectionChunk *c, | |
| 1803 | uint32_t addr) { | |
| 1804 | ExitOnError exitOnErr; | |
| 1740 | 1805 | |
| 1741 | DebugStringTableSubsectionRef CVStrTab; | |
| 1742 | DebugChecksumsSubsectionRef Checksums; | |
| 1743 | DebugLinesSubsectionRef Lines; | |
| 1744 | uint32_t OffsetInLinetable; | |
| 1806 | DebugStringTableSubsectionRef cVStrTab; | |
| 1807 | DebugChecksumsSubsectionRef checksums; | |
| 1808 | DebugLinesSubsectionRef lines; | |
| 1809 | uint32_t offsetInLinetable; | |
| 1745 | 1810 | |
| 1746 | if (!findLineTable(C, Addr, CVStrTab, Checksums, Lines, OffsetInLinetable)) | |
| 1811 | if (!findLineTable(c, addr, cVStrTab, checksums, lines, offsetInLinetable)) | |
| 1747 | 1812 | return {"", 0}; |
| 1748 | 1813 | |
| 1749 | Optional<uint32_t> NameIndex; | |
| 1750 | Optional<uint32_t> LineNumber; | |
| 1751 | for (LineColumnEntry &Entry : Lines) { | |
| 1752 | for (const LineNumberEntry &LN : Entry.LineNumbers) { | |
| 1753 | LineInfo LI(LN.Flags); | |
| 1754 | if (LN.Offset > OffsetInLinetable) { | |
| 1755 | if (!NameIndex) { | |
| 1756 | NameIndex = Entry.NameIndex; | |
| 1757 | LineNumber = LI.getStartLine(); | |
| 1814 | Optional<uint32_t> nameIndex; | |
| 1815 | Optional<uint32_t> lineNumber; | |
| 1816 | for (LineColumnEntry &entry : lines) { | |
| 1817 | for (const LineNumberEntry &ln : entry.LineNumbers) { | |
| 1818 | LineInfo li(ln.Flags); | |
| 1819 | if (ln.Offset > offsetInLinetable) { | |
| 1820 | if (!nameIndex) { | |
| 1821 | nameIndex = entry.NameIndex; | |
| 1822 | lineNumber = li.getStartLine(); | |
| 1758 | 1823 | } |
| 1759 | StringRef Filename = | |
| 1760 | ExitOnErr(getFileName(CVStrTab, Checksums, *NameIndex)); | |
| 1761 | return {Filename, *LineNumber}; | |
| 1824 | StringRef filename = | |
| 1825 | exitOnErr(getFileName(cVStrTab, checksums, *nameIndex)); | |
| 1826 | return {filename, *lineNumber}; | |
| 1762 | 1827 | } |
| 1763 | NameIndex = Entry.NameIndex; | |
| 1764 | LineNumber = LI.getStartLine(); | |
| 1828 | nameIndex = entry.NameIndex; | |
| 1829 | lineNumber = li.getStartLine(); | |
| 1765 | 1830 | } |
| 1766 | 1831 | } |
| 1767 | if (!NameIndex) | |
| 1832 | if (!nameIndex) | |
| 1768 | 1833 | return {"", 0}; |
| 1769 | StringRef Filename = ExitOnErr(getFileName(CVStrTab, Checksums, *NameIndex)); | |
| 1770 | return {Filename, *LineNumber}; | |
| 1834 | StringRef filename = exitOnErr(getFileName(cVStrTab, checksums, *nameIndex)); | |
| 1835 | return {filename, *lineNumber}; | |
| 1771 | 1836 | } |
deps/lld/COFF/PDB.h+9-10| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- PDB.h ----------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -25,13 +24,13 @@ class OutputSection; |
| 25 | 24 | class SectionChunk; |
| 26 | 25 | class SymbolTable; |
| 27 | 26 | |
| 28 | void createPDB(SymbolTable *Symtab, | |
| 29 | llvm::ArrayRef<OutputSection *> OutputSections, | |
| 30 | llvm::ArrayRef<uint8_t> SectionTable, | |
| 31 | llvm::codeview::DebugInfo *BuildId); | |
| 27 | void createPDB(SymbolTable *symtab, | |
| 28 | llvm::ArrayRef<OutputSection *> outputSections, | |
| 29 | llvm::ArrayRef<uint8_t> sectionTable, | |
| 30 | llvm::codeview::DebugInfo *buildId); | |
| 32 | 31 | |
| 33 | std::pair<llvm::StringRef, uint32_t> getFileLine(const SectionChunk *C, | |
| 34 | uint32_t Addr); | |
| 32 | std::pair<llvm::StringRef, uint32_t> getFileLine(const SectionChunk *c, | |
| 33 | uint32_t addr); | |
| 35 | 34 | } |
| 36 | 35 | } |
| 37 | 36 |
deps/lld/COFF/SymbolTable.cpp+392-337| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- SymbolTable.cpp ----------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -17,6 +16,7 @@ |
| 17 | 16 | #include "lld/Common/Memory.h" |
| 18 | 17 | #include "lld/Common/Timer.h" |
| 19 | 18 | #include "llvm/IR/LLVMContext.h" |
| 19 | #include "llvm/Object/WindowsMachineFlag.h" | |
| 20 | 20 | #include "llvm/Support/Debug.h" |
| 21 | 21 | #include "llvm/Support/raw_ostream.h" |
| 22 | 22 | #include <utility> |
| ... | ... | @@ -26,521 +26,576 @@ using namespace llvm; |
| 26 | 26 | namespace lld { |
| 27 | 27 | namespace coff { |
| 28 | 28 | |
| 29 | static Timer LTOTimer("LTO", Timer::root()); | |
| 29 | static Timer ltoTimer("LTO", Timer::root()); | |
| 30 | 30 | |
| 31 | SymbolTable *Symtab; | |
| 31 | SymbolTable *symtab; | |
| 32 | 32 | |
| 33 | void SymbolTable::addFile(InputFile *File) { | |
| 34 | log("Reading " + toString(File)); | |
| 35 | File->parse(); | |
| 33 | void SymbolTable::addFile(InputFile *file) { | |
| 34 | log("Reading " + toString(file)); | |
| 35 | file->parse(); | |
| 36 | 36 | |
| 37 | MachineTypes MT = File->getMachineType(); | |
| 38 | if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { | |
| 39 | Config->Machine = MT; | |
| 40 | } else if (MT != IMAGE_FILE_MACHINE_UNKNOWN && Config->Machine != MT) { | |
| 41 | error(toString(File) + ": machine type " + machineToStr(MT) + | |
| 42 | " conflicts with " + machineToStr(Config->Machine)); | |
| 37 | MachineTypes mt = file->getMachineType(); | |
| 38 | if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) { | |
| 39 | config->machine = mt; | |
| 40 | } else if (mt != IMAGE_FILE_MACHINE_UNKNOWN && config->machine != mt) { | |
| 41 | error(toString(file) + ": machine type " + machineToStr(mt) + | |
| 42 | " conflicts with " + machineToStr(config->machine)); | |
| 43 | 43 | return; |
| 44 | 44 | } |
| 45 | 45 | |
| 46 | if (auto *F = dyn_cast<ObjFile>(File)) { | |
| 47 | ObjFile::Instances.push_back(F); | |
| 48 | } else if (auto *F = dyn_cast<BitcodeFile>(File)) { | |
| 49 | BitcodeFile::Instances.push_back(F); | |
| 50 | } else if (auto *F = dyn_cast<ImportFile>(File)) { | |
| 51 | ImportFile::Instances.push_back(F); | |
| 46 | if (auto *f = dyn_cast<ObjFile>(file)) { | |
| 47 | ObjFile::instances.push_back(f); | |
| 48 | } else if (auto *f = dyn_cast<BitcodeFile>(file)) { | |
| 49 | BitcodeFile::instances.push_back(f); | |
| 50 | } else if (auto *f = dyn_cast<ImportFile>(file)) { | |
| 51 | ImportFile::instances.push_back(f); | |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | StringRef S = File->getDirectives(); | |
| 55 | if (S.empty()) | |
| 56 | return; | |
| 57 | ||
| 58 | log("Directives: " + toString(File) + ": " + S); | |
| 59 | Driver->parseDirectives(S); | |
| 54 | driver->parseDirectives(file); | |
| 60 | 55 | } |
| 61 | 56 | |
| 62 | static void errorOrWarn(const Twine &S) { | |
| 63 | if (Config->ForceUnresolved) | |
| 64 | warn(S); | |
| 57 | static void errorOrWarn(const Twine &s) { | |
| 58 | if (config->forceUnresolved) | |
| 59 | warn(s); | |
| 65 | 60 | else |
| 66 | error(S); | |
| 61 | error(s); | |
| 67 | 62 | } |
| 68 | 63 | |
| 69 | 64 | // Returns the symbol in SC whose value is <= Addr that is closest to Addr. |
| 70 | 65 | // This is generally the global variable or function whose definition contains |
| 71 | 66 | // Addr. |
| 72 | static Symbol *getSymbol(SectionChunk *SC, uint32_t Addr) { | |
| 73 | DefinedRegular *Candidate = nullptr; | |
| 67 | static Symbol *getSymbol(SectionChunk *sc, uint32_t addr) { | |
| 68 | DefinedRegular *candidate = nullptr; | |
| 74 | 69 | |
| 75 | for (Symbol *S : SC->File->getSymbols()) { | |
| 76 | auto *D = dyn_cast_or_null<DefinedRegular>(S); | |
| 77 | if (!D || D->getChunk() != SC || D->getValue() > Addr || | |
| 78 | (Candidate && D->getValue() < Candidate->getValue())) | |
| 70 | for (Symbol *s : sc->file->getSymbols()) { | |
| 71 | auto *d = dyn_cast_or_null<DefinedRegular>(s); | |
| 72 | if (!d || !d->data || d->getChunk() != sc || d->getValue() > addr || | |
| 73 | (candidate && d->getValue() < candidate->getValue())) | |
| 79 | 74 | continue; |
| 80 | 75 | |
| 81 | Candidate = D; | |
| 76 | candidate = d; | |
| 82 | 77 | } |
| 83 | 78 | |
| 84 | return Candidate; | |
| 79 | return candidate; | |
| 85 | 80 | } |
| 86 | 81 | |
| 87 | std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) { | |
| 82 | // Given a file and the index of a symbol in that file, returns a description | |
| 83 | // of all references to that symbol from that file. If no debug information is | |
| 84 | // available, returns just the name of the file, else one string per actual | |
| 85 | // reference as described in the debug info. | |
| 86 | std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex) { | |
| 88 | 87 | struct Location { |
| 89 | Symbol *Sym; | |
| 90 | std::pair<StringRef, uint32_t> FileLine; | |
| 88 | Symbol *sym; | |
| 89 | std::pair<StringRef, uint32_t> fileLine; | |
| 91 | 90 | }; |
| 92 | std::vector<Location> Locations; | |
| 91 | std::vector<Location> locations; | |
| 93 | 92 | |
| 94 | for (Chunk *C : File->getChunks()) { | |
| 95 | auto *SC = dyn_cast<SectionChunk>(C); | |
| 96 | if (!SC) | |
| 93 | for (Chunk *c : file->getChunks()) { | |
| 94 | auto *sc = dyn_cast<SectionChunk>(c); | |
| 95 | if (!sc) | |
| 97 | 96 | continue; |
| 98 | for (const coff_relocation &R : SC->Relocs) { | |
| 99 | if (R.SymbolTableIndex != SymIndex) | |
| 97 | for (const coff_relocation &r : sc->getRelocs()) { | |
| 98 | if (r.SymbolTableIndex != symIndex) | |
| 100 | 99 | continue; |
| 101 | std::pair<StringRef, uint32_t> FileLine = | |
| 102 | getFileLine(SC, R.VirtualAddress); | |
| 103 | Symbol *Sym = getSymbol(SC, R.VirtualAddress); | |
| 104 | if (!FileLine.first.empty() || Sym) | |
| 105 | Locations.push_back({Sym, FileLine}); | |
| 100 | std::pair<StringRef, uint32_t> fileLine = | |
| 101 | getFileLine(sc, r.VirtualAddress); | |
| 102 | Symbol *sym = getSymbol(sc, r.VirtualAddress); | |
| 103 | if (!fileLine.first.empty() || sym) | |
| 104 | locations.push_back({sym, fileLine}); | |
| 106 | 105 | } |
| 107 | 106 | } |
| 108 | 107 | |
| 109 | if (Locations.empty()) | |
| 110 | return "\n>>> referenced by " + toString(File); | |
| 108 | if (locations.empty()) | |
| 109 | return std::vector<std::string>({"\n>>> referenced by " + toString(file)}); | |
| 111 | 110 | |
| 112 | std::string Out; | |
| 113 | llvm::raw_string_ostream OS(Out); | |
| 114 | for (Location Loc : Locations) { | |
| 115 | OS << "\n>>> referenced by "; | |
| 116 | if (!Loc.FileLine.first.empty()) | |
| 117 | OS << Loc.FileLine.first << ":" << Loc.FileLine.second | |
| 111 | std::vector<std::string> symbolLocations(locations.size()); | |
| 112 | size_t i = 0; | |
| 113 | for (Location loc : locations) { | |
| 114 | llvm::raw_string_ostream os(symbolLocations[i++]); | |
| 115 | os << "\n>>> referenced by "; | |
| 116 | if (!loc.fileLine.first.empty()) | |
| 117 | os << loc.fileLine.first << ":" << loc.fileLine.second | |
| 118 | 118 | << "\n>>> "; |
| 119 | OS << toString(File); | |
| 120 | if (Loc.Sym) | |
| 121 | OS << ":(" << toString(*Loc.Sym) << ')'; | |
| 119 | os << toString(file); | |
| 120 | if (loc.sym) | |
| 121 | os << ":(" << toString(*loc.sym) << ')'; | |
| 122 | } | |
| 123 | return symbolLocations; | |
| 124 | } | |
| 125 | ||
| 126 | // For an undefined symbol, stores all files referencing it and the index of | |
| 127 | // the undefined symbol in each file. | |
| 128 | struct UndefinedDiag { | |
| 129 | Symbol *sym; | |
| 130 | struct File { | |
| 131 | ObjFile *oFile; | |
| 132 | uint64_t symIndex; | |
| 133 | }; | |
| 134 | std::vector<File> files; | |
| 135 | }; | |
| 136 | ||
| 137 | static void reportUndefinedSymbol(const UndefinedDiag &undefDiag) { | |
| 138 | std::string out; | |
| 139 | llvm::raw_string_ostream os(out); | |
| 140 | os << "undefined symbol: " << toString(*undefDiag.sym); | |
| 141 | ||
| 142 | const size_t maxUndefReferences = 10; | |
| 143 | size_t i = 0, numRefs = 0; | |
| 144 | for (const UndefinedDiag::File &ref : undefDiag.files) { | |
| 145 | std::vector<std::string> symbolLocations = | |
| 146 | getSymbolLocations(ref.oFile, ref.symIndex); | |
| 147 | numRefs += symbolLocations.size(); | |
| 148 | for (const std::string &s : symbolLocations) { | |
| 149 | if (i >= maxUndefReferences) | |
| 150 | break; | |
| 151 | os << s; | |
| 152 | i++; | |
| 153 | } | |
| 122 | 154 | } |
| 123 | return OS.str(); | |
| 155 | if (i < numRefs) | |
| 156 | os << "\n>>> referenced " << numRefs - i << " more times"; | |
| 157 | errorOrWarn(os.str()); | |
| 124 | 158 | } |
| 125 | 159 | |
| 126 | 160 | void SymbolTable::loadMinGWAutomaticImports() { |
| 127 | for (auto &I : SymMap) { | |
| 128 | Symbol *Sym = I.second; | |
| 129 | auto *Undef = dyn_cast<Undefined>(Sym); | |
| 130 | if (!Undef) | |
| 161 | for (auto &i : symMap) { | |
| 162 | Symbol *sym = i.second; | |
| 163 | auto *undef = dyn_cast<Undefined>(sym); | |
| 164 | if (!undef) | |
| 131 | 165 | continue; |
| 132 | if (!Sym->IsUsedInRegularObj) | |
| 166 | if (!sym->isUsedInRegularObj) | |
| 133 | 167 | continue; |
| 134 | 168 | |
| 135 | StringRef Name = Undef->getName(); | |
| 169 | StringRef name = undef->getName(); | |
| 136 | 170 | |
| 137 | if (Name.startswith("__imp_")) | |
| 171 | if (name.startswith("__imp_")) | |
| 138 | 172 | continue; |
| 139 | 173 | // If we have an undefined symbol, but we have a Lazy representing a |
| 140 | 174 | // symbol we could load from file, make sure to load that. |
| 141 | Lazy *L = dyn_cast_or_null<Lazy>(find(("__imp_" + Name).str())); | |
| 142 | if (!L || L->PendingArchiveLoad) | |
| 175 | Lazy *l = dyn_cast_or_null<Lazy>(find(("__imp_" + name).str())); | |
| 176 | if (!l || l->pendingArchiveLoad) | |
| 143 | 177 | continue; |
| 144 | 178 | |
| 145 | log("Loading lazy " + L->getName() + " from " + L->File->getName() + | |
| 179 | log("Loading lazy " + l->getName() + " from " + l->file->getName() + | |
| 146 | 180 | " for automatic import"); |
| 147 | L->PendingArchiveLoad = true; | |
| 148 | L->File->addMember(&L->Sym); | |
| 181 | l->pendingArchiveLoad = true; | |
| 182 | l->file->addMember(&l->sym); | |
| 149 | 183 | } |
| 150 | 184 | } |
| 151 | 185 | |
| 152 | bool SymbolTable::handleMinGWAutomaticImport(Symbol *Sym, StringRef Name) { | |
| 153 | if (Name.startswith("__imp_")) | |
| 186 | bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) { | |
| 187 | if (name.startswith("__imp_")) | |
| 154 | 188 | return false; |
| 155 | Defined *Imp = dyn_cast_or_null<Defined>(find(("__imp_" + Name).str())); | |
| 156 | if (!Imp) | |
| 189 | Defined *imp = dyn_cast_or_null<Defined>(find(("__imp_" + name).str())); | |
| 190 | if (!imp) | |
| 157 | 191 | return false; |
| 158 | 192 | |
| 159 | 193 | // Replace the reference directly to a variable with a reference |
| 160 | 194 | // to the import address table instead. This obviously isn't right, |
| 161 | // but we mark the symbol as IsRuntimePseudoReloc, and a later pass | |
| 195 | // but we mark the symbol as isRuntimePseudoReloc, and a later pass | |
| 162 | 196 | // will add runtime pseudo relocations for every relocation against |
| 163 | 197 | // this Symbol. The runtime pseudo relocation framework expects the |
| 164 | 198 | // reference itself to point at the IAT entry. |
| 165 | size_t ImpSize = 0; | |
| 166 | if (isa<DefinedImportData>(Imp)) { | |
| 167 | log("Automatically importing " + Name + " from " + | |
| 168 | cast<DefinedImportData>(Imp)->getDLLName()); | |
| 169 | ImpSize = sizeof(DefinedImportData); | |
| 170 | } else if (isa<DefinedRegular>(Imp)) { | |
| 171 | log("Automatically importing " + Name + " from " + | |
| 172 | toString(cast<DefinedRegular>(Imp)->File)); | |
| 173 | ImpSize = sizeof(DefinedRegular); | |
| 199 | size_t impSize = 0; | |
| 200 | if (isa<DefinedImportData>(imp)) { | |
| 201 | log("Automatically importing " + name + " from " + | |
| 202 | cast<DefinedImportData>(imp)->getDLLName()); | |
| 203 | impSize = sizeof(DefinedImportData); | |
| 204 | } else if (isa<DefinedRegular>(imp)) { | |
| 205 | log("Automatically importing " + name + " from " + | |
| 206 | toString(cast<DefinedRegular>(imp)->file)); | |
| 207 | impSize = sizeof(DefinedRegular); | |
| 174 | 208 | } else { |
| 175 | warn("unable to automatically import " + Name + " from " + Imp->getName() + | |
| 176 | " from " + toString(cast<DefinedRegular>(Imp)->File) + | |
| 209 | warn("unable to automatically import " + name + " from " + imp->getName() + | |
| 210 | " from " + toString(cast<DefinedRegular>(imp)->file) + | |
| 177 | 211 | "; unexpected symbol type"); |
| 178 | 212 | return false; |
| 179 | 213 | } |
| 180 | Sym->replaceKeepingName(Imp, ImpSize); | |
| 181 | Sym->IsRuntimePseudoReloc = true; | |
| 214 | sym->replaceKeepingName(imp, impSize); | |
| 215 | sym->isRuntimePseudoReloc = true; | |
| 182 | 216 | |
| 183 | 217 | // There may exist symbols named .refptr.<name> which only consist |
| 184 | 218 | // of a single pointer to <name>. If it turns out <name> is |
| 185 | 219 | // automatically imported, we don't need to keep the .refptr.<name> |
| 186 | 220 | // pointer at all, but redirect all accesses to it to the IAT entry |
| 187 | 221 | // for __imp_<name> instead, and drop the whole .refptr.<name> chunk. |
| 188 | DefinedRegular *Refptr = | |
| 189 | dyn_cast_or_null<DefinedRegular>(find((".refptr." + Name).str())); | |
| 190 | if (Refptr && Refptr->getChunk()->getSize() == Config->Wordsize) { | |
| 191 | SectionChunk *SC = dyn_cast_or_null<SectionChunk>(Refptr->getChunk()); | |
| 192 | if (SC && SC->Relocs.size() == 1 && *SC->symbols().begin() == Sym) { | |
| 193 | log("Replacing .refptr." + Name + " with " + Imp->getName()); | |
| 194 | Refptr->getChunk()->Live = false; | |
| 195 | Refptr->replaceKeepingName(Imp, ImpSize); | |
| 222 | DefinedRegular *refptr = | |
| 223 | dyn_cast_or_null<DefinedRegular>(find((".refptr." + name).str())); | |
| 224 | if (refptr && refptr->getChunk()->getSize() == config->wordsize) { | |
| 225 | SectionChunk *sc = dyn_cast_or_null<SectionChunk>(refptr->getChunk()); | |
| 226 | if (sc && sc->getRelocs().size() == 1 && *sc->symbols().begin() == sym) { | |
| 227 | log("Replacing .refptr." + name + " with " + imp->getName()); | |
| 228 | refptr->getChunk()->live = false; | |
| 229 | refptr->replaceKeepingName(imp, impSize); | |
| 196 | 230 | } |
| 197 | 231 | } |
| 198 | 232 | return true; |
| 199 | 233 | } |
| 200 | 234 | |
| 201 | 235 | void SymbolTable::reportRemainingUndefines() { |
| 202 | SmallPtrSet<Symbol *, 8> Undefs; | |
| 203 | DenseMap<Symbol *, Symbol *> LocalImports; | |
| 236 | SmallPtrSet<Symbol *, 8> undefs; | |
| 237 | DenseMap<Symbol *, Symbol *> localImports; | |
| 204 | 238 | |
| 205 | for (auto &I : SymMap) { | |
| 206 | Symbol *Sym = I.second; | |
| 207 | auto *Undef = dyn_cast<Undefined>(Sym); | |
| 208 | if (!Undef) | |
| 239 | for (auto &i : symMap) { | |
| 240 | Symbol *sym = i.second; | |
| 241 | auto *undef = dyn_cast<Undefined>(sym); | |
| 242 | if (!undef) | |
| 209 | 243 | continue; |
| 210 | if (!Sym->IsUsedInRegularObj) | |
| 244 | if (!sym->isUsedInRegularObj) | |
| 211 | 245 | continue; |
| 212 | 246 | |
| 213 | StringRef Name = Undef->getName(); | |
| 247 | StringRef name = undef->getName(); | |
| 214 | 248 | |
| 215 | 249 | // A weak alias may have been resolved, so check for that. |
| 216 | if (Defined *D = Undef->getWeakAlias()) { | |
| 250 | if (Defined *d = undef->getWeakAlias()) { | |
| 217 | 251 | // We want to replace Sym with D. However, we can't just blindly |
| 218 | 252 | // copy sizeof(SymbolUnion) bytes from D to Sym because D may be an |
| 219 | 253 | // internal symbol, and internal symbols are stored as "unparented" |
| 220 | 254 | // Symbols. For that reason we need to check which type of symbol we |
| 221 | 255 | // are dealing with and copy the correct number of bytes. |
| 222 | if (isa<DefinedRegular>(D)) | |
| 223 | memcpy(Sym, D, sizeof(DefinedRegular)); | |
| 224 | else if (isa<DefinedAbsolute>(D)) | |
| 225 | memcpy(Sym, D, sizeof(DefinedAbsolute)); | |
| 256 | if (isa<DefinedRegular>(d)) | |
| 257 | memcpy(sym, d, sizeof(DefinedRegular)); | |
| 258 | else if (isa<DefinedAbsolute>(d)) | |
| 259 | memcpy(sym, d, sizeof(DefinedAbsolute)); | |
| 226 | 260 | else |
| 227 | memcpy(Sym, D, sizeof(SymbolUnion)); | |
| 261 | memcpy(sym, d, sizeof(SymbolUnion)); | |
| 228 | 262 | continue; |
| 229 | 263 | } |
| 230 | 264 | |
| 231 | 265 | // If we can resolve a symbol by removing __imp_ prefix, do that. |
| 232 | 266 | // This odd rule is for compatibility with MSVC linker. |
| 233 | if (Name.startswith("__imp_")) { | |
| 234 | Symbol *Imp = find(Name.substr(strlen("__imp_"))); | |
| 235 | if (Imp && isa<Defined>(Imp)) { | |
| 236 | auto *D = cast<Defined>(Imp); | |
| 237 | replaceSymbol<DefinedLocalImport>(Sym, Name, D); | |
| 238 | LocalImportChunks.push_back(cast<DefinedLocalImport>(Sym)->getChunk()); | |
| 239 | LocalImports[Sym] = D; | |
| 267 | if (name.startswith("__imp_")) { | |
| 268 | Symbol *imp = find(name.substr(strlen("__imp_"))); | |
| 269 | if (imp && isa<Defined>(imp)) { | |
| 270 | auto *d = cast<Defined>(imp); | |
| 271 | replaceSymbol<DefinedLocalImport>(sym, name, d); | |
| 272 | localImportChunks.push_back(cast<DefinedLocalImport>(sym)->getChunk()); | |
| 273 | localImports[sym] = d; | |
| 240 | 274 | continue; |
| 241 | 275 | } |
| 242 | 276 | } |
| 243 | 277 | |
| 244 | 278 | // We don't want to report missing Microsoft precompiled headers symbols. |
| 245 | 279 | // A proper message will be emitted instead in PDBLinker::aquirePrecompObj |
| 246 | if (Name.contains("_PchSym_")) | |
| 280 | if (name.contains("_PchSym_")) | |
| 247 | 281 | continue; |
| 248 | 282 | |
| 249 | if (Config->MinGW && handleMinGWAutomaticImport(Sym, Name)) | |
| 283 | if (config->mingw && handleMinGWAutomaticImport(sym, name)) | |
| 250 | 284 | continue; |
| 251 | 285 | |
| 252 | 286 | // Remaining undefined symbols are not fatal if /force is specified. |
| 253 | 287 | // They are replaced with dummy defined symbols. |
| 254 | if (Config->ForceUnresolved) | |
| 255 | replaceSymbol<DefinedAbsolute>(Sym, Name, 0); | |
| 256 | Undefs.insert(Sym); | |
| 288 | if (config->forceUnresolved) | |
| 289 | replaceSymbol<DefinedAbsolute>(sym, name, 0); | |
| 290 | undefs.insert(sym); | |
| 257 | 291 | } |
| 258 | 292 | |
| 259 | if (Undefs.empty() && LocalImports.empty()) | |
| 293 | if (undefs.empty() && localImports.empty()) | |
| 260 | 294 | return; |
| 261 | 295 | |
| 262 | for (Symbol *B : Config->GCRoot) { | |
| 263 | if (Undefs.count(B)) | |
| 264 | errorOrWarn("<root>: undefined symbol: " + toString(*B)); | |
| 265 | if (Config->WarnLocallyDefinedImported) | |
| 266 | if (Symbol *Imp = LocalImports.lookup(B)) | |
| 267 | warn("<root>: locally defined symbol imported: " + toString(*Imp) + | |
| 268 | " (defined in " + toString(Imp->getFile()) + ") [LNK4217]"); | |
| 296 | for (Symbol *b : config->gcroot) { | |
| 297 | if (undefs.count(b)) | |
| 298 | errorOrWarn("<root>: undefined symbol: " + toString(*b)); | |
| 299 | if (config->warnLocallyDefinedImported) | |
| 300 | if (Symbol *imp = localImports.lookup(b)) | |
| 301 | warn("<root>: locally defined symbol imported: " + toString(*imp) + | |
| 302 | " (defined in " + toString(imp->getFile()) + ") [LNK4217]"); | |
| 269 | 303 | } |
| 270 | 304 | |
| 271 | for (ObjFile *File : ObjFile::Instances) { | |
| 272 | size_t SymIndex = (size_t)-1; | |
| 273 | for (Symbol *Sym : File->getSymbols()) { | |
| 274 | ++SymIndex; | |
| 275 | if (!Sym) | |
| 305 | std::vector<UndefinedDiag> undefDiags; | |
| 306 | DenseMap<Symbol *, int> firstDiag; | |
| 307 | ||
| 308 | for (ObjFile *file : ObjFile::instances) { | |
| 309 | size_t symIndex = (size_t)-1; | |
| 310 | for (Symbol *sym : file->getSymbols()) { | |
| 311 | ++symIndex; | |
| 312 | if (!sym) | |
| 276 | 313 | continue; |
| 277 | if (Undefs.count(Sym)) | |
| 278 | errorOrWarn("undefined symbol: " + toString(*Sym) + | |
| 279 | getSymbolLocations(File, SymIndex)); | |
| 280 | if (Config->WarnLocallyDefinedImported) | |
| 281 | if (Symbol *Imp = LocalImports.lookup(Sym)) | |
| 282 | warn(toString(File) + | |
| 283 | ": locally defined symbol imported: " + toString(*Imp) + | |
| 284 | " (defined in " + toString(Imp->getFile()) + ") [LNK4217]"); | |
| 314 | if (undefs.count(sym)) { | |
| 315 | auto it = firstDiag.find(sym); | |
| 316 | if (it == firstDiag.end()) { | |
| 317 | firstDiag[sym] = undefDiags.size(); | |
| 318 | undefDiags.push_back({sym, {{file, symIndex}}}); | |
| 319 | } else { | |
| 320 | undefDiags[it->second].files.push_back({file, symIndex}); | |
| 321 | } | |
| 322 | } | |
| 323 | if (config->warnLocallyDefinedImported) | |
| 324 | if (Symbol *imp = localImports.lookup(sym)) | |
| 325 | warn(toString(file) + | |
| 326 | ": locally defined symbol imported: " + toString(*imp) + | |
| 327 | " (defined in " + toString(imp->getFile()) + ") [LNK4217]"); | |
| 285 | 328 | } |
| 286 | 329 | } |
| 330 | ||
| 331 | for (const UndefinedDiag& undefDiag : undefDiags) | |
| 332 | reportUndefinedSymbol(undefDiag); | |
| 287 | 333 | } |
| 288 | 334 | |
| 289 | std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) { | |
| 290 | bool Inserted = false; | |
| 291 | Symbol *&Sym = SymMap[CachedHashStringRef(Name)]; | |
| 292 | if (!Sym) { | |
| 293 | Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); | |
| 294 | Sym->IsUsedInRegularObj = false; | |
| 295 | Sym->PendingArchiveLoad = false; | |
| 296 | Inserted = true; | |
| 335 | std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) { | |
| 336 | bool inserted = false; | |
| 337 | Symbol *&sym = symMap[CachedHashStringRef(name)]; | |
| 338 | if (!sym) { | |
| 339 | sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); | |
| 340 | sym->isUsedInRegularObj = false; | |
| 341 | sym->pendingArchiveLoad = false; | |
| 342 | inserted = true; | |
| 297 | 343 | } |
| 298 | return {Sym, Inserted}; | |
| 344 | return {sym, inserted}; | |
| 299 | 345 | } |
| 300 | 346 | |
| 301 | std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, InputFile *File) { | |
| 302 | std::pair<Symbol *, bool> Result = insert(Name); | |
| 303 | if (!File || !isa<BitcodeFile>(File)) | |
| 304 | Result.first->IsUsedInRegularObj = true; | |
| 305 | return Result; | |
| 347 | std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, InputFile *file) { | |
| 348 | std::pair<Symbol *, bool> result = insert(name); | |
| 349 | if (!file || !isa<BitcodeFile>(file)) | |
| 350 | result.first->isUsedInRegularObj = true; | |
| 351 | return result; | |
| 306 | 352 | } |
| 307 | 353 | |
| 308 | Symbol *SymbolTable::addUndefined(StringRef Name, InputFile *F, | |
| 309 | bool IsWeakAlias) { | |
| 310 | Symbol *S; | |
| 311 | bool WasInserted; | |
| 312 | std::tie(S, WasInserted) = insert(Name, F); | |
| 313 | if (WasInserted || (isa<Lazy>(S) && IsWeakAlias)) { | |
| 314 | replaceSymbol<Undefined>(S, Name); | |
| 315 | return S; | |
| 354 | Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f, | |
| 355 | bool isWeakAlias) { | |
| 356 | Symbol *s; | |
| 357 | bool wasInserted; | |
| 358 | std::tie(s, wasInserted) = insert(name, f); | |
| 359 | if (wasInserted || (isa<Lazy>(s) && isWeakAlias)) { | |
| 360 | replaceSymbol<Undefined>(s, name); | |
| 361 | return s; | |
| 316 | 362 | } |
| 317 | if (auto *L = dyn_cast<Lazy>(S)) { | |
| 318 | if (!S->PendingArchiveLoad) { | |
| 319 | S->PendingArchiveLoad = true; | |
| 320 | L->File->addMember(&L->Sym); | |
| 363 | if (auto *l = dyn_cast<Lazy>(s)) { | |
| 364 | if (!s->pendingArchiveLoad) { | |
| 365 | s->pendingArchiveLoad = true; | |
| 366 | l->file->addMember(&l->sym); | |
| 321 | 367 | } |
| 322 | 368 | } |
| 323 | return S; | |
| 369 | return s; | |
| 324 | 370 | } |
| 325 | 371 | |
| 326 | void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) { | |
| 327 | StringRef Name = Sym.getName(); | |
| 328 | Symbol *S; | |
| 329 | bool WasInserted; | |
| 330 | std::tie(S, WasInserted) = insert(Name); | |
| 331 | if (WasInserted) { | |
| 332 | replaceSymbol<Lazy>(S, F, Sym); | |
| 372 | void SymbolTable::addLazy(ArchiveFile *f, const Archive::Symbol sym) { | |
| 373 | StringRef name = sym.getName(); | |
| 374 | Symbol *s; | |
| 375 | bool wasInserted; | |
| 376 | std::tie(s, wasInserted) = insert(name); | |
| 377 | if (wasInserted) { | |
| 378 | replaceSymbol<Lazy>(s, f, sym); | |
| 333 | 379 | return; |
| 334 | 380 | } |
| 335 | auto *U = dyn_cast<Undefined>(S); | |
| 336 | if (!U || U->WeakAlias || S->PendingArchiveLoad) | |
| 381 | auto *u = dyn_cast<Undefined>(s); | |
| 382 | if (!u || u->weakAlias || s->pendingArchiveLoad) | |
| 337 | 383 | return; |
| 338 | S->PendingArchiveLoad = true; | |
| 339 | F->addMember(&Sym); | |
| 384 | s->pendingArchiveLoad = true; | |
| 385 | f->addMember(&sym); | |
| 340 | 386 | } |
| 341 | 387 | |
| 342 | void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) { | |
| 343 | std::string Msg = "duplicate symbol: " + toString(*Existing) + " in " + | |
| 344 | toString(Existing->getFile()) + " and in " + | |
| 345 | toString(NewFile); | |
| 388 | void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile) { | |
| 389 | std::string msg = "duplicate symbol: " + toString(*existing) + " in " + | |
| 390 | toString(existing->getFile()) + " and in " + | |
| 391 | toString(newFile); | |
| 346 | 392 | |
| 347 | if (Config->ForceMultiple) | |
| 348 | warn(Msg); | |
| 393 | if (config->forceMultiple) | |
| 394 | warn(msg); | |
| 349 | 395 | else |
| 350 | error(Msg); | |
| 396 | error(msg); | |
| 351 | 397 | } |
| 352 | 398 | |
| 353 | Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) { | |
| 354 | Symbol *S; | |
| 355 | bool WasInserted; | |
| 356 | std::tie(S, WasInserted) = insert(N, nullptr); | |
| 357 | S->IsUsedInRegularObj = true; | |
| 358 | if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) | |
| 359 | replaceSymbol<DefinedAbsolute>(S, N, Sym); | |
| 360 | else if (!isa<DefinedCOFF>(S)) | |
| 361 | reportDuplicate(S, nullptr); | |
| 362 | return S; | |
| 399 | Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) { | |
| 400 | Symbol *s; | |
| 401 | bool wasInserted; | |
| 402 | std::tie(s, wasInserted) = insert(n, nullptr); | |
| 403 | s->isUsedInRegularObj = true; | |
| 404 | if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) | |
| 405 | replaceSymbol<DefinedAbsolute>(s, n, sym); | |
| 406 | else if (!isa<DefinedCOFF>(s)) | |
| 407 | reportDuplicate(s, nullptr); | |
| 408 | return s; | |
| 363 | 409 | } |
| 364 | 410 | |
| 365 | Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) { | |
| 366 | Symbol *S; | |
| 367 | bool WasInserted; | |
| 368 | std::tie(S, WasInserted) = insert(N, nullptr); | |
| 369 | S->IsUsedInRegularObj = true; | |
| 370 | if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) | |
| 371 | replaceSymbol<DefinedAbsolute>(S, N, VA); | |
| 372 | else if (!isa<DefinedCOFF>(S)) | |
| 373 | reportDuplicate(S, nullptr); | |
| 374 | return S; | |
| 411 | Symbol *SymbolTable::addAbsolute(StringRef n, uint64_t va) { | |
| 412 | Symbol *s; | |
| 413 | bool wasInserted; | |
| 414 | std::tie(s, wasInserted) = insert(n, nullptr); | |
| 415 | s->isUsedInRegularObj = true; | |
| 416 | if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) | |
| 417 | replaceSymbol<DefinedAbsolute>(s, n, va); | |
| 418 | else if (!isa<DefinedCOFF>(s)) | |
| 419 | reportDuplicate(s, nullptr); | |
| 420 | return s; | |
| 375 | 421 | } |
| 376 | 422 | |
| 377 | Symbol *SymbolTable::addSynthetic(StringRef N, Chunk *C) { | |
| 378 | Symbol *S; | |
| 379 | bool WasInserted; | |
| 380 | std::tie(S, WasInserted) = insert(N, nullptr); | |
| 381 | S->IsUsedInRegularObj = true; | |
| 382 | if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) | |
| 383 | replaceSymbol<DefinedSynthetic>(S, N, C); | |
| 384 | else if (!isa<DefinedCOFF>(S)) | |
| 385 | reportDuplicate(S, nullptr); | |
| 386 | return S; | |
| 423 | Symbol *SymbolTable::addSynthetic(StringRef n, Chunk *c) { | |
| 424 | Symbol *s; | |
| 425 | bool wasInserted; | |
| 426 | std::tie(s, wasInserted) = insert(n, nullptr); | |
| 427 | s->isUsedInRegularObj = true; | |
| 428 | if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) | |
| 429 | replaceSymbol<DefinedSynthetic>(s, n, c); | |
| 430 | else if (!isa<DefinedCOFF>(s)) | |
| 431 | reportDuplicate(s, nullptr); | |
| 432 | return s; | |
| 387 | 433 | } |
| 388 | 434 | |
| 389 | Symbol *SymbolTable::addRegular(InputFile *F, StringRef N, | |
| 390 | const coff_symbol_generic *Sym, | |
| 391 | SectionChunk *C) { | |
| 392 | Symbol *S; | |
| 393 | bool WasInserted; | |
| 394 | std::tie(S, WasInserted) = insert(N, F); | |
| 395 | if (WasInserted || !isa<DefinedRegular>(S)) | |
| 396 | replaceSymbol<DefinedRegular>(S, F, N, /*IsCOMDAT*/ false, | |
| 397 | /*IsExternal*/ true, Sym, C); | |
| 435 | Symbol *SymbolTable::addRegular(InputFile *f, StringRef n, | |
| 436 | const coff_symbol_generic *sym, | |
| 437 | SectionChunk *c) { | |
| 438 | Symbol *s; | |
| 439 | bool wasInserted; | |
| 440 | std::tie(s, wasInserted) = insert(n, f); | |
| 441 | if (wasInserted || !isa<DefinedRegular>(s)) | |
| 442 | replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ false, | |
| 443 | /*IsExternal*/ true, sym, c); | |
| 398 | 444 | else |
| 399 | reportDuplicate(S, F); | |
| 400 | return S; | |
| 445 | reportDuplicate(s, f); | |
| 446 | return s; | |
| 401 | 447 | } |
| 402 | 448 | |
| 403 | std::pair<Symbol *, bool> | |
| 404 | SymbolTable::addComdat(InputFile *F, StringRef N, | |
| 405 | const coff_symbol_generic *Sym) { | |
| 406 | Symbol *S; | |
| 407 | bool WasInserted; | |
| 408 | std::tie(S, WasInserted) = insert(N, F); | |
| 409 | if (WasInserted || !isa<DefinedRegular>(S)) { | |
| 410 | replaceSymbol<DefinedRegular>(S, F, N, /*IsCOMDAT*/ true, | |
| 411 | /*IsExternal*/ true, Sym, nullptr); | |
| 412 | return {S, true}; | |
| 449 | std::pair<DefinedRegular *, bool> | |
| 450 | SymbolTable::addComdat(InputFile *f, StringRef n, | |
| 451 | const coff_symbol_generic *sym) { | |
| 452 | Symbol *s; | |
| 453 | bool wasInserted; | |
| 454 | std::tie(s, wasInserted) = insert(n, f); | |
| 455 | if (wasInserted || !isa<DefinedRegular>(s)) { | |
| 456 | replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ true, | |
| 457 | /*IsExternal*/ true, sym, nullptr); | |
| 458 | return {cast<DefinedRegular>(s), true}; | |
| 413 | 459 | } |
| 414 | if (!cast<DefinedRegular>(S)->isCOMDAT()) | |
| 415 | reportDuplicate(S, F); | |
| 416 | return {S, false}; | |
| 460 | auto *existingSymbol = cast<DefinedRegular>(s); | |
| 461 | if (!existingSymbol->isCOMDAT) | |
| 462 | reportDuplicate(s, f); | |
| 463 | return {existingSymbol, false}; | |
| 417 | 464 | } |
| 418 | 465 | |
| 419 | Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size, | |
| 420 | const coff_symbol_generic *Sym, CommonChunk *C) { | |
| 421 | Symbol *S; | |
| 422 | bool WasInserted; | |
| 423 | std::tie(S, WasInserted) = insert(N, F); | |
| 424 | if (WasInserted || !isa<DefinedCOFF>(S)) | |
| 425 | replaceSymbol<DefinedCommon>(S, F, N, Size, Sym, C); | |
| 426 | else if (auto *DC = dyn_cast<DefinedCommon>(S)) | |
| 427 | if (Size > DC->getSize()) | |
| 428 | replaceSymbol<DefinedCommon>(S, F, N, Size, Sym, C); | |
| 429 | return S; | |
| 466 | Symbol *SymbolTable::addCommon(InputFile *f, StringRef n, uint64_t size, | |
| 467 | const coff_symbol_generic *sym, CommonChunk *c) { | |
| 468 | Symbol *s; | |
| 469 | bool wasInserted; | |
| 470 | std::tie(s, wasInserted) = insert(n, f); | |
| 471 | if (wasInserted || !isa<DefinedCOFF>(s)) | |
| 472 | replaceSymbol<DefinedCommon>(s, f, n, size, sym, c); | |
| 473 | else if (auto *dc = dyn_cast<DefinedCommon>(s)) | |
| 474 | if (size > dc->getSize()) | |
| 475 | replaceSymbol<DefinedCommon>(s, f, n, size, sym, c); | |
| 476 | return s; | |
| 430 | 477 | } |
| 431 | 478 | |
| 432 | Symbol *SymbolTable::addImportData(StringRef N, ImportFile *F) { | |
| 433 | Symbol *S; | |
| 434 | bool WasInserted; | |
| 435 | std::tie(S, WasInserted) = insert(N, nullptr); | |
| 436 | S->IsUsedInRegularObj = true; | |
| 437 | if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) { | |
| 438 | replaceSymbol<DefinedImportData>(S, N, F); | |
| 439 | return S; | |
| 479 | Symbol *SymbolTable::addImportData(StringRef n, ImportFile *f) { | |
| 480 | Symbol *s; | |
| 481 | bool wasInserted; | |
| 482 | std::tie(s, wasInserted) = insert(n, nullptr); | |
| 483 | s->isUsedInRegularObj = true; | |
| 484 | if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) { | |
| 485 | replaceSymbol<DefinedImportData>(s, n, f); | |
| 486 | return s; | |
| 440 | 487 | } |
| 441 | 488 | |
| 442 | reportDuplicate(S, F); | |
| 489 | reportDuplicate(s, f); | |
| 443 | 490 | return nullptr; |
| 444 | 491 | } |
| 445 | 492 | |
| 446 | Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID, | |
| 447 | uint16_t Machine) { | |
| 448 | Symbol *S; | |
| 449 | bool WasInserted; | |
| 450 | std::tie(S, WasInserted) = insert(Name, nullptr); | |
| 451 | S->IsUsedInRegularObj = true; | |
| 452 | if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) { | |
| 453 | replaceSymbol<DefinedImportThunk>(S, Name, ID, Machine); | |
| 454 | return S; | |
| 493 | Symbol *SymbolTable::addImportThunk(StringRef name, DefinedImportData *id, | |
| 494 | uint16_t machine) { | |
| 495 | Symbol *s; | |
| 496 | bool wasInserted; | |
| 497 | std::tie(s, wasInserted) = insert(name, nullptr); | |
| 498 | s->isUsedInRegularObj = true; | |
| 499 | if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) { | |
| 500 | replaceSymbol<DefinedImportThunk>(s, name, id, machine); | |
| 501 | return s; | |
| 455 | 502 | } |
| 456 | 503 | |
| 457 | reportDuplicate(S, ID->File); | |
| 504 | reportDuplicate(s, id->file); | |
| 458 | 505 | return nullptr; |
| 459 | 506 | } |
| 460 | 507 | |
| 461 | 508 | std::vector<Chunk *> SymbolTable::getChunks() { |
| 462 | std::vector<Chunk *> Res; | |
| 463 | for (ObjFile *File : ObjFile::Instances) { | |
| 464 | ArrayRef<Chunk *> V = File->getChunks(); | |
| 465 | Res.insert(Res.end(), V.begin(), V.end()); | |
| 509 | std::vector<Chunk *> res; | |
| 510 | for (ObjFile *file : ObjFile::instances) { | |
| 511 | ArrayRef<Chunk *> v = file->getChunks(); | |
| 512 | res.insert(res.end(), v.begin(), v.end()); | |
| 466 | 513 | } |
| 467 | return Res; | |
| 514 | return res; | |
| 468 | 515 | } |
| 469 | 516 | |
| 470 | Symbol *SymbolTable::find(StringRef Name) { | |
| 471 | return SymMap.lookup(CachedHashStringRef(Name)); | |
| 517 | Symbol *SymbolTable::find(StringRef name) { | |
| 518 | return symMap.lookup(CachedHashStringRef(name)); | |
| 472 | 519 | } |
| 473 | 520 | |
| 474 | Symbol *SymbolTable::findUnderscore(StringRef Name) { | |
| 475 | if (Config->Machine == I386) | |
| 476 | return find(("_" + Name).str()); | |
| 477 | return find(Name); | |
| 521 | Symbol *SymbolTable::findUnderscore(StringRef name) { | |
| 522 | if (config->machine == I386) | |
| 523 | return find(("_" + name).str()); | |
| 524 | return find(name); | |
| 478 | 525 | } |
| 479 | 526 | |
| 480 | StringRef SymbolTable::findByPrefix(StringRef Prefix) { | |
| 481 | for (auto Pair : SymMap) { | |
| 482 | StringRef Name = Pair.first.val(); | |
| 483 | if (Name.startswith(Prefix)) | |
| 484 | return Name; | |
| 527 | // Return all symbols that start with Prefix, possibly ignoring the first | |
| 528 | // character of Prefix or the first character symbol. | |
| 529 | std::vector<Symbol *> SymbolTable::getSymsWithPrefix(StringRef prefix) { | |
| 530 | std::vector<Symbol *> syms; | |
| 531 | for (auto pair : symMap) { | |
| 532 | StringRef name = pair.first.val(); | |
| 533 | if (name.startswith(prefix) || name.startswith(prefix.drop_front()) || | |
| 534 | name.drop_front().startswith(prefix) || | |
| 535 | name.drop_front().startswith(prefix.drop_front())) { | |
| 536 | syms.push_back(pair.second); | |
| 537 | } | |
| 485 | 538 | } |
| 486 | return ""; | |
| 539 | return syms; | |
| 487 | 540 | } |
| 488 | 541 | |
| 489 | StringRef SymbolTable::findMangle(StringRef Name) { | |
| 490 | if (Symbol *Sym = find(Name)) | |
| 491 | if (!isa<Undefined>(Sym)) | |
| 492 | return Name; | |
| 493 | if (Config->Machine != I386) | |
| 494 | return findByPrefix(("?" + Name + "@@Y").str()); | |
| 495 | if (!Name.startswith("_")) | |
| 496 | return ""; | |
| 542 | Symbol *SymbolTable::findMangle(StringRef name) { | |
| 543 | if (Symbol *sym = find(name)) | |
| 544 | if (!isa<Undefined>(sym)) | |
| 545 | return sym; | |
| 546 | ||
| 547 | // Efficient fuzzy string lookup is impossible with a hash table, so iterate | |
| 548 | // the symbol table once and collect all possibly matching symbols into this | |
| 549 | // vector. Then compare each possibly matching symbol with each possible | |
| 550 | // mangling. | |
| 551 | std::vector<Symbol *> syms = getSymsWithPrefix(name); | |
| 552 | auto findByPrefix = [&syms](const Twine &t) -> Symbol * { | |
| 553 | std::string prefix = t.str(); | |
| 554 | for (auto *s : syms) | |
| 555 | if (s->getName().startswith(prefix)) | |
| 556 | return s; | |
| 557 | return nullptr; | |
| 558 | }; | |
| 559 | ||
| 560 | // For non-x86, just look for C++ functions. | |
| 561 | if (config->machine != I386) | |
| 562 | return findByPrefix("?" + name + "@@Y"); | |
| 563 | ||
| 564 | if (!name.startswith("_")) | |
| 565 | return nullptr; | |
| 497 | 566 | // Search for x86 stdcall function. |
| 498 | StringRef S = findByPrefix((Name + "@").str()); | |
| 499 | if (!S.empty()) | |
| 500 | return S; | |
| 567 | if (Symbol *s = findByPrefix(name + "@")) | |
| 568 | return s; | |
| 501 | 569 | // Search for x86 fastcall function. |
| 502 | S = findByPrefix(("@" + Name.substr(1) + "@").str()); | |
| 503 | if (!S.empty()) | |
| 504 | return S; | |
| 570 | if (Symbol *s = findByPrefix("@" + name.substr(1) + "@")) | |
| 571 | return s; | |
| 505 | 572 | // Search for x86 vectorcall function. |
| 506 | S = findByPrefix((Name.substr(1) + "@@").str()); | |
| 507 | if (!S.empty()) | |
| 508 | return S; | |
| 573 | if (Symbol *s = findByPrefix(name.substr(1) + "@@")) | |
| 574 | return s; | |
| 509 | 575 | // Search for x86 C++ non-member function. |
| 510 | return findByPrefix(("?" + Name.substr(1) + "@@Y").str()); | |
| 511 | } | |
| 512 | ||
| 513 | void SymbolTable::mangleMaybe(Symbol *B) { | |
| 514 | auto *U = dyn_cast<Undefined>(B); | |
| 515 | if (!U || U->WeakAlias) | |
| 516 | return; | |
| 517 | StringRef Alias = findMangle(U->getName()); | |
| 518 | if (!Alias.empty()) { | |
| 519 | log(U->getName() + " aliased to " + Alias); | |
| 520 | U->WeakAlias = addUndefined(Alias); | |
| 521 | } | |
| 576 | return findByPrefix("?" + name.substr(1) + "@@Y"); | |
| 522 | 577 | } |
| 523 | 578 | |
| 524 | Symbol *SymbolTable::addUndefined(StringRef Name) { | |
| 525 | return addUndefined(Name, nullptr, false); | |
| 579 | Symbol *SymbolTable::addUndefined(StringRef name) { | |
| 580 | return addUndefined(name, nullptr, false); | |
| 526 | 581 | } |
| 527 | 582 | |
| 528 | 583 | std::vector<StringRef> SymbolTable::compileBitcodeFiles() { |
| 529 | LTO.reset(new BitcodeCompiler); | |
| 530 | for (BitcodeFile *F : BitcodeFile::Instances) | |
| 531 | LTO->add(*F); | |
| 532 | return LTO->compile(); | |
| 584 | lto.reset(new BitcodeCompiler); | |
| 585 | for (BitcodeFile *f : BitcodeFile::instances) | |
| 586 | lto->add(*f); | |
| 587 | return lto->compile(); | |
| 533 | 588 | } |
| 534 | 589 | |
| 535 | 590 | void SymbolTable::addCombinedLTOObjects() { |
| 536 | if (BitcodeFile::Instances.empty()) | |
| 591 | if (BitcodeFile::instances.empty()) | |
| 537 | 592 | return; |
| 538 | 593 | |
| 539 | ScopedTimer T(LTOTimer); | |
| 540 | for (StringRef Object : compileBitcodeFiles()) { | |
| 541 | auto *Obj = make<ObjFile>(MemoryBufferRef(Object, "lto.tmp")); | |
| 542 | Obj->parse(); | |
| 543 | ObjFile::Instances.push_back(Obj); | |
| 594 | ScopedTimer t(ltoTimer); | |
| 595 | for (StringRef object : compileBitcodeFiles()) { | |
| 596 | auto *obj = make<ObjFile>(MemoryBufferRef(object, "lto.tmp")); | |
| 597 | obj->parse(); | |
| 598 | ObjFile::instances.push_back(obj); | |
| 544 | 599 | } |
| 545 | 600 | } |
| 546 | 601 |
deps/lld/COFF/SymbolTable.h+44-44| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- SymbolTable.h --------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -28,6 +27,7 @@ class Chunk; |
| 28 | 27 | class CommonChunk; |
| 29 | 28 | class Defined; |
| 30 | 29 | class DefinedAbsolute; |
| 30 | class DefinedRegular; | |
| 31 | 31 | class DefinedRelative; |
| 32 | 32 | class Lazy; |
| 33 | 33 | class SectionChunk; |
| ... | ... | @@ -47,7 +47,7 @@ class Symbol; |
| 47 | 47 | // There is one add* function per symbol type. |
| 48 | 48 | class SymbolTable { |
| 49 | 49 | public: |
| 50 | void addFile(InputFile *File); | |
| 50 | void addFile(InputFile *file); | |
| 51 | 51 | |
| 52 | 52 | // Try to resolve any undefined symbols and update the symbol table |
| 53 | 53 | // accordingly, then print an error message for any remaining undefined |
| ... | ... | @@ -55,21 +55,20 @@ public: |
| 55 | 55 | void reportRemainingUndefines(); |
| 56 | 56 | |
| 57 | 57 | void loadMinGWAutomaticImports(); |
| 58 | bool handleMinGWAutomaticImport(Symbol *Sym, StringRef Name); | |
| 58 | bool handleMinGWAutomaticImport(Symbol *sym, StringRef name); | |
| 59 | 59 | |
| 60 | 60 | // Returns a list of chunks of selected symbols. |
| 61 | 61 | std::vector<Chunk *> getChunks(); |
| 62 | 62 | |
| 63 | 63 | // Returns a symbol for a given name. Returns a nullptr if not found. |
| 64 | Symbol *find(StringRef Name); | |
| 65 | Symbol *findUnderscore(StringRef Name); | |
| 64 | Symbol *find(StringRef name); | |
| 65 | Symbol *findUnderscore(StringRef name); | |
| 66 | 66 | |
| 67 | 67 | // Occasionally we have to resolve an undefined symbol to its |
| 68 | 68 | // mangled symbol. This function tries to find a mangled name |
| 69 | 69 | // for U from the symbol table, and if found, set the symbol as |
| 70 | 70 | // a weak alias for U. |
| 71 | void mangleMaybe(Symbol *B); | |
| 72 | StringRef findMangle(StringRef Name); | |
| 71 | Symbol *findMangle(StringRef name); | |
| 73 | 72 | |
| 74 | 73 | // Build a set of COFF objects representing the combined contents of |
| 75 | 74 | // BitcodeFiles and add them to the symbol table. Called after all files are |
| ... | ... | @@ -78,52 +77,53 @@ public: |
| 78 | 77 | std::vector<StringRef> compileBitcodeFiles(); |
| 79 | 78 | |
| 80 | 79 | // Creates an Undefined symbol for a given name. |
| 81 | Symbol *addUndefined(StringRef Name); | |
| 82 | ||
| 83 | Symbol *addSynthetic(StringRef N, Chunk *C); | |
| 84 | Symbol *addAbsolute(StringRef N, uint64_t VA); | |
| 85 | ||
| 86 | Symbol *addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias); | |
| 87 | void addLazy(ArchiveFile *F, const Archive::Symbol Sym); | |
| 88 | Symbol *addAbsolute(StringRef N, COFFSymbolRef S); | |
| 89 | Symbol *addRegular(InputFile *F, StringRef N, | |
| 90 | const llvm::object::coff_symbol_generic *S = nullptr, | |
| 91 | SectionChunk *C = nullptr); | |
| 92 | std::pair<Symbol *, bool> | |
| 93 | addComdat(InputFile *F, StringRef N, | |
| 94 | const llvm::object::coff_symbol_generic *S = nullptr); | |
| 95 | Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size, | |
| 96 | const llvm::object::coff_symbol_generic *S = nullptr, | |
| 97 | CommonChunk *C = nullptr); | |
| 98 | Symbol *addImportData(StringRef N, ImportFile *F); | |
| 99 | Symbol *addImportThunk(StringRef Name, DefinedImportData *S, | |
| 100 | uint16_t Machine); | |
| 101 | ||
| 102 | void reportDuplicate(Symbol *Existing, InputFile *NewFile); | |
| 80 | Symbol *addUndefined(StringRef name); | |
| 81 | ||
| 82 | Symbol *addSynthetic(StringRef n, Chunk *c); | |
| 83 | Symbol *addAbsolute(StringRef n, uint64_t va); | |
| 84 | ||
| 85 | Symbol *addUndefined(StringRef name, InputFile *f, bool isWeakAlias); | |
| 86 | void addLazy(ArchiveFile *f, const Archive::Symbol sym); | |
| 87 | Symbol *addAbsolute(StringRef n, COFFSymbolRef s); | |
| 88 | Symbol *addRegular(InputFile *f, StringRef n, | |
| 89 | const llvm::object::coff_symbol_generic *s = nullptr, | |
| 90 | SectionChunk *c = nullptr); | |
| 91 | std::pair<DefinedRegular *, bool> | |
| 92 | addComdat(InputFile *f, StringRef n, | |
| 93 | const llvm::object::coff_symbol_generic *s = nullptr); | |
| 94 | Symbol *addCommon(InputFile *f, StringRef n, uint64_t size, | |
| 95 | const llvm::object::coff_symbol_generic *s = nullptr, | |
| 96 | CommonChunk *c = nullptr); | |
| 97 | Symbol *addImportData(StringRef n, ImportFile *f); | |
| 98 | Symbol *addImportThunk(StringRef name, DefinedImportData *s, | |
| 99 | uint16_t machine); | |
| 100 | ||
| 101 | void reportDuplicate(Symbol *existing, InputFile *newFile); | |
| 103 | 102 | |
| 104 | 103 | // A list of chunks which to be added to .rdata. |
| 105 | std::vector<Chunk *> LocalImportChunks; | |
| 104 | std::vector<Chunk *> localImportChunks; | |
| 106 | 105 | |
| 107 | 106 | // Iterates symbols in non-determinstic hash table order. |
| 108 | template <typename T> void forEachSymbol(T Callback) { | |
| 109 | for (auto &Pair : SymMap) | |
| 110 | Callback(Pair.second); | |
| 107 | template <typename T> void forEachSymbol(T callback) { | |
| 108 | for (auto &pair : symMap) | |
| 109 | callback(pair.second); | |
| 111 | 110 | } |
| 112 | 111 | |
| 113 | 112 | private: |
| 114 | 113 | /// Inserts symbol if not already present. |
| 115 | std::pair<Symbol *, bool> insert(StringRef Name); | |
| 116 | /// Same as insert(Name), but also sets IsUsedInRegularObj. | |
| 117 | std::pair<Symbol *, bool> insert(StringRef Name, InputFile *F); | |
| 118 | StringRef findByPrefix(StringRef Prefix); | |
| 114 | std::pair<Symbol *, bool> insert(StringRef name); | |
| 115 | /// Same as insert(Name), but also sets isUsedInRegularObj. | |
| 116 | std::pair<Symbol *, bool> insert(StringRef name, InputFile *f); | |
| 117 | ||
| 118 | std::vector<Symbol *> getSymsWithPrefix(StringRef prefix); | |
| 119 | 119 | |
| 120 | llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> SymMap; | |
| 121 | std::unique_ptr<BitcodeCompiler> LTO; | |
| 120 | llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> symMap; | |
| 121 | std::unique_ptr<BitcodeCompiler> lto; | |
| 122 | 122 | }; |
| 123 | 123 | |
| 124 | extern SymbolTable *Symtab; | |
| 124 | extern SymbolTable *symtab; | |
| 125 | 125 | |
| 126 | std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex); | |
| 126 | std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex); | |
| 127 | 127 | |
| 128 | 128 | } // namespace coff |
| 129 | 129 | } // namespace lld |
deps/lld/COFF/Symbols.cpp+58-48| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Symbols.cpp --------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -19,11 +18,17 @@ |
| 19 | 18 | using namespace llvm; |
| 20 | 19 | using namespace llvm::object; |
| 21 | 20 | |
| 21 | using namespace lld::coff; | |
| 22 | ||
| 23 | static_assert(sizeof(SymbolUnion) <= 48, | |
| 24 | "symbols should be optimized for memory usage"); | |
| 25 | ||
| 22 | 26 | // Returns a symbol name for an error message. |
| 23 | std::string lld::toString(coff::Symbol &B) { | |
| 24 | if (Optional<std::string> S = lld::demangleMSVC(B.getName())) | |
| 25 | return ("\"" + *S + "\" (" + B.getName() + ")").str(); | |
| 26 | return B.getName(); | |
| 27 | std::string lld::toString(coff::Symbol &b) { | |
| 28 | if (config->demangle) | |
| 29 | if (Optional<std::string> s = lld::demangleMSVC(b.getName())) | |
| 30 | return *s; | |
| 31 | return b.getName(); | |
| 27 | 32 | } |
| 28 | 33 | |
| 29 | 34 | namespace lld { |
| ... | ... | @@ -37,70 +42,75 @@ StringRef Symbol::getName() { |
| 37 | 42 | // name. Object files contain lots of non-external symbols, and creating |
| 38 | 43 | // StringRefs for them (which involves lots of strlen() on the string table) |
| 39 | 44 | // is a waste of time. |
| 40 | if (Name.empty()) { | |
| 41 | auto *D = cast<DefinedCOFF>(this); | |
| 42 | cast<ObjFile>(D->File)->getCOFFObj()->getSymbolName(D->Sym, Name); | |
| 45 | if (nameData == nullptr) { | |
| 46 | auto *d = cast<DefinedCOFF>(this); | |
| 47 | StringRef nameStr; | |
| 48 | cast<ObjFile>(d->file)->getCOFFObj()->getSymbolName(d->sym, nameStr); | |
| 49 | nameData = nameStr.data(); | |
| 50 | nameSize = nameStr.size(); | |
| 51 | assert(nameSize == nameStr.size() && "name length truncated"); | |
| 43 | 52 | } |
| 44 | return Name; | |
| 53 | return StringRef(nameData, nameSize); | |
| 45 | 54 | } |
| 46 | 55 | |
| 47 | 56 | InputFile *Symbol::getFile() { |
| 48 | if (auto *Sym = dyn_cast<DefinedCOFF>(this)) | |
| 49 | return Sym->File; | |
| 50 | if (auto *Sym = dyn_cast<Lazy>(this)) | |
| 51 | return Sym->File; | |
| 57 | if (auto *sym = dyn_cast<DefinedCOFF>(this)) | |
| 58 | return sym->file; | |
| 59 | if (auto *sym = dyn_cast<Lazy>(this)) | |
| 60 | return sym->file; | |
| 52 | 61 | return nullptr; |
| 53 | 62 | } |
| 54 | 63 | |
| 55 | 64 | bool Symbol::isLive() const { |
| 56 | if (auto *R = dyn_cast<DefinedRegular>(this)) | |
| 57 | return R->getChunk()->Live; | |
| 58 | if (auto *Imp = dyn_cast<DefinedImportData>(this)) | |
| 59 | return Imp->File->Live; | |
| 60 | if (auto *Imp = dyn_cast<DefinedImportThunk>(this)) | |
| 61 | return Imp->WrappedSym->File->ThunkLive; | |
| 65 | if (auto *r = dyn_cast<DefinedRegular>(this)) | |
| 66 | return r->getChunk()->live; | |
| 67 | if (auto *imp = dyn_cast<DefinedImportData>(this)) | |
| 68 | return imp->file->live; | |
| 69 | if (auto *imp = dyn_cast<DefinedImportThunk>(this)) | |
| 70 | return imp->wrappedSym->file->thunkLive; | |
| 62 | 71 | // Assume any other kind of symbol is live. |
| 63 | 72 | return true; |
| 64 | 73 | } |
| 65 | 74 | |
| 66 | 75 | // MinGW specific. |
| 67 | void Symbol::replaceKeepingName(Symbol *Other, size_t Size) { | |
| 68 | StringRef OrigName = Name; | |
| 69 | memcpy(this, Other, Size); | |
| 70 | Name = OrigName; | |
| 76 | void Symbol::replaceKeepingName(Symbol *other, size_t size) { | |
| 77 | StringRef origName = getName(); | |
| 78 | memcpy(this, other, size); | |
| 79 | nameData = origName.data(); | |
| 80 | nameSize = origName.size(); | |
| 71 | 81 | } |
| 72 | 82 | |
| 73 | 83 | COFFSymbolRef DefinedCOFF::getCOFFSymbol() { |
| 74 | size_t SymSize = cast<ObjFile>(File)->getCOFFObj()->getSymbolTableEntrySize(); | |
| 75 | if (SymSize == sizeof(coff_symbol16)) | |
| 76 | return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(Sym)); | |
| 77 | assert(SymSize == sizeof(coff_symbol32)); | |
| 78 | return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(Sym)); | |
| 84 | size_t symSize = cast<ObjFile>(file)->getCOFFObj()->getSymbolTableEntrySize(); | |
| 85 | if (symSize == sizeof(coff_symbol16)) | |
| 86 | return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(sym)); | |
| 87 | assert(symSize == sizeof(coff_symbol32)); | |
| 88 | return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(sym)); | |
| 79 | 89 | } |
| 80 | 90 | |
| 81 | uint16_t DefinedAbsolute::NumOutputSections; | |
| 91 | uint16_t DefinedAbsolute::numOutputSections; | |
| 82 | 92 | |
| 83 | static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) { | |
| 84 | if (Machine == AMD64) | |
| 85 | return make<ImportThunkChunkX64>(S); | |
| 86 | if (Machine == I386) | |
| 87 | return make<ImportThunkChunkX86>(S); | |
| 88 | if (Machine == ARM64) | |
| 89 | return make<ImportThunkChunkARM64>(S); | |
| 90 | assert(Machine == ARMNT); | |
| 91 | return make<ImportThunkChunkARM>(S); | |
| 93 | static Chunk *makeImportThunk(DefinedImportData *s, uint16_t machine) { | |
| 94 | if (machine == AMD64) | |
| 95 | return make<ImportThunkChunkX64>(s); | |
| 96 | if (machine == I386) | |
| 97 | return make<ImportThunkChunkX86>(s); | |
| 98 | if (machine == ARM64) | |
| 99 | return make<ImportThunkChunkARM64>(s); | |
| 100 | assert(machine == ARMNT); | |
| 101 | return make<ImportThunkChunkARM>(s); | |
| 92 | 102 | } |
| 93 | 103 | |
| 94 | DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S, | |
| 95 | uint16_t Machine) | |
| 96 | : Defined(DefinedImportThunkKind, Name), WrappedSym(S), | |
| 97 | Data(makeImportThunk(S, Machine)) {} | |
| 104 | DefinedImportThunk::DefinedImportThunk(StringRef name, DefinedImportData *s, | |
| 105 | uint16_t machine) | |
| 106 | : Defined(DefinedImportThunkKind, name), wrappedSym(s), | |
| 107 | data(makeImportThunk(s, machine)) {} | |
| 98 | 108 | |
| 99 | 109 | Defined *Undefined::getWeakAlias() { |
| 100 | 110 | // A weak alias may be a weak alias to another symbol, so check recursively. |
| 101 | for (Symbol *A = WeakAlias; A; A = cast<Undefined>(A)->WeakAlias) | |
| 102 | if (auto *D = dyn_cast<Defined>(A)) | |
| 103 | return D; | |
| 111 | for (Symbol *a = weakAlias; a; a = cast<Undefined>(a)->weakAlias) | |
| 112 | if (auto *d = dyn_cast<Defined>(a)) | |
| 113 | return d; | |
| 104 | 114 | return nullptr; |
| 105 | 115 | } |
| 106 | 116 | } // namespace coff |
deps/lld/COFF/Symbols.h+121-122| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Symbols.h ------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -58,15 +57,12 @@ public: |
| 58 | 57 | LastDefinedKind = DefinedSyntheticKind, |
| 59 | 58 | }; |
| 60 | 59 | |
| 61 | Kind kind() const { return static_cast<Kind>(SymbolKind); } | |
| 62 | ||
| 63 | // Returns true if this is an external symbol. | |
| 64 | bool isExternal() { return IsExternal; } | |
| 60 | Kind kind() const { return static_cast<Kind>(symbolKind); } | |
| 65 | 61 | |
| 66 | 62 | // Returns the symbol name. |
| 67 | 63 | StringRef getName(); |
| 68 | 64 | |
| 69 | void replaceKeepingName(Symbol *Other, size_t Size); | |
| 65 | void replaceKeepingName(Symbol *other, size_t size); | |
| 70 | 66 | |
| 71 | 67 | // Returns the file from which this symbol was created. |
| 72 | 68 | InputFile *getFile(); |
| ... | ... | @@ -77,46 +73,50 @@ public: |
| 77 | 73 | |
| 78 | 74 | protected: |
| 79 | 75 | friend SymbolTable; |
| 80 | explicit Symbol(Kind K, StringRef N = "") | |
| 81 | : SymbolKind(K), IsExternal(true), IsCOMDAT(false), | |
| 82 | WrittenToSymtab(false), PendingArchiveLoad(false), IsGCRoot(false), | |
| 83 | IsRuntimePseudoReloc(false), Name(N) {} | |
| 76 | explicit Symbol(Kind k, StringRef n = "") | |
| 77 | : symbolKind(k), isExternal(true), isCOMDAT(false), | |
| 78 | writtenToSymtab(false), pendingArchiveLoad(false), isGCRoot(false), | |
| 79 | isRuntimePseudoReloc(false), nameSize(n.size()), | |
| 80 | nameData(n.empty() ? nullptr : n.data()) {} | |
| 84 | 81 | |
| 85 | const unsigned SymbolKind : 8; | |
| 86 | unsigned IsExternal : 1; | |
| 82 | const unsigned symbolKind : 8; | |
| 83 | unsigned isExternal : 1; | |
| 87 | 84 | |
| 85 | public: | |
| 88 | 86 | // This bit is used by the \c DefinedRegular subclass. |
| 89 | unsigned IsCOMDAT : 1; | |
| 87 | unsigned isCOMDAT : 1; | |
| 90 | 88 | |
| 91 | public: | |
| 92 | 89 | // This bit is used by Writer::createSymbolAndStringTable() to prevent |
| 93 | 90 | // symbols from being written to the symbol table more than once. |
| 94 | unsigned WrittenToSymtab : 1; | |
| 91 | unsigned writtenToSymtab : 1; | |
| 95 | 92 | |
| 96 | 93 | // True if this symbol was referenced by a regular (non-bitcode) object. |
| 97 | unsigned IsUsedInRegularObj : 1; | |
| 94 | unsigned isUsedInRegularObj : 1; | |
| 98 | 95 | |
| 99 | 96 | // True if we've seen both a lazy and an undefined symbol with this symbol |
| 100 | 97 | // name, which means that we have enqueued an archive member load and should |
| 101 | 98 | // not load any more archive members to resolve the same symbol. |
| 102 | unsigned PendingArchiveLoad : 1; | |
| 99 | unsigned pendingArchiveLoad : 1; | |
| 103 | 100 | |
| 104 | 101 | /// True if we've already added this symbol to the list of GC roots. |
| 105 | unsigned IsGCRoot : 1; | |
| 102 | unsigned isGCRoot : 1; | |
| 106 | 103 | |
| 107 | unsigned IsRuntimePseudoReloc : 1; | |
| 104 | unsigned isRuntimePseudoReloc : 1; | |
| 108 | 105 | |
| 109 | 106 | protected: |
| 110 | StringRef Name; | |
| 107 | // Symbol name length. Assume symbol lengths fit in a 32-bit integer. | |
| 108 | uint32_t nameSize; | |
| 109 | ||
| 110 | const char *nameData; | |
| 111 | 111 | }; |
| 112 | 112 | |
| 113 | 113 | // The base class for any defined symbols, including absolute symbols, |
| 114 | 114 | // etc. |
| 115 | 115 | class Defined : public Symbol { |
| 116 | 116 | public: |
| 117 | Defined(Kind K, StringRef N) : Symbol(K, N) {} | |
| 117 | Defined(Kind k, StringRef n) : Symbol(k, n) {} | |
| 118 | 118 | |
| 119 | static bool classof(const Symbol *S) { return S->kind() <= LastDefinedKind; } | |
| 119 | static bool classof(const Symbol *s) { return s->kind() <= LastDefinedKind; } | |
| 120 | 120 | |
| 121 | 121 | // Returns the RVA (relative virtual address) of this symbol. The |
| 122 | 122 | // writer sets and uses RVAs. |
| ... | ... | @@ -130,120 +130,119 @@ public: |
| 130 | 130 | // Symbols defined via a COFF object file or bitcode file. For COFF files, this |
| 131 | 131 | // stores a coff_symbol_generic*, and names of internal symbols are lazily |
| 132 | 132 | // loaded through that. For bitcode files, Sym is nullptr and the name is stored |
| 133 | // as a StringRef. | |
| 133 | // as a decomposed StringRef. | |
| 134 | 134 | class DefinedCOFF : public Defined { |
| 135 | 135 | friend Symbol; |
| 136 | 136 | |
| 137 | 137 | public: |
| 138 | DefinedCOFF(Kind K, InputFile *F, StringRef N, const coff_symbol_generic *S) | |
| 139 | : Defined(K, N), File(F), Sym(S) {} | |
| 138 | DefinedCOFF(Kind k, InputFile *f, StringRef n, const coff_symbol_generic *s) | |
| 139 | : Defined(k, n), file(f), sym(s) {} | |
| 140 | 140 | |
| 141 | static bool classof(const Symbol *S) { | |
| 142 | return S->kind() <= LastDefinedCOFFKind; | |
| 141 | static bool classof(const Symbol *s) { | |
| 142 | return s->kind() <= LastDefinedCOFFKind; | |
| 143 | 143 | } |
| 144 | 144 | |
| 145 | InputFile *getFile() { return File; } | |
| 145 | InputFile *getFile() { return file; } | |
| 146 | 146 | |
| 147 | 147 | COFFSymbolRef getCOFFSymbol(); |
| 148 | 148 | |
| 149 | InputFile *File; | |
| 149 | InputFile *file; | |
| 150 | 150 | |
| 151 | 151 | protected: |
| 152 | const coff_symbol_generic *Sym; | |
| 152 | const coff_symbol_generic *sym; | |
| 153 | 153 | }; |
| 154 | 154 | |
| 155 | 155 | // Regular defined symbols read from object file symbol tables. |
| 156 | 156 | class DefinedRegular : public DefinedCOFF { |
| 157 | 157 | public: |
| 158 | DefinedRegular(InputFile *F, StringRef N, bool IsCOMDAT, | |
| 159 | bool IsExternal = false, | |
| 160 | const coff_symbol_generic *S = nullptr, | |
| 161 | SectionChunk *C = nullptr) | |
| 162 | : DefinedCOFF(DefinedRegularKind, F, N, S), Data(C ? &C->Repl : nullptr) { | |
| 163 | this->IsExternal = IsExternal; | |
| 164 | this->IsCOMDAT = IsCOMDAT; | |
| 158 | DefinedRegular(InputFile *f, StringRef n, bool isCOMDAT, | |
| 159 | bool isExternal = false, | |
| 160 | const coff_symbol_generic *s = nullptr, | |
| 161 | SectionChunk *c = nullptr) | |
| 162 | : DefinedCOFF(DefinedRegularKind, f, n, s), data(c ? &c->repl : nullptr) { | |
| 163 | this->isExternal = isExternal; | |
| 164 | this->isCOMDAT = isCOMDAT; | |
| 165 | 165 | } |
| 166 | 166 | |
| 167 | static bool classof(const Symbol *S) { | |
| 168 | return S->kind() == DefinedRegularKind; | |
| 167 | static bool classof(const Symbol *s) { | |
| 168 | return s->kind() == DefinedRegularKind; | |
| 169 | 169 | } |
| 170 | 170 | |
| 171 | uint64_t getRVA() const { return (*Data)->getRVA() + Sym->Value; } | |
| 172 | bool isCOMDAT() const { return IsCOMDAT; } | |
| 173 | SectionChunk *getChunk() const { return *Data; } | |
| 174 | uint32_t getValue() const { return Sym->Value; } | |
| 171 | uint64_t getRVA() const { return (*data)->getRVA() + sym->Value; } | |
| 172 | SectionChunk *getChunk() const { return *data; } | |
| 173 | uint32_t getValue() const { return sym->Value; } | |
| 175 | 174 | |
| 176 | SectionChunk **Data; | |
| 175 | SectionChunk **data; | |
| 177 | 176 | }; |
| 178 | 177 | |
| 179 | 178 | class DefinedCommon : public DefinedCOFF { |
| 180 | 179 | public: |
| 181 | DefinedCommon(InputFile *F, StringRef N, uint64_t Size, | |
| 182 | const coff_symbol_generic *S = nullptr, | |
| 183 | CommonChunk *C = nullptr) | |
| 184 | : DefinedCOFF(DefinedCommonKind, F, N, S), Data(C), Size(Size) { | |
| 185 | this->IsExternal = true; | |
| 180 | DefinedCommon(InputFile *f, StringRef n, uint64_t size, | |
| 181 | const coff_symbol_generic *s = nullptr, | |
| 182 | CommonChunk *c = nullptr) | |
| 183 | : DefinedCOFF(DefinedCommonKind, f, n, s), data(c), size(size) { | |
| 184 | this->isExternal = true; | |
| 186 | 185 | } |
| 187 | 186 | |
| 188 | static bool classof(const Symbol *S) { | |
| 189 | return S->kind() == DefinedCommonKind; | |
| 187 | static bool classof(const Symbol *s) { | |
| 188 | return s->kind() == DefinedCommonKind; | |
| 190 | 189 | } |
| 191 | 190 | |
| 192 | uint64_t getRVA() { return Data->getRVA(); } | |
| 193 | CommonChunk *getChunk() { return Data; } | |
| 191 | uint64_t getRVA() { return data->getRVA(); } | |
| 192 | CommonChunk *getChunk() { return data; } | |
| 194 | 193 | |
| 195 | 194 | private: |
| 196 | 195 | friend SymbolTable; |
| 197 | uint64_t getSize() const { return Size; } | |
| 198 | CommonChunk *Data; | |
| 199 | uint64_t Size; | |
| 196 | uint64_t getSize() const { return size; } | |
| 197 | CommonChunk *data; | |
| 198 | uint64_t size; | |
| 200 | 199 | }; |
| 201 | 200 | |
| 202 | 201 | // Absolute symbols. |
| 203 | 202 | class DefinedAbsolute : public Defined { |
| 204 | 203 | public: |
| 205 | DefinedAbsolute(StringRef N, COFFSymbolRef S) | |
| 206 | : Defined(DefinedAbsoluteKind, N), VA(S.getValue()) { | |
| 207 | IsExternal = S.isExternal(); | |
| 204 | DefinedAbsolute(StringRef n, COFFSymbolRef s) | |
| 205 | : Defined(DefinedAbsoluteKind, n), va(s.getValue()) { | |
| 206 | isExternal = s.isExternal(); | |
| 208 | 207 | } |
| 209 | 208 | |
| 210 | DefinedAbsolute(StringRef N, uint64_t V) | |
| 211 | : Defined(DefinedAbsoluteKind, N), VA(V) {} | |
| 209 | DefinedAbsolute(StringRef n, uint64_t v) | |
| 210 | : Defined(DefinedAbsoluteKind, n), va(v) {} | |
| 212 | 211 | |
| 213 | static bool classof(const Symbol *S) { | |
| 214 | return S->kind() == DefinedAbsoluteKind; | |
| 212 | static bool classof(const Symbol *s) { | |
| 213 | return s->kind() == DefinedAbsoluteKind; | |
| 215 | 214 | } |
| 216 | 215 | |
| 217 | uint64_t getRVA() { return VA - Config->ImageBase; } | |
| 218 | void setVA(uint64_t V) { VA = V; } | |
| 216 | uint64_t getRVA() { return va - config->imageBase; } | |
| 217 | void setVA(uint64_t v) { va = v; } | |
| 219 | 218 | |
| 220 | 219 | // Section index relocations against absolute symbols resolve to |
| 221 | 220 | // this 16 bit number, and it is the largest valid section index |
| 222 | 221 | // plus one. This variable keeps it. |
| 223 | static uint16_t NumOutputSections; | |
| 222 | static uint16_t numOutputSections; | |
| 224 | 223 | |
| 225 | 224 | private: |
| 226 | uint64_t VA; | |
| 225 | uint64_t va; | |
| 227 | 226 | }; |
| 228 | 227 | |
| 229 | 228 | // This symbol is used for linker-synthesized symbols like __ImageBase and |
| 230 | 229 | // __safe_se_handler_table. |
| 231 | 230 | class DefinedSynthetic : public Defined { |
| 232 | 231 | public: |
| 233 | explicit DefinedSynthetic(StringRef Name, Chunk *C) | |
| 234 | : Defined(DefinedSyntheticKind, Name), C(C) {} | |
| 232 | explicit DefinedSynthetic(StringRef name, Chunk *c) | |
| 233 | : Defined(DefinedSyntheticKind, name), c(c) {} | |
| 235 | 234 | |
| 236 | static bool classof(const Symbol *S) { | |
| 237 | return S->kind() == DefinedSyntheticKind; | |
| 235 | static bool classof(const Symbol *s) { | |
| 236 | return s->kind() == DefinedSyntheticKind; | |
| 238 | 237 | } |
| 239 | 238 | |
| 240 | 239 | // A null chunk indicates that this is __ImageBase. Otherwise, this is some |
| 241 | 240 | // other synthesized chunk, like SEHTableChunk. |
| 242 | uint32_t getRVA() { return C ? C->getRVA() : 0; } | |
| 243 | Chunk *getChunk() { return C; } | |
| 241 | uint32_t getRVA() { return c ? c->getRVA() : 0; } | |
| 242 | Chunk *getChunk() { return c; } | |
| 244 | 243 | |
| 245 | 244 | private: |
| 246 | Chunk *C; | |
| 245 | Chunk *c; | |
| 247 | 246 | }; |
| 248 | 247 | |
| 249 | 248 | // This class represents a symbol defined in an archive file. It is |
| ... | ... | @@ -253,32 +252,32 @@ private: |
| 253 | 252 | // the same name, it will ask the Lazy to load a file. |
| 254 | 253 | class Lazy : public Symbol { |
| 255 | 254 | public: |
| 256 | Lazy(ArchiveFile *F, const Archive::Symbol S) | |
| 257 | : Symbol(LazyKind, S.getName()), File(F), Sym(S) {} | |
| 255 | Lazy(ArchiveFile *f, const Archive::Symbol s) | |
| 256 | : Symbol(LazyKind, s.getName()), file(f), sym(s) {} | |
| 258 | 257 | |
| 259 | static bool classof(const Symbol *S) { return S->kind() == LazyKind; } | |
| 258 | static bool classof(const Symbol *s) { return s->kind() == LazyKind; } | |
| 260 | 259 | |
| 261 | ArchiveFile *File; | |
| 260 | ArchiveFile *file; | |
| 262 | 261 | |
| 263 | 262 | private: |
| 264 | 263 | friend SymbolTable; |
| 265 | 264 | |
| 266 | 265 | private: |
| 267 | const Archive::Symbol Sym; | |
| 266 | const Archive::Symbol sym; | |
| 268 | 267 | }; |
| 269 | 268 | |
| 270 | 269 | // Undefined symbols. |
| 271 | 270 | class Undefined : public Symbol { |
| 272 | 271 | public: |
| 273 | explicit Undefined(StringRef N) : Symbol(UndefinedKind, N) {} | |
| 272 | explicit Undefined(StringRef n) : Symbol(UndefinedKind, n) {} | |
| 274 | 273 | |
| 275 | static bool classof(const Symbol *S) { return S->kind() == UndefinedKind; } | |
| 274 | static bool classof(const Symbol *s) { return s->kind() == UndefinedKind; } | |
| 276 | 275 | |
| 277 | 276 | // An undefined symbol can have a fallback symbol which gives an |
| 278 | 277 | // undefined symbol a second chance if it would remain undefined. |
| 279 | 278 | // If it remains undefined, it'll be replaced with whatever the |
| 280 | 279 | // Alias pointer points to. |
| 281 | Symbol *WeakAlias = nullptr; | |
| 280 | Symbol *weakAlias = nullptr; | |
| 282 | 281 | |
| 283 | 282 | // If this symbol is external weak, try to resolve it to a defined |
| 284 | 283 | // symbol by searching the chain of fallback symbols. Returns the symbol if |
| ... | ... | @@ -294,23 +293,23 @@ public: |
| 294 | 293 | // table in an output. The former has "__imp_" prefix. |
| 295 | 294 | class DefinedImportData : public Defined { |
| 296 | 295 | public: |
| 297 | DefinedImportData(StringRef N, ImportFile *F) | |
| 298 | : Defined(DefinedImportDataKind, N), File(F) { | |
| 296 | DefinedImportData(StringRef n, ImportFile *f) | |
| 297 | : Defined(DefinedImportDataKind, n), file(f) { | |
| 299 | 298 | } |
| 300 | 299 | |
| 301 | static bool classof(const Symbol *S) { | |
| 302 | return S->kind() == DefinedImportDataKind; | |
| 300 | static bool classof(const Symbol *s) { | |
| 301 | return s->kind() == DefinedImportDataKind; | |
| 303 | 302 | } |
| 304 | 303 | |
| 305 | uint64_t getRVA() { return File->Location->getRVA(); } | |
| 306 | Chunk *getChunk() { return File->Location; } | |
| 307 | void setLocation(Chunk *AddressTable) { File->Location = AddressTable; } | |
| 304 | uint64_t getRVA() { return file->location->getRVA(); } | |
| 305 | Chunk *getChunk() { return file->location; } | |
| 306 | void setLocation(Chunk *addressTable) { file->location = addressTable; } | |
| 308 | 307 | |
| 309 | StringRef getDLLName() { return File->DLLName; } | |
| 310 | StringRef getExternalName() { return File->ExternalName; } | |
| 311 | uint16_t getOrdinal() { return File->Hdr->OrdinalHint; } | |
| 308 | StringRef getDLLName() { return file->dllName; } | |
| 309 | StringRef getExternalName() { return file->externalName; } | |
| 310 | uint16_t getOrdinal() { return file->hdr->OrdinalHint; } | |
| 312 | 311 | |
| 313 | ImportFile *File; | |
| 312 | ImportFile *file; | |
| 314 | 313 | }; |
| 315 | 314 | |
| 316 | 315 | // This class represents a symbol for a jump table entry which jumps |
| ... | ... | @@ -320,19 +319,19 @@ public: |
| 320 | 319 | // a regular name. A function pointer is given as a DefinedImportData. |
| 321 | 320 | class DefinedImportThunk : public Defined { |
| 322 | 321 | public: |
| 323 | DefinedImportThunk(StringRef Name, DefinedImportData *S, uint16_t Machine); | |
| 322 | DefinedImportThunk(StringRef name, DefinedImportData *s, uint16_t machine); | |
| 324 | 323 | |
| 325 | static bool classof(const Symbol *S) { | |
| 326 | return S->kind() == DefinedImportThunkKind; | |
| 324 | static bool classof(const Symbol *s) { | |
| 325 | return s->kind() == DefinedImportThunkKind; | |
| 327 | 326 | } |
| 328 | 327 | |
| 329 | uint64_t getRVA() { return Data->getRVA(); } | |
| 330 | Chunk *getChunk() { return Data; } | |
| 328 | uint64_t getRVA() { return data->getRVA(); } | |
| 329 | Chunk *getChunk() { return data; } | |
| 331 | 330 | |
| 332 | DefinedImportData *WrappedSym; | |
| 331 | DefinedImportData *wrappedSym; | |
| 333 | 332 | |
| 334 | 333 | private: |
| 335 | Chunk *Data; | |
| 334 | Chunk *data; | |
| 336 | 335 | }; |
| 337 | 336 | |
| 338 | 337 | // If you have a symbol "foo" in your object file, a symbol name |
| ... | ... | @@ -342,18 +341,18 @@ private: |
| 342 | 341 | // This is here just for compatibility with MSVC. |
| 343 | 342 | class DefinedLocalImport : public Defined { |
| 344 | 343 | public: |
| 345 | DefinedLocalImport(StringRef N, Defined *S) | |
| 346 | : Defined(DefinedLocalImportKind, N), Data(make<LocalImportChunk>(S)) {} | |
| 344 | DefinedLocalImport(StringRef n, Defined *s) | |
| 345 | : Defined(DefinedLocalImportKind, n), data(make<LocalImportChunk>(s)) {} | |
| 347 | 346 | |
| 348 | static bool classof(const Symbol *S) { | |
| 349 | return S->kind() == DefinedLocalImportKind; | |
| 347 | static bool classof(const Symbol *s) { | |
| 348 | return s->kind() == DefinedLocalImportKind; | |
| 350 | 349 | } |
| 351 | 350 | |
| 352 | uint64_t getRVA() { return Data->getRVA(); } | |
| 353 | Chunk *getChunk() { return Data; } | |
| 351 | uint64_t getRVA() { return data->getRVA(); } | |
| 352 | Chunk *getChunk() { return data; } | |
| 354 | 353 | |
| 355 | 354 | private: |
| 356 | LocalImportChunk *Data; | |
| 355 | LocalImportChunk *data; | |
| 357 | 356 | }; |
| 358 | 357 | |
| 359 | 358 | inline uint64_t Defined::getRVA() { |
| ... | ... | @@ -406,19 +405,19 @@ inline Chunk *Defined::getChunk() { |
| 406 | 405 | // object. We allocate memory using this class and instantiate a symbol |
| 407 | 406 | // using the placement new. |
| 408 | 407 | union SymbolUnion { |
| 409 | alignas(DefinedRegular) char A[sizeof(DefinedRegular)]; | |
| 410 | alignas(DefinedCommon) char B[sizeof(DefinedCommon)]; | |
| 411 | alignas(DefinedAbsolute) char C[sizeof(DefinedAbsolute)]; | |
| 412 | alignas(DefinedSynthetic) char D[sizeof(DefinedSynthetic)]; | |
| 413 | alignas(Lazy) char E[sizeof(Lazy)]; | |
| 414 | alignas(Undefined) char F[sizeof(Undefined)]; | |
| 415 | alignas(DefinedImportData) char G[sizeof(DefinedImportData)]; | |
| 416 | alignas(DefinedImportThunk) char H[sizeof(DefinedImportThunk)]; | |
| 417 | alignas(DefinedLocalImport) char I[sizeof(DefinedLocalImport)]; | |
| 408 | alignas(DefinedRegular) char a[sizeof(DefinedRegular)]; | |
| 409 | alignas(DefinedCommon) char b[sizeof(DefinedCommon)]; | |
| 410 | alignas(DefinedAbsolute) char c[sizeof(DefinedAbsolute)]; | |
| 411 | alignas(DefinedSynthetic) char d[sizeof(DefinedSynthetic)]; | |
| 412 | alignas(Lazy) char e[sizeof(Lazy)]; | |
| 413 | alignas(Undefined) char f[sizeof(Undefined)]; | |
| 414 | alignas(DefinedImportData) char g[sizeof(DefinedImportData)]; | |
| 415 | alignas(DefinedImportThunk) char h[sizeof(DefinedImportThunk)]; | |
| 416 | alignas(DefinedLocalImport) char i[sizeof(DefinedLocalImport)]; | |
| 418 | 417 | }; |
| 419 | 418 | |
| 420 | 419 | template <typename T, typename... ArgT> |
| 421 | void replaceSymbol(Symbol *S, ArgT &&... Arg) { | |
| 420 | void replaceSymbol(Symbol *s, ArgT &&... arg) { | |
| 422 | 421 | static_assert(std::is_trivially_destructible<T>(), |
| 423 | 422 | "Symbol types must be trivially destructible"); |
| 424 | 423 | static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small"); |
| ... | ... | @@ -426,11 +425,11 @@ void replaceSymbol(Symbol *S, ArgT &&... Arg) { |
| 426 | 425 | "SymbolUnion not aligned enough"); |
| 427 | 426 | assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr && |
| 428 | 427 | "Not a Symbol"); |
| 429 | new (S) T(std::forward<ArgT>(Arg)...); | |
| 428 | new (s) T(std::forward<ArgT>(arg)...); | |
| 430 | 429 | } |
| 431 | 430 | } // namespace coff |
| 432 | 431 | |
| 433 | std::string toString(coff::Symbol &B); | |
| 432 | std::string toString(coff::Symbol &b); | |
| 434 | 433 | } // namespace lld |
| 435 | 434 | |
| 436 | 435 | #endif |
deps/lld/COFF/TypeMerger.h created+65| ... | ... | @@ -0,0 +1,65 @@ |
| 1 | //===- TypeMerger.h ---------------------------------------------*- C++ -*-===// | |
| 2 | // | |
| 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 | |
| 6 | // | |
| 7 | //===----------------------------------------------------------------------===// | |
| 8 | ||
| 9 | #ifndef LLD_COFF_TYPEMERGER_H | |
| 10 | #define LLD_COFF_TYPEMERGER_H | |
| 11 | ||
| 12 | #include "Config.h" | |
| 13 | #include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h" | |
| 14 | #include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h" | |
| 15 | #include "llvm/Support/Allocator.h" | |
| 16 | ||
| 17 | namespace lld { | |
| 18 | namespace coff { | |
| 19 | ||
| 20 | class TypeMerger { | |
| 21 | public: | |
| 22 | TypeMerger(llvm::BumpPtrAllocator &alloc) | |
| 23 | : typeTable(alloc), iDTable(alloc), globalTypeTable(alloc), | |
| 24 | globalIDTable(alloc) {} | |
| 25 | ||
| 26 | /// Get the type table or the global type table if /DEBUG:GHASH is enabled. | |
| 27 | inline llvm::codeview::TypeCollection &getTypeTable() { | |
| 28 | if (config->debugGHashes) | |
| 29 | return globalTypeTable; | |
| 30 | return typeTable; | |
| 31 | } | |
| 32 | ||
| 33 | /// Get the ID table or the global ID table if /DEBUG:GHASH is enabled. | |
| 34 | inline llvm::codeview::TypeCollection &getIDTable() { | |
| 35 | if (config->debugGHashes) | |
| 36 | return globalIDTable; | |
| 37 | return iDTable; | |
| 38 | } | |
| 39 | ||
| 40 | /// Type records that will go into the PDB TPI stream. | |
| 41 | llvm::codeview::MergingTypeTableBuilder typeTable; | |
| 42 | ||
| 43 | /// Item records that will go into the PDB IPI stream. | |
| 44 | llvm::codeview::MergingTypeTableBuilder iDTable; | |
| 45 | ||
| 46 | /// Type records that will go into the PDB TPI stream (for /DEBUG:GHASH) | |
| 47 | llvm::codeview::GlobalTypeTableBuilder globalTypeTable; | |
| 48 | ||
| 49 | /// Item records that will go into the PDB IPI stream (for /DEBUG:GHASH) | |
| 50 | llvm::codeview::GlobalTypeTableBuilder globalIDTable; | |
| 51 | }; | |
| 52 | ||
| 53 | /// Map from type index and item index in a type server PDB to the | |
| 54 | /// corresponding index in the destination PDB. | |
| 55 | struct CVIndexMap { | |
| 56 | llvm::SmallVector<llvm::codeview::TypeIndex, 0> tpiMap; | |
| 57 | llvm::SmallVector<llvm::codeview::TypeIndex, 0> ipiMap; | |
| 58 | bool isTypeServerMap = false; | |
| 59 | bool isPrecompiledTypeMap = false; | |
| 60 | }; | |
| 61 | ||
| 62 | } // namespace coff | |
| 63 | } // namespace lld | |
| 64 | ||
| 65 | #endif | |
| \ No newline at end of file |
deps/lld/COFF/Writer.cpp+1111-936| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Writer.cpp ---------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -17,6 +16,7 @@ |
| 17 | 16 | #include "Symbols.h" |
| 18 | 17 | #include "lld/Common/ErrorHandler.h" |
| 19 | 18 | #include "lld/Common/Memory.h" |
| 19 | #include "lld/Common/Threads.h" | |
| 20 | 20 | #include "lld/Common/Timer.h" |
| 21 | 21 | #include "llvm/ADT/DenseMap.h" |
| 22 | 22 | #include "llvm/ADT/STLExtras.h" |
| ... | ... | @@ -63,104 +63,129 @@ align 8, db 0 |
| 63 | 63 | $ nasm -fbin /tmp/DOSProgram.asm -o /tmp/DOSProgram.bin |
| 64 | 64 | $ xxd -i /tmp/DOSProgram.bin |
| 65 | 65 | */ |
| 66 | static unsigned char DOSProgram[] = { | |
| 66 | static unsigned char dosProgram[] = { | |
| 67 | 67 | 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, |
| 68 | 68 | 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, |
| 69 | 69 | 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, |
| 70 | 70 | 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, |
| 71 | 71 | 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x24, 0x00, 0x00 |
| 72 | 72 | }; |
| 73 | static_assert(sizeof(DOSProgram) % 8 == 0, | |
| 73 | static_assert(sizeof(dosProgram) % 8 == 0, | |
| 74 | 74 | "DOSProgram size must be multiple of 8"); |
| 75 | 75 | |
| 76 | static const int SectorSize = 512; | |
| 77 | static const int DOSStubSize = sizeof(dos_header) + sizeof(DOSProgram); | |
| 78 | static_assert(DOSStubSize % 8 == 0, "DOSStub size must be multiple of 8"); | |
| 76 | static const int dosStubSize = sizeof(dos_header) + sizeof(dosProgram); | |
| 77 | static_assert(dosStubSize % 8 == 0, "DOSStub size must be multiple of 8"); | |
| 78 | ||
| 79 | static const int numberOfDataDirectory = 16; | |
| 79 | 80 | |
| 80 | static const int NumberOfDataDirectory = 16; | |
| 81 | // Global vector of all output sections. After output sections are finalized, | |
| 82 | // this can be indexed by Chunk::getOutputSection. | |
| 83 | static std::vector<OutputSection *> outputSections; | |
| 84 | ||
| 85 | OutputSection *Chunk::getOutputSection() const { | |
| 86 | return osidx == 0 ? nullptr : outputSections[osidx - 1]; | |
| 87 | } | |
| 81 | 88 | |
| 82 | 89 | namespace { |
| 83 | 90 | |
| 84 | class DebugDirectoryChunk : public Chunk { | |
| 91 | class DebugDirectoryChunk : public NonSectionChunk { | |
| 85 | 92 | public: |
| 86 | DebugDirectoryChunk(const std::vector<Chunk *> &R, bool WriteRepro) | |
| 87 | : Records(R), WriteRepro(WriteRepro) {} | |
| 93 | DebugDirectoryChunk(const std::vector<Chunk *> &r, bool writeRepro) | |
| 94 | : records(r), writeRepro(writeRepro) {} | |
| 88 | 95 | |
| 89 | 96 | size_t getSize() const override { |
| 90 | return (Records.size() + int(WriteRepro)) * sizeof(debug_directory); | |
| 97 | return (records.size() + int(writeRepro)) * sizeof(debug_directory); | |
| 91 | 98 | } |
| 92 | 99 | |
| 93 | void writeTo(uint8_t *B) const override { | |
| 94 | auto *D = reinterpret_cast<debug_directory *>(B + OutputSectionOff); | |
| 100 | void writeTo(uint8_t *b) const override { | |
| 101 | auto *d = reinterpret_cast<debug_directory *>(b); | |
| 95 | 102 | |
| 96 | for (const Chunk *Record : Records) { | |
| 97 | OutputSection *OS = Record->getOutputSection(); | |
| 98 | uint64_t Offs = OS->getFileOff() + (Record->getRVA() - OS->getRVA()); | |
| 99 | fillEntry(D, COFF::IMAGE_DEBUG_TYPE_CODEVIEW, Record->getSize(), | |
| 100 | Record->getRVA(), Offs); | |
| 101 | ++D; | |
| 103 | for (const Chunk *record : records) { | |
| 104 | OutputSection *os = record->getOutputSection(); | |
| 105 | uint64_t offs = os->getFileOff() + (record->getRVA() - os->getRVA()); | |
| 106 | fillEntry(d, COFF::IMAGE_DEBUG_TYPE_CODEVIEW, record->getSize(), | |
| 107 | record->getRVA(), offs); | |
| 108 | ++d; | |
| 102 | 109 | } |
| 103 | 110 | |
| 104 | if (WriteRepro) { | |
| 111 | if (writeRepro) { | |
| 105 | 112 | // FIXME: The COFF spec allows either a 0-sized entry to just say |
| 106 | 113 | // "the timestamp field is really a hash", or a 4-byte size field |
| 107 | 114 | // followed by that many bytes containing a longer hash (with the |
| 108 | 115 | // lowest 4 bytes usually being the timestamp in little-endian order). |
| 109 | 116 | // Consider storing the full 8 bytes computed by xxHash64 here. |
| 110 | fillEntry(D, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0); | |
| 117 | fillEntry(d, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0); | |
| 111 | 118 | } |
| 112 | 119 | } |
| 113 | 120 | |
| 114 | void setTimeDateStamp(uint32_t TimeDateStamp) { | |
| 115 | for (support::ulittle32_t *TDS : TimeDateStamps) | |
| 116 | *TDS = TimeDateStamp; | |
| 121 | void setTimeDateStamp(uint32_t timeDateStamp) { | |
| 122 | for (support::ulittle32_t *tds : timeDateStamps) | |
| 123 | *tds = timeDateStamp; | |
| 117 | 124 | } |
| 118 | 125 | |
| 119 | 126 | private: |
| 120 | void fillEntry(debug_directory *D, COFF::DebugType DebugType, size_t Size, | |
| 121 | uint64_t RVA, uint64_t Offs) const { | |
| 122 | D->Characteristics = 0; | |
| 123 | D->TimeDateStamp = 0; | |
| 124 | D->MajorVersion = 0; | |
| 125 | D->MinorVersion = 0; | |
| 126 | D->Type = DebugType; | |
| 127 | D->SizeOfData = Size; | |
| 128 | D->AddressOfRawData = RVA; | |
| 129 | D->PointerToRawData = Offs; | |
| 130 | ||
| 131 | TimeDateStamps.push_back(&D->TimeDateStamp); | |
| 132 | } | |
| 133 | ||
| 134 | mutable std::vector<support::ulittle32_t *> TimeDateStamps; | |
| 135 | const std::vector<Chunk *> &Records; | |
| 136 | bool WriteRepro; | |
| 127 | void fillEntry(debug_directory *d, COFF::DebugType debugType, size_t size, | |
| 128 | uint64_t rva, uint64_t offs) const { | |
| 129 | d->Characteristics = 0; | |
| 130 | d->TimeDateStamp = 0; | |
| 131 | d->MajorVersion = 0; | |
| 132 | d->MinorVersion = 0; | |
| 133 | d->Type = debugType; | |
| 134 | d->SizeOfData = size; | |
| 135 | d->AddressOfRawData = rva; | |
| 136 | d->PointerToRawData = offs; | |
| 137 | ||
| 138 | timeDateStamps.push_back(&d->TimeDateStamp); | |
| 139 | } | |
| 140 | ||
| 141 | mutable std::vector<support::ulittle32_t *> timeDateStamps; | |
| 142 | const std::vector<Chunk *> &records; | |
| 143 | bool writeRepro; | |
| 137 | 144 | }; |
| 138 | 145 | |
| 139 | class CVDebugRecordChunk : public Chunk { | |
| 146 | class CVDebugRecordChunk : public NonSectionChunk { | |
| 140 | 147 | public: |
| 141 | 148 | size_t getSize() const override { |
| 142 | return sizeof(codeview::DebugInfo) + Config->PDBAltPath.size() + 1; | |
| 149 | return sizeof(codeview::DebugInfo) + config->pdbAltPath.size() + 1; | |
| 143 | 150 | } |
| 144 | 151 | |
| 145 | void writeTo(uint8_t *B) const override { | |
| 152 | void writeTo(uint8_t *b) const override { | |
| 146 | 153 | // Save off the DebugInfo entry to backfill the file signature (build id) |
| 147 | 154 | // in Writer::writeBuildId |
| 148 | BuildId = reinterpret_cast<codeview::DebugInfo *>(B + OutputSectionOff); | |
| 155 | buildId = reinterpret_cast<codeview::DebugInfo *>(b); | |
| 149 | 156 | |
| 150 | 157 | // variable sized field (PDB Path) |
| 151 | char *P = reinterpret_cast<char *>(B + OutputSectionOff + sizeof(*BuildId)); | |
| 152 | if (!Config->PDBAltPath.empty()) | |
| 153 | memcpy(P, Config->PDBAltPath.data(), Config->PDBAltPath.size()); | |
| 154 | P[Config->PDBAltPath.size()] = '\0'; | |
| 158 | char *p = reinterpret_cast<char *>(b + sizeof(*buildId)); | |
| 159 | if (!config->pdbAltPath.empty()) | |
| 160 | memcpy(p, config->pdbAltPath.data(), config->pdbAltPath.size()); | |
| 161 | p[config->pdbAltPath.size()] = '\0'; | |
| 155 | 162 | } |
| 156 | 163 | |
| 157 | mutable codeview::DebugInfo *BuildId = nullptr; | |
| 164 | mutable codeview::DebugInfo *buildId = nullptr; | |
| 165 | }; | |
| 166 | ||
| 167 | // PartialSection represents a group of chunks that contribute to an | |
| 168 | // OutputSection. Collating a collection of PartialSections of same name and | |
| 169 | // characteristics constitutes the OutputSection. | |
| 170 | class PartialSectionKey { | |
| 171 | public: | |
| 172 | StringRef name; | |
| 173 | unsigned characteristics; | |
| 174 | ||
| 175 | bool operator<(const PartialSectionKey &other) const { | |
| 176 | int c = name.compare(other.name); | |
| 177 | if (c == 1) | |
| 178 | return false; | |
| 179 | if (c == 0) | |
| 180 | return characteristics < other.characteristics; | |
| 181 | return true; | |
| 182 | } | |
| 158 | 183 | }; |
| 159 | 184 | |
| 160 | 185 | // The writer writes a SymbolTable result to a file. |
| 161 | 186 | class Writer { |
| 162 | 187 | public: |
| 163 | Writer() : Buffer(errorHandler().OutputBuffer) {} | |
| 188 | Writer() : buffer(errorHandler().outputBuffer) {} | |
| 164 | 189 | void run(); |
| 165 | 190 | |
| 166 | 191 | private: |
| ... | ... | @@ -168,78 +193,81 @@ private: |
| 168 | 193 | void createMiscChunks(); |
| 169 | 194 | void createImportTables(); |
| 170 | 195 | void appendImportThunks(); |
| 171 | void locateImportTables( | |
| 172 | std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map); | |
| 196 | void locateImportTables(); | |
| 173 | 197 | void createExportTable(); |
| 174 | 198 | void mergeSections(); |
| 175 | void readRelocTargets(); | |
| 176 | 199 | void removeUnusedSections(); |
| 177 | 200 | void assignAddresses(); |
| 178 | 201 | void finalizeAddresses(); |
| 179 | 202 | void removeEmptySections(); |
| 203 | void assignOutputSectionIndices(); | |
| 180 | 204 | void createSymbolAndStringTable(); |
| 181 | void openFile(StringRef OutputPath); | |
| 205 | void openFile(StringRef outputPath); | |
| 182 | 206 | template <typename PEHeaderTy> void writeHeader(); |
| 183 | 207 | void createSEHTable(); |
| 184 | 208 | void createRuntimePseudoRelocs(); |
| 185 | 209 | void insertCtorDtorSymbols(); |
| 186 | 210 | void createGuardCFTables(); |
| 187 | void markSymbolsForRVATable(ObjFile *File, | |
| 188 | ArrayRef<SectionChunk *> SymIdxChunks, | |
| 189 | SymbolRVASet &TableSymbols); | |
| 190 | void maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym, | |
| 191 | StringRef CountSym); | |
| 211 | void markSymbolsForRVATable(ObjFile *file, | |
| 212 | ArrayRef<SectionChunk *> symIdxChunks, | |
| 213 | SymbolRVASet &tableSymbols); | |
| 214 | void maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym, | |
| 215 | StringRef countSym); | |
| 192 | 216 | void setSectionPermissions(); |
| 193 | 217 | void writeSections(); |
| 194 | 218 | void writeBuildId(); |
| 195 | 219 | void sortExceptionTable(); |
| 196 | void sortCRTSectionChunks(std::vector<Chunk *> &Chunks); | |
| 220 | void sortCRTSectionChunks(std::vector<Chunk *> &chunks); | |
| 221 | void addSyntheticIdata(); | |
| 222 | void fixPartialSectionChars(StringRef name, uint32_t chars); | |
| 223 | bool fixGnuImportChunks(); | |
| 224 | PartialSection *createPartialSection(StringRef name, uint32_t outChars); | |
| 225 | PartialSection *findPartialSection(StringRef name, uint32_t outChars); | |
| 197 | 226 | |
| 198 | llvm::Optional<coff_symbol16> createSymbol(Defined *D); | |
| 199 | size_t addEntryToStringTable(StringRef Str); | |
| 227 | llvm::Optional<coff_symbol16> createSymbol(Defined *d); | |
| 228 | size_t addEntryToStringTable(StringRef str); | |
| 200 | 229 | |
| 201 | OutputSection *findSection(StringRef Name); | |
| 230 | OutputSection *findSection(StringRef name); | |
| 202 | 231 | void addBaserels(); |
| 203 | void addBaserelBlocks(std::vector<Baserel> &V); | |
| 232 | void addBaserelBlocks(std::vector<Baserel> &v); | |
| 204 | 233 | |
| 205 | 234 | uint32_t getSizeOfInitializedData(); |
| 206 | std::map<StringRef, std::vector<DefinedImportData *>> binImports(); | |
| 207 | ||
| 208 | std::unique_ptr<FileOutputBuffer> &Buffer; | |
| 209 | std::vector<OutputSection *> OutputSections; | |
| 210 | std::vector<char> Strtab; | |
| 211 | std::vector<llvm::object::coff_symbol16> OutputSymtab; | |
| 212 | IdataContents Idata; | |
| 213 | Chunk *ImportTableStart = nullptr; | |
| 214 | uint64_t ImportTableSize = 0; | |
| 215 | Chunk *IATStart = nullptr; | |
| 216 | uint64_t IATSize = 0; | |
| 217 | DelayLoadContents DelayIdata; | |
| 218 | EdataContents Edata; | |
| 219 | bool SetNoSEHCharacteristic = false; | |
| 220 | ||
| 221 | DebugDirectoryChunk *DebugDirectory = nullptr; | |
| 222 | std::vector<Chunk *> DebugRecords; | |
| 223 | CVDebugRecordChunk *BuildId = nullptr; | |
| 224 | ArrayRef<uint8_t> SectionTable; | |
| 225 | ||
| 226 | uint64_t FileSize; | |
| 227 | uint32_t PointerToSymbolTable = 0; | |
| 228 | uint64_t SizeOfImage; | |
| 229 | uint64_t SizeOfHeaders; | |
| 230 | ||
| 231 | OutputSection *TextSec; | |
| 232 | OutputSection *RdataSec; | |
| 233 | OutputSection *BuildidSec; | |
| 234 | OutputSection *DataSec; | |
| 235 | OutputSection *PdataSec; | |
| 236 | OutputSection *IdataSec; | |
| 237 | OutputSection *EdataSec; | |
| 238 | OutputSection *DidatSec; | |
| 239 | OutputSection *RsrcSec; | |
| 240 | OutputSection *RelocSec; | |
| 241 | OutputSection *CtorsSec; | |
| 242 | OutputSection *DtorsSec; | |
| 235 | ||
| 236 | std::unique_ptr<FileOutputBuffer> &buffer; | |
| 237 | std::map<PartialSectionKey, PartialSection *> partialSections; | |
| 238 | std::vector<char> strtab; | |
| 239 | std::vector<llvm::object::coff_symbol16> outputSymtab; | |
| 240 | IdataContents idata; | |
| 241 | Chunk *importTableStart = nullptr; | |
| 242 | uint64_t importTableSize = 0; | |
| 243 | Chunk *iatStart = nullptr; | |
| 244 | uint64_t iatSize = 0; | |
| 245 | DelayLoadContents delayIdata; | |
| 246 | EdataContents edata; | |
| 247 | bool setNoSEHCharacteristic = false; | |
| 248 | ||
| 249 | DebugDirectoryChunk *debugDirectory = nullptr; | |
| 250 | std::vector<Chunk *> debugRecords; | |
| 251 | CVDebugRecordChunk *buildId = nullptr; | |
| 252 | ArrayRef<uint8_t> sectionTable; | |
| 253 | ||
| 254 | uint64_t fileSize; | |
| 255 | uint32_t pointerToSymbolTable = 0; | |
| 256 | uint64_t sizeOfImage; | |
| 257 | uint64_t sizeOfHeaders; | |
| 258 | ||
| 259 | OutputSection *textSec; | |
| 260 | OutputSection *rdataSec; | |
| 261 | OutputSection *buildidSec; | |
| 262 | OutputSection *dataSec; | |
| 263 | OutputSection *pdataSec; | |
| 264 | OutputSection *idataSec; | |
| 265 | OutputSection *edataSec; | |
| 266 | OutputSection *didatSec; | |
| 267 | OutputSection *rsrcSec; | |
| 268 | OutputSection *relocSec; | |
| 269 | OutputSection *ctorsSec; | |
| 270 | OutputSection *dtorsSec; | |
| 243 | 271 | |
| 244 | 272 | // The first and last .pdata sections in the output file. |
| 245 | 273 | // |
| ... | ... | @@ -250,82 +278,85 @@ private: |
| 250 | 278 | // are entirely linker-generated we can keep track of their locations using |
| 251 | 279 | // the chunks that the linker creates. All .pdata chunks come from input |
| 252 | 280 | // files, so we need to keep track of them separately. |
| 253 | Chunk *FirstPdata = nullptr; | |
| 254 | Chunk *LastPdata; | |
| 281 | Chunk *firstPdata = nullptr; | |
| 282 | Chunk *lastPdata; | |
| 255 | 283 | }; |
| 256 | 284 | } // anonymous namespace |
| 257 | 285 | |
| 258 | 286 | namespace lld { |
| 259 | 287 | namespace coff { |
| 260 | 288 | |
| 261 | static Timer CodeLayoutTimer("Code Layout", Timer::root()); | |
| 262 | static Timer DiskCommitTimer("Commit Output File", Timer::root()); | |
| 289 | static Timer codeLayoutTimer("Code Layout", Timer::root()); | |
| 290 | static Timer diskCommitTimer("Commit Output File", Timer::root()); | |
| 263 | 291 | |
| 264 | 292 | void writeResult() { Writer().run(); } |
| 265 | 293 | |
| 266 | void OutputSection::addChunk(Chunk *C) { | |
| 267 | Chunks.push_back(C); | |
| 268 | C->setOutputSection(this); | |
| 294 | void OutputSection::addChunk(Chunk *c) { | |
| 295 | chunks.push_back(c); | |
| 269 | 296 | } |
| 270 | 297 | |
| 271 | void OutputSection::insertChunkAtStart(Chunk *C) { | |
| 272 | Chunks.insert(Chunks.begin(), C); | |
| 273 | C->setOutputSection(this); | |
| 298 | void OutputSection::insertChunkAtStart(Chunk *c) { | |
| 299 | chunks.insert(chunks.begin(), c); | |
| 274 | 300 | } |
| 275 | 301 | |
| 276 | void OutputSection::setPermissions(uint32_t C) { | |
| 277 | Header.Characteristics &= ~PermMask; | |
| 278 | Header.Characteristics |= C; | |
| 302 | void OutputSection::setPermissions(uint32_t c) { | |
| 303 | header.Characteristics &= ~permMask; | |
| 304 | header.Characteristics |= c; | |
| 279 | 305 | } |
| 280 | 306 | |
| 281 | void OutputSection::merge(OutputSection *Other) { | |
| 282 | for (Chunk *C : Other->Chunks) | |
| 283 | C->setOutputSection(this); | |
| 284 | Chunks.insert(Chunks.end(), Other->Chunks.begin(), Other->Chunks.end()); | |
| 285 | Other->Chunks.clear(); | |
| 307 | void OutputSection::merge(OutputSection *other) { | |
| 308 | chunks.insert(chunks.end(), other->chunks.begin(), other->chunks.end()); | |
| 309 | other->chunks.clear(); | |
| 310 | contribSections.insert(contribSections.end(), other->contribSections.begin(), | |
| 311 | other->contribSections.end()); | |
| 312 | other->contribSections.clear(); | |
| 286 | 313 | } |
| 287 | 314 | |
| 288 | 315 | // Write the section header to a given buffer. |
| 289 | void OutputSection::writeHeaderTo(uint8_t *Buf) { | |
| 290 | auto *Hdr = reinterpret_cast<coff_section *>(Buf); | |
| 291 | *Hdr = Header; | |
| 292 | if (StringTableOff) { | |
| 316 | void OutputSection::writeHeaderTo(uint8_t *buf) { | |
| 317 | auto *hdr = reinterpret_cast<coff_section *>(buf); | |
| 318 | *hdr = header; | |
| 319 | if (stringTableOff) { | |
| 293 | 320 | // If name is too long, write offset into the string table as a name. |
| 294 | sprintf(Hdr->Name, "/%d", StringTableOff); | |
| 321 | sprintf(hdr->Name, "/%d", stringTableOff); | |
| 295 | 322 | } else { |
| 296 | assert(!Config->Debug || Name.size() <= COFF::NameSize || | |
| 297 | (Hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0); | |
| 298 | strncpy(Hdr->Name, Name.data(), | |
| 299 | std::min(Name.size(), (size_t)COFF::NameSize)); | |
| 323 | assert(!config->debug || name.size() <= COFF::NameSize || | |
| 324 | (hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0); | |
| 325 | strncpy(hdr->Name, name.data(), | |
| 326 | std::min(name.size(), (size_t)COFF::NameSize)); | |
| 300 | 327 | } |
| 301 | 328 | } |
| 302 | 329 | |
| 330 | void OutputSection::addContributingPartialSection(PartialSection *sec) { | |
| 331 | contribSections.push_back(sec); | |
| 332 | } | |
| 333 | ||
| 303 | 334 | } // namespace coff |
| 304 | 335 | } // namespace lld |
| 305 | 336 | |
| 306 | 337 | // Check whether the target address S is in range from a relocation |
| 307 | // of type RelType at address P. | |
| 308 | static bool isInRange(uint16_t RelType, uint64_t S, uint64_t P, int Margin) { | |
| 309 | if (Config->Machine == ARMNT) { | |
| 310 | int64_t Diff = AbsoluteDifference(S, P + 4) + Margin; | |
| 311 | switch (RelType) { | |
| 338 | // of type relType at address P. | |
| 339 | static bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin) { | |
| 340 | if (config->machine == ARMNT) { | |
| 341 | int64_t diff = AbsoluteDifference(s, p + 4) + margin; | |
| 342 | switch (relType) { | |
| 312 | 343 | case IMAGE_REL_ARM_BRANCH20T: |
| 313 | return isInt<21>(Diff); | |
| 344 | return isInt<21>(diff); | |
| 314 | 345 | case IMAGE_REL_ARM_BRANCH24T: |
| 315 | 346 | case IMAGE_REL_ARM_BLX23T: |
| 316 | return isInt<25>(Diff); | |
| 347 | return isInt<25>(diff); | |
| 317 | 348 | default: |
| 318 | 349 | return true; |
| 319 | 350 | } |
| 320 | } else if (Config->Machine == ARM64) { | |
| 321 | int64_t Diff = AbsoluteDifference(S, P) + Margin; | |
| 322 | switch (RelType) { | |
| 351 | } else if (config->machine == ARM64) { | |
| 352 | int64_t diff = AbsoluteDifference(s, p) + margin; | |
| 353 | switch (relType) { | |
| 323 | 354 | case IMAGE_REL_ARM64_BRANCH26: |
| 324 | return isInt<28>(Diff); | |
| 355 | return isInt<28>(diff); | |
| 325 | 356 | case IMAGE_REL_ARM64_BRANCH19: |
| 326 | return isInt<21>(Diff); | |
| 357 | return isInt<21>(diff); | |
| 327 | 358 | case IMAGE_REL_ARM64_BRANCH14: |
| 328 | return isInt<16>(Diff); | |
| 359 | return isInt<16>(diff); | |
| 329 | 360 | default: |
| 330 | 361 | return true; |
| 331 | 362 | } |
| ... | ... | @@ -337,25 +368,25 @@ static bool isInRange(uint16_t RelType, uint64_t S, uint64_t P, int Margin) { |
| 337 | 368 | // Return the last thunk for the given target if it is in range, |
| 338 | 369 | // or create a new one. |
| 339 | 370 | static std::pair<Defined *, bool> |
| 340 | getThunk(DenseMap<uint64_t, Defined *> &LastThunks, Defined *Target, uint64_t P, | |
| 341 | uint16_t Type, int Margin) { | |
| 342 | Defined *&LastThunk = LastThunks[Target->getRVA()]; | |
| 343 | if (LastThunk && isInRange(Type, LastThunk->getRVA(), P, Margin)) | |
| 344 | return {LastThunk, false}; | |
| 345 | Chunk *C; | |
| 346 | switch (Config->Machine) { | |
| 371 | getThunk(DenseMap<uint64_t, Defined *> &lastThunks, Defined *target, uint64_t p, | |
| 372 | uint16_t type, int margin) { | |
| 373 | Defined *&lastThunk = lastThunks[target->getRVA()]; | |
| 374 | if (lastThunk && isInRange(type, lastThunk->getRVA(), p, margin)) | |
| 375 | return {lastThunk, false}; | |
| 376 | Chunk *c; | |
| 377 | switch (config->machine) { | |
| 347 | 378 | case ARMNT: |
| 348 | C = make<RangeExtensionThunkARM>(Target); | |
| 379 | c = make<RangeExtensionThunkARM>(target); | |
| 349 | 380 | break; |
| 350 | 381 | case ARM64: |
| 351 | C = make<RangeExtensionThunkARM64>(Target); | |
| 382 | c = make<RangeExtensionThunkARM64>(target); | |
| 352 | 383 | break; |
| 353 | 384 | default: |
| 354 | 385 | llvm_unreachable("Unexpected architecture"); |
| 355 | 386 | } |
| 356 | Defined *D = make<DefinedSynthetic>("", C); | |
| 357 | LastThunk = D; | |
| 358 | return {D, true}; | |
| 387 | Defined *d = make<DefinedSynthetic>("", c); | |
| 388 | lastThunk = d; | |
| 389 | return {d, true}; | |
| 359 | 390 | } |
| 360 | 391 | |
| 361 | 392 | // This checks all relocations, and for any relocation which isn't in range |
| ... | ... | @@ -369,82 +400,124 @@ getThunk(DenseMap<uint64_t, Defined *> &LastThunks, Defined *Target, uint64_t P, |
| 369 | 400 | // After adding thunks, we verify that all relocations are in range (with |
| 370 | 401 | // no extra margin requirements). If this failed, we restart (throwing away |
| 371 | 402 | // the previously created thunks) and retry with a wider margin. |
| 372 | static bool createThunks(OutputSection *OS, int Margin) { | |
| 373 | bool AddressesChanged = false; | |
| 374 | DenseMap<uint64_t, Defined *> LastThunks; | |
| 375 | size_t ThunksSize = 0; | |
| 403 | static bool createThunks(OutputSection *os, int margin) { | |
| 404 | bool addressesChanged = false; | |
| 405 | DenseMap<uint64_t, Defined *> lastThunks; | |
| 406 | DenseMap<std::pair<ObjFile *, Defined *>, uint32_t> thunkSymtabIndices; | |
| 407 | size_t thunksSize = 0; | |
| 376 | 408 | // Recheck Chunks.size() each iteration, since we can insert more |
| 377 | 409 | // elements into it. |
| 378 | for (size_t I = 0; I != OS->Chunks.size(); ++I) { | |
| 379 | SectionChunk *SC = dyn_cast_or_null<SectionChunk>(OS->Chunks[I]); | |
| 380 | if (!SC) | |
| 410 | for (size_t i = 0; i != os->chunks.size(); ++i) { | |
| 411 | SectionChunk *sc = dyn_cast_or_null<SectionChunk>(os->chunks[i]); | |
| 412 | if (!sc) | |
| 381 | 413 | continue; |
| 382 | size_t ThunkInsertionSpot = I + 1; | |
| 414 | size_t thunkInsertionSpot = i + 1; | |
| 383 | 415 | |
| 384 | 416 | // Try to get a good enough estimate of where new thunks will be placed. |
| 385 | 417 | // Offset this by the size of the new thunks added so far, to make the |
| 386 | 418 | // estimate slightly better. |
| 387 | size_t ThunkInsertionRVA = SC->getRVA() + SC->getSize() + ThunksSize; | |
| 388 | for (size_t J = 0, E = SC->Relocs.size(); J < E; ++J) { | |
| 389 | const coff_relocation &Rel = SC->Relocs[J]; | |
| 390 | Symbol *&RelocTarget = SC->RelocTargets[J]; | |
| 419 | size_t thunkInsertionRVA = sc->getRVA() + sc->getSize() + thunksSize; | |
| 420 | ObjFile *file = sc->file; | |
| 421 | std::vector<std::pair<uint32_t, uint32_t>> relocReplacements; | |
| 422 | ArrayRef<coff_relocation> originalRelocs = | |
| 423 | file->getCOFFObj()->getRelocations(sc->header); | |
| 424 | for (size_t j = 0, e = originalRelocs.size(); j < e; ++j) { | |
| 425 | const coff_relocation &rel = originalRelocs[j]; | |
| 426 | Symbol *relocTarget = file->getSymbol(rel.SymbolTableIndex); | |
| 391 | 427 | |
| 392 | 428 | // The estimate of the source address P should be pretty accurate, |
| 393 | 429 | // but we don't know whether the target Symbol address should be |
| 394 | // offset by ThunkSize or not (or by some of ThunksSize but not all of | |
| 430 | // offset by thunksSize or not (or by some of thunksSize but not all of | |
| 395 | 431 | // it), giving us some uncertainty once we have added one thunk. |
| 396 | uint64_t P = SC->getRVA() + Rel.VirtualAddress + ThunksSize; | |
| 432 | uint64_t p = sc->getRVA() + rel.VirtualAddress + thunksSize; | |
| 397 | 433 | |
| 398 | Defined *Sym = dyn_cast_or_null<Defined>(RelocTarget); | |
| 399 | if (!Sym) | |
| 434 | Defined *sym = dyn_cast_or_null<Defined>(relocTarget); | |
| 435 | if (!sym) | |
| 400 | 436 | continue; |
| 401 | 437 | |
| 402 | uint64_t S = Sym->getRVA(); | |
| 438 | uint64_t s = sym->getRVA(); | |
| 403 | 439 | |
| 404 | if (isInRange(Rel.Type, S, P, Margin)) | |
| 440 | if (isInRange(rel.Type, s, p, margin)) | |
| 405 | 441 | continue; |
| 406 | 442 | |
| 407 | 443 | // If the target isn't in range, hook it up to an existing or new |
| 408 | 444 | // thunk. |
| 409 | Defined *Thunk; | |
| 410 | bool WasNew; | |
| 411 | std::tie(Thunk, WasNew) = getThunk(LastThunks, Sym, P, Rel.Type, Margin); | |
| 412 | if (WasNew) { | |
| 413 | Chunk *ThunkChunk = Thunk->getChunk(); | |
| 414 | ThunkChunk->setRVA( | |
| 415 | ThunkInsertionRVA); // Estimate of where it will be located. | |
| 416 | ThunkChunk->setOutputSection(OS); | |
| 417 | OS->Chunks.insert(OS->Chunks.begin() + ThunkInsertionSpot, ThunkChunk); | |
| 418 | ThunkInsertionSpot++; | |
| 419 | ThunksSize += ThunkChunk->getSize(); | |
| 420 | ThunkInsertionRVA += ThunkChunk->getSize(); | |
| 421 | AddressesChanged = true; | |
| 445 | Defined *thunk; | |
| 446 | bool wasNew; | |
| 447 | std::tie(thunk, wasNew) = getThunk(lastThunks, sym, p, rel.Type, margin); | |
| 448 | if (wasNew) { | |
| 449 | Chunk *thunkChunk = thunk->getChunk(); | |
| 450 | thunkChunk->setRVA( | |
| 451 | thunkInsertionRVA); // Estimate of where it will be located. | |
| 452 | os->chunks.insert(os->chunks.begin() + thunkInsertionSpot, thunkChunk); | |
| 453 | thunkInsertionSpot++; | |
| 454 | thunksSize += thunkChunk->getSize(); | |
| 455 | thunkInsertionRVA += thunkChunk->getSize(); | |
| 456 | addressesChanged = true; | |
| 457 | } | |
| 458 | ||
| 459 | // To redirect the relocation, add a symbol to the parent object file's | |
| 460 | // symbol table, and replace the relocation symbol table index with the | |
| 461 | // new index. | |
| 462 | auto insertion = thunkSymtabIndices.insert({{file, thunk}, ~0U}); | |
| 463 | uint32_t &thunkSymbolIndex = insertion.first->second; | |
| 464 | if (insertion.second) | |
| 465 | thunkSymbolIndex = file->addRangeThunkSymbol(thunk); | |
| 466 | relocReplacements.push_back({j, thunkSymbolIndex}); | |
| 467 | } | |
| 468 | ||
| 469 | // Get a writable copy of this section's relocations so they can be | |
| 470 | // modified. If the relocations point into the object file, allocate new | |
| 471 | // memory. Otherwise, this must be previously allocated memory that can be | |
| 472 | // modified in place. | |
| 473 | ArrayRef<coff_relocation> curRelocs = sc->getRelocs(); | |
| 474 | MutableArrayRef<coff_relocation> newRelocs; | |
| 475 | if (originalRelocs.data() == curRelocs.data()) { | |
| 476 | newRelocs = makeMutableArrayRef( | |
| 477 | bAlloc.Allocate<coff_relocation>(originalRelocs.size()), | |
| 478 | originalRelocs.size()); | |
| 479 | } else { | |
| 480 | newRelocs = makeMutableArrayRef( | |
| 481 | const_cast<coff_relocation *>(curRelocs.data()), curRelocs.size()); | |
| 482 | } | |
| 483 | ||
| 484 | // Copy each relocation, but replace the symbol table indices which need | |
| 485 | // thunks. | |
| 486 | auto nextReplacement = relocReplacements.begin(); | |
| 487 | auto endReplacement = relocReplacements.end(); | |
| 488 | for (size_t i = 0, e = originalRelocs.size(); i != e; ++i) { | |
| 489 | newRelocs[i] = originalRelocs[i]; | |
| 490 | if (nextReplacement != endReplacement && nextReplacement->first == i) { | |
| 491 | newRelocs[i].SymbolTableIndex = nextReplacement->second; | |
| 492 | ++nextReplacement; | |
| 422 | 493 | } |
| 423 | RelocTarget = Thunk; | |
| 424 | 494 | } |
| 495 | ||
| 496 | sc->setRelocs(newRelocs); | |
| 425 | 497 | } |
| 426 | return AddressesChanged; | |
| 498 | return addressesChanged; | |
| 427 | 499 | } |
| 428 | 500 | |
| 429 | 501 | // Verify that all relocations are in range, with no extra margin requirements. |
| 430 | static bool verifyRanges(const std::vector<Chunk *> Chunks) { | |
| 431 | for (Chunk *C : Chunks) { | |
| 432 | SectionChunk *SC = dyn_cast_or_null<SectionChunk>(C); | |
| 433 | if (!SC) | |
| 502 | static bool verifyRanges(const std::vector<Chunk *> chunks) { | |
| 503 | for (Chunk *c : chunks) { | |
| 504 | SectionChunk *sc = dyn_cast_or_null<SectionChunk>(c); | |
| 505 | if (!sc) | |
| 434 | 506 | continue; |
| 435 | 507 | |
| 436 | for (size_t J = 0, E = SC->Relocs.size(); J < E; ++J) { | |
| 437 | const coff_relocation &Rel = SC->Relocs[J]; | |
| 438 | Symbol *RelocTarget = SC->RelocTargets[J]; | |
| 508 | ArrayRef<coff_relocation> relocs = sc->getRelocs(); | |
| 509 | for (size_t j = 0, e = relocs.size(); j < e; ++j) { | |
| 510 | const coff_relocation &rel = relocs[j]; | |
| 511 | Symbol *relocTarget = sc->file->getSymbol(rel.SymbolTableIndex); | |
| 439 | 512 | |
| 440 | Defined *Sym = dyn_cast_or_null<Defined>(RelocTarget); | |
| 441 | if (!Sym) | |
| 513 | Defined *sym = dyn_cast_or_null<Defined>(relocTarget); | |
| 514 | if (!sym) | |
| 442 | 515 | continue; |
| 443 | 516 | |
| 444 | uint64_t P = SC->getRVA() + Rel.VirtualAddress; | |
| 445 | uint64_t S = Sym->getRVA(); | |
| 517 | uint64_t p = sc->getRVA() + rel.VirtualAddress; | |
| 518 | uint64_t s = sym->getRVA(); | |
| 446 | 519 | |
| 447 | if (!isInRange(Rel.Type, S, P, 0)) | |
| 520 | if (!isInRange(rel.Type, s, p, 0)) | |
| 448 | 521 | return false; |
| 449 | 522 | } |
| 450 | 523 | } |
| ... | ... | @@ -454,71 +527,68 @@ static bool verifyRanges(const std::vector<Chunk *> Chunks) { |
| 454 | 527 | // Assign addresses and add thunks if necessary. |
| 455 | 528 | void Writer::finalizeAddresses() { |
| 456 | 529 | assignAddresses(); |
| 457 | if (Config->Machine != ARMNT && Config->Machine != ARM64) | |
| 530 | if (config->machine != ARMNT && config->machine != ARM64) | |
| 458 | 531 | return; |
| 459 | 532 | |
| 460 | size_t OrigNumChunks = 0; | |
| 461 | for (OutputSection *Sec : OutputSections) { | |
| 462 | Sec->OrigChunks = Sec->Chunks; | |
| 463 | OrigNumChunks += Sec->Chunks.size(); | |
| 533 | size_t origNumChunks = 0; | |
| 534 | for (OutputSection *sec : outputSections) { | |
| 535 | sec->origChunks = sec->chunks; | |
| 536 | origNumChunks += sec->chunks.size(); | |
| 464 | 537 | } |
| 465 | 538 | |
| 466 | int Pass = 0; | |
| 467 | int Margin = 1024 * 100; | |
| 539 | int pass = 0; | |
| 540 | int margin = 1024 * 100; | |
| 468 | 541 | while (true) { |
| 469 | 542 | // First check whether we need thunks at all, or if the previous pass of |
| 470 | 543 | // adding them turned out ok. |
| 471 | bool RangesOk = true; | |
| 472 | size_t NumChunks = 0; | |
| 473 | for (OutputSection *Sec : OutputSections) { | |
| 474 | if (!verifyRanges(Sec->Chunks)) { | |
| 475 | RangesOk = false; | |
| 544 | bool rangesOk = true; | |
| 545 | size_t numChunks = 0; | |
| 546 | for (OutputSection *sec : outputSections) { | |
| 547 | if (!verifyRanges(sec->chunks)) { | |
| 548 | rangesOk = false; | |
| 476 | 549 | break; |
| 477 | 550 | } |
| 478 | NumChunks += Sec->Chunks.size(); | |
| 551 | numChunks += sec->chunks.size(); | |
| 479 | 552 | } |
| 480 | if (RangesOk) { | |
| 481 | if (Pass > 0) | |
| 482 | log("Added " + Twine(NumChunks - OrigNumChunks) + " thunks with " + | |
| 483 | "margin " + Twine(Margin) + " in " + Twine(Pass) + " passes"); | |
| 553 | if (rangesOk) { | |
| 554 | if (pass > 0) | |
| 555 | log("Added " + Twine(numChunks - origNumChunks) + " thunks with " + | |
| 556 | "margin " + Twine(margin) + " in " + Twine(pass) + " passes"); | |
| 484 | 557 | return; |
| 485 | 558 | } |
| 486 | 559 | |
| 487 | if (Pass >= 10) | |
| 488 | fatal("adding thunks hasn't converged after " + Twine(Pass) + " passes"); | |
| 560 | if (pass >= 10) | |
| 561 | fatal("adding thunks hasn't converged after " + Twine(pass) + " passes"); | |
| 489 | 562 | |
| 490 | if (Pass > 0) { | |
| 563 | if (pass > 0) { | |
| 491 | 564 | // If the previous pass didn't work out, reset everything back to the |
| 492 | 565 | // original conditions before retrying with a wider margin. This should |
| 493 | 566 | // ideally never happen under real circumstances. |
| 494 | for (OutputSection *Sec : OutputSections) { | |
| 495 | Sec->Chunks = Sec->OrigChunks; | |
| 496 | for (Chunk *C : Sec->Chunks) | |
| 497 | C->resetRelocTargets(); | |
| 498 | } | |
| 499 | Margin *= 2; | |
| 567 | for (OutputSection *sec : outputSections) | |
| 568 | sec->chunks = sec->origChunks; | |
| 569 | margin *= 2; | |
| 500 | 570 | } |
| 501 | 571 | |
| 502 | 572 | // Try adding thunks everywhere where it is needed, with a margin |
| 503 | 573 | // to avoid things going out of range due to the added thunks. |
| 504 | bool AddressesChanged = false; | |
| 505 | for (OutputSection *Sec : OutputSections) | |
| 506 | AddressesChanged |= createThunks(Sec, Margin); | |
| 574 | bool addressesChanged = false; | |
| 575 | for (OutputSection *sec : outputSections) | |
| 576 | addressesChanged |= createThunks(sec, margin); | |
| 507 | 577 | // If the verification above thought we needed thunks, we should have |
| 508 | 578 | // added some. |
| 509 | assert(AddressesChanged); | |
| 579 | assert(addressesChanged); | |
| 510 | 580 | |
| 511 | 581 | // Recalculate the layout for the whole image (and verify the ranges at |
| 512 | 582 | // the start of the next round). |
| 513 | 583 | assignAddresses(); |
| 514 | 584 | |
| 515 | Pass++; | |
| 585 | pass++; | |
| 516 | 586 | } |
| 517 | 587 | } |
| 518 | 588 | |
| 519 | 589 | // The main function of the writer. |
| 520 | 590 | void Writer::run() { |
| 521 | ScopedTimer T1(CodeLayoutTimer); | |
| 591 | ScopedTimer t1(codeLayoutTimer); | |
| 522 | 592 | |
| 523 | 593 | createImportTables(); |
| 524 | 594 | createSections(); |
| ... | ... | @@ -526,19 +596,19 @@ void Writer::run() { |
| 526 | 596 | appendImportThunks(); |
| 527 | 597 | createExportTable(); |
| 528 | 598 | mergeSections(); |
| 529 | readRelocTargets(); | |
| 530 | 599 | removeUnusedSections(); |
| 531 | 600 | finalizeAddresses(); |
| 532 | 601 | removeEmptySections(); |
| 602 | assignOutputSectionIndices(); | |
| 533 | 603 | setSectionPermissions(); |
| 534 | 604 | createSymbolAndStringTable(); |
| 535 | 605 | |
| 536 | if (FileSize > UINT32_MAX) | |
| 537 | fatal("image size (" + Twine(FileSize) + ") " + | |
| 606 | if (fileSize > UINT32_MAX) | |
| 607 | fatal("image size (" + Twine(fileSize) + ") " + | |
| 538 | 608 | "exceeds maximum allowable size (" + Twine(UINT32_MAX) + ")"); |
| 539 | 609 | |
| 540 | openFile(Config->OutputFile); | |
| 541 | if (Config->is64()) { | |
| 610 | openFile(config->outputFile); | |
| 611 | if (config->is64()) { | |
| 542 | 612 | writeHeader<pe32plus_header>(); |
| 543 | 613 | } else { |
| 544 | 614 | writeHeader<pe32_header>(); |
| ... | ... | @@ -546,42 +616,59 @@ void Writer::run() { |
| 546 | 616 | writeSections(); |
| 547 | 617 | sortExceptionTable(); |
| 548 | 618 | |
| 549 | T1.stop(); | |
| 619 | t1.stop(); | |
| 550 | 620 | |
| 551 | if (!Config->PDBPath.empty() && Config->Debug) { | |
| 552 | assert(BuildId); | |
| 553 | createPDB(Symtab, OutputSections, SectionTable, BuildId->BuildId); | |
| 621 | if (!config->pdbPath.empty() && config->debug) { | |
| 622 | assert(buildId); | |
| 623 | createPDB(symtab, outputSections, sectionTable, buildId->buildId); | |
| 554 | 624 | } |
| 555 | 625 | writeBuildId(); |
| 556 | 626 | |
| 557 | writeMapFile(OutputSections); | |
| 627 | writeMapFile(outputSections); | |
| 558 | 628 | |
| 559 | ScopedTimer T2(DiskCommitTimer); | |
| 560 | if (auto E = Buffer->commit()) | |
| 561 | fatal("failed to write the output file: " + toString(std::move(E))); | |
| 629 | ScopedTimer t2(diskCommitTimer); | |
| 630 | if (auto e = buffer->commit()) | |
| 631 | fatal("failed to write the output file: " + toString(std::move(e))); | |
| 562 | 632 | } |
| 563 | 633 | |
| 564 | static StringRef getOutputSectionName(StringRef Name) { | |
| 565 | StringRef S = Name.split('$').first; | |
| 634 | static StringRef getOutputSectionName(StringRef name) { | |
| 635 | StringRef s = name.split('$').first; | |
| 566 | 636 | |
| 567 | 637 | // Treat a later period as a separator for MinGW, for sections like |
| 568 | 638 | // ".ctors.01234". |
| 569 | return S.substr(0, S.find('.', 1)); | |
| 639 | return s.substr(0, s.find('.', 1)); | |
| 570 | 640 | } |
| 571 | 641 | |
| 572 | 642 | // For /order. |
| 573 | static void sortBySectionOrder(std::vector<Chunk *> &Chunks) { | |
| 574 | auto GetPriority = [](const Chunk *C) { | |
| 575 | if (auto *Sec = dyn_cast<SectionChunk>(C)) | |
| 576 | if (Sec->Sym) | |
| 577 | return Config->Order.lookup(Sec->Sym->getName()); | |
| 643 | static void sortBySectionOrder(std::vector<Chunk *> &chunks) { | |
| 644 | auto getPriority = [](const Chunk *c) { | |
| 645 | if (auto *sec = dyn_cast<SectionChunk>(c)) | |
| 646 | if (sec->sym) | |
| 647 | return config->order.lookup(sec->sym->getName()); | |
| 578 | 648 | return 0; |
| 579 | 649 | }; |
| 580 | 650 | |
| 581 | std::stable_sort(Chunks.begin(), Chunks.end(), | |
| 582 | [=](const Chunk *A, const Chunk *B) { | |
| 583 | return GetPriority(A) < GetPriority(B); | |
| 584 | }); | |
| 651 | llvm::stable_sort(chunks, [=](const Chunk *a, const Chunk *b) { | |
| 652 | return getPriority(a) < getPriority(b); | |
| 653 | }); | |
| 654 | } | |
| 655 | ||
| 656 | // Change the characteristics of existing PartialSections that belong to the | |
| 657 | // section Name to Chars. | |
| 658 | void Writer::fixPartialSectionChars(StringRef name, uint32_t chars) { | |
| 659 | for (auto it : partialSections) { | |
| 660 | PartialSection *pSec = it.second; | |
| 661 | StringRef curName = pSec->name; | |
| 662 | if (!curName.consume_front(name) || | |
| 663 | (!curName.empty() && !curName.startswith("$"))) | |
| 664 | continue; | |
| 665 | if (pSec->characteristics == chars) | |
| 666 | continue; | |
| 667 | PartialSection *destSec = createPartialSection(pSec->name, chars); | |
| 668 | destSec->chunks.insert(destSec->chunks.end(), pSec->chunks.begin(), | |
| 669 | pSec->chunks.end()); | |
| 670 | pSec->chunks.clear(); | |
| 671 | } | |
| 585 | 672 | } |
| 586 | 673 | |
| 587 | 674 | // Sort concrete section chunks from GNU import libraries. |
| ... | ... | @@ -594,249 +681,269 @@ static void sortBySectionOrder(std::vector<Chunk *> &Chunks) { |
| 594 | 681 | // be formed correctly, the section chunks within each .idata$* section need |
| 595 | 682 | // to be grouped by library, and sorted alphabetically within each library |
| 596 | 683 | // (which makes sure the header comes first and the trailer last). |
| 597 | static bool fixGnuImportChunks( | |
| 598 | std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map) { | |
| 599 | uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; | |
| 684 | bool Writer::fixGnuImportChunks() { | |
| 685 | uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; | |
| 600 | 686 | |
| 601 | 687 | // Make sure all .idata$* section chunks are mapped as RDATA in order to |
| 602 | 688 | // be sorted into the same sections as our own synthesized .idata chunks. |
| 603 | for (auto &Pair : Map) { | |
| 604 | StringRef SectionName = Pair.first.first; | |
| 605 | uint32_t OutChars = Pair.first.second; | |
| 606 | if (!SectionName.startswith(".idata")) | |
| 607 | continue; | |
| 608 | if (OutChars == RDATA) | |
| 609 | continue; | |
| 610 | std::vector<Chunk *> &SrcVect = Pair.second; | |
| 611 | std::vector<Chunk *> &DestVect = Map[{SectionName, RDATA}]; | |
| 612 | DestVect.insert(DestVect.end(), SrcVect.begin(), SrcVect.end()); | |
| 613 | SrcVect.clear(); | |
| 614 | } | |
| 689 | fixPartialSectionChars(".idata", rdata); | |
| 615 | 690 | |
| 616 | bool HasIdata = false; | |
| 691 | bool hasIdata = false; | |
| 617 | 692 | // Sort all .idata$* chunks, grouping chunks from the same library, |
| 618 | 693 | // with alphabetical ordering of the object fils within a library. |
| 619 | for (auto &Pair : Map) { | |
| 620 | StringRef SectionName = Pair.first.first; | |
| 621 | if (!SectionName.startswith(".idata")) | |
| 694 | for (auto it : partialSections) { | |
| 695 | PartialSection *pSec = it.second; | |
| 696 | if (!pSec->name.startswith(".idata")) | |
| 622 | 697 | continue; |
| 623 | 698 | |
| 624 | std::vector<Chunk *> &Chunks = Pair.second; | |
| 625 | if (!Chunks.empty()) | |
| 626 | HasIdata = true; | |
| 627 | std::stable_sort(Chunks.begin(), Chunks.end(), [&](Chunk *S, Chunk *T) { | |
| 628 | SectionChunk *SC1 = dyn_cast_or_null<SectionChunk>(S); | |
| 629 | SectionChunk *SC2 = dyn_cast_or_null<SectionChunk>(T); | |
| 630 | if (!SC1 || !SC2) { | |
| 699 | if (!pSec->chunks.empty()) | |
| 700 | hasIdata = true; | |
| 701 | llvm::stable_sort(pSec->chunks, [&](Chunk *s, Chunk *t) { | |
| 702 | SectionChunk *sc1 = dyn_cast_or_null<SectionChunk>(s); | |
| 703 | SectionChunk *sc2 = dyn_cast_or_null<SectionChunk>(t); | |
| 704 | if (!sc1 || !sc2) { | |
| 631 | 705 | // if SC1, order them ascending. If SC2 or both null, |
| 632 | 706 | // S is not less than T. |
| 633 | return SC1 != nullptr; | |
| 707 | return sc1 != nullptr; | |
| 634 | 708 | } |
| 635 | 709 | // Make a string with "libraryname/objectfile" for sorting, achieving |
| 636 | 710 | // both grouping by library and sorting of objects within a library, |
| 637 | 711 | // at once. |
| 638 | std::string Key1 = | |
| 639 | (SC1->File->ParentName + "/" + SC1->File->getName()).str(); | |
| 640 | std::string Key2 = | |
| 641 | (SC2->File->ParentName + "/" + SC2->File->getName()).str(); | |
| 642 | return Key1 < Key2; | |
| 712 | std::string key1 = | |
| 713 | (sc1->file->parentName + "/" + sc1->file->getName()).str(); | |
| 714 | std::string key2 = | |
| 715 | (sc2->file->parentName + "/" + sc2->file->getName()).str(); | |
| 716 | return key1 < key2; | |
| 643 | 717 | }); |
| 644 | 718 | } |
| 645 | return HasIdata; | |
| 719 | return hasIdata; | |
| 646 | 720 | } |
| 647 | 721 | |
| 648 | 722 | // Add generated idata chunks, for imported symbols and DLLs, and a |
| 649 | 723 | // terminator in .idata$2. |
| 650 | static void addSyntheticIdata( | |
| 651 | IdataContents &Idata, | |
| 652 | std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map) { | |
| 653 | uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; | |
| 654 | Idata.create(); | |
| 724 | void Writer::addSyntheticIdata() { | |
| 725 | uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; | |
| 726 | idata.create(); | |
| 655 | 727 | |
| 656 | 728 | // Add the .idata content in the right section groups, to allow |
| 657 | 729 | // chunks from other linked in object files to be grouped together. |
| 658 | 730 | // See Microsoft PE/COFF spec 5.4 for details. |
| 659 | auto Add = [&](StringRef N, std::vector<Chunk *> &V) { | |
| 660 | std::vector<Chunk *> &DestVect = Map[{N, RDATA}]; | |
| 661 | DestVect.insert(DestVect.end(), V.begin(), V.end()); | |
| 731 | auto add = [&](StringRef n, std::vector<Chunk *> &v) { | |
| 732 | PartialSection *pSec = createPartialSection(n, rdata); | |
| 733 | pSec->chunks.insert(pSec->chunks.end(), v.begin(), v.end()); | |
| 662 | 734 | }; |
| 663 | 735 | |
| 664 | 736 | // The loader assumes a specific order of data. |
| 665 | 737 | // Add each type in the correct order. |
| 666 | Add(".idata$2", Idata.Dirs); | |
| 667 | Add(".idata$4", Idata.Lookups); | |
| 668 | Add(".idata$5", Idata.Addresses); | |
| 669 | Add(".idata$6", Idata.Hints); | |
| 670 | Add(".idata$7", Idata.DLLNames); | |
| 738 | add(".idata$2", idata.dirs); | |
| 739 | add(".idata$4", idata.lookups); | |
| 740 | add(".idata$5", idata.addresses); | |
| 741 | add(".idata$6", idata.hints); | |
| 742 | add(".idata$7", idata.dllNames); | |
| 671 | 743 | } |
| 672 | 744 | |
| 673 | 745 | // Locate the first Chunk and size of the import directory list and the |
| 674 | 746 | // IAT. |
| 675 | void Writer::locateImportTables( | |
| 676 | std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map) { | |
| 677 | uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; | |
| 678 | std::vector<Chunk *> &ImportTables = Map[{".idata$2", RDATA}]; | |
| 679 | if (!ImportTables.empty()) | |
| 680 | ImportTableStart = ImportTables.front(); | |
| 681 | for (Chunk *C : ImportTables) | |
| 682 | ImportTableSize += C->getSize(); | |
| 683 | ||
| 684 | std::vector<Chunk *> &IAT = Map[{".idata$5", RDATA}]; | |
| 685 | if (!IAT.empty()) | |
| 686 | IATStart = IAT.front(); | |
| 687 | for (Chunk *C : IAT) | |
| 688 | IATSize += C->getSize(); | |
| 747 | void Writer::locateImportTables() { | |
| 748 | uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; | |
| 749 | ||
| 750 | if (PartialSection *importDirs = findPartialSection(".idata$2", rdata)) { | |
| 751 | if (!importDirs->chunks.empty()) | |
| 752 | importTableStart = importDirs->chunks.front(); | |
| 753 | for (Chunk *c : importDirs->chunks) | |
| 754 | importTableSize += c->getSize(); | |
| 755 | } | |
| 756 | ||
| 757 | if (PartialSection *importAddresses = findPartialSection(".idata$5", rdata)) { | |
| 758 | if (!importAddresses->chunks.empty()) | |
| 759 | iatStart = importAddresses->chunks.front(); | |
| 760 | for (Chunk *c : importAddresses->chunks) | |
| 761 | iatSize += c->getSize(); | |
| 762 | } | |
| 763 | } | |
| 764 | ||
| 765 | // Return whether a SectionChunk's suffix (the dollar and any trailing | |
| 766 | // suffix) should be removed and sorted into the main suffixless | |
| 767 | // PartialSection. | |
| 768 | static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name) { | |
| 769 | // On MinGW, comdat groups are formed by putting the comdat group name | |
| 770 | // after the '$' in the section name. For .eh_frame$<symbol>, that must | |
| 771 | // still be sorted before the .eh_frame trailer from crtend.o, thus just | |
| 772 | // strip the section name trailer. For other sections, such as | |
| 773 | // .tls$$<symbol> (where non-comdat .tls symbols are otherwise stored in | |
| 774 | // ".tls$"), they must be strictly sorted after .tls. And for the | |
| 775 | // hypothetical case of comdat .CRT$XCU, we definitely need to keep the | |
| 776 | // suffix for sorting. Thus, to play it safe, only strip the suffix for | |
| 777 | // the standard sections. | |
| 778 | if (!config->mingw) | |
| 779 | return false; | |
| 780 | if (!sc || !sc->isCOMDAT()) | |
| 781 | return false; | |
| 782 | return name.startswith(".text$") || name.startswith(".data$") || | |
| 783 | name.startswith(".rdata$") || name.startswith(".pdata$") || | |
| 784 | name.startswith(".xdata$") || name.startswith(".eh_frame$"); | |
| 689 | 785 | } |
| 690 | 786 | |
| 691 | 787 | // Create output section objects and add them to OutputSections. |
| 692 | 788 | void Writer::createSections() { |
| 693 | 789 | // First, create the builtin sections. |
| 694 | const uint32_t DATA = IMAGE_SCN_CNT_INITIALIZED_DATA; | |
| 695 | const uint32_t BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA; | |
| 696 | const uint32_t CODE = IMAGE_SCN_CNT_CODE; | |
| 697 | const uint32_t DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE; | |
| 698 | const uint32_t R = IMAGE_SCN_MEM_READ; | |
| 699 | const uint32_t W = IMAGE_SCN_MEM_WRITE; | |
| 700 | const uint32_t X = IMAGE_SCN_MEM_EXECUTE; | |
| 701 | ||
| 702 | SmallDenseMap<std::pair<StringRef, uint32_t>, OutputSection *> Sections; | |
| 703 | auto CreateSection = [&](StringRef Name, uint32_t OutChars) { | |
| 704 | OutputSection *&Sec = Sections[{Name, OutChars}]; | |
| 705 | if (!Sec) { | |
| 706 | Sec = make<OutputSection>(Name, OutChars); | |
| 707 | OutputSections.push_back(Sec); | |
| 790 | const uint32_t data = IMAGE_SCN_CNT_INITIALIZED_DATA; | |
| 791 | const uint32_t bss = IMAGE_SCN_CNT_UNINITIALIZED_DATA; | |
| 792 | const uint32_t code = IMAGE_SCN_CNT_CODE; | |
| 793 | const uint32_t discardable = IMAGE_SCN_MEM_DISCARDABLE; | |
| 794 | const uint32_t r = IMAGE_SCN_MEM_READ; | |
| 795 | const uint32_t w = IMAGE_SCN_MEM_WRITE; | |
| 796 | const uint32_t x = IMAGE_SCN_MEM_EXECUTE; | |
| 797 | ||
| 798 | SmallDenseMap<std::pair<StringRef, uint32_t>, OutputSection *> sections; | |
| 799 | auto createSection = [&](StringRef name, uint32_t outChars) { | |
| 800 | OutputSection *&sec = sections[{name, outChars}]; | |
| 801 | if (!sec) { | |
| 802 | sec = make<OutputSection>(name, outChars); | |
| 803 | outputSections.push_back(sec); | |
| 708 | 804 | } |
| 709 | return Sec; | |
| 805 | return sec; | |
| 710 | 806 | }; |
| 711 | 807 | |
| 712 | 808 | // Try to match the section order used by link.exe. |
| 713 | TextSec = CreateSection(".text", CODE | R | X); | |
| 714 | CreateSection(".bss", BSS | R | W); | |
| 715 | RdataSec = CreateSection(".rdata", DATA | R); | |
| 716 | BuildidSec = CreateSection(".buildid", DATA | R); | |
| 717 | DataSec = CreateSection(".data", DATA | R | W); | |
| 718 | PdataSec = CreateSection(".pdata", DATA | R); | |
| 719 | IdataSec = CreateSection(".idata", DATA | R); | |
| 720 | EdataSec = CreateSection(".edata", DATA | R); | |
| 721 | DidatSec = CreateSection(".didat", DATA | R); | |
| 722 | RsrcSec = CreateSection(".rsrc", DATA | R); | |
| 723 | RelocSec = CreateSection(".reloc", DATA | DISCARDABLE | R); | |
| 724 | CtorsSec = CreateSection(".ctors", DATA | R | W); | |
| 725 | DtorsSec = CreateSection(".dtors", DATA | R | W); | |
| 809 | textSec = createSection(".text", code | r | x); | |
| 810 | createSection(".bss", bss | r | w); | |
| 811 | rdataSec = createSection(".rdata", data | r); | |
| 812 | buildidSec = createSection(".buildid", data | r); | |
| 813 | dataSec = createSection(".data", data | r | w); | |
| 814 | pdataSec = createSection(".pdata", data | r); | |
| 815 | idataSec = createSection(".idata", data | r); | |
| 816 | edataSec = createSection(".edata", data | r); | |
| 817 | didatSec = createSection(".didat", data | r); | |
| 818 | rsrcSec = createSection(".rsrc", data | r); | |
| 819 | relocSec = createSection(".reloc", data | discardable | r); | |
| 820 | ctorsSec = createSection(".ctors", data | r | w); | |
| 821 | dtorsSec = createSection(".dtors", data | r | w); | |
| 726 | 822 | |
| 727 | 823 | // Then bin chunks by name and output characteristics. |
| 728 | std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> Map; | |
| 729 | for (Chunk *C : Symtab->getChunks()) { | |
| 730 | auto *SC = dyn_cast<SectionChunk>(C); | |
| 731 | if (SC && !SC->Live) { | |
| 732 | if (Config->Verbose) | |
| 733 | SC->printDiscardedMessage(); | |
| 824 | for (Chunk *c : symtab->getChunks()) { | |
| 825 | auto *sc = dyn_cast<SectionChunk>(c); | |
| 826 | if (sc && !sc->live) { | |
| 827 | if (config->verbose) | |
| 828 | sc->printDiscardedMessage(); | |
| 734 | 829 | continue; |
| 735 | 830 | } |
| 736 | Map[{C->getSectionName(), C->getOutputCharacteristics()}].push_back(C); | |
| 831 | StringRef name = c->getSectionName(); | |
| 832 | if (shouldStripSectionSuffix(sc, name)) | |
| 833 | name = name.split('$').first; | |
| 834 | PartialSection *pSec = createPartialSection(name, | |
| 835 | c->getOutputCharacteristics()); | |
| 836 | pSec->chunks.push_back(c); | |
| 737 | 837 | } |
| 738 | 838 | |
| 839 | fixPartialSectionChars(".rsrc", data | r); | |
| 739 | 840 | // Even in non MinGW cases, we might need to link against GNU import |
| 740 | 841 | // libraries. |
| 741 | bool HasIdata = fixGnuImportChunks(Map); | |
| 742 | if (!Idata.empty()) | |
| 743 | HasIdata = true; | |
| 842 | bool hasIdata = fixGnuImportChunks(); | |
| 843 | if (!idata.empty()) | |
| 844 | hasIdata = true; | |
| 744 | 845 | |
| 745 | if (HasIdata) | |
| 746 | addSyntheticIdata(Idata, Map); | |
| 846 | if (hasIdata) | |
| 847 | addSyntheticIdata(); | |
| 747 | 848 | |
| 748 | 849 | // Process an /order option. |
| 749 | if (!Config->Order.empty()) | |
| 750 | for (auto &Pair : Map) | |
| 751 | sortBySectionOrder(Pair.second); | |
| 850 | if (!config->order.empty()) | |
| 851 | for (auto it : partialSections) | |
| 852 | sortBySectionOrder(it.second->chunks); | |
| 752 | 853 | |
| 753 | if (HasIdata) | |
| 754 | locateImportTables(Map); | |
| 854 | if (hasIdata) | |
| 855 | locateImportTables(); | |
| 755 | 856 | |
| 756 | 857 | // Then create an OutputSection for each section. |
| 757 | 858 | // '$' and all following characters in input section names are |
| 758 | 859 | // discarded when determining output section. So, .text$foo |
| 759 | 860 | // contributes to .text, for example. See PE/COFF spec 3.2. |
| 760 | for (auto &Pair : Map) { | |
| 761 | StringRef Name = getOutputSectionName(Pair.first.first); | |
| 762 | uint32_t OutChars = Pair.first.second; | |
| 861 | for (auto it : partialSections) { | |
| 862 | PartialSection *pSec = it.second; | |
| 863 | StringRef name = getOutputSectionName(pSec->name); | |
| 864 | uint32_t outChars = pSec->characteristics; | |
| 763 | 865 | |
| 764 | if (Name == ".CRT") { | |
| 866 | if (name == ".CRT") { | |
| 765 | 867 | // In link.exe, there is a special case for the I386 target where .CRT |
| 766 | 868 | // sections are treated as if they have output characteristics DATA | R if |
| 767 | 869 | // their characteristics are DATA | R | W. This implements the same |
| 768 | 870 | // special case for all architectures. |
| 769 | OutChars = DATA | R; | |
| 871 | outChars = data | r; | |
| 770 | 872 | |
| 771 | log("Processing section " + Pair.first.first + " -> " + Name); | |
| 873 | log("Processing section " + pSec->name + " -> " + name); | |
| 772 | 874 | |
| 773 | sortCRTSectionChunks(Pair.second); | |
| 875 | sortCRTSectionChunks(pSec->chunks); | |
| 774 | 876 | } |
| 775 | 877 | |
| 776 | OutputSection *Sec = CreateSection(Name, OutChars); | |
| 777 | std::vector<Chunk *> &Chunks = Pair.second; | |
| 778 | for (Chunk *C : Chunks) | |
| 779 | Sec->addChunk(C); | |
| 878 | OutputSection *sec = createSection(name, outChars); | |
| 879 | for (Chunk *c : pSec->chunks) | |
| 880 | sec->addChunk(c); | |
| 881 | ||
| 882 | sec->addContributingPartialSection(pSec); | |
| 780 | 883 | } |
| 781 | 884 | |
| 782 | 885 | // Finally, move some output sections to the end. |
| 783 | auto SectionOrder = [&](OutputSection *S) { | |
| 784 | // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because | |
| 785 | // the loader cannot handle holes. Stripping can remove other discardable ones | |
| 786 | // than .reloc, which is first of them (created early). | |
| 787 | if (S->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) | |
| 886 | auto sectionOrder = [&](const OutputSection *s) { | |
| 887 | // Move DISCARDABLE (or non-memory-mapped) sections to the end of file | |
| 888 | // because the loader cannot handle holes. Stripping can remove other | |
| 889 | // discardable ones than .reloc, which is first of them (created early). | |
| 890 | if (s->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) | |
| 788 | 891 | return 2; |
| 789 | 892 | // .rsrc should come at the end of the non-discardable sections because its |
| 790 | 893 | // size may change by the Win32 UpdateResources() function, causing |
| 791 | 894 | // subsequent sections to move (see https://crbug.com/827082). |
| 792 | if (S == RsrcSec) | |
| 895 | if (s == rsrcSec) | |
| 793 | 896 | return 1; |
| 794 | 897 | return 0; |
| 795 | 898 | }; |
| 796 | std::stable_sort(OutputSections.begin(), OutputSections.end(), | |
| 797 | [&](OutputSection *S, OutputSection *T) { | |
| 798 | return SectionOrder(S) < SectionOrder(T); | |
| 799 | }); | |
| 899 | llvm::stable_sort(outputSections, | |
| 900 | [&](const OutputSection *s, const OutputSection *t) { | |
| 901 | return sectionOrder(s) < sectionOrder(t); | |
| 902 | }); | |
| 800 | 903 | } |
| 801 | 904 | |
| 802 | 905 | void Writer::createMiscChunks() { |
| 803 | for (auto &P : MergeChunk::Instances) | |
| 804 | RdataSec->addChunk(P.second); | |
| 906 | for (MergeChunk *p : MergeChunk::instances) { | |
| 907 | if (p) { | |
| 908 | p->finalizeContents(); | |
| 909 | rdataSec->addChunk(p); | |
| 910 | } | |
| 911 | } | |
| 805 | 912 | |
| 806 | 913 | // Create thunks for locally-dllimported symbols. |
| 807 | if (!Symtab->LocalImportChunks.empty()) { | |
| 808 | for (Chunk *C : Symtab->LocalImportChunks) | |
| 809 | RdataSec->addChunk(C); | |
| 914 | if (!symtab->localImportChunks.empty()) { | |
| 915 | for (Chunk *c : symtab->localImportChunks) | |
| 916 | rdataSec->addChunk(c); | |
| 810 | 917 | } |
| 811 | 918 | |
| 812 | 919 | // Create Debug Information Chunks |
| 813 | OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec; | |
| 814 | if (Config->Debug || Config->Repro) { | |
| 815 | DebugDirectory = make<DebugDirectoryChunk>(DebugRecords, Config->Repro); | |
| 816 | DebugInfoSec->addChunk(DebugDirectory); | |
| 920 | OutputSection *debugInfoSec = config->mingw ? buildidSec : rdataSec; | |
| 921 | if (config->debug || config->repro) { | |
| 922 | debugDirectory = make<DebugDirectoryChunk>(debugRecords, config->repro); | |
| 923 | debugInfoSec->addChunk(debugDirectory); | |
| 817 | 924 | } |
| 818 | 925 | |
| 819 | if (Config->Debug) { | |
| 926 | if (config->debug) { | |
| 820 | 927 | // Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We |
| 821 | 928 | // output a PDB no matter what, and this chunk provides the only means of |
| 822 | 929 | // allowing a debugger to match a PDB and an executable. So we need it even |
| 823 | 930 | // if we're ultimately not going to write CodeView data to the PDB. |
| 824 | BuildId = make<CVDebugRecordChunk>(); | |
| 825 | DebugRecords.push_back(BuildId); | |
| 931 | buildId = make<CVDebugRecordChunk>(); | |
| 932 | debugRecords.push_back(buildId); | |
| 826 | 933 | |
| 827 | for (Chunk *C : DebugRecords) | |
| 828 | DebugInfoSec->addChunk(C); | |
| 934 | for (Chunk *c : debugRecords) | |
| 935 | debugInfoSec->addChunk(c); | |
| 829 | 936 | } |
| 830 | 937 | |
| 831 | 938 | // Create SEH table. x86-only. |
| 832 | if (Config->Machine == I386) | |
| 939 | if (config->safeSEH) | |
| 833 | 940 | createSEHTable(); |
| 834 | 941 | |
| 835 | 942 | // Create /guard:cf tables if requested. |
| 836 | if (Config->GuardCF != GuardCFLevel::Off) | |
| 943 | if (config->guardCF != GuardCFLevel::Off) | |
| 837 | 944 | createGuardCFTables(); |
| 838 | 945 | |
| 839 | if (Config->MinGW) { | |
| 946 | if (config->mingw) { | |
| 840 | 947 | createRuntimePseudoRelocs(); |
| 841 | 948 | |
| 842 | 949 | insertCtorDtorSymbols(); |
| ... | ... | @@ -851,106 +958,123 @@ void Writer::createImportTables() { |
| 851 | 958 | // Initialize DLLOrder so that import entries are ordered in |
| 852 | 959 | // the same order as in the command line. (That affects DLL |
| 853 | 960 | // initialization order, and this ordering is MSVC-compatible.) |
| 854 | for (ImportFile *File : ImportFile::Instances) { | |
| 855 | if (!File->Live) | |
| 961 | for (ImportFile *file : ImportFile::instances) { | |
| 962 | if (!file->live) | |
| 856 | 963 | continue; |
| 857 | 964 | |
| 858 | std::string DLL = StringRef(File->DLLName).lower(); | |
| 859 | if (Config->DLLOrder.count(DLL) == 0) | |
| 860 | Config->DLLOrder[DLL] = Config->DLLOrder.size(); | |
| 861 | ||
| 862 | if (File->ImpSym && !isa<DefinedImportData>(File->ImpSym)) | |
| 863 | fatal(toString(*File->ImpSym) + " was replaced"); | |
| 864 | DefinedImportData *ImpSym = cast_or_null<DefinedImportData>(File->ImpSym); | |
| 865 | if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) { | |
| 866 | if (!File->ThunkSym) | |
| 867 | fatal("cannot delay-load " + toString(File) + | |
| 868 | " due to import of data: " + toString(*ImpSym)); | |
| 869 | DelayIdata.add(ImpSym); | |
| 965 | std::string dll = StringRef(file->dllName).lower(); | |
| 966 | if (config->dllOrder.count(dll) == 0) | |
| 967 | config->dllOrder[dll] = config->dllOrder.size(); | |
| 968 | ||
| 969 | if (file->impSym && !isa<DefinedImportData>(file->impSym)) | |
| 970 | fatal(toString(*file->impSym) + " was replaced"); | |
| 971 | DefinedImportData *impSym = cast_or_null<DefinedImportData>(file->impSym); | |
| 972 | if (config->delayLoads.count(StringRef(file->dllName).lower())) { | |
| 973 | if (!file->thunkSym) | |
| 974 | fatal("cannot delay-load " + toString(file) + | |
| 975 | " due to import of data: " + toString(*impSym)); | |
| 976 | delayIdata.add(impSym); | |
| 870 | 977 | } else { |
| 871 | Idata.add(ImpSym); | |
| 978 | idata.add(impSym); | |
| 872 | 979 | } |
| 873 | 980 | } |
| 874 | 981 | } |
| 875 | 982 | |
| 876 | 983 | void Writer::appendImportThunks() { |
| 877 | if (ImportFile::Instances.empty()) | |
| 984 | if (ImportFile::instances.empty()) | |
| 878 | 985 | return; |
| 879 | 986 | |
| 880 | for (ImportFile *File : ImportFile::Instances) { | |
| 881 | if (!File->Live) | |
| 987 | for (ImportFile *file : ImportFile::instances) { | |
| 988 | if (!file->live) | |
| 882 | 989 | continue; |
| 883 | 990 | |
| 884 | if (!File->ThunkSym) | |
| 991 | if (!file->thunkSym) | |
| 885 | 992 | continue; |
| 886 | 993 | |
| 887 | if (!isa<DefinedImportThunk>(File->ThunkSym)) | |
| 888 | fatal(toString(*File->ThunkSym) + " was replaced"); | |
| 889 | DefinedImportThunk *Thunk = cast<DefinedImportThunk>(File->ThunkSym); | |
| 890 | if (File->ThunkLive) | |
| 891 | TextSec->addChunk(Thunk->getChunk()); | |
| 994 | if (!isa<DefinedImportThunk>(file->thunkSym)) | |
| 995 | fatal(toString(*file->thunkSym) + " was replaced"); | |
| 996 | DefinedImportThunk *thunk = cast<DefinedImportThunk>(file->thunkSym); | |
| 997 | if (file->thunkLive) | |
| 998 | textSec->addChunk(thunk->getChunk()); | |
| 892 | 999 | } |
| 893 | 1000 | |
| 894 | if (!DelayIdata.empty()) { | |
| 895 | Defined *Helper = cast<Defined>(Config->DelayLoadHelper); | |
| 896 | DelayIdata.create(Helper); | |
| 897 | for (Chunk *C : DelayIdata.getChunks()) | |
| 898 | DidatSec->addChunk(C); | |
| 899 | for (Chunk *C : DelayIdata.getDataChunks()) | |
| 900 | DataSec->addChunk(C); | |
| 901 | for (Chunk *C : DelayIdata.getCodeChunks()) | |
| 902 | TextSec->addChunk(C); | |
| 1001 | if (!delayIdata.empty()) { | |
| 1002 | Defined *helper = cast<Defined>(config->delayLoadHelper); | |
| 1003 | delayIdata.create(helper); | |
| 1004 | for (Chunk *c : delayIdata.getChunks()) | |
| 1005 | didatSec->addChunk(c); | |
| 1006 | for (Chunk *c : delayIdata.getDataChunks()) | |
| 1007 | dataSec->addChunk(c); | |
| 1008 | for (Chunk *c : delayIdata.getCodeChunks()) | |
| 1009 | textSec->addChunk(c); | |
| 903 | 1010 | } |
| 904 | 1011 | } |
| 905 | 1012 | |
| 906 | 1013 | void Writer::createExportTable() { |
| 907 | if (Config->Exports.empty()) | |
| 1014 | if (config->exports.empty()) | |
| 908 | 1015 | return; |
| 909 | for (Chunk *C : Edata.Chunks) | |
| 910 | EdataSec->addChunk(C); | |
| 1016 | for (Chunk *c : edata.chunks) | |
| 1017 | edataSec->addChunk(c); | |
| 911 | 1018 | } |
| 912 | 1019 | |
| 913 | 1020 | void Writer::removeUnusedSections() { |
| 914 | 1021 | // Remove sections that we can be sure won't get content, to avoid |
| 915 | 1022 | // allocating space for their section headers. |
| 916 | auto IsUnused = [this](OutputSection *S) { | |
| 917 | if (S == RelocSec) | |
| 1023 | auto isUnused = [this](OutputSection *s) { | |
| 1024 | if (s == relocSec) | |
| 918 | 1025 | return false; // This section is populated later. |
| 919 | 1026 | // MergeChunks have zero size at this point, as their size is finalized |
| 920 | 1027 | // later. Only remove sections that have no Chunks at all. |
| 921 | return S->Chunks.empty(); | |
| 1028 | return s->chunks.empty(); | |
| 922 | 1029 | }; |
| 923 | OutputSections.erase( | |
| 924 | std::remove_if(OutputSections.begin(), OutputSections.end(), IsUnused), | |
| 925 | OutputSections.end()); | |
| 1030 | outputSections.erase( | |
| 1031 | std::remove_if(outputSections.begin(), outputSections.end(), isUnused), | |
| 1032 | outputSections.end()); | |
| 926 | 1033 | } |
| 927 | 1034 | |
| 928 | 1035 | // The Windows loader doesn't seem to like empty sections, |
| 929 | 1036 | // so we remove them if any. |
| 930 | 1037 | void Writer::removeEmptySections() { |
| 931 | auto IsEmpty = [](OutputSection *S) { return S->getVirtualSize() == 0; }; | |
| 932 | OutputSections.erase( | |
| 933 | std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty), | |
| 934 | OutputSections.end()); | |
| 935 | uint32_t Idx = 1; | |
| 936 | for (OutputSection *Sec : OutputSections) | |
| 937 | Sec->SectionIndex = Idx++; | |
| 1038 | auto isEmpty = [](OutputSection *s) { return s->getVirtualSize() == 0; }; | |
| 1039 | outputSections.erase( | |
| 1040 | std::remove_if(outputSections.begin(), outputSections.end(), isEmpty), | |
| 1041 | outputSections.end()); | |
| 938 | 1042 | } |
| 939 | 1043 | |
| 940 | size_t Writer::addEntryToStringTable(StringRef Str) { | |
| 941 | assert(Str.size() > COFF::NameSize); | |
| 942 | size_t OffsetOfEntry = Strtab.size() + 4; // +4 for the size field | |
| 943 | Strtab.insert(Strtab.end(), Str.begin(), Str.end()); | |
| 944 | Strtab.push_back('\0'); | |
| 945 | return OffsetOfEntry; | |
| 1044 | void Writer::assignOutputSectionIndices() { | |
| 1045 | // Assign final output section indices, and assign each chunk to its output | |
| 1046 | // section. | |
| 1047 | uint32_t idx = 1; | |
| 1048 | for (OutputSection *os : outputSections) { | |
| 1049 | os->sectionIndex = idx; | |
| 1050 | for (Chunk *c : os->chunks) | |
| 1051 | c->setOutputSectionIdx(idx); | |
| 1052 | ++idx; | |
| 1053 | } | |
| 1054 | ||
| 1055 | // Merge chunks are containers of chunks, so assign those an output section | |
| 1056 | // too. | |
| 1057 | for (MergeChunk *mc : MergeChunk::instances) | |
| 1058 | if (mc) | |
| 1059 | for (SectionChunk *sc : mc->sections) | |
| 1060 | if (sc && sc->live) | |
| 1061 | sc->setOutputSectionIdx(mc->getOutputSectionIdx()); | |
| 946 | 1062 | } |
| 947 | 1063 | |
| 948 | Optional<coff_symbol16> Writer::createSymbol(Defined *Def) { | |
| 949 | coff_symbol16 Sym; | |
| 950 | switch (Def->kind()) { | |
| 1064 | size_t Writer::addEntryToStringTable(StringRef str) { | |
| 1065 | assert(str.size() > COFF::NameSize); | |
| 1066 | size_t offsetOfEntry = strtab.size() + 4; // +4 for the size field | |
| 1067 | strtab.insert(strtab.end(), str.begin(), str.end()); | |
| 1068 | strtab.push_back('\0'); | |
| 1069 | return offsetOfEntry; | |
| 1070 | } | |
| 1071 | ||
| 1072 | Optional<coff_symbol16> Writer::createSymbol(Defined *def) { | |
| 1073 | coff_symbol16 sym; | |
| 1074 | switch (def->kind()) { | |
| 951 | 1075 | case Symbol::DefinedAbsoluteKind: |
| 952 | Sym.Value = Def->getRVA(); | |
| 953 | Sym.SectionNumber = IMAGE_SYM_ABSOLUTE; | |
| 1076 | sym.Value = def->getRVA(); | |
| 1077 | sym.SectionNumber = IMAGE_SYM_ABSOLUTE; | |
| 954 | 1078 | break; |
| 955 | 1079 | case Symbol::DefinedSyntheticKind: |
| 956 | 1080 | // Relative symbols are unrepresentable in a COFF symbol table. |
| ... | ... | @@ -958,38 +1082,38 @@ Optional<coff_symbol16> Writer::createSymbol(Defined *Def) { |
| 958 | 1082 | default: { |
| 959 | 1083 | // Don't write symbols that won't be written to the output to the symbol |
| 960 | 1084 | // table. |
| 961 | Chunk *C = Def->getChunk(); | |
| 962 | if (!C) | |
| 1085 | Chunk *c = def->getChunk(); | |
| 1086 | if (!c) | |
| 963 | 1087 | return None; |
| 964 | OutputSection *OS = C->getOutputSection(); | |
| 965 | if (!OS) | |
| 1088 | OutputSection *os = c->getOutputSection(); | |
| 1089 | if (!os) | |
| 966 | 1090 | return None; |
| 967 | 1091 | |
| 968 | Sym.Value = Def->getRVA() - OS->getRVA(); | |
| 969 | Sym.SectionNumber = OS->SectionIndex; | |
| 1092 | sym.Value = def->getRVA() - os->getRVA(); | |
| 1093 | sym.SectionNumber = os->sectionIndex; | |
| 970 | 1094 | break; |
| 971 | 1095 | } |
| 972 | 1096 | } |
| 973 | 1097 | |
| 974 | StringRef Name = Def->getName(); | |
| 975 | if (Name.size() > COFF::NameSize) { | |
| 976 | Sym.Name.Offset.Zeroes = 0; | |
| 977 | Sym.Name.Offset.Offset = addEntryToStringTable(Name); | |
| 1098 | StringRef name = def->getName(); | |
| 1099 | if (name.size() > COFF::NameSize) { | |
| 1100 | sym.Name.Offset.Zeroes = 0; | |
| 1101 | sym.Name.Offset.Offset = addEntryToStringTable(name); | |
| 978 | 1102 | } else { |
| 979 | memset(Sym.Name.ShortName, 0, COFF::NameSize); | |
| 980 | memcpy(Sym.Name.ShortName, Name.data(), Name.size()); | |
| 1103 | memset(sym.Name.ShortName, 0, COFF::NameSize); | |
| 1104 | memcpy(sym.Name.ShortName, name.data(), name.size()); | |
| 981 | 1105 | } |
| 982 | 1106 | |
| 983 | if (auto *D = dyn_cast<DefinedCOFF>(Def)) { | |
| 984 | COFFSymbolRef Ref = D->getCOFFSymbol(); | |
| 985 | Sym.Type = Ref.getType(); | |
| 986 | Sym.StorageClass = Ref.getStorageClass(); | |
| 1107 | if (auto *d = dyn_cast<DefinedCOFF>(def)) { | |
| 1108 | COFFSymbolRef ref = d->getCOFFSymbol(); | |
| 1109 | sym.Type = ref.getType(); | |
| 1110 | sym.StorageClass = ref.getStorageClass(); | |
| 987 | 1111 | } else { |
| 988 | Sym.Type = IMAGE_SYM_TYPE_NULL; | |
| 989 | Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; | |
| 1112 | sym.Type = IMAGE_SYM_TYPE_NULL; | |
| 1113 | sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; | |
| 990 | 1114 | } |
| 991 | Sym.NumberOfAuxSymbols = 0; | |
| 992 | return Sym; | |
| 1115 | sym.NumberOfAuxSymbols = 0; | |
| 1116 | return sym; | |
| 993 | 1117 | } |
| 994 | 1118 | |
| 995 | 1119 | void Writer::createSymbolAndStringTable() { |
| ... | ... | @@ -1001,113 +1125,120 @@ void Writer::createSymbolAndStringTable() { |
| 1001 | 1125 | // solution where discardable sections have long names preserved and |
| 1002 | 1126 | // non-discardable sections have their names truncated, to ensure that any |
| 1003 | 1127 | // section which is mapped at runtime also has its name mapped at runtime. |
| 1004 | for (OutputSection *Sec : OutputSections) { | |
| 1005 | if (Sec->Name.size() <= COFF::NameSize) | |
| 1128 | for (OutputSection *sec : outputSections) { | |
| 1129 | if (sec->name.size() <= COFF::NameSize) | |
| 1006 | 1130 | continue; |
| 1007 | if ((Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) | |
| 1131 | if ((sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) | |
| 1008 | 1132 | continue; |
| 1009 | Sec->setStringTableOff(addEntryToStringTable(Sec->Name)); | |
| 1133 | sec->setStringTableOff(addEntryToStringTable(sec->name)); | |
| 1010 | 1134 | } |
| 1011 | 1135 | |
| 1012 | if (Config->DebugDwarf || Config->DebugSymtab) { | |
| 1013 | for (ObjFile *File : ObjFile::Instances) { | |
| 1014 | for (Symbol *B : File->getSymbols()) { | |
| 1015 | auto *D = dyn_cast_or_null<Defined>(B); | |
| 1016 | if (!D || D->WrittenToSymtab) | |
| 1136 | if (config->debugDwarf || config->debugSymtab) { | |
| 1137 | for (ObjFile *file : ObjFile::instances) { | |
| 1138 | for (Symbol *b : file->getSymbols()) { | |
| 1139 | auto *d = dyn_cast_or_null<Defined>(b); | |
| 1140 | if (!d || d->writtenToSymtab) | |
| 1017 | 1141 | continue; |
| 1018 | D->WrittenToSymtab = true; | |
| 1142 | d->writtenToSymtab = true; | |
| 1019 | 1143 | |
| 1020 | if (Optional<coff_symbol16> Sym = createSymbol(D)) | |
| 1021 | OutputSymtab.push_back(*Sym); | |
| 1144 | if (Optional<coff_symbol16> sym = createSymbol(d)) | |
| 1145 | outputSymtab.push_back(*sym); | |
| 1022 | 1146 | } |
| 1023 | 1147 | } |
| 1024 | 1148 | } |
| 1025 | 1149 | |
| 1026 | if (OutputSymtab.empty() && Strtab.empty()) | |
| 1150 | if (outputSymtab.empty() && strtab.empty()) | |
| 1027 | 1151 | return; |
| 1028 | 1152 | |
| 1029 | 1153 | // We position the symbol table to be adjacent to the end of the last section. |
| 1030 | uint64_t FileOff = FileSize; | |
| 1031 | PointerToSymbolTable = FileOff; | |
| 1032 | FileOff += OutputSymtab.size() * sizeof(coff_symbol16); | |
| 1033 | FileOff += 4 + Strtab.size(); | |
| 1034 | FileSize = alignTo(FileOff, SectorSize); | |
| 1154 | uint64_t fileOff = fileSize; | |
| 1155 | pointerToSymbolTable = fileOff; | |
| 1156 | fileOff += outputSymtab.size() * sizeof(coff_symbol16); | |
| 1157 | fileOff += 4 + strtab.size(); | |
| 1158 | fileSize = alignTo(fileOff, config->fileAlign); | |
| 1035 | 1159 | } |
| 1036 | 1160 | |
| 1037 | 1161 | void Writer::mergeSections() { |
| 1038 | if (!PdataSec->Chunks.empty()) { | |
| 1039 | FirstPdata = PdataSec->Chunks.front(); | |
| 1040 | LastPdata = PdataSec->Chunks.back(); | |
| 1162 | if (!pdataSec->chunks.empty()) { | |
| 1163 | firstPdata = pdataSec->chunks.front(); | |
| 1164 | lastPdata = pdataSec->chunks.back(); | |
| 1041 | 1165 | } |
| 1042 | 1166 | |
| 1043 | for (auto &P : Config->Merge) { | |
| 1044 | StringRef ToName = P.second; | |
| 1045 | if (P.first == ToName) | |
| 1167 | for (auto &p : config->merge) { | |
| 1168 | StringRef toName = p.second; | |
| 1169 | if (p.first == toName) | |
| 1046 | 1170 | continue; |
| 1047 | StringSet<> Names; | |
| 1171 | StringSet<> names; | |
| 1048 | 1172 | while (1) { |
| 1049 | if (!Names.insert(ToName).second) | |
| 1050 | fatal("/merge: cycle found for section '" + P.first + "'"); | |
| 1051 | auto I = Config->Merge.find(ToName); | |
| 1052 | if (I == Config->Merge.end()) | |
| 1173 | if (!names.insert(toName).second) | |
| 1174 | fatal("/merge: cycle found for section '" + p.first + "'"); | |
| 1175 | auto i = config->merge.find(toName); | |
| 1176 | if (i == config->merge.end()) | |
| 1053 | 1177 | break; |
| 1054 | ToName = I->second; | |
| 1178 | toName = i->second; | |
| 1055 | 1179 | } |
| 1056 | OutputSection *From = findSection(P.first); | |
| 1057 | OutputSection *To = findSection(ToName); | |
| 1058 | if (!From) | |
| 1180 | OutputSection *from = findSection(p.first); | |
| 1181 | OutputSection *to = findSection(toName); | |
| 1182 | if (!from) | |
| 1059 | 1183 | continue; |
| 1060 | if (!To) { | |
| 1061 | From->Name = ToName; | |
| 1184 | if (!to) { | |
| 1185 | from->name = toName; | |
| 1062 | 1186 | continue; |
| 1063 | 1187 | } |
| 1064 | To->merge(From); | |
| 1188 | to->merge(from); | |
| 1065 | 1189 | } |
| 1066 | 1190 | } |
| 1067 | 1191 | |
| 1068 | // Visits all sections to initialize their relocation targets. | |
| 1069 | void Writer::readRelocTargets() { | |
| 1070 | for (OutputSection *Sec : OutputSections) | |
| 1071 | for_each(parallel::par, Sec->Chunks.begin(), Sec->Chunks.end(), | |
| 1072 | [&](Chunk *C) { C->readRelocTargets(); }); | |
| 1073 | } | |
| 1074 | ||
| 1075 | 1192 | // Visits all sections to assign incremental, non-overlapping RVAs and |
| 1076 | 1193 | // file offsets. |
| 1077 | 1194 | void Writer::assignAddresses() { |
| 1078 | SizeOfHeaders = DOSStubSize + sizeof(PEMagic) + sizeof(coff_file_header) + | |
| 1079 | sizeof(data_directory) * NumberOfDataDirectory + | |
| 1080 | sizeof(coff_section) * OutputSections.size(); | |
| 1081 | SizeOfHeaders += | |
| 1082 | Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); | |
| 1083 | SizeOfHeaders = alignTo(SizeOfHeaders, SectorSize); | |
| 1084 | uint64_t RVA = PageSize; // The first page is kept unmapped. | |
| 1085 | FileSize = SizeOfHeaders; | |
| 1086 | ||
| 1087 | for (OutputSection *Sec : OutputSections) { | |
| 1088 | if (Sec == RelocSec) | |
| 1195 | sizeOfHeaders = dosStubSize + sizeof(PEMagic) + sizeof(coff_file_header) + | |
| 1196 | sizeof(data_directory) * numberOfDataDirectory + | |
| 1197 | sizeof(coff_section) * outputSections.size(); | |
| 1198 | sizeOfHeaders += | |
| 1199 | config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); | |
| 1200 | sizeOfHeaders = alignTo(sizeOfHeaders, config->fileAlign); | |
| 1201 | uint64_t rva = pageSize; // The first page is kept unmapped. | |
| 1202 | fileSize = sizeOfHeaders; | |
| 1203 | ||
| 1204 | for (OutputSection *sec : outputSections) { | |
| 1205 | if (sec == relocSec) | |
| 1089 | 1206 | addBaserels(); |
| 1090 | uint64_t RawSize = 0, VirtualSize = 0; | |
| 1091 | Sec->Header.VirtualAddress = RVA; | |
| 1092 | for (Chunk *C : Sec->Chunks) { | |
| 1093 | VirtualSize = alignTo(VirtualSize, C->Alignment); | |
| 1094 | C->setRVA(RVA + VirtualSize); | |
| 1095 | C->OutputSectionOff = VirtualSize; | |
| 1096 | C->finalizeContents(); | |
| 1097 | VirtualSize += C->getSize(); | |
| 1098 | if (C->hasData()) | |
| 1099 | RawSize = alignTo(VirtualSize, SectorSize); | |
| 1207 | uint64_t rawSize = 0, virtualSize = 0; | |
| 1208 | sec->header.VirtualAddress = rva; | |
| 1209 | ||
| 1210 | // If /FUNCTIONPADMIN is used, functions are padded in order to create a | |
| 1211 | // hotpatchable image. | |
| 1212 | const bool isCodeSection = | |
| 1213 | (sec->header.Characteristics & IMAGE_SCN_CNT_CODE) && | |
| 1214 | (sec->header.Characteristics & IMAGE_SCN_MEM_READ) && | |
| 1215 | (sec->header.Characteristics & IMAGE_SCN_MEM_EXECUTE); | |
| 1216 | uint32_t padding = isCodeSection ? config->functionPadMin : 0; | |
| 1217 | ||
| 1218 | for (Chunk *c : sec->chunks) { | |
| 1219 | if (padding && c->isHotPatchable()) | |
| 1220 | virtualSize += padding; | |
| 1221 | virtualSize = alignTo(virtualSize, c->getAlignment()); | |
| 1222 | c->setRVA(rva + virtualSize); | |
| 1223 | virtualSize += c->getSize(); | |
| 1224 | if (c->hasData) | |
| 1225 | rawSize = alignTo(virtualSize, config->fileAlign); | |
| 1100 | 1226 | } |
| 1101 | if (VirtualSize > UINT32_MAX) | |
| 1102 | error("section larger than 4 GiB: " + Sec->Name); | |
| 1103 | Sec->Header.VirtualSize = VirtualSize; | |
| 1104 | Sec->Header.SizeOfRawData = RawSize; | |
| 1105 | if (RawSize != 0) | |
| 1106 | Sec->Header.PointerToRawData = FileSize; | |
| 1107 | RVA += alignTo(VirtualSize, PageSize); | |
| 1108 | FileSize += alignTo(RawSize, SectorSize); | |
| 1109 | } | |
| 1110 | SizeOfImage = alignTo(RVA, PageSize); | |
| 1227 | if (virtualSize > UINT32_MAX) | |
| 1228 | error("section larger than 4 GiB: " + sec->name); | |
| 1229 | sec->header.VirtualSize = virtualSize; | |
| 1230 | sec->header.SizeOfRawData = rawSize; | |
| 1231 | if (rawSize != 0) | |
| 1232 | sec->header.PointerToRawData = fileSize; | |
| 1233 | rva += alignTo(virtualSize, pageSize); | |
| 1234 | fileSize += alignTo(rawSize, config->fileAlign); | |
| 1235 | } | |
| 1236 | sizeOfImage = alignTo(rva, pageSize); | |
| 1237 | ||
| 1238 | // Assign addresses to sections in MergeChunks. | |
| 1239 | for (MergeChunk *mc : MergeChunk::instances) | |
| 1240 | if (mc) | |
| 1241 | mc->assignSubsectionRVAs(); | |
| 1111 | 1242 | } |
| 1112 | 1243 | |
| 1113 | 1244 | template <typename PEHeaderTy> void Writer::writeHeader() { |
| ... | ... | @@ -1116,275 +1247,299 @@ template <typename PEHeaderTy> void Writer::writeHeader() { |
| 1116 | 1247 | // under DOS, that program gets run (usually to just print an error message). |
| 1117 | 1248 | // When run under Windows, the loader looks at AddressOfNewExeHeader and uses |
| 1118 | 1249 | // the PE header instead. |
| 1119 | uint8_t *Buf = Buffer->getBufferStart(); | |
| 1120 | auto *DOS = reinterpret_cast<dos_header *>(Buf); | |
| 1121 | Buf += sizeof(dos_header); | |
| 1122 | DOS->Magic[0] = 'M'; | |
| 1123 | DOS->Magic[1] = 'Z'; | |
| 1124 | DOS->UsedBytesInTheLastPage = DOSStubSize % 512; | |
| 1125 | DOS->FileSizeInPages = divideCeil(DOSStubSize, 512); | |
| 1126 | DOS->HeaderSizeInParagraphs = sizeof(dos_header) / 16; | |
| 1127 | ||
| 1128 | DOS->AddressOfRelocationTable = sizeof(dos_header); | |
| 1129 | DOS->AddressOfNewExeHeader = DOSStubSize; | |
| 1250 | uint8_t *buf = buffer->getBufferStart(); | |
| 1251 | auto *dos = reinterpret_cast<dos_header *>(buf); | |
| 1252 | buf += sizeof(dos_header); | |
| 1253 | dos->Magic[0] = 'M'; | |
| 1254 | dos->Magic[1] = 'Z'; | |
| 1255 | dos->UsedBytesInTheLastPage = dosStubSize % 512; | |
| 1256 | dos->FileSizeInPages = divideCeil(dosStubSize, 512); | |
| 1257 | dos->HeaderSizeInParagraphs = sizeof(dos_header) / 16; | |
| 1258 | ||
| 1259 | dos->AddressOfRelocationTable = sizeof(dos_header); | |
| 1260 | dos->AddressOfNewExeHeader = dosStubSize; | |
| 1130 | 1261 | |
| 1131 | 1262 | // Write DOS program. |
| 1132 | memcpy(Buf, DOSProgram, sizeof(DOSProgram)); | |
| 1133 | Buf += sizeof(DOSProgram); | |
| 1263 | memcpy(buf, dosProgram, sizeof(dosProgram)); | |
| 1264 | buf += sizeof(dosProgram); | |
| 1134 | 1265 | |
| 1135 | 1266 | // Write PE magic |
| 1136 | memcpy(Buf, PEMagic, sizeof(PEMagic)); | |
| 1137 | Buf += sizeof(PEMagic); | |
| 1267 | memcpy(buf, PEMagic, sizeof(PEMagic)); | |
| 1268 | buf += sizeof(PEMagic); | |
| 1138 | 1269 | |
| 1139 | 1270 | // Write COFF header |
| 1140 | auto *COFF = reinterpret_cast<coff_file_header *>(Buf); | |
| 1141 | Buf += sizeof(*COFF); | |
| 1142 | COFF->Machine = Config->Machine; | |
| 1143 | COFF->NumberOfSections = OutputSections.size(); | |
| 1144 | COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; | |
| 1145 | if (Config->LargeAddressAware) | |
| 1146 | COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; | |
| 1147 | if (!Config->is64()) | |
| 1148 | COFF->Characteristics |= IMAGE_FILE_32BIT_MACHINE; | |
| 1149 | if (Config->DLL) | |
| 1150 | COFF->Characteristics |= IMAGE_FILE_DLL; | |
| 1151 | if (!Config->Relocatable) | |
| 1152 | COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; | |
| 1153 | COFF->SizeOfOptionalHeader = | |
| 1154 | sizeof(PEHeaderTy) + sizeof(data_directory) * NumberOfDataDirectory; | |
| 1271 | auto *coff = reinterpret_cast<coff_file_header *>(buf); | |
| 1272 | buf += sizeof(*coff); | |
| 1273 | coff->Machine = config->machine; | |
| 1274 | coff->NumberOfSections = outputSections.size(); | |
| 1275 | coff->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; | |
| 1276 | if (config->largeAddressAware) | |
| 1277 | coff->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; | |
| 1278 | if (!config->is64()) | |
| 1279 | coff->Characteristics |= IMAGE_FILE_32BIT_MACHINE; | |
| 1280 | if (config->dll) | |
| 1281 | coff->Characteristics |= IMAGE_FILE_DLL; | |
| 1282 | if (!config->relocatable) | |
| 1283 | coff->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; | |
| 1284 | if (config->swaprunCD) | |
| 1285 | coff->Characteristics |= IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP; | |
| 1286 | if (config->swaprunNet) | |
| 1287 | coff->Characteristics |= IMAGE_FILE_NET_RUN_FROM_SWAP; | |
| 1288 | coff->SizeOfOptionalHeader = | |
| 1289 | sizeof(PEHeaderTy) + sizeof(data_directory) * numberOfDataDirectory; | |
| 1155 | 1290 | |
| 1156 | 1291 | // Write PE header |
| 1157 | auto *PE = reinterpret_cast<PEHeaderTy *>(Buf); | |
| 1158 | Buf += sizeof(*PE); | |
| 1159 | PE->Magic = Config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32; | |
| 1292 | auto *pe = reinterpret_cast<PEHeaderTy *>(buf); | |
| 1293 | buf += sizeof(*pe); | |
| 1294 | pe->Magic = config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32; | |
| 1160 | 1295 | |
| 1161 | 1296 | // If {Major,Minor}LinkerVersion is left at 0.0, then for some |
| 1162 | 1297 | // reason signing the resulting PE file with Authenticode produces a |
| 1163 | 1298 | // signature that fails to validate on Windows 7 (but is OK on 10). |
| 1164 | 1299 | // Set it to 14.0, which is what VS2015 outputs, and which avoids |
| 1165 | 1300 | // that problem. |
| 1166 | PE->MajorLinkerVersion = 14; | |
| 1167 | PE->MinorLinkerVersion = 0; | |
| 1168 | ||
| 1169 | PE->ImageBase = Config->ImageBase; | |
| 1170 | PE->SectionAlignment = PageSize; | |
| 1171 | PE->FileAlignment = SectorSize; | |
| 1172 | PE->MajorImageVersion = Config->MajorImageVersion; | |
| 1173 | PE->MinorImageVersion = Config->MinorImageVersion; | |
| 1174 | PE->MajorOperatingSystemVersion = Config->MajorOSVersion; | |
| 1175 | PE->MinorOperatingSystemVersion = Config->MinorOSVersion; | |
| 1176 | PE->MajorSubsystemVersion = Config->MajorOSVersion; | |
| 1177 | PE->MinorSubsystemVersion = Config->MinorOSVersion; | |
| 1178 | PE->Subsystem = Config->Subsystem; | |
| 1179 | PE->SizeOfImage = SizeOfImage; | |
| 1180 | PE->SizeOfHeaders = SizeOfHeaders; | |
| 1181 | if (!Config->NoEntry) { | |
| 1182 | Defined *Entry = cast<Defined>(Config->Entry); | |
| 1183 | PE->AddressOfEntryPoint = Entry->getRVA(); | |
| 1301 | pe->MajorLinkerVersion = 14; | |
| 1302 | pe->MinorLinkerVersion = 0; | |
| 1303 | ||
| 1304 | pe->ImageBase = config->imageBase; | |
| 1305 | pe->SectionAlignment = pageSize; | |
| 1306 | pe->FileAlignment = config->fileAlign; | |
| 1307 | pe->MajorImageVersion = config->majorImageVersion; | |
| 1308 | pe->MinorImageVersion = config->minorImageVersion; | |
| 1309 | pe->MajorOperatingSystemVersion = config->majorOSVersion; | |
| 1310 | pe->MinorOperatingSystemVersion = config->minorOSVersion; | |
| 1311 | pe->MajorSubsystemVersion = config->majorOSVersion; | |
| 1312 | pe->MinorSubsystemVersion = config->minorOSVersion; | |
| 1313 | pe->Subsystem = config->subsystem; | |
| 1314 | pe->SizeOfImage = sizeOfImage; | |
| 1315 | pe->SizeOfHeaders = sizeOfHeaders; | |
| 1316 | if (!config->noEntry) { | |
| 1317 | Defined *entry = cast<Defined>(config->entry); | |
| 1318 | pe->AddressOfEntryPoint = entry->getRVA(); | |
| 1184 | 1319 | // Pointer to thumb code must have the LSB set, so adjust it. |
| 1185 | if (Config->Machine == ARMNT) | |
| 1186 | PE->AddressOfEntryPoint |= 1; | |
| 1187 | } | |
| 1188 | PE->SizeOfStackReserve = Config->StackReserve; | |
| 1189 | PE->SizeOfStackCommit = Config->StackCommit; | |
| 1190 | PE->SizeOfHeapReserve = Config->HeapReserve; | |
| 1191 | PE->SizeOfHeapCommit = Config->HeapCommit; | |
| 1192 | if (Config->AppContainer) | |
| 1193 | PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER; | |
| 1194 | if (Config->DynamicBase) | |
| 1195 | PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; | |
| 1196 | if (Config->HighEntropyVA) | |
| 1197 | PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA; | |
| 1198 | if (!Config->AllowBind) | |
| 1199 | PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND; | |
| 1200 | if (Config->NxCompat) | |
| 1201 | PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; | |
| 1202 | if (!Config->AllowIsolation) | |
| 1203 | PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; | |
| 1204 | if (Config->GuardCF != GuardCFLevel::Off) | |
| 1205 | PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF; | |
| 1206 | if (Config->IntegrityCheck) | |
| 1207 | PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY; | |
| 1208 | if (SetNoSEHCharacteristic) | |
| 1209 | PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH; | |
| 1210 | if (Config->TerminalServerAware) | |
| 1211 | PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; | |
| 1212 | PE->NumberOfRvaAndSize = NumberOfDataDirectory; | |
| 1213 | if (TextSec->getVirtualSize()) { | |
| 1214 | PE->BaseOfCode = TextSec->getRVA(); | |
| 1215 | PE->SizeOfCode = TextSec->getRawSize(); | |
| 1216 | } | |
| 1217 | PE->SizeOfInitializedData = getSizeOfInitializedData(); | |
| 1320 | if (config->machine == ARMNT) | |
| 1321 | pe->AddressOfEntryPoint |= 1; | |
| 1322 | } | |
| 1323 | pe->SizeOfStackReserve = config->stackReserve; | |
| 1324 | pe->SizeOfStackCommit = config->stackCommit; | |
| 1325 | pe->SizeOfHeapReserve = config->heapReserve; | |
| 1326 | pe->SizeOfHeapCommit = config->heapCommit; | |
| 1327 | if (config->appContainer) | |
| 1328 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER; | |
| 1329 | if (config->dynamicBase) | |
| 1330 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; | |
| 1331 | if (config->highEntropyVA) | |
| 1332 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA; | |
| 1333 | if (!config->allowBind) | |
| 1334 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND; | |
| 1335 | if (config->nxCompat) | |
| 1336 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; | |
| 1337 | if (!config->allowIsolation) | |
| 1338 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; | |
| 1339 | if (config->guardCF != GuardCFLevel::Off) | |
| 1340 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF; | |
| 1341 | if (config->integrityCheck) | |
| 1342 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY; | |
| 1343 | if (setNoSEHCharacteristic) | |
| 1344 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH; | |
| 1345 | if (config->terminalServerAware) | |
| 1346 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; | |
| 1347 | pe->NumberOfRvaAndSize = numberOfDataDirectory; | |
| 1348 | if (textSec->getVirtualSize()) { | |
| 1349 | pe->BaseOfCode = textSec->getRVA(); | |
| 1350 | pe->SizeOfCode = textSec->getRawSize(); | |
| 1351 | } | |
| 1352 | pe->SizeOfInitializedData = getSizeOfInitializedData(); | |
| 1218 | 1353 | |
| 1219 | 1354 | // Write data directory |
| 1220 | auto *Dir = reinterpret_cast<data_directory *>(Buf); | |
| 1221 | Buf += sizeof(*Dir) * NumberOfDataDirectory; | |
| 1222 | if (!Config->Exports.empty()) { | |
| 1223 | Dir[EXPORT_TABLE].RelativeVirtualAddress = Edata.getRVA(); | |
| 1224 | Dir[EXPORT_TABLE].Size = Edata.getSize(); | |
| 1225 | } | |
| 1226 | if (ImportTableStart) { | |
| 1227 | Dir[IMPORT_TABLE].RelativeVirtualAddress = ImportTableStart->getRVA(); | |
| 1228 | Dir[IMPORT_TABLE].Size = ImportTableSize; | |
| 1229 | } | |
| 1230 | if (IATStart) { | |
| 1231 | Dir[IAT].RelativeVirtualAddress = IATStart->getRVA(); | |
| 1232 | Dir[IAT].Size = IATSize; | |
| 1233 | } | |
| 1234 | if (RsrcSec->getVirtualSize()) { | |
| 1235 | Dir[RESOURCE_TABLE].RelativeVirtualAddress = RsrcSec->getRVA(); | |
| 1236 | Dir[RESOURCE_TABLE].Size = RsrcSec->getVirtualSize(); | |
| 1237 | } | |
| 1238 | if (FirstPdata) { | |
| 1239 | Dir[EXCEPTION_TABLE].RelativeVirtualAddress = FirstPdata->getRVA(); | |
| 1240 | Dir[EXCEPTION_TABLE].Size = | |
| 1241 | LastPdata->getRVA() + LastPdata->getSize() - FirstPdata->getRVA(); | |
| 1242 | } | |
| 1243 | if (RelocSec->getVirtualSize()) { | |
| 1244 | Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = RelocSec->getRVA(); | |
| 1245 | Dir[BASE_RELOCATION_TABLE].Size = RelocSec->getVirtualSize(); | |
| 1246 | } | |
| 1247 | if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) { | |
| 1248 | if (Defined *B = dyn_cast<Defined>(Sym)) { | |
| 1249 | Dir[TLS_TABLE].RelativeVirtualAddress = B->getRVA(); | |
| 1250 | Dir[TLS_TABLE].Size = Config->is64() | |
| 1355 | auto *dir = reinterpret_cast<data_directory *>(buf); | |
| 1356 | buf += sizeof(*dir) * numberOfDataDirectory; | |
| 1357 | if (!config->exports.empty()) { | |
| 1358 | dir[EXPORT_TABLE].RelativeVirtualAddress = edata.getRVA(); | |
| 1359 | dir[EXPORT_TABLE].Size = edata.getSize(); | |
| 1360 | } | |
| 1361 | if (importTableStart) { | |
| 1362 | dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA(); | |
| 1363 | dir[IMPORT_TABLE].Size = importTableSize; | |
| 1364 | } | |
| 1365 | if (iatStart) { | |
| 1366 | dir[IAT].RelativeVirtualAddress = iatStart->getRVA(); | |
| 1367 | dir[IAT].Size = iatSize; | |
| 1368 | } | |
| 1369 | if (rsrcSec->getVirtualSize()) { | |
| 1370 | dir[RESOURCE_TABLE].RelativeVirtualAddress = rsrcSec->getRVA(); | |
| 1371 | dir[RESOURCE_TABLE].Size = rsrcSec->getVirtualSize(); | |
| 1372 | } | |
| 1373 | if (firstPdata) { | |
| 1374 | dir[EXCEPTION_TABLE].RelativeVirtualAddress = firstPdata->getRVA(); | |
| 1375 | dir[EXCEPTION_TABLE].Size = | |
| 1376 | lastPdata->getRVA() + lastPdata->getSize() - firstPdata->getRVA(); | |
| 1377 | } | |
| 1378 | if (relocSec->getVirtualSize()) { | |
| 1379 | dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = relocSec->getRVA(); | |
| 1380 | dir[BASE_RELOCATION_TABLE].Size = relocSec->getVirtualSize(); | |
| 1381 | } | |
| 1382 | if (Symbol *sym = symtab->findUnderscore("_tls_used")) { | |
| 1383 | if (Defined *b = dyn_cast<Defined>(sym)) { | |
| 1384 | dir[TLS_TABLE].RelativeVirtualAddress = b->getRVA(); | |
| 1385 | dir[TLS_TABLE].Size = config->is64() | |
| 1251 | 1386 | ? sizeof(object::coff_tls_directory64) |
| 1252 | 1387 | : sizeof(object::coff_tls_directory32); |
| 1253 | 1388 | } |
| 1254 | 1389 | } |
| 1255 | if (DebugDirectory) { | |
| 1256 | Dir[DEBUG_DIRECTORY].RelativeVirtualAddress = DebugDirectory->getRVA(); | |
| 1257 | Dir[DEBUG_DIRECTORY].Size = DebugDirectory->getSize(); | |
| 1390 | if (debugDirectory) { | |
| 1391 | dir[DEBUG_DIRECTORY].RelativeVirtualAddress = debugDirectory->getRVA(); | |
| 1392 | dir[DEBUG_DIRECTORY].Size = debugDirectory->getSize(); | |
| 1258 | 1393 | } |
| 1259 | if (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) { | |
| 1260 | if (auto *B = dyn_cast<DefinedRegular>(Sym)) { | |
| 1261 | SectionChunk *SC = B->getChunk(); | |
| 1262 | assert(B->getRVA() >= SC->getRVA()); | |
| 1263 | uint64_t OffsetInChunk = B->getRVA() - SC->getRVA(); | |
| 1264 | if (!SC->hasData() || OffsetInChunk + 4 > SC->getSize()) | |
| 1394 | if (Symbol *sym = symtab->findUnderscore("_load_config_used")) { | |
| 1395 | if (auto *b = dyn_cast<DefinedRegular>(sym)) { | |
| 1396 | SectionChunk *sc = b->getChunk(); | |
| 1397 | assert(b->getRVA() >= sc->getRVA()); | |
| 1398 | uint64_t offsetInChunk = b->getRVA() - sc->getRVA(); | |
| 1399 | if (!sc->hasData || offsetInChunk + 4 > sc->getSize()) | |
| 1265 | 1400 | fatal("_load_config_used is malformed"); |
| 1266 | 1401 | |
| 1267 | ArrayRef<uint8_t> SecContents = SC->getContents(); | |
| 1268 | uint32_t LoadConfigSize = | |
| 1269 | *reinterpret_cast<const ulittle32_t *>(&SecContents[OffsetInChunk]); | |
| 1270 | if (OffsetInChunk + LoadConfigSize > SC->getSize()) | |
| 1402 | ArrayRef<uint8_t> secContents = sc->getContents(); | |
| 1403 | uint32_t loadConfigSize = | |
| 1404 | *reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]); | |
| 1405 | if (offsetInChunk + loadConfigSize > sc->getSize()) | |
| 1271 | 1406 | fatal("_load_config_used is too large"); |
| 1272 | Dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = B->getRVA(); | |
| 1273 | Dir[LOAD_CONFIG_TABLE].Size = LoadConfigSize; | |
| 1407 | dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = b->getRVA(); | |
| 1408 | dir[LOAD_CONFIG_TABLE].Size = loadConfigSize; | |
| 1274 | 1409 | } |
| 1275 | 1410 | } |
| 1276 | if (!DelayIdata.empty()) { | |
| 1277 | Dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress = | |
| 1278 | DelayIdata.getDirRVA(); | |
| 1279 | Dir[DELAY_IMPORT_DESCRIPTOR].Size = DelayIdata.getDirSize(); | |
| 1411 | if (!delayIdata.empty()) { | |
| 1412 | dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress = | |
| 1413 | delayIdata.getDirRVA(); | |
| 1414 | dir[DELAY_IMPORT_DESCRIPTOR].Size = delayIdata.getDirSize(); | |
| 1280 | 1415 | } |
| 1281 | 1416 | |
| 1282 | 1417 | // Write section table |
| 1283 | for (OutputSection *Sec : OutputSections) { | |
| 1284 | Sec->writeHeaderTo(Buf); | |
| 1285 | Buf += sizeof(coff_section); | |
| 1418 | for (OutputSection *sec : outputSections) { | |
| 1419 | sec->writeHeaderTo(buf); | |
| 1420 | buf += sizeof(coff_section); | |
| 1286 | 1421 | } |
| 1287 | SectionTable = ArrayRef<uint8_t>( | |
| 1288 | Buf - OutputSections.size() * sizeof(coff_section), Buf); | |
| 1422 | sectionTable = ArrayRef<uint8_t>( | |
| 1423 | buf - outputSections.size() * sizeof(coff_section), buf); | |
| 1289 | 1424 | |
| 1290 | if (OutputSymtab.empty() && Strtab.empty()) | |
| 1425 | if (outputSymtab.empty() && strtab.empty()) | |
| 1291 | 1426 | return; |
| 1292 | 1427 | |
| 1293 | COFF->PointerToSymbolTable = PointerToSymbolTable; | |
| 1294 | uint32_t NumberOfSymbols = OutputSymtab.size(); | |
| 1295 | COFF->NumberOfSymbols = NumberOfSymbols; | |
| 1296 | auto *SymbolTable = reinterpret_cast<coff_symbol16 *>( | |
| 1297 | Buffer->getBufferStart() + COFF->PointerToSymbolTable); | |
| 1298 | for (size_t I = 0; I != NumberOfSymbols; ++I) | |
| 1299 | SymbolTable[I] = OutputSymtab[I]; | |
| 1428 | coff->PointerToSymbolTable = pointerToSymbolTable; | |
| 1429 | uint32_t numberOfSymbols = outputSymtab.size(); | |
| 1430 | coff->NumberOfSymbols = numberOfSymbols; | |
| 1431 | auto *symbolTable = reinterpret_cast<coff_symbol16 *>( | |
| 1432 | buffer->getBufferStart() + coff->PointerToSymbolTable); | |
| 1433 | for (size_t i = 0; i != numberOfSymbols; ++i) | |
| 1434 | symbolTable[i] = outputSymtab[i]; | |
| 1300 | 1435 | // Create the string table, it follows immediately after the symbol table. |
| 1301 | 1436 | // The first 4 bytes is length including itself. |
| 1302 | Buf = reinterpret_cast<uint8_t *>(&SymbolTable[NumberOfSymbols]); | |
| 1303 | write32le(Buf, Strtab.size() + 4); | |
| 1304 | if (!Strtab.empty()) | |
| 1305 | memcpy(Buf + 4, Strtab.data(), Strtab.size()); | |
| 1437 | buf = reinterpret_cast<uint8_t *>(&symbolTable[numberOfSymbols]); | |
| 1438 | write32le(buf, strtab.size() + 4); | |
| 1439 | if (!strtab.empty()) | |
| 1440 | memcpy(buf + 4, strtab.data(), strtab.size()); | |
| 1306 | 1441 | } |
| 1307 | 1442 | |
| 1308 | void Writer::openFile(StringRef Path) { | |
| 1309 | Buffer = CHECK( | |
| 1310 | FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable), | |
| 1311 | "failed to open " + Path); | |
| 1443 | void Writer::openFile(StringRef path) { | |
| 1444 | buffer = CHECK( | |
| 1445 | FileOutputBuffer::create(path, fileSize, FileOutputBuffer::F_executable), | |
| 1446 | "failed to open " + path); | |
| 1312 | 1447 | } |
| 1313 | 1448 | |
| 1314 | 1449 | void Writer::createSEHTable() { |
| 1315 | // Set the no SEH characteristic on x86 binaries unless we find exception | |
| 1316 | // handlers. | |
| 1317 | SetNoSEHCharacteristic = true; | |
| 1318 | ||
| 1319 | SymbolRVASet Handlers; | |
| 1320 | for (ObjFile *File : ObjFile::Instances) { | |
| 1321 | // FIXME: We should error here instead of earlier unless /safeseh:no was | |
| 1322 | // passed. | |
| 1323 | if (!File->hasSafeSEH()) | |
| 1324 | return; | |
| 1325 | ||
| 1326 | markSymbolsForRVATable(File, File->getSXDataChunks(), Handlers); | |
| 1450 | SymbolRVASet handlers; | |
| 1451 | for (ObjFile *file : ObjFile::instances) { | |
| 1452 | if (!file->hasSafeSEH()) | |
| 1453 | error("/safeseh: " + file->getName() + " is not compatible with SEH"); | |
| 1454 | markSymbolsForRVATable(file, file->getSXDataChunks(), handlers); | |
| 1327 | 1455 | } |
| 1328 | 1456 | |
| 1329 | // Remove the "no SEH" characteristic if all object files were built with | |
| 1330 | // safeseh, we found some exception handlers, and there is a load config in | |
| 1331 | // the object. | |
| 1332 | SetNoSEHCharacteristic = | |
| 1333 | Handlers.empty() || !Symtab->findUnderscore("_load_config_used"); | |
| 1457 | // Set the "no SEH" characteristic if there really were no handlers, or if | |
| 1458 | // there is no load config object to point to the table of handlers. | |
| 1459 | setNoSEHCharacteristic = | |
| 1460 | handlers.empty() || !symtab->findUnderscore("_load_config_used"); | |
| 1334 | 1461 | |
| 1335 | maybeAddRVATable(std::move(Handlers), "__safe_se_handler_table", | |
| 1462 | maybeAddRVATable(std::move(handlers), "__safe_se_handler_table", | |
| 1336 | 1463 | "__safe_se_handler_count"); |
| 1337 | 1464 | } |
| 1338 | 1465 | |
| 1339 | 1466 | // Add a symbol to an RVA set. Two symbols may have the same RVA, but an RVA set |
| 1340 | 1467 | // cannot contain duplicates. Therefore, the set is uniqued by Chunk and the |
| 1341 | 1468 | // symbol's offset into that Chunk. |
| 1342 | static void addSymbolToRVASet(SymbolRVASet &RVASet, Defined *S) { | |
| 1343 | Chunk *C = S->getChunk(); | |
| 1344 | if (auto *SC = dyn_cast<SectionChunk>(C)) | |
| 1345 | C = SC->Repl; // Look through ICF replacement. | |
| 1346 | uint32_t Off = S->getRVA() - (C ? C->getRVA() : 0); | |
| 1347 | RVASet.insert({C, Off}); | |
| 1469 | static void addSymbolToRVASet(SymbolRVASet &rvaSet, Defined *s) { | |
| 1470 | Chunk *c = s->getChunk(); | |
| 1471 | if (auto *sc = dyn_cast<SectionChunk>(c)) | |
| 1472 | c = sc->repl; // Look through ICF replacement. | |
| 1473 | uint32_t off = s->getRVA() - (c ? c->getRVA() : 0); | |
| 1474 | rvaSet.insert({c, off}); | |
| 1348 | 1475 | } |
| 1349 | 1476 | |
| 1350 | 1477 | // Given a symbol, add it to the GFIDs table if it is a live, defined, function |
| 1351 | 1478 | // symbol in an executable section. |
| 1352 | static void maybeAddAddressTakenFunction(SymbolRVASet &AddressTakenSyms, | |
| 1353 | Symbol *S) { | |
| 1354 | auto *D = dyn_cast_or_null<DefinedCOFF>(S); | |
| 1355 | ||
| 1356 | // Ignore undefined symbols and references to non-functions (e.g. globals and | |
| 1357 | // labels). | |
| 1358 | if (!D || | |
| 1359 | D->getCOFFSymbol().getComplexType() != COFF::IMAGE_SYM_DTYPE_FUNCTION) | |
| 1479 | static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms, | |
| 1480 | Symbol *s) { | |
| 1481 | if (!s) | |
| 1360 | 1482 | return; |
| 1361 | 1483 | |
| 1362 | // Mark the symbol as address taken if it's in an executable section. | |
| 1363 | Chunk *RefChunk = D->getChunk(); | |
| 1364 | OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr; | |
| 1365 | if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE) | |
| 1366 | addSymbolToRVASet(AddressTakenSyms, D); | |
| 1484 | switch (s->kind()) { | |
| 1485 | case Symbol::DefinedLocalImportKind: | |
| 1486 | case Symbol::DefinedImportDataKind: | |
| 1487 | // Defines an __imp_ pointer, so it is data, so it is ignored. | |
| 1488 | break; | |
| 1489 | case Symbol::DefinedCommonKind: | |
| 1490 | // Common is always data, so it is ignored. | |
| 1491 | break; | |
| 1492 | case Symbol::DefinedAbsoluteKind: | |
| 1493 | case Symbol::DefinedSyntheticKind: | |
| 1494 | // Absolute is never code, synthetic generally isn't and usually isn't | |
| 1495 | // determinable. | |
| 1496 | break; | |
| 1497 | case Symbol::LazyKind: | |
| 1498 | case Symbol::UndefinedKind: | |
| 1499 | // Undefined symbols resolve to zero, so they don't have an RVA. Lazy | |
| 1500 | // symbols shouldn't have relocations. | |
| 1501 | break; | |
| 1502 | ||
| 1503 | case Symbol::DefinedImportThunkKind: | |
| 1504 | // Thunks are always code, include them. | |
| 1505 | addSymbolToRVASet(addressTakenSyms, cast<Defined>(s)); | |
| 1506 | break; | |
| 1507 | ||
| 1508 | case Symbol::DefinedRegularKind: { | |
| 1509 | // This is a regular, defined, symbol from a COFF file. Mark the symbol as | |
| 1510 | // address taken if the symbol type is function and it's in an executable | |
| 1511 | // section. | |
| 1512 | auto *d = cast<DefinedRegular>(s); | |
| 1513 | if (d->getCOFFSymbol().getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) { | |
| 1514 | SectionChunk *sc = dyn_cast<SectionChunk>(d->getChunk()); | |
| 1515 | if (sc && sc->live && | |
| 1516 | sc->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) | |
| 1517 | addSymbolToRVASet(addressTakenSyms, d); | |
| 1518 | } | |
| 1519 | break; | |
| 1520 | } | |
| 1521 | } | |
| 1367 | 1522 | } |
| 1368 | 1523 | |
| 1369 | 1524 | // Visit all relocations from all section contributions of this object file and |
| 1370 | 1525 | // mark the relocation target as address-taken. |
| 1371 | static void markSymbolsWithRelocations(ObjFile *File, | |
| 1372 | SymbolRVASet &UsedSymbols) { | |
| 1373 | for (Chunk *C : File->getChunks()) { | |
| 1526 | static void markSymbolsWithRelocations(ObjFile *file, | |
| 1527 | SymbolRVASet &usedSymbols) { | |
| 1528 | for (Chunk *c : file->getChunks()) { | |
| 1374 | 1529 | // We only care about live section chunks. Common chunks and other chunks |
| 1375 | 1530 | // don't generally contain relocations. |
| 1376 | SectionChunk *SC = dyn_cast<SectionChunk>(C); | |
| 1377 | if (!SC || !SC->Live) | |
| 1531 | SectionChunk *sc = dyn_cast<SectionChunk>(c); | |
| 1532 | if (!sc || !sc->live) | |
| 1378 | 1533 | continue; |
| 1379 | 1534 | |
| 1380 | for (const coff_relocation &Reloc : SC->Relocs) { | |
| 1381 | if (Config->Machine == I386 && Reloc.Type == COFF::IMAGE_REL_I386_REL32) | |
| 1535 | for (const coff_relocation &reloc : sc->getRelocs()) { | |
| 1536 | if (config->machine == I386 && reloc.Type == COFF::IMAGE_REL_I386_REL32) | |
| 1382 | 1537 | // Ignore relative relocations on x86. On x86_64 they can't be ignored |
| 1383 | 1538 | // since they're also used to compute absolute addresses. |
| 1384 | 1539 | continue; |
| 1385 | 1540 | |
| 1386 | Symbol *Ref = SC->File->getSymbol(Reloc.SymbolTableIndex); | |
| 1387 | maybeAddAddressTakenFunction(UsedSymbols, Ref); | |
| 1541 | Symbol *ref = sc->file->getSymbol(reloc.SymbolTableIndex); | |
| 1542 | maybeAddAddressTakenFunction(usedSymbols, ref); | |
| 1388 | 1543 | } |
| 1389 | 1544 | } |
| 1390 | 1545 | } |
| ... | ... | @@ -1393,109 +1548,109 @@ static void markSymbolsWithRelocations(ObjFile *File, |
| 1393 | 1548 | // address-taken functions. It is sorted and uniqued, just like the safe SEH |
| 1394 | 1549 | // table. |
| 1395 | 1550 | void Writer::createGuardCFTables() { |
| 1396 | SymbolRVASet AddressTakenSyms; | |
| 1397 | SymbolRVASet LongJmpTargets; | |
| 1398 | for (ObjFile *File : ObjFile::Instances) { | |
| 1551 | SymbolRVASet addressTakenSyms; | |
| 1552 | SymbolRVASet longJmpTargets; | |
| 1553 | for (ObjFile *file : ObjFile::instances) { | |
| 1399 | 1554 | // If the object was compiled with /guard:cf, the address taken symbols |
| 1400 | 1555 | // are in .gfids$y sections, and the longjmp targets are in .gljmp$y |
| 1401 | 1556 | // sections. If the object was not compiled with /guard:cf, we assume there |
| 1402 | 1557 | // were no setjmp targets, and that all code symbols with relocations are |
| 1403 | 1558 | // possibly address-taken. |
| 1404 | if (File->hasGuardCF()) { | |
| 1405 | markSymbolsForRVATable(File, File->getGuardFidChunks(), AddressTakenSyms); | |
| 1406 | markSymbolsForRVATable(File, File->getGuardLJmpChunks(), LongJmpTargets); | |
| 1559 | if (file->hasGuardCF()) { | |
| 1560 | markSymbolsForRVATable(file, file->getGuardFidChunks(), addressTakenSyms); | |
| 1561 | markSymbolsForRVATable(file, file->getGuardLJmpChunks(), longJmpTargets); | |
| 1407 | 1562 | } else { |
| 1408 | markSymbolsWithRelocations(File, AddressTakenSyms); | |
| 1563 | markSymbolsWithRelocations(file, addressTakenSyms); | |
| 1409 | 1564 | } |
| 1410 | 1565 | } |
| 1411 | 1566 | |
| 1412 | 1567 | // Mark the image entry as address-taken. |
| 1413 | if (Config->Entry) | |
| 1414 | maybeAddAddressTakenFunction(AddressTakenSyms, Config->Entry); | |
| 1568 | if (config->entry) | |
| 1569 | maybeAddAddressTakenFunction(addressTakenSyms, config->entry); | |
| 1415 | 1570 | |
| 1416 | 1571 | // Mark exported symbols in executable sections as address-taken. |
| 1417 | for (Export &E : Config->Exports) | |
| 1418 | maybeAddAddressTakenFunction(AddressTakenSyms, E.Sym); | |
| 1572 | for (Export &e : config->exports) | |
| 1573 | maybeAddAddressTakenFunction(addressTakenSyms, e.sym); | |
| 1419 | 1574 | |
| 1420 | 1575 | // Ensure sections referenced in the gfid table are 16-byte aligned. |
| 1421 | for (const ChunkAndOffset &C : AddressTakenSyms) | |
| 1422 | if (C.InputChunk->Alignment < 16) | |
| 1423 | C.InputChunk->Alignment = 16; | |
| 1576 | for (const ChunkAndOffset &c : addressTakenSyms) | |
| 1577 | if (c.inputChunk->getAlignment() < 16) | |
| 1578 | c.inputChunk->setAlignment(16); | |
| 1424 | 1579 | |
| 1425 | maybeAddRVATable(std::move(AddressTakenSyms), "__guard_fids_table", | |
| 1580 | maybeAddRVATable(std::move(addressTakenSyms), "__guard_fids_table", | |
| 1426 | 1581 | "__guard_fids_count"); |
| 1427 | 1582 | |
| 1428 | 1583 | // Add the longjmp target table unless the user told us not to. |
| 1429 | if (Config->GuardCF == GuardCFLevel::Full) | |
| 1430 | maybeAddRVATable(std::move(LongJmpTargets), "__guard_longjmp_table", | |
| 1584 | if (config->guardCF == GuardCFLevel::Full) | |
| 1585 | maybeAddRVATable(std::move(longJmpTargets), "__guard_longjmp_table", | |
| 1431 | 1586 | "__guard_longjmp_count"); |
| 1432 | 1587 | |
| 1433 | 1588 | // Set __guard_flags, which will be used in the load config to indicate that |
| 1434 | 1589 | // /guard:cf was enabled. |
| 1435 | uint32_t GuardFlags = uint32_t(coff_guard_flags::CFInstrumented) | | |
| 1590 | uint32_t guardFlags = uint32_t(coff_guard_flags::CFInstrumented) | | |
| 1436 | 1591 | uint32_t(coff_guard_flags::HasFidTable); |
| 1437 | if (Config->GuardCF == GuardCFLevel::Full) | |
| 1438 | GuardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable); | |
| 1439 | Symbol *FlagSym = Symtab->findUnderscore("__guard_flags"); | |
| 1440 | cast<DefinedAbsolute>(FlagSym)->setVA(GuardFlags); | |
| 1592 | if (config->guardCF == GuardCFLevel::Full) | |
| 1593 | guardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable); | |
| 1594 | Symbol *flagSym = symtab->findUnderscore("__guard_flags"); | |
| 1595 | cast<DefinedAbsolute>(flagSym)->setVA(guardFlags); | |
| 1441 | 1596 | } |
| 1442 | 1597 | |
| 1443 | 1598 | // Take a list of input sections containing symbol table indices and add those |
| 1444 | 1599 | // symbols to an RVA table. The challenge is that symbol RVAs are not known and |
| 1445 | 1600 | // depend on the table size, so we can't directly build a set of integers. |
| 1446 | void Writer::markSymbolsForRVATable(ObjFile *File, | |
| 1447 | ArrayRef<SectionChunk *> SymIdxChunks, | |
| 1448 | SymbolRVASet &TableSymbols) { | |
| 1449 | for (SectionChunk *C : SymIdxChunks) { | |
| 1601 | void Writer::markSymbolsForRVATable(ObjFile *file, | |
| 1602 | ArrayRef<SectionChunk *> symIdxChunks, | |
| 1603 | SymbolRVASet &tableSymbols) { | |
| 1604 | for (SectionChunk *c : symIdxChunks) { | |
| 1450 | 1605 | // Skip sections discarded by linker GC. This comes up when a .gfids section |
| 1451 | 1606 | // is associated with something like a vtable and the vtable is discarded. |
| 1452 | 1607 | // In this case, the associated gfids section is discarded, and we don't |
| 1453 | 1608 | // mark the virtual member functions as address-taken by the vtable. |
| 1454 | if (!C->Live) | |
| 1609 | if (!c->live) | |
| 1455 | 1610 | continue; |
| 1456 | 1611 | |
| 1457 | 1612 | // Validate that the contents look like symbol table indices. |
| 1458 | ArrayRef<uint8_t> Data = C->getContents(); | |
| 1459 | if (Data.size() % 4 != 0) { | |
| 1460 | warn("ignoring " + C->getSectionName() + | |
| 1461 | " symbol table index section in object " + toString(File)); | |
| 1613 | ArrayRef<uint8_t> data = c->getContents(); | |
| 1614 | if (data.size() % 4 != 0) { | |
| 1615 | warn("ignoring " + c->getSectionName() + | |
| 1616 | " symbol table index section in object " + toString(file)); | |
| 1462 | 1617 | continue; |
| 1463 | 1618 | } |
| 1464 | 1619 | |
| 1465 | 1620 | // Read each symbol table index and check if that symbol was included in the |
| 1466 | 1621 | // final link. If so, add it to the table symbol set. |
| 1467 | ArrayRef<ulittle32_t> SymIndices( | |
| 1468 | reinterpret_cast<const ulittle32_t *>(Data.data()), Data.size() / 4); | |
| 1469 | ArrayRef<Symbol *> ObjSymbols = File->getSymbols(); | |
| 1470 | for (uint32_t SymIndex : SymIndices) { | |
| 1471 | if (SymIndex >= ObjSymbols.size()) { | |
| 1622 | ArrayRef<ulittle32_t> symIndices( | |
| 1623 | reinterpret_cast<const ulittle32_t *>(data.data()), data.size() / 4); | |
| 1624 | ArrayRef<Symbol *> objSymbols = file->getSymbols(); | |
| 1625 | for (uint32_t symIndex : symIndices) { | |
| 1626 | if (symIndex >= objSymbols.size()) { | |
| 1472 | 1627 | warn("ignoring invalid symbol table index in section " + |
| 1473 | C->getSectionName() + " in object " + toString(File)); | |
| 1628 | c->getSectionName() + " in object " + toString(file)); | |
| 1474 | 1629 | continue; |
| 1475 | 1630 | } |
| 1476 | if (Symbol *S = ObjSymbols[SymIndex]) { | |
| 1477 | if (S->isLive()) | |
| 1478 | addSymbolToRVASet(TableSymbols, cast<Defined>(S)); | |
| 1631 | if (Symbol *s = objSymbols[symIndex]) { | |
| 1632 | if (s->isLive()) | |
| 1633 | addSymbolToRVASet(tableSymbols, cast<Defined>(s)); | |
| 1479 | 1634 | } |
| 1480 | 1635 | } |
| 1481 | 1636 | } |
| 1482 | 1637 | } |
| 1483 | 1638 | |
| 1484 | 1639 | // Replace the absolute table symbol with a synthetic symbol pointing to |
| 1485 | // TableChunk so that we can emit base relocations for it and resolve section | |
| 1640 | // tableChunk so that we can emit base relocations for it and resolve section | |
| 1486 | 1641 | // relative relocations. |
| 1487 | void Writer::maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym, | |
| 1488 | StringRef CountSym) { | |
| 1489 | if (TableSymbols.empty()) | |
| 1642 | void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym, | |
| 1643 | StringRef countSym) { | |
| 1644 | if (tableSymbols.empty()) | |
| 1490 | 1645 | return; |
| 1491 | 1646 | |
| 1492 | RVATableChunk *TableChunk = make<RVATableChunk>(std::move(TableSymbols)); | |
| 1493 | RdataSec->addChunk(TableChunk); | |
| 1647 | RVATableChunk *tableChunk = make<RVATableChunk>(std::move(tableSymbols)); | |
| 1648 | rdataSec->addChunk(tableChunk); | |
| 1494 | 1649 | |
| 1495 | Symbol *T = Symtab->findUnderscore(TableSym); | |
| 1496 | Symbol *C = Symtab->findUnderscore(CountSym); | |
| 1497 | replaceSymbol<DefinedSynthetic>(T, T->getName(), TableChunk); | |
| 1498 | cast<DefinedAbsolute>(C)->setVA(TableChunk->getSize() / 4); | |
| 1650 | Symbol *t = symtab->findUnderscore(tableSym); | |
| 1651 | Symbol *c = symtab->findUnderscore(countSym); | |
| 1652 | replaceSymbol<DefinedSynthetic>(t, t->getName(), tableChunk); | |
| 1653 | cast<DefinedAbsolute>(c)->setVA(tableChunk->getSize() / 4); | |
| 1499 | 1654 | } |
| 1500 | 1655 | |
| 1501 | 1656 | // MinGW specific. Gather all relocations that are imported from a DLL even |
| ... | ... | @@ -1503,26 +1658,26 @@ void Writer::maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym, |
| 1503 | 1658 | // uses for fixing them up, and provide the synthetic symbols that the |
| 1504 | 1659 | // runtime uses for finding the table. |
| 1505 | 1660 | void Writer::createRuntimePseudoRelocs() { |
| 1506 | std::vector<RuntimePseudoReloc> Rels; | |
| 1661 | std::vector<RuntimePseudoReloc> rels; | |
| 1507 | 1662 | |
| 1508 | for (Chunk *C : Symtab->getChunks()) { | |
| 1509 | auto *SC = dyn_cast<SectionChunk>(C); | |
| 1510 | if (!SC || !SC->Live) | |
| 1663 | for (Chunk *c : symtab->getChunks()) { | |
| 1664 | auto *sc = dyn_cast<SectionChunk>(c); | |
| 1665 | if (!sc || !sc->live) | |
| 1511 | 1666 | continue; |
| 1512 | SC->getRuntimePseudoRelocs(Rels); | |
| 1667 | sc->getRuntimePseudoRelocs(rels); | |
| 1513 | 1668 | } |
| 1514 | 1669 | |
| 1515 | if (!Rels.empty()) | |
| 1516 | log("Writing " + Twine(Rels.size()) + " runtime pseudo relocations"); | |
| 1517 | PseudoRelocTableChunk *Table = make<PseudoRelocTableChunk>(Rels); | |
| 1518 | RdataSec->addChunk(Table); | |
| 1519 | EmptyChunk *EndOfList = make<EmptyChunk>(); | |
| 1520 | RdataSec->addChunk(EndOfList); | |
| 1521 | ||
| 1522 | Symbol *HeadSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__"); | |
| 1523 | Symbol *EndSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__"); | |
| 1524 | replaceSymbol<DefinedSynthetic>(HeadSym, HeadSym->getName(), Table); | |
| 1525 | replaceSymbol<DefinedSynthetic>(EndSym, EndSym->getName(), EndOfList); | |
| 1670 | if (!rels.empty()) | |
| 1671 | log("Writing " + Twine(rels.size()) + " runtime pseudo relocations"); | |
| 1672 | PseudoRelocTableChunk *table = make<PseudoRelocTableChunk>(rels); | |
| 1673 | rdataSec->addChunk(table); | |
| 1674 | EmptyChunk *endOfList = make<EmptyChunk>(); | |
| 1675 | rdataSec->addChunk(endOfList); | |
| 1676 | ||
| 1677 | Symbol *headSym = symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__"); | |
| 1678 | Symbol *endSym = symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__"); | |
| 1679 | replaceSymbol<DefinedSynthetic>(headSym, headSym->getName(), table); | |
| 1680 | replaceSymbol<DefinedSynthetic>(endSym, endSym->getName(), endOfList); | |
| 1526 | 1681 | } |
| 1527 | 1682 | |
| 1528 | 1683 | // MinGW specific. |
| ... | ... | @@ -1531,32 +1686,32 @@ void Writer::createRuntimePseudoRelocs() { |
| 1531 | 1686 | // There's a symbol pointing to the start sentinel pointer, __CTOR_LIST__ |
| 1532 | 1687 | // and __DTOR_LIST__ respectively. |
| 1533 | 1688 | void Writer::insertCtorDtorSymbols() { |
| 1534 | AbsolutePointerChunk *CtorListHead = make<AbsolutePointerChunk>(-1); | |
| 1535 | AbsolutePointerChunk *CtorListEnd = make<AbsolutePointerChunk>(0); | |
| 1536 | AbsolutePointerChunk *DtorListHead = make<AbsolutePointerChunk>(-1); | |
| 1537 | AbsolutePointerChunk *DtorListEnd = make<AbsolutePointerChunk>(0); | |
| 1538 | CtorsSec->insertChunkAtStart(CtorListHead); | |
| 1539 | CtorsSec->addChunk(CtorListEnd); | |
| 1540 | DtorsSec->insertChunkAtStart(DtorListHead); | |
| 1541 | DtorsSec->addChunk(DtorListEnd); | |
| 1542 | ||
| 1543 | Symbol *CtorListSym = Symtab->findUnderscore("__CTOR_LIST__"); | |
| 1544 | Symbol *DtorListSym = Symtab->findUnderscore("__DTOR_LIST__"); | |
| 1545 | replaceSymbol<DefinedSynthetic>(CtorListSym, CtorListSym->getName(), | |
| 1546 | CtorListHead); | |
| 1547 | replaceSymbol<DefinedSynthetic>(DtorListSym, DtorListSym->getName(), | |
| 1548 | DtorListHead); | |
| 1689 | AbsolutePointerChunk *ctorListHead = make<AbsolutePointerChunk>(-1); | |
| 1690 | AbsolutePointerChunk *ctorListEnd = make<AbsolutePointerChunk>(0); | |
| 1691 | AbsolutePointerChunk *dtorListHead = make<AbsolutePointerChunk>(-1); | |
| 1692 | AbsolutePointerChunk *dtorListEnd = make<AbsolutePointerChunk>(0); | |
| 1693 | ctorsSec->insertChunkAtStart(ctorListHead); | |
| 1694 | ctorsSec->addChunk(ctorListEnd); | |
| 1695 | dtorsSec->insertChunkAtStart(dtorListHead); | |
| 1696 | dtorsSec->addChunk(dtorListEnd); | |
| 1697 | ||
| 1698 | Symbol *ctorListSym = symtab->findUnderscore("__CTOR_LIST__"); | |
| 1699 | Symbol *dtorListSym = symtab->findUnderscore("__DTOR_LIST__"); | |
| 1700 | replaceSymbol<DefinedSynthetic>(ctorListSym, ctorListSym->getName(), | |
| 1701 | ctorListHead); | |
| 1702 | replaceSymbol<DefinedSynthetic>(dtorListSym, dtorListSym->getName(), | |
| 1703 | dtorListHead); | |
| 1549 | 1704 | } |
| 1550 | 1705 | |
| 1551 | 1706 | // Handles /section options to allow users to overwrite |
| 1552 | 1707 | // section attributes. |
| 1553 | 1708 | void Writer::setSectionPermissions() { |
| 1554 | for (auto &P : Config->Section) { | |
| 1555 | StringRef Name = P.first; | |
| 1556 | uint32_t Perm = P.second; | |
| 1557 | for (OutputSection *Sec : OutputSections) | |
| 1558 | if (Sec->Name == Name) | |
| 1559 | Sec->setPermissions(Perm); | |
| 1709 | for (auto &p : config->section) { | |
| 1710 | StringRef name = p.first; | |
| 1711 | uint32_t perm = p.second; | |
| 1712 | for (OutputSection *sec : outputSections) | |
| 1713 | if (sec->name == name) | |
| 1714 | sec->setPermissions(perm); | |
| 1560 | 1715 | } |
| 1561 | 1716 | } |
| 1562 | 1717 | |
| ... | ... | @@ -1564,18 +1719,19 @@ void Writer::setSectionPermissions() { |
| 1564 | 1719 | void Writer::writeSections() { |
| 1565 | 1720 | // Record the number of sections to apply section index relocations |
| 1566 | 1721 | // against absolute symbols. See applySecIdx in Chunks.cpp.. |
| 1567 | DefinedAbsolute::NumOutputSections = OutputSections.size(); | |
| 1722 | DefinedAbsolute::numOutputSections = outputSections.size(); | |
| 1568 | 1723 | |
| 1569 | uint8_t *Buf = Buffer->getBufferStart(); | |
| 1570 | for (OutputSection *Sec : OutputSections) { | |
| 1571 | uint8_t *SecBuf = Buf + Sec->getFileOff(); | |
| 1724 | uint8_t *buf = buffer->getBufferStart(); | |
| 1725 | for (OutputSection *sec : outputSections) { | |
| 1726 | uint8_t *secBuf = buf + sec->getFileOff(); | |
| 1572 | 1727 | // Fill gaps between functions in .text with INT3 instructions |
| 1573 | 1728 | // instead of leaving as NUL bytes (which can be interpreted as |
| 1574 | 1729 | // ADD instructions). |
| 1575 | if (Sec->Header.Characteristics & IMAGE_SCN_CNT_CODE) | |
| 1576 | memset(SecBuf, 0xCC, Sec->getRawSize()); | |
| 1577 | for_each(parallel::par, Sec->Chunks.begin(), Sec->Chunks.end(), | |
| 1578 | [&](Chunk *C) { C->writeTo(SecBuf); }); | |
| 1730 | if (sec->header.Characteristics & IMAGE_SCN_CNT_CODE) | |
| 1731 | memset(secBuf, 0xCC, sec->getRawSize()); | |
| 1732 | parallelForEach(sec->chunks, [&](Chunk *c) { | |
| 1733 | c->writeTo(secBuf + c->getRVA() - sec->getRVA()); | |
| 1734 | }); | |
| 1579 | 1735 | } |
| 1580 | 1736 | } |
| 1581 | 1737 | |
| ... | ... | @@ -1586,8 +1742,8 @@ void Writer::writeBuildId() { |
| 1586 | 1742 | // 2) In all cases, the PE COFF file header also contains a timestamp. |
| 1587 | 1743 | // For reproducibility, instead of a timestamp we want to use a hash of the |
| 1588 | 1744 | // PE contents. |
| 1589 | if (Config->Debug) { | |
| 1590 | assert(BuildId && "BuildId is not set!"); | |
| 1745 | if (config->debug) { | |
| 1746 | assert(buildId && "BuildId is not set!"); | |
| 1591 | 1747 | // BuildId->BuildId was filled in when the PDB was written. |
| 1592 | 1748 | } |
| 1593 | 1749 | |
| ... | ... | @@ -1595,62 +1751,65 @@ void Writer::writeBuildId() { |
| 1595 | 1751 | // "timestamp" in the COFF file header, and the ones in the coff debug |
| 1596 | 1752 | // directory. Now we can hash the file and write that hash to the various |
| 1597 | 1753 | // timestamp fields in the file. |
| 1598 | StringRef OutputFileData( | |
| 1599 | reinterpret_cast<const char *>(Buffer->getBufferStart()), | |
| 1600 | Buffer->getBufferSize()); | |
| 1754 | StringRef outputFileData( | |
| 1755 | reinterpret_cast<const char *>(buffer->getBufferStart()), | |
| 1756 | buffer->getBufferSize()); | |
| 1601 | 1757 | |
| 1602 | uint32_t Timestamp = Config->Timestamp; | |
| 1603 | uint64_t Hash = 0; | |
| 1604 | bool GenerateSyntheticBuildId = | |
| 1605 | Config->MinGW && Config->Debug && Config->PDBPath.empty(); | |
| 1758 | uint32_t timestamp = config->timestamp; | |
| 1759 | uint64_t hash = 0; | |
| 1760 | bool generateSyntheticBuildId = | |
| 1761 | config->mingw && config->debug && config->pdbPath.empty(); | |
| 1606 | 1762 | |
| 1607 | if (Config->Repro || GenerateSyntheticBuildId) | |
| 1608 | Hash = xxHash64(OutputFileData); | |
| 1763 | if (config->repro || generateSyntheticBuildId) | |
| 1764 | hash = xxHash64(outputFileData); | |
| 1609 | 1765 | |
| 1610 | if (Config->Repro) | |
| 1611 | Timestamp = static_cast<uint32_t>(Hash); | |
| 1766 | if (config->repro) | |
| 1767 | timestamp = static_cast<uint32_t>(hash); | |
| 1612 | 1768 | |
| 1613 | if (GenerateSyntheticBuildId) { | |
| 1769 | if (generateSyntheticBuildId) { | |
| 1614 | 1770 | // For MinGW builds without a PDB file, we still generate a build id |
| 1615 | 1771 | // to allow associating a crash dump to the executable. |
| 1616 | BuildId->BuildId->PDB70.CVSignature = OMF::Signature::PDB70; | |
| 1617 | BuildId->BuildId->PDB70.Age = 1; | |
| 1618 | memcpy(BuildId->BuildId->PDB70.Signature, &Hash, 8); | |
| 1772 | buildId->buildId->PDB70.CVSignature = OMF::Signature::PDB70; | |
| 1773 | buildId->buildId->PDB70.Age = 1; | |
| 1774 | memcpy(buildId->buildId->PDB70.Signature, &hash, 8); | |
| 1619 | 1775 | // xxhash only gives us 8 bytes, so put some fixed data in the other half. |
| 1620 | memcpy(&BuildId->BuildId->PDB70.Signature[8], "LLD PDB.", 8); | |
| 1776 | memcpy(&buildId->buildId->PDB70.Signature[8], "LLD PDB.", 8); | |
| 1621 | 1777 | } |
| 1622 | 1778 | |
| 1623 | if (DebugDirectory) | |
| 1624 | DebugDirectory->setTimeDateStamp(Timestamp); | |
| 1779 | if (debugDirectory) | |
| 1780 | debugDirectory->setTimeDateStamp(timestamp); | |
| 1625 | 1781 | |
| 1626 | uint8_t *Buf = Buffer->getBufferStart(); | |
| 1627 | Buf += DOSStubSize + sizeof(PEMagic); | |
| 1628 | object::coff_file_header *CoffHeader = | |
| 1629 | reinterpret_cast<coff_file_header *>(Buf); | |
| 1630 | CoffHeader->TimeDateStamp = Timestamp; | |
| 1782 | uint8_t *buf = buffer->getBufferStart(); | |
| 1783 | buf += dosStubSize + sizeof(PEMagic); | |
| 1784 | object::coff_file_header *coffHeader = | |
| 1785 | reinterpret_cast<coff_file_header *>(buf); | |
| 1786 | coffHeader->TimeDateStamp = timestamp; | |
| 1631 | 1787 | } |
| 1632 | 1788 | |
| 1633 | 1789 | // Sort .pdata section contents according to PE/COFF spec 5.5. |
| 1634 | 1790 | void Writer::sortExceptionTable() { |
| 1635 | if (!FirstPdata) | |
| 1791 | if (!firstPdata) | |
| 1636 | 1792 | return; |
| 1637 | 1793 | // We assume .pdata contains function table entries only. |
| 1638 | auto BufAddr = [&](Chunk *C) { | |
| 1639 | return Buffer->getBufferStart() + C->getOutputSection()->getFileOff() + | |
| 1640 | C->getRVA() - C->getOutputSection()->getRVA(); | |
| 1794 | auto bufAddr = [&](Chunk *c) { | |
| 1795 | OutputSection *os = c->getOutputSection(); | |
| 1796 | return buffer->getBufferStart() + os->getFileOff() + c->getRVA() - | |
| 1797 | os->getRVA(); | |
| 1641 | 1798 | }; |
| 1642 | uint8_t *Begin = BufAddr(FirstPdata); | |
| 1643 | uint8_t *End = BufAddr(LastPdata) + LastPdata->getSize(); | |
| 1644 | if (Config->Machine == AMD64) { | |
| 1645 | struct Entry { ulittle32_t Begin, End, Unwind; }; | |
| 1646 | sort(parallel::par, (Entry *)Begin, (Entry *)End, | |
| 1647 | [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); | |
| 1799 | uint8_t *begin = bufAddr(firstPdata); | |
| 1800 | uint8_t *end = bufAddr(lastPdata) + lastPdata->getSize(); | |
| 1801 | if (config->machine == AMD64) { | |
| 1802 | struct Entry { ulittle32_t begin, end, unwind; }; | |
| 1803 | parallelSort( | |
| 1804 | MutableArrayRef<Entry>((Entry *)begin, (Entry *)end), | |
| 1805 | [](const Entry &a, const Entry &b) { return a.begin < b.begin; }); | |
| 1648 | 1806 | return; |
| 1649 | 1807 | } |
| 1650 | if (Config->Machine == ARMNT || Config->Machine == ARM64) { | |
| 1651 | struct Entry { ulittle32_t Begin, Unwind; }; | |
| 1652 | sort(parallel::par, (Entry *)Begin, (Entry *)End, | |
| 1653 | [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); | |
| 1808 | if (config->machine == ARMNT || config->machine == ARM64) { | |
| 1809 | struct Entry { ulittle32_t begin, unwind; }; | |
| 1810 | parallelSort( | |
| 1811 | MutableArrayRef<Entry>((Entry *)begin, (Entry *)end), | |
| 1812 | [](const Entry &a, const Entry &b) { return a.begin < b.begin; }); | |
| 1654 | 1813 | return; |
| 1655 | 1814 | } |
| 1656 | 1815 | errs() << "warning: don't know how to handle .pdata.\n"; |
| ... | ... | @@ -1670,76 +1829,92 @@ void Writer::sortExceptionTable() { |
| 1670 | 1829 | // pointers in the order that they are listed in the object file (top to |
| 1671 | 1830 | // bottom), otherwise global objects might not be initialized in the |
| 1672 | 1831 | // correct order. |
| 1673 | void Writer::sortCRTSectionChunks(std::vector<Chunk *> &Chunks) { | |
| 1674 | auto SectionChunkOrder = [](const Chunk *A, const Chunk *B) { | |
| 1675 | auto SA = dyn_cast<SectionChunk>(A); | |
| 1676 | auto SB = dyn_cast<SectionChunk>(B); | |
| 1677 | assert(SA && SB && "Non-section chunks in CRT section!"); | |
| 1832 | void Writer::sortCRTSectionChunks(std::vector<Chunk *> &chunks) { | |
| 1833 | auto sectionChunkOrder = [](const Chunk *a, const Chunk *b) { | |
| 1834 | auto sa = dyn_cast<SectionChunk>(a); | |
| 1835 | auto sb = dyn_cast<SectionChunk>(b); | |
| 1836 | assert(sa && sb && "Non-section chunks in CRT section!"); | |
| 1678 | 1837 | |
| 1679 | StringRef SAObj = SA->File->MB.getBufferIdentifier(); | |
| 1680 | StringRef SBObj = SB->File->MB.getBufferIdentifier(); | |
| 1838 | StringRef sAObj = sa->file->mb.getBufferIdentifier(); | |
| 1839 | StringRef sBObj = sb->file->mb.getBufferIdentifier(); | |
| 1681 | 1840 | |
| 1682 | return SAObj == SBObj && SA->getSectionNumber() < SB->getSectionNumber(); | |
| 1841 | return sAObj == sBObj && sa->getSectionNumber() < sb->getSectionNumber(); | |
| 1683 | 1842 | }; |
| 1684 | std::stable_sort(Chunks.begin(), Chunks.end(), SectionChunkOrder); | |
| 1843 | llvm::stable_sort(chunks, sectionChunkOrder); | |
| 1685 | 1844 | |
| 1686 | if (Config->Verbose) { | |
| 1687 | for (auto &C : Chunks) { | |
| 1688 | auto SC = dyn_cast<SectionChunk>(C); | |
| 1689 | log(" " + SC->File->MB.getBufferIdentifier().str() + | |
| 1690 | ", SectionID: " + Twine(SC->getSectionNumber())); | |
| 1845 | if (config->verbose) { | |
| 1846 | for (auto &c : chunks) { | |
| 1847 | auto sc = dyn_cast<SectionChunk>(c); | |
| 1848 | log(" " + sc->file->mb.getBufferIdentifier().str() + | |
| 1849 | ", SectionID: " + Twine(sc->getSectionNumber())); | |
| 1691 | 1850 | } |
| 1692 | 1851 | } |
| 1693 | 1852 | } |
| 1694 | 1853 | |
| 1695 | OutputSection *Writer::findSection(StringRef Name) { | |
| 1696 | for (OutputSection *Sec : OutputSections) | |
| 1697 | if (Sec->Name == Name) | |
| 1698 | return Sec; | |
| 1854 | OutputSection *Writer::findSection(StringRef name) { | |
| 1855 | for (OutputSection *sec : outputSections) | |
| 1856 | if (sec->name == name) | |
| 1857 | return sec; | |
| 1699 | 1858 | return nullptr; |
| 1700 | 1859 | } |
| 1701 | 1860 | |
| 1702 | 1861 | uint32_t Writer::getSizeOfInitializedData() { |
| 1703 | uint32_t Res = 0; | |
| 1704 | for (OutputSection *S : OutputSections) | |
| 1705 | if (S->Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) | |
| 1706 | Res += S->getRawSize(); | |
| 1707 | return Res; | |
| 1862 | uint32_t res = 0; | |
| 1863 | for (OutputSection *s : outputSections) | |
| 1864 | if (s->header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) | |
| 1865 | res += s->getRawSize(); | |
| 1866 | return res; | |
| 1708 | 1867 | } |
| 1709 | 1868 | |
| 1710 | 1869 | // Add base relocations to .reloc section. |
| 1711 | 1870 | void Writer::addBaserels() { |
| 1712 | if (!Config->Relocatable) | |
| 1871 | if (!config->relocatable) | |
| 1713 | 1872 | return; |
| 1714 | RelocSec->Chunks.clear(); | |
| 1715 | std::vector<Baserel> V; | |
| 1716 | for (OutputSection *Sec : OutputSections) { | |
| 1717 | if (Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) | |
| 1873 | relocSec->chunks.clear(); | |
| 1874 | std::vector<Baserel> v; | |
| 1875 | for (OutputSection *sec : outputSections) { | |
| 1876 | if (sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) | |
| 1718 | 1877 | continue; |
| 1719 | 1878 | // Collect all locations for base relocations. |
| 1720 | for (Chunk *C : Sec->Chunks) | |
| 1721 | C->getBaserels(&V); | |
| 1879 | for (Chunk *c : sec->chunks) | |
| 1880 | c->getBaserels(&v); | |
| 1722 | 1881 | // Add the addresses to .reloc section. |
| 1723 | if (!V.empty()) | |
| 1724 | addBaserelBlocks(V); | |
| 1725 | V.clear(); | |
| 1882 | if (!v.empty()) | |
| 1883 | addBaserelBlocks(v); | |
| 1884 | v.clear(); | |
| 1726 | 1885 | } |
| 1727 | 1886 | } |
| 1728 | 1887 | |
| 1729 | 1888 | // Add addresses to .reloc section. Note that addresses are grouped by page. |
| 1730 | void Writer::addBaserelBlocks(std::vector<Baserel> &V) { | |
| 1731 | const uint32_t Mask = ~uint32_t(PageSize - 1); | |
| 1732 | uint32_t Page = V[0].RVA & Mask; | |
| 1733 | size_t I = 0, J = 1; | |
| 1734 | for (size_t E = V.size(); J < E; ++J) { | |
| 1735 | uint32_t P = V[J].RVA & Mask; | |
| 1736 | if (P == Page) | |
| 1889 | void Writer::addBaserelBlocks(std::vector<Baserel> &v) { | |
| 1890 | const uint32_t mask = ~uint32_t(pageSize - 1); | |
| 1891 | uint32_t page = v[0].rva & mask; | |
| 1892 | size_t i = 0, j = 1; | |
| 1893 | for (size_t e = v.size(); j < e; ++j) { | |
| 1894 | uint32_t p = v[j].rva & mask; | |
| 1895 | if (p == page) | |
| 1737 | 1896 | continue; |
| 1738 | RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J)); | |
| 1739 | I = J; | |
| 1740 | Page = P; | |
| 1897 | relocSec->addChunk(make<BaserelChunk>(page, &v[i], &v[0] + j)); | |
| 1898 | i = j; | |
| 1899 | page = p; | |
| 1741 | 1900 | } |
| 1742 | if (I == J) | |
| 1901 | if (i == j) | |
| 1743 | 1902 | return; |
| 1744 | RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J)); | |
| 1903 | relocSec->addChunk(make<BaserelChunk>(page, &v[i], &v[0] + j)); | |
| 1904 | } | |
| 1905 | ||
| 1906 | PartialSection *Writer::createPartialSection(StringRef name, | |
| 1907 | uint32_t outChars) { | |
| 1908 | PartialSection *&pSec = partialSections[{name, outChars}]; | |
| 1909 | if (pSec) | |
| 1910 | return pSec; | |
| 1911 | pSec = make<PartialSection>(name, outChars); | |
| 1912 | return pSec; | |
| 1913 | } | |
| 1914 | ||
| 1915 | PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) { | |
| 1916 | auto it = partialSections.find({name, outChars}); | |
| 1917 | if (it != partialSections.end()) | |
| 1918 | return it->second; | |
| 1919 | return nullptr; | |
| 1745 | 1920 | } |
deps/lld/COFF/Writer.h+36-26| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Writer.h -------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -19,10 +18,19 @@ |
| 19 | 18 | |
| 20 | 19 | namespace lld { |
| 21 | 20 | namespace coff { |
| 22 | static const int PageSize = 4096; | |
| 21 | static const int pageSize = 4096; | |
| 23 | 22 | |
| 24 | 23 | void writeResult(); |
| 25 | 24 | |
| 25 | class PartialSection { | |
| 26 | public: | |
| 27 | PartialSection(StringRef n, uint32_t chars) | |
| 28 | : name(n), characteristics(chars) {} | |
| 29 | StringRef name; | |
| 30 | unsigned characteristics; | |
| 31 | std::vector<Chunk *> chunks; | |
| 32 | }; | |
| 33 | ||
| 26 | 34 | // OutputSection represents a section in an output file. It's a |
| 27 | 35 | // container of chunks. OutputSection and Chunk are 1:N relationship. |
| 28 | 36 | // Chunks cannot belong to more than one OutputSections. The writer |
| ... | ... | @@ -30,46 +38,48 @@ void writeResult(); |
| 30 | 38 | // non-overlapping file offsets and RVAs. |
| 31 | 39 | class OutputSection { |
| 32 | 40 | public: |
| 33 | OutputSection(llvm::StringRef N, uint32_t Chars) : Name(N) { | |
| 34 | Header.Characteristics = Chars; | |
| 41 | OutputSection(llvm::StringRef n, uint32_t chars) : name(n) { | |
| 42 | header.Characteristics = chars; | |
| 35 | 43 | } |
| 36 | void addChunk(Chunk *C); | |
| 37 | void insertChunkAtStart(Chunk *C); | |
| 38 | void merge(OutputSection *Other); | |
| 39 | void addPermissions(uint32_t C); | |
| 40 | void setPermissions(uint32_t C); | |
| 41 | uint64_t getRVA() { return Header.VirtualAddress; } | |
| 42 | uint64_t getFileOff() { return Header.PointerToRawData; } | |
| 43 | void writeHeaderTo(uint8_t *Buf); | |
| 44 | void addChunk(Chunk *c); | |
| 45 | void insertChunkAtStart(Chunk *c); | |
| 46 | void merge(OutputSection *other); | |
| 47 | void setPermissions(uint32_t c); | |
| 48 | uint64_t getRVA() { return header.VirtualAddress; } | |
| 49 | uint64_t getFileOff() { return header.PointerToRawData; } | |
| 50 | void writeHeaderTo(uint8_t *buf); | |
| 51 | void addContributingPartialSection(PartialSection *sec); | |
| 44 | 52 | |
| 45 | 53 | // Returns the size of this section in an executable memory image. |
| 46 | 54 | // This may be smaller than the raw size (the raw size is multiple |
| 47 | 55 | // of disk sector size, so there may be padding at end), or may be |
| 48 | 56 | // larger (if that's the case, the loader reserves spaces after end |
| 49 | 57 | // of raw data). |
| 50 | uint64_t getVirtualSize() { return Header.VirtualSize; } | |
| 58 | uint64_t getVirtualSize() { return header.VirtualSize; } | |
| 51 | 59 | |
| 52 | 60 | // Returns the size of the section in the output file. |
| 53 | uint64_t getRawSize() { return Header.SizeOfRawData; } | |
| 61 | uint64_t getRawSize() { return header.SizeOfRawData; } | |
| 54 | 62 | |
| 55 | 63 | // Set offset into the string table storing this section name. |
| 56 | 64 | // Used only when the name is longer than 8 bytes. |
| 57 | void setStringTableOff(uint32_t V) { StringTableOff = V; } | |
| 65 | void setStringTableOff(uint32_t v) { stringTableOff = v; } | |
| 58 | 66 | |
| 59 | 67 | // N.B. The section index is one based. |
| 60 | uint32_t SectionIndex = 0; | |
| 68 | uint32_t sectionIndex = 0; | |
| 69 | ||
| 70 | llvm::StringRef name; | |
| 71 | llvm::object::coff_section header = {}; | |
| 61 | 72 | |
| 62 | llvm::StringRef Name; | |
| 63 | llvm::object::coff_section Header = {}; | |
| 73 | std::vector<Chunk *> chunks; | |
| 74 | std::vector<Chunk *> origChunks; | |
| 64 | 75 | |
| 65 | std::vector<Chunk *> Chunks; | |
| 66 | std::vector<Chunk *> OrigChunks; | |
| 76 | std::vector<PartialSection *> contribSections; | |
| 67 | 77 | |
| 68 | 78 | private: |
| 69 | uint32_t StringTableOff = 0; | |
| 79 | uint32_t stringTableOff = 0; | |
| 70 | 80 | }; |
| 71 | 81 | |
| 72 | } | |
| 73 | } | |
| 82 | } // namespace coff | |
| 83 | } // namespace lld | |
| 74 | 84 | |
| 75 | 85 | #endif |
deps/lld/Common/Args.cpp+48-39| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Args.cpp -----------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -18,56 +17,66 @@ |
| 18 | 17 | using namespace llvm; |
| 19 | 18 | using namespace lld; |
| 20 | 19 | |
| 21 | int lld::args::getInteger(opt::InputArgList &Args, unsigned Key, int Default) { | |
| 22 | auto *A = Args.getLastArg(Key); | |
| 23 | if (!A) | |
| 20 | // TODO(sbc): Remove this once CGOptLevel can be set completely based on bitcode | |
| 21 | // function metadata. | |
| 22 | CodeGenOpt::Level lld::args::getCGOptLevel(int optLevelLTO) { | |
| 23 | if (optLevelLTO == 3) | |
| 24 | return CodeGenOpt::Aggressive; | |
| 25 | assert(optLevelLTO < 3); | |
| 26 | return CodeGenOpt::Default; | |
| 27 | } | |
| 28 | ||
| 29 | int64_t lld::args::getInteger(opt::InputArgList &args, unsigned key, | |
| 30 | int64_t Default) { | |
| 31 | auto *a = args.getLastArg(key); | |
| 32 | if (!a) | |
| 24 | 33 | return Default; |
| 25 | 34 | |
| 26 | int V; | |
| 27 | if (to_integer(A->getValue(), V, 10)) | |
| 28 | return V; | |
| 35 | int64_t v; | |
| 36 | if (to_integer(a->getValue(), v, 10)) | |
| 37 | return v; | |
| 29 | 38 | |
| 30 | StringRef Spelling = Args.getArgString(A->getIndex()); | |
| 31 | error(Spelling + ": number expected, but got '" + A->getValue() + "'"); | |
| 39 | StringRef spelling = args.getArgString(a->getIndex()); | |
| 40 | error(spelling + ": number expected, but got '" + a->getValue() + "'"); | |
| 32 | 41 | return 0; |
| 33 | 42 | } |
| 34 | 43 | |
| 35 | std::vector<StringRef> lld::args::getStrings(opt::InputArgList &Args, int Id) { | |
| 36 | std::vector<StringRef> V; | |
| 37 | for (auto *Arg : Args.filtered(Id)) | |
| 38 | V.push_back(Arg->getValue()); | |
| 39 | return V; | |
| 44 | std::vector<StringRef> lld::args::getStrings(opt::InputArgList &args, int id) { | |
| 45 | std::vector<StringRef> v; | |
| 46 | for (auto *arg : args.filtered(id)) | |
| 47 | v.push_back(arg->getValue()); | |
| 48 | return v; | |
| 40 | 49 | } |
| 41 | 50 | |
| 42 | uint64_t lld::args::getZOptionValue(opt::InputArgList &Args, int Id, | |
| 43 | StringRef Key, uint64_t Default) { | |
| 44 | for (auto *Arg : Args.filtered_reverse(Id)) { | |
| 45 | std::pair<StringRef, StringRef> KV = StringRef(Arg->getValue()).split('='); | |
| 46 | if (KV.first == Key) { | |
| 47 | uint64_t Result = Default; | |
| 48 | if (!to_integer(KV.second, Result)) | |
| 49 | error("invalid " + Key + ": " + KV.second); | |
| 50 | return Result; | |
| 51 | uint64_t lld::args::getZOptionValue(opt::InputArgList &args, int id, | |
| 52 | StringRef key, uint64_t Default) { | |
| 53 | for (auto *arg : args.filtered_reverse(id)) { | |
| 54 | std::pair<StringRef, StringRef> kv = StringRef(arg->getValue()).split('='); | |
| 55 | if (kv.first == key) { | |
| 56 | uint64_t result = Default; | |
| 57 | if (!to_integer(kv.second, result)) | |
| 58 | error("invalid " + key + ": " + kv.second); | |
| 59 | return result; | |
| 51 | 60 | } |
| 52 | 61 | } |
| 53 | 62 | return Default; |
| 54 | 63 | } |
| 55 | 64 | |
| 56 | std::vector<StringRef> lld::args::getLines(MemoryBufferRef MB) { | |
| 57 | SmallVector<StringRef, 0> Arr; | |
| 58 | MB.getBuffer().split(Arr, '\n'); | |
| 65 | std::vector<StringRef> lld::args::getLines(MemoryBufferRef mb) { | |
| 66 | SmallVector<StringRef, 0> arr; | |
| 67 | mb.getBuffer().split(arr, '\n'); | |
| 59 | 68 | |
| 60 | std::vector<StringRef> Ret; | |
| 61 | for (StringRef S : Arr) { | |
| 62 | S = S.trim(); | |
| 63 | if (!S.empty() && S[0] != '#') | |
| 64 | Ret.push_back(S); | |
| 69 | std::vector<StringRef> ret; | |
| 70 | for (StringRef s : arr) { | |
| 71 | s = s.trim(); | |
| 72 | if (!s.empty() && s[0] != '#') | |
| 73 | ret.push_back(s); | |
| 65 | 74 | } |
| 66 | return Ret; | |
| 75 | return ret; | |
| 67 | 76 | } |
| 68 | 77 | |
| 69 | StringRef lld::args::getFilenameWithoutExe(StringRef Path) { | |
| 70 | if (Path.endswith_lower(".exe")) | |
| 71 | return sys::path::stem(Path); | |
| 72 | return sys::path::filename(Path); | |
| 78 | StringRef lld::args::getFilenameWithoutExe(StringRef path) { | |
| 79 | if (path.endswith_lower(".exe")) | |
| 80 | return sys::path::stem(path); | |
| 81 | return sys::path::filename(path); | |
| 73 | 82 | } |
deps/lld/Common/CMakeLists.txt+27| ... | ... | @@ -2,15 +2,42 @@ if(NOT LLD_BUILT_STANDALONE) |
| 2 | 2 | set(tablegen_deps intrinsics_gen) |
| 3 | 3 | endif() |
| 4 | 4 | |
| 5 | find_first_existing_vc_file("${LLVM_MAIN_SRC_DIR}" llvm_vc) | |
| 6 | find_first_existing_vc_file("${LLD_SOURCE_DIR}" lld_vc) | |
| 7 | ||
| 8 | set(version_inc "${CMAKE_CURRENT_BINARY_DIR}/VCSVersion.inc") | |
| 9 | set(generate_vcs_version_script "${LLVM_CMAKE_PATH}/GenerateVersionFromVCS.cmake") | |
| 10 | ||
| 11 | if(lld_vc) | |
| 12 | set(lld_source_dir ${LLD_SOURCE_DIR}) | |
| 13 | endif() | |
| 14 | ||
| 15 | add_custom_command(OUTPUT "${version_inc}" | |
| 16 | DEPENDS "${lld_vc}" "${generate_vcs_version_script}" | |
| 17 | COMMAND ${CMAKE_COMMAND} "-DNAMES=LLD" | |
| 18 | "-DLLD_SOURCE_DIR=${LLD_SOURCE_DIR}" | |
| 19 | "-DHEADER_FILE=${version_inc}" | |
| 20 | -P "${generate_vcs_version_script}") | |
| 21 | ||
| 22 | # Mark the generated header as being generated. | |
| 23 | set_source_files_properties("${version_inc}" | |
| 24 | PROPERTIES GENERATED TRUE | |
| 25 | HEADER_FILE_ONLY TRUE) | |
| 26 | ||
| 27 | set_property(SOURCE Version.cpp APPEND PROPERTY | |
| 28 | COMPILE_DEFINITIONS "HAVE_VCS_VERSION_INC") | |
| 29 | ||
| 5 | 30 | add_lld_library(lldCommon |
| 6 | 31 | Args.cpp |
| 7 | 32 | ErrorHandler.cpp |
| 33 | Filesystem.cpp | |
| 8 | 34 | Memory.cpp |
| 9 | 35 | Reproduce.cpp |
| 10 | 36 | Strings.cpp |
| 11 | 37 | TargetOptionsCommandFlags.cpp |
| 12 | 38 | Threads.cpp |
| 13 | 39 | Timer.cpp |
| 40 | VCSVersion.inc | |
| 14 | 41 | Version.cpp |
| 15 | 42 | |
| 16 | 43 | ADDITIONAL_HEADER_DIRS |
deps/lld/Common/ErrorHandler.cpp+97-63| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- ErrorHandler.cpp ---------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -17,6 +16,7 @@ |
| 17 | 16 | #include "llvm/Support/ManagedStatic.h" |
| 18 | 17 | #include "llvm/Support/raw_ostream.h" |
| 19 | 18 | #include <mutex> |
| 19 | #include <regex> | |
| 20 | 20 | |
| 21 | 21 | #if !defined(_MSC_VER) && !defined(__MINGW32__) |
| 22 | 22 | #include <unistd.h> |
| ... | ... | @@ -27,29 +27,29 @@ using namespace lld; |
| 27 | 27 | |
| 28 | 28 | // The functions defined in this file can be called from multiple threads, |
| 29 | 29 | // but outs() or errs() are not thread-safe. We protect them using a mutex. |
| 30 | static std::mutex Mu; | |
| 30 | static std::mutex mu; | |
| 31 | 31 | |
| 32 | 32 | // Prints "\n" or does nothing, depending on Msg contents of |
| 33 | 33 | // the previous call of this function. |
| 34 | static void newline(raw_ostream *ErrorOS, const Twine &Msg) { | |
| 34 | static void newline(raw_ostream *errorOS, const Twine &msg) { | |
| 35 | 35 | // True if the previous error message contained "\n". |
| 36 | 36 | // We want to separate multi-line error messages with a newline. |
| 37 | static bool Flag; | |
| 37 | static bool flag; | |
| 38 | 38 | |
| 39 | if (Flag) | |
| 40 | *ErrorOS << "\n"; | |
| 41 | Flag = StringRef(Msg.str()).contains('\n'); | |
| 39 | if (flag) | |
| 40 | *errorOS << "\n"; | |
| 41 | flag = StringRef(msg.str()).contains('\n'); | |
| 42 | 42 | } |
| 43 | 43 | |
| 44 | 44 | ErrorHandler &lld::errorHandler() { |
| 45 | static ErrorHandler Handler; | |
| 46 | return Handler; | |
| 45 | static ErrorHandler handler; | |
| 46 | return handler; | |
| 47 | 47 | } |
| 48 | 48 | |
| 49 | void lld::exitLld(int Val) { | |
| 49 | void lld::exitLld(int val) { | |
| 50 | 50 | // Delete any temporary file, while keeping the memory mapping open. |
| 51 | if (errorHandler().OutputBuffer) | |
| 52 | errorHandler().OutputBuffer->discard(); | |
| 51 | if (errorHandler().outputBuffer) | |
| 52 | errorHandler().outputBuffer->discard(); | |
| 53 | 53 | |
| 54 | 54 | // Dealloc/destroy ManagedStatic variables before calling |
| 55 | 55 | // _exit(). In a non-LTO build, this is a nop. In an LTO |
| ... | ... | @@ -58,87 +58,121 @@ void lld::exitLld(int Val) { |
| 58 | 58 | |
| 59 | 59 | outs().flush(); |
| 60 | 60 | errs().flush(); |
| 61 | _exit(Val); | |
| 61 | _exit(val); | |
| 62 | 62 | } |
| 63 | 63 | |
| 64 | void lld::diagnosticHandler(const DiagnosticInfo &DI) { | |
| 65 | SmallString<128> S; | |
| 66 | raw_svector_ostream OS(S); | |
| 67 | DiagnosticPrinterRawOStream DP(OS); | |
| 68 | DI.print(DP); | |
| 69 | switch (DI.getSeverity()) { | |
| 64 | void lld::diagnosticHandler(const DiagnosticInfo &di) { | |
| 65 | SmallString<128> s; | |
| 66 | raw_svector_ostream os(s); | |
| 67 | DiagnosticPrinterRawOStream dp(os); | |
| 68 | di.print(dp); | |
| 69 | switch (di.getSeverity()) { | |
| 70 | 70 | case DS_Error: |
| 71 | error(S); | |
| 71 | error(s); | |
| 72 | 72 | break; |
| 73 | 73 | case DS_Warning: |
| 74 | warn(S); | |
| 74 | warn(s); | |
| 75 | 75 | break; |
| 76 | 76 | case DS_Remark: |
| 77 | 77 | case DS_Note: |
| 78 | message(S); | |
| 78 | message(s); | |
| 79 | 79 | break; |
| 80 | 80 | } |
| 81 | 81 | } |
| 82 | 82 | |
| 83 | void lld::checkError(Error E) { | |
| 84 | handleAllErrors(std::move(E), | |
| 85 | [&](ErrorInfoBase &EIB) { error(EIB.message()); }); | |
| 83 | void lld::checkError(Error e) { | |
| 84 | handleAllErrors(std::move(e), | |
| 85 | [&](ErrorInfoBase &eib) { error(eib.message()); }); | |
| 86 | } | |
| 87 | ||
| 88 | static std::string getLocation(std::string msg, std::string defaultMsg) { | |
| 89 | static std::vector<std::regex> Regexes{ | |
| 90 | std::regex(R"(^undefined symbol:.*\n>>> referenced by (\S+):(\d+)\n.*)"), | |
| 91 | std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"), | |
| 92 | std::regex( | |
| 93 | R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"), | |
| 94 | std::regex( | |
| 95 | R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+).*)"), | |
| 96 | std::regex( | |
| 97 | R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"), | |
| 98 | std::regex( | |
| 99 | R"(^undefined (internal|hidden|protected) symbol: .*\n>>> referenced by (\S+):(\d+)\n.*)"), | |
| 100 | std::regex(R"((\S+):(\d+): unclosed quote)"), | |
| 101 | }; | |
| 102 | ||
| 103 | std::smatch Match; | |
| 104 | for (std::regex &Re : Regexes) { | |
| 105 | if (std::regex_search(msg, Match, Re)) { | |
| 106 | return Match.size() > 2 ? Match.str(1) + "(" + Match.str(2) + ")" | |
| 107 | : Match.str(1); | |
| 108 | } | |
| 109 | } | |
| 110 | return defaultMsg; | |
| 86 | 111 | } |
| 87 | 112 | |
| 88 | void ErrorHandler::print(StringRef S, raw_ostream::Colors C) { | |
| 89 | *ErrorOS << LogName << ": "; | |
| 90 | if (ColorDiagnostics) { | |
| 91 | ErrorOS->changeColor(C, true); | |
| 92 | *ErrorOS << S; | |
| 93 | ErrorOS->resetColor(); | |
| 113 | void ErrorHandler::printHeader(StringRef s, raw_ostream::Colors c, | |
| 114 | const Twine &msg) { | |
| 115 | ||
| 116 | if (vsDiagnostics) { | |
| 117 | // A Visual Studio-style error message starts with an error location. | |
| 118 | // If a location cannot be extracted then we default to LogName. | |
| 119 | *errorOS << getLocation(msg.str(), logName) << ": "; | |
| 120 | } else { | |
| 121 | *errorOS << logName << ": "; | |
| 122 | } | |
| 123 | ||
| 124 | if (colorDiagnostics) { | |
| 125 | errorOS->changeColor(c, true); | |
| 126 | *errorOS << s; | |
| 127 | errorOS->resetColor(); | |
| 94 | 128 | } else { |
| 95 | *ErrorOS << S; | |
| 129 | *errorOS << s; | |
| 96 | 130 | } |
| 97 | 131 | } |
| 98 | 132 | |
| 99 | void ErrorHandler::log(const Twine &Msg) { | |
| 100 | if (Verbose) { | |
| 101 | std::lock_guard<std::mutex> Lock(Mu); | |
| 102 | *ErrorOS << LogName << ": " << Msg << "\n"; | |
| 133 | void ErrorHandler::log(const Twine &msg) { | |
| 134 | if (verbose) { | |
| 135 | std::lock_guard<std::mutex> lock(mu); | |
| 136 | *errorOS << logName << ": " << msg << "\n"; | |
| 103 | 137 | } |
| 104 | 138 | } |
| 105 | 139 | |
| 106 | void ErrorHandler::message(const Twine &Msg) { | |
| 107 | std::lock_guard<std::mutex> Lock(Mu); | |
| 108 | outs() << Msg << "\n"; | |
| 140 | void ErrorHandler::message(const Twine &msg) { | |
| 141 | std::lock_guard<std::mutex> lock(mu); | |
| 142 | outs() << msg << "\n"; | |
| 109 | 143 | outs().flush(); |
| 110 | 144 | } |
| 111 | 145 | |
| 112 | void ErrorHandler::warn(const Twine &Msg) { | |
| 113 | if (FatalWarnings) { | |
| 114 | error(Msg); | |
| 146 | void ErrorHandler::warn(const Twine &msg) { | |
| 147 | if (fatalWarnings) { | |
| 148 | error(msg); | |
| 115 | 149 | return; |
| 116 | 150 | } |
| 117 | 151 | |
| 118 | std::lock_guard<std::mutex> Lock(Mu); | |
| 119 | newline(ErrorOS, Msg); | |
| 120 | print("warning: ", raw_ostream::MAGENTA); | |
| 121 | *ErrorOS << Msg << "\n"; | |
| 152 | std::lock_guard<std::mutex> lock(mu); | |
| 153 | newline(errorOS, msg); | |
| 154 | printHeader("warning: ", raw_ostream::MAGENTA, msg); | |
| 155 | *errorOS << msg << "\n"; | |
| 122 | 156 | } |
| 123 | 157 | |
| 124 | void ErrorHandler::error(const Twine &Msg) { | |
| 125 | std::lock_guard<std::mutex> Lock(Mu); | |
| 126 | newline(ErrorOS, Msg); | |
| 127 | ||
| 128 | if (ErrorLimit == 0 || ErrorCount < ErrorLimit) { | |
| 129 | print("error: ", raw_ostream::RED); | |
| 130 | *ErrorOS << Msg << "\n"; | |
| 131 | } else if (ErrorCount == ErrorLimit) { | |
| 132 | print("error: ", raw_ostream::RED); | |
| 133 | *ErrorOS << ErrorLimitExceededMsg << "\n"; | |
| 134 | if (ExitEarly) | |
| 158 | void ErrorHandler::error(const Twine &msg) { | |
| 159 | std::lock_guard<std::mutex> lock(mu); | |
| 160 | newline(errorOS, msg); | |
| 161 | ||
| 162 | if (errorLimit == 0 || errorCount < errorLimit) { | |
| 163 | printHeader("error: ", raw_ostream::RED, msg); | |
| 164 | *errorOS << msg << "\n"; | |
| 165 | } else if (errorCount == errorLimit) { | |
| 166 | printHeader("error: ", raw_ostream::RED, msg); | |
| 167 | *errorOS << errorLimitExceededMsg << "\n"; | |
| 168 | if (exitEarly) | |
| 135 | 169 | exitLld(1); |
| 136 | 170 | } |
| 137 | 171 | |
| 138 | ++ErrorCount; | |
| 172 | ++errorCount; | |
| 139 | 173 | } |
| 140 | 174 | |
| 141 | void ErrorHandler::fatal(const Twine &Msg) { | |
| 142 | error(Msg); | |
| 175 | void ErrorHandler::fatal(const Twine &msg) { | |
| 176 | error(msg); | |
| 143 | 177 | exitLld(1); |
| 144 | 178 | } |
deps/lld/Common/Filesystem.cpp created+99| ... | ... | @@ -0,0 +1,99 @@ |
| 1 | //===- Filesystem.cpp -----------------------------------------------------===// | |
| 2 | // | |
| 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 | |
| 6 | // | |
| 7 | //===----------------------------------------------------------------------===// | |
| 8 | // | |
| 9 | // This file contains a few utility functions to handle files. | |
| 10 | // | |
| 11 | //===----------------------------------------------------------------------===// | |
| 12 | ||
| 13 | #include "lld/Common/Filesystem.h" | |
| 14 | #include "lld/Common/Threads.h" | |
| 15 | #include "llvm/Config/llvm-config.h" | |
| 16 | #include "llvm/Support/FileOutputBuffer.h" | |
| 17 | #include "llvm/Support/FileSystem.h" | |
| 18 | #if LLVM_ON_UNIX | |
| 19 | #include <unistd.h> | |
| 20 | #endif | |
| 21 | #include <thread> | |
| 22 | ||
| 23 | using namespace llvm; | |
| 24 | using namespace lld; | |
| 25 | ||
| 26 | // Removes a given file asynchronously. This is a performance hack, | |
| 27 | // so remove this when operating systems are improved. | |
| 28 | // | |
| 29 | // On Linux (and probably on other Unix-like systems), unlink(2) is a | |
| 30 | // noticeably slow system call. As of 2016, unlink takes 250 | |
| 31 | // milliseconds to remove a 1 GB file on ext4 filesystem on my machine. | |
| 32 | // | |
| 33 | // To create a new result file, we first remove existing file. So, if | |
| 34 | // you repeatedly link a 1 GB program in a regular compile-link-debug | |
| 35 | // cycle, every cycle wastes 250 milliseconds only to remove a file. | |
| 36 | // Since LLD can link a 1 GB binary in about 5 seconds, that waste | |
| 37 | // actually counts. | |
| 38 | // | |
| 39 | // This function spawns a background thread to remove the file. | |
| 40 | // The calling thread returns almost immediately. | |
| 41 | void lld::unlinkAsync(StringRef path) { | |
| 42 | // Removing a file is async on windows. | |
| 43 | #if defined(_WIN32) | |
| 44 | sys::fs::remove(path); | |
| 45 | #else | |
| 46 | if (!threadsEnabled || !sys::fs::exists(path) || | |
| 47 | !sys::fs::is_regular_file(path)) | |
| 48 | return; | |
| 49 | ||
| 50 | // We cannot just remove path from a different thread because we are now going | |
| 51 | // to create path as a new file. | |
| 52 | // Instead we open the file and unlink it on this thread. The unlink is fast | |
| 53 | // since the open fd guarantees that it is not removing the last reference. | |
| 54 | int fd; | |
| 55 | std::error_code ec = sys::fs::openFileForRead(path, fd); | |
| 56 | sys::fs::remove(path); | |
| 57 | ||
| 58 | if (ec) | |
| 59 | return; | |
| 60 | ||
| 61 | // close and therefore remove TempPath in background. | |
| 62 | std::mutex m; | |
| 63 | std::condition_variable cv; | |
| 64 | bool started = false; | |
| 65 | std::thread([&, fd] { | |
| 66 | { | |
| 67 | std::lock_guard<std::mutex> l(m); | |
| 68 | started = true; | |
| 69 | cv.notify_all(); | |
| 70 | } | |
| 71 | ::close(fd); | |
| 72 | }).detach(); | |
| 73 | ||
| 74 | // GLIBC 2.26 and earlier have race condition that crashes an entire process | |
| 75 | // if the main thread calls exit(2) while other thread is starting up. | |
| 76 | std::unique_lock<std::mutex> l(m); | |
| 77 | cv.wait(l, [&] { return started; }); | |
| 78 | #endif | |
| 79 | } | |
| 80 | ||
| 81 | // Simulate file creation to see if Path is writable. | |
| 82 | // | |
| 83 | // Determining whether a file is writable or not is amazingly hard, | |
| 84 | // and after all the only reliable way of doing that is to actually | |
| 85 | // create a file. But we don't want to do that in this function | |
| 86 | // because LLD shouldn't update any file if it will end in a failure. | |
| 87 | // We also don't want to reimplement heuristics to determine if a | |
| 88 | // file is writable. So we'll let FileOutputBuffer do the work. | |
| 89 | // | |
| 90 | // FileOutputBuffer doesn't touch a desitnation file until commit() | |
| 91 | // is called. We use that class without calling commit() to predict | |
| 92 | // if the given file is writable. | |
| 93 | std::error_code lld::tryCreateFile(StringRef path) { | |
| 94 | if (path.empty()) | |
| 95 | return std::error_code(); | |
| 96 | if (path == "-") | |
| 97 | return std::error_code(); | |
| 98 | return errorToErrorCode(FileOutputBuffer::create(path, 1).takeError()); | |
| 99 | } |
deps/lld/Common/Memory.cpp+9-10| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Memory.cpp ---------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -12,12 +11,12 @@ |
| 12 | 11 | using namespace llvm; |
| 13 | 12 | using namespace lld; |
| 14 | 13 | |
| 15 | BumpPtrAllocator lld::BAlloc; | |
| 16 | StringSaver lld::Saver{BAlloc}; | |
| 17 | std::vector<SpecificAllocBase *> lld::SpecificAllocBase::Instances; | |
| 14 | BumpPtrAllocator lld::bAlloc; | |
| 15 | StringSaver lld::saver{bAlloc}; | |
| 16 | std::vector<SpecificAllocBase *> lld::SpecificAllocBase::instances; | |
| 18 | 17 | |
| 19 | 18 | void lld::freeArena() { |
| 20 | for (SpecificAllocBase *Alloc : SpecificAllocBase::Instances) | |
| 21 | Alloc->reset(); | |
| 22 | BAlloc.Reset(); | |
| 19 | for (SpecificAllocBase *alloc : SpecificAllocBase::instances) | |
| 20 | alloc->reset(); | |
| 21 | bAlloc.Reset(); | |
| 23 | 22 | } |
deps/lld/Common/Reproduce.cpp+31-36| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Reproduce.cpp - Utilities for creating reproducers -----------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -22,45 +21,41 @@ using namespace llvm::sys; |
| 22 | 21 | // assuming that the current directory is "/home/john/bar". |
| 23 | 22 | // Returned string is a forward slash separated path even on Windows to avoid |
| 24 | 23 | // a mess with backslash-as-escape and backslash-as-path-separator. |
| 25 | std::string lld::relativeToRoot(StringRef Path) { | |
| 26 | SmallString<128> Abs = Path; | |
| 27 | if (fs::make_absolute(Abs)) | |
| 28 | return Path; | |
| 29 | path::remove_dots(Abs, /*remove_dot_dot=*/true); | |
| 24 | std::string lld::relativeToRoot(StringRef path) { | |
| 25 | SmallString<128> abs = path; | |
| 26 | if (fs::make_absolute(abs)) | |
| 27 | return path; | |
| 28 | path::remove_dots(abs, /*remove_dot_dot=*/true); | |
| 30 | 29 | |
| 31 | 30 | // This is Windows specific. root_name() returns a drive letter |
| 32 | 31 | // (e.g. "c:") or a UNC name (//net). We want to keep it as part |
| 33 | 32 | // of the result. |
| 34 | SmallString<128> Res; | |
| 35 | StringRef Root = path::root_name(Abs); | |
| 36 | if (Root.endswith(":")) | |
| 37 | Res = Root.drop_back(); | |
| 38 | else if (Root.startswith("//")) | |
| 39 | Res = Root.substr(2); | |
| 40 | ||
| 41 | path::append(Res, path::relative_path(Abs)); | |
| 42 | return path::convert_to_slash(Res); | |
| 33 | SmallString<128> res; | |
| 34 | StringRef root = path::root_name(abs); | |
| 35 | if (root.endswith(":")) | |
| 36 | res = root.drop_back(); | |
| 37 | else if (root.startswith("//")) | |
| 38 | res = root.substr(2); | |
| 39 | ||
| 40 | path::append(res, path::relative_path(abs)); | |
| 41 | return path::convert_to_slash(res); | |
| 43 | 42 | } |
| 44 | 43 | |
| 45 | 44 | // Quote a given string if it contains a space character. |
| 46 | std::string lld::quote(StringRef S) { | |
| 47 | if (S.contains(' ')) | |
| 48 | return ("\"" + S + "\"").str(); | |
| 49 | return S; | |
| 50 | } | |
| 51 | ||
| 52 | std::string lld::rewritePath(StringRef S) { | |
| 53 | if (fs::exists(S)) | |
| 54 | return relativeToRoot(S); | |
| 55 | return S; | |
| 45 | std::string lld::quote(StringRef s) { | |
| 46 | if (s.contains(' ')) | |
| 47 | return ("\"" + s + "\"").str(); | |
| 48 | return s; | |
| 56 | 49 | } |
| 57 | 50 | |
| 58 | std::string lld::toString(const opt::Arg &Arg) { | |
| 59 | std::string K = Arg.getSpelling(); | |
| 60 | if (Arg.getNumValues() == 0) | |
| 61 | return K; | |
| 62 | std::string V = quote(Arg.getValue()); | |
| 63 | if (Arg.getOption().getRenderStyle() == opt::Option::RenderJoinedStyle) | |
| 64 | return K + V; | |
| 65 | return K + " " + V; | |
| 51 | // Converts an Arg to a string representation suitable for a response file. | |
| 52 | // To show an Arg in a diagnostic, use Arg::getAsString() instead. | |
| 53 | std::string lld::toString(const opt::Arg &arg) { | |
| 54 | std::string k = arg.getSpelling(); | |
| 55 | if (arg.getNumValues() == 0) | |
| 56 | return k; | |
| 57 | std::string v = quote(arg.getValue()); | |
| 58 | if (arg.getOption().getRenderStyle() == opt::Option::RenderJoinedStyle) | |
| 59 | return k + v; | |
| 60 | return k + " " + v; | |
| 66 | 61 | } |
deps/lld/Common/Strings.cpp+49-50| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Strings.cpp -------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -20,85 +19,85 @@ using namespace llvm; |
| 20 | 19 | using namespace lld; |
| 21 | 20 | |
| 22 | 21 | // Returns the demangled C++ symbol name for Name. |
| 23 | Optional<std::string> lld::demangleItanium(StringRef Name) { | |
| 22 | Optional<std::string> lld::demangleItanium(StringRef name) { | |
| 24 | 23 | // itaniumDemangle can be used to demangle strings other than symbol |
| 25 | 24 | // names which do not necessarily start with "_Z". Name can be |
| 26 | 25 | // either a C or C++ symbol. Don't call itaniumDemangle if the name |
| 27 | 26 | // does not look like a C++ symbol name to avoid getting unexpected |
| 28 | 27 | // result for a C symbol that happens to match a mangled type name. |
| 29 | if (!Name.startswith("_Z")) | |
| 28 | if (!name.startswith("_Z")) | |
| 30 | 29 | return None; |
| 31 | 30 | |
| 32 | char *Buf = itaniumDemangle(Name.str().c_str(), nullptr, nullptr, nullptr); | |
| 33 | if (!Buf) | |
| 31 | char *buf = itaniumDemangle(name.str().c_str(), nullptr, nullptr, nullptr); | |
| 32 | if (!buf) | |
| 34 | 33 | return None; |
| 35 | std::string S(Buf); | |
| 36 | free(Buf); | |
| 37 | return S; | |
| 34 | std::string s(buf); | |
| 35 | free(buf); | |
| 36 | return s; | |
| 38 | 37 | } |
| 39 | 38 | |
| 40 | Optional<std::string> lld::demangleMSVC(StringRef Name) { | |
| 41 | std::string Prefix; | |
| 42 | if (Name.consume_front("__imp_")) | |
| 43 | Prefix = "__declspec(dllimport) "; | |
| 39 | Optional<std::string> lld::demangleMSVC(StringRef name) { | |
| 40 | std::string prefix; | |
| 41 | if (name.consume_front("__imp_")) | |
| 42 | prefix = "__declspec(dllimport) "; | |
| 44 | 43 | |
| 45 | 44 | // Demangle only C++ names. |
| 46 | if (!Name.startswith("?")) | |
| 45 | if (!name.startswith("?")) | |
| 47 | 46 | return None; |
| 48 | 47 | |
| 49 | char *Buf = microsoftDemangle(Name.str().c_str(), nullptr, nullptr, nullptr); | |
| 50 | if (!Buf) | |
| 48 | char *buf = microsoftDemangle(name.str().c_str(), nullptr, nullptr, nullptr); | |
| 49 | if (!buf) | |
| 51 | 50 | return None; |
| 52 | std::string S(Buf); | |
| 53 | free(Buf); | |
| 54 | return Prefix + S; | |
| 51 | std::string s(buf); | |
| 52 | free(buf); | |
| 53 | return prefix + s; | |
| 55 | 54 | } |
| 56 | 55 | |
| 57 | StringMatcher::StringMatcher(ArrayRef<StringRef> Pat) { | |
| 58 | for (StringRef S : Pat) { | |
| 59 | Expected<GlobPattern> Pat = GlobPattern::create(S); | |
| 60 | if (!Pat) | |
| 61 | error(toString(Pat.takeError())); | |
| 56 | StringMatcher::StringMatcher(ArrayRef<StringRef> pat) { | |
| 57 | for (StringRef s : pat) { | |
| 58 | Expected<GlobPattern> pat = GlobPattern::create(s); | |
| 59 | if (!pat) | |
| 60 | error(toString(pat.takeError())); | |
| 62 | 61 | else |
| 63 | Patterns.push_back(*Pat); | |
| 62 | patterns.push_back(*pat); | |
| 64 | 63 | } |
| 65 | 64 | } |
| 66 | 65 | |
| 67 | bool StringMatcher::match(StringRef S) const { | |
| 68 | for (const GlobPattern &Pat : Patterns) | |
| 69 | if (Pat.match(S)) | |
| 66 | bool StringMatcher::match(StringRef s) const { | |
| 67 | for (const GlobPattern &pat : patterns) | |
| 68 | if (pat.match(s)) | |
| 70 | 69 | return true; |
| 71 | 70 | return false; |
| 72 | 71 | } |
| 73 | 72 | |
| 74 | 73 | // Converts a hex string (e.g. "deadbeef") to a vector. |
| 75 | std::vector<uint8_t> lld::parseHex(StringRef S) { | |
| 76 | std::vector<uint8_t> Hex; | |
| 77 | while (!S.empty()) { | |
| 78 | StringRef B = S.substr(0, 2); | |
| 79 | S = S.substr(2); | |
| 80 | uint8_t H; | |
| 81 | if (!to_integer(B, H, 16)) { | |
| 82 | error("not a hexadecimal value: " + B); | |
| 74 | std::vector<uint8_t> lld::parseHex(StringRef s) { | |
| 75 | std::vector<uint8_t> hex; | |
| 76 | while (!s.empty()) { | |
| 77 | StringRef b = s.substr(0, 2); | |
| 78 | s = s.substr(2); | |
| 79 | uint8_t h; | |
| 80 | if (!to_integer(b, h, 16)) { | |
| 81 | error("not a hexadecimal value: " + b); | |
| 83 | 82 | return {}; |
| 84 | 83 | } |
| 85 | Hex.push_back(H); | |
| 84 | hex.push_back(h); | |
| 86 | 85 | } |
| 87 | return Hex; | |
| 86 | return hex; | |
| 88 | 87 | } |
| 89 | 88 | |
| 90 | 89 | // Returns true if S is valid as a C language identifier. |
| 91 | bool lld::isValidCIdentifier(StringRef S) { | |
| 92 | return !S.empty() && (isAlpha(S[0]) || S[0] == '_') && | |
| 93 | std::all_of(S.begin() + 1, S.end(), | |
| 94 | [](char C) { return C == '_' || isAlnum(C); }); | |
| 90 | bool lld::isValidCIdentifier(StringRef s) { | |
| 91 | return !s.empty() && (isAlpha(s[0]) || s[0] == '_') && | |
| 92 | std::all_of(s.begin() + 1, s.end(), | |
| 93 | [](char c) { return c == '_' || isAlnum(c); }); | |
| 95 | 94 | } |
| 96 | 95 | |
| 97 | 96 | // Write the contents of the a buffer to a file |
| 98 | void lld::saveBuffer(StringRef Buffer, const Twine &Path) { | |
| 99 | std::error_code EC; | |
| 100 | raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None); | |
| 101 | if (EC) | |
| 102 | error("cannot create " + Path + ": " + EC.message()); | |
| 103 | OS << Buffer; | |
| 97 | void lld::saveBuffer(StringRef buffer, const Twine &path) { | |
| 98 | std::error_code ec; | |
| 99 | raw_fd_ostream os(path.str(), ec, sys::fs::OpenFlags::F_None); | |
| 100 | if (ec) | |
| 101 | error("cannot create " + path + ": " + ec.message()); | |
| 102 | os << buffer; | |
| 104 | 103 | } |
deps/lld/Common/TargetOptionsCommandFlags.cpp+9-9| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===-- TargetOptionsCommandFlags.cpp ---------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -20,16 +19,17 @@ |
| 20 | 19 | #include "llvm/Target/TargetOptions.h" |
| 21 | 20 | |
| 22 | 21 | // Define an externally visible version of |
| 23 | // InitTargetOptionsFromCodeGenFlags, so that its functionality can be | |
| 22 | // initTargetOptionsFromCodeGenFlags, so that its functionality can be | |
| 24 | 23 | // used without having to include llvm/CodeGen/CommandFlags.inc, which |
| 25 | 24 | // would lead to multiple definitions of the command line flags. |
| 26 | llvm::TargetOptions lld::InitTargetOptionsFromCodeGenFlags() { | |
| 25 | llvm::TargetOptions lld::initTargetOptionsFromCodeGenFlags() { | |
| 27 | 26 | return ::InitTargetOptionsFromCodeGenFlags(); |
| 28 | 27 | } |
| 29 | 28 | |
| 30 | llvm::Optional<llvm::CodeModel::Model> lld::GetCodeModelFromCMModel() { | |
| 29 | llvm::Optional<llvm::CodeModel::Model> lld::getCodeModelFromCMModel() { | |
| 31 | 30 | return getCodeModel(); |
| 32 | 31 | } |
| 33 | 32 | |
| 34 | std::string lld::GetCPUStr() { return ::getCPUStr(); } | |
| 35 | std::vector<std::string> lld::GetMAttrs() { return ::MAttrs; } | |
| 33 | std::string lld::getCPUStr() { return ::getCPUStr(); } | |
| 34 | ||
| 35 | std::vector<std::string> lld::getMAttrs() { return ::MAttrs; } |
deps/lld/Common/Threads.cpp+4-5| ... | ... | @@ -1,12 +1,11 @@ |
| 1 | 1 | //===- Threads.cpp --------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| 10 | 9 | #include "lld/Common/Threads.h" |
| 11 | 10 | |
| 12 | bool lld::ThreadsEnabled = true; | |
| 11 | bool lld::threadsEnabled = true; |
deps/lld/Common/Timer.cpp+30-31| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Timer.cpp ----------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -14,43 +13,43 @@ |
| 14 | 13 | using namespace lld; |
| 15 | 14 | using namespace llvm; |
| 16 | 15 | |
| 17 | ScopedTimer::ScopedTimer(Timer &T) : T(&T) { T.start(); } | |
| 16 | ScopedTimer::ScopedTimer(Timer &t) : t(&t) { t.start(); } | |
| 18 | 17 | |
| 19 | 18 | void ScopedTimer::stop() { |
| 20 | if (!T) | |
| 19 | if (!t) | |
| 21 | 20 | return; |
| 22 | T->stop(); | |
| 23 | T = nullptr; | |
| 21 | t->stop(); | |
| 22 | t = nullptr; | |
| 24 | 23 | } |
| 25 | 24 | |
| 26 | 25 | ScopedTimer::~ScopedTimer() { stop(); } |
| 27 | 26 | |
| 28 | Timer::Timer(llvm::StringRef Name) : Name(Name), Parent(nullptr) {} | |
| 29 | Timer::Timer(llvm::StringRef Name, Timer &Parent) | |
| 30 | : Name(Name), Parent(&Parent) {} | |
| 27 | Timer::Timer(llvm::StringRef name) : name(name), parent(nullptr) {} | |
| 28 | Timer::Timer(llvm::StringRef name, Timer &parent) | |
| 29 | : name(name), parent(&parent) {} | |
| 31 | 30 | |
| 32 | 31 | void Timer::start() { |
| 33 | if (Parent && Total.count() == 0) | |
| 34 | Parent->Children.push_back(this); | |
| 35 | StartTime = std::chrono::high_resolution_clock::now(); | |
| 32 | if (parent && total.count() == 0) | |
| 33 | parent->children.push_back(this); | |
| 34 | startTime = std::chrono::high_resolution_clock::now(); | |
| 36 | 35 | } |
| 37 | 36 | |
| 38 | 37 | void Timer::stop() { |
| 39 | Total += (std::chrono::high_resolution_clock::now() - StartTime); | |
| 38 | total += (std::chrono::high_resolution_clock::now() - startTime); | |
| 40 | 39 | } |
| 41 | 40 | |
| 42 | 41 | Timer &Timer::root() { |
| 43 | static Timer RootTimer("Total Link Time"); | |
| 44 | return RootTimer; | |
| 42 | static Timer rootTimer("Total Link Time"); | |
| 43 | return rootTimer; | |
| 45 | 44 | } |
| 46 | 45 | |
| 47 | 46 | void Timer::print() { |
| 48 | double TotalDuration = static_cast<double>(root().millis()); | |
| 47 | double totalDuration = static_cast<double>(root().millis()); | |
| 49 | 48 | |
| 50 | 49 | // We want to print the grand total under all the intermediate phases, so we |
| 51 | 50 | // print all children first, then print the total under that. |
| 52 | for (const auto &Child : Children) | |
| 53 | Child->print(1, TotalDuration); | |
| 51 | for (const auto &child : children) | |
| 52 | child->print(1, totalDuration); | |
| 54 | 53 | |
| 55 | 54 | message(std::string(49, '-')); |
| 56 | 55 | |
| ... | ... | @@ -59,22 +58,22 @@ void Timer::print() { |
| 59 | 58 | |
| 60 | 59 | double Timer::millis() const { |
| 61 | 60 | return std::chrono::duration_cast<std::chrono::duration<double, std::milli>>( |
| 62 | Total) | |
| 61 | total) | |
| 63 | 62 | .count(); |
| 64 | 63 | } |
| 65 | 64 | |
| 66 | void Timer::print(int Depth, double TotalDuration, bool Recurse) const { | |
| 67 | double P = 100.0 * millis() / TotalDuration; | |
| 65 | void Timer::print(int depth, double totalDuration, bool recurse) const { | |
| 66 | double p = 100.0 * millis() / totalDuration; | |
| 68 | 67 | |
| 69 | SmallString<32> Str; | |
| 70 | llvm::raw_svector_ostream Stream(Str); | |
| 71 | std::string S = std::string(Depth * 2, ' ') + Name + std::string(":"); | |
| 72 | Stream << format("%-30s%5d ms (%5.1f%%)", S.c_str(), (int)millis(), P); | |
| 68 | SmallString<32> str; | |
| 69 | llvm::raw_svector_ostream stream(str); | |
| 70 | std::string s = std::string(depth * 2, ' ') + name + std::string(":"); | |
| 71 | stream << format("%-30s%5d ms (%5.1f%%)", s.c_str(), (int)millis(), p); | |
| 73 | 72 | |
| 74 | message(Str); | |
| 73 | message(str); | |
| 75 | 74 | |
| 76 | if (Recurse) { | |
| 77 | for (const auto &Child : Children) | |
| 78 | Child->print(Depth + 1, TotalDuration); | |
| 75 | if (recurse) { | |
| 76 | for (const auto &child : children) | |
| 77 | child->print(depth + 1, totalDuration); | |
| 79 | 78 | } |
| 80 | 79 | } |
deps/lld/Common/Version.cpp+13-29| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/Common/Version.cpp - LLD Version Number ---------------*- C++-=====// |
| 2 | 2 | // |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -13,31 +12,16 @@ |
| 13 | 12 | |
| 14 | 13 | #include "lld/Common/Version.h" |
| 15 | 14 | |
| 16 | using namespace llvm; | |
| 17 | ||
| 18 | // Returns an SVN repository path, which is usually "trunk". | |
| 19 | static std::string getRepositoryPath() { | |
| 20 | StringRef S = LLD_REPOSITORY_STRING; | |
| 21 | size_t Pos = S.find("lld/"); | |
| 22 | if (Pos != StringRef::npos) | |
| 23 | return S.substr(Pos + 4); | |
| 24 | return S; | |
| 25 | } | |
| 26 | ||
| 27 | // Returns an SVN repository name, e.g., " (trunk 284614)" | |
| 28 | // or an empty string if no repository info is available. | |
| 29 | static std::string getRepository() { | |
| 30 | std::string Repo = getRepositoryPath(); | |
| 31 | std::string Rev = LLD_REVISION_STRING; | |
| 32 | ||
| 33 | if (Repo.empty() && Rev.empty()) | |
| 34 | return ""; | |
| 35 | if (!Repo.empty() && !Rev.empty()) | |
| 36 | return " (" + Repo + " " + Rev + ")"; | |
| 37 | return " (" + Repo + Rev + ")"; | |
| 38 | } | |
| 15 | #ifdef HAVE_VCS_VERSION_INC | |
| 16 | #include "VCSVersion.inc" | |
| 17 | #endif | |
| 39 | 18 | |
| 40 | // Returns a version string, e.g., "LLD 4.0 (lld/trunk 284614)". | |
| 19 | // Returns a version string, e.g.: | |
| 20 | // lld 9.0.0 (https://github.com/llvm/llvm-project.git 9efdd7ac5e914d3c9fa1ef) | |
| 41 | 21 | std::string lld::getLLDVersion() { |
| 42 | return "LLD " + std::string(LLD_VERSION_STRING) + getRepository(); | |
| 22 | #if defined(LLD_REPOSITORY) && defined(LLD_REVISION) | |
| 23 | return "LLD " LLD_VERSION_STRING " (" LLD_REPOSITORY " " LLD_REVISION ")"; | |
| 24 | #else | |
| 25 | return "LLD " LLD_VERSION_STRING; | |
| 26 | #endif | |
| 43 | 27 | } |
deps/lld/ELF/AArch64ErrataFix.cpp+247-248| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- AArch64ErrataFix.cpp -----------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // This file implements Section Patching for the purpose of working around |
| ... | ... | @@ -57,8 +56,8 @@ using namespace lld::elf; |
| 57 | 56 | |
| 58 | 57 | // ADRP |
| 59 | 58 | // | 1 | immlo (2) | 1 | 0 0 0 0 | immhi (19) | Rd (5) | |
| 60 | static bool isADRP(uint32_t Instr) { | |
| 61 | return (Instr & 0x9f000000) == 0x90000000; | |
| 59 | static bool isADRP(uint32_t instr) { | |
| 60 | return (instr & 0x9f000000) == 0x90000000; | |
| 62 | 61 | } |
| 63 | 62 | |
| 64 | 63 | // Load and store bit patterns from ARMv8-A ARM ARM. |
| ... | ... | @@ -67,8 +66,8 @@ static bool isADRP(uint32_t Instr) { |
| 67 | 66 | |
| 68 | 67 | // All loads and stores have 1 (at bit postion 27), (0 at bit position 25). |
| 69 | 68 | // | op0 x op1 (2) | 1 op2 0 op3 (2) | x | op4 (5) | xxxx | op5 (2) | x (10) | |
| 70 | static bool isLoadStoreClass(uint32_t Instr) { | |
| 71 | return (Instr & 0x0a000000) == 0x08000000; | |
| 69 | static bool isLoadStoreClass(uint32_t instr) { | |
| 70 | return (instr & 0x0a000000) == 0x08000000; | |
| 72 | 71 | } |
| 73 | 72 | |
| 74 | 73 | // LDN/STN multiple no offset |
| ... | ... | @@ -83,20 +82,20 @@ static bool isLoadStoreClass(uint32_t Instr) { |
| 83 | 82 | // opcode == 0110 ST1 3 registers. |
| 84 | 83 | // opcode == 0111 ST1 1 register. |
| 85 | 84 | // opcode == 1010 ST1 2 registers. |
| 86 | static bool isST1MultipleOpcode(uint32_t Instr) { | |
| 87 | return (Instr & 0x0000f000) == 0x00002000 || | |
| 88 | (Instr & 0x0000f000) == 0x00006000 || | |
| 89 | (Instr & 0x0000f000) == 0x00007000 || | |
| 90 | (Instr & 0x0000f000) == 0x0000a000; | |
| 85 | static bool isST1MultipleOpcode(uint32_t instr) { | |
| 86 | return (instr & 0x0000f000) == 0x00002000 || | |
| 87 | (instr & 0x0000f000) == 0x00006000 || | |
| 88 | (instr & 0x0000f000) == 0x00007000 || | |
| 89 | (instr & 0x0000f000) == 0x0000a000; | |
| 91 | 90 | } |
| 92 | 91 | |
| 93 | static bool isST1Multiple(uint32_t Instr) { | |
| 94 | return (Instr & 0xbfff0000) == 0x0c000000 && isST1MultipleOpcode(Instr); | |
| 92 | static bool isST1Multiple(uint32_t instr) { | |
| 93 | return (instr & 0xbfff0000) == 0x0c000000 && isST1MultipleOpcode(instr); | |
| 95 | 94 | } |
| 96 | 95 | |
| 97 | 96 | // Writes to Rn (writeback). |
| 98 | static bool isST1MultiplePost(uint32_t Instr) { | |
| 99 | return (Instr & 0xbfe00000) == 0x0c800000 && isST1MultipleOpcode(Instr); | |
| 97 | static bool isST1MultiplePost(uint32_t instr) { | |
| 98 | return (instr & 0xbfe00000) == 0x0c800000 && isST1MultipleOpcode(instr); | |
| 100 | 99 | } |
| 101 | 100 | |
| 102 | 101 | // LDN/STN single no offset |
| ... | ... | @@ -111,41 +110,41 @@ static bool isST1MultiplePost(uint32_t Instr) { |
| 111 | 110 | // opcode == 000 ST1 8-bit. |
| 112 | 111 | // opcode == 010 ST1 16-bit. |
| 113 | 112 | // opcode == 100 ST1 32 or 64-bit (Size determines which). |
| 114 | static bool isST1SingleOpcode(uint32_t Instr) { | |
| 115 | return (Instr & 0x0040e000) == 0x00000000 || | |
| 116 | (Instr & 0x0040e000) == 0x00004000 || | |
| 117 | (Instr & 0x0040e000) == 0x00008000; | |
| 113 | static bool isST1SingleOpcode(uint32_t instr) { | |
| 114 | return (instr & 0x0040e000) == 0x00000000 || | |
| 115 | (instr & 0x0040e000) == 0x00004000 || | |
| 116 | (instr & 0x0040e000) == 0x00008000; | |
| 118 | 117 | } |
| 119 | 118 | |
| 120 | static bool isST1Single(uint32_t Instr) { | |
| 121 | return (Instr & 0xbfff0000) == 0x0d000000 && isST1SingleOpcode(Instr); | |
| 119 | static bool isST1Single(uint32_t instr) { | |
| 120 | return (instr & 0xbfff0000) == 0x0d000000 && isST1SingleOpcode(instr); | |
| 122 | 121 | } |
| 123 | 122 | |
| 124 | 123 | // Writes to Rn (writeback). |
| 125 | static bool isST1SinglePost(uint32_t Instr) { | |
| 126 | return (Instr & 0xbfe00000) == 0x0d800000 && isST1SingleOpcode(Instr); | |
| 124 | static bool isST1SinglePost(uint32_t instr) { | |
| 125 | return (instr & 0xbfe00000) == 0x0d800000 && isST1SingleOpcode(instr); | |
| 127 | 126 | } |
| 128 | 127 | |
| 129 | static bool isST1(uint32_t Instr) { | |
| 130 | return isST1Multiple(Instr) || isST1MultiplePost(Instr) || | |
| 131 | isST1Single(Instr) || isST1SinglePost(Instr); | |
| 128 | static bool isST1(uint32_t instr) { | |
| 129 | return isST1Multiple(instr) || isST1MultiplePost(instr) || | |
| 130 | isST1Single(instr) || isST1SinglePost(instr); | |
| 132 | 131 | } |
| 133 | 132 | |
| 134 | 133 | // Load/store exclusive |
| 135 | 134 | // | size (2) 00 | 1000 | o2 L o1 | Rs (5) | o0 | Rt2 (5) | Rn (5) | Rt (5) | |
| 136 | 135 | // L == 0 for Stores. |
| 137 | static bool isLoadStoreExclusive(uint32_t Instr) { | |
| 138 | return (Instr & 0x3f000000) == 0x08000000; | |
| 136 | static bool isLoadStoreExclusive(uint32_t instr) { | |
| 137 | return (instr & 0x3f000000) == 0x08000000; | |
| 139 | 138 | } |
| 140 | 139 | |
| 141 | static bool isLoadExclusive(uint32_t Instr) { | |
| 142 | return (Instr & 0x3f400000) == 0x08400000; | |
| 140 | static bool isLoadExclusive(uint32_t instr) { | |
| 141 | return (instr & 0x3f400000) == 0x08400000; | |
| 143 | 142 | } |
| 144 | 143 | |
| 145 | 144 | // Load register literal |
| 146 | 145 | // | opc (2) 01 | 1 V 00 | imm19 | Rt (5) | |
| 147 | static bool isLoadLiteral(uint32_t Instr) { | |
| 148 | return (Instr & 0x3b000000) == 0x18000000; | |
| 146 | static bool isLoadLiteral(uint32_t instr) { | |
| 147 | return (instr & 0x3b000000) == 0x18000000; | |
| 149 | 148 | } |
| 150 | 149 | |
| 151 | 150 | // Load/store no-allocate pair |
| ... | ... | @@ -153,8 +152,8 @@ static bool isLoadLiteral(uint32_t Instr) { |
| 153 | 152 | // | opc (2) 10 | 1 V 00 | 0 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | |
| 154 | 153 | // L == 0 for stores. |
| 155 | 154 | // Never writes to register |
| 156 | static bool isSTNP(uint32_t Instr) { | |
| 157 | return (Instr & 0x3bc00000) == 0x28000000; | |
| 155 | static bool isSTNP(uint32_t instr) { | |
| 156 | return (instr & 0x3bc00000) == 0x28000000; | |
| 158 | 157 | } |
| 159 | 158 | |
| 160 | 159 | // Load/store register pair |
| ... | ... | @@ -162,69 +161,69 @@ static bool isSTNP(uint32_t Instr) { |
| 162 | 161 | // | opc (2) 10 | 1 V 00 | 1 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | |
| 163 | 162 | // L == 0 for stores, V == 0 for Scalar, V == 1 for Simd/FP |
| 164 | 163 | // Writes to Rn. |
| 165 | static bool isSTPPost(uint32_t Instr) { | |
| 166 | return (Instr & 0x3bc00000) == 0x28800000; | |
| 164 | static bool isSTPPost(uint32_t instr) { | |
| 165 | return (instr & 0x3bc00000) == 0x28800000; | |
| 167 | 166 | } |
| 168 | 167 | |
| 169 | 168 | // (offset) |
| 170 | 169 | // | opc (2) 10 | 1 V 01 | 0 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | |
| 171 | static bool isSTPOffset(uint32_t Instr) { | |
| 172 | return (Instr & 0x3bc00000) == 0x29000000; | |
| 170 | static bool isSTPOffset(uint32_t instr) { | |
| 171 | return (instr & 0x3bc00000) == 0x29000000; | |
| 173 | 172 | } |
| 174 | 173 | |
| 175 | 174 | // (pre-index) |
| 176 | 175 | // | opc (2) 10 | 1 V 01 | 1 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | |
| 177 | 176 | // Writes to Rn. |
| 178 | static bool isSTPPre(uint32_t Instr) { | |
| 179 | return (Instr & 0x3bc00000) == 0x29800000; | |
| 177 | static bool isSTPPre(uint32_t instr) { | |
| 178 | return (instr & 0x3bc00000) == 0x29800000; | |
| 180 | 179 | } |
| 181 | 180 | |
| 182 | static bool isSTP(uint32_t Instr) { | |
| 183 | return isSTPPost(Instr) || isSTPOffset(Instr) || isSTPPre(Instr); | |
| 181 | static bool isSTP(uint32_t instr) { | |
| 182 | return isSTPPost(instr) || isSTPOffset(instr) || isSTPPre(instr); | |
| 184 | 183 | } |
| 185 | 184 | |
| 186 | 185 | // Load/store register (unscaled immediate) |
| 187 | 186 | // | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 00 | Rn (5) | Rt (5) | |
| 188 | 187 | // V == 0 for Scalar, V == 1 for Simd/FP. |
| 189 | static bool isLoadStoreUnscaled(uint32_t Instr) { | |
| 190 | return (Instr & 0x3b000c00) == 0x38000000; | |
| 188 | static bool isLoadStoreUnscaled(uint32_t instr) { | |
| 189 | return (instr & 0x3b000c00) == 0x38000000; | |
| 191 | 190 | } |
| 192 | 191 | |
| 193 | 192 | // Load/store register (immediate post-indexed) |
| 194 | 193 | // | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 01 | Rn (5) | Rt (5) | |
| 195 | static bool isLoadStoreImmediatePost(uint32_t Instr) { | |
| 196 | return (Instr & 0x3b200c00) == 0x38000400; | |
| 194 | static bool isLoadStoreImmediatePost(uint32_t instr) { | |
| 195 | return (instr & 0x3b200c00) == 0x38000400; | |
| 197 | 196 | } |
| 198 | 197 | |
| 199 | 198 | // Load/store register (unprivileged) |
| 200 | 199 | // | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 10 | Rn (5) | Rt (5) | |
| 201 | static bool isLoadStoreUnpriv(uint32_t Instr) { | |
| 202 | return (Instr & 0x3b200c00) == 0x38000800; | |
| 200 | static bool isLoadStoreUnpriv(uint32_t instr) { | |
| 201 | return (instr & 0x3b200c00) == 0x38000800; | |
| 203 | 202 | } |
| 204 | 203 | |
| 205 | 204 | // Load/store register (immediate pre-indexed) |
| 206 | 205 | // | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 11 | Rn (5) | Rt (5) | |
| 207 | static bool isLoadStoreImmediatePre(uint32_t Instr) { | |
| 208 | return (Instr & 0x3b200c00) == 0x38000c00; | |
| 206 | static bool isLoadStoreImmediatePre(uint32_t instr) { | |
| 207 | return (instr & 0x3b200c00) == 0x38000c00; | |
| 209 | 208 | } |
| 210 | 209 | |
| 211 | 210 | // Load/store register (register offset) |
| 212 | 211 | // | size (2) 11 | 1 V 00 | opc (2) 1 | Rm (5) | option (3) S | 10 | Rn | Rt | |
| 213 | static bool isLoadStoreRegisterOff(uint32_t Instr) { | |
| 214 | return (Instr & 0x3b200c00) == 0x38200800; | |
| 212 | static bool isLoadStoreRegisterOff(uint32_t instr) { | |
| 213 | return (instr & 0x3b200c00) == 0x38200800; | |
| 215 | 214 | } |
| 216 | 215 | |
| 217 | 216 | // Load/store register (unsigned immediate) |
| 218 | 217 | // | size (2) 11 | 1 V 01 | opc (2) | imm12 | Rn (5) | Rt (5) | |
| 219 | static bool isLoadStoreRegisterUnsigned(uint32_t Instr) { | |
| 220 | return (Instr & 0x3b000000) == 0x39000000; | |
| 218 | static bool isLoadStoreRegisterUnsigned(uint32_t instr) { | |
| 219 | return (instr & 0x3b000000) == 0x39000000; | |
| 221 | 220 | } |
| 222 | 221 | |
| 223 | 222 | // Rt is always in bit position 0 - 4. |
| 224 | static uint32_t getRt(uint32_t Instr) { return (Instr & 0x1f); } | |
| 223 | static uint32_t getRt(uint32_t instr) { return (instr & 0x1f); } | |
| 225 | 224 | |
| 226 | 225 | // Rn is always in bit position 5 - 9. |
| 227 | static uint32_t getRn(uint32_t Instr) { return (Instr >> 5) & 0x1f; } | |
| 226 | static uint32_t getRn(uint32_t instr) { return (instr >> 5) & 0x1f; } | |
| 228 | 227 | |
| 229 | 228 | // C4.1.2 Branches, Exception Generating and System instructions |
| 230 | 229 | // | op0 (3) 1 | 01 op1 (4) | x (22) | |
| ... | ... | @@ -233,41 +232,41 @@ static uint32_t getRn(uint32_t Instr) { return (Instr >> 5) & 0x1f; } |
| 233 | 232 | // op0 == x00 101 op1 == xxxx Unconditional Branch immediate. |
| 234 | 233 | // op0 == x01 101 op1 == 0xxx Compare and branch immediate. |
| 235 | 234 | // op0 == x01 101 op1 == 1xxx Test and branch immediate. |
| 236 | static bool isBranch(uint32_t Instr) { | |
| 237 | return ((Instr & 0xfe000000) == 0xd6000000) || // Cond branch. | |
| 238 | ((Instr & 0xfe000000) == 0x54000000) || // Uncond branch reg. | |
| 239 | ((Instr & 0x7c000000) == 0x14000000) || // Uncond branch imm. | |
| 240 | ((Instr & 0x7c000000) == 0x34000000); // Compare and test branch. | |
| 235 | static bool isBranch(uint32_t instr) { | |
| 236 | return ((instr & 0xfe000000) == 0xd6000000) || // Cond branch. | |
| 237 | ((instr & 0xfe000000) == 0x54000000) || // Uncond branch reg. | |
| 238 | ((instr & 0x7c000000) == 0x14000000) || // Uncond branch imm. | |
| 239 | ((instr & 0x7c000000) == 0x34000000); // Compare and test branch. | |
| 241 | 240 | } |
| 242 | 241 | |
| 243 | static bool isV8SingleRegisterNonStructureLoadStore(uint32_t Instr) { | |
| 244 | return isLoadStoreUnscaled(Instr) || isLoadStoreImmediatePost(Instr) || | |
| 245 | isLoadStoreUnpriv(Instr) || isLoadStoreImmediatePre(Instr) || | |
| 246 | isLoadStoreRegisterOff(Instr) || isLoadStoreRegisterUnsigned(Instr); | |
| 242 | static bool isV8SingleRegisterNonStructureLoadStore(uint32_t instr) { | |
| 243 | return isLoadStoreUnscaled(instr) || isLoadStoreImmediatePost(instr) || | |
| 244 | isLoadStoreUnpriv(instr) || isLoadStoreImmediatePre(instr) || | |
| 245 | isLoadStoreRegisterOff(instr) || isLoadStoreRegisterUnsigned(instr); | |
| 247 | 246 | } |
| 248 | 247 | |
| 249 | 248 | // Note that this function refers to v8.0 only and does not include the |
| 250 | 249 | // additional load and store instructions added for in later revisions of |
| 251 | 250 | // the architecture such as the Atomic memory operations introduced |
| 252 | 251 | // in v8.1. |
| 253 | static bool isV8NonStructureLoad(uint32_t Instr) { | |
| 254 | if (isLoadExclusive(Instr)) | |
| 252 | static bool isV8NonStructureLoad(uint32_t instr) { | |
| 253 | if (isLoadExclusive(instr)) | |
| 255 | 254 | return true; |
| 256 | if (isLoadLiteral(Instr)) | |
| 255 | if (isLoadLiteral(instr)) | |
| 257 | 256 | return true; |
| 258 | else if (isV8SingleRegisterNonStructureLoadStore(Instr)) { | |
| 257 | else if (isV8SingleRegisterNonStructureLoadStore(instr)) { | |
| 259 | 258 | // For Load and Store single register, Loads are derived from a |
| 260 | 259 | // combination of the Size, V and Opc fields. |
| 261 | uint32_t Size = (Instr >> 30) & 0xff; | |
| 262 | uint32_t V = (Instr >> 26) & 0x1; | |
| 263 | uint32_t Opc = (Instr >> 22) & 0x3; | |
| 260 | uint32_t size = (instr >> 30) & 0xff; | |
| 261 | uint32_t v = (instr >> 26) & 0x1; | |
| 262 | uint32_t opc = (instr >> 22) & 0x3; | |
| 264 | 263 | // For the load and store instructions that we are decoding. |
| 265 | 264 | // Opc == 0 are all stores. |
| 266 | 265 | // Opc == 1 with a couple of exceptions are loads. The exceptions are: |
| 267 | 266 | // Size == 00 (0), V == 1, Opc == 10 (2) which is a store and |
| 268 | 267 | // Size == 11 (3), V == 0, Opc == 10 (2) which is a prefetch. |
| 269 | return Opc != 0 && !(Size == 0 && V == 1 && Opc == 2) && | |
| 270 | !(Size == 3 && V == 0 && Opc == 2); | |
| 268 | return opc != 0 && !(size == 0 && v == 1 && opc == 2) && | |
| 269 | !(size == 3 && v == 0 && opc == 2); | |
| 271 | 270 | } |
| 272 | 271 | return false; |
| 273 | 272 | } |
| ... | ... | @@ -276,18 +275,18 @@ static bool isV8NonStructureLoad(uint32_t Instr) { |
| 276 | 275 | // needed for errata 843419. |
| 277 | 276 | |
| 278 | 277 | // Instruction with writeback updates the index register after the load/store. |
| 279 | static bool hasWriteback(uint32_t Instr) { | |
| 280 | return isLoadStoreImmediatePre(Instr) || isLoadStoreImmediatePost(Instr) || | |
| 281 | isSTPPre(Instr) || isSTPPost(Instr) || isST1SinglePost(Instr) || | |
| 282 | isST1MultiplePost(Instr); | |
| 278 | static bool hasWriteback(uint32_t instr) { | |
| 279 | return isLoadStoreImmediatePre(instr) || isLoadStoreImmediatePost(instr) || | |
| 280 | isSTPPre(instr) || isSTPPost(instr) || isST1SinglePost(instr) || | |
| 281 | isST1MultiplePost(instr); | |
| 283 | 282 | } |
| 284 | 283 | |
| 285 | 284 | // For the load and store class of instructions, a load can write to the |
| 286 | 285 | // destination register, a load and a store can write to the base register when |
| 287 | 286 | // the instruction has writeback. |
| 288 | static bool doesLoadStoreWriteToReg(uint32_t Instr, uint32_t Reg) { | |
| 289 | return (isV8NonStructureLoad(Instr) && getRt(Instr) == Reg) || | |
| 290 | (hasWriteback(Instr) && getRn(Instr) == Reg); | |
| 287 | static bool doesLoadStoreWriteToReg(uint32_t instr, uint32_t reg) { | |
| 288 | return (isV8NonStructureLoad(instr) && getRt(instr) == reg) || | |
| 289 | (hasWriteback(instr) && getRn(instr) == reg); | |
| 291 | 290 | } |
| 292 | 291 | |
| 293 | 292 | // Scanner for Cortex-A53 errata 843419 |
| ... | ... | @@ -319,18 +318,18 @@ static bool doesLoadStoreWriteToReg(uint32_t Instr, uint32_t Reg) { |
| 319 | 318 | // Return true if the Instruction sequence Adrp, Instr2, and Instr4 match |
| 320 | 319 | // the erratum sequence. The Adrp, Instr2 and Instr4 correspond to 1.), 2.), |
| 321 | 320 | // and 4.) in the Scanner for Cortex-A53 errata comment above. |
| 322 | static bool is843419ErratumSequence(uint32_t Instr1, uint32_t Instr2, | |
| 323 | uint32_t Instr4) { | |
| 324 | if (!isADRP(Instr1)) | |
| 321 | static bool is843419ErratumSequence(uint32_t instr1, uint32_t instr2, | |
| 322 | uint32_t instr4) { | |
| 323 | if (!isADRP(instr1)) | |
| 325 | 324 | return false; |
| 326 | 325 | |
| 327 | uint32_t Rn = getRt(Instr1); | |
| 328 | return isLoadStoreClass(Instr2) && | |
| 329 | (isLoadStoreExclusive(Instr2) || isLoadLiteral(Instr2) || | |
| 330 | isV8SingleRegisterNonStructureLoadStore(Instr2) || isSTP(Instr2) || | |
| 331 | isSTNP(Instr2) || isST1(Instr2)) && | |
| 332 | !doesLoadStoreWriteToReg(Instr2, Rn) && | |
| 333 | isLoadStoreRegisterUnsigned(Instr4) && getRn(Instr4) == Rn; | |
| 326 | uint32_t rn = getRt(instr1); | |
| 327 | return isLoadStoreClass(instr2) && | |
| 328 | (isLoadStoreExclusive(instr2) || isLoadLiteral(instr2) || | |
| 329 | isV8SingleRegisterNonStructureLoadStore(instr2) || isSTP(instr2) || | |
| 330 | isSTNP(instr2) || isST1(instr2)) && | |
| 331 | !doesLoadStoreWriteToReg(instr2, rn) && | |
| 332 | isLoadStoreRegisterUnsigned(instr4) && getRn(instr4) == rn; | |
| 334 | 333 | } |
| 335 | 334 | |
| 336 | 335 | // Scan the instruction sequence starting at Offset Off from the base of |
| ... | ... | @@ -339,143 +338,143 @@ static bool is843419ErratumSequence(uint32_t Instr1, uint32_t Instr2, |
| 339 | 338 | // instructions we've scanned. |
| 340 | 339 | // Return the offset of the load or store instruction in IS that we want to |
| 341 | 340 | // patch or 0 if no patch required. |
| 342 | static uint64_t scanCortexA53Errata843419(InputSection *IS, uint64_t &Off, | |
| 343 | uint64_t Limit) { | |
| 344 | uint64_t ISAddr = IS->getVA(0); | |
| 341 | static uint64_t scanCortexA53Errata843419(InputSection *isec, uint64_t &off, | |
| 342 | uint64_t limit) { | |
| 343 | uint64_t isecAddr = isec->getVA(0); | |
| 345 | 344 | |
| 346 | 345 | // Advance Off so that (ISAddr + Off) modulo 0x1000 is at least 0xff8. |
| 347 | uint64_t InitialPageOff = (ISAddr + Off) & 0xfff; | |
| 348 | if (InitialPageOff < 0xff8) | |
| 349 | Off += 0xff8 - InitialPageOff; | |
| 346 | uint64_t initialPageOff = (isecAddr + off) & 0xfff; | |
| 347 | if (initialPageOff < 0xff8) | |
| 348 | off += 0xff8 - initialPageOff; | |
| 350 | 349 | |
| 351 | bool OptionalAllowed = Limit - Off > 12; | |
| 352 | if (Off >= Limit || Limit - Off < 12) { | |
| 350 | bool optionalAllowed = limit - off > 12; | |
| 351 | if (off >= limit || limit - off < 12) { | |
| 353 | 352 | // Need at least 3 4-byte sized instructions to trigger erratum. |
| 354 | Off = Limit; | |
| 353 | off = limit; | |
| 355 | 354 | return 0; |
| 356 | 355 | } |
| 357 | 356 | |
| 358 | uint64_t PatchOff = 0; | |
| 359 | const uint8_t *Buf = IS->data().begin(); | |
| 360 | const ulittle32_t *InstBuf = reinterpret_cast<const ulittle32_t *>(Buf + Off); | |
| 361 | uint32_t Instr1 = *InstBuf++; | |
| 362 | uint32_t Instr2 = *InstBuf++; | |
| 363 | uint32_t Instr3 = *InstBuf++; | |
| 364 | if (is843419ErratumSequence(Instr1, Instr2, Instr3)) { | |
| 365 | PatchOff = Off + 8; | |
| 366 | } else if (OptionalAllowed && !isBranch(Instr3)) { | |
| 367 | uint32_t Instr4 = *InstBuf++; | |
| 368 | if (is843419ErratumSequence(Instr1, Instr2, Instr4)) | |
| 369 | PatchOff = Off + 12; | |
| 357 | uint64_t patchOff = 0; | |
| 358 | const uint8_t *buf = isec->data().begin(); | |
| 359 | const ulittle32_t *instBuf = reinterpret_cast<const ulittle32_t *>(buf + off); | |
| 360 | uint32_t instr1 = *instBuf++; | |
| 361 | uint32_t instr2 = *instBuf++; | |
| 362 | uint32_t instr3 = *instBuf++; | |
| 363 | if (is843419ErratumSequence(instr1, instr2, instr3)) { | |
| 364 | patchOff = off + 8; | |
| 365 | } else if (optionalAllowed && !isBranch(instr3)) { | |
| 366 | uint32_t instr4 = *instBuf++; | |
| 367 | if (is843419ErratumSequence(instr1, instr2, instr4)) | |
| 368 | patchOff = off + 12; | |
| 370 | 369 | } |
| 371 | if (((ISAddr + Off) & 0xfff) == 0xff8) | |
| 372 | Off += 4; | |
| 370 | if (((isecAddr + off) & 0xfff) == 0xff8) | |
| 371 | off += 4; | |
| 373 | 372 | else |
| 374 | Off += 0xffc; | |
| 375 | return PatchOff; | |
| 373 | off += 0xffc; | |
| 374 | return patchOff; | |
| 376 | 375 | } |
| 377 | 376 | |
| 378 | 377 | class lld::elf::Patch843419Section : public SyntheticSection { |
| 379 | 378 | public: |
| 380 | Patch843419Section(InputSection *P, uint64_t Off); | |
| 379 | Patch843419Section(InputSection *p, uint64_t off); | |
| 381 | 380 | |
| 382 | void writeTo(uint8_t *Buf) override; | |
| 381 | void writeTo(uint8_t *buf) override; | |
| 383 | 382 | |
| 384 | 383 | size_t getSize() const override { return 8; } |
| 385 | 384 | |
| 386 | 385 | uint64_t getLDSTAddr() const; |
| 387 | 386 | |
| 388 | 387 | // The Section we are patching. |
| 389 | const InputSection *Patchee; | |
| 388 | const InputSection *patchee; | |
| 390 | 389 | // The offset of the instruction in the Patchee section we are patching. |
| 391 | uint64_t PatcheeOffset; | |
| 390 | uint64_t patcheeOffset; | |
| 392 | 391 | // A label for the start of the Patch that we can use as a relocation target. |
| 393 | Symbol *PatchSym; | |
| 392 | Symbol *patchSym; | |
| 394 | 393 | }; |
| 395 | 394 | |
| 396 | lld::elf::Patch843419Section::Patch843419Section(InputSection *P, uint64_t Off) | |
| 395 | lld::elf::Patch843419Section::Patch843419Section(InputSection *p, uint64_t off) | |
| 397 | 396 | : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 4, |
| 398 | 397 | ".text.patch"), |
| 399 | Patchee(P), PatcheeOffset(Off) { | |
| 400 | this->Parent = P->getParent(); | |
| 401 | PatchSym = addSyntheticLocal( | |
| 402 | Saver.save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, 0, | |
| 398 | patchee(p), patcheeOffset(off) { | |
| 399 | this->parent = p->getParent(); | |
| 400 | patchSym = addSyntheticLocal( | |
| 401 | saver.save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, 0, | |
| 403 | 402 | getSize(), *this); |
| 404 | addSyntheticLocal(Saver.save("$x"), STT_NOTYPE, 0, 0, *this); | |
| 403 | addSyntheticLocal(saver.save("$x"), STT_NOTYPE, 0, 0, *this); | |
| 405 | 404 | } |
| 406 | 405 | |
| 407 | 406 | uint64_t lld::elf::Patch843419Section::getLDSTAddr() const { |
| 408 | return Patchee->getVA(PatcheeOffset); | |
| 407 | return patchee->getVA(patcheeOffset); | |
| 409 | 408 | } |
| 410 | 409 | |
| 411 | void lld::elf::Patch843419Section::writeTo(uint8_t *Buf) { | |
| 410 | void lld::elf::Patch843419Section::writeTo(uint8_t *buf) { | |
| 412 | 411 | // Copy the instruction that we will be replacing with a branch in the |
| 413 | 412 | // Patchee Section. |
| 414 | write32le(Buf, read32le(Patchee->data().begin() + PatcheeOffset)); | |
| 413 | write32le(buf, read32le(patchee->data().begin() + patcheeOffset)); | |
| 415 | 414 | |
| 416 | 415 | // Apply any relocation transferred from the original PatcheeSection. |
| 417 | // For a SyntheticSection Buf already has OutSecOff added, but relocateAlloc | |
| 418 | // also adds OutSecOff so we need to subtract to avoid double counting. | |
| 419 | this->relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + getSize()); | |
| 416 | // For a SyntheticSection Buf already has outSecOff added, but relocateAlloc | |
| 417 | // also adds outSecOff so we need to subtract to avoid double counting. | |
| 418 | this->relocateAlloc(buf - outSecOff, buf - outSecOff + getSize()); | |
| 420 | 419 | |
| 421 | 420 | // Return address is the next instruction after the one we have just copied. |
| 422 | uint64_t S = getLDSTAddr() + 4; | |
| 423 | uint64_t P = PatchSym->getVA() + 4; | |
| 424 | Target->relocateOne(Buf + 4, R_AARCH64_JUMP26, S - P); | |
| 421 | uint64_t s = getLDSTAddr() + 4; | |
| 422 | uint64_t p = patchSym->getVA() + 4; | |
| 423 | target->relocateOne(buf + 4, R_AARCH64_JUMP26, s - p); | |
| 425 | 424 | } |
| 426 | 425 | |
| 427 | 426 | void AArch64Err843419Patcher::init() { |
| 428 | 427 | // The AArch64 ABI permits data in executable sections. We must avoid scanning |
| 429 | 428 | // this data as if it were instructions to avoid false matches. We use the |
| 430 | 429 | // mapping symbols in the InputObjects to identify this data, caching the |
| 431 | // results in SectionMap so we don't have to recalculate it each pass. | |
| 430 | // results in sectionMap so we don't have to recalculate it each pass. | |
| 432 | 431 | |
| 433 | 432 | // The ABI Section 4.5.4 Mapping symbols; defines local symbols that describe |
| 434 | 433 | // half open intervals [Symbol Value, Next Symbol Value) of code and data |
| 435 | 434 | // within sections. If there is no next symbol then the half open interval is |
| 436 | 435 | // [Symbol Value, End of section). The type, code or data, is determined by |
| 437 | 436 | // the mapping symbol name, $x for code, $d for data. |
| 438 | auto IsCodeMapSymbol = [](const Symbol *B) { | |
| 439 | return B->getName() == "$x" || B->getName().startswith("$x."); | |
| 437 | auto isCodeMapSymbol = [](const Symbol *b) { | |
| 438 | return b->getName() == "$x" || b->getName().startswith("$x."); | |
| 440 | 439 | }; |
| 441 | auto IsDataMapSymbol = [](const Symbol *B) { | |
| 442 | return B->getName() == "$d" || B->getName().startswith("$d."); | |
| 440 | auto isDataMapSymbol = [](const Symbol *b) { | |
| 441 | return b->getName() == "$d" || b->getName().startswith("$d."); | |
| 443 | 442 | }; |
| 444 | 443 | |
| 445 | 444 | // Collect mapping symbols for every executable InputSection. |
| 446 | for (InputFile *File : ObjectFiles) { | |
| 447 | auto *F = cast<ObjFile<ELF64LE>>(File); | |
| 448 | for (Symbol *B : F->getLocalSymbols()) { | |
| 449 | auto *Def = dyn_cast<Defined>(B); | |
| 450 | if (!Def) | |
| 445 | for (InputFile *file : objectFiles) { | |
| 446 | auto *f = cast<ObjFile<ELF64LE>>(file); | |
| 447 | for (Symbol *b : f->getLocalSymbols()) { | |
| 448 | auto *def = dyn_cast<Defined>(b); | |
| 449 | if (!def) | |
| 451 | 450 | continue; |
| 452 | if (!IsCodeMapSymbol(Def) && !IsDataMapSymbol(Def)) | |
| 451 | if (!isCodeMapSymbol(def) && !isDataMapSymbol(def)) | |
| 453 | 452 | continue; |
| 454 | if (auto *Sec = dyn_cast_or_null<InputSection>(Def->Section)) | |
| 455 | if (Sec->Flags & SHF_EXECINSTR) | |
| 456 | SectionMap[Sec].push_back(Def); | |
| 453 | if (auto *sec = dyn_cast_or_null<InputSection>(def->section)) | |
| 454 | if (sec->flags & SHF_EXECINSTR) | |
| 455 | sectionMap[sec].push_back(def); | |
| 457 | 456 | } |
| 458 | 457 | } |
| 459 | 458 | // For each InputSection make sure the mapping symbols are in sorted in |
| 460 | 459 | // ascending order and free from consecutive runs of mapping symbols with |
| 461 | 460 | // the same type. For example we must remove the redundant $d.1 from $x.0 |
| 462 | 461 | // $d.0 $d.1 $x.1. |
| 463 | for (auto &KV : SectionMap) { | |
| 464 | std::vector<const Defined *> &MapSyms = KV.second; | |
| 465 | if (MapSyms.size() <= 1) | |
| 462 | for (auto &kv : sectionMap) { | |
| 463 | std::vector<const Defined *> &mapSyms = kv.second; | |
| 464 | if (mapSyms.size() <= 1) | |
| 466 | 465 | continue; |
| 467 | std::stable_sort( | |
| 468 | MapSyms.begin(), MapSyms.end(), | |
| 469 | [](const Defined *A, const Defined *B) { return A->Value < B->Value; }); | |
| 470 | MapSyms.erase( | |
| 471 | std::unique(MapSyms.begin(), MapSyms.end(), | |
| 472 | [=](const Defined *A, const Defined *B) { | |
| 473 | return (IsCodeMapSymbol(A) && IsCodeMapSymbol(B)) || | |
| 474 | (IsDataMapSymbol(A) && IsDataMapSymbol(B)); | |
| 466 | llvm::stable_sort(mapSyms, [](const Defined *a, const Defined *b) { | |
| 467 | return a->value < b->value; | |
| 468 | }); | |
| 469 | mapSyms.erase( | |
| 470 | std::unique(mapSyms.begin(), mapSyms.end(), | |
| 471 | [=](const Defined *a, const Defined *b) { | |
| 472 | return (isCodeMapSymbol(a) && isCodeMapSymbol(b)) || | |
| 473 | (isDataMapSymbol(a) && isDataMapSymbol(b)); | |
| 475 | 474 | }), |
| 476 | MapSyms.end()); | |
| 475 | mapSyms.end()); | |
| 477 | 476 | } |
| 478 | Initialized = true; | |
| 477 | initialized = true; | |
| 479 | 478 | } |
| 480 | 479 | |
| 481 | 480 | // Insert the PatchSections we have created back into the |
| ... | ... | @@ -484,60 +483,60 @@ void AArch64Err843419Patcher::init() { |
| 484 | 483 | // executable sections, although we may need to insert them earlier if the |
| 485 | 484 | // InputSectionDescription is larger than the maximum branch range. |
| 486 | 485 | void AArch64Err843419Patcher::insertPatches( |
| 487 | InputSectionDescription &ISD, std::vector<Patch843419Section *> &Patches) { | |
| 488 | uint64_t ISLimit; | |
| 489 | uint64_t PrevISLimit = ISD.Sections.front()->OutSecOff; | |
| 490 | uint64_t PatchUpperBound = PrevISLimit + Target->getThunkSectionSpacing(); | |
| 491 | uint64_t OutSecAddr = ISD.Sections.front()->getParent()->Addr; | |
| 486 | InputSectionDescription &isd, std::vector<Patch843419Section *> &patches) { | |
| 487 | uint64_t isecLimit; | |
| 488 | uint64_t prevIsecLimit = isd.sections.front()->outSecOff; | |
| 489 | uint64_t patchUpperBound = prevIsecLimit + target->getThunkSectionSpacing(); | |
| 490 | uint64_t outSecAddr = isd.sections.front()->getParent()->addr; | |
| 492 | 491 | |
| 493 | // Set the OutSecOff of patches to the place where we want to insert them. | |
| 492 | // Set the outSecOff of patches to the place where we want to insert them. | |
| 494 | 493 | // We use a similar strategy to Thunk placement. Place patches roughly |
| 495 | 494 | // every multiple of maximum branch range. |
| 496 | auto PatchIt = Patches.begin(); | |
| 497 | auto PatchEnd = Patches.end(); | |
| 498 | for (const InputSection *IS : ISD.Sections) { | |
| 499 | ISLimit = IS->OutSecOff + IS->getSize(); | |
| 500 | if (ISLimit > PatchUpperBound) { | |
| 501 | while (PatchIt != PatchEnd) { | |
| 502 | if ((*PatchIt)->getLDSTAddr() - OutSecAddr >= PrevISLimit) | |
| 495 | auto patchIt = patches.begin(); | |
| 496 | auto patchEnd = patches.end(); | |
| 497 | for (const InputSection *isec : isd.sections) { | |
| 498 | isecLimit = isec->outSecOff + isec->getSize(); | |
| 499 | if (isecLimit > patchUpperBound) { | |
| 500 | while (patchIt != patchEnd) { | |
| 501 | if ((*patchIt)->getLDSTAddr() - outSecAddr >= prevIsecLimit) | |
| 503 | 502 | break; |
| 504 | (*PatchIt)->OutSecOff = PrevISLimit; | |
| 505 | ++PatchIt; | |
| 503 | (*patchIt)->outSecOff = prevIsecLimit; | |
| 504 | ++patchIt; | |
| 506 | 505 | } |
| 507 | PatchUpperBound = PrevISLimit + Target->getThunkSectionSpacing(); | |
| 506 | patchUpperBound = prevIsecLimit + target->getThunkSectionSpacing(); | |
| 508 | 507 | } |
| 509 | PrevISLimit = ISLimit; | |
| 508 | prevIsecLimit = isecLimit; | |
| 510 | 509 | } |
| 511 | for (; PatchIt != PatchEnd; ++PatchIt) { | |
| 512 | (*PatchIt)->OutSecOff = ISLimit; | |
| 510 | for (; patchIt != patchEnd; ++patchIt) { | |
| 511 | (*patchIt)->outSecOff = isecLimit; | |
| 513 | 512 | } |
| 514 | 513 | |
| 515 | // merge all patch sections. We use the OutSecOff assigned above to | |
| 514 | // merge all patch sections. We use the outSecOff assigned above to | |
| 516 | 515 | // determine the insertion point. This is ok as we only merge into an |
| 517 | 516 | // InputSectionDescription once per pass, and at the end of the pass |
| 518 | // assignAddresses() will recalculate all the OutSecOff values. | |
| 519 | std::vector<InputSection *> Tmp; | |
| 520 | Tmp.reserve(ISD.Sections.size() + Patches.size()); | |
| 521 | auto MergeCmp = [](const InputSection *A, const InputSection *B) { | |
| 522 | if (A->OutSecOff < B->OutSecOff) | |
| 517 | // assignAddresses() will recalculate all the outSecOff values. | |
| 518 | std::vector<InputSection *> tmp; | |
| 519 | tmp.reserve(isd.sections.size() + patches.size()); | |
| 520 | auto mergeCmp = [](const InputSection *a, const InputSection *b) { | |
| 521 | if (a->outSecOff < b->outSecOff) | |
| 523 | 522 | return true; |
| 524 | if (A->OutSecOff == B->OutSecOff && isa<Patch843419Section>(A) && | |
| 525 | !isa<Patch843419Section>(B)) | |
| 523 | if (a->outSecOff == b->outSecOff && isa<Patch843419Section>(a) && | |
| 524 | !isa<Patch843419Section>(b)) | |
| 526 | 525 | return true; |
| 527 | 526 | return false; |
| 528 | 527 | }; |
| 529 | std::merge(ISD.Sections.begin(), ISD.Sections.end(), Patches.begin(), | |
| 530 | Patches.end(), std::back_inserter(Tmp), MergeCmp); | |
| 531 | ISD.Sections = std::move(Tmp); | |
| 528 | std::merge(isd.sections.begin(), isd.sections.end(), patches.begin(), | |
| 529 | patches.end(), std::back_inserter(tmp), mergeCmp); | |
| 530 | isd.sections = std::move(tmp); | |
| 532 | 531 | } |
| 533 | 532 | |
| 534 | // Given an erratum sequence that starts at address AdrpAddr, with an | |
| 535 | // instruction that we need to patch at PatcheeOffset from the start of | |
| 533 | // Given an erratum sequence that starts at address adrpAddr, with an | |
| 534 | // instruction that we need to patch at patcheeOffset from the start of | |
| 536 | 535 | // InputSection IS, create a Patch843419 Section and add it to the |
| 537 | 536 | // Patches that we need to insert. |
| 538 | static void implementPatch(uint64_t AdrpAddr, uint64_t PatcheeOffset, | |
| 539 | InputSection *IS, | |
| 540 | std::vector<Patch843419Section *> &Patches) { | |
| 537 | static void implementPatch(uint64_t adrpAddr, uint64_t patcheeOffset, | |
| 538 | InputSection *isec, | |
| 539 | std::vector<Patch843419Section *> &patches) { | |
| 541 | 540 | // There may be a relocation at the same offset that we are patching. There |
| 542 | 541 | // are four cases that we need to consider. |
| 543 | 542 | // Case 1: R_AARCH64_JUMP26 branch relocation. We have already patched this |
| ... | ... | @@ -552,29 +551,29 @@ static void implementPatch(uint64_t AdrpAddr, uint64_t PatcheeOffset, |
| 552 | 551 | // and replace the relocation with a R_AARCH_JUMP26 branch relocation. |
| 553 | 552 | // Case 4: No relocation. We must create a new R_AARCH64_JUMP26 branch |
| 554 | 553 | // relocation at the offset. |
| 555 | auto RelIt = std::find_if( | |
| 556 | IS->Relocations.begin(), IS->Relocations.end(), | |
| 557 | [=](const Relocation &R) { return R.Offset == PatcheeOffset; }); | |
| 558 | if (RelIt != IS->Relocations.end() && | |
| 559 | (RelIt->Type == R_AARCH64_JUMP26 || RelIt->Expr == R_RELAX_TLS_IE_TO_LE)) | |
| 554 | auto relIt = llvm::find_if(isec->relocations, [=](const Relocation &r) { | |
| 555 | return r.offset == patcheeOffset; | |
| 556 | }); | |
| 557 | if (relIt != isec->relocations.end() && | |
| 558 | (relIt->type == R_AARCH64_JUMP26 || relIt->expr == R_RELAX_TLS_IE_TO_LE)) | |
| 560 | 559 | return; |
| 561 | 560 | |
| 562 | 561 | log("detected cortex-a53-843419 erratum sequence starting at " + |
| 563 | utohexstr(AdrpAddr) + " in unpatched output."); | |
| 562 | utohexstr(adrpAddr) + " in unpatched output."); | |
| 564 | 563 | |
| 565 | auto *PS = make<Patch843419Section>(IS, PatcheeOffset); | |
| 566 | Patches.push_back(PS); | |
| 564 | auto *ps = make<Patch843419Section>(isec, patcheeOffset); | |
| 565 | patches.push_back(ps); | |
| 567 | 566 | |
| 568 | auto MakeRelToPatch = [](uint64_t Offset, Symbol *PatchSym) { | |
| 569 | return Relocation{R_PC, R_AARCH64_JUMP26, Offset, 0, PatchSym}; | |
| 567 | auto makeRelToPatch = [](uint64_t offset, Symbol *patchSym) { | |
| 568 | return Relocation{R_PC, R_AARCH64_JUMP26, offset, 0, patchSym}; | |
| 570 | 569 | }; |
| 571 | 570 | |
| 572 | if (RelIt != IS->Relocations.end()) { | |
| 573 | PS->Relocations.push_back( | |
| 574 | {RelIt->Expr, RelIt->Type, 0, RelIt->Addend, RelIt->Sym}); | |
| 575 | *RelIt = MakeRelToPatch(PatcheeOffset, PS->PatchSym); | |
| 571 | if (relIt != isec->relocations.end()) { | |
| 572 | ps->relocations.push_back( | |
| 573 | {relIt->expr, relIt->type, 0, relIt->addend, relIt->sym}); | |
| 574 | *relIt = makeRelToPatch(patcheeOffset, ps->patchSym); | |
| 576 | 575 | } else |
| 577 | IS->Relocations.push_back(MakeRelToPatch(PatcheeOffset, PS->PatchSym)); | |
| 576 | isec->relocations.push_back(makeRelToPatch(patcheeOffset, ps->patchSym)); | |
| 578 | 577 | } |
| 579 | 578 | |
| 580 | 579 | // Scan all the instructions in InputSectionDescription, for each instance of |
| ... | ... | @@ -582,40 +581,40 @@ static void implementPatch(uint64_t AdrpAddr, uint64_t PatcheeOffset, |
| 582 | 581 | // Patch843419Sections that need to be applied to ISD. |
| 583 | 582 | std::vector<Patch843419Section *> |
| 584 | 583 | AArch64Err843419Patcher::patchInputSectionDescription( |
| 585 | InputSectionDescription &ISD) { | |
| 586 | std::vector<Patch843419Section *> Patches; | |
| 587 | for (InputSection *IS : ISD.Sections) { | |
| 584 | InputSectionDescription &isd) { | |
| 585 | std::vector<Patch843419Section *> patches; | |
| 586 | for (InputSection *isec : isd.sections) { | |
| 588 | 587 | // LLD doesn't use the erratum sequence in SyntheticSections. |
| 589 | if (isa<SyntheticSection>(IS)) | |
| 588 | if (isa<SyntheticSection>(isec)) | |
| 590 | 589 | continue; |
| 591 | // Use SectionMap to make sure we only scan code and not inline data. | |
| 590 | // Use sectionMap to make sure we only scan code and not inline data. | |
| 592 | 591 | // We have already sorted MapSyms in ascending order and removed consecutive |
| 593 | 592 | // mapping symbols of the same type. Our range of executable instructions to |
| 594 | // scan is therefore [CodeSym->Value, DataSym->Value) or [CodeSym->Value, | |
| 593 | // scan is therefore [codeSym->value, dataSym->value) or [codeSym->value, | |
| 595 | 594 | // section size). |
| 596 | std::vector<const Defined *> &MapSyms = SectionMap[IS]; | |
| 595 | std::vector<const Defined *> &mapSyms = sectionMap[isec]; | |
| 597 | 596 | |
| 598 | auto CodeSym = llvm::find_if(MapSyms, [&](const Defined *MS) { | |
| 599 | return MS->getName().startswith("$x"); | |
| 597 | auto codeSym = llvm::find_if(mapSyms, [&](const Defined *ms) { | |
| 598 | return ms->getName().startswith("$x"); | |
| 600 | 599 | }); |
| 601 | 600 | |
| 602 | while (CodeSym != MapSyms.end()) { | |
| 603 | auto DataSym = std::next(CodeSym); | |
| 604 | uint64_t Off = (*CodeSym)->Value; | |
| 605 | uint64_t Limit = | |
| 606 | (DataSym == MapSyms.end()) ? IS->data().size() : (*DataSym)->Value; | |
| 601 | while (codeSym != mapSyms.end()) { | |
| 602 | auto dataSym = std::next(codeSym); | |
| 603 | uint64_t off = (*codeSym)->value; | |
| 604 | uint64_t limit = | |
| 605 | (dataSym == mapSyms.end()) ? isec->data().size() : (*dataSym)->value; | |
| 607 | 606 | |
| 608 | while (Off < Limit) { | |
| 609 | uint64_t StartAddr = IS->getVA(Off); | |
| 610 | if (uint64_t PatcheeOffset = scanCortexA53Errata843419(IS, Off, Limit)) | |
| 611 | implementPatch(StartAddr, PatcheeOffset, IS, Patches); | |
| 607 | while (off < limit) { | |
| 608 | uint64_t startAddr = isec->getVA(off); | |
| 609 | if (uint64_t patcheeOffset = scanCortexA53Errata843419(isec, off, limit)) | |
| 610 | implementPatch(startAddr, patcheeOffset, isec, patches); | |
| 612 | 611 | } |
| 613 | if (DataSym == MapSyms.end()) | |
| 612 | if (dataSym == mapSyms.end()) | |
| 614 | 613 | break; |
| 615 | CodeSym = std::next(DataSym); | |
| 614 | codeSym = std::next(dataSym); | |
| 616 | 615 | } |
| 617 | 616 | } |
| 618 | return Patches; | |
| 617 | return patches; | |
| 619 | 618 | } |
| 620 | 619 | |
| 621 | 620 | // For each InputSectionDescription make one pass over the executable sections |
| ... | ... | @@ -631,22 +630,22 @@ AArch64Err843419Patcher::patchInputSectionDescription( |
| 631 | 630 | // Ouptut and Input Sections may have been changed. |
| 632 | 631 | // Returns false if no patches were required and no changes were made. |
| 633 | 632 | bool AArch64Err843419Patcher::createFixes() { |
| 634 | if (Initialized == false) | |
| 633 | if (initialized == false) | |
| 635 | 634 | init(); |
| 636 | 635 | |
| 637 | bool AddressesChanged = false; | |
| 638 | for (OutputSection *OS : OutputSections) { | |
| 639 | if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR)) | |
| 636 | bool addressesChanged = false; | |
| 637 | for (OutputSection *os : outputSections) { | |
| 638 | if (!(os->flags & SHF_ALLOC) || !(os->flags & SHF_EXECINSTR)) | |
| 640 | 639 | continue; |
| 641 | for (BaseCommand *BC : OS->SectionCommands) | |
| 642 | if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) { | |
| 643 | std::vector<Patch843419Section *> Patches = | |
| 644 | patchInputSectionDescription(*ISD); | |
| 645 | if (!Patches.empty()) { | |
| 646 | insertPatches(*ISD, Patches); | |
| 647 | AddressesChanged = true; | |
| 640 | for (BaseCommand *bc : os->sectionCommands) | |
| 641 | if (auto *isd = dyn_cast<InputSectionDescription>(bc)) { | |
| 642 | std::vector<Patch843419Section *> patches = | |
| 643 | patchInputSectionDescription(*isd); | |
| 644 | if (!patches.empty()) { | |
| 645 | insertPatches(*isd, patches); | |
| 646 | addressesChanged = true; | |
| 648 | 647 | } |
| 649 | 648 | } |
| 650 | 649 | } |
| 651 | return AddressesChanged; | |
| 650 | return addressesChanged; | |
| 652 | 651 | } |
deps/lld/ELF/AArch64ErrataFix.h+9-10| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- AArch64ErrataFix.h ---------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -30,19 +29,19 @@ public: |
| 30 | 29 | |
| 31 | 30 | private: |
| 32 | 31 | std::vector<Patch843419Section *> |
| 33 | patchInputSectionDescription(InputSectionDescription &ISD); | |
| 32 | patchInputSectionDescription(InputSectionDescription &isd); | |
| 34 | 33 | |
| 35 | void insertPatches(InputSectionDescription &ISD, | |
| 36 | std::vector<Patch843419Section *> &Patches); | |
| 34 | void insertPatches(InputSectionDescription &isd, | |
| 35 | std::vector<Patch843419Section *> &patches); | |
| 37 | 36 | |
| 38 | 37 | void init(); |
| 39 | 38 | |
| 40 | // A cache of the mapping symbols defined by the InputSecion sorted in order | |
| 39 | // A cache of the mapping symbols defined by the InputSection sorted in order | |
| 41 | 40 | // of ascending value with redundant symbols removed. These describe |
| 42 | 41 | // the ranges of code and data in an executable InputSection. |
| 43 | std::map<InputSection *, std::vector<const Defined *>> SectionMap; | |
| 42 | std::map<InputSection *, std::vector<const Defined *>> sectionMap; | |
| 44 | 43 | |
| 45 | bool Initialized = false; | |
| 44 | bool initialized = false; | |
| 46 | 45 | }; |
| 47 | 46 | |
| 48 | 47 | } // namespace elf |
deps/lld/ELF/Arch/AArch64.cpp+308-158| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- AArch64.cpp --------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -24,60 +23,59 @@ using namespace lld::elf; |
| 24 | 23 | // Page(Expr) is the page address of the expression Expr, defined |
| 25 | 24 | // as (Expr & ~0xFFF). (This applies even if the machine page size |
| 26 | 25 | // supported by the platform has a different value.) |
| 27 | uint64_t elf::getAArch64Page(uint64_t Expr) { | |
| 28 | return Expr & ~static_cast<uint64_t>(0xFFF); | |
| 26 | uint64_t elf::getAArch64Page(uint64_t expr) { | |
| 27 | return expr & ~static_cast<uint64_t>(0xFFF); | |
| 29 | 28 | } |
| 30 | 29 | |
| 31 | 30 | namespace { |
| 32 | class AArch64 final : public TargetInfo { | |
| 31 | class AArch64 : public TargetInfo { | |
| 33 | 32 | public: |
| 34 | 33 | AArch64(); |
| 35 | RelExpr getRelExpr(RelType Type, const Symbol &S, | |
| 36 | const uint8_t *Loc) const override; | |
| 37 | RelType getDynRel(RelType Type) const override; | |
| 38 | void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; | |
| 39 | void writePltHeader(uint8_t *Buf) const override; | |
| 40 | void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, | |
| 41 | int32_t Index, unsigned RelOff) const override; | |
| 42 | bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, | |
| 43 | uint64_t BranchAddr, const Symbol &S) const override; | |
| 34 | RelExpr getRelExpr(RelType type, const Symbol &s, | |
| 35 | const uint8_t *loc) const override; | |
| 36 | RelType getDynRel(RelType type) const override; | |
| 37 | void writeGotPlt(uint8_t *buf, const Symbol &s) const override; | |
| 38 | void writePltHeader(uint8_t *buf) const override; | |
| 39 | void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, | |
| 40 | int32_t index, unsigned relOff) const override; | |
| 41 | bool needsThunk(RelExpr expr, RelType type, const InputFile *file, | |
| 42 | uint64_t branchAddr, const Symbol &s) const override; | |
| 44 | 43 | uint32_t getThunkSectionSpacing() const override; |
| 45 | bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; | |
| 46 | bool usesOnlyLowPageBits(RelType Type) const override; | |
| 47 | void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 48 | RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, | |
| 49 | RelExpr Expr) const override; | |
| 50 | void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 51 | void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 52 | void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 44 | bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; | |
| 45 | bool usesOnlyLowPageBits(RelType type) const override; | |
| 46 | void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 47 | RelExpr adjustRelaxExpr(RelType type, const uint8_t *data, | |
| 48 | RelExpr expr) const override; | |
| 49 | void relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 50 | void relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 51 | void relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 53 | 52 | }; |
| 54 | 53 | } // namespace |
| 55 | 54 | |
| 56 | 55 | AArch64::AArch64() { |
| 57 | CopyRel = R_AARCH64_COPY; | |
| 58 | RelativeRel = R_AARCH64_RELATIVE; | |
| 59 | IRelativeRel = R_AARCH64_IRELATIVE; | |
| 60 | GotRel = R_AARCH64_GLOB_DAT; | |
| 61 | NoneRel = R_AARCH64_NONE; | |
| 62 | PltRel = R_AARCH64_JUMP_SLOT; | |
| 63 | TlsDescRel = R_AARCH64_TLSDESC; | |
| 64 | TlsGotRel = R_AARCH64_TLS_TPREL64; | |
| 65 | GotEntrySize = 8; | |
| 66 | GotPltEntrySize = 8; | |
| 67 | PltEntrySize = 16; | |
| 68 | PltHeaderSize = 32; | |
| 69 | DefaultMaxPageSize = 65536; | |
| 56 | copyRel = R_AARCH64_COPY; | |
| 57 | relativeRel = R_AARCH64_RELATIVE; | |
| 58 | iRelativeRel = R_AARCH64_IRELATIVE; | |
| 59 | gotRel = R_AARCH64_GLOB_DAT; | |
| 60 | noneRel = R_AARCH64_NONE; | |
| 61 | pltRel = R_AARCH64_JUMP_SLOT; | |
| 62 | symbolicRel = R_AARCH64_ABS64; | |
| 63 | tlsDescRel = R_AARCH64_TLSDESC; | |
| 64 | tlsGotRel = R_AARCH64_TLS_TPREL64; | |
| 65 | pltEntrySize = 16; | |
| 66 | pltHeaderSize = 32; | |
| 67 | defaultMaxPageSize = 65536; | |
| 70 | 68 | |
| 71 | 69 | // Align to the 2 MiB page size (known as a superpage or huge page). |
| 72 | 70 | // FreeBSD automatically promotes 2 MiB-aligned allocations. |
| 73 | DefaultImageBase = 0x200000; | |
| 71 | defaultImageBase = 0x200000; | |
| 74 | 72 | |
| 75 | NeedsThunks = true; | |
| 73 | needsThunks = true; | |
| 76 | 74 | } |
| 77 | 75 | |
| 78 | RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S, | |
| 79 | const uint8_t *Loc) const { | |
| 80 | switch (Type) { | |
| 76 | RelExpr AArch64::getRelExpr(RelType type, const Symbol &s, | |
| 77 | const uint8_t *loc) const { | |
| 78 | switch (type) { | |
| 81 | 79 | case R_AARCH64_TLSDESC_ADR_PAGE21: |
| 82 | 80 | return R_AARCH64_TLSDESC_PAGE; |
| 83 | 81 | case R_AARCH64_TLSDESC_LD64_LO12: |
| ... | ... | @@ -105,6 +103,7 @@ RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S, |
| 105 | 103 | case R_AARCH64_LD_PREL_LO19: |
| 106 | 104 | return R_PC; |
| 107 | 105 | case R_AARCH64_ADR_PREL_PG_HI21: |
| 106 | case R_AARCH64_ADR_PREL_PG_HI21_NC: | |
| 108 | 107 | return R_AARCH64_PAGE_PC; |
| 109 | 108 | case R_AARCH64_LD64_GOT_LO12_NC: |
| 110 | 109 | case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: |
| ... | ... | @@ -119,18 +118,18 @@ RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S, |
| 119 | 118 | } |
| 120 | 119 | } |
| 121 | 120 | |
| 122 | RelExpr AArch64::adjustRelaxExpr(RelType Type, const uint8_t *Data, | |
| 123 | RelExpr Expr) const { | |
| 124 | if (Expr == R_RELAX_TLS_GD_TO_IE) { | |
| 125 | if (Type == R_AARCH64_TLSDESC_ADR_PAGE21) | |
| 121 | RelExpr AArch64::adjustRelaxExpr(RelType type, const uint8_t *data, | |
| 122 | RelExpr expr) const { | |
| 123 | if (expr == R_RELAX_TLS_GD_TO_IE) { | |
| 124 | if (type == R_AARCH64_TLSDESC_ADR_PAGE21) | |
| 126 | 125 | return R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC; |
| 127 | 126 | return R_RELAX_TLS_GD_TO_IE_ABS; |
| 128 | 127 | } |
| 129 | return Expr; | |
| 128 | return expr; | |
| 130 | 129 | } |
| 131 | 130 | |
| 132 | bool AArch64::usesOnlyLowPageBits(RelType Type) const { | |
| 133 | switch (Type) { | |
| 131 | bool AArch64::usesOnlyLowPageBits(RelType type) const { | |
| 132 | switch (type) { | |
| 134 | 133 | default: |
| 135 | 134 | return false; |
| 136 | 135 | case R_AARCH64_ADD_ABS_LO12_NC: |
| ... | ... | @@ -147,18 +146,18 @@ bool AArch64::usesOnlyLowPageBits(RelType Type) const { |
| 147 | 146 | } |
| 148 | 147 | } |
| 149 | 148 | |
| 150 | RelType AArch64::getDynRel(RelType Type) const { | |
| 151 | if (Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64) | |
| 152 | return Type; | |
| 149 | RelType AArch64::getDynRel(RelType type) const { | |
| 150 | if (type == R_AARCH64_ABS64) | |
| 151 | return type; | |
| 153 | 152 | return R_AARCH64_NONE; |
| 154 | 153 | } |
| 155 | 154 | |
| 156 | void AArch64::writeGotPlt(uint8_t *Buf, const Symbol &) const { | |
| 157 | write64le(Buf, In.Plt->getVA()); | |
| 155 | void AArch64::writeGotPlt(uint8_t *buf, const Symbol &) const { | |
| 156 | write64le(buf, in.plt->getVA()); | |
| 158 | 157 | } |
| 159 | 158 | |
| 160 | void AArch64::writePltHeader(uint8_t *Buf) const { | |
| 161 | const uint8_t PltData[] = { | |
| 159 | void AArch64::writePltHeader(uint8_t *buf) const { | |
| 160 | const uint8_t pltData[] = { | |
| 162 | 161 | 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]! |
| 163 | 162 | 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2])) |
| 164 | 163 | 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[2]))] |
| ... | ... | @@ -168,42 +167,42 @@ void AArch64::writePltHeader(uint8_t *Buf) const { |
| 168 | 167 | 0x1f, 0x20, 0x03, 0xd5, // nop |
| 169 | 168 | 0x1f, 0x20, 0x03, 0xd5 // nop |
| 170 | 169 | }; |
| 171 | memcpy(Buf, PltData, sizeof(PltData)); | |
| 172 | ||
| 173 | uint64_t Got = In.GotPlt->getVA(); | |
| 174 | uint64_t Plt = In.Plt->getVA(); | |
| 175 | relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, | |
| 176 | getAArch64Page(Got + 16) - getAArch64Page(Plt + 4)); | |
| 177 | relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16); | |
| 178 | relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16); | |
| 170 | memcpy(buf, pltData, sizeof(pltData)); | |
| 171 | ||
| 172 | uint64_t got = in.gotPlt->getVA(); | |
| 173 | uint64_t plt = in.plt->getVA(); | |
| 174 | relocateOne(buf + 4, R_AARCH64_ADR_PREL_PG_HI21, | |
| 175 | getAArch64Page(got + 16) - getAArch64Page(plt + 4)); | |
| 176 | relocateOne(buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, got + 16); | |
| 177 | relocateOne(buf + 12, R_AARCH64_ADD_ABS_LO12_NC, got + 16); | |
| 179 | 178 | } |
| 180 | 179 | |
| 181 | void AArch64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, | |
| 182 | uint64_t PltEntryAddr, int32_t Index, | |
| 183 | unsigned RelOff) const { | |
| 184 | const uint8_t Inst[] = { | |
| 180 | void AArch64::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, | |
| 181 | uint64_t pltEntryAddr, int32_t index, | |
| 182 | unsigned relOff) const { | |
| 183 | const uint8_t inst[] = { | |
| 185 | 184 | 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n])) |
| 186 | 185 | 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))] |
| 187 | 186 | 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[n])) |
| 188 | 187 | 0x20, 0x02, 0x1f, 0xd6 // br x17 |
| 189 | 188 | }; |
| 190 | memcpy(Buf, Inst, sizeof(Inst)); | |
| 189 | memcpy(buf, inst, sizeof(inst)); | |
| 191 | 190 | |
| 192 | relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21, | |
| 193 | getAArch64Page(GotPltEntryAddr) - getAArch64Page(PltEntryAddr)); | |
| 194 | relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotPltEntryAddr); | |
| 195 | relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr); | |
| 191 | relocateOne(buf, R_AARCH64_ADR_PREL_PG_HI21, | |
| 192 | getAArch64Page(gotPltEntryAddr) - getAArch64Page(pltEntryAddr)); | |
| 193 | relocateOne(buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, gotPltEntryAddr); | |
| 194 | relocateOne(buf + 8, R_AARCH64_ADD_ABS_LO12_NC, gotPltEntryAddr); | |
| 196 | 195 | } |
| 197 | 196 | |
| 198 | bool AArch64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, | |
| 199 | uint64_t BranchAddr, const Symbol &S) const { | |
| 197 | bool AArch64::needsThunk(RelExpr expr, RelType type, const InputFile *file, | |
| 198 | uint64_t branchAddr, const Symbol &s) const { | |
| 200 | 199 | // ELF for the ARM 64-bit architecture, section Call and Jump relocations |
| 201 | 200 | // only permits range extension thunks for R_AARCH64_CALL26 and |
| 202 | 201 | // R_AARCH64_JUMP26 relocation types. |
| 203 | if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26) | |
| 202 | if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26) | |
| 204 | 203 | return false; |
| 205 | uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); | |
| 206 | return !inBranchRange(Type, BranchAddr, Dst); | |
| 204 | uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA() : s.getVA(); | |
| 205 | return !inBranchRange(type, branchAddr, dst); | |
| 207 | 206 | } |
| 208 | 207 | |
| 209 | 208 | uint32_t AArch64::getThunkSectionSpacing() const { |
| ... | ... | @@ -213,71 +212,72 @@ uint32_t AArch64::getThunkSectionSpacing() const { |
| 213 | 212 | return (128 * 1024 * 1024) - 0x30000; |
| 214 | 213 | } |
| 215 | 214 | |
| 216 | bool AArch64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { | |
| 217 | if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26) | |
| 215 | bool AArch64::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { | |
| 216 | if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26) | |
| 218 | 217 | return true; |
| 219 | 218 | // The AArch64 call and unconditional branch instructions have a range of |
| 220 | 219 | // +/- 128 MiB. |
| 221 | uint64_t Range = 128 * 1024 * 1024; | |
| 222 | if (Dst > Src) { | |
| 220 | uint64_t range = 128 * 1024 * 1024; | |
| 221 | if (dst > src) { | |
| 223 | 222 | // Immediate of branch is signed. |
| 224 | Range -= 4; | |
| 225 | return Dst - Src <= Range; | |
| 223 | range -= 4; | |
| 224 | return dst - src <= range; | |
| 226 | 225 | } |
| 227 | return Src - Dst <= Range; | |
| 226 | return src - dst <= range; | |
| 228 | 227 | } |
| 229 | 228 | |
| 230 | static void write32AArch64Addr(uint8_t *L, uint64_t Imm) { | |
| 231 | uint32_t ImmLo = (Imm & 0x3) << 29; | |
| 232 | uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; | |
| 233 | uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); | |
| 234 | write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi); | |
| 229 | static void write32AArch64Addr(uint8_t *l, uint64_t imm) { | |
| 230 | uint32_t immLo = (imm & 0x3) << 29; | |
| 231 | uint32_t immHi = (imm & 0x1FFFFC) << 3; | |
| 232 | uint64_t mask = (0x3 << 29) | (0x1FFFFC << 3); | |
| 233 | write32le(l, (read32le(l) & ~mask) | immLo | immHi); | |
| 235 | 234 | } |
| 236 | 235 | |
| 237 | 236 | // Return the bits [Start, End] from Val shifted Start bits. |
| 238 | 237 | // For instance, getBits(0xF0, 4, 8) returns 0xF. |
| 239 | static uint64_t getBits(uint64_t Val, int Start, int End) { | |
| 240 | uint64_t Mask = ((uint64_t)1 << (End + 1 - Start)) - 1; | |
| 241 | return (Val >> Start) & Mask; | |
| 238 | static uint64_t getBits(uint64_t val, int start, int end) { | |
| 239 | uint64_t mask = ((uint64_t)1 << (end + 1 - start)) - 1; | |
| 240 | return (val >> start) & mask; | |
| 242 | 241 | } |
| 243 | 242 | |
| 244 | static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); } | |
| 243 | static void or32le(uint8_t *p, int32_t v) { write32le(p, read32le(p) | v); } | |
| 245 | 244 | |
| 246 | 245 | // Update the immediate field in a AARCH64 ldr, str, and add instruction. |
| 247 | static void or32AArch64Imm(uint8_t *L, uint64_t Imm) { | |
| 248 | or32le(L, (Imm & 0xFFF) << 10); | |
| 246 | static void or32AArch64Imm(uint8_t *l, uint64_t imm) { | |
| 247 | or32le(l, (imm & 0xFFF) << 10); | |
| 249 | 248 | } |
| 250 | 249 | |
| 251 | void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 252 | switch (Type) { | |
| 250 | void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { | |
| 251 | switch (type) { | |
| 253 | 252 | case R_AARCH64_ABS16: |
| 254 | 253 | case R_AARCH64_PREL16: |
| 255 | checkIntUInt(Loc, Val, 16, Type); | |
| 256 | write16le(Loc, Val); | |
| 254 | checkIntUInt(loc, val, 16, type); | |
| 255 | write16le(loc, val); | |
| 257 | 256 | break; |
| 258 | 257 | case R_AARCH64_ABS32: |
| 259 | 258 | case R_AARCH64_PREL32: |
| 260 | checkIntUInt(Loc, Val, 32, Type); | |
| 261 | write32le(Loc, Val); | |
| 259 | checkIntUInt(loc, val, 32, type); | |
| 260 | write32le(loc, val); | |
| 262 | 261 | break; |
| 263 | 262 | case R_AARCH64_ABS64: |
| 264 | case R_AARCH64_GLOB_DAT: | |
| 265 | 263 | case R_AARCH64_PREL64: |
| 266 | write64le(Loc, Val); | |
| 264 | write64le(loc, val); | |
| 267 | 265 | break; |
| 268 | 266 | case R_AARCH64_ADD_ABS_LO12_NC: |
| 269 | or32AArch64Imm(Loc, Val); | |
| 267 | or32AArch64Imm(loc, val); | |
| 270 | 268 | break; |
| 271 | 269 | case R_AARCH64_ADR_GOT_PAGE: |
| 272 | 270 | case R_AARCH64_ADR_PREL_PG_HI21: |
| 273 | 271 | case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: |
| 274 | 272 | case R_AARCH64_TLSDESC_ADR_PAGE21: |
| 275 | checkInt(Loc, Val, 33, Type); | |
| 276 | write32AArch64Addr(Loc, Val >> 12); | |
| 273 | checkInt(loc, val, 33, type); | |
| 274 | LLVM_FALLTHROUGH; | |
| 275 | case R_AARCH64_ADR_PREL_PG_HI21_NC: | |
| 276 | write32AArch64Addr(loc, val >> 12); | |
| 277 | 277 | break; |
| 278 | 278 | case R_AARCH64_ADR_PREL_LO21: |
| 279 | checkInt(Loc, Val, 21, Type); | |
| 280 | write32AArch64Addr(Loc, Val); | |
| 279 | checkInt(loc, val, 21, type); | |
| 280 | write32AArch64Addr(loc, val); | |
| 281 | 281 | break; |
| 282 | 282 | case R_AARCH64_JUMP26: |
| 283 | 283 | // Normally we would just write the bits of the immediate field, however |
| ... | ... | @@ -287,75 +287,75 @@ void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 287 | 287 | // opcode and the immediate (0 001 | 01 imm26) we can do this |
| 288 | 288 | // transformation by placing a R_AARCH64_JUMP26 relocation at the offset of |
| 289 | 289 | // the instruction we want to patch. |
| 290 | write32le(Loc, 0x14000000); | |
| 290 | write32le(loc, 0x14000000); | |
| 291 | 291 | LLVM_FALLTHROUGH; |
| 292 | 292 | case R_AARCH64_CALL26: |
| 293 | checkInt(Loc, Val, 28, Type); | |
| 294 | or32le(Loc, (Val & 0x0FFFFFFC) >> 2); | |
| 293 | checkInt(loc, val, 28, type); | |
| 294 | or32le(loc, (val & 0x0FFFFFFC) >> 2); | |
| 295 | 295 | break; |
| 296 | 296 | case R_AARCH64_CONDBR19: |
| 297 | 297 | case R_AARCH64_LD_PREL_LO19: |
| 298 | checkAlignment(Loc, Val, 4, Type); | |
| 299 | checkInt(Loc, Val, 21, Type); | |
| 300 | or32le(Loc, (Val & 0x1FFFFC) << 3); | |
| 298 | checkAlignment(loc, val, 4, type); | |
| 299 | checkInt(loc, val, 21, type); | |
| 300 | or32le(loc, (val & 0x1FFFFC) << 3); | |
| 301 | 301 | break; |
| 302 | 302 | case R_AARCH64_LDST8_ABS_LO12_NC: |
| 303 | 303 | case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: |
| 304 | or32AArch64Imm(Loc, getBits(Val, 0, 11)); | |
| 304 | or32AArch64Imm(loc, getBits(val, 0, 11)); | |
| 305 | 305 | break; |
| 306 | 306 | case R_AARCH64_LDST16_ABS_LO12_NC: |
| 307 | 307 | case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: |
| 308 | checkAlignment(Loc, Val, 2, Type); | |
| 309 | or32AArch64Imm(Loc, getBits(Val, 1, 11)); | |
| 308 | checkAlignment(loc, val, 2, type); | |
| 309 | or32AArch64Imm(loc, getBits(val, 1, 11)); | |
| 310 | 310 | break; |
| 311 | 311 | case R_AARCH64_LDST32_ABS_LO12_NC: |
| 312 | 312 | case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: |
| 313 | checkAlignment(Loc, Val, 4, Type); | |
| 314 | or32AArch64Imm(Loc, getBits(Val, 2, 11)); | |
| 313 | checkAlignment(loc, val, 4, type); | |
| 314 | or32AArch64Imm(loc, getBits(val, 2, 11)); | |
| 315 | 315 | break; |
| 316 | 316 | case R_AARCH64_LDST64_ABS_LO12_NC: |
| 317 | 317 | case R_AARCH64_LD64_GOT_LO12_NC: |
| 318 | 318 | case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: |
| 319 | 319 | case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: |
| 320 | 320 | case R_AARCH64_TLSDESC_LD64_LO12: |
| 321 | checkAlignment(Loc, Val, 8, Type); | |
| 322 | or32AArch64Imm(Loc, getBits(Val, 3, 11)); | |
| 321 | checkAlignment(loc, val, 8, type); | |
| 322 | or32AArch64Imm(loc, getBits(val, 3, 11)); | |
| 323 | 323 | break; |
| 324 | 324 | case R_AARCH64_LDST128_ABS_LO12_NC: |
| 325 | 325 | case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: |
| 326 | checkAlignment(Loc, Val, 16, Type); | |
| 327 | or32AArch64Imm(Loc, getBits(Val, 4, 11)); | |
| 326 | checkAlignment(loc, val, 16, type); | |
| 327 | or32AArch64Imm(loc, getBits(val, 4, 11)); | |
| 328 | 328 | break; |
| 329 | 329 | case R_AARCH64_MOVW_UABS_G0_NC: |
| 330 | or32le(Loc, (Val & 0xFFFF) << 5); | |
| 330 | or32le(loc, (val & 0xFFFF) << 5); | |
| 331 | 331 | break; |
| 332 | 332 | case R_AARCH64_MOVW_UABS_G1_NC: |
| 333 | or32le(Loc, (Val & 0xFFFF0000) >> 11); | |
| 333 | or32le(loc, (val & 0xFFFF0000) >> 11); | |
| 334 | 334 | break; |
| 335 | 335 | case R_AARCH64_MOVW_UABS_G2_NC: |
| 336 | or32le(Loc, (Val & 0xFFFF00000000) >> 27); | |
| 336 | or32le(loc, (val & 0xFFFF00000000) >> 27); | |
| 337 | 337 | break; |
| 338 | 338 | case R_AARCH64_MOVW_UABS_G3: |
| 339 | or32le(Loc, (Val & 0xFFFF000000000000) >> 43); | |
| 339 | or32le(loc, (val & 0xFFFF000000000000) >> 43); | |
| 340 | 340 | break; |
| 341 | 341 | case R_AARCH64_TSTBR14: |
| 342 | checkInt(Loc, Val, 16, Type); | |
| 343 | or32le(Loc, (Val & 0xFFFC) << 3); | |
| 342 | checkInt(loc, val, 16, type); | |
| 343 | or32le(loc, (val & 0xFFFC) << 3); | |
| 344 | 344 | break; |
| 345 | 345 | case R_AARCH64_TLSLE_ADD_TPREL_HI12: |
| 346 | checkUInt(Loc, Val, 24, Type); | |
| 347 | or32AArch64Imm(Loc, Val >> 12); | |
| 346 | checkUInt(loc, val, 24, type); | |
| 347 | or32AArch64Imm(loc, val >> 12); | |
| 348 | 348 | break; |
| 349 | 349 | case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: |
| 350 | 350 | case R_AARCH64_TLSDESC_ADD_LO12: |
| 351 | or32AArch64Imm(Loc, Val); | |
| 351 | or32AArch64Imm(loc, val); | |
| 352 | 352 | break; |
| 353 | 353 | default: |
| 354 | error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); | |
| 354 | error(getErrorLocation(loc) + "unrecognized relocation " + toString(type)); | |
| 355 | 355 | } |
| 356 | 356 | } |
| 357 | 357 | |
| 358 | void AArch64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 358 | void AArch64::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 359 | 359 | // TLSDESC Global-Dynamic relocation are in the form: |
| 360 | 360 | // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] |
| 361 | 361 | // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] |
| ... | ... | @@ -367,25 +367,25 @@ void AArch64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 367 | 367 | // movk x0, #0x10 |
| 368 | 368 | // nop |
| 369 | 369 | // nop |
| 370 | checkUInt(Loc, Val, 32, Type); | |
| 370 | checkUInt(loc, val, 32, type); | |
| 371 | 371 | |
| 372 | switch (Type) { | |
| 372 | switch (type) { | |
| 373 | 373 | case R_AARCH64_TLSDESC_ADD_LO12: |
| 374 | 374 | case R_AARCH64_TLSDESC_CALL: |
| 375 | write32le(Loc, 0xd503201f); // nop | |
| 375 | write32le(loc, 0xd503201f); // nop | |
| 376 | 376 | return; |
| 377 | 377 | case R_AARCH64_TLSDESC_ADR_PAGE21: |
| 378 | write32le(Loc, 0xd2a00000 | (((Val >> 16) & 0xffff) << 5)); // movz | |
| 378 | write32le(loc, 0xd2a00000 | (((val >> 16) & 0xffff) << 5)); // movz | |
| 379 | 379 | return; |
| 380 | 380 | case R_AARCH64_TLSDESC_LD64_LO12: |
| 381 | write32le(Loc, 0xf2800000 | ((Val & 0xffff) << 5)); // movk | |
| 381 | write32le(loc, 0xf2800000 | ((val & 0xffff) << 5)); // movk | |
| 382 | 382 | return; |
| 383 | 383 | default: |
| 384 | 384 | llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); |
| 385 | 385 | } |
| 386 | 386 | } |
| 387 | 387 | |
| 388 | void AArch64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 388 | void AArch64::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 389 | 389 | // TLSDESC Global-Dynamic relocation are in the form: |
| 390 | 390 | // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] |
| 391 | 391 | // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] |
| ... | ... | @@ -398,43 +398,193 @@ void AArch64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 398 | 398 | // nop |
| 399 | 399 | // nop |
| 400 | 400 | |
| 401 | switch (Type) { | |
| 401 | switch (type) { | |
| 402 | 402 | case R_AARCH64_TLSDESC_ADD_LO12: |
| 403 | 403 | case R_AARCH64_TLSDESC_CALL: |
| 404 | write32le(Loc, 0xd503201f); // nop | |
| 404 | write32le(loc, 0xd503201f); // nop | |
| 405 | 405 | break; |
| 406 | 406 | case R_AARCH64_TLSDESC_ADR_PAGE21: |
| 407 | write32le(Loc, 0x90000000); // adrp | |
| 408 | relocateOne(Loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, Val); | |
| 407 | write32le(loc, 0x90000000); // adrp | |
| 408 | relocateOne(loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, val); | |
| 409 | 409 | break; |
| 410 | 410 | case R_AARCH64_TLSDESC_LD64_LO12: |
| 411 | write32le(Loc, 0xf9400000); // ldr | |
| 412 | relocateOne(Loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, Val); | |
| 411 | write32le(loc, 0xf9400000); // ldr | |
| 412 | relocateOne(loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, val); | |
| 413 | 413 | break; |
| 414 | 414 | default: |
| 415 | 415 | llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); |
| 416 | 416 | } |
| 417 | 417 | } |
| 418 | 418 | |
| 419 | void AArch64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 420 | checkUInt(Loc, Val, 32, Type); | |
| 419 | void AArch64::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 420 | checkUInt(loc, val, 32, type); | |
| 421 | 421 | |
| 422 | if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) { | |
| 422 | if (type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) { | |
| 423 | 423 | // Generate MOVZ. |
| 424 | uint32_t RegNo = read32le(Loc) & 0x1f; | |
| 425 | write32le(Loc, (0xd2a00000 | RegNo) | (((Val >> 16) & 0xffff) << 5)); | |
| 424 | uint32_t regNo = read32le(loc) & 0x1f; | |
| 425 | write32le(loc, (0xd2a00000 | regNo) | (((val >> 16) & 0xffff) << 5)); | |
| 426 | 426 | return; |
| 427 | 427 | } |
| 428 | if (Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) { | |
| 428 | if (type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) { | |
| 429 | 429 | // Generate MOVK. |
| 430 | uint32_t RegNo = read32le(Loc) & 0x1f; | |
| 431 | write32le(Loc, (0xf2800000 | RegNo) | ((Val & 0xffff) << 5)); | |
| 430 | uint32_t regNo = read32le(loc) & 0x1f; | |
| 431 | write32le(loc, (0xf2800000 | regNo) | ((val & 0xffff) << 5)); | |
| 432 | 432 | return; |
| 433 | 433 | } |
| 434 | 434 | llvm_unreachable("invalid relocation for TLS IE to LE relaxation"); |
| 435 | 435 | } |
| 436 | 436 | |
| 437 | TargetInfo *elf::getAArch64TargetInfo() { | |
| 438 | static AArch64 Target; | |
| 439 | return &Target; | |
| 437 | // AArch64 may use security features in variant PLT sequences. These are: | |
| 438 | // Pointer Authentication (PAC), introduced in armv8.3-a and Branch Target | |
| 439 | // Indicator (BTI) introduced in armv8.5-a. The additional instructions used | |
| 440 | // in the variant Plt sequences are encoded in the Hint space so they can be | |
| 441 | // deployed on older architectures, which treat the instructions as a nop. | |
| 442 | // PAC and BTI can be combined leading to the following combinations: | |
| 443 | // writePltHeader | |
| 444 | // writePltHeaderBti (no PAC Header needed) | |
| 445 | // writePlt | |
| 446 | // writePltBti (BTI only) | |
| 447 | // writePltPac (PAC only) | |
| 448 | // writePltBtiPac (BTI and PAC) | |
| 449 | // | |
| 450 | // When PAC is enabled the dynamic loader encrypts the address that it places | |
| 451 | // in the .got.plt using the pacia1716 instruction which encrypts the value in | |
| 452 | // x17 using the modifier in x16. The static linker places autia1716 before the | |
| 453 | // indirect branch to x17 to authenticate the address in x17 with the modifier | |
| 454 | // in x16. This makes it more difficult for an attacker to modify the value in | |
| 455 | // the .got.plt. | |
| 456 | // | |
| 457 | // When BTI is enabled all indirect branches must land on a bti instruction. | |
| 458 | // The static linker must place a bti instruction at the start of any PLT entry | |
| 459 | // that may be the target of an indirect branch. As the PLT entries call the | |
| 460 | // lazy resolver indirectly this must have a bti instruction at start. In | |
| 461 | // general a bti instruction is not needed for a PLT entry as indirect calls | |
| 462 | // are resolved to the function address and not the PLT entry for the function. | |
| 463 | // There are a small number of cases where the PLT address can escape, such as | |
| 464 | // taking the address of a function or ifunc via a non got-generating | |
| 465 | // relocation, and a shared library refers to that symbol. | |
| 466 | // | |
| 467 | // We use the bti c variant of the instruction which permits indirect branches | |
| 468 | // (br) via x16/x17 and indirect function calls (blr) via any register. The ABI | |
| 469 | // guarantees that all indirect branches from code requiring BTI protection | |
| 470 | // will go via x16/x17 | |
| 471 | ||
| 472 | namespace { | |
| 473 | class AArch64BtiPac final : public AArch64 { | |
| 474 | public: | |
| 475 | AArch64BtiPac(); | |
| 476 | void writePltHeader(uint8_t *buf) const override; | |
| 477 | void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, | |
| 478 | int32_t index, unsigned relOff) const override; | |
| 479 | ||
| 480 | private: | |
| 481 | bool btiHeader; // bti instruction needed in PLT Header | |
| 482 | bool btiEntry; // bti instruction needed in PLT Entry | |
| 483 | bool pacEntry; // autia1716 instruction needed in PLT Entry | |
| 484 | }; | |
| 485 | } // namespace | |
| 486 | ||
| 487 | AArch64BtiPac::AArch64BtiPac() { | |
| 488 | btiHeader = (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI); | |
| 489 | // A BTI (Branch Target Indicator) Plt Entry is only required if the | |
| 490 | // address of the PLT entry can be taken by the program, which permits an | |
| 491 | // indirect jump to the PLT entry. This can happen when the address | |
| 492 | // of the PLT entry for a function is canonicalised due to the address of | |
| 493 | // the function in an executable being taken by a shared library. | |
| 494 | // FIXME: There is a potential optimization to omit the BTI if we detect | |
| 495 | // that the address of the PLT entry isn't taken. | |
| 496 | btiEntry = btiHeader && !config->shared; | |
| 497 | pacEntry = (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_PAC); | |
| 498 | ||
| 499 | if (btiEntry || pacEntry) | |
| 500 | pltEntrySize = 24; | |
| 440 | 501 | } |
| 502 | ||
| 503 | void AArch64BtiPac::writePltHeader(uint8_t *buf) const { | |
| 504 | const uint8_t btiData[] = { 0x5f, 0x24, 0x03, 0xd5 }; // bti c | |
| 505 | const uint8_t pltData[] = { | |
| 506 | 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]! | |
| 507 | 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2])) | |
| 508 | 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[2]))] | |
| 509 | 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[2])) | |
| 510 | 0x20, 0x02, 0x1f, 0xd6, // br x17 | |
| 511 | 0x1f, 0x20, 0x03, 0xd5, // nop | |
| 512 | 0x1f, 0x20, 0x03, 0xd5 // nop | |
| 513 | }; | |
| 514 | const uint8_t nopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop | |
| 515 | ||
| 516 | uint64_t got = in.gotPlt->getVA(); | |
| 517 | uint64_t plt = in.plt->getVA(); | |
| 518 | ||
| 519 | if (btiHeader) { | |
| 520 | // PltHeader is called indirectly by plt[N]. Prefix pltData with a BTI C | |
| 521 | // instruction. | |
| 522 | memcpy(buf, btiData, sizeof(btiData)); | |
| 523 | buf += sizeof(btiData); | |
| 524 | plt += sizeof(btiData); | |
| 525 | } | |
| 526 | memcpy(buf, pltData, sizeof(pltData)); | |
| 527 | ||
| 528 | relocateOne(buf + 4, R_AARCH64_ADR_PREL_PG_HI21, | |
| 529 | getAArch64Page(got + 16) - getAArch64Page(plt + 8)); | |
| 530 | relocateOne(buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, got + 16); | |
| 531 | relocateOne(buf + 12, R_AARCH64_ADD_ABS_LO12_NC, got + 16); | |
| 532 | if (!btiHeader) | |
| 533 | // We didn't add the BTI c instruction so round out size with NOP. | |
| 534 | memcpy(buf + sizeof(pltData), nopData, sizeof(nopData)); | |
| 535 | } | |
| 536 | ||
| 537 | void AArch64BtiPac::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, | |
| 538 | uint64_t pltEntryAddr, int32_t index, | |
| 539 | unsigned relOff) const { | |
| 540 | // The PLT entry is of the form: | |
| 541 | // [btiData] addrInst (pacBr | stdBr) [nopData] | |
| 542 | const uint8_t btiData[] = { 0x5f, 0x24, 0x03, 0xd5 }; // bti c | |
| 543 | const uint8_t addrInst[] = { | |
| 544 | 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n])) | |
| 545 | 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))] | |
| 546 | 0x10, 0x02, 0x00, 0x91 // add x16, x16, Offset(&(.plt.got[n])) | |
| 547 | }; | |
| 548 | const uint8_t pacBr[] = { | |
| 549 | 0x9f, 0x21, 0x03, 0xd5, // autia1716 | |
| 550 | 0x20, 0x02, 0x1f, 0xd6 // br x17 | |
| 551 | }; | |
| 552 | const uint8_t stdBr[] = { | |
| 553 | 0x20, 0x02, 0x1f, 0xd6, // br x17 | |
| 554 | 0x1f, 0x20, 0x03, 0xd5 // nop | |
| 555 | }; | |
| 556 | const uint8_t nopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop | |
| 557 | ||
| 558 | if (btiEntry) { | |
| 559 | memcpy(buf, btiData, sizeof(btiData)); | |
| 560 | buf += sizeof(btiData); | |
| 561 | pltEntryAddr += sizeof(btiData); | |
| 562 | } | |
| 563 | ||
| 564 | memcpy(buf, addrInst, sizeof(addrInst)); | |
| 565 | relocateOne(buf, R_AARCH64_ADR_PREL_PG_HI21, | |
| 566 | getAArch64Page(gotPltEntryAddr) - | |
| 567 | getAArch64Page(pltEntryAddr)); | |
| 568 | relocateOne(buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, gotPltEntryAddr); | |
| 569 | relocateOne(buf + 8, R_AARCH64_ADD_ABS_LO12_NC, gotPltEntryAddr); | |
| 570 | ||
| 571 | if (pacEntry) | |
| 572 | memcpy(buf + sizeof(addrInst), pacBr, sizeof(pacBr)); | |
| 573 | else | |
| 574 | memcpy(buf + sizeof(addrInst), stdBr, sizeof(stdBr)); | |
| 575 | if (!btiEntry) | |
| 576 | // We didn't add the BTI c instruction so round out size with NOP. | |
| 577 | memcpy(buf + sizeof(addrInst) + sizeof(stdBr), nopData, sizeof(nopData)); | |
| 578 | } | |
| 579 | ||
| 580 | static TargetInfo *getTargetInfo() { | |
| 581 | if (config->andFeatures & (GNU_PROPERTY_AARCH64_FEATURE_1_BTI | | |
| 582 | GNU_PROPERTY_AARCH64_FEATURE_1_PAC)) { | |
| 583 | static AArch64BtiPac t; | |
| 584 | return &t; | |
| 585 | } | |
| 586 | static AArch64 t; | |
| 587 | return &t; | |
| 588 | } | |
| 589 | ||
| 590 | TargetInfo *elf::getAArch64TargetInfo() { return getTargetInfo(); } |
deps/lld/ELF/Arch/AMDGPU.cpp+39-31| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- AMDGPU.cpp ---------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -26,62 +25,63 @@ class AMDGPU final : public TargetInfo { |
| 26 | 25 | public: |
| 27 | 26 | AMDGPU(); |
| 28 | 27 | uint32_t calcEFlags() const override; |
| 29 | void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 30 | RelExpr getRelExpr(RelType Type, const Symbol &S, | |
| 31 | const uint8_t *Loc) const override; | |
| 28 | void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 29 | RelExpr getRelExpr(RelType type, const Symbol &s, | |
| 30 | const uint8_t *loc) const override; | |
| 31 | RelType getDynRel(RelType type) const override; | |
| 32 | 32 | }; |
| 33 | 33 | } // namespace |
| 34 | 34 | |
| 35 | 35 | AMDGPU::AMDGPU() { |
| 36 | RelativeRel = R_AMDGPU_RELATIVE64; | |
| 37 | GotRel = R_AMDGPU_ABS64; | |
| 38 | NoneRel = R_AMDGPU_NONE; | |
| 39 | GotEntrySize = 8; | |
| 36 | relativeRel = R_AMDGPU_RELATIVE64; | |
| 37 | gotRel = R_AMDGPU_ABS64; | |
| 38 | noneRel = R_AMDGPU_NONE; | |
| 39 | symbolicRel = R_AMDGPU_ABS64; | |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | static uint32_t getEFlags(InputFile *File) { | |
| 43 | return cast<ObjFile<ELF64LE>>(File)->getObj().getHeader()->e_flags; | |
| 42 | static uint32_t getEFlags(InputFile *file) { | |
| 43 | return cast<ObjFile<ELF64LE>>(file)->getObj().getHeader()->e_flags; | |
| 44 | 44 | } |
| 45 | 45 | |
| 46 | 46 | uint32_t AMDGPU::calcEFlags() const { |
| 47 | assert(!ObjectFiles.empty()); | |
| 48 | uint32_t Ret = getEFlags(ObjectFiles[0]); | |
| 47 | assert(!objectFiles.empty()); | |
| 48 | uint32_t ret = getEFlags(objectFiles[0]); | |
| 49 | 49 | |
| 50 | 50 | // Verify that all input files have the same e_flags. |
| 51 | for (InputFile *F : makeArrayRef(ObjectFiles).slice(1)) { | |
| 52 | if (Ret == getEFlags(F)) | |
| 51 | for (InputFile *f : makeArrayRef(objectFiles).slice(1)) { | |
| 52 | if (ret == getEFlags(f)) | |
| 53 | 53 | continue; |
| 54 | error("incompatible e_flags: " + toString(F)); | |
| 54 | error("incompatible e_flags: " + toString(f)); | |
| 55 | 55 | return 0; |
| 56 | 56 | } |
| 57 | return Ret; | |
| 57 | return ret; | |
| 58 | 58 | } |
| 59 | 59 | |
| 60 | void AMDGPU::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 61 | switch (Type) { | |
| 60 | void AMDGPU::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { | |
| 61 | switch (type) { | |
| 62 | 62 | case R_AMDGPU_ABS32: |
| 63 | 63 | case R_AMDGPU_GOTPCREL: |
| 64 | 64 | case R_AMDGPU_GOTPCREL32_LO: |
| 65 | 65 | case R_AMDGPU_REL32: |
| 66 | 66 | case R_AMDGPU_REL32_LO: |
| 67 | write32le(Loc, Val); | |
| 67 | write32le(loc, val); | |
| 68 | 68 | break; |
| 69 | 69 | case R_AMDGPU_ABS64: |
| 70 | 70 | case R_AMDGPU_REL64: |
| 71 | write64le(Loc, Val); | |
| 71 | write64le(loc, val); | |
| 72 | 72 | break; |
| 73 | 73 | case R_AMDGPU_GOTPCREL32_HI: |
| 74 | 74 | case R_AMDGPU_REL32_HI: |
| 75 | write32le(Loc, Val >> 32); | |
| 75 | write32le(loc, val >> 32); | |
| 76 | 76 | break; |
| 77 | 77 | default: |
| 78 | error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); | |
| 78 | llvm_unreachable("unknown relocation"); | |
| 79 | 79 | } |
| 80 | 80 | } |
| 81 | 81 | |
| 82 | RelExpr AMDGPU::getRelExpr(RelType Type, const Symbol &S, | |
| 83 | const uint8_t *Loc) const { | |
| 84 | switch (Type) { | |
| 82 | RelExpr AMDGPU::getRelExpr(RelType type, const Symbol &s, | |
| 83 | const uint8_t *loc) const { | |
| 84 | switch (type) { | |
| 85 | 85 | case R_AMDGPU_ABS32: |
| 86 | 86 | case R_AMDGPU_ABS64: |
| 87 | 87 | return R_ABS; |
| ... | ... | @@ -95,11 +95,19 @@ RelExpr AMDGPU::getRelExpr(RelType Type, const Symbol &S, |
| 95 | 95 | case R_AMDGPU_GOTPCREL32_HI: |
| 96 | 96 | return R_GOT_PC; |
| 97 | 97 | default: |
| 98 | return R_INVALID; | |
| 98 | error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + | |
| 99 | ") against symbol " + toString(s)); | |
| 100 | return R_NONE; | |
| 99 | 101 | } |
| 100 | 102 | } |
| 101 | 103 | |
| 104 | RelType AMDGPU::getDynRel(RelType type) const { | |
| 105 | if (type == R_AMDGPU_ABS64) | |
| 106 | return type; | |
| 107 | return R_AMDGPU_NONE; | |
| 108 | } | |
| 109 | ||
| 102 | 110 | TargetInfo *elf::getAMDGPUTargetInfo() { |
| 103 | static AMDGPU Target; | |
| 104 | return &Target; | |
| 111 | static AMDGPU target; | |
| 112 | return &target; | |
| 105 | 113 | } |
deps/lld/ELF/Arch/ARM.cpp+228-234| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- ARM.cpp ------------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -27,63 +26,62 @@ class ARM final : public TargetInfo { |
| 27 | 26 | public: |
| 28 | 27 | ARM(); |
| 29 | 28 | uint32_t calcEFlags() const override; |
| 30 | RelExpr getRelExpr(RelType Type, const Symbol &S, | |
| 31 | const uint8_t *Loc) const override; | |
| 32 | RelType getDynRel(RelType Type) const override; | |
| 33 | int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; | |
| 34 | void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; | |
| 35 | void writeIgotPlt(uint8_t *Buf, const Symbol &S) const override; | |
| 36 | void writePltHeader(uint8_t *Buf) const override; | |
| 37 | void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, | |
| 38 | int32_t Index, unsigned RelOff) const override; | |
| 39 | void addPltSymbols(InputSection &IS, uint64_t Off) const override; | |
| 40 | void addPltHeaderSymbols(InputSection &ISD) const override; | |
| 41 | bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, | |
| 42 | uint64_t BranchAddr, const Symbol &S) const override; | |
| 29 | RelExpr getRelExpr(RelType type, const Symbol &s, | |
| 30 | const uint8_t *loc) const override; | |
| 31 | RelType getDynRel(RelType type) const override; | |
| 32 | int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; | |
| 33 | void writeGotPlt(uint8_t *buf, const Symbol &s) const override; | |
| 34 | void writeIgotPlt(uint8_t *buf, const Symbol &s) const override; | |
| 35 | void writePltHeader(uint8_t *buf) const override; | |
| 36 | void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, | |
| 37 | int32_t index, unsigned relOff) const override; | |
| 38 | void addPltSymbols(InputSection &isec, uint64_t off) const override; | |
| 39 | void addPltHeaderSymbols(InputSection &isd) const override; | |
| 40 | bool needsThunk(RelExpr expr, RelType type, const InputFile *file, | |
| 41 | uint64_t branchAddr, const Symbol &s) const override; | |
| 43 | 42 | uint32_t getThunkSectionSpacing() const override; |
| 44 | bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; | |
| 45 | void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 43 | bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; | |
| 44 | void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 46 | 45 | }; |
| 47 | 46 | } // namespace |
| 48 | 47 | |
| 49 | 48 | ARM::ARM() { |
| 50 | CopyRel = R_ARM_COPY; | |
| 51 | RelativeRel = R_ARM_RELATIVE; | |
| 52 | IRelativeRel = R_ARM_IRELATIVE; | |
| 53 | GotRel = R_ARM_GLOB_DAT; | |
| 54 | NoneRel = R_ARM_NONE; | |
| 55 | PltRel = R_ARM_JUMP_SLOT; | |
| 56 | TlsGotRel = R_ARM_TLS_TPOFF32; | |
| 57 | TlsModuleIndexRel = R_ARM_TLS_DTPMOD32; | |
| 58 | TlsOffsetRel = R_ARM_TLS_DTPOFF32; | |
| 59 | GotBaseSymInGotPlt = false; | |
| 60 | GotEntrySize = 4; | |
| 61 | GotPltEntrySize = 4; | |
| 62 | PltEntrySize = 16; | |
| 63 | PltHeaderSize = 32; | |
| 64 | TrapInstr = {0xd4, 0xd4, 0xd4, 0xd4}; | |
| 65 | NeedsThunks = true; | |
| 49 | copyRel = R_ARM_COPY; | |
| 50 | relativeRel = R_ARM_RELATIVE; | |
| 51 | iRelativeRel = R_ARM_IRELATIVE; | |
| 52 | gotRel = R_ARM_GLOB_DAT; | |
| 53 | noneRel = R_ARM_NONE; | |
| 54 | pltRel = R_ARM_JUMP_SLOT; | |
| 55 | symbolicRel = R_ARM_ABS32; | |
| 56 | tlsGotRel = R_ARM_TLS_TPOFF32; | |
| 57 | tlsModuleIndexRel = R_ARM_TLS_DTPMOD32; | |
| 58 | tlsOffsetRel = R_ARM_TLS_DTPOFF32; | |
| 59 | gotBaseSymInGotPlt = false; | |
| 60 | pltEntrySize = 16; | |
| 61 | pltHeaderSize = 32; | |
| 62 | trapInstr = {0xd4, 0xd4, 0xd4, 0xd4}; | |
| 63 | needsThunks = true; | |
| 66 | 64 | } |
| 67 | 65 | |
| 68 | 66 | uint32_t ARM::calcEFlags() const { |
| 69 | 67 | // The ABIFloatType is used by loaders to detect the floating point calling |
| 70 | 68 | // convention. |
| 71 | uint32_t ABIFloatType = 0; | |
| 72 | if (Config->ARMVFPArgs == ARMVFPArgKind::Base || | |
| 73 | Config->ARMVFPArgs == ARMVFPArgKind::Default) | |
| 74 | ABIFloatType = EF_ARM_ABI_FLOAT_SOFT; | |
| 75 | else if (Config->ARMVFPArgs == ARMVFPArgKind::VFP) | |
| 76 | ABIFloatType = EF_ARM_ABI_FLOAT_HARD; | |
| 69 | uint32_t abiFloatType = 0; | |
| 70 | if (config->armVFPArgs == ARMVFPArgKind::Base || | |
| 71 | config->armVFPArgs == ARMVFPArgKind::Default) | |
| 72 | abiFloatType = EF_ARM_ABI_FLOAT_SOFT; | |
| 73 | else if (config->armVFPArgs == ARMVFPArgKind::VFP) | |
| 74 | abiFloatType = EF_ARM_ABI_FLOAT_HARD; | |
| 77 | 75 | |
| 78 | 76 | // We don't currently use any features incompatible with EF_ARM_EABI_VER5, |
| 79 | 77 | // but we don't have any firm guarantees of conformance. Linux AArch64 |
| 80 | 78 | // kernels (as of 2016) require an EABI version to be set. |
| 81 | return EF_ARM_EABI_VER5 | ABIFloatType; | |
| 79 | return EF_ARM_EABI_VER5 | abiFloatType; | |
| 82 | 80 | } |
| 83 | 81 | |
| 84 | RelExpr ARM::getRelExpr(RelType Type, const Symbol &S, | |
| 85 | const uint8_t *Loc) const { | |
| 86 | switch (Type) { | |
| 82 | RelExpr ARM::getRelExpr(RelType type, const Symbol &s, | |
| 83 | const uint8_t *loc) const { | |
| 84 | switch (type) { | |
| 87 | 85 | case R_ARM_THM_JUMP11: |
| 88 | 86 | return R_PC; |
| 89 | 87 | case R_ARM_CALL: |
| ... | ... | @@ -108,11 +106,11 @@ RelExpr ARM::getRelExpr(RelType Type, const Symbol &S, |
| 108 | 106 | case R_ARM_SBREL32: |
| 109 | 107 | return R_ARM_SBREL; |
| 110 | 108 | case R_ARM_TARGET1: |
| 111 | return Config->Target1Rel ? R_PC : R_ABS; | |
| 109 | return config->target1Rel ? R_PC : R_ABS; | |
| 112 | 110 | case R_ARM_TARGET2: |
| 113 | if (Config->Target2 == Target2Policy::Rel) | |
| 111 | if (config->target2 == Target2Policy::Rel) | |
| 114 | 112 | return R_PC; |
| 115 | if (Config->Target2 == Target2Policy::Abs) | |
| 113 | if (config->target2 == Target2Policy::Abs) | |
| 116 | 114 | return R_ABS; |
| 117 | 115 | return R_GOT_PC; |
| 118 | 116 | case R_ARM_TLS_GD32: |
| ... | ... | @@ -145,25 +143,25 @@ RelExpr ARM::getRelExpr(RelType Type, const Symbol &S, |
| 145 | 143 | } |
| 146 | 144 | } |
| 147 | 145 | |
| 148 | RelType ARM::getDynRel(RelType Type) const { | |
| 149 | if ((Type == R_ARM_ABS32) || (Type == R_ARM_TARGET1 && !Config->Target1Rel)) | |
| 146 | RelType ARM::getDynRel(RelType type) const { | |
| 147 | if ((type == R_ARM_ABS32) || (type == R_ARM_TARGET1 && !config->target1Rel)) | |
| 150 | 148 | return R_ARM_ABS32; |
| 151 | 149 | return R_ARM_NONE; |
| 152 | 150 | } |
| 153 | 151 | |
| 154 | void ARM::writeGotPlt(uint8_t *Buf, const Symbol &) const { | |
| 155 | write32le(Buf, In.Plt->getVA()); | |
| 152 | void ARM::writeGotPlt(uint8_t *buf, const Symbol &) const { | |
| 153 | write32le(buf, in.plt->getVA()); | |
| 156 | 154 | } |
| 157 | 155 | |
| 158 | void ARM::writeIgotPlt(uint8_t *Buf, const Symbol &S) const { | |
| 156 | void ARM::writeIgotPlt(uint8_t *buf, const Symbol &s) const { | |
| 159 | 157 | // An ARM entry is the address of the ifunc resolver function. |
| 160 | write32le(Buf, S.getVA()); | |
| 158 | write32le(buf, s.getVA()); | |
| 161 | 159 | } |
| 162 | 160 | |
| 163 | 161 | // Long form PLT Header that does not have any restrictions on the displacement |
| 164 | 162 | // of the .plt from the .plt.got. |
| 165 | static void writePltHeaderLong(uint8_t *Buf) { | |
| 166 | const uint8_t PltData[] = { | |
| 163 | static void writePltHeaderLong(uint8_t *buf) { | |
| 164 | const uint8_t pltData[] = { | |
| 167 | 165 | 0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]! |
| 168 | 166 | 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, L2 |
| 169 | 167 | 0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr |
| ... | ... | @@ -172,128 +170,128 @@ static void writePltHeaderLong(uint8_t *Buf) { |
| 172 | 170 | 0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary |
| 173 | 171 | 0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary |
| 174 | 172 | 0xd4, 0xd4, 0xd4, 0xd4}; |
| 175 | memcpy(Buf, PltData, sizeof(PltData)); | |
| 176 | uint64_t GotPlt = In.GotPlt->getVA(); | |
| 177 | uint64_t L1 = In.Plt->getVA() + 8; | |
| 178 | write32le(Buf + 16, GotPlt - L1 - 8); | |
| 173 | memcpy(buf, pltData, sizeof(pltData)); | |
| 174 | uint64_t gotPlt = in.gotPlt->getVA(); | |
| 175 | uint64_t l1 = in.plt->getVA() + 8; | |
| 176 | write32le(buf + 16, gotPlt - l1 - 8); | |
| 179 | 177 | } |
| 180 | 178 | |
| 181 | 179 | // The default PLT header requires the .plt.got to be within 128 Mb of the |
| 182 | 180 | // .plt in the positive direction. |
| 183 | void ARM::writePltHeader(uint8_t *Buf) const { | |
| 181 | void ARM::writePltHeader(uint8_t *buf) const { | |
| 184 | 182 | // Use a similar sequence to that in writePlt(), the difference is the calling |
| 185 | 183 | // conventions mean we use lr instead of ip. The PLT entry is responsible for |
| 186 | 184 | // saving lr on the stack, the dynamic loader is responsible for reloading |
| 187 | 185 | // it. |
| 188 | const uint32_t PltData[] = { | |
| 186 | const uint32_t pltData[] = { | |
| 189 | 187 | 0xe52de004, // L1: str lr, [sp,#-4]! |
| 190 | 188 | 0xe28fe600, // add lr, pc, #0x0NN00000 &(.got.plt - L1 - 4) |
| 191 | 189 | 0xe28eea00, // add lr, lr, #0x000NN000 &(.got.plt - L1 - 4) |
| 192 | 190 | 0xe5bef000, // ldr pc, [lr, #0x00000NNN] &(.got.plt -L1 - 4) |
| 193 | 191 | }; |
| 194 | 192 | |
| 195 | uint64_t Offset = In.GotPlt->getVA() - In.Plt->getVA() - 4; | |
| 196 | if (!llvm::isUInt<27>(Offset)) { | |
| 193 | uint64_t offset = in.gotPlt->getVA() - in.plt->getVA() - 4; | |
| 194 | if (!llvm::isUInt<27>(offset)) { | |
| 197 | 195 | // We cannot encode the Offset, use the long form. |
| 198 | writePltHeaderLong(Buf); | |
| 196 | writePltHeaderLong(buf); | |
| 199 | 197 | return; |
| 200 | 198 | } |
| 201 | write32le(Buf + 0, PltData[0]); | |
| 202 | write32le(Buf + 4, PltData[1] | ((Offset >> 20) & 0xff)); | |
| 203 | write32le(Buf + 8, PltData[2] | ((Offset >> 12) & 0xff)); | |
| 204 | write32le(Buf + 12, PltData[3] | (Offset & 0xfff)); | |
| 205 | memcpy(Buf + 16, TrapInstr.data(), 4); // Pad to 32-byte boundary | |
| 206 | memcpy(Buf + 20, TrapInstr.data(), 4); | |
| 207 | memcpy(Buf + 24, TrapInstr.data(), 4); | |
| 208 | memcpy(Buf + 28, TrapInstr.data(), 4); | |
| 199 | write32le(buf + 0, pltData[0]); | |
| 200 | write32le(buf + 4, pltData[1] | ((offset >> 20) & 0xff)); | |
| 201 | write32le(buf + 8, pltData[2] | ((offset >> 12) & 0xff)); | |
| 202 | write32le(buf + 12, pltData[3] | (offset & 0xfff)); | |
| 203 | memcpy(buf + 16, trapInstr.data(), 4); // Pad to 32-byte boundary | |
| 204 | memcpy(buf + 20, trapInstr.data(), 4); | |
| 205 | memcpy(buf + 24, trapInstr.data(), 4); | |
| 206 | memcpy(buf + 28, trapInstr.data(), 4); | |
| 209 | 207 | } |
| 210 | 208 | |
| 211 | void ARM::addPltHeaderSymbols(InputSection &IS) const { | |
| 212 | addSyntheticLocal("$a", STT_NOTYPE, 0, 0, IS); | |
| 213 | addSyntheticLocal("$d", STT_NOTYPE, 16, 0, IS); | |
| 209 | void ARM::addPltHeaderSymbols(InputSection &isec) const { | |
| 210 | addSyntheticLocal("$a", STT_NOTYPE, 0, 0, isec); | |
| 211 | addSyntheticLocal("$d", STT_NOTYPE, 16, 0, isec); | |
| 214 | 212 | } |
| 215 | 213 | |
| 216 | 214 | // Long form PLT entries that do not have any restrictions on the displacement |
| 217 | 215 | // of the .plt from the .plt.got. |
| 218 | static void writePltLong(uint8_t *Buf, uint64_t GotPltEntryAddr, | |
| 219 | uint64_t PltEntryAddr, int32_t Index, | |
| 220 | unsigned RelOff) { | |
| 221 | const uint8_t PltData[] = { | |
| 216 | static void writePltLong(uint8_t *buf, uint64_t gotPltEntryAddr, | |
| 217 | uint64_t pltEntryAddr, int32_t index, | |
| 218 | unsigned relOff) { | |
| 219 | const uint8_t pltData[] = { | |
| 222 | 220 | 0x04, 0xc0, 0x9f, 0xe5, // ldr ip, L2 |
| 223 | 221 | 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc |
| 224 | 222 | 0x00, 0xf0, 0x9c, 0xe5, // ldr pc, [ip] |
| 225 | 223 | 0x00, 0x00, 0x00, 0x00, // L2: .word Offset(&(.plt.got) - L1 - 8 |
| 226 | 224 | }; |
| 227 | memcpy(Buf, PltData, sizeof(PltData)); | |
| 228 | uint64_t L1 = PltEntryAddr + 4; | |
| 229 | write32le(Buf + 12, GotPltEntryAddr - L1 - 8); | |
| 225 | memcpy(buf, pltData, sizeof(pltData)); | |
| 226 | uint64_t l1 = pltEntryAddr + 4; | |
| 227 | write32le(buf + 12, gotPltEntryAddr - l1 - 8); | |
| 230 | 228 | } |
| 231 | 229 | |
| 232 | 230 | // The default PLT entries require the .plt.got to be within 128 Mb of the |
| 233 | 231 | // .plt in the positive direction. |
| 234 | void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, | |
| 235 | uint64_t PltEntryAddr, int32_t Index, | |
| 236 | unsigned RelOff) const { | |
| 232 | void ARM::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, | |
| 233 | uint64_t pltEntryAddr, int32_t index, | |
| 234 | unsigned relOff) const { | |
| 237 | 235 | // The PLT entry is similar to the example given in Appendix A of ELF for |
| 238 | 236 | // the Arm Architecture. Instead of using the Group Relocations to find the |
| 239 | 237 | // optimal rotation for the 8-bit immediate used in the add instructions we |
| 240 | 238 | // hard code the most compact rotations for simplicity. This saves a load |
| 241 | 239 | // instruction over the long plt sequences. |
| 242 | const uint32_t PltData[] = { | |
| 240 | const uint32_t pltData[] = { | |
| 243 | 241 | 0xe28fc600, // L1: add ip, pc, #0x0NN00000 Offset(&(.plt.got) - L1 - 8 |
| 244 | 242 | 0xe28cca00, // add ip, ip, #0x000NN000 Offset(&(.plt.got) - L1 - 8 |
| 245 | 243 | 0xe5bcf000, // ldr pc, [ip, #0x00000NNN] Offset(&(.plt.got) - L1 - 8 |
| 246 | 244 | }; |
| 247 | 245 | |
| 248 | uint64_t Offset = GotPltEntryAddr - PltEntryAddr - 8; | |
| 249 | if (!llvm::isUInt<27>(Offset)) { | |
| 246 | uint64_t offset = gotPltEntryAddr - pltEntryAddr - 8; | |
| 247 | if (!llvm::isUInt<27>(offset)) { | |
| 250 | 248 | // We cannot encode the Offset, use the long form. |
| 251 | writePltLong(Buf, GotPltEntryAddr, PltEntryAddr, Index, RelOff); | |
| 249 | writePltLong(buf, gotPltEntryAddr, pltEntryAddr, index, relOff); | |
| 252 | 250 | return; |
| 253 | 251 | } |
| 254 | write32le(Buf + 0, PltData[0] | ((Offset >> 20) & 0xff)); | |
| 255 | write32le(Buf + 4, PltData[1] | ((Offset >> 12) & 0xff)); | |
| 256 | write32le(Buf + 8, PltData[2] | (Offset & 0xfff)); | |
| 257 | memcpy(Buf + 12, TrapInstr.data(), 4); // Pad to 16-byte boundary | |
| 252 | write32le(buf + 0, pltData[0] | ((offset >> 20) & 0xff)); | |
| 253 | write32le(buf + 4, pltData[1] | ((offset >> 12) & 0xff)); | |
| 254 | write32le(buf + 8, pltData[2] | (offset & 0xfff)); | |
| 255 | memcpy(buf + 12, trapInstr.data(), 4); // Pad to 16-byte boundary | |
| 258 | 256 | } |
| 259 | 257 | |
| 260 | void ARM::addPltSymbols(InputSection &IS, uint64_t Off) const { | |
| 261 | addSyntheticLocal("$a", STT_NOTYPE, Off, 0, IS); | |
| 262 | addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS); | |
| 258 | void ARM::addPltSymbols(InputSection &isec, uint64_t off) const { | |
| 259 | addSyntheticLocal("$a", STT_NOTYPE, off, 0, isec); | |
| 260 | addSyntheticLocal("$d", STT_NOTYPE, off + 12, 0, isec); | |
| 263 | 261 | } |
| 264 | 262 | |
| 265 | bool ARM::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, | |
| 266 | uint64_t BranchAddr, const Symbol &S) const { | |
| 263 | bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file, | |
| 264 | uint64_t branchAddr, const Symbol &s) const { | |
| 267 | 265 | // If S is an undefined weak symbol and does not have a PLT entry then it |
| 268 | 266 | // will be resolved as a branch to the next instruction. |
| 269 | if (S.isUndefWeak() && !S.isInPlt()) | |
| 267 | if (s.isUndefWeak() && !s.isInPlt()) | |
| 270 | 268 | return false; |
| 271 | 269 | // A state change from ARM to Thumb and vice versa must go through an |
| 272 | 270 | // interworking thunk if the relocation type is not R_ARM_CALL or |
| 273 | 271 | // R_ARM_THM_CALL. |
| 274 | switch (Type) { | |
| 272 | switch (type) { | |
| 275 | 273 | case R_ARM_PC24: |
| 276 | 274 | case R_ARM_PLT32: |
| 277 | 275 | case R_ARM_JUMP24: |
| 278 | 276 | // Source is ARM, all PLT entries are ARM so no interworking required. |
| 279 | 277 | // Otherwise we need to interwork if Symbol has bit 0 set (Thumb). |
| 280 | if (Expr == R_PC && ((S.getVA() & 1) == 1)) | |
| 278 | if (expr == R_PC && ((s.getVA() & 1) == 1)) | |
| 281 | 279 | return true; |
| 282 | 280 | LLVM_FALLTHROUGH; |
| 283 | 281 | case R_ARM_CALL: { |
| 284 | uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); | |
| 285 | return !inBranchRange(Type, BranchAddr, Dst); | |
| 282 | uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA() : s.getVA(); | |
| 283 | return !inBranchRange(type, branchAddr, dst); | |
| 286 | 284 | } |
| 287 | 285 | case R_ARM_THM_JUMP19: |
| 288 | 286 | case R_ARM_THM_JUMP24: |
| 289 | 287 | // Source is Thumb, all PLT entries are ARM so interworking is required. |
| 290 | 288 | // Otherwise we need to interwork if Symbol has bit 0 clear (ARM). |
| 291 | if (Expr == R_PLT_PC || ((S.getVA() & 1) == 0)) | |
| 289 | if (expr == R_PLT_PC || ((s.getVA() & 1) == 0)) | |
| 292 | 290 | return true; |
| 293 | 291 | LLVM_FALLTHROUGH; |
| 294 | 292 | case R_ARM_THM_CALL: { |
| 295 | uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); | |
| 296 | return !inBranchRange(Type, BranchAddr, Dst); | |
| 293 | uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA() : s.getVA(); | |
| 294 | return !inBranchRange(type, branchAddr, dst); | |
| 297 | 295 | } |
| 298 | 296 | } |
| 299 | 297 | return false; |
| ... | ... | @@ -301,13 +299,13 @@ bool ARM::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, |
| 301 | 299 | |
| 302 | 300 | uint32_t ARM::getThunkSectionSpacing() const { |
| 303 | 301 | // The placing of pre-created ThunkSections is controlled by the value |
| 304 | // ThunkSectionSpacing returned by getThunkSectionSpacing(). The aim is to | |
| 302 | // thunkSectionSpacing returned by getThunkSectionSpacing(). The aim is to | |
| 305 | 303 | // place the ThunkSection such that all branches from the InputSections |
| 306 | 304 | // prior to the ThunkSection can reach a Thunk placed at the end of the |
| 307 | 305 | // ThunkSection. Graphically: |
| 308 | // | up to ThunkSectionSpacing .text input sections | | |
| 306 | // | up to thunkSectionSpacing .text input sections | | |
| 309 | 307 | // | ThunkSection | |
| 310 | // | up to ThunkSectionSpacing .text input sections | | |
| 308 | // | up to thunkSectionSpacing .text input sections | | |
| 311 | 309 | // | ThunkSection | |
| 312 | 310 | |
| 313 | 311 | // Pre-created ThunkSections are spaced roughly 16MiB apart on ARMv7. This |
| ... | ... | @@ -318,69 +316,68 @@ uint32_t ARM::getThunkSectionSpacing() const { |
| 318 | 316 | // Thumb B<cc>.W range +/- 1MiB |
| 319 | 317 | // If a branch cannot reach a pre-created ThunkSection a new one will be |
| 320 | 318 | // created so we can handle the rare cases of a Thumb 2 conditional branch. |
| 321 | // We intentionally use a lower size for ThunkSectionSpacing than the maximum | |
| 319 | // We intentionally use a lower size for thunkSectionSpacing than the maximum | |
| 322 | 320 | // branch range so the end of the ThunkSection is more likely to be within |
| 323 | 321 | // range of the branch instruction that is furthest away. The value we shorten |
| 324 | // ThunkSectionSpacing by is set conservatively to allow us to create 16,384 | |
| 322 | // thunkSectionSpacing by is set conservatively to allow us to create 16,384 | |
| 325 | 323 | // 12 byte Thunks at any offset in a ThunkSection without risk of a branch to |
| 326 | 324 | // one of the Thunks going out of range. |
| 327 | 325 | |
| 328 | // On Arm the ThunkSectionSpacing depends on the range of the Thumb Branch | |
| 326 | // On Arm the thunkSectionSpacing depends on the range of the Thumb Branch | |
| 329 | 327 | // range. On earlier Architectures such as ARMv4, ARMv5 and ARMv6 (except |
| 330 | 328 | // ARMv6T2) the range is +/- 4MiB. |
| 331 | 329 | |
| 332 | return (Config->ARMJ1J2BranchEncoding) ? 0x1000000 - 0x30000 | |
| 330 | return (config->armJ1J2BranchEncoding) ? 0x1000000 - 0x30000 | |
| 333 | 331 | : 0x400000 - 0x7500; |
| 334 | 332 | } |
| 335 | 333 | |
| 336 | bool ARM::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { | |
| 337 | uint64_t Range; | |
| 338 | uint64_t InstrSize; | |
| 334 | bool ARM::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { | |
| 335 | uint64_t range; | |
| 336 | uint64_t instrSize; | |
| 339 | 337 | |
| 340 | switch (Type) { | |
| 338 | switch (type) { | |
| 341 | 339 | case R_ARM_PC24: |
| 342 | 340 | case R_ARM_PLT32: |
| 343 | 341 | case R_ARM_JUMP24: |
| 344 | 342 | case R_ARM_CALL: |
| 345 | Range = 0x2000000; | |
| 346 | InstrSize = 4; | |
| 343 | range = 0x2000000; | |
| 344 | instrSize = 4; | |
| 347 | 345 | break; |
| 348 | 346 | case R_ARM_THM_JUMP19: |
| 349 | Range = 0x100000; | |
| 350 | InstrSize = 2; | |
| 347 | range = 0x100000; | |
| 348 | instrSize = 2; | |
| 351 | 349 | break; |
| 352 | 350 | case R_ARM_THM_JUMP24: |
| 353 | 351 | case R_ARM_THM_CALL: |
| 354 | Range = Config->ARMJ1J2BranchEncoding ? 0x1000000 : 0x400000; | |
| 355 | InstrSize = 2; | |
| 352 | range = config->armJ1J2BranchEncoding ? 0x1000000 : 0x400000; | |
| 353 | instrSize = 2; | |
| 356 | 354 | break; |
| 357 | 355 | default: |
| 358 | 356 | return true; |
| 359 | 357 | } |
| 360 | 358 | // PC at Src is 2 instructions ahead, immediate of branch is signed |
| 361 | if (Src > Dst) | |
| 362 | Range -= 2 * InstrSize; | |
| 359 | if (src > dst) | |
| 360 | range -= 2 * instrSize; | |
| 363 | 361 | else |
| 364 | Range += InstrSize; | |
| 362 | range += instrSize; | |
| 365 | 363 | |
| 366 | if ((Dst & 0x1) == 0) | |
| 364 | if ((dst & 0x1) == 0) | |
| 367 | 365 | // Destination is ARM, if ARM caller then Src is already 4-byte aligned. |
| 368 | 366 | // If Thumb Caller (BLX) the Src address has bottom 2 bits cleared to ensure |
| 369 | 367 | // destination will be 4 byte aligned. |
| 370 | Src &= ~0x3; | |
| 368 | src &= ~0x3; | |
| 371 | 369 | else |
| 372 | 370 | // Bit 0 == 1 denotes Thumb state, it is not part of the range |
| 373 | Dst &= ~0x1; | |
| 371 | dst &= ~0x1; | |
| 374 | 372 | |
| 375 | uint64_t Distance = (Src > Dst) ? Src - Dst : Dst - Src; | |
| 376 | return Distance <= Range; | |
| 373 | uint64_t distance = (src > dst) ? src - dst : dst - src; | |
| 374 | return distance <= range; | |
| 377 | 375 | } |
| 378 | 376 | |
| 379 | void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 380 | switch (Type) { | |
| 377 | void ARM::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { | |
| 378 | switch (type) { | |
| 381 | 379 | case R_ARM_ABS32: |
| 382 | 380 | case R_ARM_BASE_PREL: |
| 383 | case R_ARM_GLOB_DAT: | |
| 384 | 381 | case R_ARM_GOTOFF32: |
| 385 | 382 | case R_ARM_GOT_BREL: |
| 386 | 383 | case R_ARM_GOT_PREL: |
| ... | ... | @@ -396,135 +393,132 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 396 | 393 | case R_ARM_TLS_LE32: |
| 397 | 394 | case R_ARM_TLS_TPOFF32: |
| 398 | 395 | case R_ARM_TLS_DTPOFF32: |
| 399 | write32le(Loc, Val); | |
| 400 | break; | |
| 401 | case R_ARM_TLS_DTPMOD32: | |
| 402 | write32le(Loc, 1); | |
| 396 | write32le(loc, val); | |
| 403 | 397 | break; |
| 404 | 398 | case R_ARM_PREL31: |
| 405 | checkInt(Loc, Val, 31, Type); | |
| 406 | write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000)); | |
| 399 | checkInt(loc, val, 31, type); | |
| 400 | write32le(loc, (read32le(loc) & 0x80000000) | (val & ~0x80000000)); | |
| 407 | 401 | break; |
| 408 | 402 | case R_ARM_CALL: |
| 409 | 403 | // R_ARM_CALL is used for BL and BLX instructions, depending on the |
| 410 | 404 | // value of bit 0 of Val, we must select a BL or BLX instruction |
| 411 | if (Val & 1) { | |
| 405 | if (val & 1) { | |
| 412 | 406 | // If bit 0 of Val is 1 the target is Thumb, we must select a BLX. |
| 413 | 407 | // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1' |
| 414 | checkInt(Loc, Val, 26, Type); | |
| 415 | write32le(Loc, 0xfa000000 | // opcode | |
| 416 | ((Val & 2) << 23) | // H | |
| 417 | ((Val >> 2) & 0x00ffffff)); // imm24 | |
| 408 | checkInt(loc, val, 26, type); | |
| 409 | write32le(loc, 0xfa000000 | // opcode | |
| 410 | ((val & 2) << 23) | // H | |
| 411 | ((val >> 2) & 0x00ffffff)); // imm24 | |
| 418 | 412 | break; |
| 419 | 413 | } |
| 420 | if ((read32le(Loc) & 0xfe000000) == 0xfa000000) | |
| 414 | if ((read32le(loc) & 0xfe000000) == 0xfa000000) | |
| 421 | 415 | // BLX (always unconditional) instruction to an ARM Target, select an |
| 422 | 416 | // unconditional BL. |
| 423 | write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff)); | |
| 417 | write32le(loc, 0xeb000000 | (read32le(loc) & 0x00ffffff)); | |
| 424 | 418 | // fall through as BL encoding is shared with B |
| 425 | 419 | LLVM_FALLTHROUGH; |
| 426 | 420 | case R_ARM_JUMP24: |
| 427 | 421 | case R_ARM_PC24: |
| 428 | 422 | case R_ARM_PLT32: |
| 429 | checkInt(Loc, Val, 26, Type); | |
| 430 | write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff)); | |
| 423 | checkInt(loc, val, 26, type); | |
| 424 | write32le(loc, (read32le(loc) & ~0x00ffffff) | ((val >> 2) & 0x00ffffff)); | |
| 431 | 425 | break; |
| 432 | 426 | case R_ARM_THM_JUMP11: |
| 433 | checkInt(Loc, Val, 12, Type); | |
| 434 | write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff)); | |
| 427 | checkInt(loc, val, 12, type); | |
| 428 | write16le(loc, (read32le(loc) & 0xf800) | ((val >> 1) & 0x07ff)); | |
| 435 | 429 | break; |
| 436 | 430 | case R_ARM_THM_JUMP19: |
| 437 | 431 | // Encoding T3: Val = S:J2:J1:imm6:imm11:0 |
| 438 | checkInt(Loc, Val, 21, Type); | |
| 439 | write16le(Loc, | |
| 440 | (read16le(Loc) & 0xfbc0) | // opcode cond | |
| 441 | ((Val >> 10) & 0x0400) | // S | |
| 442 | ((Val >> 12) & 0x003f)); // imm6 | |
| 443 | write16le(Loc + 2, | |
| 432 | checkInt(loc, val, 21, type); | |
| 433 | write16le(loc, | |
| 434 | (read16le(loc) & 0xfbc0) | // opcode cond | |
| 435 | ((val >> 10) & 0x0400) | // S | |
| 436 | ((val >> 12) & 0x003f)); // imm6 | |
| 437 | write16le(loc + 2, | |
| 444 | 438 | 0x8000 | // opcode |
| 445 | ((Val >> 8) & 0x0800) | // J2 | |
| 446 | ((Val >> 5) & 0x2000) | // J1 | |
| 447 | ((Val >> 1) & 0x07ff)); // imm11 | |
| 439 | ((val >> 8) & 0x0800) | // J2 | |
| 440 | ((val >> 5) & 0x2000) | // J1 | |
| 441 | ((val >> 1) & 0x07ff)); // imm11 | |
| 448 | 442 | break; |
| 449 | 443 | case R_ARM_THM_CALL: |
| 450 | 444 | // R_ARM_THM_CALL is used for BL and BLX instructions, depending on the |
| 451 | 445 | // value of bit 0 of Val, we must select a BL or BLX instruction |
| 452 | if ((Val & 1) == 0) { | |
| 446 | if ((val & 1) == 0) { | |
| 453 | 447 | // Ensure BLX destination is 4-byte aligned. As BLX instruction may |
| 454 | 448 | // only be two byte aligned. This must be done before overflow check |
| 455 | Val = alignTo(Val, 4); | |
| 449 | val = alignTo(val, 4); | |
| 456 | 450 | } |
| 457 | 451 | // Bit 12 is 0 for BLX, 1 for BL |
| 458 | write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12); | |
| 459 | if (!Config->ARMJ1J2BranchEncoding) { | |
| 452 | write16le(loc + 2, (read16le(loc + 2) & ~0x1000) | (val & 1) << 12); | |
| 453 | if (!config->armJ1J2BranchEncoding) { | |
| 460 | 454 | // Older Arm architectures do not support R_ARM_THM_JUMP24 and have |
| 461 | 455 | // different encoding rules and range due to J1 and J2 always being 1. |
| 462 | checkInt(Loc, Val, 23, Type); | |
| 463 | write16le(Loc, | |
| 456 | checkInt(loc, val, 23, type); | |
| 457 | write16le(loc, | |
| 464 | 458 | 0xf000 | // opcode |
| 465 | ((Val >> 12) & 0x07ff)); // imm11 | |
| 466 | write16le(Loc + 2, | |
| 467 | (read16le(Loc + 2) & 0xd000) | // opcode | |
| 459 | ((val >> 12) & 0x07ff)); // imm11 | |
| 460 | write16le(loc + 2, | |
| 461 | (read16le(loc + 2) & 0xd000) | // opcode | |
| 468 | 462 | 0x2800 | // J1 == J2 == 1 |
| 469 | ((Val >> 1) & 0x07ff)); // imm11 | |
| 463 | ((val >> 1) & 0x07ff)); // imm11 | |
| 470 | 464 | break; |
| 471 | 465 | } |
| 472 | 466 | // Fall through as rest of encoding is the same as B.W |
| 473 | 467 | LLVM_FALLTHROUGH; |
| 474 | 468 | case R_ARM_THM_JUMP24: |
| 475 | 469 | // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0 |
| 476 | checkInt(Loc, Val, 25, Type); | |
| 477 | write16le(Loc, | |
| 470 | checkInt(loc, val, 25, type); | |
| 471 | write16le(loc, | |
| 478 | 472 | 0xf000 | // opcode |
| 479 | ((Val >> 14) & 0x0400) | // S | |
| 480 | ((Val >> 12) & 0x03ff)); // imm10 | |
| 481 | write16le(Loc + 2, | |
| 482 | (read16le(Loc + 2) & 0xd000) | // opcode | |
| 483 | (((~(Val >> 10)) ^ (Val >> 11)) & 0x2000) | // J1 | |
| 484 | (((~(Val >> 11)) ^ (Val >> 13)) & 0x0800) | // J2 | |
| 485 | ((Val >> 1) & 0x07ff)); // imm11 | |
| 473 | ((val >> 14) & 0x0400) | // S | |
| 474 | ((val >> 12) & 0x03ff)); // imm10 | |
| 475 | write16le(loc + 2, | |
| 476 | (read16le(loc + 2) & 0xd000) | // opcode | |
| 477 | (((~(val >> 10)) ^ (val >> 11)) & 0x2000) | // J1 | |
| 478 | (((~(val >> 11)) ^ (val >> 13)) & 0x0800) | // J2 | |
| 479 | ((val >> 1) & 0x07ff)); // imm11 | |
| 486 | 480 | break; |
| 487 | 481 | case R_ARM_MOVW_ABS_NC: |
| 488 | 482 | case R_ARM_MOVW_PREL_NC: |
| 489 | write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) | | |
| 490 | (Val & 0x0fff)); | |
| 483 | write32le(loc, (read32le(loc) & ~0x000f0fff) | ((val & 0xf000) << 4) | | |
| 484 | (val & 0x0fff)); | |
| 491 | 485 | break; |
| 492 | 486 | case R_ARM_MOVT_ABS: |
| 493 | 487 | case R_ARM_MOVT_PREL: |
| 494 | write32le(Loc, (read32le(Loc) & ~0x000f0fff) | | |
| 495 | (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff)); | |
| 488 | write32le(loc, (read32le(loc) & ~0x000f0fff) | | |
| 489 | (((val >> 16) & 0xf000) << 4) | ((val >> 16) & 0xfff)); | |
| 496 | 490 | break; |
| 497 | 491 | case R_ARM_THM_MOVT_ABS: |
| 498 | 492 | case R_ARM_THM_MOVT_PREL: |
| 499 | 493 | // Encoding T1: A = imm4:i:imm3:imm8 |
| 500 | write16le(Loc, | |
| 494 | write16le(loc, | |
| 501 | 495 | 0xf2c0 | // opcode |
| 502 | ((Val >> 17) & 0x0400) | // i | |
| 503 | ((Val >> 28) & 0x000f)); // imm4 | |
| 504 | write16le(Loc + 2, | |
| 505 | (read16le(Loc + 2) & 0x8f00) | // opcode | |
| 506 | ((Val >> 12) & 0x7000) | // imm3 | |
| 507 | ((Val >> 16) & 0x00ff)); // imm8 | |
| 496 | ((val >> 17) & 0x0400) | // i | |
| 497 | ((val >> 28) & 0x000f)); // imm4 | |
| 498 | write16le(loc + 2, | |
| 499 | (read16le(loc + 2) & 0x8f00) | // opcode | |
| 500 | ((val >> 12) & 0x7000) | // imm3 | |
| 501 | ((val >> 16) & 0x00ff)); // imm8 | |
| 508 | 502 | break; |
| 509 | 503 | case R_ARM_THM_MOVW_ABS_NC: |
| 510 | 504 | case R_ARM_THM_MOVW_PREL_NC: |
| 511 | 505 | // Encoding T3: A = imm4:i:imm3:imm8 |
| 512 | write16le(Loc, | |
| 506 | write16le(loc, | |
| 513 | 507 | 0xf240 | // opcode |
| 514 | ((Val >> 1) & 0x0400) | // i | |
| 515 | ((Val >> 12) & 0x000f)); // imm4 | |
| 516 | write16le(Loc + 2, | |
| 517 | (read16le(Loc + 2) & 0x8f00) | // opcode | |
| 518 | ((Val << 4) & 0x7000) | // imm3 | |
| 519 | (Val & 0x00ff)); // imm8 | |
| 508 | ((val >> 1) & 0x0400) | // i | |
| 509 | ((val >> 12) & 0x000f)); // imm4 | |
| 510 | write16le(loc + 2, | |
| 511 | (read16le(loc + 2) & 0x8f00) | // opcode | |
| 512 | ((val << 4) & 0x7000) | // imm3 | |
| 513 | (val & 0x00ff)); // imm8 | |
| 520 | 514 | break; |
| 521 | 515 | default: |
| 522 | error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); | |
| 516 | error(getErrorLocation(loc) + "unrecognized relocation " + toString(type)); | |
| 523 | 517 | } |
| 524 | 518 | } |
| 525 | 519 | |
| 526 | int64_t ARM::getImplicitAddend(const uint8_t *Buf, RelType Type) const { | |
| 527 | switch (Type) { | |
| 520 | int64_t ARM::getImplicitAddend(const uint8_t *buf, RelType type) const { | |
| 521 | switch (type) { | |
| 528 | 522 | default: |
| 529 | 523 | return 0; |
| 530 | 524 | case R_ARM_ABS32: |
| ... | ... | @@ -540,47 +534,47 @@ int64_t ARM::getImplicitAddend(const uint8_t *Buf, RelType Type) const { |
| 540 | 534 | case R_ARM_TLS_LDO32: |
| 541 | 535 | case R_ARM_TLS_IE32: |
| 542 | 536 | case R_ARM_TLS_LE32: |
| 543 | return SignExtend64<32>(read32le(Buf)); | |
| 537 | return SignExtend64<32>(read32le(buf)); | |
| 544 | 538 | case R_ARM_PREL31: |
| 545 | return SignExtend64<31>(read32le(Buf)); | |
| 539 | return SignExtend64<31>(read32le(buf)); | |
| 546 | 540 | case R_ARM_CALL: |
| 547 | 541 | case R_ARM_JUMP24: |
| 548 | 542 | case R_ARM_PC24: |
| 549 | 543 | case R_ARM_PLT32: |
| 550 | return SignExtend64<26>(read32le(Buf) << 2); | |
| 544 | return SignExtend64<26>(read32le(buf) << 2); | |
| 551 | 545 | case R_ARM_THM_JUMP11: |
| 552 | return SignExtend64<12>(read16le(Buf) << 1); | |
| 546 | return SignExtend64<12>(read16le(buf) << 1); | |
| 553 | 547 | case R_ARM_THM_JUMP19: { |
| 554 | 548 | // Encoding T3: A = S:J2:J1:imm10:imm6:0 |
| 555 | uint16_t Hi = read16le(Buf); | |
| 556 | uint16_t Lo = read16le(Buf + 2); | |
| 557 | return SignExtend64<20>(((Hi & 0x0400) << 10) | // S | |
| 558 | ((Lo & 0x0800) << 8) | // J2 | |
| 559 | ((Lo & 0x2000) << 5) | // J1 | |
| 560 | ((Hi & 0x003f) << 12) | // imm6 | |
| 561 | ((Lo & 0x07ff) << 1)); // imm11:0 | |
| 549 | uint16_t hi = read16le(buf); | |
| 550 | uint16_t lo = read16le(buf + 2); | |
| 551 | return SignExtend64<20>(((hi & 0x0400) << 10) | // S | |
| 552 | ((lo & 0x0800) << 8) | // J2 | |
| 553 | ((lo & 0x2000) << 5) | // J1 | |
| 554 | ((hi & 0x003f) << 12) | // imm6 | |
| 555 | ((lo & 0x07ff) << 1)); // imm11:0 | |
| 562 | 556 | } |
| 563 | 557 | case R_ARM_THM_CALL: |
| 564 | if (!Config->ARMJ1J2BranchEncoding) { | |
| 558 | if (!config->armJ1J2BranchEncoding) { | |
| 565 | 559 | // Older Arm architectures do not support R_ARM_THM_JUMP24 and have |
| 566 | 560 | // different encoding rules and range due to J1 and J2 always being 1. |
| 567 | uint16_t Hi = read16le(Buf); | |
| 568 | uint16_t Lo = read16le(Buf + 2); | |
| 569 | return SignExtend64<22>(((Hi & 0x7ff) << 12) | // imm11 | |
| 570 | ((Lo & 0x7ff) << 1)); // imm11:0 | |
| 561 | uint16_t hi = read16le(buf); | |
| 562 | uint16_t lo = read16le(buf + 2); | |
| 563 | return SignExtend64<22>(((hi & 0x7ff) << 12) | // imm11 | |
| 564 | ((lo & 0x7ff) << 1)); // imm11:0 | |
| 571 | 565 | break; |
| 572 | 566 | } |
| 573 | 567 | LLVM_FALLTHROUGH; |
| 574 | 568 | case R_ARM_THM_JUMP24: { |
| 575 | 569 | // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0 |
| 576 | 570 | // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S) |
| 577 | uint16_t Hi = read16le(Buf); | |
| 578 | uint16_t Lo = read16le(Buf + 2); | |
| 579 | return SignExtend64<24>(((Hi & 0x0400) << 14) | // S | |
| 580 | (~((Lo ^ (Hi << 3)) << 10) & 0x00800000) | // I1 | |
| 581 | (~((Lo ^ (Hi << 1)) << 11) & 0x00400000) | // I2 | |
| 582 | ((Hi & 0x003ff) << 12) | // imm0 | |
| 583 | ((Lo & 0x007ff) << 1)); // imm11:0 | |
| 571 | uint16_t hi = read16le(buf); | |
| 572 | uint16_t lo = read16le(buf + 2); | |
| 573 | return SignExtend64<24>(((hi & 0x0400) << 14) | // S | |
| 574 | (~((lo ^ (hi << 3)) << 10) & 0x00800000) | // I1 | |
| 575 | (~((lo ^ (hi << 1)) << 11) & 0x00400000) | // I2 | |
| 576 | ((hi & 0x003ff) << 12) | // imm0 | |
| 577 | ((lo & 0x007ff) << 1)); // imm11:0 | |
| 584 | 578 | } |
| 585 | 579 | // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and |
| 586 | 580 | // MOVT is in the range -32768 <= A < 32768 |
| ... | ... | @@ -588,25 +582,25 @@ int64_t ARM::getImplicitAddend(const uint8_t *Buf, RelType Type) const { |
| 588 | 582 | case R_ARM_MOVT_ABS: |
| 589 | 583 | case R_ARM_MOVW_PREL_NC: |
| 590 | 584 | case R_ARM_MOVT_PREL: { |
| 591 | uint64_t Val = read32le(Buf) & 0x000f0fff; | |
| 592 | return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff)); | |
| 585 | uint64_t val = read32le(buf) & 0x000f0fff; | |
| 586 | return SignExtend64<16>(((val & 0x000f0000) >> 4) | (val & 0x00fff)); | |
| 593 | 587 | } |
| 594 | 588 | case R_ARM_THM_MOVW_ABS_NC: |
| 595 | 589 | case R_ARM_THM_MOVT_ABS: |
| 596 | 590 | case R_ARM_THM_MOVW_PREL_NC: |
| 597 | 591 | case R_ARM_THM_MOVT_PREL: { |
| 598 | 592 | // Encoding T3: A = imm4:i:imm3:imm8 |
| 599 | uint16_t Hi = read16le(Buf); | |
| 600 | uint16_t Lo = read16le(Buf + 2); | |
| 601 | return SignExtend64<16>(((Hi & 0x000f) << 12) | // imm4 | |
| 602 | ((Hi & 0x0400) << 1) | // i | |
| 603 | ((Lo & 0x7000) >> 4) | // imm3 | |
| 604 | (Lo & 0x00ff)); // imm8 | |
| 593 | uint16_t hi = read16le(buf); | |
| 594 | uint16_t lo = read16le(buf + 2); | |
| 595 | return SignExtend64<16>(((hi & 0x000f) << 12) | // imm4 | |
| 596 | ((hi & 0x0400) << 1) | // i | |
| 597 | ((lo & 0x7000) >> 4) | // imm3 | |
| 598 | (lo & 0x00ff)); // imm8 | |
| 605 | 599 | } |
| 606 | 600 | } |
| 607 | 601 | } |
| 608 | 602 | |
| 609 | 603 | TargetInfo *elf::getARMTargetInfo() { |
| 610 | static ARM Target; | |
| 611 | return &Target; | |
| 604 | static ARM target; | |
| 605 | return &target; | |
| 612 | 606 | } |
deps/lld/ELF/Arch/AVR.cpp+18-19| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- AVR.cpp ------------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -44,34 +43,34 @@ namespace { |
| 44 | 43 | class AVR final : public TargetInfo { |
| 45 | 44 | public: |
| 46 | 45 | AVR(); |
| 47 | RelExpr getRelExpr(RelType Type, const Symbol &S, | |
| 48 | const uint8_t *Loc) const override; | |
| 49 | void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 46 | RelExpr getRelExpr(RelType type, const Symbol &s, | |
| 47 | const uint8_t *loc) const override; | |
| 48 | void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 50 | 49 | }; |
| 51 | 50 | } // namespace |
| 52 | 51 | |
| 53 | AVR::AVR() { NoneRel = R_AVR_NONE; } | |
| 52 | AVR::AVR() { noneRel = R_AVR_NONE; } | |
| 54 | 53 | |
| 55 | RelExpr AVR::getRelExpr(RelType Type, const Symbol &S, | |
| 56 | const uint8_t *Loc) const { | |
| 54 | RelExpr AVR::getRelExpr(RelType type, const Symbol &s, | |
| 55 | const uint8_t *loc) const { | |
| 57 | 56 | return R_ABS; |
| 58 | 57 | } |
| 59 | 58 | |
| 60 | void AVR::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 61 | switch (Type) { | |
| 59 | void AVR::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { | |
| 60 | switch (type) { | |
| 62 | 61 | case R_AVR_CALL: { |
| 63 | uint16_t Hi = Val >> 17; | |
| 64 | uint16_t Lo = Val >> 1; | |
| 65 | write16le(Loc, read16le(Loc) | ((Hi >> 1) << 4) | (Hi & 1)); | |
| 66 | write16le(Loc + 2, Lo); | |
| 62 | uint16_t hi = val >> 17; | |
| 63 | uint16_t lo = val >> 1; | |
| 64 | write16le(loc, read16le(loc) | ((hi >> 1) << 4) | (hi & 1)); | |
| 65 | write16le(loc + 2, lo); | |
| 67 | 66 | break; |
| 68 | 67 | } |
| 69 | 68 | default: |
| 70 | error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type)); | |
| 69 | error(getErrorLocation(loc) + "unrecognized relocation " + toString(type)); | |
| 71 | 70 | } |
| 72 | 71 | } |
| 73 | 72 | |
| 74 | 73 | TargetInfo *elf::getAVRTargetInfo() { |
| 75 | static AVR Target; | |
| 76 | return &Target; | |
| 74 | static AVR target; | |
| 75 | return &target; | |
| 77 | 76 | } |
deps/lld/ELF/Arch/Hexagon.cpp+97-98| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===-- Hexagon.cpp -------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -28,65 +27,65 @@ class Hexagon final : public TargetInfo { |
| 28 | 27 | public: |
| 29 | 28 | Hexagon(); |
| 30 | 29 | uint32_t calcEFlags() const override; |
| 31 | RelExpr getRelExpr(RelType Type, const Symbol &S, | |
| 32 | const uint8_t *Loc) const override; | |
| 33 | void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 34 | void writePltHeader(uint8_t *Buf) const override; | |
| 35 | void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, | |
| 36 | int32_t Index, unsigned RelOff) const override; | |
| 30 | RelExpr getRelExpr(RelType type, const Symbol &s, | |
| 31 | const uint8_t *loc) const override; | |
| 32 | void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 33 | void writePltHeader(uint8_t *buf) const override; | |
| 34 | void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, | |
| 35 | int32_t index, unsigned relOff) const override; | |
| 37 | 36 | }; |
| 38 | 37 | } // namespace |
| 39 | 38 | |
| 40 | 39 | Hexagon::Hexagon() { |
| 41 | PltRel = R_HEX_JMP_SLOT; | |
| 42 | RelativeRel = R_HEX_RELATIVE; | |
| 43 | GotRel = R_HEX_GLOB_DAT; | |
| 44 | GotEntrySize = 4; | |
| 40 | pltRel = R_HEX_JMP_SLOT; | |
| 41 | relativeRel = R_HEX_RELATIVE; | |
| 42 | gotRel = R_HEX_GLOB_DAT; | |
| 43 | symbolicRel = R_HEX_32; | |
| 44 | ||
| 45 | 45 | // The zero'th GOT entry is reserved for the address of _DYNAMIC. The |
| 46 | 46 | // next 3 are reserved for the dynamic loader. |
| 47 | GotPltHeaderEntriesNum = 4; | |
| 48 | GotPltEntrySize = 4; | |
| 47 | gotPltHeaderEntriesNum = 4; | |
| 49 | 48 | |
| 50 | PltEntrySize = 16; | |
| 51 | PltHeaderSize = 32; | |
| 49 | pltEntrySize = 16; | |
| 50 | pltHeaderSize = 32; | |
| 52 | 51 | |
| 53 | 52 | // Hexagon Linux uses 64K pages by default. |
| 54 | DefaultMaxPageSize = 0x10000; | |
| 55 | NoneRel = R_HEX_NONE; | |
| 53 | defaultMaxPageSize = 0x10000; | |
| 54 | noneRel = R_HEX_NONE; | |
| 56 | 55 | } |
| 57 | 56 | |
| 58 | 57 | uint32_t Hexagon::calcEFlags() const { |
| 59 | assert(!ObjectFiles.empty()); | |
| 58 | assert(!objectFiles.empty()); | |
| 60 | 59 | |
| 61 | 60 | // The architecture revision must always be equal to or greater than |
| 62 | 61 | // greatest revision in the list of inputs. |
| 63 | uint32_t Ret = 0; | |
| 64 | for (InputFile *F : ObjectFiles) { | |
| 65 | uint32_t EFlags = cast<ObjFile<ELF32LE>>(F)->getObj().getHeader()->e_flags; | |
| 66 | if (EFlags > Ret) | |
| 67 | Ret = EFlags; | |
| 62 | uint32_t ret = 0; | |
| 63 | for (InputFile *f : objectFiles) { | |
| 64 | uint32_t eflags = cast<ObjFile<ELF32LE>>(f)->getObj().getHeader()->e_flags; | |
| 65 | if (eflags > ret) | |
| 66 | ret = eflags; | |
| 68 | 67 | } |
| 69 | return Ret; | |
| 68 | return ret; | |
| 70 | 69 | } |
| 71 | 70 | |
| 72 | static uint32_t applyMask(uint32_t Mask, uint32_t Data) { | |
| 73 | uint32_t Result = 0; | |
| 74 | size_t Off = 0; | |
| 71 | static uint32_t applyMask(uint32_t mask, uint32_t data) { | |
| 72 | uint32_t result = 0; | |
| 73 | size_t off = 0; | |
| 75 | 74 | |
| 76 | for (size_t Bit = 0; Bit != 32; ++Bit) { | |
| 77 | uint32_t ValBit = (Data >> Off) & 1; | |
| 78 | uint32_t MaskBit = (Mask >> Bit) & 1; | |
| 79 | if (MaskBit) { | |
| 80 | Result |= (ValBit << Bit); | |
| 81 | ++Off; | |
| 75 | for (size_t bit = 0; bit != 32; ++bit) { | |
| 76 | uint32_t valBit = (data >> off) & 1; | |
| 77 | uint32_t maskBit = (mask >> bit) & 1; | |
| 78 | if (maskBit) { | |
| 79 | result |= (valBit << bit); | |
| 80 | ++off; | |
| 82 | 81 | } |
| 83 | 82 | } |
| 84 | return Result; | |
| 83 | return result; | |
| 85 | 84 | } |
| 86 | 85 | |
| 87 | RelExpr Hexagon::getRelExpr(RelType Type, const Symbol &S, | |
| 88 | const uint8_t *Loc) const { | |
| 89 | switch (Type) { | |
| 86 | RelExpr Hexagon::getRelExpr(RelType type, const Symbol &s, | |
| 87 | const uint8_t *loc) const { | |
| 88 | switch (type) { | |
| 90 | 89 | case R_HEX_B9_PCREL: |
| 91 | 90 | case R_HEX_B9_PCREL_X: |
| 92 | 91 | case R_HEX_B13_PCREL: |
| ... | ... | @@ -109,16 +108,16 @@ RelExpr Hexagon::getRelExpr(RelType Type, const Symbol &S, |
| 109 | 108 | } |
| 110 | 109 | } |
| 111 | 110 | |
| 112 | static uint32_t findMaskR6(uint32_t Insn) { | |
| 111 | static uint32_t findMaskR6(uint32_t insn) { | |
| 113 | 112 | // There are (arguably too) many relocation masks for the DSP's |
| 114 | 113 | // R_HEX_6_X type. The table below is used to select the correct mask |
| 115 | 114 | // for the given instruction. |
| 116 | 115 | struct InstructionMask { |
| 117 | uint32_t CmpMask; | |
| 118 | uint32_t RelocMask; | |
| 116 | uint32_t cmpMask; | |
| 117 | uint32_t relocMask; | |
| 119 | 118 | }; |
| 120 | 119 | |
| 121 | static const InstructionMask R6[] = { | |
| 120 | static const InstructionMask r6[] = { | |
| 122 | 121 | {0x38000000, 0x0000201f}, {0x39000000, 0x0000201f}, |
| 123 | 122 | {0x3e000000, 0x00001f80}, {0x3f000000, 0x00001f80}, |
| 124 | 123 | {0x40000000, 0x000020f8}, {0x41000000, 0x000007e0}, |
| ... | ... | @@ -136,124 +135,124 @@ static uint32_t findMaskR6(uint32_t Insn) { |
| 136 | 135 | // Duplex forms have a fixed mask and parse bits 15:14 are always |
| 137 | 136 | // zero. Non-duplex insns will always have at least one bit set in the |
| 138 | 137 | // parse field. |
| 139 | if ((0xC000 & Insn) == 0x0) | |
| 138 | if ((0xC000 & insn) == 0x0) | |
| 140 | 139 | return 0x03f00000; |
| 141 | 140 | |
| 142 | for (InstructionMask I : R6) | |
| 143 | if ((0xff000000 & Insn) == I.CmpMask) | |
| 144 | return I.RelocMask; | |
| 141 | for (InstructionMask i : r6) | |
| 142 | if ((0xff000000 & insn) == i.cmpMask) | |
| 143 | return i.relocMask; | |
| 145 | 144 | |
| 146 | 145 | error("unrecognized instruction for R_HEX_6 relocation: 0x" + |
| 147 | utohexstr(Insn)); | |
| 146 | utohexstr(insn)); | |
| 148 | 147 | return 0; |
| 149 | 148 | } |
| 150 | 149 | |
| 151 | static uint32_t findMaskR8(uint32_t Insn) { | |
| 152 | if ((0xff000000 & Insn) == 0xde000000) | |
| 150 | static uint32_t findMaskR8(uint32_t insn) { | |
| 151 | if ((0xff000000 & insn) == 0xde000000) | |
| 153 | 152 | return 0x00e020e8; |
| 154 | if ((0xff000000 & Insn) == 0x3c000000) | |
| 153 | if ((0xff000000 & insn) == 0x3c000000) | |
| 155 | 154 | return 0x0000207f; |
| 156 | 155 | return 0x00001fe0; |
| 157 | 156 | } |
| 158 | 157 | |
| 159 | static uint32_t findMaskR11(uint32_t Insn) { | |
| 160 | if ((0xff000000 & Insn) == 0xa1000000) | |
| 158 | static uint32_t findMaskR11(uint32_t insn) { | |
| 159 | if ((0xff000000 & insn) == 0xa1000000) | |
| 161 | 160 | return 0x060020ff; |
| 162 | 161 | return 0x06003fe0; |
| 163 | 162 | } |
| 164 | 163 | |
| 165 | static uint32_t findMaskR16(uint32_t Insn) { | |
| 166 | if ((0xff000000 & Insn) == 0x48000000) | |
| 164 | static uint32_t findMaskR16(uint32_t insn) { | |
| 165 | if ((0xff000000 & insn) == 0x48000000) | |
| 167 | 166 | return 0x061f20ff; |
| 168 | if ((0xff000000 & Insn) == 0x49000000) | |
| 167 | if ((0xff000000 & insn) == 0x49000000) | |
| 169 | 168 | return 0x061f3fe0; |
| 170 | if ((0xff000000 & Insn) == 0x78000000) | |
| 169 | if ((0xff000000 & insn) == 0x78000000) | |
| 171 | 170 | return 0x00df3fe0; |
| 172 | if ((0xff000000 & Insn) == 0xb0000000) | |
| 171 | if ((0xff000000 & insn) == 0xb0000000) | |
| 173 | 172 | return 0x0fe03fe0; |
| 174 | 173 | |
| 175 | 174 | error("unrecognized instruction for R_HEX_16_X relocation: 0x" + |
| 176 | utohexstr(Insn)); | |
| 175 | utohexstr(insn)); | |
| 177 | 176 | return 0; |
| 178 | 177 | } |
| 179 | 178 | |
| 180 | static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); } | |
| 179 | static void or32le(uint8_t *p, int32_t v) { write32le(p, read32le(p) | v); } | |
| 181 | 180 | |
| 182 | void Hexagon::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 183 | switch (Type) { | |
| 181 | void Hexagon::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { | |
| 182 | switch (type) { | |
| 184 | 183 | case R_HEX_NONE: |
| 185 | 184 | break; |
| 186 | 185 | case R_HEX_6_PCREL_X: |
| 187 | 186 | case R_HEX_6_X: |
| 188 | or32le(Loc, applyMask(findMaskR6(read32le(Loc)), Val)); | |
| 187 | or32le(loc, applyMask(findMaskR6(read32le(loc)), val)); | |
| 189 | 188 | break; |
| 190 | 189 | case R_HEX_8_X: |
| 191 | or32le(Loc, applyMask(findMaskR8(read32le(Loc)), Val)); | |
| 190 | or32le(loc, applyMask(findMaskR8(read32le(loc)), val)); | |
| 192 | 191 | break; |
| 193 | 192 | case R_HEX_9_X: |
| 194 | or32le(Loc, applyMask(0x00003fe0, Val & 0x3f)); | |
| 193 | or32le(loc, applyMask(0x00003fe0, val & 0x3f)); | |
| 195 | 194 | break; |
| 196 | 195 | case R_HEX_10_X: |
| 197 | or32le(Loc, applyMask(0x00203fe0, Val & 0x3f)); | |
| 196 | or32le(loc, applyMask(0x00203fe0, val & 0x3f)); | |
| 198 | 197 | break; |
| 199 | 198 | case R_HEX_11_X: |
| 200 | 199 | case R_HEX_GOT_11_X: |
| 201 | or32le(Loc, applyMask(findMaskR11(read32le(Loc)), Val & 0x3f)); | |
| 200 | or32le(loc, applyMask(findMaskR11(read32le(loc)), val & 0x3f)); | |
| 202 | 201 | break; |
| 203 | 202 | case R_HEX_12_X: |
| 204 | or32le(Loc, applyMask(0x000007e0, Val)); | |
| 203 | or32le(loc, applyMask(0x000007e0, val)); | |
| 205 | 204 | break; |
| 206 | 205 | case R_HEX_16_X: // These relocs only have 6 effective bits. |
| 207 | 206 | case R_HEX_GOT_16_X: |
| 208 | or32le(Loc, applyMask(findMaskR16(read32le(Loc)), Val & 0x3f)); | |
| 207 | or32le(loc, applyMask(findMaskR16(read32le(loc)), val & 0x3f)); | |
| 209 | 208 | break; |
| 210 | 209 | case R_HEX_32: |
| 211 | 210 | case R_HEX_32_PCREL: |
| 212 | or32le(Loc, Val); | |
| 211 | or32le(loc, val); | |
| 213 | 212 | break; |
| 214 | 213 | case R_HEX_32_6_X: |
| 215 | 214 | case R_HEX_GOT_32_6_X: |
| 216 | or32le(Loc, applyMask(0x0fff3fff, Val >> 6)); | |
| 215 | or32le(loc, applyMask(0x0fff3fff, val >> 6)); | |
| 217 | 216 | break; |
| 218 | 217 | case R_HEX_B9_PCREL: |
| 219 | or32le(Loc, applyMask(0x003000fe, Val >> 2)); | |
| 218 | or32le(loc, applyMask(0x003000fe, val >> 2)); | |
| 220 | 219 | break; |
| 221 | 220 | case R_HEX_B9_PCREL_X: |
| 222 | or32le(Loc, applyMask(0x003000fe, Val & 0x3f)); | |
| 221 | or32le(loc, applyMask(0x003000fe, val & 0x3f)); | |
| 223 | 222 | break; |
| 224 | 223 | case R_HEX_B13_PCREL: |
| 225 | or32le(Loc, applyMask(0x00202ffe, Val >> 2)); | |
| 224 | or32le(loc, applyMask(0x00202ffe, val >> 2)); | |
| 226 | 225 | break; |
| 227 | 226 | case R_HEX_B15_PCREL: |
| 228 | or32le(Loc, applyMask(0x00df20fe, Val >> 2)); | |
| 227 | or32le(loc, applyMask(0x00df20fe, val >> 2)); | |
| 229 | 228 | break; |
| 230 | 229 | case R_HEX_B15_PCREL_X: |
| 231 | or32le(Loc, applyMask(0x00df20fe, Val & 0x3f)); | |
| 230 | or32le(loc, applyMask(0x00df20fe, val & 0x3f)); | |
| 232 | 231 | break; |
| 233 | 232 | case R_HEX_B22_PCREL: |
| 234 | 233 | case R_HEX_PLT_B22_PCREL: |
| 235 | or32le(Loc, applyMask(0x1ff3ffe, Val >> 2)); | |
| 234 | or32le(loc, applyMask(0x1ff3ffe, val >> 2)); | |
| 236 | 235 | break; |
| 237 | 236 | case R_HEX_B22_PCREL_X: |
| 238 | or32le(Loc, applyMask(0x1ff3ffe, Val & 0x3f)); | |
| 237 | or32le(loc, applyMask(0x1ff3ffe, val & 0x3f)); | |
| 239 | 238 | break; |
| 240 | 239 | case R_HEX_B32_PCREL_X: |
| 241 | or32le(Loc, applyMask(0x0fff3fff, Val >> 6)); | |
| 240 | or32le(loc, applyMask(0x0fff3fff, val >> 6)); | |
| 242 | 241 | break; |
| 243 | 242 | case R_HEX_HI16: |
| 244 | or32le(Loc, applyMask(0x00c03fff, Val >> 16)); | |
| 243 | or32le(loc, applyMask(0x00c03fff, val >> 16)); | |
| 245 | 244 | break; |
| 246 | 245 | case R_HEX_LO16: |
| 247 | or32le(Loc, applyMask(0x00c03fff, Val)); | |
| 246 | or32le(loc, applyMask(0x00c03fff, val)); | |
| 248 | 247 | break; |
| 249 | 248 | default: |
| 250 | error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type)); | |
| 249 | error(getErrorLocation(loc) + "unrecognized relocation " + toString(type)); | |
| 251 | 250 | break; |
| 252 | 251 | } |
| 253 | 252 | } |
| 254 | 253 | |
| 255 | void Hexagon::writePltHeader(uint8_t *Buf) const { | |
| 256 | const uint8_t PltData[] = { | |
| 254 | void Hexagon::writePltHeader(uint8_t *buf) const { | |
| 255 | const uint8_t pltData[] = { | |
| 257 | 256 | 0x00, 0x40, 0x00, 0x00, // { immext (#0) |
| 258 | 257 | 0x1c, 0xc0, 0x49, 0x6a, // r28 = add (pc, ##GOT0@PCREL) } # @GOT0 |
| 259 | 258 | 0x0e, 0x42, 0x9c, 0xe2, // { r14 -= add (r28, #16) # offset of GOTn |
| ... | ... | @@ -263,30 +262,30 @@ void Hexagon::writePltHeader(uint8_t *Buf) const { |
| 263 | 262 | 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 } # call dynamic linker |
| 264 | 263 | 0x0c, 0xdb, 0x00, 0x54, // trap0(#0xdb) # bring plt0 into 16byte alignment |
| 265 | 264 | }; |
| 266 | memcpy(Buf, PltData, sizeof(PltData)); | |
| 265 | memcpy(buf, pltData, sizeof(pltData)); | |
| 267 | 266 | |
| 268 | 267 | // Offset from PLT0 to the GOT. |
| 269 | uint64_t Off = In.GotPlt->getVA() - In.Plt->getVA(); | |
| 270 | relocateOne(Buf, R_HEX_B32_PCREL_X, Off); | |
| 271 | relocateOne(Buf + 4, R_HEX_6_PCREL_X, Off); | |
| 268 | uint64_t off = in.gotPlt->getVA() - in.plt->getVA(); | |
| 269 | relocateOne(buf, R_HEX_B32_PCREL_X, off); | |
| 270 | relocateOne(buf + 4, R_HEX_6_PCREL_X, off); | |
| 272 | 271 | } |
| 273 | 272 | |
| 274 | void Hexagon::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, | |
| 275 | uint64_t PltEntryAddr, int32_t Index, | |
| 276 | unsigned RelOff) const { | |
| 277 | const uint8_t Inst[] = { | |
| 273 | void Hexagon::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, | |
| 274 | uint64_t pltEntryAddr, int32_t index, | |
| 275 | unsigned relOff) const { | |
| 276 | const uint8_t inst[] = { | |
| 278 | 277 | 0x00, 0x40, 0x00, 0x00, // { immext (#0) |
| 279 | 278 | 0x0e, 0xc0, 0x49, 0x6a, // r14 = add (pc, ##GOTn@PCREL) } |
| 280 | 279 | 0x1c, 0xc0, 0x8e, 0x91, // r28 = memw (r14) |
| 281 | 280 | 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 |
| 282 | 281 | }; |
| 283 | memcpy(Buf, Inst, sizeof(Inst)); | |
| 282 | memcpy(buf, inst, sizeof(inst)); | |
| 284 | 283 | |
| 285 | relocateOne(Buf, R_HEX_B32_PCREL_X, GotPltEntryAddr - PltEntryAddr); | |
| 286 | relocateOne(Buf + 4, R_HEX_6_PCREL_X, GotPltEntryAddr - PltEntryAddr); | |
| 284 | relocateOne(buf, R_HEX_B32_PCREL_X, gotPltEntryAddr - pltEntryAddr); | |
| 285 | relocateOne(buf + 4, R_HEX_6_PCREL_X, gotPltEntryAddr - pltEntryAddr); | |
| 287 | 286 | } |
| 288 | 287 | |
| 289 | 288 | TargetInfo *elf::getHexagonTargetInfo() { |
| 290 | static Hexagon Target; | |
| 291 | return &Target; | |
| 289 | static Hexagon target; | |
| 290 | return &target; | |
| 292 | 291 | } |
deps/lld/ELF/Arch/MSP430.cpp+24-25| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- MSP430.cpp ---------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -34,20 +33,20 @@ namespace { |
| 34 | 33 | class MSP430 final : public TargetInfo { |
| 35 | 34 | public: |
| 36 | 35 | MSP430(); |
| 37 | RelExpr getRelExpr(RelType Type, const Symbol &S, | |
| 38 | const uint8_t *Loc) const override; | |
| 39 | void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 36 | RelExpr getRelExpr(RelType type, const Symbol &s, | |
| 37 | const uint8_t *loc) const override; | |
| 38 | void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 40 | 39 | }; |
| 41 | 40 | } // namespace |
| 42 | 41 | |
| 43 | 42 | MSP430::MSP430() { |
| 44 | 43 | // mov.b #0, r3 |
| 45 | TrapInstr = {0x43, 0x43, 0x43, 0x43}; | |
| 44 | trapInstr = {0x43, 0x43, 0x43, 0x43}; | |
| 46 | 45 | } |
| 47 | 46 | |
| 48 | RelExpr MSP430::getRelExpr(RelType Type, const Symbol &S, | |
| 49 | const uint8_t *Loc) const { | |
| 50 | switch (Type) { | |
| 47 | RelExpr MSP430::getRelExpr(RelType type, const Symbol &s, | |
| 48 | const uint8_t *loc) const { | |
| 49 | switch (type) { | |
| 51 | 50 | case R_MSP430_10_PCREL: |
| 52 | 51 | case R_MSP430_16_PCREL: |
| 53 | 52 | case R_MSP430_16_PCREL_BYTE: |
| ... | ... | @@ -60,35 +59,35 @@ RelExpr MSP430::getRelExpr(RelType Type, const Symbol &S, |
| 60 | 59 | } |
| 61 | 60 | } |
| 62 | 61 | |
| 63 | void MSP430::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 64 | switch (Type) { | |
| 62 | void MSP430::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { | |
| 63 | switch (type) { | |
| 65 | 64 | case R_MSP430_8: |
| 66 | checkIntUInt(Loc, Val, 8, Type); | |
| 67 | *Loc = Val; | |
| 65 | checkIntUInt(loc, val, 8, type); | |
| 66 | *loc = val; | |
| 68 | 67 | break; |
| 69 | 68 | case R_MSP430_16: |
| 70 | 69 | case R_MSP430_16_PCREL: |
| 71 | 70 | case R_MSP430_16_BYTE: |
| 72 | 71 | case R_MSP430_16_PCREL_BYTE: |
| 73 | checkIntUInt(Loc, Val, 16, Type); | |
| 74 | write16le(Loc, Val); | |
| 72 | checkIntUInt(loc, val, 16, type); | |
| 73 | write16le(loc, val); | |
| 75 | 74 | break; |
| 76 | 75 | case R_MSP430_32: |
| 77 | checkIntUInt(Loc, Val, 32, Type); | |
| 78 | write32le(Loc, Val); | |
| 76 | checkIntUInt(loc, val, 32, type); | |
| 77 | write32le(loc, val); | |
| 79 | 78 | break; |
| 80 | 79 | case R_MSP430_10_PCREL: { |
| 81 | int16_t Offset = ((int16_t)Val >> 1) - 1; | |
| 82 | checkInt(Loc, Offset, 10, Type); | |
| 83 | write16le(Loc, (read16le(Loc) & 0xFC00) | (Offset & 0x3FF)); | |
| 80 | int16_t offset = ((int16_t)val >> 1) - 1; | |
| 81 | checkInt(loc, offset, 10, type); | |
| 82 | write16le(loc, (read16le(loc) & 0xFC00) | (offset & 0x3FF)); | |
| 84 | 83 | break; |
| 85 | 84 | } |
| 86 | 85 | default: |
| 87 | error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type)); | |
| 86 | error(getErrorLocation(loc) + "unrecognized relocation " + toString(type)); | |
| 88 | 87 | } |
| 89 | 88 | } |
| 90 | 89 | |
| 91 | 90 | TargetInfo *elf::getMSP430TargetInfo() { |
| 92 | static MSP430 Target; | |
| 93 | return &Target; | |
| 91 | static MSP430 target; | |
| 92 | return &target; | |
| 94 | 93 | } |
deps/lld/ELF/Arch/Mips.cpp+336-271| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- MIPS.cpp -----------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -29,47 +28,47 @@ template <class ELFT> class MIPS final : public TargetInfo { |
| 29 | 28 | public: |
| 30 | 29 | MIPS(); |
| 31 | 30 | uint32_t calcEFlags() const override; |
| 32 | RelExpr getRelExpr(RelType Type, const Symbol &S, | |
| 33 | const uint8_t *Loc) const override; | |
| 34 | int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; | |
| 35 | RelType getDynRel(RelType Type) const override; | |
| 36 | void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; | |
| 37 | void writePltHeader(uint8_t *Buf) const override; | |
| 38 | void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, | |
| 39 | int32_t Index, unsigned RelOff) const override; | |
| 40 | bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, | |
| 41 | uint64_t BranchAddr, const Symbol &S) const override; | |
| 42 | void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 43 | bool usesOnlyLowPageBits(RelType Type) const override; | |
| 31 | RelExpr getRelExpr(RelType type, const Symbol &s, | |
| 32 | const uint8_t *loc) const override; | |
| 33 | int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; | |
| 34 | RelType getDynRel(RelType type) const override; | |
| 35 | void writeGotPlt(uint8_t *buf, const Symbol &s) const override; | |
| 36 | void writePltHeader(uint8_t *buf) const override; | |
| 37 | void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, | |
| 38 | int32_t index, unsigned relOff) const override; | |
| 39 | bool needsThunk(RelExpr expr, RelType type, const InputFile *file, | |
| 40 | uint64_t branchAddr, const Symbol &s) const override; | |
| 41 | void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 42 | bool usesOnlyLowPageBits(RelType type) const override; | |
| 44 | 43 | }; |
| 45 | 44 | } // namespace |
| 46 | 45 | |
| 47 | 46 | template <class ELFT> MIPS<ELFT>::MIPS() { |
| 48 | GotPltHeaderEntriesNum = 2; | |
| 49 | DefaultMaxPageSize = 65536; | |
| 50 | GotEntrySize = sizeof(typename ELFT::uint); | |
| 51 | GotPltEntrySize = sizeof(typename ELFT::uint); | |
| 52 | GotBaseSymInGotPlt = false; | |
| 53 | PltEntrySize = 16; | |
| 54 | PltHeaderSize = 32; | |
| 55 | CopyRel = R_MIPS_COPY; | |
| 56 | NoneRel = R_MIPS_NONE; | |
| 57 | PltRel = R_MIPS_JUMP_SLOT; | |
| 58 | NeedsThunks = true; | |
| 47 | gotPltHeaderEntriesNum = 2; | |
| 48 | defaultMaxPageSize = 65536; | |
| 49 | gotBaseSymInGotPlt = false; | |
| 50 | pltEntrySize = 16; | |
| 51 | pltHeaderSize = 32; | |
| 52 | copyRel = R_MIPS_COPY; | |
| 53 | noneRel = R_MIPS_NONE; | |
| 54 | pltRel = R_MIPS_JUMP_SLOT; | |
| 55 | needsThunks = true; | |
| 59 | 56 | |
| 60 | 57 | // Set `sigrie 1` as a trap instruction. |
| 61 | write32(TrapInstr.data(), 0x04170001); | |
| 58 | write32(trapInstr.data(), 0x04170001); | |
| 62 | 59 | |
| 63 | 60 | if (ELFT::Is64Bits) { |
| 64 | RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32; | |
| 65 | TlsGotRel = R_MIPS_TLS_TPREL64; | |
| 66 | TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64; | |
| 67 | TlsOffsetRel = R_MIPS_TLS_DTPREL64; | |
| 61 | relativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32; | |
| 62 | symbolicRel = R_MIPS_64; | |
| 63 | tlsGotRel = R_MIPS_TLS_TPREL64; | |
| 64 | tlsModuleIndexRel = R_MIPS_TLS_DTPMOD64; | |
| 65 | tlsOffsetRel = R_MIPS_TLS_DTPREL64; | |
| 68 | 66 | } else { |
| 69 | RelativeRel = R_MIPS_REL32; | |
| 70 | TlsGotRel = R_MIPS_TLS_TPREL32; | |
| 71 | TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32; | |
| 72 | TlsOffsetRel = R_MIPS_TLS_DTPREL32; | |
| 67 | relativeRel = R_MIPS_REL32; | |
| 68 | symbolicRel = R_MIPS_32; | |
| 69 | tlsGotRel = R_MIPS_TLS_TPREL32; | |
| 70 | tlsModuleIndexRel = R_MIPS_TLS_DTPMOD32; | |
| 71 | tlsOffsetRel = R_MIPS_TLS_DTPREL32; | |
| 73 | 72 | } |
| 74 | 73 | } |
| 75 | 74 | |
| ... | ... | @@ -78,13 +77,13 @@ template <class ELFT> uint32_t MIPS<ELFT>::calcEFlags() const { |
| 78 | 77 | } |
| 79 | 78 | |
| 80 | 79 | template <class ELFT> |
| 81 | RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S, | |
| 82 | const uint8_t *Loc) const { | |
| 80 | RelExpr MIPS<ELFT>::getRelExpr(RelType type, const Symbol &s, | |
| 81 | const uint8_t *loc) const { | |
| 83 | 82 | // See comment in the calculateMipsRelChain. |
| 84 | if (ELFT::Is64Bits || Config->MipsN32Abi) | |
| 85 | Type &= 0xff; | |
| 83 | if (ELFT::Is64Bits || config->mipsN32Abi) | |
| 84 | type &= 0xff; | |
| 86 | 85 | |
| 87 | switch (Type) { | |
| 86 | switch (type) { | |
| 88 | 87 | case R_MIPS_JALR: |
| 89 | 88 | case R_MICROMIPS_JALR: |
| 90 | 89 | return R_HINT; |
| ... | ... | @@ -108,9 +107,9 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S, |
| 108 | 107 | // offset between start of function and 'gp' value which by default |
| 109 | 108 | // equal to the start of .got section. In that case we consider these |
| 110 | 109 | // relocations as relative. |
| 111 | if (&S == ElfSym::MipsGpDisp) | |
| 110 | if (&s == ElfSym::mipsGpDisp) | |
| 112 | 111 | return R_MIPS_GOT_GP_PC; |
| 113 | if (&S == ElfSym::MipsLocalGp) | |
| 112 | if (&s == ElfSym::mipsLocalGp) | |
| 114 | 113 | return R_MIPS_GOT_GP; |
| 115 | 114 | LLVM_FALLTHROUGH; |
| 116 | 115 | case R_MIPS_32: |
| ... | ... | @@ -147,7 +146,7 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S, |
| 147 | 146 | return R_PC; |
| 148 | 147 | case R_MIPS_GOT16: |
| 149 | 148 | case R_MICROMIPS_GOT16: |
| 150 | if (S.isLocal()) | |
| 149 | if (s.isLocal()) | |
| 151 | 150 | return R_MIPS_GOT_LOCAL_PAGE; |
| 152 | 151 | LLVM_FALLTHROUGH; |
| 153 | 152 | case R_MIPS_CALL16: |
| ... | ... | @@ -176,209 +175,213 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S, |
| 176 | 175 | case R_MIPS_NONE: |
| 177 | 176 | return R_NONE; |
| 178 | 177 | default: |
| 179 | return R_INVALID; | |
| 178 | error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + | |
| 179 | ") against symbol " + toString(s)); | |
| 180 | return R_NONE; | |
| 180 | 181 | } |
| 181 | 182 | } |
| 182 | 183 | |
| 183 | template <class ELFT> RelType MIPS<ELFT>::getDynRel(RelType Type) const { | |
| 184 | if (Type == R_MIPS_32 || Type == R_MIPS_64) | |
| 185 | return RelativeRel; | |
| 184 | template <class ELFT> RelType MIPS<ELFT>::getDynRel(RelType type) const { | |
| 185 | if (type == symbolicRel) | |
| 186 | return type; | |
| 186 | 187 | return R_MIPS_NONE; |
| 187 | 188 | } |
| 188 | 189 | |
| 189 | 190 | template <class ELFT> |
| 190 | void MIPS<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &) const { | |
| 191 | uint64_t VA = In.Plt->getVA(); | |
| 191 | void MIPS<ELFT>::writeGotPlt(uint8_t *buf, const Symbol &) const { | |
| 192 | uint64_t va = in.plt->getVA(); | |
| 192 | 193 | if (isMicroMips()) |
| 193 | VA |= 1; | |
| 194 | write32<ELFT::TargetEndianness>(Buf, VA); | |
| 194 | va |= 1; | |
| 195 | write32<ELFT::TargetEndianness>(buf, va); | |
| 195 | 196 | } |
| 196 | 197 | |
| 197 | template <endianness E> static uint32_t readShuffle(const uint8_t *Loc) { | |
| 198 | template <endianness E> static uint32_t readShuffle(const uint8_t *loc) { | |
| 198 | 199 | // The major opcode of a microMIPS instruction needs to appear |
| 199 | 200 | // in the first 16-bit word (lowest address) for efficient hardware |
| 200 | 201 | // decode so that it knows if the instruction is 16-bit or 32-bit |
| 201 | 202 | // as early as possible. To do so, little-endian binaries keep 16-bit |
| 202 | 203 | // words in a big-endian order. That is why we have to swap these |
| 203 | 204 | // words to get a correct value. |
| 204 | uint32_t V = read32<E>(Loc); | |
| 205 | uint32_t v = read32<E>(loc); | |
| 205 | 206 | if (E == support::little) |
| 206 | return (V << 16) | (V >> 16); | |
| 207 | return V; | |
| 207 | return (v << 16) | (v >> 16); | |
| 208 | return v; | |
| 208 | 209 | } |
| 209 | 210 | |
| 210 | 211 | template <endianness E> |
| 211 | static void writeValue(uint8_t *Loc, uint64_t V, uint8_t BitsSize, | |
| 212 | uint8_t Shift) { | |
| 213 | uint32_t Instr = read32<E>(Loc); | |
| 214 | uint32_t Mask = 0xffffffff >> (32 - BitsSize); | |
| 215 | uint32_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask); | |
| 216 | write32<E>(Loc, Data); | |
| 212 | static void writeValue(uint8_t *loc, uint64_t v, uint8_t bitsSize, | |
| 213 | uint8_t shift) { | |
| 214 | uint32_t instr = read32<E>(loc); | |
| 215 | uint32_t mask = 0xffffffff >> (32 - bitsSize); | |
| 216 | uint32_t data = (instr & ~mask) | ((v >> shift) & mask); | |
| 217 | write32<E>(loc, data); | |
| 217 | 218 | } |
| 218 | 219 | |
| 219 | 220 | template <endianness E> |
| 220 | static void writeShuffleValue(uint8_t *Loc, uint64_t V, uint8_t BitsSize, | |
| 221 | uint8_t Shift) { | |
| 221 | static void writeShuffleValue(uint8_t *loc, uint64_t v, uint8_t bitsSize, | |
| 222 | uint8_t shift) { | |
| 222 | 223 | // See comments in readShuffle for purpose of this code. |
| 223 | uint16_t *Words = (uint16_t *)Loc; | |
| 224 | uint16_t *words = (uint16_t *)loc; | |
| 224 | 225 | if (E == support::little) |
| 225 | std::swap(Words[0], Words[1]); | |
| 226 | std::swap(words[0], words[1]); | |
| 226 | 227 | |
| 227 | writeValue<E>(Loc, V, BitsSize, Shift); | |
| 228 | writeValue<E>(loc, v, bitsSize, shift); | |
| 228 | 229 | |
| 229 | 230 | if (E == support::little) |
| 230 | std::swap(Words[0], Words[1]); | |
| 231 | std::swap(words[0], words[1]); | |
| 231 | 232 | } |
| 232 | 233 | |
| 233 | 234 | template <endianness E> |
| 234 | static void writeMicroRelocation16(uint8_t *Loc, uint64_t V, uint8_t BitsSize, | |
| 235 | uint8_t Shift) { | |
| 236 | uint16_t Instr = read16<E>(Loc); | |
| 237 | uint16_t Mask = 0xffff >> (16 - BitsSize); | |
| 238 | uint16_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask); | |
| 239 | write16<E>(Loc, Data); | |
| 235 | static void writeMicroRelocation16(uint8_t *loc, uint64_t v, uint8_t bitsSize, | |
| 236 | uint8_t shift) { | |
| 237 | uint16_t instr = read16<E>(loc); | |
| 238 | uint16_t mask = 0xffff >> (16 - bitsSize); | |
| 239 | uint16_t data = (instr & ~mask) | ((v >> shift) & mask); | |
| 240 | write16<E>(loc, data); | |
| 240 | 241 | } |
| 241 | 242 | |
| 242 | template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const { | |
| 243 | const endianness E = ELFT::TargetEndianness; | |
| 243 | template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *buf) const { | |
| 244 | const endianness e = ELFT::TargetEndianness; | |
| 244 | 245 | if (isMicroMips()) { |
| 245 | uint64_t GotPlt = In.GotPlt->getVA(); | |
| 246 | uint64_t Plt = In.Plt->getVA(); | |
| 246 | uint64_t gotPlt = in.gotPlt->getVA(); | |
| 247 | uint64_t plt = in.plt->getVA(); | |
| 247 | 248 | // Overwrite trap instructions written by Writer::writeTrapInstr. |
| 248 | memset(Buf, 0, PltHeaderSize); | |
| 249 | ||
| 250 | write16<E>(Buf, isMipsR6() ? 0x7860 : 0x7980); // addiupc v1, (GOTPLT) - . | |
| 251 | write16<E>(Buf + 4, 0xff23); // lw $25, 0($3) | |
| 252 | write16<E>(Buf + 8, 0x0535); // subu16 $2, $2, $3 | |
| 253 | write16<E>(Buf + 10, 0x2525); // srl16 $2, $2, 2 | |
| 254 | write16<E>(Buf + 12, 0x3302); // addiu $24, $2, -2 | |
| 255 | write16<E>(Buf + 14, 0xfffe); | |
| 256 | write16<E>(Buf + 16, 0x0dff); // move $15, $31 | |
| 249 | memset(buf, 0, pltHeaderSize); | |
| 250 | ||
| 251 | write16<e>(buf, isMipsR6() ? 0x7860 : 0x7980); // addiupc v1, (GOTPLT) - . | |
| 252 | write16<e>(buf + 4, 0xff23); // lw $25, 0($3) | |
| 253 | write16<e>(buf + 8, 0x0535); // subu16 $2, $2, $3 | |
| 254 | write16<e>(buf + 10, 0x2525); // srl16 $2, $2, 2 | |
| 255 | write16<e>(buf + 12, 0x3302); // addiu $24, $2, -2 | |
| 256 | write16<e>(buf + 14, 0xfffe); | |
| 257 | write16<e>(buf + 16, 0x0dff); // move $15, $31 | |
| 257 | 258 | if (isMipsR6()) { |
| 258 | write16<E>(Buf + 18, 0x0f83); // move $28, $3 | |
| 259 | write16<E>(Buf + 20, 0x472b); // jalrc $25 | |
| 260 | write16<E>(Buf + 22, 0x0c00); // nop | |
| 261 | relocateOne(Buf, R_MICROMIPS_PC19_S2, GotPlt - Plt); | |
| 259 | write16<e>(buf + 18, 0x0f83); // move $28, $3 | |
| 260 | write16<e>(buf + 20, 0x472b); // jalrc $25 | |
| 261 | write16<e>(buf + 22, 0x0c00); // nop | |
| 262 | relocateOne(buf, R_MICROMIPS_PC19_S2, gotPlt - plt); | |
| 262 | 263 | } else { |
| 263 | write16<E>(Buf + 18, 0x45f9); // jalrc $25 | |
| 264 | write16<E>(Buf + 20, 0x0f83); // move $28, $3 | |
| 265 | write16<E>(Buf + 22, 0x0c00); // nop | |
| 266 | relocateOne(Buf, R_MICROMIPS_PC23_S2, GotPlt - Plt); | |
| 264 | write16<e>(buf + 18, 0x45f9); // jalrc $25 | |
| 265 | write16<e>(buf + 20, 0x0f83); // move $28, $3 | |
| 266 | write16<e>(buf + 22, 0x0c00); // nop | |
| 267 | relocateOne(buf, R_MICROMIPS_PC23_S2, gotPlt - plt); | |
| 267 | 268 | } |
| 268 | 269 | return; |
| 269 | 270 | } |
| 270 | 271 | |
| 271 | if (Config->MipsN32Abi) { | |
| 272 | write32<E>(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) | |
| 273 | write32<E>(Buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14) | |
| 274 | write32<E>(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) | |
| 275 | write32<E>(Buf + 12, 0x030ec023); // subu $24, $24, $14 | |
| 276 | write32<E>(Buf + 16, 0x03e07825); // move $15, $31 | |
| 277 | write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2 | |
| 272 | if (config->mipsN32Abi) { | |
| 273 | write32<e>(buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) | |
| 274 | write32<e>(buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14) | |
| 275 | write32<e>(buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) | |
| 276 | write32<e>(buf + 12, 0x030ec023); // subu $24, $24, $14 | |
| 277 | write32<e>(buf + 16, 0x03e07825); // move $15, $31 | |
| 278 | write32<e>(buf + 20, 0x0018c082); // srl $24, $24, 2 | |
| 278 | 279 | } else if (ELFT::Is64Bits) { |
| 279 | write32<E>(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) | |
| 280 | write32<E>(Buf + 4, 0xddd90000); // ld $25, %lo(&GOTPLT[0])($14) | |
| 281 | write32<E>(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) | |
| 282 | write32<E>(Buf + 12, 0x030ec023); // subu $24, $24, $14 | |
| 283 | write32<E>(Buf + 16, 0x03e07825); // move $15, $31 | |
| 284 | write32<E>(Buf + 20, 0x0018c0c2); // srl $24, $24, 3 | |
| 280 | write32<e>(buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) | |
| 281 | write32<e>(buf + 4, 0xddd90000); // ld $25, %lo(&GOTPLT[0])($14) | |
| 282 | write32<e>(buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) | |
| 283 | write32<e>(buf + 12, 0x030ec023); // subu $24, $24, $14 | |
| 284 | write32<e>(buf + 16, 0x03e07825); // move $15, $31 | |
| 285 | write32<e>(buf + 20, 0x0018c0c2); // srl $24, $24, 3 | |
| 285 | 286 | } else { |
| 286 | write32<E>(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0]) | |
| 287 | write32<E>(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28) | |
| 288 | write32<E>(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0]) | |
| 289 | write32<E>(Buf + 12, 0x031cc023); // subu $24, $24, $28 | |
| 290 | write32<E>(Buf + 16, 0x03e07825); // move $15, $31 | |
| 291 | write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2 | |
| 287 | write32<e>(buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0]) | |
| 288 | write32<e>(buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28) | |
| 289 | write32<e>(buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0]) | |
| 290 | write32<e>(buf + 12, 0x031cc023); // subu $24, $24, $28 | |
| 291 | write32<e>(buf + 16, 0x03e07825); // move $15, $31 | |
| 292 | write32<e>(buf + 20, 0x0018c082); // srl $24, $24, 2 | |
| 292 | 293 | } |
| 293 | 294 | |
| 294 | uint32_t JalrInst = Config->ZHazardplt ? 0x0320fc09 : 0x0320f809; | |
| 295 | write32<E>(Buf + 24, JalrInst); // jalr.hb $25 or jalr $25 | |
| 296 | write32<E>(Buf + 28, 0x2718fffe); // subu $24, $24, 2 | |
| 295 | uint32_t jalrInst = config->zHazardplt ? 0x0320fc09 : 0x0320f809; | |
| 296 | write32<e>(buf + 24, jalrInst); // jalr.hb $25 or jalr $25 | |
| 297 | write32<e>(buf + 28, 0x2718fffe); // subu $24, $24, 2 | |
| 297 | 298 | |
| 298 | uint64_t GotPlt = In.GotPlt->getVA(); | |
| 299 | writeValue<E>(Buf, GotPlt + 0x8000, 16, 16); | |
| 300 | writeValue<E>(Buf + 4, GotPlt, 16, 0); | |
| 301 | writeValue<E>(Buf + 8, GotPlt, 16, 0); | |
| 299 | uint64_t gotPlt = in.gotPlt->getVA(); | |
| 300 | writeValue<e>(buf, gotPlt + 0x8000, 16, 16); | |
| 301 | writeValue<e>(buf + 4, gotPlt, 16, 0); | |
| 302 | writeValue<e>(buf + 8, gotPlt, 16, 0); | |
| 302 | 303 | } |
| 303 | 304 | |
| 304 | 305 | template <class ELFT> |
| 305 | void MIPS<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, | |
| 306 | uint64_t PltEntryAddr, int32_t Index, | |
| 307 | unsigned RelOff) const { | |
| 308 | const endianness E = ELFT::TargetEndianness; | |
| 306 | void MIPS<ELFT>::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, | |
| 307 | uint64_t pltEntryAddr, int32_t index, | |
| 308 | unsigned relOff) const { | |
| 309 | const endianness e = ELFT::TargetEndianness; | |
| 309 | 310 | if (isMicroMips()) { |
| 310 | 311 | // Overwrite trap instructions written by Writer::writeTrapInstr. |
| 311 | memset(Buf, 0, PltEntrySize); | |
| 312 | memset(buf, 0, pltEntrySize); | |
| 312 | 313 | |
| 313 | 314 | if (isMipsR6()) { |
| 314 | write16<E>(Buf, 0x7840); // addiupc $2, (GOTPLT) - . | |
| 315 | write16<E>(Buf + 4, 0xff22); // lw $25, 0($2) | |
| 316 | write16<E>(Buf + 8, 0x0f02); // move $24, $2 | |
| 317 | write16<E>(Buf + 10, 0x4723); // jrc $25 / jr16 $25 | |
| 318 | relocateOne(Buf, R_MICROMIPS_PC19_S2, GotPltEntryAddr - PltEntryAddr); | |
| 315 | write16<e>(buf, 0x7840); // addiupc $2, (GOTPLT) - . | |
| 316 | write16<e>(buf + 4, 0xff22); // lw $25, 0($2) | |
| 317 | write16<e>(buf + 8, 0x0f02); // move $24, $2 | |
| 318 | write16<e>(buf + 10, 0x4723); // jrc $25 / jr16 $25 | |
| 319 | relocateOne(buf, R_MICROMIPS_PC19_S2, gotPltEntryAddr - pltEntryAddr); | |
| 319 | 320 | } else { |
| 320 | write16<E>(Buf, 0x7900); // addiupc $2, (GOTPLT) - . | |
| 321 | write16<E>(Buf + 4, 0xff22); // lw $25, 0($2) | |
| 322 | write16<E>(Buf + 8, 0x4599); // jrc $25 / jr16 $25 | |
| 323 | write16<E>(Buf + 10, 0x0f02); // move $24, $2 | |
| 324 | relocateOne(Buf, R_MICROMIPS_PC23_S2, GotPltEntryAddr - PltEntryAddr); | |
| 321 | write16<e>(buf, 0x7900); // addiupc $2, (GOTPLT) - . | |
| 322 | write16<e>(buf + 4, 0xff22); // lw $25, 0($2) | |
| 323 | write16<e>(buf + 8, 0x4599); // jrc $25 / jr16 $25 | |
| 324 | write16<e>(buf + 10, 0x0f02); // move $24, $2 | |
| 325 | relocateOne(buf, R_MICROMIPS_PC23_S2, gotPltEntryAddr - pltEntryAddr); | |
| 325 | 326 | } |
| 326 | 327 | return; |
| 327 | 328 | } |
| 328 | 329 | |
| 329 | uint32_t JrInst = isMipsR6() ? (Config->ZHazardplt ? 0x03200409 : 0x03200009) | |
| 330 | : (Config->ZHazardplt ? 0x03200408 : 0x03200008); | |
| 331 | ||
| 332 | write32<E>(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry) | |
| 333 | write32<E>(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15) | |
| 334 | write32<E>(Buf + 8, JrInst); // jr $25 / jr.hb $25 | |
| 335 | write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry) | |
| 336 | writeValue<E>(Buf, GotPltEntryAddr + 0x8000, 16, 16); | |
| 337 | writeValue<E>(Buf + 4, GotPltEntryAddr, 16, 0); | |
| 338 | writeValue<E>(Buf + 12, GotPltEntryAddr, 16, 0); | |
| 330 | uint32_t loadInst = ELFT::Is64Bits ? 0xddf90000 : 0x8df90000; | |
| 331 | uint32_t jrInst = isMipsR6() ? (config->zHazardplt ? 0x03200409 : 0x03200009) | |
| 332 | : (config->zHazardplt ? 0x03200408 : 0x03200008); | |
| 333 | uint32_t addInst = ELFT::Is64Bits ? 0x65f80000 : 0x25f80000; | |
| 334 | ||
| 335 | write32<e>(buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry) | |
| 336 | write32<e>(buf + 4, loadInst); // l[wd] $25, %lo(.got.plt entry)($15) | |
| 337 | write32<e>(buf + 8, jrInst); // jr $25 / jr.hb $25 | |
| 338 | write32<e>(buf + 12, addInst); // [d]addiu $24, $15, %lo(.got.plt entry) | |
| 339 | writeValue<e>(buf, gotPltEntryAddr + 0x8000, 16, 16); | |
| 340 | writeValue<e>(buf + 4, gotPltEntryAddr, 16, 0); | |
| 341 | writeValue<e>(buf + 12, gotPltEntryAddr, 16, 0); | |
| 339 | 342 | } |
| 340 | 343 | |
| 341 | 344 | template <class ELFT> |
| 342 | bool MIPS<ELFT>::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, | |
| 343 | uint64_t BranchAddr, const Symbol &S) const { | |
| 345 | bool MIPS<ELFT>::needsThunk(RelExpr expr, RelType type, const InputFile *file, | |
| 346 | uint64_t branchAddr, const Symbol &s) const { | |
| 344 | 347 | // Any MIPS PIC code function is invoked with its address in register $t9. |
| 345 | 348 | // So if we have a branch instruction from non-PIC code to the PIC one |
| 346 | 349 | // we cannot make the jump directly and need to create a small stubs |
| 347 | 350 | // to save the target function address. |
| 348 | 351 | // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf |
| 349 | if (Type != R_MIPS_26 && Type != R_MICROMIPS_26_S1 && | |
| 350 | Type != R_MICROMIPS_PC26_S1) | |
| 352 | if (type != R_MIPS_26 && type != R_MIPS_PC26_S2 && | |
| 353 | type != R_MICROMIPS_26_S1 && type != R_MICROMIPS_PC26_S1) | |
| 351 | 354 | return false; |
| 352 | auto *F = dyn_cast_or_null<ELFFileBase<ELFT>>(File); | |
| 353 | if (!F) | |
| 355 | auto *f = dyn_cast_or_null<ObjFile<ELFT>>(file); | |
| 356 | if (!f) | |
| 354 | 357 | return false; |
| 355 | 358 | // If current file has PIC code, LA25 stub is not required. |
| 356 | if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC) | |
| 359 | if (f->getObj().getHeader()->e_flags & EF_MIPS_PIC) | |
| 357 | 360 | return false; |
| 358 | auto *D = dyn_cast<Defined>(&S); | |
| 361 | auto *d = dyn_cast<Defined>(&s); | |
| 359 | 362 | // LA25 is required if target file has PIC code |
| 360 | 363 | // or target symbol is a PIC symbol. |
| 361 | return D && isMipsPIC<ELFT>(D); | |
| 364 | return d && isMipsPIC<ELFT>(d); | |
| 362 | 365 | } |
| 363 | 366 | |
| 364 | 367 | template <class ELFT> |
| 365 | int64_t MIPS<ELFT>::getImplicitAddend(const uint8_t *Buf, RelType Type) const { | |
| 366 | const endianness E = ELFT::TargetEndianness; | |
| 367 | switch (Type) { | |
| 368 | int64_t MIPS<ELFT>::getImplicitAddend(const uint8_t *buf, RelType type) const { | |
| 369 | const endianness e = ELFT::TargetEndianness; | |
| 370 | switch (type) { | |
| 368 | 371 | case R_MIPS_32: |
| 369 | 372 | case R_MIPS_GPREL32: |
| 370 | 373 | case R_MIPS_TLS_DTPREL32: |
| 371 | 374 | case R_MIPS_TLS_TPREL32: |
| 372 | return SignExtend64<32>(read32<E>(Buf)); | |
| 375 | return SignExtend64<32>(read32<e>(buf)); | |
| 373 | 376 | case R_MIPS_26: |
| 374 | 377 | // FIXME (simon): If the relocation target symbol is not a PLT entry |
| 375 | 378 | // we should use another expression for calculation: |
| 376 | 379 | // ((A << 2) | (P & 0xf0000000)) >> 2 |
| 377 | return SignExtend64<28>(read32<E>(Buf) << 2); | |
| 380 | return SignExtend64<28>(read32<e>(buf) << 2); | |
| 378 | 381 | case R_MIPS_GOT16: |
| 379 | 382 | case R_MIPS_HI16: |
| 380 | 383 | case R_MIPS_PCHI16: |
| 381 | return SignExtend64<16>(read32<E>(Buf)) << 16; | |
| 384 | return SignExtend64<16>(read32<e>(buf)) << 16; | |
| 382 | 385 | case R_MIPS_GPREL16: |
| 383 | 386 | case R_MIPS_LO16: |
| 384 | 387 | case R_MIPS_PCLO16: |
| ... | ... | @@ -386,54 +389,54 @@ int64_t MIPS<ELFT>::getImplicitAddend(const uint8_t *Buf, RelType Type) const { |
| 386 | 389 | case R_MIPS_TLS_DTPREL_LO16: |
| 387 | 390 | case R_MIPS_TLS_TPREL_HI16: |
| 388 | 391 | case R_MIPS_TLS_TPREL_LO16: |
| 389 | return SignExtend64<16>(read32<E>(Buf)); | |
| 392 | return SignExtend64<16>(read32<e>(buf)); | |
| 390 | 393 | case R_MICROMIPS_GOT16: |
| 391 | 394 | case R_MICROMIPS_HI16: |
| 392 | return SignExtend64<16>(readShuffle<E>(Buf)) << 16; | |
| 395 | return SignExtend64<16>(readShuffle<e>(buf)) << 16; | |
| 393 | 396 | case R_MICROMIPS_GPREL16: |
| 394 | 397 | case R_MICROMIPS_LO16: |
| 395 | 398 | case R_MICROMIPS_TLS_DTPREL_HI16: |
| 396 | 399 | case R_MICROMIPS_TLS_DTPREL_LO16: |
| 397 | 400 | case R_MICROMIPS_TLS_TPREL_HI16: |
| 398 | 401 | case R_MICROMIPS_TLS_TPREL_LO16: |
| 399 | return SignExtend64<16>(readShuffle<E>(Buf)); | |
| 402 | return SignExtend64<16>(readShuffle<e>(buf)); | |
| 400 | 403 | case R_MICROMIPS_GPREL7_S2: |
| 401 | return SignExtend64<9>(readShuffle<E>(Buf) << 2); | |
| 404 | return SignExtend64<9>(readShuffle<e>(buf) << 2); | |
| 402 | 405 | case R_MIPS_PC16: |
| 403 | return SignExtend64<18>(read32<E>(Buf) << 2); | |
| 406 | return SignExtend64<18>(read32<e>(buf) << 2); | |
| 404 | 407 | case R_MIPS_PC19_S2: |
| 405 | return SignExtend64<21>(read32<E>(Buf) << 2); | |
| 408 | return SignExtend64<21>(read32<e>(buf) << 2); | |
| 406 | 409 | case R_MIPS_PC21_S2: |
| 407 | return SignExtend64<23>(read32<E>(Buf) << 2); | |
| 410 | return SignExtend64<23>(read32<e>(buf) << 2); | |
| 408 | 411 | case R_MIPS_PC26_S2: |
| 409 | return SignExtend64<28>(read32<E>(Buf) << 2); | |
| 412 | return SignExtend64<28>(read32<e>(buf) << 2); | |
| 410 | 413 | case R_MIPS_PC32: |
| 411 | return SignExtend64<32>(read32<E>(Buf)); | |
| 414 | return SignExtend64<32>(read32<e>(buf)); | |
| 412 | 415 | case R_MICROMIPS_26_S1: |
| 413 | return SignExtend64<27>(readShuffle<E>(Buf) << 1); | |
| 416 | return SignExtend64<27>(readShuffle<e>(buf) << 1); | |
| 414 | 417 | case R_MICROMIPS_PC7_S1: |
| 415 | return SignExtend64<8>(read16<E>(Buf) << 1); | |
| 418 | return SignExtend64<8>(read16<e>(buf) << 1); | |
| 416 | 419 | case R_MICROMIPS_PC10_S1: |
| 417 | return SignExtend64<11>(read16<E>(Buf) << 1); | |
| 420 | return SignExtend64<11>(read16<e>(buf) << 1); | |
| 418 | 421 | case R_MICROMIPS_PC16_S1: |
| 419 | return SignExtend64<17>(readShuffle<E>(Buf) << 1); | |
| 422 | return SignExtend64<17>(readShuffle<e>(buf) << 1); | |
| 420 | 423 | case R_MICROMIPS_PC18_S3: |
| 421 | return SignExtend64<21>(readShuffle<E>(Buf) << 3); | |
| 424 | return SignExtend64<21>(readShuffle<e>(buf) << 3); | |
| 422 | 425 | case R_MICROMIPS_PC19_S2: |
| 423 | return SignExtend64<21>(readShuffle<E>(Buf) << 2); | |
| 426 | return SignExtend64<21>(readShuffle<e>(buf) << 2); | |
| 424 | 427 | case R_MICROMIPS_PC21_S1: |
| 425 | return SignExtend64<22>(readShuffle<E>(Buf) << 1); | |
| 428 | return SignExtend64<22>(readShuffle<e>(buf) << 1); | |
| 426 | 429 | case R_MICROMIPS_PC23_S2: |
| 427 | return SignExtend64<25>(readShuffle<E>(Buf) << 2); | |
| 430 | return SignExtend64<25>(readShuffle<e>(buf) << 2); | |
| 428 | 431 | case R_MICROMIPS_PC26_S1: |
| 429 | return SignExtend64<27>(readShuffle<E>(Buf) << 1); | |
| 432 | return SignExtend64<27>(readShuffle<e>(buf) << 1); | |
| 430 | 433 | default: |
| 431 | 434 | return 0; |
| 432 | 435 | } |
| 433 | 436 | } |
| 434 | 437 | |
| 435 | 438 | static std::pair<uint32_t, uint64_t> |
| 436 | calculateMipsRelChain(uint8_t *Loc, RelType Type, uint64_t Val) { | |
| 439 | calculateMipsRelChain(uint8_t *loc, RelType type, uint64_t val) { | |
| 437 | 440 | // MIPS N64 ABI packs multiple relocations into the single relocation |
| 438 | 441 | // record. In general, all up to three relocations can have arbitrary |
| 439 | 442 | // types. In fact, Clang and GCC uses only a few combinations. For now, |
| ... | ... | @@ -446,72 +449,134 @@ calculateMipsRelChain(uint8_t *Loc, RelType Type, uint64_t Val) { |
| 446 | 449 | // relocations used to modify result of the first one: extend it to |
| 447 | 450 | // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation |
| 448 | 451 | // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf |
| 449 | RelType Type2 = (Type >> 8) & 0xff; | |
| 450 | RelType Type3 = (Type >> 16) & 0xff; | |
| 451 | if (Type2 == R_MIPS_NONE && Type3 == R_MIPS_NONE) | |
| 452 | return std::make_pair(Type, Val); | |
| 453 | if (Type2 == R_MIPS_64 && Type3 == R_MIPS_NONE) | |
| 454 | return std::make_pair(Type2, Val); | |
| 455 | if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16)) | |
| 456 | return std::make_pair(Type3, -Val); | |
| 457 | error(getErrorLocation(Loc) + "unsupported relocations combination " + | |
| 458 | Twine(Type)); | |
| 459 | return std::make_pair(Type & 0xff, Val); | |
| 452 | RelType type2 = (type >> 8) & 0xff; | |
| 453 | RelType type3 = (type >> 16) & 0xff; | |
| 454 | if (type2 == R_MIPS_NONE && type3 == R_MIPS_NONE) | |
| 455 | return std::make_pair(type, val); | |
| 456 | if (type2 == R_MIPS_64 && type3 == R_MIPS_NONE) | |
| 457 | return std::make_pair(type2, val); | |
| 458 | if (type2 == R_MIPS_SUB && (type3 == R_MIPS_HI16 || type3 == R_MIPS_LO16)) | |
| 459 | return std::make_pair(type3, -val); | |
| 460 | error(getErrorLocation(loc) + "unsupported relocations combination " + | |
| 461 | Twine(type)); | |
| 462 | return std::make_pair(type & 0xff, val); | |
| 463 | } | |
| 464 | ||
| 465 | static bool isBranchReloc(RelType type) { | |
| 466 | return type == R_MIPS_26 || type == R_MIPS_PC26_S2 || | |
| 467 | type == R_MIPS_PC21_S2 || type == R_MIPS_PC16; | |
| 468 | } | |
| 469 | ||
| 470 | static bool isMicroBranchReloc(RelType type) { | |
| 471 | return type == R_MICROMIPS_26_S1 || type == R_MICROMIPS_PC16_S1 || | |
| 472 | type == R_MICROMIPS_PC10_S1 || type == R_MICROMIPS_PC7_S1; | |
| 460 | 473 | } |
| 461 | 474 | |
| 462 | 475 | template <class ELFT> |
| 463 | void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 464 | const endianness E = ELFT::TargetEndianness; | |
| 476 | static uint64_t fixupCrossModeJump(uint8_t *loc, RelType type, uint64_t val) { | |
| 477 | // Here we need to detect jump/branch from regular MIPS code | |
| 478 | // to a microMIPS target and vice versa. In that cases jump | |
| 479 | // instructions need to be replaced by their "cross-mode" | |
| 480 | // equivalents. | |
| 481 | const endianness e = ELFT::TargetEndianness; | |
| 482 | bool isMicroTgt = val & 0x1; | |
| 483 | bool isCrossJump = (isMicroTgt && isBranchReloc(type)) || | |
| 484 | (!isMicroTgt && isMicroBranchReloc(type)); | |
| 485 | if (!isCrossJump) | |
| 486 | return val; | |
| 487 | ||
| 488 | switch (type) { | |
| 489 | case R_MIPS_26: { | |
| 490 | uint32_t inst = read32<e>(loc) >> 26; | |
| 491 | if (inst == 0x3 || inst == 0x1d) { // JAL or JALX | |
| 492 | writeValue<e>(loc, 0x1d << 26, 32, 0); | |
| 493 | return val; | |
| 494 | } | |
| 495 | break; | |
| 496 | } | |
| 497 | case R_MICROMIPS_26_S1: { | |
| 498 | uint32_t inst = readShuffle<e>(loc) >> 26; | |
| 499 | if (inst == 0x3d || inst == 0x3c) { // JAL32 or JALX32 | |
| 500 | val >>= 1; | |
| 501 | writeShuffleValue<e>(loc, 0x3c << 26, 32, 0); | |
| 502 | return val; | |
| 503 | } | |
| 504 | break; | |
| 505 | } | |
| 506 | case R_MIPS_PC26_S2: | |
| 507 | case R_MIPS_PC21_S2: | |
| 508 | case R_MIPS_PC16: | |
| 509 | case R_MICROMIPS_PC16_S1: | |
| 510 | case R_MICROMIPS_PC10_S1: | |
| 511 | case R_MICROMIPS_PC7_S1: | |
| 512 | // FIXME (simon): Support valid branch relocations. | |
| 513 | break; | |
| 514 | default: | |
| 515 | llvm_unreachable("unexpected jump/branch relocation"); | |
| 516 | } | |
| 517 | ||
| 518 | error(getErrorLocation(loc) + | |
| 519 | "unsupported jump/branch instruction between ISA modes referenced by " + | |
| 520 | toString(type) + " relocation"); | |
| 521 | return val; | |
| 522 | } | |
| 523 | ||
| 524 | template <class ELFT> | |
| 525 | void MIPS<ELFT>::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { | |
| 526 | const endianness e = ELFT::TargetEndianness; | |
| 527 | ||
| 528 | if (ELFT::Is64Bits || config->mipsN32Abi) | |
| 529 | std::tie(type, val) = calculateMipsRelChain(loc, type, val); | |
| 465 | 530 | |
| 466 | if (ELFT::Is64Bits || Config->MipsN32Abi) | |
| 467 | std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val); | |
| 531 | // Detect cross-mode jump/branch and fix instruction. | |
| 532 | val = fixupCrossModeJump<ELFT>(loc, type, val); | |
| 468 | 533 | |
| 469 | 534 | // Thread pointer and DRP offsets from the start of TLS data area. |
| 470 | 535 | // https://www.linux-mips.org/wiki/NPTL |
| 471 | if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 || | |
| 472 | Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64 || | |
| 473 | Type == R_MICROMIPS_TLS_DTPREL_HI16 || | |
| 474 | Type == R_MICROMIPS_TLS_DTPREL_LO16) { | |
| 475 | Val -= 0x8000; | |
| 476 | } else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 || | |
| 477 | Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64 || | |
| 478 | Type == R_MICROMIPS_TLS_TPREL_HI16 || | |
| 479 | Type == R_MICROMIPS_TLS_TPREL_LO16) { | |
| 480 | Val -= 0x7000; | |
| 536 | if (type == R_MIPS_TLS_DTPREL_HI16 || type == R_MIPS_TLS_DTPREL_LO16 || | |
| 537 | type == R_MIPS_TLS_DTPREL32 || type == R_MIPS_TLS_DTPREL64 || | |
| 538 | type == R_MICROMIPS_TLS_DTPREL_HI16 || | |
| 539 | type == R_MICROMIPS_TLS_DTPREL_LO16) { | |
| 540 | val -= 0x8000; | |
| 541 | } else if (type == R_MIPS_TLS_TPREL_HI16 || type == R_MIPS_TLS_TPREL_LO16 || | |
| 542 | type == R_MIPS_TLS_TPREL32 || type == R_MIPS_TLS_TPREL64 || | |
| 543 | type == R_MICROMIPS_TLS_TPREL_HI16 || | |
| 544 | type == R_MICROMIPS_TLS_TPREL_LO16) { | |
| 545 | val -= 0x7000; | |
| 481 | 546 | } |
| 482 | 547 | |
| 483 | switch (Type) { | |
| 548 | switch (type) { | |
| 484 | 549 | case R_MIPS_32: |
| 485 | 550 | case R_MIPS_GPREL32: |
| 486 | 551 | case R_MIPS_TLS_DTPREL32: |
| 487 | 552 | case R_MIPS_TLS_TPREL32: |
| 488 | write32<E>(Loc, Val); | |
| 553 | write32<e>(loc, val); | |
| 489 | 554 | break; |
| 490 | 555 | case R_MIPS_64: |
| 491 | 556 | case R_MIPS_TLS_DTPREL64: |
| 492 | 557 | case R_MIPS_TLS_TPREL64: |
| 493 | write64<E>(Loc, Val); | |
| 558 | write64<e>(loc, val); | |
| 494 | 559 | break; |
| 495 | 560 | case R_MIPS_26: |
| 496 | writeValue<E>(Loc, Val, 26, 2); | |
| 561 | writeValue<e>(loc, val, 26, 2); | |
| 497 | 562 | break; |
| 498 | 563 | case R_MIPS_GOT16: |
| 499 | 564 | // The R_MIPS_GOT16 relocation's value in "relocatable" linking mode |
| 500 | 565 | // is updated addend (not a GOT index). In that case write high 16 bits |
| 501 | 566 | // to store a correct addend value. |
| 502 | if (Config->Relocatable) { | |
| 503 | writeValue<E>(Loc, Val + 0x8000, 16, 16); | |
| 567 | if (config->relocatable) { | |
| 568 | writeValue<e>(loc, val + 0x8000, 16, 16); | |
| 504 | 569 | } else { |
| 505 | checkInt(Loc, Val, 16, Type); | |
| 506 | writeValue<E>(Loc, Val, 16, 0); | |
| 570 | checkInt(loc, val, 16, type); | |
| 571 | writeValue<e>(loc, val, 16, 0); | |
| 507 | 572 | } |
| 508 | 573 | break; |
| 509 | 574 | case R_MICROMIPS_GOT16: |
| 510 | if (Config->Relocatable) { | |
| 511 | writeShuffleValue<E>(Loc, Val + 0x8000, 16, 16); | |
| 575 | if (config->relocatable) { | |
| 576 | writeShuffleValue<e>(loc, val + 0x8000, 16, 16); | |
| 512 | 577 | } else { |
| 513 | checkInt(Loc, Val, 16, Type); | |
| 514 | writeShuffleValue<E>(Loc, Val, 16, 0); | |
| 578 | checkInt(loc, val, 16, type); | |
| 579 | writeShuffleValue<e>(loc, val, 16, 0); | |
| 515 | 580 | } |
| 516 | 581 | break; |
| 517 | 582 | case R_MIPS_CALL16: |
| ... | ... | @@ -521,7 +586,7 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 521 | 586 | case R_MIPS_TLS_GD: |
| 522 | 587 | case R_MIPS_TLS_GOTTPREL: |
| 523 | 588 | case R_MIPS_TLS_LDM: |
| 524 | checkInt(Loc, Val, 16, Type); | |
| 589 | checkInt(loc, val, 16, type); | |
| 525 | 590 | LLVM_FALLTHROUGH; |
| 526 | 591 | case R_MIPS_CALL_LO16: |
| 527 | 592 | case R_MIPS_GOT_LO16: |
| ... | ... | @@ -530,13 +595,13 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 530 | 595 | case R_MIPS_PCLO16: |
| 531 | 596 | case R_MIPS_TLS_DTPREL_LO16: |
| 532 | 597 | case R_MIPS_TLS_TPREL_LO16: |
| 533 | writeValue<E>(Loc, Val, 16, 0); | |
| 598 | writeValue<e>(loc, val, 16, 0); | |
| 534 | 599 | break; |
| 535 | 600 | case R_MICROMIPS_GPREL16: |
| 536 | 601 | case R_MICROMIPS_TLS_GD: |
| 537 | 602 | case R_MICROMIPS_TLS_LDM: |
| 538 | checkInt(Loc, Val, 16, Type); | |
| 539 | writeShuffleValue<E>(Loc, Val, 16, 0); | |
| 603 | checkInt(loc, val, 16, type); | |
| 604 | writeShuffleValue<e>(loc, val, 16, 0); | |
| 540 | 605 | break; |
| 541 | 606 | case R_MICROMIPS_CALL16: |
| 542 | 607 | case R_MICROMIPS_CALL_LO16: |
| ... | ... | @@ -544,11 +609,11 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 544 | 609 | case R_MICROMIPS_TLS_DTPREL_LO16: |
| 545 | 610 | case R_MICROMIPS_TLS_GOTTPREL: |
| 546 | 611 | case R_MICROMIPS_TLS_TPREL_LO16: |
| 547 | writeShuffleValue<E>(Loc, Val, 16, 0); | |
| 612 | writeShuffleValue<e>(loc, val, 16, 0); | |
| 548 | 613 | break; |
| 549 | 614 | case R_MICROMIPS_GPREL7_S2: |
| 550 | checkInt(Loc, Val, 7, Type); | |
| 551 | writeShuffleValue<E>(Loc, Val, 7, 2); | |
| 615 | checkInt(loc, val, 7, type); | |
| 616 | writeShuffleValue<e>(loc, val, 7, 2); | |
| 552 | 617 | break; |
| 553 | 618 | case R_MIPS_CALL_HI16: |
| 554 | 619 | case R_MIPS_GOT_HI16: |
| ... | ... | @@ -556,113 +621,113 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 556 | 621 | case R_MIPS_PCHI16: |
| 557 | 622 | case R_MIPS_TLS_DTPREL_HI16: |
| 558 | 623 | case R_MIPS_TLS_TPREL_HI16: |
| 559 | writeValue<E>(Loc, Val + 0x8000, 16, 16); | |
| 624 | writeValue<e>(loc, val + 0x8000, 16, 16); | |
| 560 | 625 | break; |
| 561 | 626 | case R_MICROMIPS_CALL_HI16: |
| 562 | 627 | case R_MICROMIPS_GOT_HI16: |
| 563 | 628 | case R_MICROMIPS_HI16: |
| 564 | 629 | case R_MICROMIPS_TLS_DTPREL_HI16: |
| 565 | 630 | case R_MICROMIPS_TLS_TPREL_HI16: |
| 566 | writeShuffleValue<E>(Loc, Val + 0x8000, 16, 16); | |
| 631 | writeShuffleValue<e>(loc, val + 0x8000, 16, 16); | |
| 567 | 632 | break; |
| 568 | 633 | case R_MIPS_HIGHER: |
| 569 | writeValue<E>(Loc, Val + 0x80008000, 16, 32); | |
| 634 | writeValue<e>(loc, val + 0x80008000, 16, 32); | |
| 570 | 635 | break; |
| 571 | 636 | case R_MIPS_HIGHEST: |
| 572 | writeValue<E>(Loc, Val + 0x800080008000, 16, 48); | |
| 637 | writeValue<e>(loc, val + 0x800080008000, 16, 48); | |
| 573 | 638 | break; |
| 574 | 639 | case R_MIPS_JALR: |
| 575 | 640 | case R_MICROMIPS_JALR: |
| 576 | 641 | // Ignore this optimization relocation for now |
| 577 | 642 | break; |
| 578 | 643 | case R_MIPS_PC16: |
| 579 | checkAlignment(Loc, Val, 4, Type); | |
| 580 | checkInt(Loc, Val, 18, Type); | |
| 581 | writeValue<E>(Loc, Val, 16, 2); | |
| 644 | checkAlignment(loc, val, 4, type); | |
| 645 | checkInt(loc, val, 18, type); | |
| 646 | writeValue<e>(loc, val, 16, 2); | |
| 582 | 647 | break; |
| 583 | 648 | case R_MIPS_PC19_S2: |
| 584 | checkAlignment(Loc, Val, 4, Type); | |
| 585 | checkInt(Loc, Val, 21, Type); | |
| 586 | writeValue<E>(Loc, Val, 19, 2); | |
| 649 | checkAlignment(loc, val, 4, type); | |
| 650 | checkInt(loc, val, 21, type); | |
| 651 | writeValue<e>(loc, val, 19, 2); | |
| 587 | 652 | break; |
| 588 | 653 | case R_MIPS_PC21_S2: |
| 589 | checkAlignment(Loc, Val, 4, Type); | |
| 590 | checkInt(Loc, Val, 23, Type); | |
| 591 | writeValue<E>(Loc, Val, 21, 2); | |
| 654 | checkAlignment(loc, val, 4, type); | |
| 655 | checkInt(loc, val, 23, type); | |
| 656 | writeValue<e>(loc, val, 21, 2); | |
| 592 | 657 | break; |
| 593 | 658 | case R_MIPS_PC26_S2: |
| 594 | checkAlignment(Loc, Val, 4, Type); | |
| 595 | checkInt(Loc, Val, 28, Type); | |
| 596 | writeValue<E>(Loc, Val, 26, 2); | |
| 659 | checkAlignment(loc, val, 4, type); | |
| 660 | checkInt(loc, val, 28, type); | |
| 661 | writeValue<e>(loc, val, 26, 2); | |
| 597 | 662 | break; |
| 598 | 663 | case R_MIPS_PC32: |
| 599 | writeValue<E>(Loc, Val, 32, 0); | |
| 664 | writeValue<e>(loc, val, 32, 0); | |
| 600 | 665 | break; |
| 601 | 666 | case R_MICROMIPS_26_S1: |
| 602 | 667 | case R_MICROMIPS_PC26_S1: |
| 603 | checkInt(Loc, Val, 27, Type); | |
| 604 | writeShuffleValue<E>(Loc, Val, 26, 1); | |
| 668 | checkInt(loc, val, 27, type); | |
| 669 | writeShuffleValue<e>(loc, val, 26, 1); | |
| 605 | 670 | break; |
| 606 | 671 | case R_MICROMIPS_PC7_S1: |
| 607 | checkInt(Loc, Val, 8, Type); | |
| 608 | writeMicroRelocation16<E>(Loc, Val, 7, 1); | |
| 672 | checkInt(loc, val, 8, type); | |
| 673 | writeMicroRelocation16<e>(loc, val, 7, 1); | |
| 609 | 674 | break; |
| 610 | 675 | case R_MICROMIPS_PC10_S1: |
| 611 | checkInt(Loc, Val, 11, Type); | |
| 612 | writeMicroRelocation16<E>(Loc, Val, 10, 1); | |
| 676 | checkInt(loc, val, 11, type); | |
| 677 | writeMicroRelocation16<e>(loc, val, 10, 1); | |
| 613 | 678 | break; |
| 614 | 679 | case R_MICROMIPS_PC16_S1: |
| 615 | checkInt(Loc, Val, 17, Type); | |
| 616 | writeShuffleValue<E>(Loc, Val, 16, 1); | |
| 680 | checkInt(loc, val, 17, type); | |
| 681 | writeShuffleValue<e>(loc, val, 16, 1); | |
| 617 | 682 | break; |
| 618 | 683 | case R_MICROMIPS_PC18_S3: |
| 619 | checkInt(Loc, Val, 21, Type); | |
| 620 | writeShuffleValue<E>(Loc, Val, 18, 3); | |
| 684 | checkInt(loc, val, 21, type); | |
| 685 | writeShuffleValue<e>(loc, val, 18, 3); | |
| 621 | 686 | break; |
| 622 | 687 | case R_MICROMIPS_PC19_S2: |
| 623 | checkInt(Loc, Val, 21, Type); | |
| 624 | writeShuffleValue<E>(Loc, Val, 19, 2); | |
| 688 | checkInt(loc, val, 21, type); | |
| 689 | writeShuffleValue<e>(loc, val, 19, 2); | |
| 625 | 690 | break; |
| 626 | 691 | case R_MICROMIPS_PC21_S1: |
| 627 | checkInt(Loc, Val, 22, Type); | |
| 628 | writeShuffleValue<E>(Loc, Val, 21, 1); | |
| 692 | checkInt(loc, val, 22, type); | |
| 693 | writeShuffleValue<e>(loc, val, 21, 1); | |
| 629 | 694 | break; |
| 630 | 695 | case R_MICROMIPS_PC23_S2: |
| 631 | checkInt(Loc, Val, 25, Type); | |
| 632 | writeShuffleValue<E>(Loc, Val, 23, 2); | |
| 696 | checkInt(loc, val, 25, type); | |
| 697 | writeShuffleValue<e>(loc, val, 23, 2); | |
| 633 | 698 | break; |
| 634 | 699 | default: |
| 635 | error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); | |
| 700 | llvm_unreachable("unknown relocation"); | |
| 636 | 701 | } |
| 637 | 702 | } |
| 638 | 703 | |
| 639 | template <class ELFT> bool MIPS<ELFT>::usesOnlyLowPageBits(RelType Type) const { | |
| 640 | return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST || | |
| 641 | Type == R_MICROMIPS_LO16; | |
| 704 | template <class ELFT> bool MIPS<ELFT>::usesOnlyLowPageBits(RelType type) const { | |
| 705 | return type == R_MIPS_LO16 || type == R_MIPS_GOT_OFST || | |
| 706 | type == R_MICROMIPS_LO16; | |
| 642 | 707 | } |
| 643 | 708 | |
| 644 | 709 | // Return true if the symbol is a PIC function. |
| 645 | template <class ELFT> bool elf::isMipsPIC(const Defined *Sym) { | |
| 646 | if (!Sym->isFunc()) | |
| 710 | template <class ELFT> bool elf::isMipsPIC(const Defined *sym) { | |
| 711 | if (!sym->isFunc()) | |
| 647 | 712 | return false; |
| 648 | 713 | |
| 649 | if (Sym->StOther & STO_MIPS_PIC) | |
| 714 | if (sym->stOther & STO_MIPS_PIC) | |
| 650 | 715 | return true; |
| 651 | 716 | |
| 652 | if (!Sym->Section) | |
| 717 | if (!sym->section) | |
| 653 | 718 | return false; |
| 654 | 719 | |
| 655 | ObjFile<ELFT> *File = | |
| 656 | cast<InputSectionBase>(Sym->Section)->template getFile<ELFT>(); | |
| 657 | if (!File) | |
| 720 | ObjFile<ELFT> *file = | |
| 721 | cast<InputSectionBase>(sym->section)->template getFile<ELFT>(); | |
| 722 | if (!file) | |
| 658 | 723 | return false; |
| 659 | 724 | |
| 660 | return File->getObj().getHeader()->e_flags & EF_MIPS_PIC; | |
| 725 | return file->getObj().getHeader()->e_flags & EF_MIPS_PIC; | |
| 661 | 726 | } |
| 662 | 727 | |
| 663 | 728 | template <class ELFT> TargetInfo *elf::getMipsTargetInfo() { |
| 664 | static MIPS<ELFT> Target; | |
| 665 | return &Target; | |
| 729 | static MIPS<ELFT> target; | |
| 730 | return &target; | |
| 666 | 731 | } |
| 667 | 732 | |
| 668 | 733 | template TargetInfo *elf::getMipsTargetInfo<ELF32LE>(); |
deps/lld/ELF/Arch/MipsArchTree.cpp+119-120| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- MipsArchTree.cpp --------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===---------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -29,18 +28,18 @@ using namespace lld::elf; |
| 29 | 28 | |
| 30 | 29 | namespace { |
| 31 | 30 | struct ArchTreeEdge { |
| 32 | uint32_t Child; | |
| 33 | uint32_t Parent; | |
| 31 | uint32_t child; | |
| 32 | uint32_t parent; | |
| 34 | 33 | }; |
| 35 | 34 | |
| 36 | 35 | struct FileFlags { |
| 37 | InputFile *File; | |
| 38 | uint32_t Flags; | |
| 36 | InputFile *file; | |
| 37 | uint32_t flags; | |
| 39 | 38 | }; |
| 40 | 39 | } // namespace |
| 41 | 40 | |
| 42 | static StringRef getAbiName(uint32_t Flags) { | |
| 43 | switch (Flags) { | |
| 41 | static StringRef getAbiName(uint32_t flags) { | |
| 42 | switch (flags) { | |
| 44 | 43 | case 0: |
| 45 | 44 | return "n64"; |
| 46 | 45 | case EF_MIPS_ABI2: |
| ... | ... | @@ -58,76 +57,76 @@ static StringRef getAbiName(uint32_t Flags) { |
| 58 | 57 | } |
| 59 | 58 | } |
| 60 | 59 | |
| 61 | static StringRef getNanName(bool IsNan2008) { | |
| 62 | return IsNan2008 ? "2008" : "legacy"; | |
| 60 | static StringRef getNanName(bool isNan2008) { | |
| 61 | return isNan2008 ? "2008" : "legacy"; | |
| 63 | 62 | } |
| 64 | 63 | |
| 65 | static StringRef getFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; } | |
| 64 | static StringRef getFpName(bool isFp64) { return isFp64 ? "64" : "32"; } | |
| 66 | 65 | |
| 67 | static void checkFlags(ArrayRef<FileFlags> Files) { | |
| 68 | assert(!Files.empty() && "expected non-empty file list"); | |
| 66 | static void checkFlags(ArrayRef<FileFlags> files) { | |
| 67 | assert(!files.empty() && "expected non-empty file list"); | |
| 69 | 68 | |
| 70 | uint32_t ABI = Files[0].Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); | |
| 71 | bool Nan = Files[0].Flags & EF_MIPS_NAN2008; | |
| 72 | bool Fp = Files[0].Flags & EF_MIPS_FP64; | |
| 69 | uint32_t abi = files[0].flags & (EF_MIPS_ABI | EF_MIPS_ABI2); | |
| 70 | bool nan = files[0].flags & EF_MIPS_NAN2008; | |
| 71 | bool fp = files[0].flags & EF_MIPS_FP64; | |
| 73 | 72 | |
| 74 | for (const FileFlags &F : Files) { | |
| 75 | if (Config->Is64 && F.Flags & EF_MIPS_MICROMIPS) | |
| 76 | error(toString(F.File) + ": microMIPS 64-bit is not supported"); | |
| 73 | for (const FileFlags &f : files) { | |
| 74 | if (config->is64 && f.flags & EF_MIPS_MICROMIPS) | |
| 75 | error(toString(f.file) + ": microMIPS 64-bit is not supported"); | |
| 77 | 76 | |
| 78 | uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); | |
| 79 | if (ABI != ABI2) | |
| 80 | error(toString(F.File) + ": ABI '" + getAbiName(ABI2) + | |
| 81 | "' is incompatible with target ABI '" + getAbiName(ABI) + "'"); | |
| 77 | uint32_t abi2 = f.flags & (EF_MIPS_ABI | EF_MIPS_ABI2); | |
| 78 | if (abi != abi2) | |
| 79 | error(toString(f.file) + ": ABI '" + getAbiName(abi2) + | |
| 80 | "' is incompatible with target ABI '" + getAbiName(abi) + "'"); | |
| 82 | 81 | |
| 83 | bool Nan2 = F.Flags & EF_MIPS_NAN2008; | |
| 84 | if (Nan != Nan2) | |
| 85 | error(toString(F.File) + ": -mnan=" + getNanName(Nan2) + | |
| 86 | " is incompatible with target -mnan=" + getNanName(Nan)); | |
| 82 | bool nan2 = f.flags & EF_MIPS_NAN2008; | |
| 83 | if (nan != nan2) | |
| 84 | error(toString(f.file) + ": -mnan=" + getNanName(nan2) + | |
| 85 | " is incompatible with target -mnan=" + getNanName(nan)); | |
| 87 | 86 | |
| 88 | bool Fp2 = F.Flags & EF_MIPS_FP64; | |
| 89 | if (Fp != Fp2) | |
| 90 | error(toString(F.File) + ": -mfp" + getFpName(Fp2) + | |
| 91 | " is incompatible with target -mfp" + getFpName(Fp)); | |
| 87 | bool fp2 = f.flags & EF_MIPS_FP64; | |
| 88 | if (fp != fp2) | |
| 89 | error(toString(f.file) + ": -mfp" + getFpName(fp2) + | |
| 90 | " is incompatible with target -mfp" + getFpName(fp)); | |
| 92 | 91 | } |
| 93 | 92 | } |
| 94 | 93 | |
| 95 | static uint32_t getMiscFlags(ArrayRef<FileFlags> Files) { | |
| 96 | uint32_t Ret = 0; | |
| 97 | for (const FileFlags &F : Files) | |
| 98 | Ret |= F.Flags & | |
| 94 | static uint32_t getMiscFlags(ArrayRef<FileFlags> files) { | |
| 95 | uint32_t ret = 0; | |
| 96 | for (const FileFlags &f : files) | |
| 97 | ret |= f.flags & | |
| 99 | 98 | (EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER | |
| 100 | 99 | EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE); |
| 101 | return Ret; | |
| 100 | return ret; | |
| 102 | 101 | } |
| 103 | 102 | |
| 104 | static uint32_t getPicFlags(ArrayRef<FileFlags> Files) { | |
| 103 | static uint32_t getPicFlags(ArrayRef<FileFlags> files) { | |
| 105 | 104 | // Check PIC/non-PIC compatibility. |
| 106 | bool IsPic = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); | |
| 107 | for (const FileFlags &F : Files.slice(1)) { | |
| 108 | bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); | |
| 109 | if (IsPic && !IsPic2) | |
| 110 | warn(toString(F.File) + | |
| 105 | bool isPic = files[0].flags & (EF_MIPS_PIC | EF_MIPS_CPIC); | |
| 106 | for (const FileFlags &f : files.slice(1)) { | |
| 107 | bool isPic2 = f.flags & (EF_MIPS_PIC | EF_MIPS_CPIC); | |
| 108 | if (isPic && !isPic2) | |
| 109 | warn(toString(f.file) + | |
| 111 | 110 | ": linking non-abicalls code with abicalls code " + |
| 112 | toString(Files[0].File)); | |
| 113 | if (!IsPic && IsPic2) | |
| 114 | warn(toString(F.File) + | |
| 111 | toString(files[0].file)); | |
| 112 | if (!isPic && isPic2) | |
| 113 | warn(toString(f.file) + | |
| 115 | 114 | ": linking abicalls code with non-abicalls code " + |
| 116 | toString(Files[0].File)); | |
| 115 | toString(files[0].file)); | |
| 117 | 116 | } |
| 118 | 117 | |
| 119 | 118 | // Compute the result PIC/non-PIC flag. |
| 120 | uint32_t Ret = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); | |
| 121 | for (const FileFlags &F : Files.slice(1)) | |
| 122 | Ret &= F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); | |
| 119 | uint32_t ret = files[0].flags & (EF_MIPS_PIC | EF_MIPS_CPIC); | |
| 120 | for (const FileFlags &f : files.slice(1)) | |
| 121 | ret &= f.flags & (EF_MIPS_PIC | EF_MIPS_CPIC); | |
| 123 | 122 | |
| 124 | 123 | // PIC code is inherently CPIC and may not set CPIC flag explicitly. |
| 125 | if (Ret & EF_MIPS_PIC) | |
| 126 | Ret |= EF_MIPS_CPIC; | |
| 127 | return Ret; | |
| 124 | if (ret & EF_MIPS_PIC) | |
| 125 | ret |= EF_MIPS_CPIC; | |
| 126 | return ret; | |
| 128 | 127 | } |
| 129 | 128 | |
| 130 | static ArchTreeEdge ArchTree[] = { | |
| 129 | static ArchTreeEdge archTree[] = { | |
| 131 | 130 | // MIPS32R6 and MIPS64R6 are not compatible with other extensions |
| 132 | 131 | // MIPS64R2 extensions. |
| 133 | 132 | {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2}, |
| ... | ... | @@ -167,25 +166,25 @@ static ArchTreeEdge ArchTree[] = { |
| 167 | 166 | {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1}, |
| 168 | 167 | }; |
| 169 | 168 | |
| 170 | static bool isArchMatched(uint32_t New, uint32_t Res) { | |
| 171 | if (New == Res) | |
| 169 | static bool isArchMatched(uint32_t New, uint32_t res) { | |
| 170 | if (New == res) | |
| 172 | 171 | return true; |
| 173 | if (New == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, Res)) | |
| 172 | if (New == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, res)) | |
| 174 | 173 | return true; |
| 175 | if (New == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, Res)) | |
| 174 | if (New == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, res)) | |
| 176 | 175 | return true; |
| 177 | for (const auto &Edge : ArchTree) { | |
| 178 | if (Res == Edge.Child) { | |
| 179 | Res = Edge.Parent; | |
| 180 | if (Res == New) | |
| 176 | for (const auto &edge : archTree) { | |
| 177 | if (res == edge.child) { | |
| 178 | res = edge.parent; | |
| 179 | if (res == New) | |
| 181 | 180 | return true; |
| 182 | 181 | } |
| 183 | 182 | } |
| 184 | 183 | return false; |
| 185 | 184 | } |
| 186 | 185 | |
| 187 | static StringRef getMachName(uint32_t Flags) { | |
| 188 | switch (Flags & EF_MIPS_MACH) { | |
| 186 | static StringRef getMachName(uint32_t flags) { | |
| 187 | switch (flags & EF_MIPS_MACH) { | |
| 189 | 188 | case EF_MIPS_MACH_NONE: |
| 190 | 189 | return ""; |
| 191 | 190 | case EF_MIPS_MACH_3900: |
| ... | ... | @@ -229,8 +228,8 @@ static StringRef getMachName(uint32_t Flags) { |
| 229 | 228 | } |
| 230 | 229 | } |
| 231 | 230 | |
| 232 | static StringRef getArchName(uint32_t Flags) { | |
| 233 | switch (Flags & EF_MIPS_ARCH) { | |
| 231 | static StringRef getArchName(uint32_t flags) { | |
| 232 | switch (flags & EF_MIPS_ARCH) { | |
| 234 | 233 | case EF_MIPS_ARCH_1: |
| 235 | 234 | return "mips1"; |
| 236 | 235 | case EF_MIPS_ARCH_2: |
| ... | ... | @@ -258,12 +257,12 @@ static StringRef getArchName(uint32_t Flags) { |
| 258 | 257 | } |
| 259 | 258 | } |
| 260 | 259 | |
| 261 | static std::string getFullArchName(uint32_t Flags) { | |
| 262 | StringRef Arch = getArchName(Flags); | |
| 263 | StringRef Mach = getMachName(Flags); | |
| 264 | if (Mach.empty()) | |
| 265 | return Arch.str(); | |
| 266 | return (Arch + " (" + Mach + ")").str(); | |
| 260 | static std::string getFullArchName(uint32_t flags) { | |
| 261 | StringRef arch = getArchName(flags); | |
| 262 | StringRef mach = getMachName(flags); | |
| 263 | if (mach.empty()) | |
| 264 | return arch.str(); | |
| 265 | return (arch + " (" + mach + ")").str(); | |
| 267 | 266 | } |
| 268 | 267 | |
| 269 | 268 | // There are (arguably too) many MIPS ISAs out there. Their relationships |
| ... | ... | @@ -275,55 +274,55 @@ static std::string getFullArchName(uint32_t Flags) { |
| 275 | 274 | // Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32 |
| 276 | 275 | // are incompatible because nor mips3 is a parent for misp32, nor mips32 |
| 277 | 276 | // is a parent for mips3. |
| 278 | static uint32_t getArchFlags(ArrayRef<FileFlags> Files) { | |
| 279 | uint32_t Ret = Files[0].Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); | |
| 277 | static uint32_t getArchFlags(ArrayRef<FileFlags> files) { | |
| 278 | uint32_t ret = files[0].flags & (EF_MIPS_ARCH | EF_MIPS_MACH); | |
| 280 | 279 | |
| 281 | for (const FileFlags &F : Files.slice(1)) { | |
| 282 | uint32_t New = F.Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); | |
| 280 | for (const FileFlags &f : files.slice(1)) { | |
| 281 | uint32_t New = f.flags & (EF_MIPS_ARCH | EF_MIPS_MACH); | |
| 283 | 282 | |
| 284 | 283 | // Check ISA compatibility. |
| 285 | if (isArchMatched(New, Ret)) | |
| 284 | if (isArchMatched(New, ret)) | |
| 286 | 285 | continue; |
| 287 | if (!isArchMatched(Ret, New)) { | |
| 288 | error("incompatible target ISA:\n>>> " + toString(Files[0].File) + ": " + | |
| 289 | getFullArchName(Ret) + "\n>>> " + toString(F.File) + ": " + | |
| 286 | if (!isArchMatched(ret, New)) { | |
| 287 | error("incompatible target ISA:\n>>> " + toString(files[0].file) + ": " + | |
| 288 | getFullArchName(ret) + "\n>>> " + toString(f.file) + ": " + | |
| 290 | 289 | getFullArchName(New)); |
| 291 | 290 | return 0; |
| 292 | 291 | } |
| 293 | Ret = New; | |
| 292 | ret = New; | |
| 294 | 293 | } |
| 295 | return Ret; | |
| 294 | return ret; | |
| 296 | 295 | } |
| 297 | 296 | |
| 298 | 297 | template <class ELFT> uint32_t elf::calcMipsEFlags() { |
| 299 | std::vector<FileFlags> V; | |
| 300 | for (InputFile *F : ObjectFiles) | |
| 301 | V.push_back({F, cast<ObjFile<ELFT>>(F)->getObj().getHeader()->e_flags}); | |
| 302 | if (V.empty()) | |
| 298 | std::vector<FileFlags> v; | |
| 299 | for (InputFile *f : objectFiles) | |
| 300 | v.push_back({f, cast<ObjFile<ELFT>>(f)->getObj().getHeader()->e_flags}); | |
| 301 | if (v.empty()) | |
| 303 | 302 | return 0; |
| 304 | checkFlags(V); | |
| 305 | return getMiscFlags(V) | getPicFlags(V) | getArchFlags(V); | |
| 303 | checkFlags(v); | |
| 304 | return getMiscFlags(v) | getPicFlags(v) | getArchFlags(v); | |
| 306 | 305 | } |
| 307 | 306 | |
| 308 | static int compareMipsFpAbi(uint8_t FpA, uint8_t FpB) { | |
| 309 | if (FpA == FpB) | |
| 307 | static int compareMipsFpAbi(uint8_t fpA, uint8_t fpB) { | |
| 308 | if (fpA == fpB) | |
| 310 | 309 | return 0; |
| 311 | if (FpB == Mips::Val_GNU_MIPS_ABI_FP_ANY) | |
| 310 | if (fpB == Mips::Val_GNU_MIPS_ABI_FP_ANY) | |
| 312 | 311 | return 1; |
| 313 | if (FpB == Mips::Val_GNU_MIPS_ABI_FP_64A && | |
| 314 | FpA == Mips::Val_GNU_MIPS_ABI_FP_64) | |
| 312 | if (fpB == Mips::Val_GNU_MIPS_ABI_FP_64A && | |
| 313 | fpA == Mips::Val_GNU_MIPS_ABI_FP_64) | |
| 315 | 314 | return 1; |
| 316 | if (FpB != Mips::Val_GNU_MIPS_ABI_FP_XX) | |
| 315 | if (fpB != Mips::Val_GNU_MIPS_ABI_FP_XX) | |
| 317 | 316 | return -1; |
| 318 | if (FpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE || | |
| 319 | FpA == Mips::Val_GNU_MIPS_ABI_FP_64 || | |
| 320 | FpA == Mips::Val_GNU_MIPS_ABI_FP_64A) | |
| 317 | if (fpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE || | |
| 318 | fpA == Mips::Val_GNU_MIPS_ABI_FP_64 || | |
| 319 | fpA == Mips::Val_GNU_MIPS_ABI_FP_64A) | |
| 321 | 320 | return 1; |
| 322 | 321 | return -1; |
| 323 | 322 | } |
| 324 | 323 | |
| 325 | static StringRef getMipsFpAbiName(uint8_t FpAbi) { | |
| 326 | switch (FpAbi) { | |
| 324 | static StringRef getMipsFpAbiName(uint8_t fpAbi) { | |
| 325 | switch (fpAbi) { | |
| 327 | 326 | case Mips::Val_GNU_MIPS_ABI_FP_ANY: |
| 328 | 327 | return "any"; |
| 329 | 328 | case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE: |
| ... | ... | @@ -345,43 +344,43 @@ static StringRef getMipsFpAbiName(uint8_t FpAbi) { |
| 345 | 344 | } |
| 346 | 345 | } |
| 347 | 346 | |
| 348 | uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag, | |
| 349 | StringRef FileName) { | |
| 350 | if (compareMipsFpAbi(NewFlag, OldFlag) >= 0) | |
| 351 | return NewFlag; | |
| 352 | if (compareMipsFpAbi(OldFlag, NewFlag) < 0) | |
| 353 | error(FileName + ": floating point ABI '" + getMipsFpAbiName(NewFlag) + | |
| 347 | uint8_t elf::getMipsFpAbiFlag(uint8_t oldFlag, uint8_t newFlag, | |
| 348 | StringRef fileName) { | |
| 349 | if (compareMipsFpAbi(newFlag, oldFlag) >= 0) | |
| 350 | return newFlag; | |
| 351 | if (compareMipsFpAbi(oldFlag, newFlag) < 0) | |
| 352 | error(fileName + ": floating point ABI '" + getMipsFpAbiName(newFlag) + | |
| 354 | 353 | "' is incompatible with target floating point ABI '" + |
| 355 | getMipsFpAbiName(OldFlag) + "'"); | |
| 356 | return OldFlag; | |
| 354 | getMipsFpAbiName(oldFlag) + "'"); | |
| 355 | return oldFlag; | |
| 357 | 356 | } |
| 358 | 357 | |
| 359 | template <class ELFT> static bool isN32Abi(const InputFile *F) { | |
| 360 | if (auto *EF = dyn_cast<ELFFileBase<ELFT>>(F)) | |
| 361 | return EF->getObj().getHeader()->e_flags & EF_MIPS_ABI2; | |
| 358 | template <class ELFT> static bool isN32Abi(const InputFile *f) { | |
| 359 | if (auto *ef = dyn_cast<ELFFileBase>(f)) | |
| 360 | return ef->template getObj<ELFT>().getHeader()->e_flags & EF_MIPS_ABI2; | |
| 362 | 361 | return false; |
| 363 | 362 | } |
| 364 | 363 | |
| 365 | bool elf::isMipsN32Abi(const InputFile *F) { | |
| 366 | switch (Config->EKind) { | |
| 364 | bool elf::isMipsN32Abi(const InputFile *f) { | |
| 365 | switch (config->ekind) { | |
| 367 | 366 | case ELF32LEKind: |
| 368 | return isN32Abi<ELF32LE>(F); | |
| 367 | return isN32Abi<ELF32LE>(f); | |
| 369 | 368 | case ELF32BEKind: |
| 370 | return isN32Abi<ELF32BE>(F); | |
| 369 | return isN32Abi<ELF32BE>(f); | |
| 371 | 370 | case ELF64LEKind: |
| 372 | return isN32Abi<ELF64LE>(F); | |
| 371 | return isN32Abi<ELF64LE>(f); | |
| 373 | 372 | case ELF64BEKind: |
| 374 | return isN32Abi<ELF64BE>(F); | |
| 373 | return isN32Abi<ELF64BE>(f); | |
| 375 | 374 | default: |
| 376 | 375 | llvm_unreachable("unknown Config->EKind"); |
| 377 | 376 | } |
| 378 | 377 | } |
| 379 | 378 | |
| 380 | bool elf::isMicroMips() { return Config->EFlags & EF_MIPS_MICROMIPS; } | |
| 379 | bool elf::isMicroMips() { return config->eflags & EF_MIPS_MICROMIPS; } | |
| 381 | 380 | |
| 382 | 381 | bool elf::isMipsR6() { |
| 383 | uint32_t Arch = Config->EFlags & EF_MIPS_ARCH; | |
| 384 | return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6; | |
| 382 | uint32_t arch = config->eflags & EF_MIPS_ARCH; | |
| 383 | return arch == EF_MIPS_ARCH_32R6 || arch == EF_MIPS_ARCH_64R6; | |
| 385 | 384 | } |
| 386 | 385 | |
| 387 | 386 | template uint32_t elf::calcMipsEFlags<ELF32LE>(); |
deps/lld/ELF/Arch/PPC.cpp+379-28| ... | ... | @@ -1,13 +1,14 @@ |
| 1 | 1 | //===- PPC.cpp ------------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| 9 | #include "OutputSections.h" | |
| 10 | 10 | #include "Symbols.h" |
| 11 | #include "SyntheticSections.h" | |
| 11 | 12 | #include "Target.h" |
| 12 | 13 | #include "lld/Common/ErrorHandler.h" |
| 13 | 14 | #include "llvm/Support/Endian.h" |
| ... | ... | @@ -22,60 +23,410 @@ namespace { |
| 22 | 23 | class PPC final : public TargetInfo { |
| 23 | 24 | public: |
| 24 | 25 | PPC(); |
| 25 | void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 26 | RelExpr getRelExpr(RelType Type, const Symbol &S, | |
| 27 | const uint8_t *Loc) const override; | |
| 26 | RelExpr getRelExpr(RelType type, const Symbol &s, | |
| 27 | const uint8_t *loc) const override; | |
| 28 | RelType getDynRel(RelType type) const override; | |
| 29 | void writeGotHeader(uint8_t *buf) const override; | |
| 30 | void writePltHeader(uint8_t *buf) const override { | |
| 31 | llvm_unreachable("should call writePPC32GlinkSection() instead"); | |
| 32 | } | |
| 33 | void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, | |
| 34 | int32_t index, unsigned relOff) const override { | |
| 35 | llvm_unreachable("should call writePPC32GlinkSection() instead"); | |
| 36 | } | |
| 37 | void writeGotPlt(uint8_t *buf, const Symbol &s) const override; | |
| 38 | bool needsThunk(RelExpr expr, RelType relocType, const InputFile *file, | |
| 39 | uint64_t branchAddr, const Symbol &s) const override; | |
| 40 | uint32_t getThunkSectionSpacing() const override; | |
| 41 | bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; | |
| 42 | void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 43 | RelExpr adjustRelaxExpr(RelType type, const uint8_t *data, | |
| 44 | RelExpr expr) const override; | |
| 45 | int getTlsGdRelaxSkip(RelType type) const override; | |
| 46 | void relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 47 | void relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 48 | void relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 49 | void relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 28 | 50 | }; |
| 29 | 51 | } // namespace |
| 30 | 52 | |
| 53 | static uint16_t lo(uint32_t v) { return v; } | |
| 54 | static uint16_t ha(uint32_t v) { return (v + 0x8000) >> 16; } | |
| 55 | ||
| 56 | static uint32_t readFromHalf16(const uint8_t *loc) { | |
| 57 | return read32(config->isLE ? loc : loc - 2); | |
| 58 | } | |
| 59 | ||
| 60 | static void writeFromHalf16(uint8_t *loc, uint32_t insn) { | |
| 61 | write32(config->isLE ? loc : loc - 2, insn); | |
| 62 | } | |
| 63 | ||
| 64 | void elf::writePPC32GlinkSection(uint8_t *buf, size_t numEntries) { | |
| 65 | // On PPC Secure PLT ABI, bl foo@plt jumps to a call stub, which loads an | |
| 66 | // absolute address from a specific .plt slot (usually called .got.plt on | |
| 67 | // other targets) and jumps there. | |
| 68 | // | |
| 69 | // a) With immediate binding (BIND_NOW), the .plt entry is resolved at load | |
| 70 | // time. The .glink section is not used. | |
| 71 | // b) With lazy binding, the .plt entry points to a `b PLTresolve` | |
| 72 | // instruction in .glink, filled in by PPC::writeGotPlt(). | |
| 73 | ||
| 74 | // Write N `b PLTresolve` first. | |
| 75 | for (size_t i = 0; i != numEntries; ++i) | |
| 76 | write32(buf + 4 * i, 0x48000000 | 4 * (numEntries - i)); | |
| 77 | buf += 4 * numEntries; | |
| 78 | ||
| 79 | // Then write PLTresolve(), which has two forms: PIC and non-PIC. PLTresolve() | |
| 80 | // computes the PLT index (by computing the distance from the landing b to | |
| 81 | // itself) and calls _dl_runtime_resolve() (in glibc). | |
| 82 | uint32_t got = in.got->getVA(); | |
| 83 | uint32_t glink = in.plt->getVA(); // VA of .glink | |
| 84 | const uint8_t *end = buf + 64; | |
| 85 | if (config->isPic) { | |
| 86 | uint32_t afterBcl = in.plt->getSize() - target->pltHeaderSize + 12; | |
| 87 | uint32_t gotBcl = got + 4 - (glink + afterBcl); | |
| 88 | write32(buf + 0, 0x3d6b0000 | ha(afterBcl)); // addis r11,r11,1f-glink@ha | |
| 89 | write32(buf + 4, 0x7c0802a6); // mflr r0 | |
| 90 | write32(buf + 8, 0x429f0005); // bcl 20,30,.+4 | |
| 91 | write32(buf + 12, 0x396b0000 | lo(afterBcl)); // 1: addi r11,r11,1b-.glink@l | |
| 92 | write32(buf + 16, 0x7d8802a6); // mflr r12 | |
| 93 | write32(buf + 20, 0x7c0803a6); // mtlr r0 | |
| 94 | write32(buf + 24, 0x7d6c5850); // sub r11,r11,r12 | |
| 95 | write32(buf + 28, 0x3d8c0000 | ha(gotBcl)); // addis 12,12,GOT+4-1b@ha | |
| 96 | if (ha(gotBcl) == ha(gotBcl + 4)) { | |
| 97 | write32(buf + 32, 0x800c0000 | lo(gotBcl)); // lwz r0,r12,GOT+4-1b@l(r12) | |
| 98 | write32(buf + 36, | |
| 99 | 0x818c0000 | lo(gotBcl + 4)); // lwz r12,r12,GOT+8-1b@l(r12) | |
| 100 | } else { | |
| 101 | write32(buf + 32, 0x840c0000 | lo(gotBcl)); // lwzu r0,r12,GOT+4-1b@l(r12) | |
| 102 | write32(buf + 36, 0x818c0000 | 4); // lwz r12,r12,4(r12) | |
| 103 | } | |
| 104 | write32(buf + 40, 0x7c0903a6); // mtctr 0 | |
| 105 | write32(buf + 44, 0x7c0b5a14); // add r0,11,11 | |
| 106 | write32(buf + 48, 0x7d605a14); // add r11,0,11 | |
| 107 | write32(buf + 52, 0x4e800420); // bctr | |
| 108 | buf += 56; | |
| 109 | } else { | |
| 110 | write32(buf + 0, 0x3d800000 | ha(got + 4)); // lis r12,GOT+4@ha | |
| 111 | write32(buf + 4, 0x3d6b0000 | ha(-glink)); // addis r11,r11,-Glink@ha | |
| 112 | if (ha(got + 4) == ha(got + 8)) | |
| 113 | write32(buf + 8, 0x800c0000 | lo(got + 4)); // lwz r0,GOT+4@l(r12) | |
| 114 | else | |
| 115 | write32(buf + 8, 0x840c0000 | lo(got + 4)); // lwzu r0,GOT+4@l(r12) | |
| 116 | write32(buf + 12, 0x396b0000 | lo(-glink)); // addi r11,r11,-Glink@l | |
| 117 | write32(buf + 16, 0x7c0903a6); // mtctr r0 | |
| 118 | write32(buf + 20, 0x7c0b5a14); // add r0,r11,r11 | |
| 119 | if (ha(got + 4) == ha(got + 8)) | |
| 120 | write32(buf + 24, 0x818c0000 | lo(got + 8)); // lwz r12,GOT+8@ha(r12) | |
| 121 | else | |
| 122 | write32(buf + 24, 0x818c0000 | 4); // lwz r12,4(r12) | |
| 123 | write32(buf + 28, 0x7d605a14); // add r11,r0,r11 | |
| 124 | write32(buf + 32, 0x4e800420); // bctr | |
| 125 | buf += 36; | |
| 126 | } | |
| 127 | ||
| 128 | // Pad with nop. They should not be executed. | |
| 129 | for (; buf < end; buf += 4) | |
| 130 | write32(buf, 0x60000000); | |
| 131 | } | |
| 132 | ||
| 31 | 133 | PPC::PPC() { |
| 32 | NoneRel = R_PPC_NONE; | |
| 33 | GotBaseSymOff = 0x8000; | |
| 34 | GotBaseSymInGotPlt = false; | |
| 134 | gotRel = R_PPC_GLOB_DAT; | |
| 135 | noneRel = R_PPC_NONE; | |
| 136 | pltRel = R_PPC_JMP_SLOT; | |
| 137 | relativeRel = R_PPC_RELATIVE; | |
| 138 | iRelativeRel = R_PPC_IRELATIVE; | |
| 139 | symbolicRel = R_PPC_ADDR32; | |
| 140 | gotBaseSymInGotPlt = false; | |
| 141 | gotHeaderEntriesNum = 3; | |
| 142 | gotPltHeaderEntriesNum = 0; | |
| 143 | pltHeaderSize = 64; // size of PLTresolve in .glink | |
| 144 | pltEntrySize = 4; | |
| 145 | ||
| 146 | needsThunks = true; | |
| 147 | ||
| 148 | tlsModuleIndexRel = R_PPC_DTPMOD32; | |
| 149 | tlsOffsetRel = R_PPC_DTPREL32; | |
| 150 | tlsGotRel = R_PPC_TPREL32; | |
| 151 | ||
| 152 | defaultMaxPageSize = 65536; | |
| 153 | defaultImageBase = 0x10000000; | |
| 154 | ||
| 155 | write32(trapInstr.data(), 0x7fe00008); | |
| 156 | } | |
| 157 | ||
| 158 | void PPC::writeGotHeader(uint8_t *buf) const { | |
| 159 | // _GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC | |
| 160 | // glibc stores _dl_runtime_resolve in _GLOBAL_OFFSET_TABLE_[1], | |
| 161 | // link_map in _GLOBAL_OFFSET_TABLE_[2]. | |
| 162 | write32(buf, mainPart->dynamic->getVA()); | |
| 163 | } | |
| 164 | ||
| 165 | void PPC::writeGotPlt(uint8_t *buf, const Symbol &s) const { | |
| 166 | // Address of the symbol resolver stub in .glink . | |
| 167 | write32(buf, in.plt->getVA() + 4 * s.pltIndex); | |
| 168 | } | |
| 169 | ||
| 170 | bool PPC::needsThunk(RelExpr expr, RelType type, const InputFile *file, | |
| 171 | uint64_t branchAddr, const Symbol &s) const { | |
| 172 | if (type != R_PPC_REL24 && type != R_PPC_PLTREL24) | |
| 173 | return false; | |
| 174 | if (s.isInPlt()) | |
| 175 | return true; | |
| 176 | if (s.isUndefWeak()) | |
| 177 | return false; | |
| 178 | return !(expr == R_PC && PPC::inBranchRange(type, branchAddr, s.getVA())); | |
| 35 | 179 | } |
| 36 | 180 | |
| 37 | RelExpr PPC::getRelExpr(RelType Type, const Symbol &S, | |
| 38 | const uint8_t *Loc) const { | |
| 39 | switch (Type) { | |
| 181 | uint32_t PPC::getThunkSectionSpacing() const { return 0x2000000; } | |
| 182 | ||
| 183 | bool PPC::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { | |
| 184 | uint64_t offset = dst - src; | |
| 185 | if (type == R_PPC_REL24 || type == R_PPC_PLTREL24) | |
| 186 | return isInt<26>(offset); | |
| 187 | llvm_unreachable("unsupported relocation type used in branch"); | |
| 188 | } | |
| 189 | ||
| 190 | RelExpr PPC::getRelExpr(RelType type, const Symbol &s, | |
| 191 | const uint8_t *loc) const { | |
| 192 | switch (type) { | |
| 193 | case R_PPC_DTPREL16: | |
| 194 | case R_PPC_DTPREL16_HA: | |
| 195 | case R_PPC_DTPREL16_HI: | |
| 196 | case R_PPC_DTPREL16_LO: | |
| 197 | case R_PPC_DTPREL32: | |
| 198 | return R_DTPREL; | |
| 40 | 199 | case R_PPC_REL14: |
| 41 | case R_PPC_REL24: | |
| 42 | 200 | case R_PPC_REL32: |
| 201 | case R_PPC_LOCAL24PC: | |
| 202 | case R_PPC_REL16_LO: | |
| 203 | case R_PPC_REL16_HI: | |
| 204 | case R_PPC_REL16_HA: | |
| 43 | 205 | return R_PC; |
| 44 | case R_PPC_PLTREL24: | |
| 206 | case R_PPC_GOT16: | |
| 207 | return R_GOT_OFF; | |
| 208 | case R_PPC_REL24: | |
| 45 | 209 | return R_PLT_PC; |
| 210 | case R_PPC_PLTREL24: | |
| 211 | return R_PPC32_PLTREL; | |
| 212 | case R_PPC_GOT_TLSGD16: | |
| 213 | return R_TLSGD_GOT; | |
| 214 | case R_PPC_GOT_TLSLD16: | |
| 215 | return R_TLSLD_GOT; | |
| 216 | case R_PPC_GOT_TPREL16: | |
| 217 | return R_GOT_OFF; | |
| 218 | case R_PPC_TLS: | |
| 219 | return R_TLSIE_HINT; | |
| 220 | case R_PPC_TLSGD: | |
| 221 | return R_TLSDESC_CALL; | |
| 222 | case R_PPC_TLSLD: | |
| 223 | return R_TLSLD_HINT; | |
| 224 | case R_PPC_TPREL16: | |
| 225 | case R_PPC_TPREL16_HA: | |
| 226 | case R_PPC_TPREL16_LO: | |
| 227 | case R_PPC_TPREL16_HI: | |
| 228 | return R_TLS; | |
| 46 | 229 | default: |
| 47 | 230 | return R_ABS; |
| 48 | 231 | } |
| 49 | 232 | } |
| 50 | 233 | |
| 51 | void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 52 | switch (Type) { | |
| 234 | RelType PPC::getDynRel(RelType type) const { | |
| 235 | if (type == R_PPC_ADDR32) | |
| 236 | return type; | |
| 237 | return R_PPC_NONE; | |
| 238 | } | |
| 239 | ||
| 240 | static std::pair<RelType, uint64_t> fromDTPREL(RelType type, uint64_t val) { | |
| 241 | uint64_t dtpBiasedVal = val - 0x8000; | |
| 242 | switch (type) { | |
| 243 | case R_PPC_DTPREL16: | |
| 244 | return {R_PPC64_ADDR16, dtpBiasedVal}; | |
| 245 | case R_PPC_DTPREL16_HA: | |
| 246 | return {R_PPC_ADDR16_HA, dtpBiasedVal}; | |
| 247 | case R_PPC_DTPREL16_HI: | |
| 248 | return {R_PPC_ADDR16_HI, dtpBiasedVal}; | |
| 249 | case R_PPC_DTPREL16_LO: | |
| 250 | return {R_PPC_ADDR16_LO, dtpBiasedVal}; | |
| 251 | case R_PPC_DTPREL32: | |
| 252 | return {R_PPC_ADDR32, dtpBiasedVal}; | |
| 253 | default: | |
| 254 | return {type, val}; | |
| 255 | } | |
| 256 | } | |
| 257 | ||
| 258 | void PPC::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { | |
| 259 | RelType newType; | |
| 260 | std::tie(newType, val) = fromDTPREL(type, val); | |
| 261 | switch (newType) { | |
| 262 | case R_PPC_ADDR16: | |
| 263 | checkIntUInt(loc, val, 16, type); | |
| 264 | write16(loc, val); | |
| 265 | break; | |
| 266 | case R_PPC_GOT16: | |
| 267 | case R_PPC_GOT_TLSGD16: | |
| 268 | case R_PPC_GOT_TLSLD16: | |
| 269 | case R_PPC_GOT_TPREL16: | |
| 270 | case R_PPC_TPREL16: | |
| 271 | checkInt(loc, val, 16, type); | |
| 272 | write16(loc, val); | |
| 273 | break; | |
| 53 | 274 | case R_PPC_ADDR16_HA: |
| 54 | write16be(Loc, (Val + 0x8000) >> 16); | |
| 275 | case R_PPC_DTPREL16_HA: | |
| 276 | case R_PPC_GOT_TLSGD16_HA: | |
| 277 | case R_PPC_GOT_TLSLD16_HA: | |
| 278 | case R_PPC_GOT_TPREL16_HA: | |
| 279 | case R_PPC_REL16_HA: | |
| 280 | case R_PPC_TPREL16_HA: | |
| 281 | write16(loc, ha(val)); | |
| 55 | 282 | break; |
| 56 | 283 | case R_PPC_ADDR16_HI: |
| 57 | write16be(Loc, Val >> 16); | |
| 284 | case R_PPC_DTPREL16_HI: | |
| 285 | case R_PPC_GOT_TLSGD16_HI: | |
| 286 | case R_PPC_GOT_TLSLD16_HI: | |
| 287 | case R_PPC_GOT_TPREL16_HI: | |
| 288 | case R_PPC_REL16_HI: | |
| 289 | case R_PPC_TPREL16_HI: | |
| 290 | write16(loc, val >> 16); | |
| 58 | 291 | break; |
| 59 | 292 | case R_PPC_ADDR16_LO: |
| 60 | write16be(Loc, Val); | |
| 293 | case R_PPC_DTPREL16_LO: | |
| 294 | case R_PPC_GOT_TLSGD16_LO: | |
| 295 | case R_PPC_GOT_TLSLD16_LO: | |
| 296 | case R_PPC_GOT_TPREL16_LO: | |
| 297 | case R_PPC_REL16_LO: | |
| 298 | case R_PPC_TPREL16_LO: | |
| 299 | write16(loc, val); | |
| 61 | 300 | break; |
| 62 | 301 | case R_PPC_ADDR32: |
| 63 | 302 | case R_PPC_REL32: |
| 64 | write32be(Loc, Val); | |
| 303 | write32(loc, val); | |
| 65 | 304 | break; |
| 66 | case R_PPC_REL14: | |
| 67 | write32be(Loc, read32be(Loc) | (Val & 0xFFFC)); | |
| 305 | case R_PPC_REL14: { | |
| 306 | uint32_t mask = 0x0000FFFC; | |
| 307 | checkInt(loc, val, 16, type); | |
| 308 | checkAlignment(loc, val, 4, type); | |
| 309 | write32(loc, (read32(loc) & ~mask) | (val & mask)); | |
| 68 | 310 | break; |
| 69 | case R_PPC_PLTREL24: | |
| 311 | } | |
| 70 | 312 | case R_PPC_REL24: |
| 71 | write32be(Loc, read32be(Loc) | (Val & 0x3FFFFFC)); | |
| 313 | case R_PPC_LOCAL24PC: | |
| 314 | case R_PPC_PLTREL24: { | |
| 315 | uint32_t mask = 0x03FFFFFC; | |
| 316 | checkInt(loc, val, 26, type); | |
| 317 | checkAlignment(loc, val, 4, type); | |
| 318 | write32(loc, (read32(loc) & ~mask) | (val & mask)); | |
| 72 | 319 | break; |
| 320 | } | |
| 321 | default: | |
| 322 | error(getErrorLocation(loc) + "unrecognized relocation " + toString(type)); | |
| 323 | } | |
| 324 | } | |
| 325 | ||
| 326 | RelExpr PPC::adjustRelaxExpr(RelType type, const uint8_t *data, | |
| 327 | RelExpr expr) const { | |
| 328 | if (expr == R_RELAX_TLS_GD_TO_IE) | |
| 329 | return R_RELAX_TLS_GD_TO_IE_GOT_OFF; | |
| 330 | if (expr == R_RELAX_TLS_LD_TO_LE) | |
| 331 | return R_RELAX_TLS_LD_TO_LE_ABS; | |
| 332 | return expr; | |
| 333 | } | |
| 334 | ||
| 335 | int PPC::getTlsGdRelaxSkip(RelType type) const { | |
| 336 | // A __tls_get_addr call instruction is marked with 2 relocations: | |
| 337 | // | |
| 338 | // R_PPC_TLSGD / R_PPC_TLSLD: marker relocation | |
| 339 | // R_PPC_REL24: __tls_get_addr | |
| 340 | // | |
| 341 | // After the relaxation we no longer call __tls_get_addr and should skip both | |
| 342 | // relocations to not create a false dependence on __tls_get_addr being | |
| 343 | // defined. | |
| 344 | if (type == R_PPC_TLSGD || type == R_PPC_TLSLD) | |
| 345 | return 2; | |
| 346 | return 1; | |
| 347 | } | |
| 348 | ||
| 349 | void PPC::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 350 | switch (type) { | |
| 351 | case R_PPC_GOT_TLSGD16: { | |
| 352 | // addi rT, rA, x@got@tlsgd --> lwz rT, x@got@tprel(rA) | |
| 353 | uint32_t insn = readFromHalf16(loc); | |
| 354 | writeFromHalf16(loc, 0x80000000 | (insn & 0x03ff0000)); | |
| 355 | relocateOne(loc, R_PPC_GOT_TPREL16, val); | |
| 356 | break; | |
| 357 | } | |
| 358 | case R_PPC_TLSGD: | |
| 359 | // bl __tls_get_addr(x@tldgd) --> add r3, r3, r2 | |
| 360 | write32(loc, 0x7c631214); | |
| 361 | break; | |
| 362 | default: | |
| 363 | llvm_unreachable("unsupported relocation for TLS GD to IE relaxation"); | |
| 364 | } | |
| 365 | } | |
| 366 | ||
| 367 | void PPC::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 368 | switch (type) { | |
| 369 | case R_PPC_GOT_TLSGD16: | |
| 370 | // addi r3, r31, x@got@tlsgd --> addis r3, r2, x@tprel@ha | |
| 371 | writeFromHalf16(loc, 0x3c620000 | ha(val)); | |
| 372 | break; | |
| 373 | case R_PPC_TLSGD: | |
| 374 | // bl __tls_get_addr(x@tldgd) --> add r3, r3, x@tprel@l | |
| 375 | write32(loc, 0x38630000 | lo(val)); | |
| 376 | break; | |
| 377 | default: | |
| 378 | llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); | |
| 379 | } | |
| 380 | } | |
| 381 | ||
| 382 | void PPC::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 383 | switch (type) { | |
| 384 | case R_PPC_GOT_TLSLD16: | |
| 385 | // addi r3, rA, x@got@tlsgd --> addis r3, r2, 0 | |
| 386 | writeFromHalf16(loc, 0x3c620000); | |
| 387 | break; | |
| 388 | case R_PPC_TLSLD: | |
| 389 | // r3+x@dtprel computes r3+x-0x8000, while we want it to compute r3+x@tprel | |
| 390 | // = r3+x-0x7000, so add 4096 to r3. | |
| 391 | // bl __tls_get_addr(x@tlsld) --> addi r3, r3, 4096 | |
| 392 | write32(loc, 0x38631000); | |
| 393 | break; | |
| 394 | case R_PPC_DTPREL16: | |
| 395 | case R_PPC_DTPREL16_HA: | |
| 396 | case R_PPC_DTPREL16_HI: | |
| 397 | case R_PPC_DTPREL16_LO: | |
| 398 | relocateOne(loc, type, val); | |
| 399 | break; | |
| 400 | default: | |
| 401 | llvm_unreachable("unsupported relocation for TLS LD to LE relaxation"); | |
| 402 | } | |
| 403 | } | |
| 404 | ||
| 405 | void PPC::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 406 | switch (type) { | |
| 407 | case R_PPC_GOT_TPREL16: { | |
| 408 | // lwz rT, x@got@tprel(rA) --> addis rT, r2, x@tprel@ha | |
| 409 | uint32_t rt = readFromHalf16(loc) & 0x03e00000; | |
| 410 | writeFromHalf16(loc, 0x3c020000 | rt | ha(val)); | |
| 411 | break; | |
| 412 | } | |
| 413 | case R_PPC_TLS: { | |
| 414 | uint32_t insn = read32(loc); | |
| 415 | if (insn >> 26 != 31) | |
| 416 | error("unrecognized instruction for IE to LE R_PPC_TLS"); | |
| 417 | // addi rT, rT, x@tls --> addi rT, rT, x@tprel@l | |
| 418 | uint32_t dFormOp = getPPCDFormOp((read32(loc) & 0x000007fe) >> 1); | |
| 419 | if (dFormOp == 0) | |
| 420 | error("unrecognized instruction for IE to LE R_PPC_TLS"); | |
| 421 | write32(loc, (dFormOp << 26) | (insn & 0x03ff0000) | lo(val)); | |
| 422 | break; | |
| 423 | } | |
| 73 | 424 | default: |
| 74 | error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); | |
| 425 | llvm_unreachable("unsupported relocation for TLS IE to LE relaxation"); | |
| 75 | 426 | } |
| 76 | 427 | } |
| 77 | 428 | |
| 78 | 429 | TargetInfo *elf::getPPCTargetInfo() { |
| 79 | static PPC Target; | |
| 80 | return &Target; | |
| 430 | static PPC target; | |
| 431 | return &target; | |
| 81 | 432 | } |
deps/lld/ELF/Arch/PPC64.cpp+438-292| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- PPC64.cpp ----------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -20,8 +19,8 @@ using namespace llvm::ELF; |
| 20 | 19 | using namespace lld; |
| 21 | 20 | using namespace lld::elf; |
| 22 | 21 | |
| 23 | static uint64_t PPC64TocOffset = 0x8000; | |
| 24 | static uint64_t DynamicThreadPointerOffset = 0x8000; | |
| 22 | static uint64_t ppc64TocOffset = 0x8000; | |
| 23 | static uint64_t dynamicThreadPointerOffset = 0x8000; | |
| 25 | 24 | |
| 26 | 25 | // The instruction encoding of bits 21-30 from the ISA for the Xform and Dform |
| 27 | 26 | // instructions that can be used as part of the initial exec TLS sequence. |
| ... | ... | @@ -65,16 +64,16 @@ uint64_t elf::getPPC64TocBase() { |
| 65 | 64 | // TOC starts where the first of these sections starts. We always create a |
| 66 | 65 | // .got when we see a relocation that uses it, so for us the start is always |
| 67 | 66 | // the .got. |
| 68 | uint64_t TocVA = In.Got->getVA(); | |
| 67 | uint64_t tocVA = in.got->getVA(); | |
| 69 | 68 | |
| 70 | 69 | // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 |
| 71 | 70 | // thus permitting a full 64 Kbytes segment. Note that the glibc startup |
| 72 | 71 | // code (crt1.o) assumes that you can get from the TOC base to the |
| 73 | 72 | // start of the .toc section with only a single (signed) 16-bit relocation. |
| 74 | return TocVA + PPC64TocOffset; | |
| 73 | return tocVA + ppc64TocOffset; | |
| 75 | 74 | } |
| 76 | 75 | |
| 77 | unsigned elf::getPPC64GlobalEntryToLocalEntryOffset(uint8_t StOther) { | |
| 76 | unsigned elf::getPPC64GlobalEntryToLocalEntryOffset(uint8_t stOther) { | |
| 78 | 77 | // The offset is encoded into the 3 most significant bits of the st_other |
| 79 | 78 | // field, with some special values described in section 3.4.1 of the ABI: |
| 80 | 79 | // 0 --> Zero offset between the GEP and LEP, and the function does NOT use |
| ... | ... | @@ -86,43 +85,134 @@ unsigned elf::getPPC64GlobalEntryToLocalEntryOffset(uint8_t StOther) { |
| 86 | 85 | // 2 --> 2^2 = 4 bytes --> 1 instruction. |
| 87 | 86 | // 6 --> 2^6 = 64 bytes --> 16 instructions. |
| 88 | 87 | // 7 --> Reserved. |
| 89 | uint8_t GepToLep = (StOther >> 5) & 7; | |
| 90 | if (GepToLep < 2) | |
| 88 | uint8_t gepToLep = (stOther >> 5) & 7; | |
| 89 | if (gepToLep < 2) | |
| 91 | 90 | return 0; |
| 92 | 91 | |
| 93 | 92 | // The value encoded in the st_other bits is the |
| 94 | 93 | // log-base-2(offset). |
| 95 | if (GepToLep < 7) | |
| 96 | return 1 << GepToLep; | |
| 94 | if (gepToLep < 7) | |
| 95 | return 1 << gepToLep; | |
| 97 | 96 | |
| 98 | 97 | error("reserved value of 7 in the 3 most-significant-bits of st_other"); |
| 99 | 98 | return 0; |
| 100 | 99 | } |
| 101 | 100 | |
| 101 | bool elf::isPPC64SmallCodeModelTocReloc(RelType type) { | |
| 102 | // The only small code model relocations that access the .toc section. | |
| 103 | return type == R_PPC64_TOC16 || type == R_PPC64_TOC16_DS; | |
| 104 | } | |
| 105 | ||
| 106 | // Find the R_PPC64_ADDR64 in .rela.toc with matching offset. | |
| 107 | template <typename ELFT> | |
| 108 | static std::pair<Defined *, int64_t> | |
| 109 | getRelaTocSymAndAddend(InputSectionBase *tocSec, uint64_t offset) { | |
| 110 | if (tocSec->numRelocations == 0) | |
| 111 | return {}; | |
| 112 | ||
| 113 | // .rela.toc contains exclusively R_PPC64_ADDR64 relocations sorted by | |
| 114 | // r_offset: 0, 8, 16, etc. For a given Offset, Offset / 8 gives us the | |
| 115 | // relocation index in most cases. | |
| 116 | // | |
| 117 | // In rare cases a TOC entry may store a constant that doesn't need an | |
| 118 | // R_PPC64_ADDR64, the corresponding r_offset is therefore missing. Offset / 8 | |
| 119 | // points to a relocation with larger r_offset. Do a linear probe then. | |
| 120 | // Constants are extremely uncommon in .toc and the extra number of array | |
| 121 | // accesses can be seen as a small constant. | |
| 122 | ArrayRef<typename ELFT::Rela> relas = tocSec->template relas<ELFT>(); | |
| 123 | uint64_t index = std::min<uint64_t>(offset / 8, relas.size() - 1); | |
| 124 | for (;;) { | |
| 125 | if (relas[index].r_offset == offset) { | |
| 126 | Symbol &sym = tocSec->getFile<ELFT>()->getRelocTargetSym(relas[index]); | |
| 127 | return {dyn_cast<Defined>(&sym), getAddend<ELFT>(relas[index])}; | |
| 128 | } | |
| 129 | if (relas[index].r_offset < offset || index == 0) | |
| 130 | break; | |
| 131 | --index; | |
| 132 | } | |
| 133 | return {}; | |
| 134 | } | |
| 135 | ||
| 136 | // When accessing a symbol defined in another translation unit, compilers | |
| 137 | // reserve a .toc entry, allocate a local label and generate toc-indirect | |
| 138 | // instuctions: | |
| 139 | // | |
| 140 | // addis 3, 2, .LC0@toc@ha # R_PPC64_TOC16_HA | |
| 141 | // ld 3, .LC0@toc@l(3) # R_PPC64_TOC16_LO_DS, load the address from a .toc entry | |
| 142 | // ld/lwa 3, 0(3) # load the value from the address | |
| 143 | // | |
| 144 | // .section .toc,"aw",@progbits | |
| 145 | // .LC0: .tc var[TC],var | |
| 146 | // | |
| 147 | // If var is defined, non-preemptable and addressable with a 32-bit signed | |
| 148 | // offset from the toc base, the address of var can be computed by adding an | |
| 149 | // offset to the toc base, saving a load. | |
| 150 | // | |
| 151 | // addis 3,2,var@toc@ha # this may be relaxed to a nop, | |
| 152 | // addi 3,3,var@toc@l # then this becomes addi 3,2,var@toc | |
| 153 | // ld/lwa 3, 0(3) # load the value from the address | |
| 154 | // | |
| 155 | // Returns true if the relaxation is performed. | |
| 156 | bool elf::tryRelaxPPC64TocIndirection(RelType type, const Relocation &rel, | |
| 157 | uint8_t *bufLoc) { | |
| 158 | assert(config->tocOptimize); | |
| 159 | if (rel.addend < 0) | |
| 160 | return false; | |
| 161 | ||
| 162 | // If the symbol is not the .toc section, this isn't a toc-indirection. | |
| 163 | Defined *defSym = dyn_cast<Defined>(rel.sym); | |
| 164 | if (!defSym || !defSym->isSection() || defSym->section->name != ".toc") | |
| 165 | return false; | |
| 166 | ||
| 167 | Defined *d; | |
| 168 | int64_t addend; | |
| 169 | auto *tocISB = cast<InputSectionBase>(defSym->section); | |
| 170 | std::tie(d, addend) = | |
| 171 | config->isLE ? getRelaTocSymAndAddend<ELF64LE>(tocISB, rel.addend) | |
| 172 | : getRelaTocSymAndAddend<ELF64BE>(tocISB, rel.addend); | |
| 173 | ||
| 174 | // Only non-preemptable defined symbols can be relaxed. | |
| 175 | if (!d || d->isPreemptible) | |
| 176 | return false; | |
| 177 | ||
| 178 | // Two instructions can materialize a 32-bit signed offset from the toc base. | |
| 179 | uint64_t tocRelative = d->getVA(addend) - getPPC64TocBase(); | |
| 180 | if (!isInt<32>(tocRelative)) | |
| 181 | return false; | |
| 182 | ||
| 183 | // Add PPC64TocOffset that will be subtracted by relocateOne(). | |
| 184 | target->relaxGot(bufLoc, type, tocRelative + ppc64TocOffset); | |
| 185 | return true; | |
| 186 | } | |
| 187 | ||
| 102 | 188 | namespace { |
| 103 | 189 | class PPC64 final : public TargetInfo { |
| 104 | 190 | public: |
| 105 | 191 | PPC64(); |
| 192 | int getTlsGdRelaxSkip(RelType type) const override; | |
| 106 | 193 | uint32_t calcEFlags() const override; |
| 107 | RelExpr getRelExpr(RelType Type, const Symbol &S, | |
| 108 | const uint8_t *Loc) const override; | |
| 109 | void writePltHeader(uint8_t *Buf) const override; | |
| 110 | void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, | |
| 111 | int32_t Index, unsigned RelOff) const override; | |
| 112 | void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 113 | void writeGotHeader(uint8_t *Buf) const override; | |
| 114 | bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, | |
| 115 | uint64_t BranchAddr, const Symbol &S) const override; | |
| 116 | bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; | |
| 117 | RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, | |
| 118 | RelExpr Expr) const override; | |
| 119 | void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 120 | void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 121 | void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 122 | void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 123 | ||
| 124 | bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End, | |
| 125 | uint8_t StOther) const override; | |
| 194 | RelExpr getRelExpr(RelType type, const Symbol &s, | |
| 195 | const uint8_t *loc) const override; | |
| 196 | RelType getDynRel(RelType type) const override; | |
| 197 | void writePltHeader(uint8_t *buf) const override; | |
| 198 | void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, | |
| 199 | int32_t index, unsigned relOff) const override; | |
| 200 | void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 201 | void writeGotHeader(uint8_t *buf) const override; | |
| 202 | bool needsThunk(RelExpr expr, RelType type, const InputFile *file, | |
| 203 | uint64_t branchAddr, const Symbol &s) const override; | |
| 204 | uint32_t getThunkSectionSpacing() const override; | |
| 205 | bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; | |
| 206 | RelExpr adjustRelaxExpr(RelType type, const uint8_t *data, | |
| 207 | RelExpr expr) const override; | |
| 208 | void relaxGot(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 209 | void relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 210 | void relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 211 | void relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 212 | void relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 213 | ||
| 214 | bool adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end, | |
| 215 | uint8_t stOther) const override; | |
| 126 | 216 | }; |
| 127 | 217 | } // namespace |
| 128 | 218 | |
| ... | ... | @@ -130,19 +220,19 @@ public: |
| 130 | 220 | // #higher(value), #highera(value), #highest(value), and #highesta(value) |
| 131 | 221 | // macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi |
| 132 | 222 | // document. |
| 133 | static uint16_t lo(uint64_t V) { return V; } | |
| 134 | static uint16_t hi(uint64_t V) { return V >> 16; } | |
| 135 | static uint16_t ha(uint64_t V) { return (V + 0x8000) >> 16; } | |
| 136 | static uint16_t higher(uint64_t V) { return V >> 32; } | |
| 137 | static uint16_t highera(uint64_t V) { return (V + 0x8000) >> 32; } | |
| 138 | static uint16_t highest(uint64_t V) { return V >> 48; } | |
| 139 | static uint16_t highesta(uint64_t V) { return (V + 0x8000) >> 48; } | |
| 223 | static uint16_t lo(uint64_t v) { return v; } | |
| 224 | static uint16_t hi(uint64_t v) { return v >> 16; } | |
| 225 | static uint16_t ha(uint64_t v) { return (v + 0x8000) >> 16; } | |
| 226 | static uint16_t higher(uint64_t v) { return v >> 32; } | |
| 227 | static uint16_t highera(uint64_t v) { return (v + 0x8000) >> 32; } | |
| 228 | static uint16_t highest(uint64_t v) { return v >> 48; } | |
| 229 | static uint16_t highesta(uint64_t v) { return (v + 0x8000) >> 48; } | |
| 140 | 230 | |
| 141 | 231 | // Extracts the 'PO' field of an instruction encoding. |
| 142 | static uint8_t getPrimaryOpCode(uint32_t Encoding) { return (Encoding >> 26); } | |
| 232 | static uint8_t getPrimaryOpCode(uint32_t encoding) { return (encoding >> 26); } | |
| 143 | 233 | |
| 144 | static bool isDQFormInstruction(uint32_t Encoding) { | |
| 145 | switch (getPrimaryOpCode(Encoding)) { | |
| 234 | static bool isDQFormInstruction(uint32_t encoding) { | |
| 235 | switch (getPrimaryOpCode(encoding)) { | |
| 146 | 236 | default: |
| 147 | 237 | return false; |
| 148 | 238 | case 56: |
| ... | ... | @@ -152,12 +242,12 @@ static bool isDQFormInstruction(uint32_t Encoding) { |
| 152 | 242 | // There are both DS and DQ instruction forms with this primary opcode. |
| 153 | 243 | // Namely `lxv` and `stxv` are the DQ-forms that use it. |
| 154 | 244 | // The DS 'XO' bits being set to 01 is restricted to DQ form. |
| 155 | return (Encoding & 3) == 0x1; | |
| 245 | return (encoding & 3) == 0x1; | |
| 156 | 246 | } |
| 157 | 247 | } |
| 158 | 248 | |
| 159 | static bool isInstructionUpdateForm(uint32_t Encoding) { | |
| 160 | switch (getPrimaryOpCode(Encoding)) { | |
| 249 | static bool isInstructionUpdateForm(uint32_t encoding) { | |
| 250 | switch (getPrimaryOpCode(encoding)) { | |
| 161 | 251 | default: |
| 162 | 252 | return false; |
| 163 | 253 | case LBZU: |
| ... | ... | @@ -176,7 +266,7 @@ static bool isInstructionUpdateForm(uint32_t Encoding) { |
| 176 | 266 | // between LD/LDU/LWA |
| 177 | 267 | case LD: |
| 178 | 268 | case STD: |
| 179 | return (Encoding & 3) == 1; | |
| 269 | return (encoding & 3) == 1; | |
| 180 | 270 | } |
| 181 | 271 | } |
| 182 | 272 | |
| ... | ... | @@ -185,40 +275,38 @@ static bool isInstructionUpdateForm(uint32_t Encoding) { |
| 185 | 275 | // pointer is pointing into the middle of the word we want to extract, and on |
| 186 | 276 | // little-endian it is pointing to the start of the word. These 2 helpers are to |
| 187 | 277 | // simplify reading and writing in that context. |
| 188 | static void writeInstrFromHalf16(uint8_t *Loc, uint32_t Instr) { | |
| 189 | write32(Loc - (Config->EKind == ELF64BEKind ? 2 : 0), Instr); | |
| 278 | static void writeFromHalf16(uint8_t *loc, uint32_t insn) { | |
| 279 | write32(config->isLE ? loc : loc - 2, insn); | |
| 190 | 280 | } |
| 191 | 281 | |
| 192 | static uint32_t readInstrFromHalf16(const uint8_t *Loc) { | |
| 193 | return read32(Loc - (Config->EKind == ELF64BEKind ? 2 : 0)); | |
| 282 | static uint32_t readFromHalf16(const uint8_t *loc) { | |
| 283 | return read32(config->isLE ? loc : loc - 2); | |
| 194 | 284 | } |
| 195 | 285 | |
| 196 | 286 | PPC64::PPC64() { |
| 197 | GotRel = R_PPC64_GLOB_DAT; | |
| 198 | NoneRel = R_PPC64_NONE; | |
| 199 | PltRel = R_PPC64_JMP_SLOT; | |
| 200 | RelativeRel = R_PPC64_RELATIVE; | |
| 201 | IRelativeRel = R_PPC64_IRELATIVE; | |
| 202 | GotEntrySize = 8; | |
| 203 | PltEntrySize = 4; | |
| 204 | GotPltEntrySize = 8; | |
| 205 | GotBaseSymInGotPlt = false; | |
| 206 | GotBaseSymOff = 0x8000; | |
| 207 | GotHeaderEntriesNum = 1; | |
| 208 | GotPltHeaderEntriesNum = 2; | |
| 209 | PltHeaderSize = 60; | |
| 210 | NeedsThunks = true; | |
| 211 | ||
| 212 | TlsModuleIndexRel = R_PPC64_DTPMOD64; | |
| 213 | TlsOffsetRel = R_PPC64_DTPREL64; | |
| 214 | ||
| 215 | TlsGotRel = R_PPC64_TPREL64; | |
| 216 | ||
| 217 | NeedsMoreStackNonSplit = false; | |
| 287 | gotRel = R_PPC64_GLOB_DAT; | |
| 288 | noneRel = R_PPC64_NONE; | |
| 289 | pltRel = R_PPC64_JMP_SLOT; | |
| 290 | relativeRel = R_PPC64_RELATIVE; | |
| 291 | iRelativeRel = R_PPC64_IRELATIVE; | |
| 292 | symbolicRel = R_PPC64_ADDR64; | |
| 293 | pltEntrySize = 4; | |
| 294 | gotBaseSymInGotPlt = false; | |
| 295 | gotHeaderEntriesNum = 1; | |
| 296 | gotPltHeaderEntriesNum = 2; | |
| 297 | pltHeaderSize = 60; | |
| 298 | needsThunks = true; | |
| 299 | ||
| 300 | tlsModuleIndexRel = R_PPC64_DTPMOD64; | |
| 301 | tlsOffsetRel = R_PPC64_DTPREL64; | |
| 302 | ||
| 303 | tlsGotRel = R_PPC64_TPREL64; | |
| 304 | ||
| 305 | needsMoreStackNonSplit = false; | |
| 218 | 306 | |
| 219 | 307 | // We need 64K pages (at least under glibc/Linux, the loader won't |
| 220 | 308 | // set different permissions on a finer granularity than that). |
| 221 | DefaultMaxPageSize = 65536; | |
| 309 | defaultMaxPageSize = 65536; | |
| 222 | 310 | |
| 223 | 311 | // The PPC64 ELF ABI v1 spec, says: |
| 224 | 312 | // |
| ... | ... | @@ -228,31 +316,66 @@ PPC64::PPC64() { |
| 228 | 316 | // |
| 229 | 317 | // And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers |
| 230 | 318 | // use 0x10000000 as the starting address. |
| 231 | DefaultImageBase = 0x10000000; | |
| 319 | defaultImageBase = 0x10000000; | |
| 232 | 320 | |
| 233 | write32(TrapInstr.data(), 0x7fe00008); | |
| 321 | write32(trapInstr.data(), 0x7fe00008); | |
| 322 | } | |
| 323 | ||
| 324 | int PPC64::getTlsGdRelaxSkip(RelType type) const { | |
| 325 | // A __tls_get_addr call instruction is marked with 2 relocations: | |
| 326 | // | |
| 327 | // R_PPC64_TLSGD / R_PPC64_TLSLD: marker relocation | |
| 328 | // R_PPC64_REL24: __tls_get_addr | |
| 329 | // | |
| 330 | // After the relaxation we no longer call __tls_get_addr and should skip both | |
| 331 | // relocations to not create a false dependence on __tls_get_addr being | |
| 332 | // defined. | |
| 333 | if (type == R_PPC64_TLSGD || type == R_PPC64_TLSLD) | |
| 334 | return 2; | |
| 335 | return 1; | |
| 234 | 336 | } |
| 235 | 337 | |
| 236 | static uint32_t getEFlags(InputFile *File) { | |
| 237 | if (Config->EKind == ELF64BEKind) | |
| 238 | return cast<ObjFile<ELF64BE>>(File)->getObj().getHeader()->e_flags; | |
| 239 | return cast<ObjFile<ELF64LE>>(File)->getObj().getHeader()->e_flags; | |
| 338 | static uint32_t getEFlags(InputFile *file) { | |
| 339 | if (config->ekind == ELF64BEKind) | |
| 340 | return cast<ObjFile<ELF64BE>>(file)->getObj().getHeader()->e_flags; | |
| 341 | return cast<ObjFile<ELF64LE>>(file)->getObj().getHeader()->e_flags; | |
| 240 | 342 | } |
| 241 | 343 | |
| 242 | 344 | // This file implements v2 ABI. This function makes sure that all |
| 243 | 345 | // object files have v2 or an unspecified version as an ABI version. |
| 244 | 346 | uint32_t PPC64::calcEFlags() const { |
| 245 | for (InputFile *F : ObjectFiles) { | |
| 246 | uint32_t Flag = getEFlags(F); | |
| 247 | if (Flag == 1) | |
| 248 | error(toString(F) + ": ABI version 1 is not supported"); | |
| 249 | else if (Flag > 2) | |
| 250 | error(toString(F) + ": unrecognized e_flags: " + Twine(Flag)); | |
| 347 | for (InputFile *f : objectFiles) { | |
| 348 | uint32_t flag = getEFlags(f); | |
| 349 | if (flag == 1) | |
| 350 | error(toString(f) + ": ABI version 1 is not supported"); | |
| 351 | else if (flag > 2) | |
| 352 | error(toString(f) + ": unrecognized e_flags: " + Twine(flag)); | |
| 251 | 353 | } |
| 252 | 354 | return 2; |
| 253 | 355 | } |
| 254 | 356 | |
| 255 | void PPC64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 357 | void PPC64::relaxGot(uint8_t *loc, RelType type, uint64_t val) const { | |
| 358 | switch (type) { | |
| 359 | case R_PPC64_TOC16_HA: | |
| 360 | // Convert "addis reg, 2, .LC0@toc@h" to "addis reg, 2, var@toc@h" or "nop". | |
| 361 | relocateOne(loc, type, val); | |
| 362 | break; | |
| 363 | case R_PPC64_TOC16_LO_DS: { | |
| 364 | // Convert "ld reg, .LC0@toc@l(reg)" to "addi reg, reg, var@toc@l" or | |
| 365 | // "addi reg, 2, var@toc". | |
| 366 | uint32_t insn = readFromHalf16(loc); | |
| 367 | if (getPrimaryOpCode(insn) != LD) | |
| 368 | error("expected a 'ld' for got-indirect to toc-relative relaxing"); | |
| 369 | writeFromHalf16(loc, (insn & 0x03ffffff) | 0x38000000); | |
| 370 | relocateOne(loc, R_PPC64_TOC16_LO, val); | |
| 371 | break; | |
| 372 | } | |
| 373 | default: | |
| 374 | llvm_unreachable("unexpected relocation type"); | |
| 375 | } | |
| 376 | } | |
| 377 | ||
| 378 | void PPC64::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 256 | 379 | // Reference: 3.7.4.2 of the 64-bit ELF V2 abi supplement. |
| 257 | 380 | // The general dynamic code sequence for a global `x` will look like: |
| 258 | 381 | // Instruction Relocation Symbol |
| ... | ... | @@ -268,30 +391,30 @@ void PPC64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 268 | 391 | // bl __tls_get_addr(x@tlsgd) into nop |
| 269 | 392 | // nop into addi r3, r3, x@tprel@l |
| 270 | 393 | |
| 271 | switch (Type) { | |
| 394 | switch (type) { | |
| 272 | 395 | case R_PPC64_GOT_TLSGD16_HA: |
| 273 | writeInstrFromHalf16(Loc, 0x60000000); // nop | |
| 396 | writeFromHalf16(loc, 0x60000000); // nop | |
| 274 | 397 | break; |
| 275 | 398 | case R_PPC64_GOT_TLSGD16: |
| 276 | 399 | case R_PPC64_GOT_TLSGD16_LO: |
| 277 | writeInstrFromHalf16(Loc, 0x3c6d0000); // addis r3, r13 | |
| 278 | relocateOne(Loc, R_PPC64_TPREL16_HA, Val); | |
| 400 | writeFromHalf16(loc, 0x3c6d0000); // addis r3, r13 | |
| 401 | relocateOne(loc, R_PPC64_TPREL16_HA, val); | |
| 279 | 402 | break; |
| 280 | 403 | case R_PPC64_TLSGD: |
| 281 | write32(Loc, 0x60000000); // nop | |
| 282 | write32(Loc + 4, 0x38630000); // addi r3, r3 | |
| 404 | write32(loc, 0x60000000); // nop | |
| 405 | write32(loc + 4, 0x38630000); // addi r3, r3 | |
| 283 | 406 | // Since we are relocating a half16 type relocation and Loc + 4 points to |
| 284 | 407 | // the start of an instruction we need to advance the buffer by an extra |
| 285 | 408 | // 2 bytes on BE. |
| 286 | relocateOne(Loc + 4 + (Config->EKind == ELF64BEKind ? 2 : 0), | |
| 287 | R_PPC64_TPREL16_LO, Val); | |
| 409 | relocateOne(loc + 4 + (config->ekind == ELF64BEKind ? 2 : 0), | |
| 410 | R_PPC64_TPREL16_LO, val); | |
| 288 | 411 | break; |
| 289 | 412 | default: |
| 290 | 413 | llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); |
| 291 | 414 | } |
| 292 | 415 | } |
| 293 | 416 | |
| 294 | void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 417 | void PPC64::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 295 | 418 | // Reference: 3.7.4.3 of the 64-bit ELF V2 abi supplement. |
| 296 | 419 | // The local dynamic code sequence for a global `x` will look like: |
| 297 | 420 | // Instruction Relocation Symbol |
| ... | ... | @@ -307,16 +430,16 @@ void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 307 | 430 | // bl __tls_get_addr(x@tlsgd) into nop |
| 308 | 431 | // nop into addi r3, r3, 4096 |
| 309 | 432 | |
| 310 | switch (Type) { | |
| 433 | switch (type) { | |
| 311 | 434 | case R_PPC64_GOT_TLSLD16_HA: |
| 312 | writeInstrFromHalf16(Loc, 0x60000000); // nop | |
| 435 | writeFromHalf16(loc, 0x60000000); // nop | |
| 313 | 436 | break; |
| 314 | 437 | case R_PPC64_GOT_TLSLD16_LO: |
| 315 | writeInstrFromHalf16(Loc, 0x3c6d0000); // addis r3, r13, 0 | |
| 438 | writeFromHalf16(loc, 0x3c6d0000); // addis r3, r13, 0 | |
| 316 | 439 | break; |
| 317 | 440 | case R_PPC64_TLSLD: |
| 318 | write32(Loc, 0x60000000); // nop | |
| 319 | write32(Loc + 4, 0x38631000); // addi r3, r3, 4096 | |
| 441 | write32(loc, 0x60000000); // nop | |
| 442 | write32(loc + 4, 0x38631000); // addi r3, r3, 4096 | |
| 320 | 443 | break; |
| 321 | 444 | case R_PPC64_DTPREL16: |
| 322 | 445 | case R_PPC64_DTPREL16_HA: |
| ... | ... | @@ -324,19 +447,15 @@ void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 324 | 447 | case R_PPC64_DTPREL16_DS: |
| 325 | 448 | case R_PPC64_DTPREL16_LO: |
| 326 | 449 | case R_PPC64_DTPREL16_LO_DS: |
| 327 | case R_PPC64_GOT_DTPREL16_HA: | |
| 328 | case R_PPC64_GOT_DTPREL16_LO_DS: | |
| 329 | case R_PPC64_GOT_DTPREL16_DS: | |
| 330 | case R_PPC64_GOT_DTPREL16_HI: | |
| 331 | relocateOne(Loc, Type, Val); | |
| 450 | relocateOne(loc, type, val); | |
| 332 | 451 | break; |
| 333 | 452 | default: |
| 334 | 453 | llvm_unreachable("unsupported relocation for TLS LD to LE relaxation"); |
| 335 | 454 | } |
| 336 | 455 | } |
| 337 | 456 | |
| 338 | static unsigned getDFormOp(unsigned SecondaryOp) { | |
| 339 | switch (SecondaryOp) { | |
| 457 | unsigned elf::getPPCDFormOp(unsigned secondaryOp) { | |
| 458 | switch (secondaryOp) { | |
| 340 | 459 | case LBZX: |
| 341 | 460 | return LBZ; |
| 342 | 461 | case LHZX: |
| ... | ... | @@ -356,12 +475,11 @@ static unsigned getDFormOp(unsigned SecondaryOp) { |
| 356 | 475 | case ADD: |
| 357 | 476 | return ADDI; |
| 358 | 477 | default: |
| 359 | error("unrecognized instruction for IE to LE R_PPC64_TLS"); | |
| 360 | 478 | return 0; |
| 361 | 479 | } |
| 362 | 480 | } |
| 363 | 481 | |
| 364 | void PPC64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 482 | void PPC64::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 365 | 483 | // The initial exec code sequence for a global `x` will look like: |
| 366 | 484 | // Instruction Relocation Symbol |
| 367 | 485 | // addis r9, r2, x@got@tprel@ha R_PPC64_GOT_TPREL16_HA x |
| ... | ... | @@ -381,26 +499,28 @@ void PPC64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 381 | 499 | // instruction, if we are accessing memory it will use any of the X-form |
| 382 | 500 | // indexed load or store instructions. |
| 383 | 501 | |
| 384 | unsigned Offset = (Config->EKind == ELF64BEKind) ? 2 : 0; | |
| 385 | switch (Type) { | |
| 502 | unsigned offset = (config->ekind == ELF64BEKind) ? 2 : 0; | |
| 503 | switch (type) { | |
| 386 | 504 | case R_PPC64_GOT_TPREL16_HA: |
| 387 | write32(Loc - Offset, 0x60000000); // nop | |
| 505 | write32(loc - offset, 0x60000000); // nop | |
| 388 | 506 | break; |
| 389 | 507 | case R_PPC64_GOT_TPREL16_LO_DS: |
| 390 | 508 | case R_PPC64_GOT_TPREL16_DS: { |
| 391 | uint32_t RegNo = read32(Loc - Offset) & 0x03E00000; // bits 6-10 | |
| 392 | write32(Loc - Offset, 0x3C0D0000 | RegNo); // addis RegNo, r13 | |
| 393 | relocateOne(Loc, R_PPC64_TPREL16_HA, Val); | |
| 509 | uint32_t regNo = read32(loc - offset) & 0x03E00000; // bits 6-10 | |
| 510 | write32(loc - offset, 0x3C0D0000 | regNo); // addis RegNo, r13 | |
| 511 | relocateOne(loc, R_PPC64_TPREL16_HA, val); | |
| 394 | 512 | break; |
| 395 | 513 | } |
| 396 | 514 | case R_PPC64_TLS: { |
| 397 | uint32_t PrimaryOp = getPrimaryOpCode(read32(Loc)); | |
| 398 | if (PrimaryOp != 31) | |
| 515 | uint32_t primaryOp = getPrimaryOpCode(read32(loc)); | |
| 516 | if (primaryOp != 31) | |
| 399 | 517 | error("unrecognized instruction for IE to LE R_PPC64_TLS"); |
| 400 | uint32_t SecondaryOp = (read32(Loc) & 0x000007FE) >> 1; // bits 21-30 | |
| 401 | uint32_t DFormOp = getDFormOp(SecondaryOp); | |
| 402 | write32(Loc, ((DFormOp << 26) | (read32(Loc) & 0x03FFFFFF))); | |
| 403 | relocateOne(Loc + Offset, R_PPC64_TPREL16_LO, Val); | |
| 518 | uint32_t secondaryOp = (read32(loc) & 0x000007FE) >> 1; // bits 21-30 | |
| 519 | uint32_t dFormOp = getPPCDFormOp(secondaryOp); | |
| 520 | if (dFormOp == 0) | |
| 521 | error("unrecognized instruction for IE to LE R_PPC64_TLS"); | |
| 522 | write32(loc, ((dFormOp << 26) | (read32(loc) & 0x03FFFFFF))); | |
| 523 | relocateOne(loc + offset, R_PPC64_TPREL16_LO, val); | |
| 404 | 524 | break; |
| 405 | 525 | } |
| 406 | 526 | default: |
| ... | ... | @@ -409,9 +529,9 @@ void PPC64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 409 | 529 | } |
| 410 | 530 | } |
| 411 | 531 | |
| 412 | RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S, | |
| 413 | const uint8_t *Loc) const { | |
| 414 | switch (Type) { | |
| 532 | RelExpr PPC64::getRelExpr(RelType type, const Symbol &s, | |
| 533 | const uint8_t *loc) const { | |
| 534 | switch (type) { | |
| 415 | 535 | case R_PPC64_GOT16: |
| 416 | 536 | case R_PPC64_GOT16_DS: |
| 417 | 537 | case R_PPC64_GOT16_HA: |
| ... | ... | @@ -421,16 +541,17 @@ RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S, |
| 421 | 541 | return R_GOT_OFF; |
| 422 | 542 | case R_PPC64_TOC16: |
| 423 | 543 | case R_PPC64_TOC16_DS: |
| 424 | case R_PPC64_TOC16_HA: | |
| 425 | 544 | case R_PPC64_TOC16_HI: |
| 426 | 545 | case R_PPC64_TOC16_LO: |
| 427 | case R_PPC64_TOC16_LO_DS: | |
| 428 | 546 | return R_GOTREL; |
| 547 | case R_PPC64_TOC16_HA: | |
| 548 | case R_PPC64_TOC16_LO_DS: | |
| 549 | return config->tocOptimize ? R_PPC64_RELAX_TOC : R_GOTREL; | |
| 429 | 550 | case R_PPC64_TOC: |
| 430 | return R_PPC_TOC; | |
| 551 | return R_PPC64_TOCBASE; | |
| 431 | 552 | case R_PPC64_REL14: |
| 432 | 553 | case R_PPC64_REL24: |
| 433 | return R_PPC_CALL_PLT; | |
| 554 | return R_PPC64_CALL_PLT; | |
| 434 | 555 | case R_PPC64_REL16_LO: |
| 435 | 556 | case R_PPC64_REL16_HA: |
| 436 | 557 | case R_PPC64_REL32: |
| ... | ... | @@ -478,7 +599,7 @@ RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S, |
| 478 | 599 | case R_PPC64_DTPREL16_LO: |
| 479 | 600 | case R_PPC64_DTPREL16_LO_DS: |
| 480 | 601 | case R_PPC64_DTPREL64: |
| 481 | return R_ABS; | |
| 602 | return R_DTPREL; | |
| 482 | 603 | case R_PPC64_TLSGD: |
| 483 | 604 | return R_TLSDESC_CALL; |
| 484 | 605 | case R_PPC64_TLSLD: |
| ... | ... | @@ -490,115 +611,121 @@ RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S, |
| 490 | 611 | } |
| 491 | 612 | } |
| 492 | 613 | |
| 493 | void PPC64::writeGotHeader(uint8_t *Buf) const { | |
| 494 | write64(Buf, getPPC64TocBase()); | |
| 614 | RelType PPC64::getDynRel(RelType type) const { | |
| 615 | if (type == R_PPC64_ADDR64 || type == R_PPC64_TOC) | |
| 616 | return R_PPC64_ADDR64; | |
| 617 | return R_PPC64_NONE; | |
| 495 | 618 | } |
| 496 | 619 | |
| 497 | void PPC64::writePltHeader(uint8_t *Buf) const { | |
| 620 | void PPC64::writeGotHeader(uint8_t *buf) const { | |
| 621 | write64(buf, getPPC64TocBase()); | |
| 622 | } | |
| 623 | ||
| 624 | void PPC64::writePltHeader(uint8_t *buf) const { | |
| 498 | 625 | // The generic resolver stub goes first. |
| 499 | write32(Buf + 0, 0x7c0802a6); // mflr r0 | |
| 500 | write32(Buf + 4, 0x429f0005); // bcl 20,4*cr7+so,8 <_glink+0x8> | |
| 501 | write32(Buf + 8, 0x7d6802a6); // mflr r11 | |
| 502 | write32(Buf + 12, 0x7c0803a6); // mtlr r0 | |
| 503 | write32(Buf + 16, 0x7d8b6050); // subf r12, r11, r12 | |
| 504 | write32(Buf + 20, 0x380cffcc); // subi r0,r12,52 | |
| 505 | write32(Buf + 24, 0x7800f082); // srdi r0,r0,62,2 | |
| 506 | write32(Buf + 28, 0xe98b002c); // ld r12,44(r11) | |
| 507 | write32(Buf + 32, 0x7d6c5a14); // add r11,r12,r11 | |
| 508 | write32(Buf + 36, 0xe98b0000); // ld r12,0(r11) | |
| 509 | write32(Buf + 40, 0xe96b0008); // ld r11,8(r11) | |
| 510 | write32(Buf + 44, 0x7d8903a6); // mtctr r12 | |
| 511 | write32(Buf + 48, 0x4e800420); // bctr | |
| 626 | write32(buf + 0, 0x7c0802a6); // mflr r0 | |
| 627 | write32(buf + 4, 0x429f0005); // bcl 20,4*cr7+so,8 <_glink+0x8> | |
| 628 | write32(buf + 8, 0x7d6802a6); // mflr r11 | |
| 629 | write32(buf + 12, 0x7c0803a6); // mtlr r0 | |
| 630 | write32(buf + 16, 0x7d8b6050); // subf r12, r11, r12 | |
| 631 | write32(buf + 20, 0x380cffcc); // subi r0,r12,52 | |
| 632 | write32(buf + 24, 0x7800f082); // srdi r0,r0,62,2 | |
| 633 | write32(buf + 28, 0xe98b002c); // ld r12,44(r11) | |
| 634 | write32(buf + 32, 0x7d6c5a14); // add r11,r12,r11 | |
| 635 | write32(buf + 36, 0xe98b0000); // ld r12,0(r11) | |
| 636 | write32(buf + 40, 0xe96b0008); // ld r11,8(r11) | |
| 637 | write32(buf + 44, 0x7d8903a6); // mtctr r12 | |
| 638 | write32(buf + 48, 0x4e800420); // bctr | |
| 512 | 639 | |
| 513 | 640 | // The 'bcl' instruction will set the link register to the address of the |
| 514 | 641 | // following instruction ('mflr r11'). Here we store the offset from that |
| 515 | 642 | // instruction to the first entry in the GotPlt section. |
| 516 | int64_t GotPltOffset = In.GotPlt->getVA() - (In.Plt->getVA() + 8); | |
| 517 | write64(Buf + 52, GotPltOffset); | |
| 643 | int64_t gotPltOffset = in.gotPlt->getVA() - (in.plt->getVA() + 8); | |
| 644 | write64(buf + 52, gotPltOffset); | |
| 518 | 645 | } |
| 519 | 646 | |
| 520 | void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, | |
| 521 | uint64_t PltEntryAddr, int32_t Index, | |
| 522 | unsigned RelOff) const { | |
| 523 | int32_t Offset = PltHeaderSize + Index * PltEntrySize; | |
| 647 | void PPC64::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, | |
| 648 | uint64_t pltEntryAddr, int32_t index, | |
| 649 | unsigned relOff) const { | |
| 650 | int32_t offset = pltHeaderSize + index * pltEntrySize; | |
| 524 | 651 | // bl __glink_PLTresolve |
| 525 | write32(Buf, 0x48000000 | ((-Offset) & 0x03FFFFFc)); | |
| 652 | write32(buf, 0x48000000 | ((-offset) & 0x03FFFFFc)); | |
| 526 | 653 | } |
| 527 | 654 | |
| 528 | static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) { | |
| 655 | static std::pair<RelType, uint64_t> toAddr16Rel(RelType type, uint64_t val) { | |
| 529 | 656 | // Relocations relative to the toc-base need to be adjusted by the Toc offset. |
| 530 | uint64_t TocBiasedVal = Val - PPC64TocOffset; | |
| 657 | uint64_t tocBiasedVal = val - ppc64TocOffset; | |
| 531 | 658 | // Relocations relative to dtv[dtpmod] need to be adjusted by the DTP offset. |
| 532 | uint64_t DTPBiasedVal = Val - DynamicThreadPointerOffset; | |
| 659 | uint64_t dtpBiasedVal = val - dynamicThreadPointerOffset; | |
| 533 | 660 | |
| 534 | switch (Type) { | |
| 661 | switch (type) { | |
| 535 | 662 | // TOC biased relocation. |
| 536 | 663 | case R_PPC64_GOT16: |
| 537 | 664 | case R_PPC64_GOT_TLSGD16: |
| 538 | 665 | case R_PPC64_GOT_TLSLD16: |
| 539 | 666 | case R_PPC64_TOC16: |
| 540 | return {R_PPC64_ADDR16, TocBiasedVal}; | |
| 667 | return {R_PPC64_ADDR16, tocBiasedVal}; | |
| 541 | 668 | case R_PPC64_GOT16_DS: |
| 542 | 669 | case R_PPC64_TOC16_DS: |
| 543 | 670 | case R_PPC64_GOT_TPREL16_DS: |
| 544 | 671 | case R_PPC64_GOT_DTPREL16_DS: |
| 545 | return {R_PPC64_ADDR16_DS, TocBiasedVal}; | |
| 672 | return {R_PPC64_ADDR16_DS, tocBiasedVal}; | |
| 546 | 673 | case R_PPC64_GOT16_HA: |
| 547 | 674 | case R_PPC64_GOT_TLSGD16_HA: |
| 548 | 675 | case R_PPC64_GOT_TLSLD16_HA: |
| 549 | 676 | case R_PPC64_GOT_TPREL16_HA: |
| 550 | 677 | case R_PPC64_GOT_DTPREL16_HA: |
| 551 | 678 | case R_PPC64_TOC16_HA: |
| 552 | return {R_PPC64_ADDR16_HA, TocBiasedVal}; | |
| 679 | return {R_PPC64_ADDR16_HA, tocBiasedVal}; | |
| 553 | 680 | case R_PPC64_GOT16_HI: |
| 554 | 681 | case R_PPC64_GOT_TLSGD16_HI: |
| 555 | 682 | case R_PPC64_GOT_TLSLD16_HI: |
| 556 | 683 | case R_PPC64_GOT_TPREL16_HI: |
| 557 | 684 | case R_PPC64_GOT_DTPREL16_HI: |
| 558 | 685 | case R_PPC64_TOC16_HI: |
| 559 | return {R_PPC64_ADDR16_HI, TocBiasedVal}; | |
| 686 | return {R_PPC64_ADDR16_HI, tocBiasedVal}; | |
| 560 | 687 | case R_PPC64_GOT16_LO: |
| 561 | 688 | case R_PPC64_GOT_TLSGD16_LO: |
| 562 | 689 | case R_PPC64_GOT_TLSLD16_LO: |
| 563 | 690 | case R_PPC64_TOC16_LO: |
| 564 | return {R_PPC64_ADDR16_LO, TocBiasedVal}; | |
| 691 | return {R_PPC64_ADDR16_LO, tocBiasedVal}; | |
| 565 | 692 | case R_PPC64_GOT16_LO_DS: |
| 566 | 693 | case R_PPC64_TOC16_LO_DS: |
| 567 | 694 | case R_PPC64_GOT_TPREL16_LO_DS: |
| 568 | 695 | case R_PPC64_GOT_DTPREL16_LO_DS: |
| 569 | return {R_PPC64_ADDR16_LO_DS, TocBiasedVal}; | |
| 696 | return {R_PPC64_ADDR16_LO_DS, tocBiasedVal}; | |
| 570 | 697 | |
| 571 | 698 | // Dynamic Thread pointer biased relocation types. |
| 572 | 699 | case R_PPC64_DTPREL16: |
| 573 | return {R_PPC64_ADDR16, DTPBiasedVal}; | |
| 700 | return {R_PPC64_ADDR16, dtpBiasedVal}; | |
| 574 | 701 | case R_PPC64_DTPREL16_DS: |
| 575 | return {R_PPC64_ADDR16_DS, DTPBiasedVal}; | |
| 702 | return {R_PPC64_ADDR16_DS, dtpBiasedVal}; | |
| 576 | 703 | case R_PPC64_DTPREL16_HA: |
| 577 | return {R_PPC64_ADDR16_HA, DTPBiasedVal}; | |
| 704 | return {R_PPC64_ADDR16_HA, dtpBiasedVal}; | |
| 578 | 705 | case R_PPC64_DTPREL16_HI: |
| 579 | return {R_PPC64_ADDR16_HI, DTPBiasedVal}; | |
| 706 | return {R_PPC64_ADDR16_HI, dtpBiasedVal}; | |
| 580 | 707 | case R_PPC64_DTPREL16_HIGHER: |
| 581 | return {R_PPC64_ADDR16_HIGHER, DTPBiasedVal}; | |
| 708 | return {R_PPC64_ADDR16_HIGHER, dtpBiasedVal}; | |
| 582 | 709 | case R_PPC64_DTPREL16_HIGHERA: |
| 583 | return {R_PPC64_ADDR16_HIGHERA, DTPBiasedVal}; | |
| 710 | return {R_PPC64_ADDR16_HIGHERA, dtpBiasedVal}; | |
| 584 | 711 | case R_PPC64_DTPREL16_HIGHEST: |
| 585 | return {R_PPC64_ADDR16_HIGHEST, DTPBiasedVal}; | |
| 712 | return {R_PPC64_ADDR16_HIGHEST, dtpBiasedVal}; | |
| 586 | 713 | case R_PPC64_DTPREL16_HIGHESTA: |
| 587 | return {R_PPC64_ADDR16_HIGHESTA, DTPBiasedVal}; | |
| 714 | return {R_PPC64_ADDR16_HIGHESTA, dtpBiasedVal}; | |
| 588 | 715 | case R_PPC64_DTPREL16_LO: |
| 589 | return {R_PPC64_ADDR16_LO, DTPBiasedVal}; | |
| 716 | return {R_PPC64_ADDR16_LO, dtpBiasedVal}; | |
| 590 | 717 | case R_PPC64_DTPREL16_LO_DS: |
| 591 | return {R_PPC64_ADDR16_LO_DS, DTPBiasedVal}; | |
| 718 | return {R_PPC64_ADDR16_LO_DS, dtpBiasedVal}; | |
| 592 | 719 | case R_PPC64_DTPREL64: |
| 593 | return {R_PPC64_ADDR64, DTPBiasedVal}; | |
| 720 | return {R_PPC64_ADDR64, dtpBiasedVal}; | |
| 594 | 721 | |
| 595 | 722 | default: |
| 596 | return {Type, Val}; | |
| 723 | return {type, val}; | |
| 597 | 724 | } |
| 598 | 725 | } |
| 599 | 726 | |
| 600 | static bool isTocOptType(RelType Type) { | |
| 601 | switch (Type) { | |
| 727 | static bool isTocOptType(RelType type) { | |
| 728 | switch (type) { | |
| 602 | 729 | case R_PPC64_GOT16_HA: |
| 603 | 730 | case R_PPC64_GOT16_LO_DS: |
| 604 | 731 | case R_PPC64_TOC16_HA: |
| ... | ... | @@ -610,66 +737,69 @@ static bool isTocOptType(RelType Type) { |
| 610 | 737 | } |
| 611 | 738 | } |
| 612 | 739 | |
| 613 | void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 740 | void PPC64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { | |
| 614 | 741 | // We need to save the original relocation type to use in diagnostics, and |
| 615 | 742 | // use the original type to determine if we should toc-optimize the |
| 616 | 743 | // instructions being relocated. |
| 617 | RelType OriginalType = Type; | |
| 618 | bool ShouldTocOptimize = isTocOptType(Type); | |
| 744 | RelType originalType = type; | |
| 745 | bool shouldTocOptimize = isTocOptType(type); | |
| 619 | 746 | // For dynamic thread pointer relative, toc-relative, and got-indirect |
| 620 | 747 | // relocations, proceed in terms of the corresponding ADDR16 relocation type. |
| 621 | std::tie(Type, Val) = toAddr16Rel(Type, Val); | |
| 748 | std::tie(type, val) = toAddr16Rel(type, val); | |
| 622 | 749 | |
| 623 | switch (Type) { | |
| 750 | switch (type) { | |
| 624 | 751 | case R_PPC64_ADDR14: { |
| 625 | checkAlignment(Loc, Val, 4, Type); | |
| 752 | checkAlignment(loc, val, 4, type); | |
| 626 | 753 | // Preserve the AA/LK bits in the branch instruction |
| 627 | uint8_t AALK = Loc[3]; | |
| 628 | write16(Loc + 2, (AALK & 3) | (Val & 0xfffc)); | |
| 754 | uint8_t aalk = loc[3]; | |
| 755 | write16(loc + 2, (aalk & 3) | (val & 0xfffc)); | |
| 629 | 756 | break; |
| 630 | 757 | } |
| 631 | 758 | case R_PPC64_ADDR16: |
| 632 | case R_PPC64_TPREL16: | |
| 633 | checkInt(Loc, Val, 16, OriginalType); | |
| 634 | write16(Loc, Val); | |
| 759 | checkIntUInt(loc, val, 16, originalType); | |
| 760 | write16(loc, val); | |
| 761 | break; | |
| 762 | case R_PPC64_ADDR32: | |
| 763 | checkIntUInt(loc, val, 32, originalType); | |
| 764 | write32(loc, val); | |
| 635 | 765 | break; |
| 636 | 766 | case R_PPC64_ADDR16_DS: |
| 637 | 767 | case R_PPC64_TPREL16_DS: { |
| 638 | checkInt(Loc, Val, 16, OriginalType); | |
| 768 | checkInt(loc, val, 16, originalType); | |
| 639 | 769 | // DQ-form instructions use bits 28-31 as part of the instruction encoding |
| 640 | 770 | // DS-form instructions only use bits 30-31. |
| 641 | uint16_t Mask = isDQFormInstruction(readInstrFromHalf16(Loc)) ? 0xF : 0x3; | |
| 642 | checkAlignment(Loc, lo(Val), Mask + 1, OriginalType); | |
| 643 | write16(Loc, (read16(Loc) & Mask) | lo(Val)); | |
| 771 | uint16_t mask = isDQFormInstruction(readFromHalf16(loc)) ? 0xf : 0x3; | |
| 772 | checkAlignment(loc, lo(val), mask + 1, originalType); | |
| 773 | write16(loc, (read16(loc) & mask) | lo(val)); | |
| 644 | 774 | } break; |
| 645 | 775 | case R_PPC64_ADDR16_HA: |
| 646 | 776 | case R_PPC64_REL16_HA: |
| 647 | 777 | case R_PPC64_TPREL16_HA: |
| 648 | if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) | |
| 649 | writeInstrFromHalf16(Loc, 0x60000000); | |
| 778 | if (config->tocOptimize && shouldTocOptimize && ha(val) == 0) | |
| 779 | writeFromHalf16(loc, 0x60000000); | |
| 650 | 780 | else |
| 651 | write16(Loc, ha(Val)); | |
| 781 | write16(loc, ha(val)); | |
| 652 | 782 | break; |
| 653 | 783 | case R_PPC64_ADDR16_HI: |
| 654 | 784 | case R_PPC64_REL16_HI: |
| 655 | 785 | case R_PPC64_TPREL16_HI: |
| 656 | write16(Loc, hi(Val)); | |
| 786 | write16(loc, hi(val)); | |
| 657 | 787 | break; |
| 658 | 788 | case R_PPC64_ADDR16_HIGHER: |
| 659 | 789 | case R_PPC64_TPREL16_HIGHER: |
| 660 | write16(Loc, higher(Val)); | |
| 790 | write16(loc, higher(val)); | |
| 661 | 791 | break; |
| 662 | 792 | case R_PPC64_ADDR16_HIGHERA: |
| 663 | 793 | case R_PPC64_TPREL16_HIGHERA: |
| 664 | write16(Loc, highera(Val)); | |
| 794 | write16(loc, highera(val)); | |
| 665 | 795 | break; |
| 666 | 796 | case R_PPC64_ADDR16_HIGHEST: |
| 667 | 797 | case R_PPC64_TPREL16_HIGHEST: |
| 668 | write16(Loc, highest(Val)); | |
| 798 | write16(loc, highest(val)); | |
| 669 | 799 | break; |
| 670 | 800 | case R_PPC64_ADDR16_HIGHESTA: |
| 671 | 801 | case R_PPC64_TPREL16_HIGHESTA: |
| 672 | write16(Loc, highesta(Val)); | |
| 802 | write16(loc, highesta(val)); | |
| 673 | 803 | break; |
| 674 | 804 | case R_PPC64_ADDR16_LO: |
| 675 | 805 | case R_PPC64_REL16_LO: |
| ... | ... | @@ -677,104 +807,119 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 677 | 807 | // When the high-adjusted part of a toc relocation evalutes to 0, it is |
| 678 | 808 | // changed into a nop. The lo part then needs to be updated to use the |
| 679 | 809 | // toc-pointer register r2, as the base register. |
| 680 | if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) { | |
| 681 | uint32_t Instr = readInstrFromHalf16(Loc); | |
| 682 | if (isInstructionUpdateForm(Instr)) | |
| 683 | error(getErrorLocation(Loc) + | |
| 810 | if (config->tocOptimize && shouldTocOptimize && ha(val) == 0) { | |
| 811 | uint32_t insn = readFromHalf16(loc); | |
| 812 | if (isInstructionUpdateForm(insn)) | |
| 813 | error(getErrorLocation(loc) + | |
| 684 | 814 | "can't toc-optimize an update instruction: 0x" + |
| 685 | utohexstr(Instr)); | |
| 686 | Instr = (Instr & 0xFFE00000) | 0x00020000; | |
| 687 | writeInstrFromHalf16(Loc, Instr); | |
| 815 | utohexstr(insn)); | |
| 816 | writeFromHalf16(loc, (insn & 0xffe00000) | 0x00020000 | lo(val)); | |
| 817 | } else { | |
| 818 | write16(loc, lo(val)); | |
| 688 | 819 | } |
| 689 | write16(Loc, lo(Val)); | |
| 690 | 820 | break; |
| 691 | 821 | case R_PPC64_ADDR16_LO_DS: |
| 692 | 822 | case R_PPC64_TPREL16_LO_DS: { |
| 693 | 823 | // DQ-form instructions use bits 28-31 as part of the instruction encoding |
| 694 | 824 | // DS-form instructions only use bits 30-31. |
| 695 | uint32_t Inst = readInstrFromHalf16(Loc); | |
| 696 | uint16_t Mask = isDQFormInstruction(Inst) ? 0xF : 0x3; | |
| 697 | checkAlignment(Loc, lo(Val), Mask + 1, OriginalType); | |
| 698 | if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) { | |
| 825 | uint32_t insn = readFromHalf16(loc); | |
| 826 | uint16_t mask = isDQFormInstruction(insn) ? 0xf : 0x3; | |
| 827 | checkAlignment(loc, lo(val), mask + 1, originalType); | |
| 828 | if (config->tocOptimize && shouldTocOptimize && ha(val) == 0) { | |
| 699 | 829 | // When the high-adjusted part of a toc relocation evalutes to 0, it is |
| 700 | 830 | // changed into a nop. The lo part then needs to be updated to use the toc |
| 701 | 831 | // pointer register r2, as the base register. |
| 702 | if (isInstructionUpdateForm(Inst)) | |
| 703 | error(getErrorLocation(Loc) + | |
| 832 | if (isInstructionUpdateForm(insn)) | |
| 833 | error(getErrorLocation(loc) + | |
| 704 | 834 | "Can't toc-optimize an update instruction: 0x" + |
| 705 | Twine::utohexstr(Inst)); | |
| 706 | Inst = (Inst & 0xFFE0000F) | 0x00020000; | |
| 707 | writeInstrFromHalf16(Loc, Inst); | |
| 835 | Twine::utohexstr(insn)); | |
| 836 | insn &= 0xffe00000 | mask; | |
| 837 | writeFromHalf16(loc, insn | 0x00020000 | lo(val)); | |
| 838 | } else { | |
| 839 | write16(loc, (read16(loc) & mask) | lo(val)); | |
| 708 | 840 | } |
| 709 | write16(Loc, (read16(Loc) & Mask) | lo(Val)); | |
| 710 | 841 | } break; |
| 711 | case R_PPC64_ADDR32: | |
| 842 | case R_PPC64_TPREL16: | |
| 843 | checkInt(loc, val, 16, originalType); | |
| 844 | write16(loc, val); | |
| 845 | break; | |
| 712 | 846 | case R_PPC64_REL32: |
| 713 | checkInt(Loc, Val, 32, Type); | |
| 714 | write32(Loc, Val); | |
| 847 | checkInt(loc, val, 32, type); | |
| 848 | write32(loc, val); | |
| 715 | 849 | break; |
| 716 | 850 | case R_PPC64_ADDR64: |
| 717 | 851 | case R_PPC64_REL64: |
| 718 | 852 | case R_PPC64_TOC: |
| 719 | write64(Loc, Val); | |
| 853 | write64(loc, val); | |
| 720 | 854 | break; |
| 721 | 855 | case R_PPC64_REL14: { |
| 722 | uint32_t Mask = 0x0000FFFC; | |
| 723 | checkInt(Loc, Val, 16, Type); | |
| 724 | checkAlignment(Loc, Val, 4, Type); | |
| 725 | write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask)); | |
| 856 | uint32_t mask = 0x0000FFFC; | |
| 857 | checkInt(loc, val, 16, type); | |
| 858 | checkAlignment(loc, val, 4, type); | |
| 859 | write32(loc, (read32(loc) & ~mask) | (val & mask)); | |
| 726 | 860 | break; |
| 727 | 861 | } |
| 728 | 862 | case R_PPC64_REL24: { |
| 729 | uint32_t Mask = 0x03FFFFFC; | |
| 730 | checkInt(Loc, Val, 26, Type); | |
| 731 | checkAlignment(Loc, Val, 4, Type); | |
| 732 | write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask)); | |
| 863 | uint32_t mask = 0x03FFFFFC; | |
| 864 | checkInt(loc, val, 26, type); | |
| 865 | checkAlignment(loc, val, 4, type); | |
| 866 | write32(loc, (read32(loc) & ~mask) | (val & mask)); | |
| 733 | 867 | break; |
| 734 | 868 | } |
| 735 | 869 | case R_PPC64_DTPREL64: |
| 736 | write64(Loc, Val - DynamicThreadPointerOffset); | |
| 870 | write64(loc, val - dynamicThreadPointerOffset); | |
| 737 | 871 | break; |
| 738 | 872 | default: |
| 739 | error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); | |
| 873 | error(getErrorLocation(loc) + "unrecognized relocation " + toString(type)); | |
| 740 | 874 | } |
| 741 | 875 | } |
| 742 | 876 | |
| 743 | bool PPC64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, | |
| 744 | uint64_t BranchAddr, const Symbol &S) const { | |
| 745 | if (Type != R_PPC64_REL14 && Type != R_PPC64_REL24) | |
| 877 | bool PPC64::needsThunk(RelExpr expr, RelType type, const InputFile *file, | |
| 878 | uint64_t branchAddr, const Symbol &s) const { | |
| 879 | if (type != R_PPC64_REL14 && type != R_PPC64_REL24) | |
| 746 | 880 | return false; |
| 747 | 881 | |
| 748 | 882 | // If a function is in the Plt it needs to be called with a call-stub. |
| 749 | if (S.isInPlt()) | |
| 883 | if (s.isInPlt()) | |
| 750 | 884 | return true; |
| 751 | 885 | |
| 752 | 886 | // If a symbol is a weak undefined and we are compiling an executable |
| 753 | 887 | // it doesn't need a range-extending thunk since it can't be called. |
| 754 | if (S.isUndefWeak() && !Config->Shared) | |
| 888 | if (s.isUndefWeak() && !config->shared) | |
| 755 | 889 | return false; |
| 756 | 890 | |
| 757 | 891 | // If the offset exceeds the range of the branch type then it will need |
| 758 | 892 | // a range-extending thunk. |
| 759 | return !inBranchRange(Type, BranchAddr, S.getVA()); | |
| 893 | // See the comment in getRelocTargetVA() about R_PPC64_CALL. | |
| 894 | return !inBranchRange(type, branchAddr, | |
| 895 | s.getVA() + | |
| 896 | getPPC64GlobalEntryToLocalEntryOffset(s.stOther)); | |
| 760 | 897 | } |
| 761 | 898 | |
| 762 | bool PPC64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { | |
| 763 | int64_t Offset = Dst - Src; | |
| 764 | if (Type == R_PPC64_REL14) | |
| 765 | return isInt<16>(Offset); | |
| 766 | if (Type == R_PPC64_REL24) | |
| 767 | return isInt<26>(Offset); | |
| 899 | uint32_t PPC64::getThunkSectionSpacing() const { | |
| 900 | // See comment in Arch/ARM.cpp for a more detailed explanation of | |
| 901 | // getThunkSectionSpacing(). For PPC64 we pick the constant here based on | |
| 902 | // R_PPC64_REL24, which is used by unconditional branch instructions. | |
| 903 | // 0x2000000 = (1 << 24-1) * 4 | |
| 904 | return 0x2000000; | |
| 905 | } | |
| 906 | ||
| 907 | bool PPC64::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { | |
| 908 | int64_t offset = dst - src; | |
| 909 | if (type == R_PPC64_REL14) | |
| 910 | return isInt<16>(offset); | |
| 911 | if (type == R_PPC64_REL24) | |
| 912 | return isInt<26>(offset); | |
| 768 | 913 | llvm_unreachable("unsupported relocation type used in branch"); |
| 769 | 914 | } |
| 770 | 915 | |
| 771 | RelExpr PPC64::adjustRelaxExpr(RelType Type, const uint8_t *Data, | |
| 772 | RelExpr Expr) const { | |
| 773 | if (Expr == R_RELAX_TLS_GD_TO_IE) | |
| 916 | RelExpr PPC64::adjustRelaxExpr(RelType type, const uint8_t *data, | |
| 917 | RelExpr expr) const { | |
| 918 | if (expr == R_RELAX_TLS_GD_TO_IE) | |
| 774 | 919 | return R_RELAX_TLS_GD_TO_IE_GOT_OFF; |
| 775 | if (Expr == R_RELAX_TLS_LD_TO_LE) | |
| 920 | if (expr == R_RELAX_TLS_LD_TO_LE) | |
| 776 | 921 | return R_RELAX_TLS_LD_TO_LE_ABS; |
| 777 | return Expr; | |
| 922 | return expr; | |
| 778 | 923 | } |
| 779 | 924 | |
| 780 | 925 | // Reference: 3.7.4.1 of the 64-bit ELF V2 abi supplement. |
| ... | ... | @@ -794,24 +939,25 @@ RelExpr PPC64::adjustRelaxExpr(RelType Type, const uint8_t *Data, |
| 794 | 939 | // thread pointer. |
| 795 | 940 | // Since the nop must directly follow the call, the R_PPC64_TLSGD relocation is |
| 796 | 941 | // used as the relaxation hint for both steps 2 and 3. |
| 797 | void PPC64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 798 | switch (Type) { | |
| 942 | void PPC64::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 943 | switch (type) { | |
| 799 | 944 | case R_PPC64_GOT_TLSGD16_HA: |
| 800 | 945 | // This is relaxed from addis rT, r2, sym@got@tlsgd@ha to |
| 801 | 946 | // addis rT, r2, sym@got@tprel@ha. |
| 802 | relocateOne(Loc, R_PPC64_GOT_TPREL16_HA, Val); | |
| 947 | relocateOne(loc, R_PPC64_GOT_TPREL16_HA, val); | |
| 803 | 948 | return; |
| 949 | case R_PPC64_GOT_TLSGD16: | |
| 804 | 950 | case R_PPC64_GOT_TLSGD16_LO: { |
| 805 | 951 | // Relax from addi r3, rA, sym@got@tlsgd@l to |
| 806 | 952 | // ld r3, sym@got@tprel@l(rA) |
| 807 | uint32_t InputRegister = (readInstrFromHalf16(Loc) & (0x1f << 16)); | |
| 808 | writeInstrFromHalf16(Loc, 0xE8600000 | InputRegister); | |
| 809 | relocateOne(Loc, R_PPC64_GOT_TPREL16_LO_DS, Val); | |
| 953 | uint32_t ra = (readFromHalf16(loc) & (0x1f << 16)); | |
| 954 | writeFromHalf16(loc, 0xe8600000 | ra); | |
| 955 | relocateOne(loc, R_PPC64_GOT_TPREL16_LO_DS, val); | |
| 810 | 956 | return; |
| 811 | 957 | } |
| 812 | 958 | case R_PPC64_TLSGD: |
| 813 | write32(Loc, 0x60000000); // bl __tls_get_addr(sym@tlsgd) --> nop | |
| 814 | write32(Loc + 4, 0x7c636A14); // nop --> add r3, r3, r13 | |
| 959 | write32(loc, 0x60000000); // bl __tls_get_addr(sym@tlsgd) --> nop | |
| 960 | write32(loc + 4, 0x7c636A14); // nop --> add r3, r3, r13 | |
| 815 | 961 | return; |
| 816 | 962 | default: |
| 817 | 963 | llvm_unreachable("unsupported relocation for TLS GD to IE relaxation"); |
| ... | ... | @@ -846,86 +992,86 @@ void PPC64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 846 | 992 | // pair by split-stack-size-adjust. |
| 847 | 993 | // addis r12, r1, ha(-stack-frame size - split-stack-adjust-size) |
| 848 | 994 | // addi r12, r12, l(-stack-frame size - split-stack-adjust-size) |
| 849 | bool PPC64::adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End, | |
| 850 | uint8_t StOther) const { | |
| 995 | bool PPC64::adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end, | |
| 996 | uint8_t stOther) const { | |
| 851 | 997 | // If the caller has a global entry point adjust the buffer past it. The start |
| 852 | 998 | // of the split-stack prologue will be at the local entry point. |
| 853 | Loc += getPPC64GlobalEntryToLocalEntryOffset(StOther); | |
| 999 | loc += getPPC64GlobalEntryToLocalEntryOffset(stOther); | |
| 854 | 1000 | |
| 855 | 1001 | // At the very least we expect to see a load of some split-stack data from the |
| 856 | 1002 | // tcb, and 2 instructions that calculate the ending stack address this |
| 857 | 1003 | // function will require. If there is not enough room for at least 3 |
| 858 | 1004 | // instructions it can't be a split-stack prologue. |
| 859 | if (Loc + 12 >= End) | |
| 1005 | if (loc + 12 >= end) | |
| 860 | 1006 | return false; |
| 861 | 1007 | |
| 862 | 1008 | // First instruction must be `ld r0, -0x7000-64(r13)` |
| 863 | if (read32(Loc) != 0xe80d8fc0) | |
| 1009 | if (read32(loc) != 0xe80d8fc0) | |
| 864 | 1010 | return false; |
| 865 | 1011 | |
| 866 | int16_t HiImm = 0; | |
| 867 | int16_t LoImm = 0; | |
| 1012 | int16_t hiImm = 0; | |
| 1013 | int16_t loImm = 0; | |
| 868 | 1014 | // First instruction can be either an addis if the frame size is larger then |
| 869 | 1015 | // 32K, or an addi if the size is less then 32K. |
| 870 | int32_t FirstInstr = read32(Loc + 4); | |
| 871 | if (getPrimaryOpCode(FirstInstr) == 15) { | |
| 872 | HiImm = FirstInstr & 0xFFFF; | |
| 873 | } else if (getPrimaryOpCode(FirstInstr) == 14) { | |
| 874 | LoImm = FirstInstr & 0xFFFF; | |
| 1016 | int32_t firstInstr = read32(loc + 4); | |
| 1017 | if (getPrimaryOpCode(firstInstr) == 15) { | |
| 1018 | hiImm = firstInstr & 0xFFFF; | |
| 1019 | } else if (getPrimaryOpCode(firstInstr) == 14) { | |
| 1020 | loImm = firstInstr & 0xFFFF; | |
| 875 | 1021 | } else { |
| 876 | 1022 | return false; |
| 877 | 1023 | } |
| 878 | 1024 | |
| 879 | 1025 | // Second instruction is either an addi or a nop. If the first instruction was |
| 880 | 1026 | // an addi then LoImm is set and the second instruction must be a nop. |
| 881 | uint32_t SecondInstr = read32(Loc + 8); | |
| 882 | if (!LoImm && getPrimaryOpCode(SecondInstr) == 14) { | |
| 883 | LoImm = SecondInstr & 0xFFFF; | |
| 884 | } else if (SecondInstr != 0x60000000) { | |
| 1027 | uint32_t secondInstr = read32(loc + 8); | |
| 1028 | if (!loImm && getPrimaryOpCode(secondInstr) == 14) { | |
| 1029 | loImm = secondInstr & 0xFFFF; | |
| 1030 | } else if (secondInstr != 0x60000000) { | |
| 885 | 1031 | return false; |
| 886 | 1032 | } |
| 887 | 1033 | |
| 888 | 1034 | // The register operands of the first instruction should be the stack-pointer |
| 889 | 1035 | // (r1) as the input (RA) and r12 as the output (RT). If the second |
| 890 | 1036 | // instruction is not a nop, then it should use r12 as both input and output. |
| 891 | auto CheckRegOperands = [](uint32_t Instr, uint8_t ExpectedRT, | |
| 892 | uint8_t ExpectedRA) { | |
| 893 | return ((Instr & 0x3E00000) >> 21 == ExpectedRT) && | |
| 894 | ((Instr & 0x1F0000) >> 16 == ExpectedRA); | |
| 1037 | auto checkRegOperands = [](uint32_t instr, uint8_t expectedRT, | |
| 1038 | uint8_t expectedRA) { | |
| 1039 | return ((instr & 0x3E00000) >> 21 == expectedRT) && | |
| 1040 | ((instr & 0x1F0000) >> 16 == expectedRA); | |
| 895 | 1041 | }; |
| 896 | if (!CheckRegOperands(FirstInstr, 12, 1)) | |
| 1042 | if (!checkRegOperands(firstInstr, 12, 1)) | |
| 897 | 1043 | return false; |
| 898 | if (SecondInstr != 0x60000000 && !CheckRegOperands(SecondInstr, 12, 12)) | |
| 1044 | if (secondInstr != 0x60000000 && !checkRegOperands(secondInstr, 12, 12)) | |
| 899 | 1045 | return false; |
| 900 | 1046 | |
| 901 | int32_t StackFrameSize = (HiImm * 65536) + LoImm; | |
| 1047 | int32_t stackFrameSize = (hiImm * 65536) + loImm; | |
| 902 | 1048 | // Check that the adjusted size doesn't overflow what we can represent with 2 |
| 903 | 1049 | // instructions. |
| 904 | if (StackFrameSize < Config->SplitStackAdjustSize + INT32_MIN) { | |
| 905 | error(getErrorLocation(Loc) + "split-stack prologue adjustment overflows"); | |
| 1050 | if (stackFrameSize < config->splitStackAdjustSize + INT32_MIN) { | |
| 1051 | error(getErrorLocation(loc) + "split-stack prologue adjustment overflows"); | |
| 906 | 1052 | return false; |
| 907 | 1053 | } |
| 908 | 1054 | |
| 909 | int32_t AdjustedStackFrameSize = | |
| 910 | StackFrameSize - Config->SplitStackAdjustSize; | |
| 1055 | int32_t adjustedStackFrameSize = | |
| 1056 | stackFrameSize - config->splitStackAdjustSize; | |
| 911 | 1057 | |
| 912 | LoImm = AdjustedStackFrameSize & 0xFFFF; | |
| 913 | HiImm = (AdjustedStackFrameSize + 0x8000) >> 16; | |
| 914 | if (HiImm) { | |
| 915 | write32(Loc + 4, 0x3D810000 | (uint16_t)HiImm); | |
| 1058 | loImm = adjustedStackFrameSize & 0xFFFF; | |
| 1059 | hiImm = (adjustedStackFrameSize + 0x8000) >> 16; | |
| 1060 | if (hiImm) { | |
| 1061 | write32(loc + 4, 0x3D810000 | (uint16_t)hiImm); | |
| 916 | 1062 | // If the low immediate is zero the second instruction will be a nop. |
| 917 | SecondInstr = LoImm ? 0x398C0000 | (uint16_t)LoImm : 0x60000000; | |
| 918 | write32(Loc + 8, SecondInstr); | |
| 1063 | secondInstr = loImm ? 0x398C0000 | (uint16_t)loImm : 0x60000000; | |
| 1064 | write32(loc + 8, secondInstr); | |
| 919 | 1065 | } else { |
| 920 | 1066 | // addi r12, r1, imm |
| 921 | write32(Loc + 4, (0x39810000) | (uint16_t)LoImm); | |
| 922 | write32(Loc + 8, 0x60000000); | |
| 1067 | write32(loc + 4, (0x39810000) | (uint16_t)loImm); | |
| 1068 | write32(loc + 8, 0x60000000); | |
| 923 | 1069 | } |
| 924 | 1070 | |
| 925 | 1071 | return true; |
| 926 | 1072 | } |
| 927 | 1073 | |
| 928 | 1074 | TargetInfo *elf::getPPC64TargetInfo() { |
| 929 | static PPC64 Target; | |
| 930 | return &Target; | |
| 1075 | static PPC64 target; | |
| 1076 | return &target; | |
| 931 | 1077 | } |
deps/lld/ELF/Arch/RISCV.cpp+282-119| ... | ... | @@ -1,13 +1,13 @@ |
| 1 | 1 | //===- RISCV.cpp ----------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| 10 | 9 | #include "InputFiles.h" |
| 10 | #include "SyntheticSections.h" | |
| 11 | 11 | #include "Target.h" |
| 12 | 12 | |
| 13 | 13 | using namespace llvm; |
| ... | ... | @@ -23,59 +23,207 @@ class RISCV final : public TargetInfo { |
| 23 | 23 | public: |
| 24 | 24 | RISCV(); |
| 25 | 25 | uint32_t calcEFlags() const override; |
| 26 | RelExpr getRelExpr(RelType Type, const Symbol &S, | |
| 27 | const uint8_t *Loc) const override; | |
| 28 | void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 26 | void writeGotHeader(uint8_t *buf) const override; | |
| 27 | void writeGotPlt(uint8_t *buf, const Symbol &s) const override; | |
| 28 | void writePltHeader(uint8_t *buf) const override; | |
| 29 | void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, | |
| 30 | int32_t index, unsigned relOff) const override; | |
| 31 | RelType getDynRel(RelType type) const override; | |
| 32 | RelExpr getRelExpr(RelType type, const Symbol &s, | |
| 33 | const uint8_t *loc) const override; | |
| 34 | void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 29 | 35 | }; |
| 30 | 36 | |
| 31 | 37 | } // end anonymous namespace |
| 32 | 38 | |
| 33 | RISCV::RISCV() { NoneRel = R_RISCV_NONE; } | |
| 39 | const uint64_t dtpOffset = 0x800; | |
| 40 | ||
| 41 | enum Op { | |
| 42 | ADDI = 0x13, | |
| 43 | AUIPC = 0x17, | |
| 44 | JALR = 0x67, | |
| 45 | LD = 0x3003, | |
| 46 | LW = 0x2003, | |
| 47 | SRLI = 0x5013, | |
| 48 | SUB = 0x40000033, | |
| 49 | }; | |
| 50 | ||
| 51 | enum Reg { | |
| 52 | X_RA = 1, | |
| 53 | X_T0 = 5, | |
| 54 | X_T1 = 6, | |
| 55 | X_T2 = 7, | |
| 56 | X_T3 = 28, | |
| 57 | }; | |
| 58 | ||
| 59 | static uint32_t hi20(uint32_t val) { return (val + 0x800) >> 12; } | |
| 60 | static uint32_t lo12(uint32_t val) { return val & 4095; } | |
| 61 | ||
| 62 | static uint32_t itype(uint32_t op, uint32_t rd, uint32_t rs1, uint32_t imm) { | |
| 63 | return op | (rd << 7) | (rs1 << 15) | (imm << 20); | |
| 64 | } | |
| 65 | static uint32_t rtype(uint32_t op, uint32_t rd, uint32_t rs1, uint32_t rs2) { | |
| 66 | return op | (rd << 7) | (rs1 << 15) | (rs2 << 20); | |
| 67 | } | |
| 68 | static uint32_t utype(uint32_t op, uint32_t rd, uint32_t imm) { | |
| 69 | return op | (rd << 7) | (imm << 12); | |
| 70 | } | |
| 71 | ||
| 72 | RISCV::RISCV() { | |
| 73 | copyRel = R_RISCV_COPY; | |
| 74 | noneRel = R_RISCV_NONE; | |
| 75 | pltRel = R_RISCV_JUMP_SLOT; | |
| 76 | relativeRel = R_RISCV_RELATIVE; | |
| 77 | if (config->is64) { | |
| 78 | symbolicRel = R_RISCV_64; | |
| 79 | tlsModuleIndexRel = R_RISCV_TLS_DTPMOD64; | |
| 80 | tlsOffsetRel = R_RISCV_TLS_DTPREL64; | |
| 81 | tlsGotRel = R_RISCV_TLS_TPREL64; | |
| 82 | } else { | |
| 83 | symbolicRel = R_RISCV_32; | |
| 84 | tlsModuleIndexRel = R_RISCV_TLS_DTPMOD32; | |
| 85 | tlsOffsetRel = R_RISCV_TLS_DTPREL32; | |
| 86 | tlsGotRel = R_RISCV_TLS_TPREL32; | |
| 87 | } | |
| 88 | gotRel = symbolicRel; | |
| 89 | ||
| 90 | // .got[0] = _DYNAMIC | |
| 91 | gotBaseSymInGotPlt = false; | |
| 92 | gotHeaderEntriesNum = 1; | |
| 93 | ||
| 94 | // .got.plt[0] = _dl_runtime_resolve, .got.plt[1] = link_map | |
| 95 | gotPltHeaderEntriesNum = 2; | |
| 34 | 96 | |
| 35 | static uint32_t getEFlags(InputFile *F) { | |
| 36 | if (Config->Is64) | |
| 37 | return cast<ObjFile<ELF64LE>>(F)->getObj().getHeader()->e_flags; | |
| 38 | return cast<ObjFile<ELF32LE>>(F)->getObj().getHeader()->e_flags; | |
| 97 | pltEntrySize = 16; | |
| 98 | pltHeaderSize = 32; | |
| 99 | } | |
| 100 | ||
| 101 | static uint32_t getEFlags(InputFile *f) { | |
| 102 | if (config->is64) | |
| 103 | return cast<ObjFile<ELF64LE>>(f)->getObj().getHeader()->e_flags; | |
| 104 | return cast<ObjFile<ELF32LE>>(f)->getObj().getHeader()->e_flags; | |
| 39 | 105 | } |
| 40 | 106 | |
| 41 | 107 | uint32_t RISCV::calcEFlags() const { |
| 42 | assert(!ObjectFiles.empty()); | |
| 108 | assert(!objectFiles.empty()); | |
| 43 | 109 | |
| 44 | uint32_t Target = getEFlags(ObjectFiles.front()); | |
| 110 | uint32_t target = getEFlags(objectFiles.front()); | |
| 45 | 111 | |
| 46 | for (InputFile *F : ObjectFiles) { | |
| 47 | uint32_t EFlags = getEFlags(F); | |
| 48 | if (EFlags & EF_RISCV_RVC) | |
| 49 | Target |= EF_RISCV_RVC; | |
| 112 | for (InputFile *f : objectFiles) { | |
| 113 | uint32_t eflags = getEFlags(f); | |
| 114 | if (eflags & EF_RISCV_RVC) | |
| 115 | target |= EF_RISCV_RVC; | |
| 50 | 116 | |
| 51 | if ((EFlags & EF_RISCV_FLOAT_ABI) != (Target & EF_RISCV_FLOAT_ABI)) | |
| 52 | error(toString(F) + | |
| 117 | if ((eflags & EF_RISCV_FLOAT_ABI) != (target & EF_RISCV_FLOAT_ABI)) | |
| 118 | error(toString(f) + | |
| 53 | 119 | ": cannot link object files with different floating-point ABI"); |
| 54 | 120 | |
| 55 | if ((EFlags & EF_RISCV_RVE) != (Target & EF_RISCV_RVE)) | |
| 56 | error(toString(F) + | |
| 121 | if ((eflags & EF_RISCV_RVE) != (target & EF_RISCV_RVE)) | |
| 122 | error(toString(f) + | |
| 57 | 123 | ": cannot link object files with different EF_RISCV_RVE"); |
| 58 | 124 | } |
| 59 | 125 | |
| 60 | return Target; | |
| 126 | return target; | |
| 127 | } | |
| 128 | ||
| 129 | void RISCV::writeGotHeader(uint8_t *buf) const { | |
| 130 | if (config->is64) | |
| 131 | write64le(buf, mainPart->dynamic->getVA()); | |
| 132 | else | |
| 133 | write32le(buf, mainPart->dynamic->getVA()); | |
| 134 | } | |
| 135 | ||
| 136 | void RISCV::writeGotPlt(uint8_t *buf, const Symbol &s) const { | |
| 137 | if (config->is64) | |
| 138 | write64le(buf, in.plt->getVA()); | |
| 139 | else | |
| 140 | write32le(buf, in.plt->getVA()); | |
| 141 | } | |
| 142 | ||
| 143 | void RISCV::writePltHeader(uint8_t *buf) const { | |
| 144 | // 1: auipc t2, %pcrel_hi(.got.plt) | |
| 145 | // sub t1, t1, t3 | |
| 146 | // l[wd] t3, %pcrel_lo(1b)(t2); t3 = _dl_runtime_resolve | |
| 147 | // addi t1, t1, -pltHeaderSize-12; t1 = &.plt[i] - &.plt[0] | |
| 148 | // addi t0, t2, %pcrel_lo(1b) | |
| 149 | // srli t1, t1, (rv64?1:2); t1 = &.got.plt[i] - &.got.plt[0] | |
| 150 | // l[wd] t0, Wordsize(t0); t0 = link_map | |
| 151 | // jr t3 | |
| 152 | uint32_t offset = in.gotPlt->getVA() - in.plt->getVA(); | |
| 153 | uint32_t load = config->is64 ? LD : LW; | |
| 154 | write32le(buf + 0, utype(AUIPC, X_T2, hi20(offset))); | |
| 155 | write32le(buf + 4, rtype(SUB, X_T1, X_T1, X_T3)); | |
| 156 | write32le(buf + 8, itype(load, X_T3, X_T2, lo12(offset))); | |
| 157 | write32le(buf + 12, itype(ADDI, X_T1, X_T1, -target->pltHeaderSize - 12)); | |
| 158 | write32le(buf + 16, itype(ADDI, X_T0, X_T2, lo12(offset))); | |
| 159 | write32le(buf + 20, itype(SRLI, X_T1, X_T1, config->is64 ? 1 : 2)); | |
| 160 | write32le(buf + 24, itype(load, X_T0, X_T0, config->wordsize)); | |
| 161 | write32le(buf + 28, itype(JALR, 0, X_T3, 0)); | |
| 61 | 162 | } |
| 62 | 163 | |
| 63 | RelExpr RISCV::getRelExpr(const RelType Type, const Symbol &S, | |
| 64 | const uint8_t *Loc) const { | |
| 65 | switch (Type) { | |
| 164 | void RISCV::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, | |
| 165 | uint64_t pltEntryAddr, int32_t index, | |
| 166 | unsigned relOff) const { | |
| 167 | // 1: auipc t3, %pcrel_hi(f@.got.plt) | |
| 168 | // l[wd] t3, %pcrel_lo(1b)(t3) | |
| 169 | // jalr t1, t3 | |
| 170 | // nop | |
| 171 | uint32_t offset = gotPltEntryAddr - pltEntryAddr; | |
| 172 | write32le(buf + 0, utype(AUIPC, X_T3, hi20(offset))); | |
| 173 | write32le(buf + 4, itype(config->is64 ? LD : LW, X_T3, X_T3, lo12(offset))); | |
| 174 | write32le(buf + 8, itype(JALR, X_T1, X_T3, 0)); | |
| 175 | write32le(buf + 12, itype(ADDI, 0, 0, 0)); | |
| 176 | } | |
| 177 | ||
| 178 | RelType RISCV::getDynRel(RelType type) const { | |
| 179 | return type == target->symbolicRel ? type | |
| 180 | : static_cast<RelType>(R_RISCV_NONE); | |
| 181 | } | |
| 182 | ||
| 183 | RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s, | |
| 184 | const uint8_t *loc) const { | |
| 185 | switch (type) { | |
| 186 | case R_RISCV_ADD8: | |
| 187 | case R_RISCV_ADD16: | |
| 188 | case R_RISCV_ADD32: | |
| 189 | case R_RISCV_ADD64: | |
| 190 | case R_RISCV_SET6: | |
| 191 | case R_RISCV_SET8: | |
| 192 | case R_RISCV_SET16: | |
| 193 | case R_RISCV_SET32: | |
| 194 | case R_RISCV_SUB6: | |
| 195 | case R_RISCV_SUB8: | |
| 196 | case R_RISCV_SUB16: | |
| 197 | case R_RISCV_SUB32: | |
| 198 | case R_RISCV_SUB64: | |
| 199 | return R_RISCV_ADD; | |
| 66 | 200 | case R_RISCV_JAL: |
| 67 | 201 | case R_RISCV_BRANCH: |
| 68 | case R_RISCV_CALL: | |
| 69 | 202 | case R_RISCV_PCREL_HI20: |
| 70 | 203 | case R_RISCV_RVC_BRANCH: |
| 71 | 204 | case R_RISCV_RVC_JUMP: |
| 72 | 205 | case R_RISCV_32_PCREL: |
| 73 | 206 | return R_PC; |
| 207 | case R_RISCV_CALL: | |
| 208 | case R_RISCV_CALL_PLT: | |
| 209 | return R_PLT_PC; | |
| 210 | case R_RISCV_GOT_HI20: | |
| 211 | return R_GOT_PC; | |
| 74 | 212 | case R_RISCV_PCREL_LO12_I: |
| 75 | 213 | case R_RISCV_PCREL_LO12_S: |
| 76 | 214 | return R_RISCV_PC_INDIRECT; |
| 215 | case R_RISCV_TLS_GD_HI20: | |
| 216 | return R_TLSGD_PC; | |
| 217 | case R_RISCV_TLS_GOT_HI20: | |
| 218 | config->hasStaticTlsModel = true; | |
| 219 | return R_GOT_PC; | |
| 220 | case R_RISCV_TPREL_HI20: | |
| 221 | case R_RISCV_TPREL_LO12_I: | |
| 222 | case R_RISCV_TPREL_LO12_S: | |
| 223 | return R_TLS; | |
| 77 | 224 | case R_RISCV_RELAX: |
| 78 | 225 | case R_RISCV_ALIGN: |
| 226 | case R_RISCV_TPREL_ADD: | |
| 79 | 227 | return R_HINT; |
| 80 | 228 | default: |
| 81 | 229 | return R_ABS; |
| ... | ... | @@ -83,175 +231,190 @@ RelExpr RISCV::getRelExpr(const RelType Type, const Symbol &S, |
| 83 | 231 | } |
| 84 | 232 | |
| 85 | 233 | // Extract bits V[Begin:End], where range is inclusive, and Begin must be < 63. |
| 86 | static uint32_t extractBits(uint64_t V, uint32_t Begin, uint32_t End) { | |
| 87 | return (V & ((1ULL << (Begin + 1)) - 1)) >> End; | |
| 234 | static uint32_t extractBits(uint64_t v, uint32_t begin, uint32_t end) { | |
| 235 | return (v & ((1ULL << (begin + 1)) - 1)) >> end; | |
| 88 | 236 | } |
| 89 | 237 | |
| 90 | void RISCV::relocateOne(uint8_t *Loc, const RelType Type, | |
| 91 | const uint64_t Val) const { | |
| 92 | switch (Type) { | |
| 238 | void RISCV::relocateOne(uint8_t *loc, const RelType type, | |
| 239 | const uint64_t val) const { | |
| 240 | const unsigned bits = config->wordsize * 8; | |
| 241 | ||
| 242 | switch (type) { | |
| 93 | 243 | case R_RISCV_32: |
| 94 | write32le(Loc, Val); | |
| 244 | write32le(loc, val); | |
| 95 | 245 | return; |
| 96 | 246 | case R_RISCV_64: |
| 97 | write64le(Loc, Val); | |
| 247 | write64le(loc, val); | |
| 98 | 248 | return; |
| 99 | 249 | |
| 100 | 250 | case R_RISCV_RVC_BRANCH: { |
| 101 | checkInt(Loc, static_cast<int64_t>(Val) >> 1, 8, Type); | |
| 102 | checkAlignment(Loc, Val, 2, Type); | |
| 103 | uint16_t Insn = read16le(Loc) & 0xE383; | |
| 104 | uint16_t Imm8 = extractBits(Val, 8, 8) << 12; | |
| 105 | uint16_t Imm4_3 = extractBits(Val, 4, 3) << 10; | |
| 106 | uint16_t Imm7_6 = extractBits(Val, 7, 6) << 5; | |
| 107 | uint16_t Imm2_1 = extractBits(Val, 2, 1) << 3; | |
| 108 | uint16_t Imm5 = extractBits(Val, 5, 5) << 2; | |
| 109 | Insn |= Imm8 | Imm4_3 | Imm7_6 | Imm2_1 | Imm5; | |
| 110 | ||
| 111 | write16le(Loc, Insn); | |
| 251 | checkInt(loc, static_cast<int64_t>(val) >> 1, 8, type); | |
| 252 | checkAlignment(loc, val, 2, type); | |
| 253 | uint16_t insn = read16le(loc) & 0xE383; | |
| 254 | uint16_t imm8 = extractBits(val, 8, 8) << 12; | |
| 255 | uint16_t imm4_3 = extractBits(val, 4, 3) << 10; | |
| 256 | uint16_t imm7_6 = extractBits(val, 7, 6) << 5; | |
| 257 | uint16_t imm2_1 = extractBits(val, 2, 1) << 3; | |
| 258 | uint16_t imm5 = extractBits(val, 5, 5) << 2; | |
| 259 | insn |= imm8 | imm4_3 | imm7_6 | imm2_1 | imm5; | |
| 260 | ||
| 261 | write16le(loc, insn); | |
| 112 | 262 | return; |
| 113 | 263 | } |
| 114 | 264 | |
| 115 | 265 | case R_RISCV_RVC_JUMP: { |
| 116 | checkInt(Loc, static_cast<int64_t>(Val) >> 1, 11, Type); | |
| 117 | checkAlignment(Loc, Val, 2, Type); | |
| 118 | uint16_t Insn = read16le(Loc) & 0xE003; | |
| 119 | uint16_t Imm11 = extractBits(Val, 11, 11) << 12; | |
| 120 | uint16_t Imm4 = extractBits(Val, 4, 4) << 11; | |
| 121 | uint16_t Imm9_8 = extractBits(Val, 9, 8) << 9; | |
| 122 | uint16_t Imm10 = extractBits(Val, 10, 10) << 8; | |
| 123 | uint16_t Imm6 = extractBits(Val, 6, 6) << 7; | |
| 124 | uint16_t Imm7 = extractBits(Val, 7, 7) << 6; | |
| 125 | uint16_t Imm3_1 = extractBits(Val, 3, 1) << 3; | |
| 126 | uint16_t Imm5 = extractBits(Val, 5, 5) << 2; | |
| 127 | Insn |= Imm11 | Imm4 | Imm9_8 | Imm10 | Imm6 | Imm7 | Imm3_1 | Imm5; | |
| 128 | ||
| 129 | write16le(Loc, Insn); | |
| 266 | checkInt(loc, static_cast<int64_t>(val) >> 1, 11, type); | |
| 267 | checkAlignment(loc, val, 2, type); | |
| 268 | uint16_t insn = read16le(loc) & 0xE003; | |
| 269 | uint16_t imm11 = extractBits(val, 11, 11) << 12; | |
| 270 | uint16_t imm4 = extractBits(val, 4, 4) << 11; | |
| 271 | uint16_t imm9_8 = extractBits(val, 9, 8) << 9; | |
| 272 | uint16_t imm10 = extractBits(val, 10, 10) << 8; | |
| 273 | uint16_t imm6 = extractBits(val, 6, 6) << 7; | |
| 274 | uint16_t imm7 = extractBits(val, 7, 7) << 6; | |
| 275 | uint16_t imm3_1 = extractBits(val, 3, 1) << 3; | |
| 276 | uint16_t imm5 = extractBits(val, 5, 5) << 2; | |
| 277 | insn |= imm11 | imm4 | imm9_8 | imm10 | imm6 | imm7 | imm3_1 | imm5; | |
| 278 | ||
| 279 | write16le(loc, insn); | |
| 130 | 280 | return; |
| 131 | 281 | } |
| 132 | 282 | |
| 133 | 283 | case R_RISCV_RVC_LUI: { |
| 134 | int32_t Imm = ((Val + 0x800) >> 12); | |
| 135 | checkUInt(Loc, Imm, 6, Type); | |
| 136 | if (Imm == 0) { // `c.lui rd, 0` is illegal, convert to `c.li rd, 0` | |
| 137 | write16le(Loc, (read16le(Loc) & 0x0F83) | 0x4000); | |
| 284 | int64_t imm = SignExtend64(val + 0x800, bits) >> 12; | |
| 285 | checkInt(loc, imm, 6, type); | |
| 286 | if (imm == 0) { // `c.lui rd, 0` is illegal, convert to `c.li rd, 0` | |
| 287 | write16le(loc, (read16le(loc) & 0x0F83) | 0x4000); | |
| 138 | 288 | } else { |
| 139 | uint16_t Imm17 = extractBits(Val + 0x800, 17, 17) << 12; | |
| 140 | uint16_t Imm16_12 = extractBits(Val + 0x800, 16, 12) << 2; | |
| 141 | write16le(Loc, (read16le(Loc) & 0xEF83) | Imm17 | Imm16_12); | |
| 289 | uint16_t imm17 = extractBits(val + 0x800, 17, 17) << 12; | |
| 290 | uint16_t imm16_12 = extractBits(val + 0x800, 16, 12) << 2; | |
| 291 | write16le(loc, (read16le(loc) & 0xEF83) | imm17 | imm16_12); | |
| 142 | 292 | } |
| 143 | 293 | return; |
| 144 | 294 | } |
| 145 | 295 | |
| 146 | 296 | case R_RISCV_JAL: { |
| 147 | checkInt(Loc, static_cast<int64_t>(Val) >> 1, 20, Type); | |
| 148 | checkAlignment(Loc, Val, 2, Type); | |
| 297 | checkInt(loc, static_cast<int64_t>(val) >> 1, 20, type); | |
| 298 | checkAlignment(loc, val, 2, type); | |
| 149 | 299 | |
| 150 | uint32_t Insn = read32le(Loc) & 0xFFF; | |
| 151 | uint32_t Imm20 = extractBits(Val, 20, 20) << 31; | |
| 152 | uint32_t Imm10_1 = extractBits(Val, 10, 1) << 21; | |
| 153 | uint32_t Imm11 = extractBits(Val, 11, 11) << 20; | |
| 154 | uint32_t Imm19_12 = extractBits(Val, 19, 12) << 12; | |
| 155 | Insn |= Imm20 | Imm10_1 | Imm11 | Imm19_12; | |
| 300 | uint32_t insn = read32le(loc) & 0xFFF; | |
| 301 | uint32_t imm20 = extractBits(val, 20, 20) << 31; | |
| 302 | uint32_t imm10_1 = extractBits(val, 10, 1) << 21; | |
| 303 | uint32_t imm11 = extractBits(val, 11, 11) << 20; | |
| 304 | uint32_t imm19_12 = extractBits(val, 19, 12) << 12; | |
| 305 | insn |= imm20 | imm10_1 | imm11 | imm19_12; | |
| 156 | 306 | |
| 157 | write32le(Loc, Insn); | |
| 307 | write32le(loc, insn); | |
| 158 | 308 | return; |
| 159 | 309 | } |
| 160 | 310 | |
| 161 | 311 | case R_RISCV_BRANCH: { |
| 162 | checkInt(Loc, static_cast<int64_t>(Val) >> 1, 12, Type); | |
| 163 | checkAlignment(Loc, Val, 2, Type); | |
| 312 | checkInt(loc, static_cast<int64_t>(val) >> 1, 12, type); | |
| 313 | checkAlignment(loc, val, 2, type); | |
| 164 | 314 | |
| 165 | uint32_t Insn = read32le(Loc) & 0x1FFF07F; | |
| 166 | uint32_t Imm12 = extractBits(Val, 12, 12) << 31; | |
| 167 | uint32_t Imm10_5 = extractBits(Val, 10, 5) << 25; | |
| 168 | uint32_t Imm4_1 = extractBits(Val, 4, 1) << 8; | |
| 169 | uint32_t Imm11 = extractBits(Val, 11, 11) << 7; | |
| 170 | Insn |= Imm12 | Imm10_5 | Imm4_1 | Imm11; | |
| 315 | uint32_t insn = read32le(loc) & 0x1FFF07F; | |
| 316 | uint32_t imm12 = extractBits(val, 12, 12) << 31; | |
| 317 | uint32_t imm10_5 = extractBits(val, 10, 5) << 25; | |
| 318 | uint32_t imm4_1 = extractBits(val, 4, 1) << 8; | |
| 319 | uint32_t imm11 = extractBits(val, 11, 11) << 7; | |
| 320 | insn |= imm12 | imm10_5 | imm4_1 | imm11; | |
| 171 | 321 | |
| 172 | write32le(Loc, Insn); | |
| 322 | write32le(loc, insn); | |
| 173 | 323 | return; |
| 174 | 324 | } |
| 175 | 325 | |
| 176 | 326 | // auipc + jalr pair |
| 177 | case R_RISCV_CALL: { | |
| 178 | checkInt(Loc, Val, 32, Type); | |
| 179 | if (isInt<32>(Val)) { | |
| 180 | relocateOne(Loc, R_RISCV_PCREL_HI20, Val); | |
| 181 | relocateOne(Loc + 4, R_RISCV_PCREL_LO12_I, Val); | |
| 327 | case R_RISCV_CALL: | |
| 328 | case R_RISCV_CALL_PLT: { | |
| 329 | int64_t hi = SignExtend64(val + 0x800, bits) >> 12; | |
| 330 | checkInt(loc, hi, 20, type); | |
| 331 | if (isInt<20>(hi)) { | |
| 332 | relocateOne(loc, R_RISCV_PCREL_HI20, val); | |
| 333 | relocateOne(loc + 4, R_RISCV_PCREL_LO12_I, val); | |
| 182 | 334 | } |
| 183 | 335 | return; |
| 184 | 336 | } |
| 185 | 337 | |
| 338 | case R_RISCV_GOT_HI20: | |
| 186 | 339 | case R_RISCV_PCREL_HI20: |
| 340 | case R_RISCV_TLS_GD_HI20: | |
| 341 | case R_RISCV_TLS_GOT_HI20: | |
| 342 | case R_RISCV_TPREL_HI20: | |
| 187 | 343 | case R_RISCV_HI20: { |
| 188 | checkInt(Loc, Val, 32, Type); | |
| 189 | uint32_t Hi = Val + 0x800; | |
| 190 | write32le(Loc, (read32le(Loc) & 0xFFF) | (Hi & 0xFFFFF000)); | |
| 344 | uint64_t hi = val + 0x800; | |
| 345 | checkInt(loc, SignExtend64(hi, bits) >> 12, 20, type); | |
| 346 | write32le(loc, (read32le(loc) & 0xFFF) | (hi & 0xFFFFF000)); | |
| 191 | 347 | return; |
| 192 | 348 | } |
| 193 | 349 | |
| 194 | 350 | case R_RISCV_PCREL_LO12_I: |
| 351 | case R_RISCV_TPREL_LO12_I: | |
| 195 | 352 | case R_RISCV_LO12_I: { |
| 196 | checkInt(Loc, Val, 32, Type); | |
| 197 | uint32_t Hi = Val + 0x800; | |
| 198 | uint32_t Lo = Val - (Hi & 0xFFFFF000); | |
| 199 | write32le(Loc, (read32le(Loc) & 0xFFFFF) | ((Lo & 0xFFF) << 20)); | |
| 353 | uint64_t hi = (val + 0x800) >> 12; | |
| 354 | uint64_t lo = val - (hi << 12); | |
| 355 | write32le(loc, (read32le(loc) & 0xFFFFF) | ((lo & 0xFFF) << 20)); | |
| 200 | 356 | return; |
| 201 | 357 | } |
| 202 | 358 | |
| 203 | 359 | case R_RISCV_PCREL_LO12_S: |
| 360 | case R_RISCV_TPREL_LO12_S: | |
| 204 | 361 | case R_RISCV_LO12_S: { |
| 205 | checkInt(Loc, Val, 32, Type); | |
| 206 | uint32_t Hi = Val + 0x800; | |
| 207 | uint32_t Lo = Val - (Hi & 0xFFFFF000); | |
| 208 | uint32_t Imm11_5 = extractBits(Lo, 11, 5) << 25; | |
| 209 | uint32_t Imm4_0 = extractBits(Lo, 4, 0) << 7; | |
| 210 | write32le(Loc, (read32le(Loc) & 0x1FFF07F) | Imm11_5 | Imm4_0); | |
| 362 | uint64_t hi = (val + 0x800) >> 12; | |
| 363 | uint64_t lo = val - (hi << 12); | |
| 364 | uint32_t imm11_5 = extractBits(lo, 11, 5) << 25; | |
| 365 | uint32_t imm4_0 = extractBits(lo, 4, 0) << 7; | |
| 366 | write32le(loc, (read32le(loc) & 0x1FFF07F) | imm11_5 | imm4_0); | |
| 211 | 367 | return; |
| 212 | 368 | } |
| 213 | 369 | |
| 214 | 370 | case R_RISCV_ADD8: |
| 215 | *Loc += Val; | |
| 371 | *loc += val; | |
| 216 | 372 | return; |
| 217 | 373 | case R_RISCV_ADD16: |
| 218 | write16le(Loc, read16le(Loc) + Val); | |
| 374 | write16le(loc, read16le(loc) + val); | |
| 219 | 375 | return; |
| 220 | 376 | case R_RISCV_ADD32: |
| 221 | write32le(Loc, read32le(Loc) + Val); | |
| 377 | write32le(loc, read32le(loc) + val); | |
| 222 | 378 | return; |
| 223 | 379 | case R_RISCV_ADD64: |
| 224 | write64le(Loc, read64le(Loc) + Val); | |
| 380 | write64le(loc, read64le(loc) + val); | |
| 225 | 381 | return; |
| 226 | 382 | case R_RISCV_SUB6: |
| 227 | *Loc = (*Loc & 0xc0) | (((*Loc & 0x3f) - Val) & 0x3f); | |
| 383 | *loc = (*loc & 0xc0) | (((*loc & 0x3f) - val) & 0x3f); | |
| 228 | 384 | return; |
| 229 | 385 | case R_RISCV_SUB8: |
| 230 | *Loc -= Val; | |
| 386 | *loc -= val; | |
| 231 | 387 | return; |
| 232 | 388 | case R_RISCV_SUB16: |
| 233 | write16le(Loc, read16le(Loc) - Val); | |
| 389 | write16le(loc, read16le(loc) - val); | |
| 234 | 390 | return; |
| 235 | 391 | case R_RISCV_SUB32: |
| 236 | write32le(Loc, read32le(Loc) - Val); | |
| 392 | write32le(loc, read32le(loc) - val); | |
| 237 | 393 | return; |
| 238 | 394 | case R_RISCV_SUB64: |
| 239 | write64le(Loc, read64le(Loc) - Val); | |
| 395 | write64le(loc, read64le(loc) - val); | |
| 240 | 396 | return; |
| 241 | 397 | case R_RISCV_SET6: |
| 242 | *Loc = (*Loc & 0xc0) | (Val & 0x3f); | |
| 398 | *loc = (*loc & 0xc0) | (val & 0x3f); | |
| 243 | 399 | return; |
| 244 | 400 | case R_RISCV_SET8: |
| 245 | *Loc = Val; | |
| 401 | *loc = val; | |
| 246 | 402 | return; |
| 247 | 403 | case R_RISCV_SET16: |
| 248 | write16le(Loc, Val); | |
| 404 | write16le(loc, val); | |
| 249 | 405 | return; |
| 250 | 406 | case R_RISCV_SET32: |
| 251 | 407 | case R_RISCV_32_PCREL: |
| 252 | write32le(Loc, Val); | |
| 408 | write32le(loc, val); | |
| 253 | 409 | return; |
| 254 | 410 | |
| 411 | case R_RISCV_TLS_DTPREL32: | |
| 412 | write32le(loc, val - dtpOffset); | |
| 413 | break; | |
| 414 | case R_RISCV_TLS_DTPREL64: | |
| 415 | write64le(loc, val - dtpOffset); | |
| 416 | break; | |
| 417 | ||
| 255 | 418 | case R_RISCV_ALIGN: |
| 256 | 419 | case R_RISCV_RELAX: |
| 257 | 420 | return; // Ignored (for now) |
| ... | ... | @@ -267,13 +430,13 @@ void RISCV::relocateOne(uint8_t *Loc, const RelType Type, |
| 267 | 430 | case R_RISCV_GPREL_I: |
| 268 | 431 | case R_RISCV_GPREL_S: |
| 269 | 432 | default: |
| 270 | error(getErrorLocation(Loc) + | |
| 271 | "unimplemented relocation: " + toString(Type)); | |
| 433 | error(getErrorLocation(loc) + | |
| 434 | "unimplemented relocation: " + toString(type)); | |
| 272 | 435 | return; |
| 273 | 436 | } |
| 274 | 437 | } |
| 275 | 438 | |
| 276 | 439 | TargetInfo *elf::getRISCVTargetInfo() { |
| 277 | static RISCV Target; | |
| 278 | return &Target; | |
| 440 | static RISCV target; | |
| 441 | return &target; | |
| 279 | 442 | } |
deps/lld/ELF/Arch/SPARCV9.cpp+51-51| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- SPARCV9.cpp --------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -24,32 +23,32 @@ namespace { |
| 24 | 23 | class SPARCV9 final : public TargetInfo { |
| 25 | 24 | public: |
| 26 | 25 | SPARCV9(); |
| 27 | RelExpr getRelExpr(RelType Type, const Symbol &S, | |
| 28 | const uint8_t *Loc) const override; | |
| 29 | void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, | |
| 30 | int32_t Index, unsigned RelOff) const override; | |
| 31 | void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 26 | RelExpr getRelExpr(RelType type, const Symbol &s, | |
| 27 | const uint8_t *loc) const override; | |
| 28 | void writePlt(uint8_t *buf, uint64_t gotEntryAddr, uint64_t pltEntryAddr, | |
| 29 | int32_t index, unsigned relOff) const override; | |
| 30 | void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 32 | 31 | }; |
| 33 | 32 | } // namespace |
| 34 | 33 | |
| 35 | 34 | SPARCV9::SPARCV9() { |
| 36 | CopyRel = R_SPARC_COPY; | |
| 37 | GotRel = R_SPARC_GLOB_DAT; | |
| 38 | NoneRel = R_SPARC_NONE; | |
| 39 | PltRel = R_SPARC_JMP_SLOT; | |
| 40 | RelativeRel = R_SPARC_RELATIVE; | |
| 41 | GotEntrySize = 8; | |
| 42 | PltEntrySize = 32; | |
| 43 | PltHeaderSize = 4 * PltEntrySize; | |
| 35 | copyRel = R_SPARC_COPY; | |
| 36 | gotRel = R_SPARC_GLOB_DAT; | |
| 37 | noneRel = R_SPARC_NONE; | |
| 38 | pltRel = R_SPARC_JMP_SLOT; | |
| 39 | relativeRel = R_SPARC_RELATIVE; | |
| 40 | symbolicRel = R_SPARC_64; | |
| 41 | pltEntrySize = 32; | |
| 42 | pltHeaderSize = 4 * pltEntrySize; | |
| 44 | 43 | |
| 45 | PageSize = 8192; | |
| 46 | DefaultMaxPageSize = 0x100000; | |
| 47 | DefaultImageBase = 0x100000; | |
| 44 | defaultCommonPageSize = 8192; | |
| 45 | defaultMaxPageSize = 0x100000; | |
| 46 | defaultImageBase = 0x100000; | |
| 48 | 47 | } |
| 49 | 48 | |
| 50 | RelExpr SPARCV9::getRelExpr(RelType Type, const Symbol &S, | |
| 51 | const uint8_t *Loc) const { | |
| 52 | switch (Type) { | |
| 49 | RelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s, | |
| 50 | const uint8_t *loc) const { | |
| 51 | switch (type) { | |
| 53 | 52 | case R_SPARC_32: |
| 54 | 53 | case R_SPARC_UA32: |
| 55 | 54 | case R_SPARC_64: |
| ... | ... | @@ -69,64 +68,65 @@ RelExpr SPARCV9::getRelExpr(RelType Type, const Symbol &S, |
| 69 | 68 | case R_SPARC_NONE: |
| 70 | 69 | return R_NONE; |
| 71 | 70 | default: |
| 72 | return R_INVALID; | |
| 71 | error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + | |
| 72 | ") against symbol " + toString(s)); | |
| 73 | return R_NONE; | |
| 73 | 74 | } |
| 74 | 75 | } |
| 75 | 76 | |
| 76 | void SPARCV9::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 77 | switch (Type) { | |
| 77 | void SPARCV9::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { | |
| 78 | switch (type) { | |
| 78 | 79 | case R_SPARC_32: |
| 79 | 80 | case R_SPARC_UA32: |
| 80 | 81 | // V-word32 |
| 81 | checkUInt(Loc, Val, 32, Type); | |
| 82 | write32be(Loc, Val); | |
| 82 | checkUInt(loc, val, 32, type); | |
| 83 | write32be(loc, val); | |
| 83 | 84 | break; |
| 84 | 85 | case R_SPARC_DISP32: |
| 85 | 86 | // V-disp32 |
| 86 | checkInt(Loc, Val, 32, Type); | |
| 87 | write32be(Loc, Val); | |
| 87 | checkInt(loc, val, 32, type); | |
| 88 | write32be(loc, val); | |
| 88 | 89 | break; |
| 89 | 90 | case R_SPARC_WDISP30: |
| 90 | 91 | case R_SPARC_WPLT30: |
| 91 | 92 | // V-disp30 |
| 92 | checkInt(Loc, Val, 32, Type); | |
| 93 | write32be(Loc, (read32be(Loc) & ~0x3fffffff) | ((Val >> 2) & 0x3fffffff)); | |
| 93 | checkInt(loc, val, 32, type); | |
| 94 | write32be(loc, (read32be(loc) & ~0x3fffffff) | ((val >> 2) & 0x3fffffff)); | |
| 94 | 95 | break; |
| 95 | 96 | case R_SPARC_22: |
| 96 | 97 | // V-imm22 |
| 97 | checkUInt(Loc, Val, 22, Type); | |
| 98 | write32be(Loc, (read32be(Loc) & ~0x003fffff) | (Val & 0x003fffff)); | |
| 98 | checkUInt(loc, val, 22, type); | |
| 99 | write32be(loc, (read32be(loc) & ~0x003fffff) | (val & 0x003fffff)); | |
| 99 | 100 | break; |
| 100 | 101 | case R_SPARC_GOT22: |
| 101 | 102 | case R_SPARC_PC22: |
| 102 | 103 | // T-imm22 |
| 103 | write32be(Loc, (read32be(Loc) & ~0x003fffff) | ((Val >> 10) & 0x003fffff)); | |
| 104 | write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff)); | |
| 104 | 105 | break; |
| 105 | 106 | case R_SPARC_WDISP19: |
| 106 | 107 | // V-disp19 |
| 107 | checkInt(Loc, Val, 21, Type); | |
| 108 | write32be(Loc, (read32be(Loc) & ~0x0007ffff) | ((Val >> 2) & 0x0007ffff)); | |
| 108 | checkInt(loc, val, 21, type); | |
| 109 | write32be(loc, (read32be(loc) & ~0x0007ffff) | ((val >> 2) & 0x0007ffff)); | |
| 109 | 110 | break; |
| 110 | 111 | case R_SPARC_GOT10: |
| 111 | 112 | case R_SPARC_PC10: |
| 112 | 113 | // T-simm10 |
| 113 | write32be(Loc, (read32be(Loc) & ~0x000003ff) | (Val & 0x000003ff)); | |
| 114 | write32be(loc, (read32be(loc) & ~0x000003ff) | (val & 0x000003ff)); | |
| 114 | 115 | break; |
| 115 | 116 | case R_SPARC_64: |
| 116 | 117 | case R_SPARC_UA64: |
| 117 | case R_SPARC_GLOB_DAT: | |
| 118 | 118 | // V-xword64 |
| 119 | write64be(Loc, Val); | |
| 119 | write64be(loc, val); | |
| 120 | 120 | break; |
| 121 | 121 | default: |
| 122 | error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); | |
| 122 | llvm_unreachable("unknown relocation"); | |
| 123 | 123 | } |
| 124 | 124 | } |
| 125 | 125 | |
| 126 | void SPARCV9::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, | |
| 127 | uint64_t PltEntryAddr, int32_t Index, | |
| 128 | unsigned RelOff) const { | |
| 129 | const uint8_t PltData[] = { | |
| 126 | void SPARCV9::writePlt(uint8_t *buf, uint64_t gotEntryAddr, | |
| 127 | uint64_t pltEntryAddr, int32_t index, | |
| 128 | unsigned relOff) const { | |
| 129 | const uint8_t pltData[] = { | |
| 130 | 130 | 0x03, 0x00, 0x00, 0x00, // sethi (. - .PLT0), %g1 |
| 131 | 131 | 0x30, 0x68, 0x00, 0x00, // ba,a %xcc, .PLT1 |
| 132 | 132 | 0x01, 0x00, 0x00, 0x00, // nop |
| ... | ... | @@ -136,14 +136,14 @@ void SPARCV9::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, |
| 136 | 136 | 0x01, 0x00, 0x00, 0x00, // nop |
| 137 | 137 | 0x01, 0x00, 0x00, 0x00 // nop |
| 138 | 138 | }; |
| 139 | memcpy(Buf, PltData, sizeof(PltData)); | |
| 139 | memcpy(buf, pltData, sizeof(pltData)); | |
| 140 | 140 | |
| 141 | uint64_t Off = getPltEntryOffset(Index); | |
| 142 | relocateOne(Buf, R_SPARC_22, Off); | |
| 143 | relocateOne(Buf + 4, R_SPARC_WDISP19, -(Off + 4 - PltEntrySize)); | |
| 141 | uint64_t off = pltHeaderSize + pltEntrySize * index; | |
| 142 | relocateOne(buf, R_SPARC_22, off); | |
| 143 | relocateOne(buf + 4, R_SPARC_WDISP19, -(off + 4 - pltEntrySize)); | |
| 144 | 144 | } |
| 145 | 145 | |
| 146 | 146 | TargetInfo *elf::getSPARCV9TargetInfo() { |
| 147 | static SPARCV9 Target; | |
| 148 | return &Target; | |
| 147 | static SPARCV9 target; | |
| 148 | return &target; | |
| 149 | 149 | } |
deps/lld/ELF/Arch/X86.cpp+221-221| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- X86.cpp ------------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -24,63 +23,73 @@ namespace { |
| 24 | 23 | class X86 : public TargetInfo { |
| 25 | 24 | public: |
| 26 | 25 | X86(); |
| 27 | RelExpr getRelExpr(RelType Type, const Symbol &S, | |
| 28 | const uint8_t *Loc) const override; | |
| 29 | int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; | |
| 30 | void writeGotPltHeader(uint8_t *Buf) const override; | |
| 31 | RelType getDynRel(RelType Type) const override; | |
| 32 | void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; | |
| 33 | void writeIgotPlt(uint8_t *Buf, const Symbol &S) const override; | |
| 34 | void writePltHeader(uint8_t *Buf) const override; | |
| 35 | void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, | |
| 36 | int32_t Index, unsigned RelOff) const override; | |
| 37 | void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 38 | ||
| 39 | RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, | |
| 40 | RelExpr Expr) const override; | |
| 41 | void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 42 | void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 43 | void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 44 | void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 26 | int getTlsGdRelaxSkip(RelType type) const override; | |
| 27 | RelExpr getRelExpr(RelType type, const Symbol &s, | |
| 28 | const uint8_t *loc) const override; | |
| 29 | int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; | |
| 30 | void writeGotPltHeader(uint8_t *buf) const override; | |
| 31 | RelType getDynRel(RelType type) const override; | |
| 32 | void writeGotPlt(uint8_t *buf, const Symbol &s) const override; | |
| 33 | void writeIgotPlt(uint8_t *buf, const Symbol &s) const override; | |
| 34 | void writePltHeader(uint8_t *buf) const override; | |
| 35 | void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, | |
| 36 | int32_t index, unsigned relOff) const override; | |
| 37 | void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 38 | ||
| 39 | RelExpr adjustRelaxExpr(RelType type, const uint8_t *data, | |
| 40 | RelExpr expr) const override; | |
| 41 | void relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 42 | void relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 43 | void relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 44 | void relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 45 | 45 | }; |
| 46 | 46 | } // namespace |
| 47 | 47 | |
| 48 | 48 | X86::X86() { |
| 49 | CopyRel = R_386_COPY; | |
| 50 | GotRel = R_386_GLOB_DAT; | |
| 51 | NoneRel = R_386_NONE; | |
| 52 | PltRel = R_386_JUMP_SLOT; | |
| 53 | IRelativeRel = R_386_IRELATIVE; | |
| 54 | RelativeRel = R_386_RELATIVE; | |
| 55 | TlsGotRel = R_386_TLS_TPOFF; | |
| 56 | TlsModuleIndexRel = R_386_TLS_DTPMOD32; | |
| 57 | TlsOffsetRel = R_386_TLS_DTPOFF32; | |
| 58 | GotEntrySize = 4; | |
| 59 | GotPltEntrySize = 4; | |
| 60 | PltEntrySize = 16; | |
| 61 | PltHeaderSize = 16; | |
| 62 | TlsGdRelaxSkip = 2; | |
| 63 | TrapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3 | |
| 49 | copyRel = R_386_COPY; | |
| 50 | gotRel = R_386_GLOB_DAT; | |
| 51 | noneRel = R_386_NONE; | |
| 52 | pltRel = R_386_JUMP_SLOT; | |
| 53 | iRelativeRel = R_386_IRELATIVE; | |
| 54 | relativeRel = R_386_RELATIVE; | |
| 55 | symbolicRel = R_386_32; | |
| 56 | tlsGotRel = R_386_TLS_TPOFF; | |
| 57 | tlsModuleIndexRel = R_386_TLS_DTPMOD32; | |
| 58 | tlsOffsetRel = R_386_TLS_DTPOFF32; | |
| 59 | pltEntrySize = 16; | |
| 60 | pltHeaderSize = 16; | |
| 61 | trapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3 | |
| 64 | 62 | |
| 65 | 63 | // Align to the non-PAE large page size (known as a superpage or huge page). |
| 66 | 64 | // FreeBSD automatically promotes large, superpage-aligned allocations. |
| 67 | DefaultImageBase = 0x400000; | |
| 65 | defaultImageBase = 0x400000; | |
| 68 | 66 | } |
| 69 | 67 | |
| 70 | static bool hasBaseReg(uint8_t ModRM) { return (ModRM & 0xc7) != 0x5; } | |
| 68 | int X86::getTlsGdRelaxSkip(RelType type) const { | |
| 69 | return 2; | |
| 70 | } | |
| 71 | 71 | |
| 72 | RelExpr X86::getRelExpr(RelType Type, const Symbol &S, | |
| 73 | const uint8_t *Loc) const { | |
| 74 | switch (Type) { | |
| 72 | RelExpr X86::getRelExpr(RelType type, const Symbol &s, | |
| 73 | const uint8_t *loc) const { | |
| 74 | // There are 4 different TLS variable models with varying degrees of | |
| 75 | // flexibility and performance. LocalExec and InitialExec models are fast but | |
| 76 | // less-flexible models. If they are in use, we set DF_STATIC_TLS flag in the | |
| 77 | // dynamic section to let runtime know about that. | |
| 78 | if (type == R_386_TLS_LE || type == R_386_TLS_LE_32 || type == R_386_TLS_IE || | |
| 79 | type == R_386_TLS_GOTIE) | |
| 80 | config->hasStaticTlsModel = true; | |
| 81 | ||
| 82 | switch (type) { | |
| 75 | 83 | case R_386_8: |
| 76 | 84 | case R_386_16: |
| 77 | 85 | case R_386_32: |
| 78 | case R_386_TLS_LDO_32: | |
| 79 | 86 | return R_ABS; |
| 87 | case R_386_TLS_LDO_32: | |
| 88 | return R_DTPREL; | |
| 80 | 89 | case R_386_TLS_GD: |
| 81 | return R_TLSGD_GOT_FROM_END; | |
| 90 | return R_TLSGD_GOTPLT; | |
| 82 | 91 | case R_386_TLS_LDM: |
| 83 | return R_TLSLD_GOT_FROM_END; | |
| 92 | return R_TLSLD_GOTPLT; | |
| 84 | 93 | case R_386_PLT32: |
| 85 | 94 | return R_PLT_PC; |
| 86 | 95 | case R_386_PC8: |
| ... | ... | @@ -88,7 +97,7 @@ RelExpr X86::getRelExpr(RelType Type, const Symbol &S, |
| 88 | 97 | case R_386_PC32: |
| 89 | 98 | return R_PC; |
| 90 | 99 | case R_386_GOTPC: |
| 91 | return R_GOTONLY_PC_FROM_END; | |
| 100 | return R_GOTPLTONLY_PC; | |
| 92 | 101 | case R_386_TLS_IE: |
| 93 | 102 | return R_GOT; |
| 94 | 103 | case R_386_GOT32: |
| ... | ... | @@ -108,14 +117,14 @@ RelExpr X86::getRelExpr(RelType Type, const Symbol &S, |
| 108 | 117 | // load an GOT address to a register, which is usually %ebx. |
| 109 | 118 | // |
| 110 | 119 | // So, there are two ways to refer to symbol foo's GOT entry: foo@GOT or |
| 111 | // foo@GOT(%reg). | |
| 120 | // foo@GOT(%ebx). | |
| 112 | 121 | // |
| 113 | 122 | // foo@GOT is not usable in PIC. If we are creating a PIC output and if we |
| 114 | 123 | // find such relocation, we should report an error. foo@GOT is resolved to |
| 115 | 124 | // an *absolute* address of foo's GOT entry, because both GOT address and |
| 116 | 125 | // foo's offset are known. In other words, it's G + A. |
| 117 | 126 | // |
| 118 | // foo@GOT(%reg) needs to be resolved to a *relative* offset from a GOT to | |
| 127 | // foo@GOT(%ebx) needs to be resolved to a *relative* offset from a GOT to | |
| 119 | 128 | // foo's GOT entry in the table, because GOT address is not known but foo's |
| 120 | 129 | // offset in the table is known. It's G + A - GOT. |
| 121 | 130 | // |
| ... | ... | @@ -123,16 +132,16 @@ RelExpr X86::getRelExpr(RelType Type, const Symbol &S, |
| 123 | 132 | // different use cases. In order to distinguish them, we have to read a |
| 124 | 133 | // machine instruction. |
| 125 | 134 | // |
| 126 | // The following code implements it. We assume that Loc[0] is the first | |
| 127 | // byte of a displacement or an immediate field of a valid machine | |
| 135 | // The following code implements it. We assume that Loc[0] is the first byte | |
| 136 | // of a displacement or an immediate field of a valid machine | |
| 128 | 137 | // instruction. That means a ModRM byte is at Loc[-1]. By taking a look at |
| 129 | // the byte, we can determine whether the instruction is register-relative | |
| 130 | // (i.e. it was generated for foo@GOT(%reg)) or absolute (i.e. foo@GOT). | |
| 131 | return hasBaseReg(Loc[-1]) ? R_GOT_FROM_END : R_GOT; | |
| 138 | // the byte, we can determine whether the instruction uses the operand as an | |
| 139 | // absolute address (R_GOT) or a register-relative address (R_GOTPLT). | |
| 140 | return (loc[-1] & 0xc7) == 0x5 ? R_GOT : R_GOTPLT; | |
| 132 | 141 | case R_386_TLS_GOTIE: |
| 133 | return R_GOT_FROM_END; | |
| 142 | return R_GOTPLT; | |
| 134 | 143 | case R_386_GOTOFF: |
| 135 | return R_GOTREL_FROM_END; | |
| 144 | return R_GOTPLTREL; | |
| 136 | 145 | case R_386_TLS_LE: |
| 137 | 146 | return R_TLS; |
| 138 | 147 | case R_386_TLS_LE_32: |
| ... | ... | @@ -140,105 +149,102 @@ RelExpr X86::getRelExpr(RelType Type, const Symbol &S, |
| 140 | 149 | case R_386_NONE: |
| 141 | 150 | return R_NONE; |
| 142 | 151 | default: |
| 143 | return R_INVALID; | |
| 152 | error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + | |
| 153 | ") against symbol " + toString(s)); | |
| 154 | return R_NONE; | |
| 144 | 155 | } |
| 145 | 156 | } |
| 146 | 157 | |
| 147 | RelExpr X86::adjustRelaxExpr(RelType Type, const uint8_t *Data, | |
| 148 | RelExpr Expr) const { | |
| 149 | switch (Expr) { | |
| 158 | RelExpr X86::adjustRelaxExpr(RelType type, const uint8_t *data, | |
| 159 | RelExpr expr) const { | |
| 160 | switch (expr) { | |
| 150 | 161 | default: |
| 151 | return Expr; | |
| 162 | return expr; | |
| 152 | 163 | case R_RELAX_TLS_GD_TO_IE: |
| 153 | return R_RELAX_TLS_GD_TO_IE_END; | |
| 164 | return R_RELAX_TLS_GD_TO_IE_GOTPLT; | |
| 154 | 165 | case R_RELAX_TLS_GD_TO_LE: |
| 155 | 166 | return R_RELAX_TLS_GD_TO_LE_NEG; |
| 156 | 167 | } |
| 157 | 168 | } |
| 158 | 169 | |
| 159 | void X86::writeGotPltHeader(uint8_t *Buf) const { | |
| 160 | write32le(Buf, In.Dynamic->getVA()); | |
| 170 | void X86::writeGotPltHeader(uint8_t *buf) const { | |
| 171 | write32le(buf, mainPart->dynamic->getVA()); | |
| 161 | 172 | } |
| 162 | 173 | |
| 163 | void X86::writeGotPlt(uint8_t *Buf, const Symbol &S) const { | |
| 174 | void X86::writeGotPlt(uint8_t *buf, const Symbol &s) const { | |
| 164 | 175 | // Entries in .got.plt initially points back to the corresponding |
| 165 | 176 | // PLT entries with a fixed offset to skip the first instruction. |
| 166 | write32le(Buf, S.getPltVA() + 6); | |
| 177 | write32le(buf, s.getPltVA() + 6); | |
| 167 | 178 | } |
| 168 | 179 | |
| 169 | void X86::writeIgotPlt(uint8_t *Buf, const Symbol &S) const { | |
| 180 | void X86::writeIgotPlt(uint8_t *buf, const Symbol &s) const { | |
| 170 | 181 | // An x86 entry is the address of the ifunc resolver function. |
| 171 | write32le(Buf, S.getVA()); | |
| 182 | write32le(buf, s.getVA()); | |
| 172 | 183 | } |
| 173 | 184 | |
| 174 | RelType X86::getDynRel(RelType Type) const { | |
| 175 | if (Type == R_386_TLS_LE) | |
| 185 | RelType X86::getDynRel(RelType type) const { | |
| 186 | if (type == R_386_TLS_LE) | |
| 176 | 187 | return R_386_TLS_TPOFF; |
| 177 | if (Type == R_386_TLS_LE_32) | |
| 188 | if (type == R_386_TLS_LE_32) | |
| 178 | 189 | return R_386_TLS_TPOFF32; |
| 179 | return Type; | |
| 190 | return type; | |
| 180 | 191 | } |
| 181 | 192 | |
| 182 | void X86::writePltHeader(uint8_t *Buf) const { | |
| 183 | if (Config->Pic) { | |
| 184 | const uint8_t V[] = { | |
| 185 | 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl GOTPLT+4(%ebx) | |
| 186 | 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *GOTPLT+8(%ebx) | |
| 193 | void X86::writePltHeader(uint8_t *buf) const { | |
| 194 | if (config->isPic) { | |
| 195 | const uint8_t v[] = { | |
| 196 | 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx) | |
| 197 | 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *8(%ebx) | |
| 187 | 198 | 0x90, 0x90, 0x90, 0x90 // nop |
| 188 | 199 | }; |
| 189 | memcpy(Buf, V, sizeof(V)); | |
| 190 | ||
| 191 | uint32_t Ebx = In.Got->getVA() + In.Got->getSize(); | |
| 192 | uint32_t GotPlt = In.GotPlt->getVA() - Ebx; | |
| 193 | write32le(Buf + 2, GotPlt + 4); | |
| 194 | write32le(Buf + 8, GotPlt + 8); | |
| 200 | memcpy(buf, v, sizeof(v)); | |
| 195 | 201 | return; |
| 196 | 202 | } |
| 197 | 203 | |
| 198 | const uint8_t PltData[] = { | |
| 204 | const uint8_t pltData[] = { | |
| 199 | 205 | 0xff, 0x35, 0, 0, 0, 0, // pushl (GOTPLT+4) |
| 200 | 206 | 0xff, 0x25, 0, 0, 0, 0, // jmp *(GOTPLT+8) |
| 201 | 207 | 0x90, 0x90, 0x90, 0x90, // nop |
| 202 | 208 | }; |
| 203 | memcpy(Buf, PltData, sizeof(PltData)); | |
| 204 | uint32_t GotPlt = In.GotPlt->getVA(); | |
| 205 | write32le(Buf + 2, GotPlt + 4); | |
| 206 | write32le(Buf + 8, GotPlt + 8); | |
| 209 | memcpy(buf, pltData, sizeof(pltData)); | |
| 210 | uint32_t gotPlt = in.gotPlt->getVA(); | |
| 211 | write32le(buf + 2, gotPlt + 4); | |
| 212 | write32le(buf + 8, gotPlt + 8); | |
| 207 | 213 | } |
| 208 | 214 | |
| 209 | void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, | |
| 210 | uint64_t PltEntryAddr, int32_t Index, | |
| 211 | unsigned RelOff) const { | |
| 212 | const uint8_t Inst[] = { | |
| 213 | 0xff, 0x00, 0, 0, 0, 0, // jmp *foo_in_GOT or jmp *foo@GOT(%ebx) | |
| 214 | 0x68, 0, 0, 0, 0, // pushl $reloc_offset | |
| 215 | 0xe9, 0, 0, 0, 0, // jmp .PLT0@PC | |
| 216 | }; | |
| 217 | memcpy(Buf, Inst, sizeof(Inst)); | |
| 218 | ||
| 219 | if (Config->Pic) { | |
| 220 | // jmp *foo@GOT(%ebx) | |
| 221 | uint32_t Ebx = In.Got->getVA() + In.Got->getSize(); | |
| 222 | Buf[1] = 0xa3; | |
| 223 | write32le(Buf + 2, GotPltEntryAddr - Ebx); | |
| 215 | void X86::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, | |
| 216 | uint64_t pltEntryAddr, int32_t index, | |
| 217 | unsigned relOff) const { | |
| 218 | if (config->isPic) { | |
| 219 | const uint8_t inst[] = { | |
| 220 | 0xff, 0xa3, 0, 0, 0, 0, // jmp *foo@GOT(%ebx) | |
| 221 | 0x68, 0, 0, 0, 0, // pushl $reloc_offset | |
| 222 | 0xe9, 0, 0, 0, 0, // jmp .PLT0@PC | |
| 223 | }; | |
| 224 | memcpy(buf, inst, sizeof(inst)); | |
| 225 | write32le(buf + 2, gotPltEntryAddr - in.gotPlt->getVA()); | |
| 224 | 226 | } else { |
| 225 | // jmp *foo_in_GOT | |
| 226 | Buf[1] = 0x25; | |
| 227 | write32le(Buf + 2, GotPltEntryAddr); | |
| 227 | const uint8_t inst[] = { | |
| 228 | 0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT | |
| 229 | 0x68, 0, 0, 0, 0, // pushl $reloc_offset | |
| 230 | 0xe9, 0, 0, 0, 0, // jmp .PLT0@PC | |
| 231 | }; | |
| 232 | memcpy(buf, inst, sizeof(inst)); | |
| 233 | write32le(buf + 2, gotPltEntryAddr); | |
| 228 | 234 | } |
| 229 | 235 | |
| 230 | write32le(Buf + 7, RelOff); | |
| 231 | write32le(Buf + 12, -getPltEntryOffset(Index) - 16); | |
| 236 | write32le(buf + 7, relOff); | |
| 237 | write32le(buf + 12, -pltHeaderSize - pltEntrySize * index - 16); | |
| 232 | 238 | } |
| 233 | 239 | |
| 234 | int64_t X86::getImplicitAddend(const uint8_t *Buf, RelType Type) const { | |
| 235 | switch (Type) { | |
| 240 | int64_t X86::getImplicitAddend(const uint8_t *buf, RelType type) const { | |
| 241 | switch (type) { | |
| 236 | 242 | case R_386_8: |
| 237 | 243 | case R_386_PC8: |
| 238 | return SignExtend64<8>(*Buf); | |
| 244 | return SignExtend64<8>(*buf); | |
| 239 | 245 | case R_386_16: |
| 240 | 246 | case R_386_PC16: |
| 241 | return SignExtend64<16>(read16le(Buf)); | |
| 247 | return SignExtend64<16>(read16le(buf)); | |
| 242 | 248 | case R_386_32: |
| 243 | 249 | case R_386_GOT32: |
| 244 | 250 | case R_386_GOT32X: |
| ... | ... | @@ -248,28 +254,28 @@ int64_t X86::getImplicitAddend(const uint8_t *Buf, RelType Type) const { |
| 248 | 254 | case R_386_PLT32: |
| 249 | 255 | case R_386_TLS_LDO_32: |
| 250 | 256 | case R_386_TLS_LE: |
| 251 | return SignExtend64<32>(read32le(Buf)); | |
| 257 | return SignExtend64<32>(read32le(buf)); | |
| 252 | 258 | default: |
| 253 | 259 | return 0; |
| 254 | 260 | } |
| 255 | 261 | } |
| 256 | 262 | |
| 257 | void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 258 | switch (Type) { | |
| 263 | void X86::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { | |
| 264 | switch (type) { | |
| 259 | 265 | case R_386_8: |
| 260 | 266 | // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are |
| 261 | 267 | // being used for some 16-bit programs such as boot loaders, so |
| 262 | 268 | // we want to support them. |
| 263 | checkIntUInt(Loc, Val, 8, Type); | |
| 264 | *Loc = Val; | |
| 269 | checkIntUInt(loc, val, 8, type); | |
| 270 | *loc = val; | |
| 265 | 271 | break; |
| 266 | 272 | case R_386_PC8: |
| 267 | checkInt(Loc, Val, 8, Type); | |
| 268 | *Loc = Val; | |
| 273 | checkInt(loc, val, 8, type); | |
| 274 | *loc = val; | |
| 269 | 275 | break; |
| 270 | 276 | case R_386_16: |
| 271 | checkIntUInt(Loc, Val, 16, Type); | |
| 272 | write16le(Loc, Val); | |
| 277 | checkIntUInt(loc, val, 16, type); | |
| 278 | write16le(loc, val); | |
| 273 | 279 | break; |
| 274 | 280 | case R_386_PC16: |
| 275 | 281 | // R_386_PC16 is normally used with 16 bit code. In that situation |
| ... | ... | @@ -282,11 +288,10 @@ void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 282 | 288 | // current location subtracted from it. |
| 283 | 289 | // We just check that Val fits in 17 bits. This misses some cases, but |
| 284 | 290 | // should have no false positives. |
| 285 | checkInt(Loc, Val, 17, Type); | |
| 286 | write16le(Loc, Val); | |
| 291 | checkInt(loc, val, 17, type); | |
| 292 | write16le(loc, val); | |
| 287 | 293 | break; |
| 288 | 294 | case R_386_32: |
| 289 | case R_386_GLOB_DAT: | |
| 290 | 295 | case R_386_GOT32: |
| 291 | 296 | case R_386_GOT32X: |
| 292 | 297 | case R_386_GOTOFF: |
| ... | ... | @@ -305,86 +310,86 @@ void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 305 | 310 | case R_386_TLS_LE_32: |
| 306 | 311 | case R_386_TLS_TPOFF: |
| 307 | 312 | case R_386_TLS_TPOFF32: |
| 308 | checkInt(Loc, Val, 32, Type); | |
| 309 | write32le(Loc, Val); | |
| 313 | checkInt(loc, val, 32, type); | |
| 314 | write32le(loc, val); | |
| 310 | 315 | break; |
| 311 | 316 | default: |
| 312 | error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); | |
| 317 | llvm_unreachable("unknown relocation"); | |
| 313 | 318 | } |
| 314 | 319 | } |
| 315 | 320 | |
| 316 | void X86::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 321 | void X86::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 317 | 322 | // Convert |
| 318 | 323 | // leal x@tlsgd(, %ebx, 1), |
| 319 | 324 | // call __tls_get_addr@plt |
| 320 | 325 | // to |
| 321 | 326 | // movl %gs:0,%eax |
| 322 | 327 | // subl $x@ntpoff,%eax |
| 323 | const uint8_t Inst[] = { | |
| 328 | const uint8_t inst[] = { | |
| 324 | 329 | 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax |
| 325 | 330 | 0x81, 0xe8, 0, 0, 0, 0, // subl Val(%ebx), %eax |
| 326 | 331 | }; |
| 327 | memcpy(Loc - 3, Inst, sizeof(Inst)); | |
| 328 | write32le(Loc + 5, Val); | |
| 332 | memcpy(loc - 3, inst, sizeof(inst)); | |
| 333 | write32le(loc + 5, val); | |
| 329 | 334 | } |
| 330 | 335 | |
| 331 | void X86::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 336 | void X86::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 332 | 337 | // Convert |
| 333 | 338 | // leal x@tlsgd(, %ebx, 1), |
| 334 | 339 | // call __tls_get_addr@plt |
| 335 | 340 | // to |
| 336 | 341 | // movl %gs:0, %eax |
| 337 | 342 | // addl x@gotntpoff(%ebx), %eax |
| 338 | const uint8_t Inst[] = { | |
| 343 | const uint8_t inst[] = { | |
| 339 | 344 | 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax |
| 340 | 345 | 0x03, 0x83, 0, 0, 0, 0, // addl Val(%ebx), %eax |
| 341 | 346 | }; |
| 342 | memcpy(Loc - 3, Inst, sizeof(Inst)); | |
| 343 | write32le(Loc + 5, Val); | |
| 347 | memcpy(loc - 3, inst, sizeof(inst)); | |
| 348 | write32le(loc + 5, val); | |
| 344 | 349 | } |
| 345 | 350 | |
| 346 | 351 | // In some conditions, relocations can be optimized to avoid using GOT. |
| 347 | 352 | // This function does that for Initial Exec to Local Exec case. |
| 348 | void X86::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 353 | void X86::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 349 | 354 | // Ulrich's document section 6.2 says that @gotntpoff can |
| 350 | 355 | // be used with MOVL or ADDL instructions. |
| 351 | 356 | // @indntpoff is similar to @gotntpoff, but for use in |
| 352 | 357 | // position dependent code. |
| 353 | uint8_t Reg = (Loc[-1] >> 3) & 7; | |
| 358 | uint8_t reg = (loc[-1] >> 3) & 7; | |
| 354 | 359 | |
| 355 | if (Type == R_386_TLS_IE) { | |
| 356 | if (Loc[-1] == 0xa1) { | |
| 360 | if (type == R_386_TLS_IE) { | |
| 361 | if (loc[-1] == 0xa1) { | |
| 357 | 362 | // "movl foo@indntpoff,%eax" -> "movl $foo,%eax" |
| 358 | 363 | // This case is different from the generic case below because |
| 359 | 364 | // this is a 5 byte instruction while below is 6 bytes. |
| 360 | Loc[-1] = 0xb8; | |
| 361 | } else if (Loc[-2] == 0x8b) { | |
| 365 | loc[-1] = 0xb8; | |
| 366 | } else if (loc[-2] == 0x8b) { | |
| 362 | 367 | // "movl foo@indntpoff,%reg" -> "movl $foo,%reg" |
| 363 | Loc[-2] = 0xc7; | |
| 364 | Loc[-1] = 0xc0 | Reg; | |
| 368 | loc[-2] = 0xc7; | |
| 369 | loc[-1] = 0xc0 | reg; | |
| 365 | 370 | } else { |
| 366 | 371 | // "addl foo@indntpoff,%reg" -> "addl $foo,%reg" |
| 367 | Loc[-2] = 0x81; | |
| 368 | Loc[-1] = 0xc0 | Reg; | |
| 372 | loc[-2] = 0x81; | |
| 373 | loc[-1] = 0xc0 | reg; | |
| 369 | 374 | } |
| 370 | 375 | } else { |
| 371 | assert(Type == R_386_TLS_GOTIE); | |
| 372 | if (Loc[-2] == 0x8b) { | |
| 376 | assert(type == R_386_TLS_GOTIE); | |
| 377 | if (loc[-2] == 0x8b) { | |
| 373 | 378 | // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg" |
| 374 | Loc[-2] = 0xc7; | |
| 375 | Loc[-1] = 0xc0 | Reg; | |
| 379 | loc[-2] = 0xc7; | |
| 380 | loc[-1] = 0xc0 | reg; | |
| 376 | 381 | } else { |
| 377 | 382 | // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg" |
| 378 | Loc[-2] = 0x8d; | |
| 379 | Loc[-1] = 0x80 | (Reg << 3) | Reg; | |
| 383 | loc[-2] = 0x8d; | |
| 384 | loc[-1] = 0x80 | (reg << 3) | reg; | |
| 380 | 385 | } |
| 381 | 386 | } |
| 382 | write32le(Loc, Val); | |
| 387 | write32le(loc, val); | |
| 383 | 388 | } |
| 384 | 389 | |
| 385 | void X86::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 386 | if (Type == R_386_TLS_LDO_32) { | |
| 387 | write32le(Loc, Val); | |
| 390 | void X86::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 391 | if (type == R_386_TLS_LDO_32) { | |
| 392 | write32le(loc, val); | |
| 388 | 393 | return; |
| 389 | 394 | } |
| 390 | 395 | |
| ... | ... | @@ -395,48 +400,48 @@ void X86::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 395 | 400 | // movl %gs:0,%eax |
| 396 | 401 | // nop |
| 397 | 402 | // leal 0(%esi,1),%esi |
| 398 | const uint8_t Inst[] = { | |
| 403 | const uint8_t inst[] = { | |
| 399 | 404 | 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax |
| 400 | 405 | 0x90, // nop |
| 401 | 406 | 0x8d, 0x74, 0x26, 0x00, // leal 0(%esi,1),%esi |
| 402 | 407 | }; |
| 403 | memcpy(Loc - 2, Inst, sizeof(Inst)); | |
| 408 | memcpy(loc - 2, inst, sizeof(inst)); | |
| 404 | 409 | } |
| 405 | 410 | |
| 406 | 411 | namespace { |
| 407 | 412 | class RetpolinePic : public X86 { |
| 408 | 413 | public: |
| 409 | 414 | RetpolinePic(); |
| 410 | void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; | |
| 411 | void writePltHeader(uint8_t *Buf) const override; | |
| 412 | void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, | |
| 413 | int32_t Index, unsigned RelOff) const override; | |
| 415 | void writeGotPlt(uint8_t *buf, const Symbol &s) const override; | |
| 416 | void writePltHeader(uint8_t *buf) const override; | |
| 417 | void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, | |
| 418 | int32_t index, unsigned relOff) const override; | |
| 414 | 419 | }; |
| 415 | 420 | |
| 416 | 421 | class RetpolineNoPic : public X86 { |
| 417 | 422 | public: |
| 418 | 423 | RetpolineNoPic(); |
| 419 | void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; | |
| 420 | void writePltHeader(uint8_t *Buf) const override; | |
| 421 | void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, | |
| 422 | int32_t Index, unsigned RelOff) const override; | |
| 424 | void writeGotPlt(uint8_t *buf, const Symbol &s) const override; | |
| 425 | void writePltHeader(uint8_t *buf) const override; | |
| 426 | void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, | |
| 427 | int32_t index, unsigned relOff) const override; | |
| 423 | 428 | }; |
| 424 | 429 | } // namespace |
| 425 | 430 | |
| 426 | 431 | RetpolinePic::RetpolinePic() { |
| 427 | PltHeaderSize = 48; | |
| 428 | PltEntrySize = 32; | |
| 432 | pltHeaderSize = 48; | |
| 433 | pltEntrySize = 32; | |
| 429 | 434 | } |
| 430 | 435 | |
| 431 | void RetpolinePic::writeGotPlt(uint8_t *Buf, const Symbol &S) const { | |
| 432 | write32le(Buf, S.getPltVA() + 17); | |
| 436 | void RetpolinePic::writeGotPlt(uint8_t *buf, const Symbol &s) const { | |
| 437 | write32le(buf, s.getPltVA() + 17); | |
| 433 | 438 | } |
| 434 | 439 | |
| 435 | void RetpolinePic::writePltHeader(uint8_t *Buf) const { | |
| 436 | const uint8_t Insn[] = { | |
| 437 | 0xff, 0xb3, 0, 0, 0, 0, // 0: pushl GOTPLT+4(%ebx) | |
| 440 | void RetpolinePic::writePltHeader(uint8_t *buf) const { | |
| 441 | const uint8_t insn[] = { | |
| 442 | 0xff, 0xb3, 4, 0, 0, 0, // 0: pushl 4(%ebx) | |
| 438 | 443 | 0x50, // 6: pushl %eax |
| 439 | 0x8b, 0x83, 0, 0, 0, 0, // 7: mov GOTPLT+8(%ebx), %eax | |
| 444 | 0x8b, 0x83, 8, 0, 0, 0, // 7: mov 8(%ebx), %eax | |
| 440 | 445 | 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: call next |
| 441 | 446 | 0xf3, 0x90, // 12: loop: pause |
| 442 | 447 | 0x0f, 0xae, 0xe8, // 14: lfence |
| ... | ... | @@ -450,18 +455,13 @@ void RetpolinePic::writePltHeader(uint8_t *Buf) const { |
| 450 | 455 | 0xc3, // 2e: ret |
| 451 | 456 | 0xcc, // 2f: int3; padding |
| 452 | 457 | }; |
| 453 | memcpy(Buf, Insn, sizeof(Insn)); | |
| 454 | ||
| 455 | uint32_t Ebx = In.Got->getVA() + In.Got->getSize(); | |
| 456 | uint32_t GotPlt = In.GotPlt->getVA() - Ebx; | |
| 457 | write32le(Buf + 2, GotPlt + 4); | |
| 458 | write32le(Buf + 9, GotPlt + 8); | |
| 458 | memcpy(buf, insn, sizeof(insn)); | |
| 459 | 459 | } |
| 460 | 460 | |
| 461 | void RetpolinePic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, | |
| 462 | uint64_t PltEntryAddr, int32_t Index, | |
| 463 | unsigned RelOff) const { | |
| 464 | const uint8_t Insn[] = { | |
| 461 | void RetpolinePic::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, | |
| 462 | uint64_t pltEntryAddr, int32_t index, | |
| 463 | unsigned relOff) const { | |
| 464 | const uint8_t insn[] = { | |
| 465 | 465 | 0x50, // pushl %eax |
| 466 | 466 | 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax |
| 467 | 467 | 0xe8, 0, 0, 0, 0, // call plt+0x20 |
| ... | ... | @@ -470,28 +470,28 @@ void RetpolinePic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, |
| 470 | 470 | 0xe9, 0, 0, 0, 0, // jmp plt+0 |
| 471 | 471 | 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding |
| 472 | 472 | }; |
| 473 | memcpy(Buf, Insn, sizeof(Insn)); | |
| 474 | ||
| 475 | uint32_t Ebx = In.Got->getVA() + In.Got->getSize(); | |
| 476 | unsigned Off = getPltEntryOffset(Index); | |
| 477 | write32le(Buf + 3, GotPltEntryAddr - Ebx); | |
| 478 | write32le(Buf + 8, -Off - 12 + 32); | |
| 479 | write32le(Buf + 13, -Off - 17 + 18); | |
| 480 | write32le(Buf + 18, RelOff); | |
| 481 | write32le(Buf + 23, -Off - 27); | |
| 473 | memcpy(buf, insn, sizeof(insn)); | |
| 474 | ||
| 475 | uint32_t ebx = in.gotPlt->getVA(); | |
| 476 | unsigned off = pltHeaderSize + pltEntrySize * index; | |
| 477 | write32le(buf + 3, gotPltEntryAddr - ebx); | |
| 478 | write32le(buf + 8, -off - 12 + 32); | |
| 479 | write32le(buf + 13, -off - 17 + 18); | |
| 480 | write32le(buf + 18, relOff); | |
| 481 | write32le(buf + 23, -off - 27); | |
| 482 | 482 | } |
| 483 | 483 | |
| 484 | 484 | RetpolineNoPic::RetpolineNoPic() { |
| 485 | PltHeaderSize = 48; | |
| 486 | PltEntrySize = 32; | |
| 485 | pltHeaderSize = 48; | |
| 486 | pltEntrySize = 32; | |
| 487 | 487 | } |
| 488 | 488 | |
| 489 | void RetpolineNoPic::writeGotPlt(uint8_t *Buf, const Symbol &S) const { | |
| 490 | write32le(Buf, S.getPltVA() + 16); | |
| 489 | void RetpolineNoPic::writeGotPlt(uint8_t *buf, const Symbol &s) const { | |
| 490 | write32le(buf, s.getPltVA() + 16); | |
| 491 | 491 | } |
| 492 | 492 | |
| 493 | void RetpolineNoPic::writePltHeader(uint8_t *Buf) const { | |
| 494 | const uint8_t Insn[] = { | |
| 493 | void RetpolineNoPic::writePltHeader(uint8_t *buf) const { | |
| 494 | const uint8_t insn[] = { | |
| 495 | 495 | 0xff, 0x35, 0, 0, 0, 0, // 0: pushl GOTPLT+4 |
| 496 | 496 | 0x50, // 6: pushl %eax |
| 497 | 497 | 0xa1, 0, 0, 0, 0, // 7: mov GOTPLT+8, %eax |
| ... | ... | @@ -509,17 +509,17 @@ void RetpolineNoPic::writePltHeader(uint8_t *Buf) const { |
| 509 | 509 | 0xc3, // 2e: ret |
| 510 | 510 | 0xcc, // 2f: int3; padding |
| 511 | 511 | }; |
| 512 | memcpy(Buf, Insn, sizeof(Insn)); | |
| 512 | memcpy(buf, insn, sizeof(insn)); | |
| 513 | 513 | |
| 514 | uint32_t GotPlt = In.GotPlt->getVA(); | |
| 515 | write32le(Buf + 2, GotPlt + 4); | |
| 516 | write32le(Buf + 8, GotPlt + 8); | |
| 514 | uint32_t gotPlt = in.gotPlt->getVA(); | |
| 515 | write32le(buf + 2, gotPlt + 4); | |
| 516 | write32le(buf + 8, gotPlt + 8); | |
| 517 | 517 | } |
| 518 | 518 | |
| 519 | void RetpolineNoPic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, | |
| 520 | uint64_t PltEntryAddr, int32_t Index, | |
| 521 | unsigned RelOff) const { | |
| 522 | const uint8_t Insn[] = { | |
| 519 | void RetpolineNoPic::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, | |
| 520 | uint64_t pltEntryAddr, int32_t index, | |
| 521 | unsigned relOff) const { | |
| 522 | const uint8_t insn[] = { | |
| 523 | 523 | 0x50, // 0: pushl %eax |
| 524 | 524 | 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax |
| 525 | 525 | 0xe8, 0, 0, 0, 0, // 6: call plt+0x20 |
| ... | ... | @@ -529,26 +529,26 @@ void RetpolineNoPic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, |
| 529 | 529 | 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding |
| 530 | 530 | 0xcc, // 1f: int3; padding |
| 531 | 531 | }; |
| 532 | memcpy(Buf, Insn, sizeof(Insn)); | |
| 533 | ||
| 534 | unsigned Off = getPltEntryOffset(Index); | |
| 535 | write32le(Buf + 2, GotPltEntryAddr); | |
| 536 | write32le(Buf + 7, -Off - 11 + 32); | |
| 537 | write32le(Buf + 12, -Off - 16 + 17); | |
| 538 | write32le(Buf + 17, RelOff); | |
| 539 | write32le(Buf + 22, -Off - 26); | |
| 532 | memcpy(buf, insn, sizeof(insn)); | |
| 533 | ||
| 534 | unsigned off = pltHeaderSize + pltEntrySize * index; | |
| 535 | write32le(buf + 2, gotPltEntryAddr); | |
| 536 | write32le(buf + 7, -off - 11 + 32); | |
| 537 | write32le(buf + 12, -off - 16 + 17); | |
| 538 | write32le(buf + 17, relOff); | |
| 539 | write32le(buf + 22, -off - 26); | |
| 540 | 540 | } |
| 541 | 541 | |
| 542 | 542 | TargetInfo *elf::getX86TargetInfo() { |
| 543 | if (Config->ZRetpolineplt) { | |
| 544 | if (Config->Pic) { | |
| 545 | static RetpolinePic T; | |
| 546 | return &T; | |
| 543 | if (config->zRetpolineplt) { | |
| 544 | if (config->isPic) { | |
| 545 | static RetpolinePic t; | |
| 546 | return &t; | |
| 547 | 547 | } |
| 548 | static RetpolineNoPic T; | |
| 549 | return &T; | |
| 548 | static RetpolineNoPic t; | |
| 549 | return &t; | |
| 550 | 550 | } |
| 551 | 551 | |
| 552 | static X86 T; | |
| 553 | return &T; | |
| 552 | static X86 t; | |
| 553 | return &t; | |
| 554 | 554 | } |
deps/lld/ELF/Arch/X86_64.cpp+323-299| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- X86_64.cpp ---------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -23,71 +22,74 @@ using namespace lld; |
| 23 | 22 | using namespace lld::elf; |
| 24 | 23 | |
| 25 | 24 | namespace { |
| 26 | template <class ELFT> class X86_64 : public TargetInfo { | |
| 25 | class X86_64 : public TargetInfo { | |
| 27 | 26 | public: |
| 28 | 27 | X86_64(); |
| 29 | RelExpr getRelExpr(RelType Type, const Symbol &S, | |
| 30 | const uint8_t *Loc) const override; | |
| 31 | RelType getDynRel(RelType Type) const override; | |
| 32 | void writeGotPltHeader(uint8_t *Buf) const override; | |
| 33 | void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; | |
| 34 | void writePltHeader(uint8_t *Buf) const override; | |
| 35 | void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, | |
| 36 | int32_t Index, unsigned RelOff) const override; | |
| 37 | void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 38 | ||
| 39 | RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, | |
| 40 | RelExpr Expr) const override; | |
| 41 | void relaxGot(uint8_t *Loc, uint64_t Val) const override; | |
| 42 | void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 43 | void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 44 | void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 45 | void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; | |
| 46 | bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End, | |
| 47 | uint8_t StOther) const override; | |
| 48 | ||
| 49 | private: | |
| 50 | void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, | |
| 51 | uint8_t ModRm) const; | |
| 28 | int getTlsGdRelaxSkip(RelType type) const override; | |
| 29 | RelExpr getRelExpr(RelType type, const Symbol &s, | |
| 30 | const uint8_t *loc) const override; | |
| 31 | RelType getDynRel(RelType type) const override; | |
| 32 | void writeGotPltHeader(uint8_t *buf) const override; | |
| 33 | void writeGotPlt(uint8_t *buf, const Symbol &s) const override; | |
| 34 | void writePltHeader(uint8_t *buf) const override; | |
| 35 | void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, | |
| 36 | int32_t index, unsigned relOff) const override; | |
| 37 | void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 38 | ||
| 39 | RelExpr adjustRelaxExpr(RelType type, const uint8_t *data, | |
| 40 | RelExpr expr) const override; | |
| 41 | void relaxGot(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 42 | void relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 43 | void relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 44 | void relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 45 | void relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const override; | |
| 46 | bool adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end, | |
| 47 | uint8_t stOther) const override; | |
| 52 | 48 | }; |
| 53 | 49 | } // namespace |
| 54 | 50 | |
| 55 | template <class ELFT> X86_64<ELFT>::X86_64() { | |
| 56 | CopyRel = R_X86_64_COPY; | |
| 57 | GotRel = R_X86_64_GLOB_DAT; | |
| 58 | NoneRel = R_X86_64_NONE; | |
| 59 | PltRel = R_X86_64_JUMP_SLOT; | |
| 60 | RelativeRel = R_X86_64_RELATIVE; | |
| 61 | IRelativeRel = R_X86_64_IRELATIVE; | |
| 62 | TlsGotRel = R_X86_64_TPOFF64; | |
| 63 | TlsModuleIndexRel = R_X86_64_DTPMOD64; | |
| 64 | TlsOffsetRel = R_X86_64_DTPOFF64; | |
| 65 | GotEntrySize = 8; | |
| 66 | GotPltEntrySize = 8; | |
| 67 | PltEntrySize = 16; | |
| 68 | PltHeaderSize = 16; | |
| 69 | TlsGdRelaxSkip = 2; | |
| 70 | TrapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3 | |
| 51 | X86_64::X86_64() { | |
| 52 | copyRel = R_X86_64_COPY; | |
| 53 | gotRel = R_X86_64_GLOB_DAT; | |
| 54 | noneRel = R_X86_64_NONE; | |
| 55 | pltRel = R_X86_64_JUMP_SLOT; | |
| 56 | relativeRel = R_X86_64_RELATIVE; | |
| 57 | iRelativeRel = R_X86_64_IRELATIVE; | |
| 58 | symbolicRel = R_X86_64_64; | |
| 59 | tlsDescRel = R_X86_64_TLSDESC; | |
| 60 | tlsGotRel = R_X86_64_TPOFF64; | |
| 61 | tlsModuleIndexRel = R_X86_64_DTPMOD64; | |
| 62 | tlsOffsetRel = R_X86_64_DTPOFF64; | |
| 63 | pltEntrySize = 16; | |
| 64 | pltHeaderSize = 16; | |
| 65 | trapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3 | |
| 71 | 66 | |
| 72 | 67 | // Align to the large page size (known as a superpage or huge page). |
| 73 | 68 | // FreeBSD automatically promotes large, superpage-aligned allocations. |
| 74 | DefaultImageBase = 0x200000; | |
| 69 | defaultImageBase = 0x200000; | |
| 75 | 70 | } |
| 76 | 71 | |
| 77 | template <class ELFT> | |
| 78 | RelExpr X86_64<ELFT>::getRelExpr(RelType Type, const Symbol &S, | |
| 79 | const uint8_t *Loc) const { | |
| 80 | switch (Type) { | |
| 72 | int X86_64::getTlsGdRelaxSkip(RelType type) const { return 2; } | |
| 73 | ||
| 74 | RelExpr X86_64::getRelExpr(RelType type, const Symbol &s, | |
| 75 | const uint8_t *loc) const { | |
| 76 | if (type == R_X86_64_GOTTPOFF) | |
| 77 | config->hasStaticTlsModel = true; | |
| 78 | ||
| 79 | switch (type) { | |
| 81 | 80 | case R_X86_64_8: |
| 82 | 81 | case R_X86_64_16: |
| 83 | 82 | case R_X86_64_32: |
| 84 | 83 | case R_X86_64_32S: |
| 85 | 84 | case R_X86_64_64: |
| 85 | return R_ABS; | |
| 86 | 86 | case R_X86_64_DTPOFF32: |
| 87 | 87 | case R_X86_64_DTPOFF64: |
| 88 | return R_ABS; | |
| 88 | return R_DTPREL; | |
| 89 | 89 | case R_X86_64_TPOFF32: |
| 90 | 90 | return R_TLS; |
| 91 | case R_X86_64_TLSDESC_CALL: | |
| 92 | return R_TLSDESC_CALL; | |
| 91 | 93 | case R_X86_64_TLSLD: |
| 92 | 94 | return R_TLSLD_PC; |
| 93 | 95 | case R_X86_64_TLSGD: |
| ... | ... | @@ -97,189 +99,222 @@ RelExpr X86_64<ELFT>::getRelExpr(RelType Type, const Symbol &S, |
| 97 | 99 | return R_SIZE; |
| 98 | 100 | case R_X86_64_PLT32: |
| 99 | 101 | return R_PLT_PC; |
| 102 | case R_X86_64_PC8: | |
| 103 | case R_X86_64_PC16: | |
| 100 | 104 | case R_X86_64_PC32: |
| 101 | 105 | case R_X86_64_PC64: |
| 102 | 106 | return R_PC; |
| 103 | 107 | case R_X86_64_GOT32: |
| 104 | 108 | case R_X86_64_GOT64: |
| 105 | return R_GOT_FROM_END; | |
| 109 | return R_GOTPLT; | |
| 110 | case R_X86_64_GOTPC32_TLSDESC: | |
| 111 | return R_TLSDESC_PC; | |
| 106 | 112 | case R_X86_64_GOTPCREL: |
| 107 | 113 | case R_X86_64_GOTPCRELX: |
| 108 | 114 | case R_X86_64_REX_GOTPCRELX: |
| 109 | 115 | case R_X86_64_GOTTPOFF: |
| 110 | 116 | return R_GOT_PC; |
| 111 | 117 | case R_X86_64_GOTOFF64: |
| 112 | return R_GOTREL_FROM_END; | |
| 118 | return R_GOTPLTREL; | |
| 113 | 119 | case R_X86_64_GOTPC32: |
| 114 | 120 | case R_X86_64_GOTPC64: |
| 115 | return R_GOTONLY_PC_FROM_END; | |
| 121 | return R_GOTPLTONLY_PC; | |
| 116 | 122 | case R_X86_64_NONE: |
| 117 | 123 | return R_NONE; |
| 118 | 124 | default: |
| 119 | return R_INVALID; | |
| 125 | error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + | |
| 126 | ") against symbol " + toString(s)); | |
| 127 | return R_NONE; | |
| 120 | 128 | } |
| 121 | 129 | } |
| 122 | 130 | |
| 123 | template <class ELFT> void X86_64<ELFT>::writeGotPltHeader(uint8_t *Buf) const { | |
| 131 | void X86_64::writeGotPltHeader(uint8_t *buf) const { | |
| 124 | 132 | // The first entry holds the value of _DYNAMIC. It is not clear why that is |
| 125 | 133 | // required, but it is documented in the psabi and the glibc dynamic linker |
| 126 | 134 | // seems to use it (note that this is relevant for linking ld.so, not any |
| 127 | 135 | // other program). |
| 128 | write64le(Buf, In.Dynamic->getVA()); | |
| 136 | write64le(buf, mainPart->dynamic->getVA()); | |
| 129 | 137 | } |
| 130 | 138 | |
| 131 | template <class ELFT> | |
| 132 | void X86_64<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &S) const { | |
| 139 | void X86_64::writeGotPlt(uint8_t *buf, const Symbol &s) const { | |
| 133 | 140 | // See comments in X86::writeGotPlt. |
| 134 | write64le(Buf, S.getPltVA() + 6); | |
| 141 | write64le(buf, s.getPltVA() + 6); | |
| 135 | 142 | } |
| 136 | 143 | |
| 137 | template <class ELFT> void X86_64<ELFT>::writePltHeader(uint8_t *Buf) const { | |
| 138 | const uint8_t PltData[] = { | |
| 144 | void X86_64::writePltHeader(uint8_t *buf) const { | |
| 145 | const uint8_t pltData[] = { | |
| 139 | 146 | 0xff, 0x35, 0, 0, 0, 0, // pushq GOTPLT+8(%rip) |
| 140 | 147 | 0xff, 0x25, 0, 0, 0, 0, // jmp *GOTPLT+16(%rip) |
| 141 | 148 | 0x0f, 0x1f, 0x40, 0x00, // nop |
| 142 | 149 | }; |
| 143 | memcpy(Buf, PltData, sizeof(PltData)); | |
| 144 | uint64_t GotPlt = In.GotPlt->getVA(); | |
| 145 | uint64_t Plt = In.Plt->getVA(); | |
| 146 | write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8 | |
| 147 | write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16 | |
| 150 | memcpy(buf, pltData, sizeof(pltData)); | |
| 151 | uint64_t gotPlt = in.gotPlt->getVA(); | |
| 152 | uint64_t plt = in.plt->getVA(); | |
| 153 | write32le(buf + 2, gotPlt - plt + 2); // GOTPLT+8 | |
| 154 | write32le(buf + 8, gotPlt - plt + 4); // GOTPLT+16 | |
| 148 | 155 | } |
| 149 | 156 | |
| 150 | template <class ELFT> | |
| 151 | void X86_64<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, | |
| 152 | uint64_t PltEntryAddr, int32_t Index, | |
| 153 | unsigned RelOff) const { | |
| 154 | const uint8_t Inst[] = { | |
| 157 | void X86_64::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, | |
| 158 | uint64_t pltEntryAddr, int32_t index, | |
| 159 | unsigned relOff) const { | |
| 160 | const uint8_t inst[] = { | |
| 155 | 161 | 0xff, 0x25, 0, 0, 0, 0, // jmpq *got(%rip) |
| 156 | 162 | 0x68, 0, 0, 0, 0, // pushq <relocation index> |
| 157 | 163 | 0xe9, 0, 0, 0, 0, // jmpq plt[0] |
| 158 | 164 | }; |
| 159 | memcpy(Buf, Inst, sizeof(Inst)); | |
| 165 | memcpy(buf, inst, sizeof(inst)); | |
| 160 | 166 | |
| 161 | write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6); | |
| 162 | write32le(Buf + 7, Index); | |
| 163 | write32le(Buf + 12, -getPltEntryOffset(Index) - 16); | |
| 167 | write32le(buf + 2, gotPltEntryAddr - pltEntryAddr - 6); | |
| 168 | write32le(buf + 7, index); | |
| 169 | write32le(buf + 12, -pltHeaderSize - pltEntrySize * index - 16); | |
| 164 | 170 | } |
| 165 | 171 | |
| 166 | template <class ELFT> RelType X86_64<ELFT>::getDynRel(RelType Type) const { | |
| 167 | if (Type == R_X86_64_64 || Type == R_X86_64_PC64 || Type == R_X86_64_SIZE32 || | |
| 168 | Type == R_X86_64_SIZE64) | |
| 169 | return Type; | |
| 172 | RelType X86_64::getDynRel(RelType type) const { | |
| 173 | if (type == R_X86_64_64 || type == R_X86_64_PC64 || type == R_X86_64_SIZE32 || | |
| 174 | type == R_X86_64_SIZE64) | |
| 175 | return type; | |
| 170 | 176 | return R_X86_64_NONE; |
| 171 | 177 | } |
| 172 | 178 | |
| 173 | template <class ELFT> | |
| 174 | void X86_64<ELFT>::relaxTlsGdToLe(uint8_t *Loc, RelType Type, | |
| 175 | uint64_t Val) const { | |
| 176 | // Convert | |
| 177 | // .byte 0x66 | |
| 178 | // leaq x@tlsgd(%rip), %rdi | |
| 179 | // .word 0x6666 | |
| 180 | // rex64 | |
| 181 | // call __tls_get_addr@plt | |
| 182 | // to | |
| 183 | // mov %fs:0x0,%rax | |
| 184 | // lea x@tpoff,%rax | |
| 185 | const uint8_t Inst[] = { | |
| 186 | 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax | |
| 187 | 0x48, 0x8d, 0x80, 0, 0, 0, 0, // lea x@tpoff,%rax | |
| 188 | }; | |
| 189 | memcpy(Loc - 4, Inst, sizeof(Inst)); | |
| 190 | ||
| 191 | // The original code used a pc relative relocation and so we have to | |
| 192 | // compensate for the -4 in had in the addend. | |
| 193 | write32le(Loc + 8, Val + 4); | |
| 179 | void X86_64::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 180 | if (type == R_X86_64_TLSGD) { | |
| 181 | // Convert | |
| 182 | // .byte 0x66 | |
| 183 | // leaq x@tlsgd(%rip), %rdi | |
| 184 | // .word 0x6666 | |
| 185 | // rex64 | |
| 186 | // call __tls_get_addr@plt | |
| 187 | // to the following two instructions. | |
| 188 | const uint8_t inst[] = { | |
| 189 | 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, | |
| 190 | 0x00, 0x00, // mov %fs:0x0,%rax | |
| 191 | 0x48, 0x8d, 0x80, 0, 0, 0, 0, // lea x@tpoff,%rax | |
| 192 | }; | |
| 193 | memcpy(loc - 4, inst, sizeof(inst)); | |
| 194 | ||
| 195 | // The original code used a pc relative relocation and so we have to | |
| 196 | // compensate for the -4 in had in the addend. | |
| 197 | write32le(loc + 8, val + 4); | |
| 198 | } else { | |
| 199 | // Convert | |
| 200 | // lea x@tlsgd(%rip), %rax | |
| 201 | // call *(%rax) | |
| 202 | // to the following two instructions. | |
| 203 | assert(type == R_X86_64_GOTPC32_TLSDESC); | |
| 204 | if (memcmp(loc - 3, "\x48\x8d\x05", 3)) { | |
| 205 | error(getErrorLocation(loc - 3) + "R_X86_64_GOTPC32_TLSDESC must be used " | |
| 206 | "in callq *x@tlsdesc(%rip), %rax"); | |
| 207 | return; | |
| 208 | } | |
| 209 | // movq $x@tpoff(%rip),%rax | |
| 210 | loc[-2] = 0xc7; | |
| 211 | loc[-1] = 0xc0; | |
| 212 | write32le(loc, val + 4); | |
| 213 | // xchg ax,ax | |
| 214 | loc[4] = 0x66; | |
| 215 | loc[5] = 0x90; | |
| 216 | } | |
| 194 | 217 | } |
| 195 | 218 | |
| 196 | template <class ELFT> | |
| 197 | void X86_64<ELFT>::relaxTlsGdToIe(uint8_t *Loc, RelType Type, | |
| 198 | uint64_t Val) const { | |
| 199 | // Convert | |
| 200 | // .byte 0x66 | |
| 201 | // leaq x@tlsgd(%rip), %rdi | |
| 202 | // .word 0x6666 | |
| 203 | // rex64 | |
| 204 | // call __tls_get_addr@plt | |
| 205 | // to | |
| 206 | // mov %fs:0x0,%rax | |
| 207 | // addq x@tpoff,%rax | |
| 208 | const uint8_t Inst[] = { | |
| 209 | 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax | |
| 210 | 0x48, 0x03, 0x05, 0, 0, 0, 0, // addq x@tpoff,%rax | |
| 211 | }; | |
| 212 | memcpy(Loc - 4, Inst, sizeof(Inst)); | |
| 213 | ||
| 214 | // Both code sequences are PC relatives, but since we are moving the constant | |
| 215 | // forward by 8 bytes we have to subtract the value by 8. | |
| 216 | write32le(Loc + 8, Val - 8); | |
| 219 | void X86_64::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 220 | if (type == R_X86_64_TLSGD) { | |
| 221 | // Convert | |
| 222 | // .byte 0x66 | |
| 223 | // leaq x@tlsgd(%rip), %rdi | |
| 224 | // .word 0x6666 | |
| 225 | // rex64 | |
| 226 | // call __tls_get_addr@plt | |
| 227 | // to the following two instructions. | |
| 228 | const uint8_t inst[] = { | |
| 229 | 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, | |
| 230 | 0x00, 0x00, // mov %fs:0x0,%rax | |
| 231 | 0x48, 0x03, 0x05, 0, 0, 0, 0, // addq x@gottpoff(%rip),%rax | |
| 232 | }; | |
| 233 | memcpy(loc - 4, inst, sizeof(inst)); | |
| 234 | ||
| 235 | // Both code sequences are PC relatives, but since we are moving the | |
| 236 | // constant forward by 8 bytes we have to subtract the value by 8. | |
| 237 | write32le(loc + 8, val - 8); | |
| 238 | } else { | |
| 239 | // Convert | |
| 240 | // lea x@tlsgd(%rip), %rax | |
| 241 | // call *(%rax) | |
| 242 | // to the following two instructions. | |
| 243 | assert(type == R_X86_64_GOTPC32_TLSDESC); | |
| 244 | if (memcmp(loc - 3, "\x48\x8d\x05", 3)) { | |
| 245 | error(getErrorLocation(loc - 3) + "R_X86_64_GOTPC32_TLSDESC must be used " | |
| 246 | "in callq *x@tlsdesc(%rip), %rax"); | |
| 247 | return; | |
| 248 | } | |
| 249 | // movq x@gottpoff(%rip),%rax | |
| 250 | loc[-2] = 0x8b; | |
| 251 | write32le(loc, val); | |
| 252 | // xchg ax,ax | |
| 253 | loc[4] = 0x66; | |
| 254 | loc[5] = 0x90; | |
| 255 | } | |
| 217 | 256 | } |
| 218 | 257 | |
| 219 | 258 | // In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to |
| 220 | 259 | // R_X86_64_TPOFF32 so that it does not use GOT. |
| 221 | template <class ELFT> | |
| 222 | void X86_64<ELFT>::relaxTlsIeToLe(uint8_t *Loc, RelType Type, | |
| 223 | uint64_t Val) const { | |
| 224 | uint8_t *Inst = Loc - 3; | |
| 225 | uint8_t Reg = Loc[-1] >> 3; | |
| 226 | uint8_t *RegSlot = Loc - 1; | |
| 260 | void X86_64::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 261 | uint8_t *inst = loc - 3; | |
| 262 | uint8_t reg = loc[-1] >> 3; | |
| 263 | uint8_t *regSlot = loc - 1; | |
| 227 | 264 | |
| 228 | 265 | // Note that ADD with RSP or R12 is converted to ADD instead of LEA |
| 229 | 266 | // because LEA with these registers needs 4 bytes to encode and thus |
| 230 | 267 | // wouldn't fit the space. |
| 231 | 268 | |
| 232 | if (memcmp(Inst, "\x48\x03\x25", 3) == 0) { | |
| 269 | if (memcmp(inst, "\x48\x03\x25", 3) == 0) { | |
| 233 | 270 | // "addq foo@gottpoff(%rip),%rsp" -> "addq $foo,%rsp" |
| 234 | memcpy(Inst, "\x48\x81\xc4", 3); | |
| 235 | } else if (memcmp(Inst, "\x4c\x03\x25", 3) == 0) { | |
| 271 | memcpy(inst, "\x48\x81\xc4", 3); | |
| 272 | } else if (memcmp(inst, "\x4c\x03\x25", 3) == 0) { | |
| 236 | 273 | // "addq foo@gottpoff(%rip),%r12" -> "addq $foo,%r12" |
| 237 | memcpy(Inst, "\x49\x81\xc4", 3); | |
| 238 | } else if (memcmp(Inst, "\x4c\x03", 2) == 0) { | |
| 274 | memcpy(inst, "\x49\x81\xc4", 3); | |
| 275 | } else if (memcmp(inst, "\x4c\x03", 2) == 0) { | |
| 239 | 276 | // "addq foo@gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]" |
| 240 | memcpy(Inst, "\x4d\x8d", 2); | |
| 241 | *RegSlot = 0x80 | (Reg << 3) | Reg; | |
| 242 | } else if (memcmp(Inst, "\x48\x03", 2) == 0) { | |
| 277 | memcpy(inst, "\x4d\x8d", 2); | |
| 278 | *regSlot = 0x80 | (reg << 3) | reg; | |
| 279 | } else if (memcmp(inst, "\x48\x03", 2) == 0) { | |
| 243 | 280 | // "addq foo@gottpoff(%rip),%reg -> "leaq foo(%reg),%reg" |
| 244 | memcpy(Inst, "\x48\x8d", 2); | |
| 245 | *RegSlot = 0x80 | (Reg << 3) | Reg; | |
| 246 | } else if (memcmp(Inst, "\x4c\x8b", 2) == 0) { | |
| 281 | memcpy(inst, "\x48\x8d", 2); | |
| 282 | *regSlot = 0x80 | (reg << 3) | reg; | |
| 283 | } else if (memcmp(inst, "\x4c\x8b", 2) == 0) { | |
| 247 | 284 | // "movq foo@gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]" |
| 248 | memcpy(Inst, "\x49\xc7", 2); | |
| 249 | *RegSlot = 0xc0 | Reg; | |
| 250 | } else if (memcmp(Inst, "\x48\x8b", 2) == 0) { | |
| 285 | memcpy(inst, "\x49\xc7", 2); | |
| 286 | *regSlot = 0xc0 | reg; | |
| 287 | } else if (memcmp(inst, "\x48\x8b", 2) == 0) { | |
| 251 | 288 | // "movq foo@gottpoff(%rip),%reg" -> "movq $foo,%reg" |
| 252 | memcpy(Inst, "\x48\xc7", 2); | |
| 253 | *RegSlot = 0xc0 | Reg; | |
| 289 | memcpy(inst, "\x48\xc7", 2); | |
| 290 | *regSlot = 0xc0 | reg; | |
| 254 | 291 | } else { |
| 255 | error(getErrorLocation(Loc - 3) + | |
| 292 | error(getErrorLocation(loc - 3) + | |
| 256 | 293 | "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only"); |
| 257 | 294 | } |
| 258 | 295 | |
| 259 | 296 | // The original code used a PC relative relocation. |
| 260 | 297 | // Need to compensate for the -4 it had in the addend. |
| 261 | write32le(Loc, Val + 4); | |
| 298 | write32le(loc, val + 4); | |
| 262 | 299 | } |
| 263 | 300 | |
| 264 | template <class ELFT> | |
| 265 | void X86_64<ELFT>::relaxTlsLdToLe(uint8_t *Loc, RelType Type, | |
| 266 | uint64_t Val) const { | |
| 267 | if (Type == R_X86_64_DTPOFF64) { | |
| 268 | write64le(Loc, Val); | |
| 301 | void X86_64::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { | |
| 302 | if (type == R_X86_64_DTPOFF64) { | |
| 303 | write64le(loc, val); | |
| 269 | 304 | return; |
| 270 | 305 | } |
| 271 | if (Type == R_X86_64_DTPOFF32) { | |
| 272 | write32le(Loc, Val); | |
| 306 | if (type == R_X86_64_DTPOFF32) { | |
| 307 | write32le(loc, val); | |
| 273 | 308 | return; |
| 274 | 309 | } |
| 275 | 310 | |
| 276 | const uint8_t Inst[] = { | |
| 311 | const uint8_t inst[] = { | |
| 277 | 312 | 0x66, 0x66, // .word 0x6666 |
| 278 | 313 | 0x66, // .byte 0x66 |
| 279 | 314 | 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0,%rax |
| 280 | 315 | }; |
| 281 | 316 | |
| 282 | if (Loc[4] == 0xe8) { | |
| 317 | if (loc[4] == 0xe8) { | |
| 283 | 318 | // Convert |
| 284 | 319 | // leaq bar@tlsld(%rip), %rdi # 48 8d 3d <Loc> |
| 285 | 320 | // callq __tls_get_addr@PLT # e8 <disp32> |
| ... | ... | @@ -289,11 +324,11 @@ void X86_64<ELFT>::relaxTlsLdToLe(uint8_t *Loc, RelType Type, |
| 289 | 324 | // .byte 0x66 |
| 290 | 325 | // mov %fs:0,%rax |
| 291 | 326 | // leaq bar@tpoff(%rax), %rcx |
| 292 | memcpy(Loc - 3, Inst, sizeof(Inst)); | |
| 327 | memcpy(loc - 3, inst, sizeof(inst)); | |
| 293 | 328 | return; |
| 294 | 329 | } |
| 295 | 330 | |
| 296 | if (Loc[4] == 0xff && Loc[5] == 0x15) { | |
| 331 | if (loc[4] == 0xff && loc[5] == 0x15) { | |
| 297 | 332 | // Convert |
| 298 | 333 | // leaq x@tlsld(%rip),%rdi # 48 8d 3d <Loc> |
| 299 | 334 | // call *__tls_get_addr@GOTPCREL(%rip) # ff 15 <disp32> |
| ... | ... | @@ -302,34 +337,42 @@ void X86_64<ELFT>::relaxTlsLdToLe(uint8_t *Loc, RelType Type, |
| 302 | 337 | // movq %fs:0,%rax |
| 303 | 338 | // See "Table 11.9: LD -> LE Code Transition (LP64)" in |
| 304 | 339 | // https://raw.githubusercontent.com/wiki/hjl-tools/x86-psABI/x86-64-psABI-1.0.pdf |
| 305 | Loc[-3] = 0x66; | |
| 306 | memcpy(Loc - 2, Inst, sizeof(Inst)); | |
| 340 | loc[-3] = 0x66; | |
| 341 | memcpy(loc - 2, inst, sizeof(inst)); | |
| 307 | 342 | return; |
| 308 | 343 | } |
| 309 | 344 | |
| 310 | error(getErrorLocation(Loc - 3) + | |
| 345 | error(getErrorLocation(loc - 3) + | |
| 311 | 346 | "expected R_X86_64_PLT32 or R_X86_64_GOTPCRELX after R_X86_64_TLSLD"); |
| 312 | 347 | } |
| 313 | 348 | |
| 314 | template <class ELFT> | |
| 315 | void X86_64<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { | |
| 316 | switch (Type) { | |
| 349 | void X86_64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { | |
| 350 | switch (type) { | |
| 317 | 351 | case R_X86_64_8: |
| 318 | checkUInt(Loc, Val, 8, Type); | |
| 319 | *Loc = Val; | |
| 352 | checkIntUInt(loc, val, 8, type); | |
| 353 | *loc = val; | |
| 354 | break; | |
| 355 | case R_X86_64_PC8: | |
| 356 | checkInt(loc, val, 8, type); | |
| 357 | *loc = val; | |
| 320 | 358 | break; |
| 321 | 359 | case R_X86_64_16: |
| 322 | checkUInt(Loc, Val, 16, Type); | |
| 323 | write16le(Loc, Val); | |
| 360 | checkIntUInt(loc, val, 16, type); | |
| 361 | write16le(loc, val); | |
| 362 | break; | |
| 363 | case R_X86_64_PC16: | |
| 364 | checkInt(loc, val, 16, type); | |
| 365 | write16le(loc, val); | |
| 324 | 366 | break; |
| 325 | 367 | case R_X86_64_32: |
| 326 | checkUInt(Loc, Val, 32, Type); | |
| 327 | write32le(Loc, Val); | |
| 368 | checkUInt(loc, val, 32, type); | |
| 369 | write32le(loc, val); | |
| 328 | 370 | break; |
| 329 | 371 | case R_X86_64_32S: |
| 330 | 372 | case R_X86_64_TPOFF32: |
| 331 | 373 | case R_X86_64_GOT32: |
| 332 | 374 | case R_X86_64_GOTPC32: |
| 375 | case R_X86_64_GOTPC32_TLSDESC: | |
| 333 | 376 | case R_X86_64_GOTPCREL: |
| 334 | 377 | case R_X86_64_GOTPCRELX: |
| 335 | 378 | case R_X86_64_REX_GOTPCRELX: |
| ... | ... | @@ -340,49 +383,47 @@ void X86_64<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { |
| 340 | 383 | case R_X86_64_TLSLD: |
| 341 | 384 | case R_X86_64_DTPOFF32: |
| 342 | 385 | case R_X86_64_SIZE32: |
| 343 | checkInt(Loc, Val, 32, Type); | |
| 344 | write32le(Loc, Val); | |
| 386 | checkInt(loc, val, 32, type); | |
| 387 | write32le(loc, val); | |
| 345 | 388 | break; |
| 346 | 389 | case R_X86_64_64: |
| 347 | 390 | case R_X86_64_DTPOFF64: |
| 348 | case R_X86_64_GLOB_DAT: | |
| 349 | 391 | case R_X86_64_PC64: |
| 350 | 392 | case R_X86_64_SIZE64: |
| 351 | 393 | case R_X86_64_GOT64: |
| 352 | 394 | case R_X86_64_GOTOFF64: |
| 353 | 395 | case R_X86_64_GOTPC64: |
| 354 | write64le(Loc, Val); | |
| 396 | write64le(loc, val); | |
| 355 | 397 | break; |
| 356 | 398 | default: |
| 357 | error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); | |
| 399 | llvm_unreachable("unknown relocation"); | |
| 358 | 400 | } |
| 359 | 401 | } |
| 360 | 402 | |
| 361 | template <class ELFT> | |
| 362 | RelExpr X86_64<ELFT>::adjustRelaxExpr(RelType Type, const uint8_t *Data, | |
| 363 | RelExpr RelExpr) const { | |
| 364 | if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX) | |
| 365 | return RelExpr; | |
| 366 | const uint8_t Op = Data[-2]; | |
| 367 | const uint8_t ModRm = Data[-1]; | |
| 403 | RelExpr X86_64::adjustRelaxExpr(RelType type, const uint8_t *data, | |
| 404 | RelExpr relExpr) const { | |
| 405 | if (type != R_X86_64_GOTPCRELX && type != R_X86_64_REX_GOTPCRELX) | |
| 406 | return relExpr; | |
| 407 | const uint8_t op = data[-2]; | |
| 408 | const uint8_t modRm = data[-1]; | |
| 368 | 409 | |
| 369 | 410 | // FIXME: When PIC is disabled and foo is defined locally in the |
| 370 | 411 | // lower 32 bit address space, memory operand in mov can be converted into |
| 371 | 412 | // immediate operand. Otherwise, mov must be changed to lea. We support only |
| 372 | 413 | // latter relaxation at this moment. |
| 373 | if (Op == 0x8b) | |
| 414 | if (op == 0x8b) | |
| 374 | 415 | return R_RELAX_GOT_PC; |
| 375 | 416 | |
| 376 | 417 | // Relax call and jmp. |
| 377 | if (Op == 0xff && (ModRm == 0x15 || ModRm == 0x25)) | |
| 418 | if (op == 0xff && (modRm == 0x15 || modRm == 0x25)) | |
| 378 | 419 | return R_RELAX_GOT_PC; |
| 379 | 420 | |
| 380 | 421 | // Relaxation of test, adc, add, and, cmp, or, sbb, sub, xor. |
| 381 | 422 | // If PIC then no relaxation is available. |
| 382 | 423 | // We also don't relax test/binop instructions without REX byte, |
| 383 | 424 | // they are 32bit operations and not common to have. |
| 384 | assert(Type == R_X86_64_REX_GOTPCRELX); | |
| 385 | return Config->Pic ? RelExpr : R_RELAX_GOT_PC_NOPIC; | |
| 425 | assert(type == R_X86_64_REX_GOTPCRELX); | |
| 426 | return config->isPic ? relExpr : R_RELAX_GOT_PC_NOPIC; | |
| 386 | 427 | } |
| 387 | 428 | |
| 388 | 429 | // A subset of relaxations can only be applied for no-PIC. This method |
| ... | ... | @@ -390,12 +431,11 @@ RelExpr X86_64<ELFT>::adjustRelaxExpr(RelType Type, const uint8_t *Data, |
| 390 | 431 | // "Intel 64 and IA-32 Architectures Software Developer's Manual V2" |
| 391 | 432 | // (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/ |
| 392 | 433 | // 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf) |
| 393 | template <class ELFT> | |
| 394 | void X86_64<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, | |
| 395 | uint8_t ModRm) const { | |
| 396 | const uint8_t Rex = Loc[-3]; | |
| 434 | static void relaxGotNoPic(uint8_t *loc, uint64_t val, uint8_t op, | |
| 435 | uint8_t modRm) { | |
| 436 | const uint8_t rex = loc[-3]; | |
| 397 | 437 | // Convert "test %reg, foo@GOTPCREL(%rip)" to "test $foo, %reg". |
| 398 | if (Op == 0x85) { | |
| 438 | if (op == 0x85) { | |
| 399 | 439 | // See "TEST-Logical Compare" (4-428 Vol. 2B), |
| 400 | 440 | // TEST r/m64, r64 uses "full" ModR / M byte (no opcode extension). |
| 401 | 441 | |
| ... | ... | @@ -412,11 +452,11 @@ void X86_64<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, |
| 412 | 452 | // 0x38 == 00 111 000 binary. |
| 413 | 453 | // We transfer reg2 to reg1 here as operand. |
| 414 | 454 | // See "2.1.3 ModR/M and SIB Bytes" (Vol. 2A 2-3). |
| 415 | Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3; // ModR/M byte. | |
| 455 | loc[-1] = 0xc0 | (modRm & 0x38) >> 3; // ModR/M byte. | |
| 416 | 456 | |
| 417 | 457 | // Change opcode from TEST r/m64, r64 to TEST r/m64, imm32 |
| 418 | 458 | // See "TEST-Logical Compare" (4-428 Vol. 2B). |
| 419 | Loc[-2] = 0xf7; | |
| 459 | loc[-2] = 0xf7; | |
| 420 | 460 | |
| 421 | 461 | // Move R bit to the B bit in REX byte. |
| 422 | 462 | // REX byte is encoded as 0100WRXB, where |
| ... | ... | @@ -429,8 +469,8 @@ void X86_64<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, |
| 429 | 469 | // REX.B This 1-bit value is an extension to the MODRM.rm field or the |
| 430 | 470 | // SIB.base field. |
| 431 | 471 | // See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A). |
| 432 | Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2; | |
| 433 | write32le(Loc, Val); | |
| 472 | loc[-3] = (rex & ~0x4) | (rex & 0x4) >> 2; | |
| 473 | write32le(loc, val); | |
| 434 | 474 | return; |
| 435 | 475 | } |
| 436 | 476 | |
| ... | ... | @@ -440,7 +480,7 @@ void X86_64<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, |
| 440 | 480 | // Convert "binop foo@GOTPCREL(%rip), %reg" to "binop $foo, %reg". |
| 441 | 481 | // Logic is close to one for test instruction above, but we also |
| 442 | 482 | // write opcode extension here, see below for details. |
| 443 | Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3 | (Op & 0x3c); // ModR/M byte. | |
| 483 | loc[-1] = 0xc0 | (modRm & 0x38) >> 3 | (op & 0x3c); // ModR/M byte. | |
| 444 | 484 | |
| 445 | 485 | // Primary opcode is 0x81, opcode extension is one of: |
| 446 | 486 | // 000b = ADD, 001b is OR, 010b is ADC, 011b is SBB, |
| ... | ... | @@ -449,69 +489,67 @@ void X86_64<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, |
| 449 | 489 | // See "3.2 INSTRUCTIONS (A-M)" (Vol. 2A 3-15), |
| 450 | 490 | // "INSTRUCTION SET REFERENCE, N-Z" (Vol. 2B 4-1) for |
| 451 | 491 | // descriptions about each operation. |
| 452 | Loc[-2] = 0x81; | |
| 453 | Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2; | |
| 454 | write32le(Loc, Val); | |
| 492 | loc[-2] = 0x81; | |
| 493 | loc[-3] = (rex & ~0x4) | (rex & 0x4) >> 2; | |
| 494 | write32le(loc, val); | |
| 455 | 495 | } |
| 456 | 496 | |
| 457 | template <class ELFT> | |
| 458 | void X86_64<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const { | |
| 459 | const uint8_t Op = Loc[-2]; | |
| 460 | const uint8_t ModRm = Loc[-1]; | |
| 497 | void X86_64::relaxGot(uint8_t *loc, RelType type, uint64_t val) const { | |
| 498 | const uint8_t op = loc[-2]; | |
| 499 | const uint8_t modRm = loc[-1]; | |
| 461 | 500 | |
| 462 | 501 | // Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg". |
| 463 | if (Op == 0x8b) { | |
| 464 | Loc[-2] = 0x8d; | |
| 465 | write32le(Loc, Val); | |
| 502 | if (op == 0x8b) { | |
| 503 | loc[-2] = 0x8d; | |
| 504 | write32le(loc, val); | |
| 466 | 505 | return; |
| 467 | 506 | } |
| 468 | 507 | |
| 469 | if (Op != 0xff) { | |
| 508 | if (op != 0xff) { | |
| 470 | 509 | // We are relaxing a rip relative to an absolute, so compensate |
| 471 | 510 | // for the old -4 addend. |
| 472 | assert(!Config->Pic); | |
| 473 | relaxGotNoPic(Loc, Val + 4, Op, ModRm); | |
| 511 | assert(!config->isPic); | |
| 512 | relaxGotNoPic(loc, val + 4, op, modRm); | |
| 474 | 513 | return; |
| 475 | 514 | } |
| 476 | 515 | |
| 477 | 516 | // Convert call/jmp instructions. |
| 478 | if (ModRm == 0x15) { | |
| 517 | if (modRm == 0x15) { | |
| 479 | 518 | // ABI says we can convert "call *foo@GOTPCREL(%rip)" to "nop; call foo". |
| 480 | 519 | // Instead we convert to "addr32 call foo" where addr32 is an instruction |
| 481 | 520 | // prefix. That makes result expression to be a single instruction. |
| 482 | Loc[-2] = 0x67; // addr32 prefix | |
| 483 | Loc[-1] = 0xe8; // call | |
| 484 | write32le(Loc, Val); | |
| 521 | loc[-2] = 0x67; // addr32 prefix | |
| 522 | loc[-1] = 0xe8; // call | |
| 523 | write32le(loc, val); | |
| 485 | 524 | return; |
| 486 | 525 | } |
| 487 | 526 | |
| 488 | 527 | // Convert "jmp *foo@GOTPCREL(%rip)" to "jmp foo; nop". |
| 489 | 528 | // jmp doesn't return, so it is fine to use nop here, it is just a stub. |
| 490 | assert(ModRm == 0x25); | |
| 491 | Loc[-2] = 0xe9; // jmp | |
| 492 | Loc[3] = 0x90; // nop | |
| 493 | write32le(Loc - 1, Val + 1); | |
| 529 | assert(modRm == 0x25); | |
| 530 | loc[-2] = 0xe9; // jmp | |
| 531 | loc[3] = 0x90; // nop | |
| 532 | write32le(loc - 1, val + 1); | |
| 494 | 533 | } |
| 495 | 534 | |
| 496 | // This anonymous namespace works around a warning bug in | |
| 497 | // old versions of gcc. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 | |
| 498 | namespace { | |
| 499 | ||
| 500 | 535 | // A split-stack prologue starts by checking the amount of stack remaining |
| 501 | 536 | // in one of two ways: |
| 502 | 537 | // A) Comparing of the stack pointer to a field in the tcb. |
| 503 | 538 | // B) Or a load of a stack pointer offset with an lea to r10 or r11. |
| 504 | template <> | |
| 505 | bool X86_64<ELF64LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc, | |
| 506 | uint8_t *End, | |
| 507 | uint8_t StOther) const { | |
| 508 | if (Loc + 8 >= End) | |
| 539 | bool X86_64::adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end, | |
| 540 | uint8_t stOther) const { | |
| 541 | if (!config->is64) { | |
| 542 | error("Target doesn't support split stacks."); | |
| 543 | return false; | |
| 544 | } | |
| 545 | ||
| 546 | if (loc + 8 >= end) | |
| 509 | 547 | return false; |
| 510 | 548 | |
| 511 | 549 | // Replace "cmp %fs:0x70,%rsp" and subsequent branch |
| 512 | 550 | // with "stc, nopl 0x0(%rax,%rax,1)" |
| 513 | if (memcmp(Loc, "\x64\x48\x3b\x24\x25", 5) == 0) { | |
| 514 | memcpy(Loc, "\xf9\x0f\x1f\x84\x00\x00\x00\x00", 8); | |
| 551 | if (memcmp(loc, "\x64\x48\x3b\x24\x25", 5) == 0) { | |
| 552 | memcpy(loc, "\xf9\x0f\x1f\x84\x00\x00\x00\x00", 8); | |
| 515 | 553 | return true; |
| 516 | 554 | } |
| 517 | 555 | |
| ... | ... | @@ -519,25 +557,16 @@ bool X86_64<ELF64LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc, |
| 519 | 557 | // be r10 or r11. The lea instruction feeds a subsequent compare which checks |
| 520 | 558 | // if there is X available stack space. Making X larger effectively reserves |
| 521 | 559 | // that much additional space. The stack grows downward so subtract the value. |
| 522 | if (memcmp(Loc, "\x4c\x8d\x94\x24", 4) == 0 || | |
| 523 | memcmp(Loc, "\x4c\x8d\x9c\x24", 4) == 0) { | |
| 560 | if (memcmp(loc, "\x4c\x8d\x94\x24", 4) == 0 || | |
| 561 | memcmp(loc, "\x4c\x8d\x9c\x24", 4) == 0) { | |
| 524 | 562 | // The offset bytes are encoded four bytes after the start of the |
| 525 | 563 | // instruction. |
| 526 | write32le(Loc + 4, read32le(Loc + 4) - 0x4000); | |
| 564 | write32le(loc + 4, read32le(loc + 4) - 0x4000); | |
| 527 | 565 | return true; |
| 528 | 566 | } |
| 529 | 567 | return false; |
| 530 | 568 | } |
| 531 | 569 | |
| 532 | template <> | |
| 533 | bool X86_64<ELF32LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc, | |
| 534 | uint8_t *End, | |
| 535 | uint8_t StOther) const { | |
| 536 | llvm_unreachable("Target doesn't support split stacks."); | |
| 537 | } | |
| 538 | ||
| 539 | } // namespace | |
| 540 | ||
| 541 | 570 | // These nonstandard PLT entries are to migtigate Spectre v2 security |
| 542 | 571 | // vulnerability. In order to mitigate Spectre v2, we want to avoid indirect |
| 543 | 572 | // branch instructions such as `jmp *GOTPLT(%rip)`. So, in the following PLT |
| ... | ... | @@ -548,37 +577,36 @@ bool X86_64<ELF32LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc, |
| 548 | 577 | // is specified, all dynamic symbols are resolved at load-time. Thus, when |
| 549 | 578 | // that option is given, we can omit code for symbol lazy resolution. |
| 550 | 579 | namespace { |
| 551 | template <class ELFT> class Retpoline : public X86_64<ELFT> { | |
| 580 | class Retpoline : public X86_64 { | |
| 552 | 581 | public: |
| 553 | 582 | Retpoline(); |
| 554 | void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; | |
| 555 | void writePltHeader(uint8_t *Buf) const override; | |
| 556 | void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, | |
| 557 | int32_t Index, unsigned RelOff) const override; | |
| 583 | void writeGotPlt(uint8_t *buf, const Symbol &s) const override; | |
| 584 | void writePltHeader(uint8_t *buf) const override; | |
| 585 | void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, | |
| 586 | int32_t index, unsigned relOff) const override; | |
| 558 | 587 | }; |
| 559 | 588 | |
| 560 | template <class ELFT> class RetpolineZNow : public X86_64<ELFT> { | |
| 589 | class RetpolineZNow : public X86_64 { | |
| 561 | 590 | public: |
| 562 | 591 | RetpolineZNow(); |
| 563 | void writeGotPlt(uint8_t *Buf, const Symbol &S) const override {} | |
| 564 | void writePltHeader(uint8_t *Buf) const override; | |
| 565 | void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, | |
| 566 | int32_t Index, unsigned RelOff) const override; | |
| 592 | void writeGotPlt(uint8_t *buf, const Symbol &s) const override {} | |
| 593 | void writePltHeader(uint8_t *buf) const override; | |
| 594 | void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, | |
| 595 | int32_t index, unsigned relOff) const override; | |
| 567 | 596 | }; |
| 568 | 597 | } // namespace |
| 569 | 598 | |
| 570 | template <class ELFT> Retpoline<ELFT>::Retpoline() { | |
| 571 | TargetInfo::PltHeaderSize = 48; | |
| 572 | TargetInfo::PltEntrySize = 32; | |
| 599 | Retpoline::Retpoline() { | |
| 600 | pltHeaderSize = 48; | |
| 601 | pltEntrySize = 32; | |
| 573 | 602 | } |
| 574 | 603 | |
| 575 | template <class ELFT> | |
| 576 | void Retpoline<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &S) const { | |
| 577 | write64le(Buf, S.getPltVA() + 17); | |
| 604 | void Retpoline::writeGotPlt(uint8_t *buf, const Symbol &s) const { | |
| 605 | write64le(buf, s.getPltVA() + 17); | |
| 578 | 606 | } |
| 579 | 607 | |
| 580 | template <class ELFT> void Retpoline<ELFT>::writePltHeader(uint8_t *Buf) const { | |
| 581 | const uint8_t Insn[] = { | |
| 608 | void Retpoline::writePltHeader(uint8_t *buf) const { | |
| 609 | const uint8_t insn[] = { | |
| 582 | 610 | 0xff, 0x35, 0, 0, 0, 0, // 0: pushq GOTPLT+8(%rip) |
| 583 | 611 | 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 6: mov GOTPLT+16(%rip), %r11 |
| 584 | 612 | 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: callq next |
| ... | ... | @@ -591,19 +619,18 @@ template <class ELFT> void Retpoline<ELFT>::writePltHeader(uint8_t *Buf) const { |
| 591 | 619 | 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 25: int3; padding |
| 592 | 620 | 0xcc, 0xcc, 0xcc, 0xcc, // 2c: int3; padding |
| 593 | 621 | }; |
| 594 | memcpy(Buf, Insn, sizeof(Insn)); | |
| 622 | memcpy(buf, insn, sizeof(insn)); | |
| 595 | 623 | |
| 596 | uint64_t GotPlt = In.GotPlt->getVA(); | |
| 597 | uint64_t Plt = In.Plt->getVA(); | |
| 598 | write32le(Buf + 2, GotPlt - Plt - 6 + 8); | |
| 599 | write32le(Buf + 9, GotPlt - Plt - 13 + 16); | |
| 624 | uint64_t gotPlt = in.gotPlt->getVA(); | |
| 625 | uint64_t plt = in.plt->getVA(); | |
| 626 | write32le(buf + 2, gotPlt - plt - 6 + 8); | |
| 627 | write32le(buf + 9, gotPlt - plt - 13 + 16); | |
| 600 | 628 | } |
| 601 | 629 | |
| 602 | template <class ELFT> | |
| 603 | void Retpoline<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, | |
| 604 | uint64_t PltEntryAddr, int32_t Index, | |
| 605 | unsigned RelOff) const { | |
| 606 | const uint8_t Insn[] = { | |
| 630 | void Retpoline::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, | |
| 631 | uint64_t pltEntryAddr, int32_t index, | |
| 632 | unsigned relOff) const { | |
| 633 | const uint8_t insn[] = { | |
| 607 | 634 | 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 0: mov foo@GOTPLT(%rip), %r11 |
| 608 | 635 | 0xe8, 0, 0, 0, 0, // 7: callq plt+0x20 |
| 609 | 636 | 0xe9, 0, 0, 0, 0, // c: jmp plt+0x12 |
| ... | ... | @@ -611,25 +638,24 @@ void Retpoline<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, |
| 611 | 638 | 0xe9, 0, 0, 0, 0, // 16: jmp plt+0 |
| 612 | 639 | 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1b: int3; padding |
| 613 | 640 | }; |
| 614 | memcpy(Buf, Insn, sizeof(Insn)); | |
| 641 | memcpy(buf, insn, sizeof(insn)); | |
| 615 | 642 | |
| 616 | uint64_t Off = getPltEntryOffset(Index); | |
| 643 | uint64_t off = pltHeaderSize + pltEntrySize * index; | |
| 617 | 644 | |
| 618 | write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7); | |
| 619 | write32le(Buf + 8, -Off - 12 + 32); | |
| 620 | write32le(Buf + 13, -Off - 17 + 18); | |
| 621 | write32le(Buf + 18, Index); | |
| 622 | write32le(Buf + 23, -Off - 27); | |
| 645 | write32le(buf + 3, gotPltEntryAddr - pltEntryAddr - 7); | |
| 646 | write32le(buf + 8, -off - 12 + 32); | |
| 647 | write32le(buf + 13, -off - 17 + 18); | |
| 648 | write32le(buf + 18, index); | |
| 649 | write32le(buf + 23, -off - 27); | |
| 623 | 650 | } |
| 624 | 651 | |
| 625 | template <class ELFT> RetpolineZNow<ELFT>::RetpolineZNow() { | |
| 626 | TargetInfo::PltHeaderSize = 32; | |
| 627 | TargetInfo::PltEntrySize = 16; | |
| 652 | RetpolineZNow::RetpolineZNow() { | |
| 653 | pltHeaderSize = 32; | |
| 654 | pltEntrySize = 16; | |
| 628 | 655 | } |
| 629 | 656 | |
| 630 | template <class ELFT> | |
| 631 | void RetpolineZNow<ELFT>::writePltHeader(uint8_t *Buf) const { | |
| 632 | const uint8_t Insn[] = { | |
| 657 | void RetpolineZNow::writePltHeader(uint8_t *buf) const { | |
| 658 | const uint8_t insn[] = { | |
| 633 | 659 | 0xe8, 0x0b, 0x00, 0x00, 0x00, // 0: call next |
| 634 | 660 | 0xf3, 0x90, // 5: loop: pause |
| 635 | 661 | 0x0f, 0xae, 0xe8, // 7: lfence |
| ... | ... | @@ -641,37 +667,35 @@ void RetpolineZNow<ELFT>::writePltHeader(uint8_t *Buf) const { |
| 641 | 667 | 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding |
| 642 | 668 | 0xcc, // 1f: int3; padding |
| 643 | 669 | }; |
| 644 | memcpy(Buf, Insn, sizeof(Insn)); | |
| 670 | memcpy(buf, insn, sizeof(insn)); | |
| 645 | 671 | } |
| 646 | 672 | |
| 647 | template <class ELFT> | |
| 648 | void RetpolineZNow<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, | |
| 649 | uint64_t PltEntryAddr, int32_t Index, | |
| 650 | unsigned RelOff) const { | |
| 651 | const uint8_t Insn[] = { | |
| 673 | void RetpolineZNow::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, | |
| 674 | uint64_t pltEntryAddr, int32_t index, | |
| 675 | unsigned relOff) const { | |
| 676 | const uint8_t insn[] = { | |
| 652 | 677 | 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // mov foo@GOTPLT(%rip), %r11 |
| 653 | 678 | 0xe9, 0, 0, 0, 0, // jmp plt+0 |
| 654 | 679 | 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding |
| 655 | 680 | }; |
| 656 | memcpy(Buf, Insn, sizeof(Insn)); | |
| 681 | memcpy(buf, insn, sizeof(insn)); | |
| 657 | 682 | |
| 658 | write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7); | |
| 659 | write32le(Buf + 8, -getPltEntryOffset(Index) - 12); | |
| 683 | write32le(buf + 3, gotPltEntryAddr - pltEntryAddr - 7); | |
| 684 | write32le(buf + 8, -pltHeaderSize - pltEntrySize * index - 12); | |
| 660 | 685 | } |
| 661 | 686 | |
| 662 | template <class ELFT> static TargetInfo *getTargetInfo() { | |
| 663 | if (Config->ZRetpolineplt) { | |
| 664 | if (Config->ZNow) { | |
| 665 | static RetpolineZNow<ELFT> T; | |
| 666 | return &T; | |
| 687 | static TargetInfo *getTargetInfo() { | |
| 688 | if (config->zRetpolineplt) { | |
| 689 | if (config->zNow) { | |
| 690 | static RetpolineZNow t; | |
| 691 | return &t; | |
| 667 | 692 | } |
| 668 | static Retpoline<ELFT> T; | |
| 669 | return &T; | |
| 693 | static Retpoline t; | |
| 694 | return &t; | |
| 670 | 695 | } |
| 671 | 696 | |
| 672 | static X86_64<ELFT> T; | |
| 673 | return &T; | |
| 697 | static X86_64 t; | |
| 698 | return &t; | |
| 674 | 699 | } |
| 675 | 700 | |
| 676 | TargetInfo *elf::getX32TargetInfo() { return getTargetInfo<ELF32LE>(); } | |
| 677 | TargetInfo *elf::getX86_64TargetInfo() { return getTargetInfo<ELF64LE>(); } | |
| 701 | TargetInfo *elf::getX86_64TargetInfo() { return getTargetInfo(); } |
deps/lld/ELF/Bits.h deleted-35| ... | ... | @@ -1,35 +0,0 @@ |
| 1 | //===- Bits.h ---------------------------------------------------*- C++ -*-===// | |
| 2 | // | |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | //===----------------------------------------------------------------------===// | |
| 9 | ||
| 10 | #ifndef LLD_ELF_BITS_H | |
| 11 | #define LLD_ELF_BITS_H | |
| 12 | ||
| 13 | #include "Config.h" | |
| 14 | #include "llvm/Support/Endian.h" | |
| 15 | ||
| 16 | namespace lld { | |
| 17 | namespace elf { | |
| 18 | ||
| 19 | inline uint64_t readUint(uint8_t *Buf) { | |
| 20 | if (Config->Is64) | |
| 21 | return llvm::support::endian::read64(Buf, Config->Endianness); | |
| 22 | return llvm::support::endian::read32(Buf, Config->Endianness); | |
| 23 | } | |
| 24 | ||
| 25 | inline void writeUint(uint8_t *Buf, uint64_t Val) { | |
| 26 | if (Config->Is64) | |
| 27 | llvm::support::endian::write64(Buf, Val, Config->Endianness); | |
| 28 | else | |
| 29 | llvm::support::endian::write32(Buf, Val, Config->Endianness); | |
| 30 | } | |
| 31 | ||
| 32 | } // namespace elf | |
| 33 | } // namespace lld | |
| 34 | ||
| 35 | #endif |
deps/lld/ELF/CMakeLists.txt-1| ... | ... | @@ -27,7 +27,6 @@ add_lld_library(lldELF |
| 27 | 27 | Driver.cpp |
| 28 | 28 | DriverUtils.cpp |
| 29 | 29 | EhFrame.cpp |
| 30 | Filesystem.cpp | |
| 31 | 30 | ICF.cpp |
| 32 | 31 | InputFiles.cpp |
| 33 | 32 | InputSection.cpp |
deps/lld/ELF/CallGraphSort.cpp+102-83| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- CallGraphSort.cpp --------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | /// |
| ... | ... | @@ -52,24 +51,24 @@ using namespace lld::elf; |
| 52 | 51 | |
| 53 | 52 | namespace { |
| 54 | 53 | struct Edge { |
| 55 | int From; | |
| 56 | uint64_t Weight; | |
| 54 | int from; | |
| 55 | uint64_t weight; | |
| 57 | 56 | }; |
| 58 | 57 | |
| 59 | 58 | struct Cluster { |
| 60 | Cluster(int Sec, size_t S) : Sections{Sec}, Size(S) {} | |
| 59 | Cluster(int sec, size_t s) : sections{sec}, size(s) {} | |
| 61 | 60 | |
| 62 | 61 | double getDensity() const { |
| 63 | if (Size == 0) | |
| 62 | if (size == 0) | |
| 64 | 63 | return 0; |
| 65 | return double(Weight) / double(Size); | |
| 64 | return double(weight) / double(size); | |
| 66 | 65 | } |
| 67 | 66 | |
| 68 | std::vector<int> Sections; | |
| 69 | size_t Size = 0; | |
| 70 | uint64_t Weight = 0; | |
| 71 | uint64_t InitialWeight = 0; | |
| 72 | Edge BestPred = {-1, 0}; | |
| 67 | std::vector<int> sections; | |
| 68 | size_t size = 0; | |
| 69 | uint64_t weight = 0; | |
| 70 | uint64_t initialWeight = 0; | |
| 71 | Edge bestPred = {-1, 0}; | |
| 73 | 72 | }; |
| 74 | 73 | |
| 75 | 74 | class CallGraphSort { |
| ... | ... | @@ -79,8 +78,8 @@ public: |
| 79 | 78 | DenseMap<const InputSectionBase *, int> run(); |
| 80 | 79 | |
| 81 | 80 | private: |
| 82 | std::vector<Cluster> Clusters; | |
| 83 | std::vector<const InputSectionBase *> Sections; | |
| 81 | std::vector<Cluster> clusters; | |
| 82 | std::vector<const InputSectionBase *> sections; | |
| 84 | 83 | |
| 85 | 84 | void groupClusters(); |
| 86 | 85 | }; |
| ... | ... | @@ -93,30 +92,30 @@ constexpr int MAX_DENSITY_DEGRADATION = 8; |
| 93 | 92 | constexpr uint64_t MAX_CLUSTER_SIZE = 1024 * 1024; |
| 94 | 93 | } // end anonymous namespace |
| 95 | 94 | |
| 96 | typedef std::pair<const InputSectionBase *, const InputSectionBase *> | |
| 97 | SectionPair; | |
| 95 | using SectionPair = | |
| 96 | std::pair<const InputSectionBase *, const InputSectionBase *>; | |
| 98 | 97 | |
| 99 | 98 | // Take the edge list in Config->CallGraphProfile, resolve symbol names to |
| 100 | 99 | // Symbols, and generate a graph between InputSections with the provided |
| 101 | 100 | // weights. |
| 102 | 101 | CallGraphSort::CallGraphSort() { |
| 103 | MapVector<SectionPair, uint64_t> &Profile = Config->CallGraphProfile; | |
| 104 | DenseMap<const InputSectionBase *, int> SecToCluster; | |
| 105 | ||
| 106 | auto GetOrCreateNode = [&](const InputSectionBase *IS) -> int { | |
| 107 | auto Res = SecToCluster.insert(std::make_pair(IS, Clusters.size())); | |
| 108 | if (Res.second) { | |
| 109 | Sections.push_back(IS); | |
| 110 | Clusters.emplace_back(Clusters.size(), IS->getSize()); | |
| 102 | MapVector<SectionPair, uint64_t> &profile = config->callGraphProfile; | |
| 103 | DenseMap<const InputSectionBase *, int> secToCluster; | |
| 104 | ||
| 105 | auto getOrCreateNode = [&](const InputSectionBase *isec) -> int { | |
| 106 | auto res = secToCluster.insert(std::make_pair(isec, clusters.size())); | |
| 107 | if (res.second) { | |
| 108 | sections.push_back(isec); | |
| 109 | clusters.emplace_back(clusters.size(), isec->getSize()); | |
| 111 | 110 | } |
| 112 | return Res.first->second; | |
| 111 | return res.first->second; | |
| 113 | 112 | }; |
| 114 | 113 | |
| 115 | 114 | // Create the graph. |
| 116 | for (std::pair<SectionPair, uint64_t> &C : Profile) { | |
| 117 | const auto *FromSB = cast<InputSectionBase>(C.first.first->Repl); | |
| 118 | const auto *ToSB = cast<InputSectionBase>(C.first.second->Repl); | |
| 119 | uint64_t Weight = C.second; | |
| 115 | for (std::pair<SectionPair, uint64_t> &c : profile) { | |
| 116 | const auto *fromSB = cast<InputSectionBase>(c.first.first->repl); | |
| 117 | const auto *toSB = cast<InputSectionBase>(c.first.second->repl); | |
| 118 | uint64_t weight = c.second; | |
| 120 | 119 | |
| 121 | 120 | // Ignore edges between input sections belonging to different output |
| 122 | 121 | // sections. This is done because otherwise we would end up with clusters |
| ... | ... | @@ -124,110 +123,130 @@ CallGraphSort::CallGraphSort() { |
| 124 | 123 | // output. This messes with the cluster size and density calculations. We |
| 125 | 124 | // would also end up moving input sections in other output sections without |
| 126 | 125 | // moving them closer to what calls them. |
| 127 | if (FromSB->getOutputSection() != ToSB->getOutputSection()) | |
| 126 | if (fromSB->getOutputSection() != toSB->getOutputSection()) | |
| 128 | 127 | continue; |
| 129 | 128 | |
| 130 | int From = GetOrCreateNode(FromSB); | |
| 131 | int To = GetOrCreateNode(ToSB); | |
| 129 | int from = getOrCreateNode(fromSB); | |
| 130 | int to = getOrCreateNode(toSB); | |
| 132 | 131 | |
| 133 | Clusters[To].Weight += Weight; | |
| 132 | clusters[to].weight += weight; | |
| 134 | 133 | |
| 135 | if (From == To) | |
| 134 | if (from == to) | |
| 136 | 135 | continue; |
| 137 | 136 | |
| 138 | 137 | // Remember the best edge. |
| 139 | Cluster &ToC = Clusters[To]; | |
| 140 | if (ToC.BestPred.From == -1 || ToC.BestPred.Weight < Weight) { | |
| 141 | ToC.BestPred.From = From; | |
| 142 | ToC.BestPred.Weight = Weight; | |
| 138 | Cluster &toC = clusters[to]; | |
| 139 | if (toC.bestPred.from == -1 || toC.bestPred.weight < weight) { | |
| 140 | toC.bestPred.from = from; | |
| 141 | toC.bestPred.weight = weight; | |
| 143 | 142 | } |
| 144 | 143 | } |
| 145 | for (Cluster &C : Clusters) | |
| 146 | C.InitialWeight = C.Weight; | |
| 144 | for (Cluster &c : clusters) | |
| 145 | c.initialWeight = c.weight; | |
| 147 | 146 | } |
| 148 | 147 | |
| 149 | 148 | // It's bad to merge clusters which would degrade the density too much. |
| 150 | static bool isNewDensityBad(Cluster &A, Cluster &B) { | |
| 151 | double NewDensity = double(A.Weight + B.Weight) / double(A.Size + B.Size); | |
| 152 | return NewDensity < A.getDensity() / MAX_DENSITY_DEGRADATION; | |
| 149 | static bool isNewDensityBad(Cluster &a, Cluster &b) { | |
| 150 | double newDensity = double(a.weight + b.weight) / double(a.size + b.size); | |
| 151 | return newDensity < a.getDensity() / MAX_DENSITY_DEGRADATION; | |
| 153 | 152 | } |
| 154 | 153 | |
| 155 | static void mergeClusters(Cluster &Into, Cluster &From) { | |
| 156 | Into.Sections.insert(Into.Sections.end(), From.Sections.begin(), | |
| 157 | From.Sections.end()); | |
| 158 | Into.Size += From.Size; | |
| 159 | Into.Weight += From.Weight; | |
| 160 | From.Sections.clear(); | |
| 161 | From.Size = 0; | |
| 162 | From.Weight = 0; | |
| 154 | static void mergeClusters(Cluster &into, Cluster &from) { | |
| 155 | into.sections.insert(into.sections.end(), from.sections.begin(), | |
| 156 | from.sections.end()); | |
| 157 | into.size += from.size; | |
| 158 | into.weight += from.weight; | |
| 159 | from.sections.clear(); | |
| 160 | from.size = 0; | |
| 161 | from.weight = 0; | |
| 163 | 162 | } |
| 164 | 163 | |
| 165 | 164 | // Group InputSections into clusters using the Call-Chain Clustering heuristic |
| 166 | 165 | // then sort the clusters by density. |
| 167 | 166 | void CallGraphSort::groupClusters() { |
| 168 | std::vector<int> SortedSecs(Clusters.size()); | |
| 169 | std::vector<Cluster *> SecToCluster(Clusters.size()); | |
| 167 | std::vector<int> sortedSecs(clusters.size()); | |
| 168 | std::vector<Cluster *> secToCluster(clusters.size()); | |
| 170 | 169 | |
| 171 | for (size_t I = 0; I < Clusters.size(); ++I) { | |
| 172 | SortedSecs[I] = I; | |
| 173 | SecToCluster[I] = &Clusters[I]; | |
| 170 | for (size_t i = 0; i < clusters.size(); ++i) { | |
| 171 | sortedSecs[i] = i; | |
| 172 | secToCluster[i] = &clusters[i]; | |
| 174 | 173 | } |
| 175 | 174 | |
| 176 | std::stable_sort(SortedSecs.begin(), SortedSecs.end(), [&](int A, int B) { | |
| 177 | return Clusters[B].getDensity() < Clusters[A].getDensity(); | |
| 175 | llvm::stable_sort(sortedSecs, [&](int a, int b) { | |
| 176 | return clusters[a].getDensity() > clusters[b].getDensity(); | |
| 178 | 177 | }); |
| 179 | 178 | |
| 180 | for (int SI : SortedSecs) { | |
| 181 | // Clusters[SI] is the same as SecToClusters[SI] here because it has not | |
| 179 | for (int si : sortedSecs) { | |
| 180 | // clusters[si] is the same as secToClusters[si] here because it has not | |
| 182 | 181 | // been merged into another cluster yet. |
| 183 | Cluster &C = Clusters[SI]; | |
| 182 | Cluster &c = clusters[si]; | |
| 184 | 183 | |
| 185 | 184 | // Don't consider merging if the edge is unlikely. |
| 186 | if (C.BestPred.From == -1 || C.BestPred.Weight * 10 <= C.InitialWeight) | |
| 185 | if (c.bestPred.from == -1 || c.bestPred.weight * 10 <= c.initialWeight) | |
| 187 | 186 | continue; |
| 188 | 187 | |
| 189 | Cluster *PredC = SecToCluster[C.BestPred.From]; | |
| 190 | if (PredC == &C) | |
| 188 | Cluster *predC = secToCluster[c.bestPred.from]; | |
| 189 | if (predC == &c) | |
| 191 | 190 | continue; |
| 192 | 191 | |
| 193 | if (C.Size + PredC->Size > MAX_CLUSTER_SIZE) | |
| 192 | if (c.size + predC->size > MAX_CLUSTER_SIZE) | |
| 194 | 193 | continue; |
| 195 | 194 | |
| 196 | if (isNewDensityBad(*PredC, C)) | |
| 195 | if (isNewDensityBad(*predC, c)) | |
| 197 | 196 | continue; |
| 198 | 197 | |
| 199 | 198 | // NOTE: Consider using a disjoint-set to track section -> cluster mapping |
| 200 | 199 | // if this is ever slow. |
| 201 | for (int SI : C.Sections) | |
| 202 | SecToCluster[SI] = PredC; | |
| 200 | for (int si : c.sections) | |
| 201 | secToCluster[si] = predC; | |
| 203 | 202 | |
| 204 | mergeClusters(*PredC, C); | |
| 203 | mergeClusters(*predC, c); | |
| 205 | 204 | } |
| 206 | 205 | |
| 207 | 206 | // Remove empty or dead nodes. Invalidates all cluster indices. |
| 208 | llvm::erase_if(Clusters, [](const Cluster &C) { | |
| 209 | return C.Size == 0 || C.Sections.empty(); | |
| 207 | llvm::erase_if(clusters, [](const Cluster &c) { | |
| 208 | return c.size == 0 || c.sections.empty(); | |
| 210 | 209 | }); |
| 211 | 210 | |
| 212 | 211 | // Sort by density. |
| 213 | std::stable_sort(Clusters.begin(), Clusters.end(), | |
| 214 | [](const Cluster &A, const Cluster &B) { | |
| 215 | return A.getDensity() > B.getDensity(); | |
| 216 | }); | |
| 212 | llvm::stable_sort(clusters, [](const Cluster &a, const Cluster &b) { | |
| 213 | return a.getDensity() > b.getDensity(); | |
| 214 | }); | |
| 217 | 215 | } |
| 218 | 216 | |
| 219 | 217 | DenseMap<const InputSectionBase *, int> CallGraphSort::run() { |
| 220 | 218 | groupClusters(); |
| 221 | 219 | |
| 222 | 220 | // Generate order. |
| 223 | DenseMap<const InputSectionBase *, int> OrderMap; | |
| 224 | ssize_t CurOrder = 1; | |
| 221 | DenseMap<const InputSectionBase *, int> orderMap; | |
| 222 | ssize_t curOrder = 1; | |
| 223 | ||
| 224 | for (const Cluster &c : clusters) | |
| 225 | for (int secIndex : c.sections) | |
| 226 | orderMap[sections[secIndex]] = curOrder++; | |
| 227 | ||
| 228 | if (!config->printSymbolOrder.empty()) { | |
| 229 | std::error_code ec; | |
| 230 | raw_fd_ostream os(config->printSymbolOrder, ec, sys::fs::F_None); | |
| 231 | if (ec) { | |
| 232 | error("cannot open " + config->printSymbolOrder + ": " + ec.message()); | |
| 233 | return orderMap; | |
| 234 | } | |
| 225 | 235 | |
| 226 | for (const Cluster &C : Clusters) | |
| 227 | for (int SecIndex : C.Sections) | |
| 228 | OrderMap[Sections[SecIndex]] = CurOrder++; | |
| 236 | // Print the symbols ordered by C3, in the order of increasing curOrder | |
| 237 | // Instead of sorting all the orderMap, just repeat the loops above. | |
| 238 | for (const Cluster &c : clusters) | |
| 239 | for (int secIndex : c.sections) | |
| 240 | // Search all the symbols in the file of the section | |
| 241 | // and find out a Defined symbol with name that is within the section. | |
| 242 | for (Symbol *sym: sections[secIndex]->file->getSymbols()) | |
| 243 | if (!sym->isSection()) // Filter out section-type symbols here. | |
| 244 | if (auto *d = dyn_cast<Defined>(sym)) | |
| 245 | if (sections[secIndex] == d->section) | |
| 246 | os << sym->getName() << "\n"; | |
| 247 | } | |
| 229 | 248 | |
| 230 | return OrderMap; | |
| 249 | return orderMap; | |
| 231 | 250 | } |
| 232 | 251 | |
| 233 | 252 | // Sort sections by the profile data provided by -callgraph-profile-file |
deps/lld/ELF/CallGraphSort.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- CallGraphSort.h ------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/ELF/Config.h+192-165| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Config.h -------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -18,6 +17,7 @@ |
| 18 | 17 | #include "llvm/Support/CachePruning.h" |
| 19 | 18 | #include "llvm/Support/CodeGen.h" |
| 20 | 19 | #include "llvm/Support/Endian.h" |
| 20 | #include <atomic> | |
| 21 | 21 | #include <vector> |
| 22 | 22 | |
| 23 | 23 | namespace lld { |
| ... | ... | @@ -62,18 +62,17 @@ enum class Target2Policy { Abs, Rel, GotRel }; |
| 62 | 62 | enum class ARMVFPArgKind { Default, Base, VFP, ToolChain }; |
| 63 | 63 | |
| 64 | 64 | struct SymbolVersion { |
| 65 | llvm::StringRef Name; | |
| 66 | bool IsExternCpp; | |
| 67 | bool HasWildcard; | |
| 65 | llvm::StringRef name; | |
| 66 | bool isExternCpp; | |
| 67 | bool hasWildcard; | |
| 68 | 68 | }; |
| 69 | 69 | |
| 70 | 70 | // This struct contains symbols version definition that |
| 71 | 71 | // can be found in version script if it is used for link. |
| 72 | 72 | struct VersionDefinition { |
| 73 | llvm::StringRef Name; | |
| 74 | uint16_t Id = 0; | |
| 75 | std::vector<SymbolVersion> Globals; | |
| 76 | size_t NameOff = 0; // Offset in the string table | |
| 73 | llvm::StringRef name; | |
| 74 | uint16_t id = 0; | |
| 75 | std::vector<SymbolVersion> globals; | |
| 77 | 76 | }; |
| 78 | 77 | |
| 79 | 78 | // This struct contains the global configuration for the linker. |
| ... | ... | @@ -81,163 +80,177 @@ struct VersionDefinition { |
| 81 | 80 | // and such fields have the same name as the corresponding options. |
| 82 | 81 | // Most fields are initialized by the driver. |
| 83 | 82 | struct Configuration { |
| 84 | uint8_t OSABI = 0; | |
| 85 | llvm::CachePruningPolicy ThinLTOCachePolicy; | |
| 86 | llvm::StringMap<uint64_t> SectionStartMap; | |
| 87 | llvm::StringRef Chroot; | |
| 88 | llvm::StringRef DynamicLinker; | |
| 89 | llvm::StringRef DwoDir; | |
| 90 | llvm::StringRef Entry; | |
| 91 | llvm::StringRef Emulation; | |
| 92 | llvm::StringRef Fini; | |
| 93 | llvm::StringRef Init; | |
| 94 | llvm::StringRef LTOAAPipeline; | |
| 95 | llvm::StringRef LTONewPmPasses; | |
| 96 | llvm::StringRef LTOObjPath; | |
| 97 | llvm::StringRef LTOSampleProfile; | |
| 98 | llvm::StringRef MapFile; | |
| 99 | llvm::StringRef OutputFile; | |
| 100 | llvm::StringRef OptRemarksFilename; | |
| 101 | llvm::StringRef ProgName; | |
| 102 | llvm::StringRef SoName; | |
| 103 | llvm::StringRef Sysroot; | |
| 104 | llvm::StringRef ThinLTOCacheDir; | |
| 105 | llvm::StringRef ThinLTOIndexOnlyArg; | |
| 106 | std::pair<llvm::StringRef, llvm::StringRef> ThinLTOObjectSuffixReplace; | |
| 107 | std::pair<llvm::StringRef, llvm::StringRef> ThinLTOPrefixReplace; | |
| 108 | std::string Rpath; | |
| 109 | std::vector<VersionDefinition> VersionDefinitions; | |
| 110 | std::vector<llvm::StringRef> AuxiliaryList; | |
| 111 | std::vector<llvm::StringRef> FilterList; | |
| 112 | std::vector<llvm::StringRef> SearchPaths; | |
| 113 | std::vector<llvm::StringRef> SymbolOrderingFile; | |
| 114 | std::vector<llvm::StringRef> Undefined; | |
| 115 | std::vector<SymbolVersion> DynamicList; | |
| 116 | std::vector<SymbolVersion> VersionScriptGlobals; | |
| 117 | std::vector<SymbolVersion> VersionScriptLocals; | |
| 118 | std::vector<uint8_t> BuildIdVector; | |
| 83 | uint8_t osabi = 0; | |
| 84 | uint32_t andFeatures = 0; | |
| 85 | llvm::CachePruningPolicy thinLTOCachePolicy; | |
| 86 | llvm::StringMap<uint64_t> sectionStartMap; | |
| 87 | llvm::StringRef chroot; | |
| 88 | llvm::StringRef dynamicLinker; | |
| 89 | llvm::StringRef dwoDir; | |
| 90 | llvm::StringRef entry; | |
| 91 | llvm::StringRef emulation; | |
| 92 | llvm::StringRef fini; | |
| 93 | llvm::StringRef init; | |
| 94 | llvm::StringRef ltoAAPipeline; | |
| 95 | llvm::StringRef ltoCSProfileFile; | |
| 96 | llvm::StringRef ltoNewPmPasses; | |
| 97 | llvm::StringRef ltoObjPath; | |
| 98 | llvm::StringRef ltoSampleProfile; | |
| 99 | llvm::StringRef mapFile; | |
| 100 | llvm::StringRef outputFile; | |
| 101 | llvm::StringRef optRemarksFilename; | |
| 102 | llvm::StringRef optRemarksPasses; | |
| 103 | llvm::StringRef optRemarksFormat; | |
| 104 | llvm::StringRef progName; | |
| 105 | llvm::StringRef printSymbolOrder; | |
| 106 | llvm::StringRef soName; | |
| 107 | llvm::StringRef sysroot; | |
| 108 | llvm::StringRef thinLTOCacheDir; | |
| 109 | llvm::StringRef thinLTOIndexOnlyArg; | |
| 110 | std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace; | |
| 111 | std::pair<llvm::StringRef, llvm::StringRef> thinLTOPrefixReplace; | |
| 112 | std::string rpath; | |
| 113 | std::vector<VersionDefinition> versionDefinitions; | |
| 114 | std::vector<llvm::StringRef> auxiliaryList; | |
| 115 | std::vector<llvm::StringRef> filterList; | |
| 116 | std::vector<llvm::StringRef> searchPaths; | |
| 117 | std::vector<llvm::StringRef> symbolOrderingFile; | |
| 118 | std::vector<llvm::StringRef> undefined; | |
| 119 | std::vector<SymbolVersion> dynamicList; | |
| 120 | std::vector<SymbolVersion> versionScriptGlobals; | |
| 121 | std::vector<SymbolVersion> versionScriptLocals; | |
| 122 | std::vector<uint8_t> buildIdVector; | |
| 119 | 123 | llvm::MapVector<std::pair<const InputSectionBase *, const InputSectionBase *>, |
| 120 | 124 | uint64_t> |
| 121 | CallGraphProfile; | |
| 122 | bool AllowMultipleDefinition; | |
| 123 | bool AndroidPackDynRelocs; | |
| 124 | bool ARMHasBlx = false; | |
| 125 | bool ARMHasMovtMovw = false; | |
| 126 | bool ARMJ1J2BranchEncoding = false; | |
| 127 | bool AsNeeded = false; | |
| 128 | bool Bsymbolic; | |
| 129 | bool BsymbolicFunctions; | |
| 130 | bool CallGraphProfileSort; | |
| 131 | bool CheckSections; | |
| 132 | bool CompressDebugSections; | |
| 133 | bool Cref; | |
| 134 | bool DefineCommon; | |
| 135 | bool Demangle = true; | |
| 136 | bool DisableVerify; | |
| 137 | bool EhFrameHdr; | |
| 138 | bool EmitLLVM; | |
| 139 | bool EmitRelocs; | |
| 140 | bool EnableNewDtags; | |
| 141 | bool ExecuteOnly; | |
| 142 | bool ExportDynamic; | |
| 143 | bool FixCortexA53Errata843419; | |
| 144 | bool FormatBinary = false; | |
| 145 | bool GcSections; | |
| 146 | bool GdbIndex; | |
| 147 | bool GnuHash = false; | |
| 148 | bool GnuUnique; | |
| 149 | bool HasDynamicList = false; | |
| 150 | bool HasDynSymTab; | |
| 151 | bool IgnoreDataAddressEquality; | |
| 152 | bool IgnoreFunctionAddressEquality; | |
| 153 | bool LTODebugPassManager; | |
| 154 | bool LTONewPassManager; | |
| 155 | bool MergeArmExidx; | |
| 156 | bool MipsN32Abi = false; | |
| 157 | bool NoinhibitExec; | |
| 158 | bool Nostdlib; | |
| 159 | bool OFormatBinary; | |
| 160 | bool Omagic; | |
| 161 | bool OptRemarksWithHotness; | |
| 162 | bool PicThunk; | |
| 163 | bool Pie; | |
| 164 | bool PrintGcSections; | |
| 165 | bool PrintIcfSections; | |
| 166 | bool Relocatable; | |
| 167 | bool RelrPackDynRelocs; | |
| 168 | bool SaveTemps; | |
| 169 | bool SingleRoRx; | |
| 170 | bool Shared; | |
| 171 | bool Static = false; | |
| 172 | bool SysvHash = false; | |
| 173 | bool Target1Rel; | |
| 174 | bool Trace; | |
| 175 | bool ThinLTOEmitImportsFiles; | |
| 176 | bool ThinLTOIndexOnly; | |
| 177 | bool TocOptimize; | |
| 178 | bool UndefinedVersion; | |
| 179 | bool UseAndroidRelrTags = false; | |
| 180 | bool WarnBackrefs; | |
| 181 | bool WarnCommon; | |
| 182 | bool WarnIfuncTextrel; | |
| 183 | bool WarnMissingEntry; | |
| 184 | bool WarnSymbolOrdering; | |
| 185 | bool WriteAddends; | |
| 186 | bool ZCombreloc; | |
| 187 | bool ZCopyreloc; | |
| 188 | bool ZExecstack; | |
| 189 | bool ZGlobal; | |
| 190 | bool ZHazardplt; | |
| 191 | bool ZInitfirst; | |
| 192 | bool ZInterpose; | |
| 193 | bool ZKeepTextSectionPrefix; | |
| 194 | bool ZNodefaultlib; | |
| 195 | bool ZNodelete; | |
| 196 | bool ZNodlopen; | |
| 197 | bool ZNow; | |
| 198 | bool ZOrigin; | |
| 199 | bool ZRelro; | |
| 200 | bool ZRodynamic; | |
| 201 | bool ZText; | |
| 202 | bool ZRetpolineplt; | |
| 203 | bool ZWxneeded; | |
| 204 | DiscardPolicy Discard; | |
| 205 | ICFLevel ICF; | |
| 206 | OrphanHandlingPolicy OrphanHandling; | |
| 207 | SortSectionPolicy SortSection; | |
| 208 | StripPolicy Strip; | |
| 209 | UnresolvedPolicy UnresolvedSymbols; | |
| 210 | Target2Policy Target2; | |
| 211 | ARMVFPArgKind ARMVFPArgs = ARMVFPArgKind::Default; | |
| 212 | BuildIdKind BuildId = BuildIdKind::None; | |
| 213 | ELFKind EKind = ELFNoneKind; | |
| 214 | uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL; | |
| 215 | uint16_t EMachine = llvm::ELF::EM_NONE; | |
| 216 | llvm::Optional<uint64_t> ImageBase; | |
| 217 | uint64_t MaxPageSize; | |
| 218 | uint64_t MipsGotSize; | |
| 219 | uint64_t ZStackSize; | |
| 220 | unsigned LTOPartitions; | |
| 221 | unsigned LTOO; | |
| 222 | unsigned Optimize; | |
| 223 | unsigned ThinLTOJobs; | |
| 224 | int32_t SplitStackAdjustSize; | |
| 125 | callGraphProfile; | |
| 126 | bool allowMultipleDefinition; | |
| 127 | bool allowShlibUndefined; | |
| 128 | bool androidPackDynRelocs; | |
| 129 | bool armHasBlx = false; | |
| 130 | bool armHasMovtMovw = false; | |
| 131 | bool armJ1J2BranchEncoding = false; | |
| 132 | bool asNeeded = false; | |
| 133 | bool bsymbolic; | |
| 134 | bool bsymbolicFunctions; | |
| 135 | bool callGraphProfileSort; | |
| 136 | bool checkSections; | |
| 137 | bool compressDebugSections; | |
| 138 | bool cref; | |
| 139 | bool defineCommon; | |
| 140 | bool demangle = true; | |
| 141 | bool dependentLibraries; | |
| 142 | bool disableVerify; | |
| 143 | bool ehFrameHdr; | |
| 144 | bool emitLLVM; | |
| 145 | bool emitRelocs; | |
| 146 | bool enableNewDtags; | |
| 147 | bool executeOnly; | |
| 148 | bool exportDynamic; | |
| 149 | bool fixCortexA53Errata843419; | |
| 150 | bool forceBTI; | |
| 151 | bool formatBinary = false; | |
| 152 | bool requireCET; | |
| 153 | bool gcSections; | |
| 154 | bool gdbIndex; | |
| 155 | bool gnuHash = false; | |
| 156 | bool gnuUnique; | |
| 157 | bool hasDynamicList = false; | |
| 158 | bool hasDynSymTab; | |
| 159 | bool ignoreDataAddressEquality; | |
| 160 | bool ignoreFunctionAddressEquality; | |
| 161 | bool ltoCSProfileGenerate; | |
| 162 | bool ltoDebugPassManager; | |
| 163 | bool ltoNewPassManager; | |
| 164 | bool mergeArmExidx; | |
| 165 | bool mipsN32Abi = false; | |
| 166 | bool nmagic; | |
| 167 | bool noinhibitExec; | |
| 168 | bool nostdlib; | |
| 169 | bool oFormatBinary; | |
| 170 | bool omagic; | |
| 171 | bool optRemarksWithHotness; | |
| 172 | bool pacPlt; | |
| 173 | bool picThunk; | |
| 174 | bool pie; | |
| 175 | bool printGcSections; | |
| 176 | bool printIcfSections; | |
| 177 | bool relocatable; | |
| 178 | bool relrPackDynRelocs; | |
| 179 | bool saveTemps; | |
| 180 | bool singleRoRx; | |
| 181 | bool shared; | |
| 182 | bool isStatic = false; | |
| 183 | bool sysvHash = false; | |
| 184 | bool target1Rel; | |
| 185 | bool trace; | |
| 186 | bool thinLTOEmitImportsFiles; | |
| 187 | bool thinLTOIndexOnly; | |
| 188 | bool tocOptimize; | |
| 189 | bool undefinedVersion; | |
| 190 | bool useAndroidRelrTags = false; | |
| 191 | bool warnBackrefs; | |
| 192 | bool warnCommon; | |
| 193 | bool warnIfuncTextrel; | |
| 194 | bool warnMissingEntry; | |
| 195 | bool warnSymbolOrdering; | |
| 196 | bool writeAddends; | |
| 197 | bool zCombreloc; | |
| 198 | bool zCopyreloc; | |
| 199 | bool zExecstack; | |
| 200 | bool zGlobal; | |
| 201 | bool zHazardplt; | |
| 202 | bool zIfuncNoplt; | |
| 203 | bool zInitfirst; | |
| 204 | bool zInterpose; | |
| 205 | bool zKeepTextSectionPrefix; | |
| 206 | bool zNodefaultlib; | |
| 207 | bool zNodelete; | |
| 208 | bool zNodlopen; | |
| 209 | bool zNow; | |
| 210 | bool zOrigin; | |
| 211 | bool zRelro; | |
| 212 | bool zRodynamic; | |
| 213 | bool zText; | |
| 214 | bool zRetpolineplt; | |
| 215 | bool zWxneeded; | |
| 216 | DiscardPolicy discard; | |
| 217 | ICFLevel icf; | |
| 218 | OrphanHandlingPolicy orphanHandling; | |
| 219 | SortSectionPolicy sortSection; | |
| 220 | StripPolicy strip; | |
| 221 | UnresolvedPolicy unresolvedSymbols; | |
| 222 | Target2Policy target2; | |
| 223 | ARMVFPArgKind armVFPArgs = ARMVFPArgKind::Default; | |
| 224 | BuildIdKind buildId = BuildIdKind::None; | |
| 225 | ELFKind ekind = ELFNoneKind; | |
| 226 | uint16_t defaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL; | |
| 227 | uint16_t emachine = llvm::ELF::EM_NONE; | |
| 228 | llvm::Optional<uint64_t> imageBase; | |
| 229 | uint64_t commonPageSize; | |
| 230 | uint64_t maxPageSize; | |
| 231 | uint64_t mipsGotSize; | |
| 232 | uint64_t zStackSize; | |
| 233 | unsigned ltoPartitions; | |
| 234 | unsigned ltoo; | |
| 235 | unsigned optimize; | |
| 236 | unsigned thinLTOJobs; | |
| 237 | int32_t splitStackAdjustSize; | |
| 225 | 238 | |
| 226 | 239 | // The following config options do not directly correspond to any |
| 227 | 240 | // particualr command line options. |
| 228 | 241 | |
| 229 | 242 | // True if we need to pass through relocations in input files to the |
| 230 | 243 | // output file. Usually false because we consume relocations. |
| 231 | bool CopyRelocs; | |
| 244 | bool copyRelocs; | |
| 232 | 245 | |
| 233 | 246 | // True if the target is ELF64. False if ELF32. |
| 234 | bool Is64; | |
| 247 | bool is64; | |
| 235 | 248 | |
| 236 | 249 | // True if the target is little-endian. False if big-endian. |
| 237 | bool IsLE; | |
| 250 | bool isLE; | |
| 238 | 251 | |
| 239 | // endianness::little if IsLE is true. endianness::big otherwise. | |
| 240 | llvm::support::endianness Endianness; | |
| 252 | // endianness::little if isLE is true. endianness::big otherwise. | |
| 253 | llvm::support::endianness endianness; | |
| 241 | 254 | |
| 242 | 255 | // True if the target is the little-endian MIPS64. |
| 243 | 256 | // |
| ... | ... | @@ -251,10 +264,24 @@ struct Configuration { |
| 251 | 264 | // name whatever that means. A fun hypothesis is that "EL" is short for |
| 252 | 265 | // little-endian written in the little-endian order, but I don't know |
| 253 | 266 | // if that's true.) |
| 254 | bool IsMips64EL; | |
| 267 | bool isMips64EL; | |
| 268 | ||
| 269 | // True if we need to set the DF_STATIC_TLS flag to an output file, | |
| 270 | // which works as a hint to the dynamic loader that the file contains | |
| 271 | // code compiled with the static TLS model. The thread-local variable | |
| 272 | // compiled with the static TLS model is faster but less flexible, and | |
| 273 | // it may not be loaded using dlopen(). | |
| 274 | // | |
| 275 | // We set this flag to true when we see a relocation for the static TLS | |
| 276 | // model. Once this becomes true, it will never become false. | |
| 277 | // | |
| 278 | // Since the flag is updated by multi-threaded code, we use std::atomic. | |
| 279 | // (Writing to a variable is not considered thread-safe even if the | |
| 280 | // variable is boolean and we always set the same value from all threads.) | |
| 281 | std::atomic<bool> hasStaticTlsModel{false}; | |
| 255 | 282 | |
| 256 | 283 | // Holds set of ELF header flags for the target. |
| 257 | uint32_t EFlags = 0; | |
| 284 | uint32_t eflags = 0; | |
| 258 | 285 | |
| 259 | 286 | // The ELF spec defines two types of relocation table entries, RELA and |
| 260 | 287 | // REL. RELA is a triplet of (offset, info, addend) while REL is a |
| ... | ... | @@ -270,23 +297,23 @@ struct Configuration { |
| 270 | 297 | // Each ABI defines its relocation type. IsRela is true if target |
| 271 | 298 | // uses RELA. As far as we know, all 64-bit ABIs are using RELA. A |
| 272 | 299 | // few 32-bit ABIs are using RELA too. |
| 273 | bool IsRela; | |
| 300 | bool isRela; | |
| 274 | 301 | |
| 275 | 302 | // True if we are creating position-independent code. |
| 276 | bool Pic; | |
| 303 | bool isPic; | |
| 277 | 304 | |
| 278 | 305 | // 4 for ELF32, 8 for ELF64. |
| 279 | int Wordsize; | |
| 306 | int wordsize; | |
| 280 | 307 | }; |
| 281 | 308 | |
| 282 | 309 | // The only instance of Configuration struct. |
| 283 | extern Configuration *Config; | |
| 310 | extern Configuration *config; | |
| 284 | 311 | |
| 285 | static inline void errorOrWarn(const Twine &Msg) { | |
| 286 | if (!Config->NoinhibitExec) | |
| 287 | error(Msg); | |
| 312 | static inline void errorOrWarn(const Twine &msg) { | |
| 313 | if (!config->noinhibitExec) | |
| 314 | error(msg); | |
| 288 | 315 | else |
| 289 | warn(Msg); | |
| 316 | warn(msg); | |
| 290 | 317 | } |
| 291 | 318 | } // namespace elf |
| 292 | 319 | } // namespace lld |
deps/lld/ELF/DWARF.cpp+76-56| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- DWARF.cpp ----------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -26,81 +25,102 @@ using namespace llvm::object; |
| 26 | 25 | using namespace lld; |
| 27 | 26 | using namespace lld::elf; |
| 28 | 27 | |
| 29 | template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *Obj) { | |
| 30 | for (InputSectionBase *Sec : Obj->getSections()) { | |
| 31 | if (!Sec) | |
| 28 | template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *obj) { | |
| 29 | for (InputSectionBase *sec : obj->getSections()) { | |
| 30 | if (!sec) | |
| 32 | 31 | continue; |
| 33 | 32 | |
| 34 | if (LLDDWARFSection *M = | |
| 35 | StringSwitch<LLDDWARFSection *>(Sec->Name) | |
| 36 | .Case(".debug_addr", &AddrSection) | |
| 37 | .Case(".debug_gnu_pubnames", &GnuPubNamesSection) | |
| 38 | .Case(".debug_gnu_pubtypes", &GnuPubTypesSection) | |
| 39 | .Case(".debug_info", &InfoSection) | |
| 40 | .Case(".debug_ranges", &RangeSection) | |
| 41 | .Case(".debug_rnglists", &RngListsSection) | |
| 42 | .Case(".debug_line", &LineSection) | |
| 33 | if (LLDDWARFSection *m = | |
| 34 | StringSwitch<LLDDWARFSection *>(sec->name) | |
| 35 | .Case(".debug_addr", &addrSection) | |
| 36 | .Case(".debug_gnu_pubnames", &gnuPubNamesSection) | |
| 37 | .Case(".debug_gnu_pubtypes", &gnuPubTypesSection) | |
| 38 | .Case(".debug_info", &infoSection) | |
| 39 | .Case(".debug_ranges", &rangeSection) | |
| 40 | .Case(".debug_rnglists", &rngListsSection) | |
| 41 | .Case(".debug_line", &lineSection) | |
| 43 | 42 | .Default(nullptr)) { |
| 44 | M->Data = toStringRef(Sec->data()); | |
| 45 | M->Sec = Sec; | |
| 43 | m->Data = toStringRef(sec->data()); | |
| 44 | m->sec = sec; | |
| 46 | 45 | continue; |
| 47 | 46 | } |
| 48 | 47 | |
| 49 | if (Sec->Name == ".debug_abbrev") | |
| 50 | AbbrevSection = toStringRef(Sec->data()); | |
| 51 | else if (Sec->Name == ".debug_str") | |
| 52 | StrSection = toStringRef(Sec->data()); | |
| 53 | else if (Sec->Name == ".debug_line_str") | |
| 54 | LineStringSection = toStringRef(Sec->data()); | |
| 48 | if (sec->name == ".debug_abbrev") | |
| 49 | abbrevSection = toStringRef(sec->data()); | |
| 50 | else if (sec->name == ".debug_str") | |
| 51 | strSection = toStringRef(sec->data()); | |
| 52 | else if (sec->name == ".debug_line_str") | |
| 53 | lineStringSection = toStringRef(sec->data()); | |
| 55 | 54 | } |
| 56 | 55 | } |
| 57 | 56 | |
| 57 | namespace { | |
| 58 | template <class RelTy> struct LLDRelocationResolver { | |
| 59 | // In the ELF ABIs, S sepresents the value of the symbol in the relocation | |
| 60 | // entry. For Rela, the addend is stored as part of the relocation entry. | |
| 61 | static uint64_t resolve(object::RelocationRef ref, uint64_t s, | |
| 62 | uint64_t /* A */) { | |
| 63 | return s + ref.getRawDataRefImpl().p; | |
| 64 | } | |
| 65 | }; | |
| 66 | ||
| 67 | template <class ELFT> struct LLDRelocationResolver<Elf_Rel_Impl<ELFT, false>> { | |
| 68 | // For Rel, the addend A is supplied by the caller. | |
| 69 | static uint64_t resolve(object::RelocationRef /*Ref*/, uint64_t s, | |
| 70 | uint64_t a) { | |
| 71 | return s + a; | |
| 72 | } | |
| 73 | }; | |
| 74 | } // namespace | |
| 75 | ||
| 58 | 76 | // Find if there is a relocation at Pos in Sec. The code is a bit |
| 59 | 77 | // more complicated than usual because we need to pass a section index |
| 60 | 78 | // to llvm since it has no idea about InputSection. |
| 61 | 79 | template <class ELFT> |
| 62 | 80 | template <class RelTy> |
| 63 | 81 | Optional<RelocAddrEntry> |
| 64 | LLDDwarfObj<ELFT>::findAux(const InputSectionBase &Sec, uint64_t Pos, | |
| 65 | ArrayRef<RelTy> Rels) const { | |
| 66 | auto It = std::lower_bound( | |
| 67 | Rels.begin(), Rels.end(), Pos, | |
| 68 | [](const RelTy &A, uint64_t B) { return A.r_offset < B; }); | |
| 69 | if (It == Rels.end() || It->r_offset != Pos) | |
| 82 | LLDDwarfObj<ELFT>::findAux(const InputSectionBase &sec, uint64_t pos, | |
| 83 | ArrayRef<RelTy> rels) const { | |
| 84 | auto it = | |
| 85 | partition_point(rels, [=](const RelTy &a) { return a.r_offset < pos; }); | |
| 86 | if (it == rels.end() || it->r_offset != pos) | |
| 70 | 87 | return None; |
| 71 | const RelTy &Rel = *It; | |
| 88 | const RelTy &rel = *it; | |
| 72 | 89 | |
| 73 | const ObjFile<ELFT> *File = Sec.getFile<ELFT>(); | |
| 74 | uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); | |
| 75 | const typename ELFT::Sym &Sym = File->getELFSyms()[SymIndex]; | |
| 76 | uint32_t SecIndex = File->getSectionIndex(Sym); | |
| 90 | const ObjFile<ELFT> *file = sec.getFile<ELFT>(); | |
| 91 | uint32_t symIndex = rel.getSymbol(config->isMips64EL); | |
| 92 | const typename ELFT::Sym &sym = file->template getELFSyms<ELFT>()[symIndex]; | |
| 93 | uint32_t secIndex = file->getSectionIndex(sym); | |
| 77 | 94 | |
| 78 | // Broken debug info can point to a non-Defined symbol. | |
| 79 | auto *DR = dyn_cast<Defined>(&File->getRelocTargetSym(Rel)); | |
| 80 | if (!DR) { | |
| 81 | RelType Type = Rel.getType(Config->IsMips64EL); | |
| 82 | if (Type != Target->NoneRel) | |
| 83 | error(toString(File) + ": relocation " + lld::toString(Type) + " at 0x" + | |
| 84 | llvm::utohexstr(Rel.r_offset) + " has unsupported target"); | |
| 85 | return None; | |
| 86 | } | |
| 87 | uint64_t Val = DR->Value + getAddend<ELFT>(Rel); | |
| 95 | // An undefined symbol may be a symbol defined in a discarded section. We | |
| 96 | // shall still resolve it. This is important for --gdb-index: the end address | |
| 97 | // offset of an entry in .debug_ranges is relocated. If it is not resolved, | |
| 98 | // its zero value will terminate the decoding of .debug_ranges prematurely. | |
| 99 | Symbol &s = file->getRelocTargetSym(rel); | |
| 100 | uint64_t val = 0; | |
| 101 | if (auto *dr = dyn_cast<Defined>(&s)) { | |
| 102 | val = dr->value; | |
| 88 | 103 | |
| 89 | // FIXME: We should be consistent about always adding the file | |
| 90 | // offset or not. | |
| 91 | if (DR->Section->Flags & ELF::SHF_ALLOC) | |
| 92 | Val += cast<InputSection>(DR->Section)->getOffsetInFile(); | |
| 104 | // FIXME: We should be consistent about always adding the file | |
| 105 | // offset or not. | |
| 106 | if (dr->section->flags & ELF::SHF_ALLOC) | |
| 107 | val += cast<InputSection>(dr->section)->getOffsetInFile(); | |
| 108 | } | |
| 93 | 109 | |
| 94 | return RelocAddrEntry{SecIndex, Val}; | |
| 110 | DataRefImpl d; | |
| 111 | d.p = getAddend<ELFT>(rel); | |
| 112 | return RelocAddrEntry{secIndex, RelocationRef(d, nullptr), | |
| 113 | val, Optional<object::RelocationRef>(), | |
| 114 | 0, LLDRelocationResolver<RelTy>::resolve}; | |
| 95 | 115 | } |
| 96 | 116 | |
| 97 | 117 | template <class ELFT> |
| 98 | Optional<RelocAddrEntry> LLDDwarfObj<ELFT>::find(const llvm::DWARFSection &S, | |
| 99 | uint64_t Pos) const { | |
| 100 | auto &Sec = static_cast<const LLDDWARFSection &>(S); | |
| 101 | if (Sec.Sec->AreRelocsRela) | |
| 102 | return findAux(*Sec.Sec, Pos, Sec.Sec->template relas<ELFT>()); | |
| 103 | return findAux(*Sec.Sec, Pos, Sec.Sec->template rels<ELFT>()); | |
| 118 | Optional<RelocAddrEntry> LLDDwarfObj<ELFT>::find(const llvm::DWARFSection &s, | |
| 119 | uint64_t pos) const { | |
| 120 | auto &sec = static_cast<const LLDDWARFSection &>(s); | |
| 121 | if (sec.sec->areRelocsRela) | |
| 122 | return findAux(*sec.sec, pos, sec.sec->template relas<ELFT>()); | |
| 123 | return findAux(*sec.sec, pos, sec.sec->template rels<ELFT>()); | |
| 104 | 124 | } |
| 105 | 125 | |
| 106 | 126 | template class elf::LLDDwarfObj<ELF32LE>; |
deps/lld/ELF/DWARF.h+32-33| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- DWARF.h -----------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===-------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -21,70 +20,70 @@ namespace elf { |
| 21 | 20 | class InputSection; |
| 22 | 21 | |
| 23 | 22 | struct LLDDWARFSection final : public llvm::DWARFSection { |
| 24 | InputSectionBase *Sec = nullptr; | |
| 23 | InputSectionBase *sec = nullptr; | |
| 25 | 24 | }; |
| 26 | 25 | |
| 27 | 26 | template <class ELFT> class LLDDwarfObj final : public llvm::DWARFObject { |
| 28 | 27 | public: |
| 29 | explicit LLDDwarfObj(ObjFile<ELFT> *Obj); | |
| 28 | explicit LLDDwarfObj(ObjFile<ELFT> *obj); | |
| 30 | 29 | |
| 31 | 30 | void forEachInfoSections( |
| 32 | llvm::function_ref<void(const llvm::DWARFSection &)> F) const override { | |
| 33 | F(InfoSection); | |
| 31 | llvm::function_ref<void(const llvm::DWARFSection &)> f) const override { | |
| 32 | f(infoSection); | |
| 34 | 33 | } |
| 35 | 34 | |
| 36 | 35 | const llvm::DWARFSection &getRangeSection() const override { |
| 37 | return RangeSection; | |
| 36 | return rangeSection; | |
| 38 | 37 | } |
| 39 | 38 | |
| 40 | 39 | const llvm::DWARFSection &getRnglistsSection() const override { |
| 41 | return RngListsSection; | |
| 40 | return rngListsSection; | |
| 42 | 41 | } |
| 43 | 42 | |
| 44 | 43 | const llvm::DWARFSection &getLineSection() const override { |
| 45 | return LineSection; | |
| 44 | return lineSection; | |
| 46 | 45 | } |
| 47 | 46 | |
| 48 | 47 | const llvm::DWARFSection &getAddrSection() const override { |
| 49 | return AddrSection; | |
| 48 | return addrSection; | |
| 50 | 49 | } |
| 51 | 50 | |
| 52 | 51 | const llvm::DWARFSection &getGnuPubNamesSection() const override { |
| 53 | return GnuPubNamesSection; | |
| 52 | return gnuPubNamesSection; | |
| 54 | 53 | } |
| 55 | 54 | |
| 56 | 55 | const llvm::DWARFSection &getGnuPubTypesSection() const override { |
| 57 | return GnuPubTypesSection; | |
| 56 | return gnuPubTypesSection; | |
| 58 | 57 | } |
| 59 | 58 | |
| 60 | 59 | StringRef getFileName() const override { return ""; } |
| 61 | StringRef getAbbrevSection() const override { return AbbrevSection; } | |
| 62 | StringRef getStringSection() const override { return StrSection; } | |
| 63 | StringRef getLineStringSection() const override { return LineStringSection; } | |
| 60 | StringRef getAbbrevSection() const override { return abbrevSection; } | |
| 61 | StringRef getStringSection() const override { return strSection; } | |
| 62 | StringRef getLineStringSection() const override { return lineStringSection; } | |
| 64 | 63 | |
| 65 | 64 | bool isLittleEndian() const override { |
| 66 | 65 | return ELFT::TargetEndianness == llvm::support::little; |
| 67 | 66 | } |
| 68 | 67 | |
| 69 | llvm::Optional<llvm::RelocAddrEntry> find(const llvm::DWARFSection &Sec, | |
| 70 | uint64_t Pos) const override; | |
| 68 | llvm::Optional<llvm::RelocAddrEntry> find(const llvm::DWARFSection &sec, | |
| 69 | uint64_t pos) const override; | |
| 71 | 70 | |
| 72 | 71 | private: |
| 73 | 72 | template <class RelTy> |
| 74 | llvm::Optional<llvm::RelocAddrEntry> findAux(const InputSectionBase &Sec, | |
| 75 | uint64_t Pos, | |
| 76 | ArrayRef<RelTy> Rels) const; | |
| 77 | ||
| 78 | LLDDWARFSection GnuPubNamesSection; | |
| 79 | LLDDWARFSection GnuPubTypesSection; | |
| 80 | LLDDWARFSection InfoSection; | |
| 81 | LLDDWARFSection RangeSection; | |
| 82 | LLDDWARFSection RngListsSection; | |
| 83 | LLDDWARFSection LineSection; | |
| 84 | LLDDWARFSection AddrSection; | |
| 85 | StringRef AbbrevSection; | |
| 86 | StringRef StrSection; | |
| 87 | StringRef LineStringSection; | |
| 73 | llvm::Optional<llvm::RelocAddrEntry> findAux(const InputSectionBase &sec, | |
| 74 | uint64_t pos, | |
| 75 | ArrayRef<RelTy> rels) const; | |
| 76 | ||
| 77 | LLDDWARFSection gnuPubNamesSection; | |
| 78 | LLDDWARFSection gnuPubTypesSection; | |
| 79 | LLDDWARFSection infoSection; | |
| 80 | LLDDWARFSection rangeSection; | |
| 81 | LLDDWARFSection rngListsSection; | |
| 82 | LLDDWARFSection lineSection; | |
| 83 | LLDDWARFSection addrSection; | |
| 84 | StringRef abbrevSection; | |
| 85 | StringRef strSection; | |
| 86 | StringRef lineStringSection; | |
| 88 | 87 | }; |
| 89 | 88 | |
| 90 | 89 | } // namespace elf |
deps/lld/ELF/Driver.cpp+1080-818| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Driver.cpp ---------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -25,7 +24,6 @@ |
| 25 | 24 | |
| 26 | 25 | #include "Driver.h" |
| 27 | 26 | #include "Config.h" |
| 28 | #include "Filesystem.h" | |
| 29 | 27 | #include "ICF.h" |
| 30 | 28 | #include "InputFiles.h" |
| 31 | 29 | #include "InputSection.h" |
| ... | ... | @@ -41,6 +39,7 @@ |
| 41 | 39 | #include "lld/Common/Args.h" |
| 42 | 40 | #include "lld/Common/Driver.h" |
| 43 | 41 | #include "lld/Common/ErrorHandler.h" |
| 42 | #include "lld/Common/Filesystem.h" | |
| 44 | 43 | #include "lld/Common/Memory.h" |
| 45 | 44 | #include "lld/Common/Strings.h" |
| 46 | 45 | #include "lld/Common/TargetOptionsCommandFlags.h" |
| ... | ... | @@ -51,6 +50,7 @@ |
| 51 | 50 | #include "llvm/ADT/StringSwitch.h" |
| 52 | 51 | #include "llvm/Support/CommandLine.h" |
| 53 | 52 | #include "llvm/Support/Compression.h" |
| 53 | #include "llvm/Support/GlobPattern.h" | |
| 54 | 54 | #include "llvm/Support/LEB128.h" |
| 55 | 55 | #include "llvm/Support/Path.h" |
| 56 | 56 | #include "llvm/Support/TarWriter.h" |
| ... | ... | @@ -68,44 +68,49 @@ using namespace llvm::support; |
| 68 | 68 | using namespace lld; |
| 69 | 69 | using namespace lld::elf; |
| 70 | 70 | |
| 71 | Configuration *elf::Config; | |
| 72 | LinkerDriver *elf::Driver; | |
| 71 | Configuration *elf::config; | |
| 72 | LinkerDriver *elf::driver; | |
| 73 | 73 | |
| 74 | static void setConfigs(opt::InputArgList &Args); | |
| 74 | static void setConfigs(opt::InputArgList &args); | |
| 75 | static void readConfigs(opt::InputArgList &args); | |
| 75 | 76 | |
| 76 | bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly, | |
| 77 | raw_ostream &Error) { | |
| 78 | errorHandler().LogName = args::getFilenameWithoutExe(Args[0]); | |
| 79 | errorHandler().ErrorLimitExceededMsg = | |
| 77 | bool elf::link(ArrayRef<const char *> args, bool canExitEarly, | |
| 78 | raw_ostream &error) { | |
| 79 | errorHandler().logName = args::getFilenameWithoutExe(args[0]); | |
| 80 | errorHandler().errorLimitExceededMsg = | |
| 80 | 81 | "too many errors emitted, stopping now (use " |
| 81 | 82 | "-error-limit=0 to see all errors)"; |
| 82 | errorHandler().ErrorOS = &Error; | |
| 83 | errorHandler().ExitEarly = CanExitEarly; | |
| 84 | errorHandler().ColorDiagnostics = Error.has_colors(); | |
| 83 | errorHandler().errorOS = &error; | |
| 84 | errorHandler().exitEarly = canExitEarly; | |
| 85 | errorHandler().colorDiagnostics = error.has_colors(); | |
| 86 | ||
| 87 | inputSections.clear(); | |
| 88 | outputSections.clear(); | |
| 89 | binaryFiles.clear(); | |
| 90 | bitcodeFiles.clear(); | |
| 91 | objectFiles.clear(); | |
| 92 | sharedFiles.clear(); | |
| 93 | ||
| 94 | config = make<Configuration>(); | |
| 95 | driver = make<LinkerDriver>(); | |
| 96 | script = make<LinkerScript>(); | |
| 97 | symtab = make<SymbolTable>(); | |
| 85 | 98 | |
| 86 | InputSections.clear(); | |
| 87 | OutputSections.clear(); | |
| 88 | BinaryFiles.clear(); | |
| 89 | BitcodeFiles.clear(); | |
| 90 | ObjectFiles.clear(); | |
| 91 | SharedFiles.clear(); | |
| 99 | tar = nullptr; | |
| 100 | memset(&in, 0, sizeof(in)); | |
| 92 | 101 | |
| 93 | Config = make<Configuration>(); | |
| 94 | Driver = make<LinkerDriver>(); | |
| 95 | Script = make<LinkerScript>(); | |
| 96 | Symtab = make<SymbolTable>(); | |
| 102 | partitions = {Partition()}; | |
| 97 | 103 | |
| 98 | Tar = nullptr; | |
| 99 | memset(&In, 0, sizeof(In)); | |
| 104 | SharedFile::vernauxNum = 0; | |
| 100 | 105 | |
| 101 | Config->ProgName = Args[0]; | |
| 106 | config->progName = args[0]; | |
| 102 | 107 | |
| 103 | Driver->main(Args); | |
| 108 | driver->main(args); | |
| 104 | 109 | |
| 105 | 110 | // Exit immediately if we don't need to return to the caller. |
| 106 | 111 | // This saves time because the overhead of calling destructors |
| 107 | 112 | // for all globally-allocated objects is not negligible. |
| 108 | if (CanExitEarly) | |
| 113 | if (canExitEarly) | |
| 109 | 114 | exitLld(errorCount() ? 1 : 0); |
| 110 | 115 | |
| 111 | 116 | freeArena(); |
| ... | ... | @@ -113,16 +118,16 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly, |
| 113 | 118 | } |
| 114 | 119 | |
| 115 | 120 | // Parses a linker -m option. |
| 116 | static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) { | |
| 117 | uint8_t OSABI = 0; | |
| 118 | StringRef S = Emul; | |
| 119 | if (S.endswith("_fbsd")) { | |
| 120 | S = S.drop_back(5); | |
| 121 | OSABI = ELFOSABI_FREEBSD; | |
| 121 | static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef emul) { | |
| 122 | uint8_t osabi = 0; | |
| 123 | StringRef s = emul; | |
| 124 | if (s.endswith("_fbsd")) { | |
| 125 | s = s.drop_back(5); | |
| 126 | osabi = ELFOSABI_FREEBSD; | |
| 122 | 127 | } |
| 123 | 128 | |
| 124 | std::pair<ELFKind, uint16_t> Ret = | |
| 125 | StringSwitch<std::pair<ELFKind, uint16_t>>(S) | |
| 129 | std::pair<ELFKind, uint16_t> ret = | |
| 130 | StringSwitch<std::pair<ELFKind, uint16_t>>(s) | |
| 126 | 131 | .Cases("aarch64elf", "aarch64linux", "aarch64_elf64_le_vec", |
| 127 | 132 | {ELF64LEKind, EM_AARCH64}) |
| 128 | 133 | .Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM}) |
| ... | ... | @@ -141,91 +146,101 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) { |
| 141 | 146 | .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU}) |
| 142 | 147 | .Default({ELFNoneKind, EM_NONE}); |
| 143 | 148 | |
| 144 | if (Ret.first == ELFNoneKind) | |
| 145 | error("unknown emulation: " + Emul); | |
| 146 | return std::make_tuple(Ret.first, Ret.second, OSABI); | |
| 149 | if (ret.first == ELFNoneKind) | |
| 150 | error("unknown emulation: " + emul); | |
| 151 | return std::make_tuple(ret.first, ret.second, osabi); | |
| 147 | 152 | } |
| 148 | 153 | |
| 149 | 154 | // Returns slices of MB by parsing MB as an archive file. |
| 150 | 155 | // Each slice consists of a member file in the archive. |
| 151 | 156 | std::vector<std::pair<MemoryBufferRef, uint64_t>> static getArchiveMembers( |
| 152 | MemoryBufferRef MB) { | |
| 153 | std::unique_ptr<Archive> File = | |
| 154 | CHECK(Archive::create(MB), | |
| 155 | MB.getBufferIdentifier() + ": failed to parse archive"); | |
| 156 | ||
| 157 | std::vector<std::pair<MemoryBufferRef, uint64_t>> V; | |
| 158 | Error Err = Error::success(); | |
| 159 | bool AddToTar = File->isThin() && Tar; | |
| 160 | for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) { | |
| 161 | Archive::Child C = | |
| 162 | CHECK(COrErr, MB.getBufferIdentifier() + | |
| 157 | MemoryBufferRef mb) { | |
| 158 | std::unique_ptr<Archive> file = | |
| 159 | CHECK(Archive::create(mb), | |
| 160 | mb.getBufferIdentifier() + ": failed to parse archive"); | |
| 161 | ||
| 162 | std::vector<std::pair<MemoryBufferRef, uint64_t>> v; | |
| 163 | Error err = Error::success(); | |
| 164 | bool addToTar = file->isThin() && tar; | |
| 165 | for (const ErrorOr<Archive::Child> &cOrErr : file->children(err)) { | |
| 166 | Archive::Child c = | |
| 167 | CHECK(cOrErr, mb.getBufferIdentifier() + | |
| 163 | 168 | ": could not get the child of the archive"); |
| 164 | MemoryBufferRef MBRef = | |
| 165 | CHECK(C.getMemoryBufferRef(), | |
| 166 | MB.getBufferIdentifier() + | |
| 169 | MemoryBufferRef mbref = | |
| 170 | CHECK(c.getMemoryBufferRef(), | |
| 171 | mb.getBufferIdentifier() + | |
| 167 | 172 | ": could not get the buffer for a child of the archive"); |
| 168 | if (AddToTar) | |
| 169 | Tar->append(relativeToRoot(check(C.getFullName())), MBRef.getBuffer()); | |
| 170 | V.push_back(std::make_pair(MBRef, C.getChildOffset())); | |
| 173 | if (addToTar) | |
| 174 | tar->append(relativeToRoot(check(c.getFullName())), mbref.getBuffer()); | |
| 175 | v.push_back(std::make_pair(mbref, c.getChildOffset())); | |
| 171 | 176 | } |
| 172 | if (Err) | |
| 173 | fatal(MB.getBufferIdentifier() + ": Archive::children failed: " + | |
| 174 | toString(std::move(Err))); | |
| 177 | if (err) | |
| 178 | fatal(mb.getBufferIdentifier() + ": Archive::children failed: " + | |
| 179 | toString(std::move(err))); | |
| 175 | 180 | |
| 176 | 181 | // Take ownership of memory buffers created for members of thin archives. |
| 177 | for (std::unique_ptr<MemoryBuffer> &MB : File->takeThinBuffers()) | |
| 178 | make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); | |
| 182 | for (std::unique_ptr<MemoryBuffer> &mb : file->takeThinBuffers()) | |
| 183 | make<std::unique_ptr<MemoryBuffer>>(std::move(mb)); | |
| 179 | 184 | |
| 180 | return V; | |
| 185 | return v; | |
| 181 | 186 | } |
| 182 | 187 | |
| 183 | 188 | // Opens a file and create a file object. Path has to be resolved already. |
| 184 | void LinkerDriver::addFile(StringRef Path, bool WithLOption) { | |
| 189 | void LinkerDriver::addFile(StringRef path, bool withLOption) { | |
| 185 | 190 | using namespace sys::fs; |
| 186 | 191 | |
| 187 | Optional<MemoryBufferRef> Buffer = readFile(Path); | |
| 188 | if (!Buffer.hasValue()) | |
| 192 | Optional<MemoryBufferRef> buffer = readFile(path); | |
| 193 | if (!buffer.hasValue()) | |
| 189 | 194 | return; |
| 190 | MemoryBufferRef MBRef = *Buffer; | |
| 195 | MemoryBufferRef mbref = *buffer; | |
| 191 | 196 | |
| 192 | if (Config->FormatBinary) { | |
| 193 | Files.push_back(make<BinaryFile>(MBRef)); | |
| 197 | if (config->formatBinary) { | |
| 198 | files.push_back(make<BinaryFile>(mbref)); | |
| 194 | 199 | return; |
| 195 | 200 | } |
| 196 | 201 | |
| 197 | switch (identify_magic(MBRef.getBuffer())) { | |
| 202 | switch (identify_magic(mbref.getBuffer())) { | |
| 198 | 203 | case file_magic::unknown: |
| 199 | readLinkerScript(MBRef); | |
| 204 | readLinkerScript(mbref); | |
| 200 | 205 | return; |
| 201 | 206 | case file_magic::archive: { |
| 202 | 207 | // Handle -whole-archive. |
| 203 | if (InWholeArchive) { | |
| 204 | for (const auto &P : getArchiveMembers(MBRef)) | |
| 205 | Files.push_back(createObjectFile(P.first, Path, P.second)); | |
| 208 | if (inWholeArchive) { | |
| 209 | for (const auto &p : getArchiveMembers(mbref)) | |
| 210 | files.push_back(createObjectFile(p.first, path, p.second)); | |
| 206 | 211 | return; |
| 207 | 212 | } |
| 208 | 213 | |
| 209 | std::unique_ptr<Archive> File = | |
| 210 | CHECK(Archive::create(MBRef), Path + ": failed to parse archive"); | |
| 214 | std::unique_ptr<Archive> file = | |
| 215 | CHECK(Archive::create(mbref), path + ": failed to parse archive"); | |
| 211 | 216 | |
| 212 | 217 | // If an archive file has no symbol table, it is likely that a user |
| 213 | 218 | // is attempting LTO and using a default ar command that doesn't |
| 214 | 219 | // understand the LLVM bitcode file. It is a pretty common error, so |
| 215 | 220 | // we'll handle it as if it had a symbol table. |
| 216 | if (!File->isEmpty() && !File->hasSymbolTable()) { | |
| 217 | for (const auto &P : getArchiveMembers(MBRef)) | |
| 218 | Files.push_back(make<LazyObjFile>(P.first, Path, P.second)); | |
| 221 | if (!file->isEmpty() && !file->hasSymbolTable()) { | |
| 222 | // Check if all members are bitcode files. If not, ignore, which is the | |
| 223 | // default action without the LTO hack described above. | |
| 224 | for (const std::pair<MemoryBufferRef, uint64_t> &p : | |
| 225 | getArchiveMembers(mbref)) | |
| 226 | if (identify_magic(p.first.getBuffer()) != file_magic::bitcode) { | |
| 227 | error(path + ": archive has no index; run ranlib to add one"); | |
| 228 | return; | |
| 229 | } | |
| 230 | ||
| 231 | for (const std::pair<MemoryBufferRef, uint64_t> &p : | |
| 232 | getArchiveMembers(mbref)) | |
| 233 | files.push_back(make<LazyObjFile>(p.first, path, p.second)); | |
| 219 | 234 | return; |
| 220 | 235 | } |
| 221 | 236 | |
| 222 | 237 | // Handle the regular case. |
| 223 | Files.push_back(make<ArchiveFile>(std::move(File))); | |
| 238 | files.push_back(make<ArchiveFile>(std::move(file))); | |
| 224 | 239 | return; |
| 225 | 240 | } |
| 226 | 241 | case file_magic::elf_shared_object: |
| 227 | if (Config->Static || Config->Relocatable) { | |
| 228 | error("attempted static link of dynamic object " + Path); | |
| 242 | if (config->isStatic || config->relocatable) { | |
| 243 | error("attempted static link of dynamic object " + path); | |
| 229 | 244 | return; |
| 230 | 245 | } |
| 231 | 246 | |
| ... | ... | @@ -239,27 +254,27 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { |
| 239 | 254 | // If a file was specified by -lfoo, the directory part is not |
| 240 | 255 | // significant, as a user did not specify it. This behavior is |
| 241 | 256 | // compatible with GNU. |
| 242 | Files.push_back( | |
| 243 | createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path)); | |
| 257 | files.push_back( | |
| 258 | make<SharedFile>(mbref, withLOption ? path::filename(path) : path)); | |
| 244 | 259 | return; |
| 245 | 260 | case file_magic::bitcode: |
| 246 | 261 | case file_magic::elf_relocatable: |
| 247 | if (InLib) | |
| 248 | Files.push_back(make<LazyObjFile>(MBRef, "", 0)); | |
| 262 | if (inLib) | |
| 263 | files.push_back(make<LazyObjFile>(mbref, "", 0)); | |
| 249 | 264 | else |
| 250 | Files.push_back(createObjectFile(MBRef)); | |
| 265 | files.push_back(createObjectFile(mbref)); | |
| 251 | 266 | break; |
| 252 | 267 | default: |
| 253 | error(Path + ": unknown file type"); | |
| 268 | error(path + ": unknown file type"); | |
| 254 | 269 | } |
| 255 | 270 | } |
| 256 | 271 | |
| 257 | 272 | // Add a given library by searching it from input search paths. |
| 258 | void LinkerDriver::addLibrary(StringRef Name) { | |
| 259 | if (Optional<std::string> Path = searchLibrary(Name)) | |
| 260 | addFile(*Path, /*WithLOption=*/true); | |
| 273 | void LinkerDriver::addLibrary(StringRef name) { | |
| 274 | if (Optional<std::string> path = searchLibrary(name)) | |
| 275 | addFile(*path, /*withLOption=*/true); | |
| 261 | 276 | else |
| 262 | error("unable to find library -l" + Name); | |
| 277 | error("unable to find library -l" + name); | |
| 263 | 278 | } |
| 264 | 279 | |
| 265 | 280 | // This function is called on startup. We need this for LTO since |
| ... | ... | @@ -278,102 +293,117 @@ static void initLLVM() { |
| 278 | 293 | static void checkOptions() { |
| 279 | 294 | // The MIPS ABI as of 2016 does not support the GNU-style symbol lookup |
| 280 | 295 | // table which is a relatively new feature. |
| 281 | if (Config->EMachine == EM_MIPS && Config->GnuHash) | |
| 296 | if (config->emachine == EM_MIPS && config->gnuHash) | |
| 282 | 297 | error("the .gnu.hash section is not compatible with the MIPS target"); |
| 283 | 298 | |
| 284 | if (Config->FixCortexA53Errata843419 && Config->EMachine != EM_AARCH64) | |
| 299 | if (config->fixCortexA53Errata843419 && config->emachine != EM_AARCH64) | |
| 285 | 300 | error("--fix-cortex-a53-843419 is only supported on AArch64 targets"); |
| 286 | 301 | |
| 287 | if (Config->TocOptimize && Config->EMachine != EM_PPC64) | |
| 302 | if (config->tocOptimize && config->emachine != EM_PPC64) | |
| 288 | 303 | error("--toc-optimize is only supported on the PowerPC64 target"); |
| 289 | 304 | |
| 290 | if (Config->Pie && Config->Shared) | |
| 305 | if (config->pie && config->shared) | |
| 291 | 306 | error("-shared and -pie may not be used together"); |
| 292 | 307 | |
| 293 | if (!Config->Shared && !Config->FilterList.empty()) | |
| 308 | if (!config->shared && !config->filterList.empty()) | |
| 294 | 309 | error("-F may not be used without -shared"); |
| 295 | 310 | |
| 296 | if (!Config->Shared && !Config->AuxiliaryList.empty()) | |
| 311 | if (!config->shared && !config->auxiliaryList.empty()) | |
| 297 | 312 | error("-f may not be used without -shared"); |
| 298 | 313 | |
| 299 | if (!Config->Relocatable && !Config->DefineCommon) | |
| 314 | if (!config->relocatable && !config->defineCommon) | |
| 300 | 315 | error("-no-define-common not supported in non relocatable output"); |
| 301 | 316 | |
| 302 | if (Config->Relocatable) { | |
| 303 | if (Config->Shared) | |
| 317 | if (config->zText && config->zIfuncNoplt) | |
| 318 | error("-z text and -z ifunc-noplt may not be used together"); | |
| 319 | ||
| 320 | if (config->relocatable) { | |
| 321 | if (config->shared) | |
| 304 | 322 | error("-r and -shared may not be used together"); |
| 305 | if (Config->GcSections) | |
| 323 | if (config->gcSections) | |
| 306 | 324 | error("-r and --gc-sections may not be used together"); |
| 307 | if (Config->GdbIndex) | |
| 325 | if (config->gdbIndex) | |
| 308 | 326 | error("-r and --gdb-index may not be used together"); |
| 309 | if (Config->ICF != ICFLevel::None) | |
| 327 | if (config->icf != ICFLevel::None) | |
| 310 | 328 | error("-r and --icf may not be used together"); |
| 311 | if (Config->Pie) | |
| 329 | if (config->pie) | |
| 312 | 330 | error("-r and -pie may not be used together"); |
| 313 | 331 | } |
| 314 | 332 | |
| 315 | if (Config->ExecuteOnly) { | |
| 316 | if (Config->EMachine != EM_AARCH64) | |
| 333 | if (config->executeOnly) { | |
| 334 | if (config->emachine != EM_AARCH64) | |
| 317 | 335 | error("-execute-only is only supported on AArch64 targets"); |
| 318 | 336 | |
| 319 | if (Config->SingleRoRx && !Script->HasSectionsCommand) | |
| 337 | if (config->singleRoRx && !script->hasSectionsCommand) | |
| 320 | 338 | error("-execute-only and -no-rosegment cannot be used together"); |
| 321 | 339 | } |
| 340 | ||
| 341 | if (config->zRetpolineplt && config->requireCET) | |
| 342 | error("--require-cet may not be used with -z retpolineplt"); | |
| 343 | ||
| 344 | if (config->emachine != EM_AARCH64) { | |
| 345 | if (config->pacPlt) | |
| 346 | error("--pac-plt only supported on AArch64"); | |
| 347 | if (config->forceBTI) | |
| 348 | error("--force-bti only supported on AArch64"); | |
| 349 | } | |
| 322 | 350 | } |
| 323 | 351 | |
| 324 | static const char *getReproduceOption(opt::InputArgList &Args) { | |
| 325 | if (auto *Arg = Args.getLastArg(OPT_reproduce)) | |
| 326 | return Arg->getValue(); | |
| 352 | static const char *getReproduceOption(opt::InputArgList &args) { | |
| 353 | if (auto *arg = args.getLastArg(OPT_reproduce)) | |
| 354 | return arg->getValue(); | |
| 327 | 355 | return getenv("LLD_REPRODUCE"); |
| 328 | 356 | } |
| 329 | 357 | |
| 330 | static bool hasZOption(opt::InputArgList &Args, StringRef Key) { | |
| 331 | for (auto *Arg : Args.filtered(OPT_z)) | |
| 332 | if (Key == Arg->getValue()) | |
| 358 | static bool hasZOption(opt::InputArgList &args, StringRef key) { | |
| 359 | for (auto *arg : args.filtered(OPT_z)) | |
| 360 | if (key == arg->getValue()) | |
| 333 | 361 | return true; |
| 334 | 362 | return false; |
| 335 | 363 | } |
| 336 | 364 | |
| 337 | static bool getZFlag(opt::InputArgList &Args, StringRef K1, StringRef K2, | |
| 365 | static bool getZFlag(opt::InputArgList &args, StringRef k1, StringRef k2, | |
| 338 | 366 | bool Default) { |
| 339 | for (auto *Arg : Args.filtered_reverse(OPT_z)) { | |
| 340 | if (K1 == Arg->getValue()) | |
| 367 | for (auto *arg : args.filtered_reverse(OPT_z)) { | |
| 368 | if (k1 == arg->getValue()) | |
| 341 | 369 | return true; |
| 342 | if (K2 == Arg->getValue()) | |
| 370 | if (k2 == arg->getValue()) | |
| 343 | 371 | return false; |
| 344 | 372 | } |
| 345 | 373 | return Default; |
| 346 | 374 | } |
| 347 | 375 | |
| 348 | static bool isKnownZFlag(StringRef S) { | |
| 349 | return S == "combreloc" || S == "copyreloc" || S == "defs" || | |
| 350 | S == "execstack" || S == "global" || S == "hazardplt" || | |
| 351 | S == "initfirst" || S == "interpose" || | |
| 352 | S == "keep-text-section-prefix" || S == "lazy" || S == "muldefs" || | |
| 353 | S == "nocombreloc" || S == "nocopyreloc" || S == "nodefaultlib" || | |
| 354 | S == "nodelete" || S == "nodlopen" || S == "noexecstack" || | |
| 355 | S == "nokeep-text-section-prefix" || S == "norelro" || S == "notext" || | |
| 356 | S == "now" || S == "origin" || S == "relro" || S == "retpolineplt" || | |
| 357 | S == "rodynamic" || S == "text" || S == "wxneeded" || | |
| 358 | S.startswith("max-page-size=") || S.startswith("stack-size="); | |
| 376 | static bool isKnownZFlag(StringRef s) { | |
| 377 | return s == "combreloc" || s == "copyreloc" || s == "defs" || | |
| 378 | s == "execstack" || s == "global" || s == "hazardplt" || | |
| 379 | s == "ifunc-noplt" || s == "initfirst" || s == "interpose" || | |
| 380 | s == "keep-text-section-prefix" || s == "lazy" || s == "muldefs" || | |
| 381 | s == "nocombreloc" || s == "nocopyreloc" || s == "nodefaultlib" || | |
| 382 | s == "nodelete" || s == "nodlopen" || s == "noexecstack" || | |
| 383 | s == "nokeep-text-section-prefix" || s == "norelro" || s == "notext" || | |
| 384 | s == "now" || s == "origin" || s == "relro" || s == "retpolineplt" || | |
| 385 | s == "rodynamic" || s == "text" || s == "wxneeded" || | |
| 386 | s.startswith("common-page-size") || s.startswith("max-page-size=") || | |
| 387 | s.startswith("stack-size="); | |
| 359 | 388 | } |
| 360 | 389 | |
| 361 | 390 | // Report an error for an unknown -z option. |
| 362 | static void checkZOptions(opt::InputArgList &Args) { | |
| 363 | for (auto *Arg : Args.filtered(OPT_z)) | |
| 364 | if (!isKnownZFlag(Arg->getValue())) | |
| 365 | error("unknown -z value: " + StringRef(Arg->getValue())); | |
| 391 | static void checkZOptions(opt::InputArgList &args) { | |
| 392 | for (auto *arg : args.filtered(OPT_z)) | |
| 393 | if (!isKnownZFlag(arg->getValue())) | |
| 394 | error("unknown -z value: " + StringRef(arg->getValue())); | |
| 366 | 395 | } |
| 367 | 396 | |
| 368 | void LinkerDriver::main(ArrayRef<const char *> ArgsArr) { | |
| 369 | ELFOptTable Parser; | |
| 370 | opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); | |
| 397 | void LinkerDriver::main(ArrayRef<const char *> argsArr) { | |
| 398 | ELFOptTable parser; | |
| 399 | opt::InputArgList args = parser.parse(argsArr.slice(1)); | |
| 371 | 400 | |
| 372 | 401 | // Interpret this flag early because error() depends on them. |
| 373 | errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20); | |
| 402 | errorHandler().errorLimit = args::getInteger(args, OPT_error_limit, 20); | |
| 403 | checkZOptions(args); | |
| 374 | 404 | |
| 375 | 405 | // Handle -help |
| 376 | if (Args.hasArg(OPT_help)) { | |
| 406 | if (args.hasArg(OPT_help)) { | |
| 377 | 407 | printHelp(); |
| 378 | 408 | return; |
| 379 | 409 | } |
| ... | ... | @@ -393,213 +423,218 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr) { |
| 393 | 423 | // lot of "configure" scripts out there that are generated by old version |
| 394 | 424 | // of Libtool. We cannot convince every software developer to migrate to |
| 395 | 425 | // the latest version and re-generate scripts. So we have this hack. |
| 396 | if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version)) | |
| 426 | if (args.hasArg(OPT_v) || args.hasArg(OPT_version)) | |
| 397 | 427 | message(getLLDVersion() + " (compatible with GNU linkers)"); |
| 398 | 428 | |
| 399 | if (const char *Path = getReproduceOption(Args)) { | |
| 429 | if (const char *path = getReproduceOption(args)) { | |
| 400 | 430 | // Note that --reproduce is a debug option so you can ignore it |
| 401 | 431 | // if you are trying to understand the whole picture of the code. |
| 402 | Expected<std::unique_ptr<TarWriter>> ErrOrWriter = | |
| 403 | TarWriter::create(Path, path::stem(Path)); | |
| 404 | if (ErrOrWriter) { | |
| 405 | Tar = std::move(*ErrOrWriter); | |
| 406 | Tar->append("response.txt", createResponseFile(Args)); | |
| 407 | Tar->append("version.txt", getLLDVersion() + "\n"); | |
| 432 | Expected<std::unique_ptr<TarWriter>> errOrWriter = | |
| 433 | TarWriter::create(path, path::stem(path)); | |
| 434 | if (errOrWriter) { | |
| 435 | tar = std::move(*errOrWriter); | |
| 436 | tar->append("response.txt", createResponseFile(args)); | |
| 437 | tar->append("version.txt", getLLDVersion() + "\n"); | |
| 408 | 438 | } else { |
| 409 | error("--reproduce: " + toString(ErrOrWriter.takeError())); | |
| 439 | error("--reproduce: " + toString(errOrWriter.takeError())); | |
| 410 | 440 | } |
| 411 | 441 | } |
| 412 | 442 | |
| 413 | readConfigs(Args); | |
| 414 | checkZOptions(Args); | |
| 443 | readConfigs(args); | |
| 415 | 444 | |
| 416 | 445 | // The behavior of -v or --version is a bit strange, but this is |
| 417 | 446 | // needed for compatibility with GNU linkers. |
| 418 | if (Args.hasArg(OPT_v) && !Args.hasArg(OPT_INPUT)) | |
| 447 | if (args.hasArg(OPT_v) && !args.hasArg(OPT_INPUT)) | |
| 419 | 448 | return; |
| 420 | if (Args.hasArg(OPT_version)) | |
| 449 | if (args.hasArg(OPT_version)) | |
| 421 | 450 | return; |
| 422 | 451 | |
| 423 | 452 | initLLVM(); |
| 424 | createFiles(Args); | |
| 453 | createFiles(args); | |
| 425 | 454 | if (errorCount()) |
| 426 | 455 | return; |
| 427 | 456 | |
| 428 | 457 | inferMachineType(); |
| 429 | setConfigs(Args); | |
| 458 | setConfigs(args); | |
| 430 | 459 | checkOptions(); |
| 431 | 460 | if (errorCount()) |
| 432 | 461 | return; |
| 433 | 462 | |
| 434 | switch (Config->EKind) { | |
| 463 | // The Target instance handles target-specific stuff, such as applying | |
| 464 | // relocations or writing a PLT section. It also contains target-dependent | |
| 465 | // values such as a default image base address. | |
| 466 | target = getTarget(); | |
| 467 | ||
| 468 | switch (config->ekind) { | |
| 435 | 469 | case ELF32LEKind: |
| 436 | link<ELF32LE>(Args); | |
| 470 | link<ELF32LE>(args); | |
| 437 | 471 | return; |
| 438 | 472 | case ELF32BEKind: |
| 439 | link<ELF32BE>(Args); | |
| 473 | link<ELF32BE>(args); | |
| 440 | 474 | return; |
| 441 | 475 | case ELF64LEKind: |
| 442 | link<ELF64LE>(Args); | |
| 476 | link<ELF64LE>(args); | |
| 443 | 477 | return; |
| 444 | 478 | case ELF64BEKind: |
| 445 | link<ELF64BE>(Args); | |
| 479 | link<ELF64BE>(args); | |
| 446 | 480 | return; |
| 447 | 481 | default: |
| 448 | 482 | llvm_unreachable("unknown Config->EKind"); |
| 449 | 483 | } |
| 450 | 484 | } |
| 451 | 485 | |
| 452 | static std::string getRpath(opt::InputArgList &Args) { | |
| 453 | std::vector<StringRef> V = args::getStrings(Args, OPT_rpath); | |
| 454 | return llvm::join(V.begin(), V.end(), ":"); | |
| 486 | static std::string getRpath(opt::InputArgList &args) { | |
| 487 | std::vector<StringRef> v = args::getStrings(args, OPT_rpath); | |
| 488 | return llvm::join(v.begin(), v.end(), ":"); | |
| 455 | 489 | } |
| 456 | 490 | |
| 457 | 491 | // Determines what we should do if there are remaining unresolved |
| 458 | 492 | // symbols after the name resolution. |
| 459 | static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) { | |
| 460 | UnresolvedPolicy ErrorOrWarn = Args.hasFlag(OPT_error_unresolved_symbols, | |
| 493 | static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &args) { | |
| 494 | UnresolvedPolicy errorOrWarn = args.hasFlag(OPT_error_unresolved_symbols, | |
| 461 | 495 | OPT_warn_unresolved_symbols, true) |
| 462 | 496 | ? UnresolvedPolicy::ReportError |
| 463 | 497 | : UnresolvedPolicy::Warn; |
| 464 | 498 | |
| 465 | 499 | // Process the last of -unresolved-symbols, -no-undefined or -z defs. |
| 466 | for (auto *Arg : llvm::reverse(Args)) { | |
| 467 | switch (Arg->getOption().getID()) { | |
| 500 | for (auto *arg : llvm::reverse(args)) { | |
| 501 | switch (arg->getOption().getID()) { | |
| 468 | 502 | case OPT_unresolved_symbols: { |
| 469 | StringRef S = Arg->getValue(); | |
| 470 | if (S == "ignore-all" || S == "ignore-in-object-files") | |
| 503 | StringRef s = arg->getValue(); | |
| 504 | if (s == "ignore-all" || s == "ignore-in-object-files") | |
| 471 | 505 | return UnresolvedPolicy::Ignore; |
| 472 | if (S == "ignore-in-shared-libs" || S == "report-all") | |
| 473 | return ErrorOrWarn; | |
| 474 | error("unknown --unresolved-symbols value: " + S); | |
| 506 | if (s == "ignore-in-shared-libs" || s == "report-all") | |
| 507 | return errorOrWarn; | |
| 508 | error("unknown --unresolved-symbols value: " + s); | |
| 475 | 509 | continue; |
| 476 | 510 | } |
| 477 | 511 | case OPT_no_undefined: |
| 478 | return ErrorOrWarn; | |
| 512 | return errorOrWarn; | |
| 479 | 513 | case OPT_z: |
| 480 | if (StringRef(Arg->getValue()) == "defs") | |
| 481 | return ErrorOrWarn; | |
| 514 | if (StringRef(arg->getValue()) == "defs") | |
| 515 | return errorOrWarn; | |
| 482 | 516 | continue; |
| 483 | 517 | } |
| 484 | 518 | } |
| 485 | 519 | |
| 486 | 520 | // -shared implies -unresolved-symbols=ignore-all because missing |
| 487 | 521 | // symbols are likely to be resolved at runtime using other DSOs. |
| 488 | if (Config->Shared) | |
| 522 | if (config->shared) | |
| 489 | 523 | return UnresolvedPolicy::Ignore; |
| 490 | return ErrorOrWarn; | |
| 524 | return errorOrWarn; | |
| 491 | 525 | } |
| 492 | 526 | |
| 493 | static Target2Policy getTarget2(opt::InputArgList &Args) { | |
| 494 | StringRef S = Args.getLastArgValue(OPT_target2, "got-rel"); | |
| 495 | if (S == "rel") | |
| 527 | static Target2Policy getTarget2(opt::InputArgList &args) { | |
| 528 | StringRef s = args.getLastArgValue(OPT_target2, "got-rel"); | |
| 529 | if (s == "rel") | |
| 496 | 530 | return Target2Policy::Rel; |
| 497 | if (S == "abs") | |
| 531 | if (s == "abs") | |
| 498 | 532 | return Target2Policy::Abs; |
| 499 | if (S == "got-rel") | |
| 533 | if (s == "got-rel") | |
| 500 | 534 | return Target2Policy::GotRel; |
| 501 | error("unknown --target2 option: " + S); | |
| 535 | error("unknown --target2 option: " + s); | |
| 502 | 536 | return Target2Policy::GotRel; |
| 503 | 537 | } |
| 504 | 538 | |
| 505 | static bool isOutputFormatBinary(opt::InputArgList &Args) { | |
| 506 | StringRef S = Args.getLastArgValue(OPT_oformat, "elf"); | |
| 507 | if (S == "binary") | |
| 539 | static bool isOutputFormatBinary(opt::InputArgList &args) { | |
| 540 | StringRef s = args.getLastArgValue(OPT_oformat, "elf"); | |
| 541 | if (s == "binary") | |
| 508 | 542 | return true; |
| 509 | if (!S.startswith("elf")) | |
| 510 | error("unknown --oformat value: " + S); | |
| 543 | if (!s.startswith("elf")) | |
| 544 | error("unknown --oformat value: " + s); | |
| 511 | 545 | return false; |
| 512 | 546 | } |
| 513 | 547 | |
| 514 | static DiscardPolicy getDiscard(opt::InputArgList &Args) { | |
| 515 | if (Args.hasArg(OPT_relocatable)) | |
| 548 | static DiscardPolicy getDiscard(opt::InputArgList &args) { | |
| 549 | if (args.hasArg(OPT_relocatable)) | |
| 516 | 550 | return DiscardPolicy::None; |
| 517 | 551 | |
| 518 | auto *Arg = | |
| 519 | Args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none); | |
| 520 | if (!Arg) | |
| 552 | auto *arg = | |
| 553 | args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none); | |
| 554 | if (!arg) | |
| 521 | 555 | return DiscardPolicy::Default; |
| 522 | if (Arg->getOption().getID() == OPT_discard_all) | |
| 556 | if (arg->getOption().getID() == OPT_discard_all) | |
| 523 | 557 | return DiscardPolicy::All; |
| 524 | if (Arg->getOption().getID() == OPT_discard_locals) | |
| 558 | if (arg->getOption().getID() == OPT_discard_locals) | |
| 525 | 559 | return DiscardPolicy::Locals; |
| 526 | 560 | return DiscardPolicy::None; |
| 527 | 561 | } |
| 528 | 562 | |
| 529 | static StringRef getDynamicLinker(opt::InputArgList &Args) { | |
| 530 | auto *Arg = Args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker); | |
| 531 | if (!Arg || Arg->getOption().getID() == OPT_no_dynamic_linker) | |
| 563 | static StringRef getDynamicLinker(opt::InputArgList &args) { | |
| 564 | auto *arg = args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker); | |
| 565 | if (!arg || arg->getOption().getID() == OPT_no_dynamic_linker) | |
| 532 | 566 | return ""; |
| 533 | return Arg->getValue(); | |
| 567 | return arg->getValue(); | |
| 534 | 568 | } |
| 535 | 569 | |
| 536 | static ICFLevel getICF(opt::InputArgList &Args) { | |
| 537 | auto *Arg = Args.getLastArg(OPT_icf_none, OPT_icf_safe, OPT_icf_all); | |
| 538 | if (!Arg || Arg->getOption().getID() == OPT_icf_none) | |
| 570 | static ICFLevel getICF(opt::InputArgList &args) { | |
| 571 | auto *arg = args.getLastArg(OPT_icf_none, OPT_icf_safe, OPT_icf_all); | |
| 572 | if (!arg || arg->getOption().getID() == OPT_icf_none) | |
| 539 | 573 | return ICFLevel::None; |
| 540 | if (Arg->getOption().getID() == OPT_icf_safe) | |
| 574 | if (arg->getOption().getID() == OPT_icf_safe) | |
| 541 | 575 | return ICFLevel::Safe; |
| 542 | 576 | return ICFLevel::All; |
| 543 | 577 | } |
| 544 | 578 | |
| 545 | static StripPolicy getStrip(opt::InputArgList &Args) { | |
| 546 | if (Args.hasArg(OPT_relocatable)) | |
| 579 | static StripPolicy getStrip(opt::InputArgList &args) { | |
| 580 | if (args.hasArg(OPT_relocatable)) | |
| 547 | 581 | return StripPolicy::None; |
| 548 | 582 | |
| 549 | auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug); | |
| 550 | if (!Arg) | |
| 583 | auto *arg = args.getLastArg(OPT_strip_all, OPT_strip_debug); | |
| 584 | if (!arg) | |
| 551 | 585 | return StripPolicy::None; |
| 552 | if (Arg->getOption().getID() == OPT_strip_all) | |
| 586 | if (arg->getOption().getID() == OPT_strip_all) | |
| 553 | 587 | return StripPolicy::All; |
| 554 | 588 | return StripPolicy::Debug; |
| 555 | 589 | } |
| 556 | 590 | |
| 557 | static uint64_t parseSectionAddress(StringRef S, const opt::Arg &Arg) { | |
| 558 | uint64_t VA = 0; | |
| 559 | if (S.startswith("0x")) | |
| 560 | S = S.drop_front(2); | |
| 561 | if (!to_integer(S, VA, 16)) | |
| 562 | error("invalid argument: " + toString(Arg)); | |
| 563 | return VA; | |
| 591 | static uint64_t parseSectionAddress(StringRef s, opt::InputArgList &args, | |
| 592 | const opt::Arg &arg) { | |
| 593 | uint64_t va = 0; | |
| 594 | if (s.startswith("0x")) | |
| 595 | s = s.drop_front(2); | |
| 596 | if (!to_integer(s, va, 16)) | |
| 597 | error("invalid argument: " + arg.getAsString(args)); | |
| 598 | return va; | |
| 564 | 599 | } |
| 565 | 600 | |
| 566 | static StringMap<uint64_t> getSectionStartMap(opt::InputArgList &Args) { | |
| 567 | StringMap<uint64_t> Ret; | |
| 568 | for (auto *Arg : Args.filtered(OPT_section_start)) { | |
| 569 | StringRef Name; | |
| 570 | StringRef Addr; | |
| 571 | std::tie(Name, Addr) = StringRef(Arg->getValue()).split('='); | |
| 572 | Ret[Name] = parseSectionAddress(Addr, *Arg); | |
| 601 | static StringMap<uint64_t> getSectionStartMap(opt::InputArgList &args) { | |
| 602 | StringMap<uint64_t> ret; | |
| 603 | for (auto *arg : args.filtered(OPT_section_start)) { | |
| 604 | StringRef name; | |
| 605 | StringRef addr; | |
| 606 | std::tie(name, addr) = StringRef(arg->getValue()).split('='); | |
| 607 | ret[name] = parseSectionAddress(addr, args, *arg); | |
| 573 | 608 | } |
| 574 | 609 | |
| 575 | if (auto *Arg = Args.getLastArg(OPT_Ttext)) | |
| 576 | Ret[".text"] = parseSectionAddress(Arg->getValue(), *Arg); | |
| 577 | if (auto *Arg = Args.getLastArg(OPT_Tdata)) | |
| 578 | Ret[".data"] = parseSectionAddress(Arg->getValue(), *Arg); | |
| 579 | if (auto *Arg = Args.getLastArg(OPT_Tbss)) | |
| 580 | Ret[".bss"] = parseSectionAddress(Arg->getValue(), *Arg); | |
| 581 | return Ret; | |
| 610 | if (auto *arg = args.getLastArg(OPT_Ttext)) | |
| 611 | ret[".text"] = parseSectionAddress(arg->getValue(), args, *arg); | |
| 612 | if (auto *arg = args.getLastArg(OPT_Tdata)) | |
| 613 | ret[".data"] = parseSectionAddress(arg->getValue(), args, *arg); | |
| 614 | if (auto *arg = args.getLastArg(OPT_Tbss)) | |
| 615 | ret[".bss"] = parseSectionAddress(arg->getValue(), args, *arg); | |
| 616 | return ret; | |
| 582 | 617 | } |
| 583 | 618 | |
| 584 | static SortSectionPolicy getSortSection(opt::InputArgList &Args) { | |
| 585 | StringRef S = Args.getLastArgValue(OPT_sort_section); | |
| 586 | if (S == "alignment") | |
| 619 | static SortSectionPolicy getSortSection(opt::InputArgList &args) { | |
| 620 | StringRef s = args.getLastArgValue(OPT_sort_section); | |
| 621 | if (s == "alignment") | |
| 587 | 622 | return SortSectionPolicy::Alignment; |
| 588 | if (S == "name") | |
| 623 | if (s == "name") | |
| 589 | 624 | return SortSectionPolicy::Name; |
| 590 | if (!S.empty()) | |
| 591 | error("unknown --sort-section rule: " + S); | |
| 625 | if (!s.empty()) | |
| 626 | error("unknown --sort-section rule: " + s); | |
| 592 | 627 | return SortSectionPolicy::Default; |
| 593 | 628 | } |
| 594 | 629 | |
| 595 | static OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &Args) { | |
| 596 | StringRef S = Args.getLastArgValue(OPT_orphan_handling, "place"); | |
| 597 | if (S == "warn") | |
| 630 | static OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &args) { | |
| 631 | StringRef s = args.getLastArgValue(OPT_orphan_handling, "place"); | |
| 632 | if (s == "warn") | |
| 598 | 633 | return OrphanHandlingPolicy::Warn; |
| 599 | if (S == "error") | |
| 634 | if (s == "error") | |
| 600 | 635 | return OrphanHandlingPolicy::Error; |
| 601 | if (S != "place") | |
| 602 | error("unknown --orphan-handling mode: " + S); | |
| 636 | if (s != "place") | |
| 637 | error("unknown --orphan-handling mode: " + s); | |
| 603 | 638 | return OrphanHandlingPolicy::Place; |
| 604 | 639 | } |
| 605 | 640 | |
| ... | ... | @@ -607,388 +642,412 @@ static OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &Args) { |
| 607 | 642 | // synonym for "sha1" because all our hash functions including |
| 608 | 643 | // -build-id=sha1 are actually tree hashes for performance reasons. |
| 609 | 644 | static std::pair<BuildIdKind, std::vector<uint8_t>> |
| 610 | getBuildId(opt::InputArgList &Args) { | |
| 611 | auto *Arg = Args.getLastArg(OPT_build_id, OPT_build_id_eq); | |
| 612 | if (!Arg) | |
| 645 | getBuildId(opt::InputArgList &args) { | |
| 646 | auto *arg = args.getLastArg(OPT_build_id, OPT_build_id_eq); | |
| 647 | if (!arg) | |
| 613 | 648 | return {BuildIdKind::None, {}}; |
| 614 | 649 | |
| 615 | if (Arg->getOption().getID() == OPT_build_id) | |
| 650 | if (arg->getOption().getID() == OPT_build_id) | |
| 616 | 651 | return {BuildIdKind::Fast, {}}; |
| 617 | 652 | |
| 618 | StringRef S = Arg->getValue(); | |
| 619 | if (S == "fast") | |
| 653 | StringRef s = arg->getValue(); | |
| 654 | if (s == "fast") | |
| 620 | 655 | return {BuildIdKind::Fast, {}}; |
| 621 | if (S == "md5") | |
| 656 | if (s == "md5") | |
| 622 | 657 | return {BuildIdKind::Md5, {}}; |
| 623 | if (S == "sha1" || S == "tree") | |
| 658 | if (s == "sha1" || s == "tree") | |
| 624 | 659 | return {BuildIdKind::Sha1, {}}; |
| 625 | if (S == "uuid") | |
| 660 | if (s == "uuid") | |
| 626 | 661 | return {BuildIdKind::Uuid, {}}; |
| 627 | if (S.startswith("0x")) | |
| 628 | return {BuildIdKind::Hexstring, parseHex(S.substr(2))}; | |
| 662 | if (s.startswith("0x")) | |
| 663 | return {BuildIdKind::Hexstring, parseHex(s.substr(2))}; | |
| 629 | 664 | |
| 630 | if (S != "none") | |
| 631 | error("unknown --build-id style: " + S); | |
| 665 | if (s != "none") | |
| 666 | error("unknown --build-id style: " + s); | |
| 632 | 667 | return {BuildIdKind::None, {}}; |
| 633 | 668 | } |
| 634 | 669 | |
| 635 | static std::pair<bool, bool> getPackDynRelocs(opt::InputArgList &Args) { | |
| 636 | StringRef S = Args.getLastArgValue(OPT_pack_dyn_relocs, "none"); | |
| 637 | if (S == "android") | |
| 670 | static std::pair<bool, bool> getPackDynRelocs(opt::InputArgList &args) { | |
| 671 | StringRef s = args.getLastArgValue(OPT_pack_dyn_relocs, "none"); | |
| 672 | if (s == "android") | |
| 638 | 673 | return {true, false}; |
| 639 | if (S == "relr") | |
| 674 | if (s == "relr") | |
| 640 | 675 | return {false, true}; |
| 641 | if (S == "android+relr") | |
| 676 | if (s == "android+relr") | |
| 642 | 677 | return {true, true}; |
| 643 | 678 | |
| 644 | if (S != "none") | |
| 645 | error("unknown -pack-dyn-relocs format: " + S); | |
| 679 | if (s != "none") | |
| 680 | error("unknown -pack-dyn-relocs format: " + s); | |
| 646 | 681 | return {false, false}; |
| 647 | 682 | } |
| 648 | 683 | |
| 649 | static void readCallGraph(MemoryBufferRef MB) { | |
| 684 | static void readCallGraph(MemoryBufferRef mb) { | |
| 650 | 685 | // Build a map from symbol name to section |
| 651 | DenseMap<StringRef, Symbol *> Map; | |
| 652 | for (InputFile *File : ObjectFiles) | |
| 653 | for (Symbol *Sym : File->getSymbols()) | |
| 654 | Map[Sym->getName()] = Sym; | |
| 655 | ||
| 656 | auto FindSection = [&](StringRef Name) -> InputSectionBase * { | |
| 657 | Symbol *Sym = Map.lookup(Name); | |
| 658 | if (!Sym) { | |
| 659 | if (Config->WarnSymbolOrdering) | |
| 660 | warn(MB.getBufferIdentifier() + ": no such symbol: " + Name); | |
| 686 | DenseMap<StringRef, Symbol *> map; | |
| 687 | for (InputFile *file : objectFiles) | |
| 688 | for (Symbol *sym : file->getSymbols()) | |
| 689 | map[sym->getName()] = sym; | |
| 690 | ||
| 691 | auto findSection = [&](StringRef name) -> InputSectionBase * { | |
| 692 | Symbol *sym = map.lookup(name); | |
| 693 | if (!sym) { | |
| 694 | if (config->warnSymbolOrdering) | |
| 695 | warn(mb.getBufferIdentifier() + ": no such symbol: " + name); | |
| 661 | 696 | return nullptr; |
| 662 | 697 | } |
| 663 | maybeWarnUnorderableSymbol(Sym); | |
| 698 | maybeWarnUnorderableSymbol(sym); | |
| 664 | 699 | |
| 665 | if (Defined *DR = dyn_cast_or_null<Defined>(Sym)) | |
| 666 | return dyn_cast_or_null<InputSectionBase>(DR->Section); | |
| 700 | if (Defined *dr = dyn_cast_or_null<Defined>(sym)) | |
| 701 | return dyn_cast_or_null<InputSectionBase>(dr->section); | |
| 667 | 702 | return nullptr; |
| 668 | 703 | }; |
| 669 | 704 | |
| 670 | for (StringRef Line : args::getLines(MB)) { | |
| 671 | SmallVector<StringRef, 3> Fields; | |
| 672 | Line.split(Fields, ' '); | |
| 673 | uint64_t Count; | |
| 705 | for (StringRef line : args::getLines(mb)) { | |
| 706 | SmallVector<StringRef, 3> fields; | |
| 707 | line.split(fields, ' '); | |
| 708 | uint64_t count; | |
| 674 | 709 | |
| 675 | if (Fields.size() != 3 || !to_integer(Fields[2], Count)) { | |
| 676 | error(MB.getBufferIdentifier() + ": parse error"); | |
| 710 | if (fields.size() != 3 || !to_integer(fields[2], count)) { | |
| 711 | error(mb.getBufferIdentifier() + ": parse error"); | |
| 677 | 712 | return; |
| 678 | 713 | } |
| 679 | 714 | |
| 680 | if (InputSectionBase *From = FindSection(Fields[0])) | |
| 681 | if (InputSectionBase *To = FindSection(Fields[1])) | |
| 682 | Config->CallGraphProfile[std::make_pair(From, To)] += Count; | |
| 715 | if (InputSectionBase *from = findSection(fields[0])) | |
| 716 | if (InputSectionBase *to = findSection(fields[1])) | |
| 717 | config->callGraphProfile[std::make_pair(from, to)] += count; | |
| 683 | 718 | } |
| 684 | 719 | } |
| 685 | 720 | |
| 686 | 721 | template <class ELFT> static void readCallGraphsFromObjectFiles() { |
| 687 | for (auto File : ObjectFiles) { | |
| 688 | auto *Obj = cast<ObjFile<ELFT>>(File); | |
| 722 | for (auto file : objectFiles) { | |
| 723 | auto *obj = cast<ObjFile<ELFT>>(file); | |
| 689 | 724 | |
| 690 | for (const Elf_CGProfile_Impl<ELFT> &CGPE : Obj->CGProfile) { | |
| 691 | auto *FromSym = dyn_cast<Defined>(&Obj->getSymbol(CGPE.cgp_from)); | |
| 692 | auto *ToSym = dyn_cast<Defined>(&Obj->getSymbol(CGPE.cgp_to)); | |
| 693 | if (!FromSym || !ToSym) | |
| 725 | for (const Elf_CGProfile_Impl<ELFT> &cgpe : obj->cgProfile) { | |
| 726 | auto *fromSym = dyn_cast<Defined>(&obj->getSymbol(cgpe.cgp_from)); | |
| 727 | auto *toSym = dyn_cast<Defined>(&obj->getSymbol(cgpe.cgp_to)); | |
| 728 | if (!fromSym || !toSym) | |
| 694 | 729 | continue; |
| 695 | 730 | |
| 696 | auto *From = dyn_cast_or_null<InputSectionBase>(FromSym->Section); | |
| 697 | auto *To = dyn_cast_or_null<InputSectionBase>(ToSym->Section); | |
| 698 | if (From && To) | |
| 699 | Config->CallGraphProfile[{From, To}] += CGPE.cgp_weight; | |
| 731 | auto *from = dyn_cast_or_null<InputSectionBase>(fromSym->section); | |
| 732 | auto *to = dyn_cast_or_null<InputSectionBase>(toSym->section); | |
| 733 | if (from && to) | |
| 734 | config->callGraphProfile[{from, to}] += cgpe.cgp_weight; | |
| 700 | 735 | } |
| 701 | 736 | } |
| 702 | 737 | } |
| 703 | 738 | |
| 704 | static bool getCompressDebugSections(opt::InputArgList &Args) { | |
| 705 | StringRef S = Args.getLastArgValue(OPT_compress_debug_sections, "none"); | |
| 706 | if (S == "none") | |
| 739 | static bool getCompressDebugSections(opt::InputArgList &args) { | |
| 740 | StringRef s = args.getLastArgValue(OPT_compress_debug_sections, "none"); | |
| 741 | if (s == "none") | |
| 707 | 742 | return false; |
| 708 | if (S != "zlib") | |
| 709 | error("unknown --compress-debug-sections value: " + S); | |
| 743 | if (s != "zlib") | |
| 744 | error("unknown --compress-debug-sections value: " + s); | |
| 710 | 745 | if (!zlib::isAvailable()) |
| 711 | 746 | error("--compress-debug-sections: zlib is not available"); |
| 712 | 747 | return true; |
| 713 | 748 | } |
| 714 | 749 | |
| 715 | static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &Args, | |
| 716 | unsigned Id) { | |
| 717 | auto *Arg = Args.getLastArg(Id); | |
| 718 | if (!Arg) | |
| 750 | static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &args, | |
| 751 | unsigned id) { | |
| 752 | auto *arg = args.getLastArg(id); | |
| 753 | if (!arg) | |
| 719 | 754 | return {"", ""}; |
| 720 | 755 | |
| 721 | StringRef S = Arg->getValue(); | |
| 722 | std::pair<StringRef, StringRef> Ret = S.split(';'); | |
| 723 | if (Ret.second.empty()) | |
| 724 | error(Arg->getSpelling() + " expects 'old;new' format, but got " + S); | |
| 725 | return Ret; | |
| 756 | StringRef s = arg->getValue(); | |
| 757 | std::pair<StringRef, StringRef> ret = s.split(';'); | |
| 758 | if (ret.second.empty()) | |
| 759 | error(arg->getSpelling() + " expects 'old;new' format, but got " + s); | |
| 760 | return ret; | |
| 726 | 761 | } |
| 727 | 762 | |
| 728 | 763 | // Parse the symbol ordering file and warn for any duplicate entries. |
| 729 | static std::vector<StringRef> getSymbolOrderingFile(MemoryBufferRef MB) { | |
| 730 | SetVector<StringRef> Names; | |
| 731 | for (StringRef S : args::getLines(MB)) | |
| 732 | if (!Names.insert(S) && Config->WarnSymbolOrdering) | |
| 733 | warn(MB.getBufferIdentifier() + ": duplicate ordered symbol: " + S); | |
| 764 | static std::vector<StringRef> getSymbolOrderingFile(MemoryBufferRef mb) { | |
| 765 | SetVector<StringRef> names; | |
| 766 | for (StringRef s : args::getLines(mb)) | |
| 767 | if (!names.insert(s) && config->warnSymbolOrdering) | |
| 768 | warn(mb.getBufferIdentifier() + ": duplicate ordered symbol: " + s); | |
| 734 | 769 | |
| 735 | return Names.takeVector(); | |
| 770 | return names.takeVector(); | |
| 736 | 771 | } |
| 737 | 772 | |
| 738 | static void parseClangOption(StringRef Opt, const Twine &Msg) { | |
| 739 | std::string Err; | |
| 740 | raw_string_ostream OS(Err); | |
| 773 | static void parseClangOption(StringRef opt, const Twine &msg) { | |
| 774 | std::string err; | |
| 775 | raw_string_ostream os(err); | |
| 741 | 776 | |
| 742 | const char *Argv[] = {Config->ProgName.data(), Opt.data()}; | |
| 743 | if (cl::ParseCommandLineOptions(2, Argv, "", &OS)) | |
| 777 | const char *argv[] = {config->progName.data(), opt.data()}; | |
| 778 | if (cl::ParseCommandLineOptions(2, argv, "", &os)) | |
| 744 | 779 | return; |
| 745 | OS.flush(); | |
| 746 | error(Msg + ": " + StringRef(Err).trim()); | |
| 780 | os.flush(); | |
| 781 | error(msg + ": " + StringRef(err).trim()); | |
| 747 | 782 | } |
| 748 | 783 | |
| 749 | 784 | // Initializes Config members by the command line options. |
| 750 | void LinkerDriver::readConfigs(opt::InputArgList &Args) { | |
| 751 | errorHandler().Verbose = Args.hasArg(OPT_verbose); | |
| 752 | errorHandler().FatalWarnings = | |
| 753 | Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); | |
| 754 | ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); | |
| 755 | ||
| 756 | Config->AllowMultipleDefinition = | |
| 757 | Args.hasFlag(OPT_allow_multiple_definition, | |
| 785 | static void readConfigs(opt::InputArgList &args) { | |
| 786 | errorHandler().verbose = args.hasArg(OPT_verbose); | |
| 787 | errorHandler().fatalWarnings = | |
| 788 | args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); | |
| 789 | errorHandler().vsDiagnostics = | |
| 790 | args.hasArg(OPT_visual_studio_diagnostics_format, false); | |
| 791 | threadsEnabled = args.hasFlag(OPT_threads, OPT_no_threads, true); | |
| 792 | ||
| 793 | config->allowMultipleDefinition = | |
| 794 | args.hasFlag(OPT_allow_multiple_definition, | |
| 758 | 795 | OPT_no_allow_multiple_definition, false) || |
| 759 | hasZOption(Args, "muldefs"); | |
| 760 | Config->AuxiliaryList = args::getStrings(Args, OPT_auxiliary); | |
| 761 | Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic); | |
| 762 | Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions); | |
| 763 | Config->CheckSections = | |
| 764 | Args.hasFlag(OPT_check_sections, OPT_no_check_sections, true); | |
| 765 | Config->Chroot = Args.getLastArgValue(OPT_chroot); | |
| 766 | Config->CompressDebugSections = getCompressDebugSections(Args); | |
| 767 | Config->Cref = Args.hasFlag(OPT_cref, OPT_no_cref, false); | |
| 768 | Config->DefineCommon = Args.hasFlag(OPT_define_common, OPT_no_define_common, | |
| 769 | !Args.hasArg(OPT_relocatable)); | |
| 770 | Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true); | |
| 771 | Config->DisableVerify = Args.hasArg(OPT_disable_verify); | |
| 772 | Config->Discard = getDiscard(Args); | |
| 773 | Config->DwoDir = Args.getLastArgValue(OPT_plugin_opt_dwo_dir_eq); | |
| 774 | Config->DynamicLinker = getDynamicLinker(Args); | |
| 775 | Config->EhFrameHdr = | |
| 776 | Args.hasFlag(OPT_eh_frame_hdr, OPT_no_eh_frame_hdr, false); | |
| 777 | Config->EmitLLVM = Args.hasArg(OPT_plugin_opt_emit_llvm, false); | |
| 778 | Config->EmitRelocs = Args.hasArg(OPT_emit_relocs); | |
| 779 | Config->CallGraphProfileSort = Args.hasFlag( | |
| 796 | hasZOption(args, "muldefs"); | |
| 797 | config->allowShlibUndefined = | |
| 798 | args.hasFlag(OPT_allow_shlib_undefined, OPT_no_allow_shlib_undefined, | |
| 799 | args.hasArg(OPT_shared)); | |
| 800 | config->auxiliaryList = args::getStrings(args, OPT_auxiliary); | |
| 801 | config->bsymbolic = args.hasArg(OPT_Bsymbolic); | |
| 802 | config->bsymbolicFunctions = args.hasArg(OPT_Bsymbolic_functions); | |
| 803 | config->checkSections = | |
| 804 | args.hasFlag(OPT_check_sections, OPT_no_check_sections, true); | |
| 805 | config->chroot = args.getLastArgValue(OPT_chroot); | |
| 806 | config->compressDebugSections = getCompressDebugSections(args); | |
| 807 | config->cref = args.hasFlag(OPT_cref, OPT_no_cref, false); | |
| 808 | config->defineCommon = args.hasFlag(OPT_define_common, OPT_no_define_common, | |
| 809 | !args.hasArg(OPT_relocatable)); | |
| 810 | config->demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true); | |
| 811 | config->dependentLibraries = args.hasFlag(OPT_dependent_libraries, OPT_no_dependent_libraries, true); | |
| 812 | config->disableVerify = args.hasArg(OPT_disable_verify); | |
| 813 | config->discard = getDiscard(args); | |
| 814 | config->dwoDir = args.getLastArgValue(OPT_plugin_opt_dwo_dir_eq); | |
| 815 | config->dynamicLinker = getDynamicLinker(args); | |
| 816 | config->ehFrameHdr = | |
| 817 | args.hasFlag(OPT_eh_frame_hdr, OPT_no_eh_frame_hdr, false); | |
| 818 | config->emitLLVM = args.hasArg(OPT_plugin_opt_emit_llvm, false); | |
| 819 | config->emitRelocs = args.hasArg(OPT_emit_relocs); | |
| 820 | config->callGraphProfileSort = args.hasFlag( | |
| 780 | 821 | OPT_call_graph_profile_sort, OPT_no_call_graph_profile_sort, true); |
| 781 | Config->EnableNewDtags = | |
| 782 | Args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true); | |
| 783 | Config->Entry = Args.getLastArgValue(OPT_entry); | |
| 784 | Config->ExecuteOnly = | |
| 785 | Args.hasFlag(OPT_execute_only, OPT_no_execute_only, false); | |
| 786 | Config->ExportDynamic = | |
| 787 | Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false); | |
| 788 | Config->FilterList = args::getStrings(Args, OPT_filter); | |
| 789 | Config->Fini = Args.getLastArgValue(OPT_fini, "_fini"); | |
| 790 | Config->FixCortexA53Errata843419 = Args.hasArg(OPT_fix_cortex_a53_843419); | |
| 791 | Config->GcSections = Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false); | |
| 792 | Config->GnuUnique = Args.hasFlag(OPT_gnu_unique, OPT_no_gnu_unique, true); | |
| 793 | Config->GdbIndex = Args.hasFlag(OPT_gdb_index, OPT_no_gdb_index, false); | |
| 794 | Config->ICF = getICF(Args); | |
| 795 | Config->IgnoreDataAddressEquality = | |
| 796 | Args.hasArg(OPT_ignore_data_address_equality); | |
| 797 | Config->IgnoreFunctionAddressEquality = | |
| 798 | Args.hasArg(OPT_ignore_function_address_equality); | |
| 799 | Config->Init = Args.getLastArgValue(OPT_init, "_init"); | |
| 800 | Config->LTOAAPipeline = Args.getLastArgValue(OPT_lto_aa_pipeline); | |
| 801 | Config->LTODebugPassManager = Args.hasArg(OPT_lto_debug_pass_manager); | |
| 802 | Config->LTONewPassManager = Args.hasArg(OPT_lto_new_pass_manager); | |
| 803 | Config->LTONewPmPasses = Args.getLastArgValue(OPT_lto_newpm_passes); | |
| 804 | Config->LTOO = args::getInteger(Args, OPT_lto_O, 2); | |
| 805 | Config->LTOObjPath = Args.getLastArgValue(OPT_plugin_opt_obj_path_eq); | |
| 806 | Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1); | |
| 807 | Config->LTOSampleProfile = Args.getLastArgValue(OPT_lto_sample_profile); | |
| 808 | Config->MapFile = Args.getLastArgValue(OPT_Map); | |
| 809 | Config->MipsGotSize = args::getInteger(Args, OPT_mips_got_size, 0xfff0); | |
| 810 | Config->MergeArmExidx = | |
| 811 | Args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true); | |
| 812 | Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec); | |
| 813 | Config->Nostdlib = Args.hasArg(OPT_nostdlib); | |
| 814 | Config->OFormatBinary = isOutputFormatBinary(Args); | |
| 815 | Config->Omagic = Args.hasFlag(OPT_omagic, OPT_no_omagic, false); | |
| 816 | Config->OptRemarksFilename = Args.getLastArgValue(OPT_opt_remarks_filename); | |
| 817 | Config->OptRemarksWithHotness = Args.hasArg(OPT_opt_remarks_with_hotness); | |
| 818 | Config->Optimize = args::getInteger(Args, OPT_O, 1); | |
| 819 | Config->OrphanHandling = getOrphanHandling(Args); | |
| 820 | Config->OutputFile = Args.getLastArgValue(OPT_o); | |
| 821 | Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false); | |
| 822 | Config->PrintIcfSections = | |
| 823 | Args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false); | |
| 824 | Config->PrintGcSections = | |
| 825 | Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false); | |
| 826 | Config->Rpath = getRpath(Args); | |
| 827 | Config->Relocatable = Args.hasArg(OPT_relocatable); | |
| 828 | Config->SaveTemps = Args.hasArg(OPT_save_temps); | |
| 829 | Config->SearchPaths = args::getStrings(Args, OPT_library_path); | |
| 830 | Config->SectionStartMap = getSectionStartMap(Args); | |
| 831 | Config->Shared = Args.hasArg(OPT_shared); | |
| 832 | Config->SingleRoRx = Args.hasArg(OPT_no_rosegment); | |
| 833 | Config->SoName = Args.getLastArgValue(OPT_soname); | |
| 834 | Config->SortSection = getSortSection(Args); | |
| 835 | Config->SplitStackAdjustSize = args::getInteger(Args, OPT_split_stack_adjust_size, 16384); | |
| 836 | Config->Strip = getStrip(Args); | |
| 837 | Config->Sysroot = Args.getLastArgValue(OPT_sysroot); | |
| 838 | Config->Target1Rel = Args.hasFlag(OPT_target1_rel, OPT_target1_abs, false); | |
| 839 | Config->Target2 = getTarget2(Args); | |
| 840 | Config->ThinLTOCacheDir = Args.getLastArgValue(OPT_thinlto_cache_dir); | |
| 841 | Config->ThinLTOCachePolicy = CHECK( | |
| 842 | parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)), | |
| 822 | config->enableNewDtags = | |
| 823 | args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true); | |
| 824 | config->entry = args.getLastArgValue(OPT_entry); | |
| 825 | config->executeOnly = | |
| 826 | args.hasFlag(OPT_execute_only, OPT_no_execute_only, false); | |
| 827 | config->exportDynamic = | |
| 828 | args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false); | |
| 829 | config->filterList = args::getStrings(args, OPT_filter); | |
| 830 | config->fini = args.getLastArgValue(OPT_fini, "_fini"); | |
| 831 | config->fixCortexA53Errata843419 = args.hasArg(OPT_fix_cortex_a53_843419); | |
| 832 | config->forceBTI = args.hasArg(OPT_force_bti); | |
| 833 | config->requireCET = args.hasArg(OPT_require_cet); | |
| 834 | config->gcSections = args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false); | |
| 835 | config->gnuUnique = args.hasFlag(OPT_gnu_unique, OPT_no_gnu_unique, true); | |
| 836 | config->gdbIndex = args.hasFlag(OPT_gdb_index, OPT_no_gdb_index, false); | |
| 837 | config->icf = getICF(args); | |
| 838 | config->ignoreDataAddressEquality = | |
| 839 | args.hasArg(OPT_ignore_data_address_equality); | |
| 840 | config->ignoreFunctionAddressEquality = | |
| 841 | args.hasArg(OPT_ignore_function_address_equality); | |
| 842 | config->init = args.getLastArgValue(OPT_init, "_init"); | |
| 843 | config->ltoAAPipeline = args.getLastArgValue(OPT_lto_aa_pipeline); | |
| 844 | config->ltoCSProfileGenerate = args.hasArg(OPT_lto_cs_profile_generate); | |
| 845 | config->ltoCSProfileFile = args.getLastArgValue(OPT_lto_cs_profile_file); | |
| 846 | config->ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager); | |
| 847 | config->ltoNewPassManager = args.hasArg(OPT_lto_new_pass_manager); | |
| 848 | config->ltoNewPmPasses = args.getLastArgValue(OPT_lto_newpm_passes); | |
| 849 | config->ltoo = args::getInteger(args, OPT_lto_O, 2); | |
| 850 | config->ltoObjPath = args.getLastArgValue(OPT_plugin_opt_obj_path_eq); | |
| 851 | config->ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1); | |
| 852 | config->ltoSampleProfile = args.getLastArgValue(OPT_lto_sample_profile); | |
| 853 | config->mapFile = args.getLastArgValue(OPT_Map); | |
| 854 | config->mipsGotSize = args::getInteger(args, OPT_mips_got_size, 0xfff0); | |
| 855 | config->mergeArmExidx = | |
| 856 | args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true); | |
| 857 | config->nmagic = args.hasFlag(OPT_nmagic, OPT_no_nmagic, false); | |
| 858 | config->noinhibitExec = args.hasArg(OPT_noinhibit_exec); | |
| 859 | config->nostdlib = args.hasArg(OPT_nostdlib); | |
| 860 | config->oFormatBinary = isOutputFormatBinary(args); | |
| 861 | config->omagic = args.hasFlag(OPT_omagic, OPT_no_omagic, false); | |
| 862 | config->optRemarksFilename = args.getLastArgValue(OPT_opt_remarks_filename); | |
| 863 | config->optRemarksPasses = args.getLastArgValue(OPT_opt_remarks_passes); | |
| 864 | config->optRemarksWithHotness = args.hasArg(OPT_opt_remarks_with_hotness); | |
| 865 | config->optRemarksFormat = args.getLastArgValue(OPT_opt_remarks_format); | |
| 866 | config->optimize = args::getInteger(args, OPT_O, 1); | |
| 867 | config->orphanHandling = getOrphanHandling(args); | |
| 868 | config->outputFile = args.getLastArgValue(OPT_o); | |
| 869 | config->pacPlt = args.hasArg(OPT_pac_plt); | |
| 870 | config->pie = args.hasFlag(OPT_pie, OPT_no_pie, false); | |
| 871 | config->printIcfSections = | |
| 872 | args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false); | |
| 873 | config->printGcSections = | |
| 874 | args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false); | |
| 875 | config->printSymbolOrder = | |
| 876 | args.getLastArgValue(OPT_print_symbol_order); | |
| 877 | config->rpath = getRpath(args); | |
| 878 | config->relocatable = args.hasArg(OPT_relocatable); | |
| 879 | config->saveTemps = args.hasArg(OPT_save_temps); | |
| 880 | config->searchPaths = args::getStrings(args, OPT_library_path); | |
| 881 | config->sectionStartMap = getSectionStartMap(args); | |
| 882 | config->shared = args.hasArg(OPT_shared); | |
| 883 | config->singleRoRx = args.hasArg(OPT_no_rosegment); | |
| 884 | config->soName = args.getLastArgValue(OPT_soname); | |
| 885 | config->sortSection = getSortSection(args); | |
| 886 | config->splitStackAdjustSize = args::getInteger(args, OPT_split_stack_adjust_size, 16384); | |
| 887 | config->strip = getStrip(args); | |
| 888 | config->sysroot = args.getLastArgValue(OPT_sysroot); | |
| 889 | config->target1Rel = args.hasFlag(OPT_target1_rel, OPT_target1_abs, false); | |
| 890 | config->target2 = getTarget2(args); | |
| 891 | config->thinLTOCacheDir = args.getLastArgValue(OPT_thinlto_cache_dir); | |
| 892 | config->thinLTOCachePolicy = CHECK( | |
| 893 | parseCachePruningPolicy(args.getLastArgValue(OPT_thinlto_cache_policy)), | |
| 843 | 894 | "--thinlto-cache-policy: invalid cache policy"); |
| 844 | Config->ThinLTOEmitImportsFiles = | |
| 845 | Args.hasArg(OPT_plugin_opt_thinlto_emit_imports_files); | |
| 846 | Config->ThinLTOIndexOnly = Args.hasArg(OPT_plugin_opt_thinlto_index_only) || | |
| 847 | Args.hasArg(OPT_plugin_opt_thinlto_index_only_eq); | |
| 848 | Config->ThinLTOIndexOnlyArg = | |
| 849 | Args.getLastArgValue(OPT_plugin_opt_thinlto_index_only_eq); | |
| 850 | Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u); | |
| 851 | Config->ThinLTOObjectSuffixReplace = | |
| 852 | getOldNewOptions(Args, OPT_plugin_opt_thinlto_object_suffix_replace_eq); | |
| 853 | Config->ThinLTOPrefixReplace = | |
| 854 | getOldNewOptions(Args, OPT_plugin_opt_thinlto_prefix_replace_eq); | |
| 855 | Config->Trace = Args.hasArg(OPT_trace); | |
| 856 | Config->Undefined = args::getStrings(Args, OPT_undefined); | |
| 857 | Config->UndefinedVersion = | |
| 858 | Args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, true); | |
| 859 | Config->UseAndroidRelrTags = Args.hasFlag( | |
| 895 | config->thinLTOEmitImportsFiles = | |
| 896 | args.hasArg(OPT_plugin_opt_thinlto_emit_imports_files); | |
| 897 | config->thinLTOIndexOnly = args.hasArg(OPT_plugin_opt_thinlto_index_only) || | |
| 898 | args.hasArg(OPT_plugin_opt_thinlto_index_only_eq); | |
| 899 | config->thinLTOIndexOnlyArg = | |
| 900 | args.getLastArgValue(OPT_plugin_opt_thinlto_index_only_eq); | |
| 901 | config->thinLTOJobs = args::getInteger(args, OPT_thinlto_jobs, -1u); | |
| 902 | config->thinLTOObjectSuffixReplace = | |
| 903 | getOldNewOptions(args, OPT_plugin_opt_thinlto_object_suffix_replace_eq); | |
| 904 | config->thinLTOPrefixReplace = | |
| 905 | getOldNewOptions(args, OPT_plugin_opt_thinlto_prefix_replace_eq); | |
| 906 | config->trace = args.hasArg(OPT_trace); | |
| 907 | config->undefined = args::getStrings(args, OPT_undefined); | |
| 908 | config->undefinedVersion = | |
| 909 | args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, true); | |
| 910 | config->useAndroidRelrTags = args.hasFlag( | |
| 860 | 911 | OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false); |
| 861 | Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args); | |
| 862 | Config->WarnBackrefs = | |
| 863 | Args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false); | |
| 864 | Config->WarnCommon = Args.hasFlag(OPT_warn_common, OPT_no_warn_common, false); | |
| 865 | Config->WarnIfuncTextrel = | |
| 866 | Args.hasFlag(OPT_warn_ifunc_textrel, OPT_no_warn_ifunc_textrel, false); | |
| 867 | Config->WarnSymbolOrdering = | |
| 868 | Args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true); | |
| 869 | Config->ZCombreloc = getZFlag(Args, "combreloc", "nocombreloc", true); | |
| 870 | Config->ZCopyreloc = getZFlag(Args, "copyreloc", "nocopyreloc", true); | |
| 871 | Config->ZExecstack = getZFlag(Args, "execstack", "noexecstack", false); | |
| 872 | Config->ZGlobal = hasZOption(Args, "global"); | |
| 873 | Config->ZHazardplt = hasZOption(Args, "hazardplt"); | |
| 874 | Config->ZInitfirst = hasZOption(Args, "initfirst"); | |
| 875 | Config->ZInterpose = hasZOption(Args, "interpose"); | |
| 876 | Config->ZKeepTextSectionPrefix = getZFlag( | |
| 877 | Args, "keep-text-section-prefix", "nokeep-text-section-prefix", false); | |
| 878 | Config->ZNodefaultlib = hasZOption(Args, "nodefaultlib"); | |
| 879 | Config->ZNodelete = hasZOption(Args, "nodelete"); | |
| 880 | Config->ZNodlopen = hasZOption(Args, "nodlopen"); | |
| 881 | Config->ZNow = getZFlag(Args, "now", "lazy", false); | |
| 882 | Config->ZOrigin = hasZOption(Args, "origin"); | |
| 883 | Config->ZRelro = getZFlag(Args, "relro", "norelro", true); | |
| 884 | Config->ZRetpolineplt = hasZOption(Args, "retpolineplt"); | |
| 885 | Config->ZRodynamic = hasZOption(Args, "rodynamic"); | |
| 886 | Config->ZStackSize = args::getZOptionValue(Args, OPT_z, "stack-size", 0); | |
| 887 | Config->ZText = getZFlag(Args, "text", "notext", true); | |
| 888 | Config->ZWxneeded = hasZOption(Args, "wxneeded"); | |
| 912 | config->unresolvedSymbols = getUnresolvedSymbolPolicy(args); | |
| 913 | config->warnBackrefs = | |
| 914 | args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false); | |
| 915 | config->warnCommon = args.hasFlag(OPT_warn_common, OPT_no_warn_common, false); | |
| 916 | config->warnIfuncTextrel = | |
| 917 | args.hasFlag(OPT_warn_ifunc_textrel, OPT_no_warn_ifunc_textrel, false); | |
| 918 | config->warnSymbolOrdering = | |
| 919 | args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true); | |
| 920 | config->zCombreloc = getZFlag(args, "combreloc", "nocombreloc", true); | |
| 921 | config->zCopyreloc = getZFlag(args, "copyreloc", "nocopyreloc", true); | |
| 922 | config->zExecstack = getZFlag(args, "execstack", "noexecstack", false); | |
| 923 | config->zGlobal = hasZOption(args, "global"); | |
| 924 | config->zHazardplt = hasZOption(args, "hazardplt"); | |
| 925 | config->zIfuncNoplt = hasZOption(args, "ifunc-noplt"); | |
| 926 | config->zInitfirst = hasZOption(args, "initfirst"); | |
| 927 | config->zInterpose = hasZOption(args, "interpose"); | |
| 928 | config->zKeepTextSectionPrefix = getZFlag( | |
| 929 | args, "keep-text-section-prefix", "nokeep-text-section-prefix", false); | |
| 930 | config->zNodefaultlib = hasZOption(args, "nodefaultlib"); | |
| 931 | config->zNodelete = hasZOption(args, "nodelete"); | |
| 932 | config->zNodlopen = hasZOption(args, "nodlopen"); | |
| 933 | config->zNow = getZFlag(args, "now", "lazy", false); | |
| 934 | config->zOrigin = hasZOption(args, "origin"); | |
| 935 | config->zRelro = getZFlag(args, "relro", "norelro", true); | |
| 936 | config->zRetpolineplt = hasZOption(args, "retpolineplt"); | |
| 937 | config->zRodynamic = hasZOption(args, "rodynamic"); | |
| 938 | config->zStackSize = args::getZOptionValue(args, OPT_z, "stack-size", 0); | |
| 939 | config->zText = getZFlag(args, "text", "notext", true); | |
| 940 | config->zWxneeded = hasZOption(args, "wxneeded"); | |
| 889 | 941 | |
| 890 | 942 | // Parse LTO options. |
| 891 | if (auto *Arg = Args.getLastArg(OPT_plugin_opt_mcpu_eq)) | |
| 892 | parseClangOption(Saver.save("-mcpu=" + StringRef(Arg->getValue())), | |
| 893 | Arg->getSpelling()); | |
| 943 | if (auto *arg = args.getLastArg(OPT_plugin_opt_mcpu_eq)) | |
| 944 | parseClangOption(saver.save("-mcpu=" + StringRef(arg->getValue())), | |
| 945 | arg->getSpelling()); | |
| 894 | 946 | |
| 895 | for (auto *Arg : Args.filtered(OPT_plugin_opt)) | |
| 896 | parseClangOption(Arg->getValue(), Arg->getSpelling()); | |
| 947 | for (auto *arg : args.filtered(OPT_plugin_opt)) | |
| 948 | parseClangOption(arg->getValue(), arg->getSpelling()); | |
| 897 | 949 | |
| 898 | 950 | // Parse -mllvm options. |
| 899 | for (auto *Arg : Args.filtered(OPT_mllvm)) | |
| 900 | parseClangOption(Arg->getValue(), Arg->getSpelling()); | |
| 951 | for (auto *arg : args.filtered(OPT_mllvm)) | |
| 952 | parseClangOption(arg->getValue(), arg->getSpelling()); | |
| 901 | 953 | |
| 902 | if (Config->LTOO > 3) | |
| 903 | error("invalid optimization level for LTO: " + Twine(Config->LTOO)); | |
| 904 | if (Config->LTOPartitions == 0) | |
| 954 | if (config->ltoo > 3) | |
| 955 | error("invalid optimization level for LTO: " + Twine(config->ltoo)); | |
| 956 | if (config->ltoPartitions == 0) | |
| 905 | 957 | error("--lto-partitions: number of threads must be > 0"); |
| 906 | if (Config->ThinLTOJobs == 0) | |
| 958 | if (config->thinLTOJobs == 0) | |
| 907 | 959 | error("--thinlto-jobs: number of threads must be > 0"); |
| 908 | 960 | |
| 909 | if (Config->SplitStackAdjustSize < 0) | |
| 961 | if (config->splitStackAdjustSize < 0) | |
| 910 | 962 | error("--split-stack-adjust-size: size must be >= 0"); |
| 911 | 963 | |
| 912 | 964 | // Parse ELF{32,64}{LE,BE} and CPU type. |
| 913 | if (auto *Arg = Args.getLastArg(OPT_m)) { | |
| 914 | StringRef S = Arg->getValue(); | |
| 915 | std::tie(Config->EKind, Config->EMachine, Config->OSABI) = | |
| 916 | parseEmulation(S); | |
| 917 | Config->MipsN32Abi = (S == "elf32btsmipn32" || S == "elf32ltsmipn32"); | |
| 918 | Config->Emulation = S; | |
| 965 | if (auto *arg = args.getLastArg(OPT_m)) { | |
| 966 | StringRef s = arg->getValue(); | |
| 967 | std::tie(config->ekind, config->emachine, config->osabi) = | |
| 968 | parseEmulation(s); | |
| 969 | config->mipsN32Abi = (s == "elf32btsmipn32" || s == "elf32ltsmipn32"); | |
| 970 | config->emulation = s; | |
| 919 | 971 | } |
| 920 | 972 | |
| 921 | 973 | // Parse -hash-style={sysv,gnu,both}. |
| 922 | if (auto *Arg = Args.getLastArg(OPT_hash_style)) { | |
| 923 | StringRef S = Arg->getValue(); | |
| 924 | if (S == "sysv") | |
| 925 | Config->SysvHash = true; | |
| 926 | else if (S == "gnu") | |
| 927 | Config->GnuHash = true; | |
| 928 | else if (S == "both") | |
| 929 | Config->SysvHash = Config->GnuHash = true; | |
| 974 | if (auto *arg = args.getLastArg(OPT_hash_style)) { | |
| 975 | StringRef s = arg->getValue(); | |
| 976 | if (s == "sysv") | |
| 977 | config->sysvHash = true; | |
| 978 | else if (s == "gnu") | |
| 979 | config->gnuHash = true; | |
| 980 | else if (s == "both") | |
| 981 | config->sysvHash = config->gnuHash = true; | |
| 930 | 982 | else |
| 931 | error("unknown -hash-style: " + S); | |
| 983 | error("unknown -hash-style: " + s); | |
| 932 | 984 | } |
| 933 | 985 | |
| 934 | if (Args.hasArg(OPT_print_map)) | |
| 935 | Config->MapFile = "-"; | |
| 936 | ||
| 937 | // --omagic is an option to create old-fashioned executables in which | |
| 938 | // .text segments are writable. Today, the option is still in use to | |
| 939 | // create special-purpose programs such as boot loaders. It doesn't | |
| 940 | // make sense to create PT_GNU_RELRO for such executables. | |
| 941 | if (Config->Omagic) | |
| 942 | Config->ZRelro = false; | |
| 943 | ||
| 944 | std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args); | |
| 945 | ||
| 946 | std::tie(Config->AndroidPackDynRelocs, Config->RelrPackDynRelocs) = | |
| 947 | getPackDynRelocs(Args); | |
| 948 | ||
| 949 | if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file)) | |
| 950 | if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) | |
| 951 | Config->SymbolOrderingFile = getSymbolOrderingFile(*Buffer); | |
| 986 | if (args.hasArg(OPT_print_map)) | |
| 987 | config->mapFile = "-"; | |
| 988 | ||
| 989 | // Page alignment can be disabled by the -n (--nmagic) and -N (--omagic). | |
| 990 | // As PT_GNU_RELRO relies on Paging, do not create it when we have disabled | |
| 991 | // it. | |
| 992 | if (config->nmagic || config->omagic) | |
| 993 | config->zRelro = false; | |
| 994 | ||
| 995 | std::tie(config->buildId, config->buildIdVector) = getBuildId(args); | |
| 996 | ||
| 997 | std::tie(config->androidPackDynRelocs, config->relrPackDynRelocs) = | |
| 998 | getPackDynRelocs(args); | |
| 999 | ||
| 1000 | if (auto *arg = args.getLastArg(OPT_symbol_ordering_file)){ | |
| 1001 | if (args.hasArg(OPT_call_graph_ordering_file)) | |
| 1002 | error("--symbol-ordering-file and --call-graph-order-file " | |
| 1003 | "may not be used together"); | |
| 1004 | if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue())){ | |
| 1005 | config->symbolOrderingFile = getSymbolOrderingFile(*buffer); | |
| 1006 | // Also need to disable CallGraphProfileSort to prevent | |
| 1007 | // LLD order symbols with CGProfile | |
| 1008 | config->callGraphProfileSort = false; | |
| 1009 | } | |
| 1010 | } | |
| 952 | 1011 | |
| 953 | 1012 | // If --retain-symbol-file is used, we'll keep only the symbols listed in |
| 954 | 1013 | // the file and discard all others. |
| 955 | if (auto *Arg = Args.getLastArg(OPT_retain_symbols_file)) { | |
| 956 | Config->DefaultSymbolVersion = VER_NDX_LOCAL; | |
| 957 | if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) | |
| 958 | for (StringRef S : args::getLines(*Buffer)) | |
| 959 | Config->VersionScriptGlobals.push_back( | |
| 960 | {S, /*IsExternCpp*/ false, /*HasWildcard*/ false}); | |
| 1014 | if (auto *arg = args.getLastArg(OPT_retain_symbols_file)) { | |
| 1015 | config->defaultSymbolVersion = VER_NDX_LOCAL; | |
| 1016 | if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue())) | |
| 1017 | for (StringRef s : args::getLines(*buffer)) | |
| 1018 | config->versionScriptGlobals.push_back( | |
| 1019 | {s, /*IsExternCpp*/ false, /*HasWildcard*/ false}); | |
| 961 | 1020 | } |
| 962 | 1021 | |
| 963 | bool HasExportDynamic = | |
| 964 | Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false); | |
| 1022 | bool hasExportDynamic = | |
| 1023 | args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false); | |
| 965 | 1024 | |
| 966 | 1025 | // Parses -dynamic-list and -export-dynamic-symbol. They make some |
| 967 | 1026 | // symbols private. Note that -export-dynamic takes precedence over them |
| 968 | 1027 | // as it says all symbols should be exported. |
| 969 | if (!HasExportDynamic) { | |
| 970 | for (auto *Arg : Args.filtered(OPT_dynamic_list)) | |
| 971 | if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) | |
| 972 | readDynamicList(*Buffer); | |
| 973 | ||
| 974 | for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) | |
| 975 | Config->DynamicList.push_back( | |
| 976 | {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false}); | |
| 1028 | if (!hasExportDynamic) { | |
| 1029 | for (auto *arg : args.filtered(OPT_dynamic_list)) | |
| 1030 | if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue())) | |
| 1031 | readDynamicList(*buffer); | |
| 1032 | ||
| 1033 | for (auto *arg : args.filtered(OPT_export_dynamic_symbol)) | |
| 1034 | config->dynamicList.push_back( | |
| 1035 | {arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false}); | |
| 977 | 1036 | } |
| 978 | 1037 | |
| 979 | 1038 | // If --export-dynamic-symbol=foo is given and symbol foo is defined in |
| 980 | 1039 | // an object file in an archive file, that object file should be pulled |
| 981 | 1040 | // out and linked. (It doesn't have to behave like that from technical |
| 982 | 1041 | // point of view, but this is needed for compatibility with GNU.) |
| 983 | for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) | |
| 984 | Config->Undefined.push_back(Arg->getValue()); | |
| 1042 | for (auto *arg : args.filtered(OPT_export_dynamic_symbol)) | |
| 1043 | config->undefined.push_back(arg->getValue()); | |
| 985 | 1044 | |
| 986 | for (auto *Arg : Args.filtered(OPT_version_script)) | |
| 987 | if (Optional<std::string> Path = searchScript(Arg->getValue())) { | |
| 988 | if (Optional<MemoryBufferRef> Buffer = readFile(*Path)) | |
| 989 | readVersionScript(*Buffer); | |
| 1045 | for (auto *arg : args.filtered(OPT_version_script)) | |
| 1046 | if (Optional<std::string> path = searchScript(arg->getValue())) { | |
| 1047 | if (Optional<MemoryBufferRef> buffer = readFile(*path)) | |
| 1048 | readVersionScript(*buffer); | |
| 990 | 1049 | } else { |
| 991 | error(Twine("cannot find version script ") + Arg->getValue()); | |
| 1050 | error(Twine("cannot find version script ") + arg->getValue()); | |
| 992 | 1051 | } |
| 993 | 1052 | } |
| 994 | 1053 | |
| ... | ... | @@ -996,18 +1055,18 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { |
| 996 | 1055 | // command line options, but computed based on other Config values. |
| 997 | 1056 | // This function initialize such members. See Config.h for the details |
| 998 | 1057 | // of these values. |
| 999 | static void setConfigs(opt::InputArgList &Args) { | |
| 1000 | ELFKind K = Config->EKind; | |
| 1001 | uint16_t M = Config->EMachine; | |
| 1002 | ||
| 1003 | Config->CopyRelocs = (Config->Relocatable || Config->EmitRelocs); | |
| 1004 | Config->Is64 = (K == ELF64LEKind || K == ELF64BEKind); | |
| 1005 | Config->IsLE = (K == ELF32LEKind || K == ELF64LEKind); | |
| 1006 | Config->Endianness = Config->IsLE ? endianness::little : endianness::big; | |
| 1007 | Config->IsMips64EL = (K == ELF64LEKind && M == EM_MIPS); | |
| 1008 | Config->Pic = Config->Pie || Config->Shared; | |
| 1009 | Config->PicThunk = Args.hasArg(OPT_pic_veneer, Config->Pic); | |
| 1010 | Config->Wordsize = Config->Is64 ? 8 : 4; | |
| 1058 | static void setConfigs(opt::InputArgList &args) { | |
| 1059 | ELFKind k = config->ekind; | |
| 1060 | uint16_t m = config->emachine; | |
| 1061 | ||
| 1062 | config->copyRelocs = (config->relocatable || config->emitRelocs); | |
| 1063 | config->is64 = (k == ELF64LEKind || k == ELF64BEKind); | |
| 1064 | config->isLE = (k == ELF32LEKind || k == ELF64LEKind); | |
| 1065 | config->endianness = config->isLE ? endianness::little : endianness::big; | |
| 1066 | config->isMips64EL = (k == ELF64LEKind && m == EM_MIPS); | |
| 1067 | config->isPic = config->pie || config->shared; | |
| 1068 | config->picThunk = args.hasArg(OPT_pic_veneer, config->isPic); | |
| 1069 | config->wordsize = config->is64 ? 8 : 4; | |
| 1011 | 1070 | |
| 1012 | 1071 | // ELF defines two different ways to store relocation addends as shown below: |
| 1013 | 1072 | // |
| ... | ... | @@ -1022,148 +1081,150 @@ static void setConfigs(opt::InputArgList &Args) { |
| 1022 | 1081 | // You cannot choose which one, Rel or Rela, you want to use. Instead each |
| 1023 | 1082 | // ABI defines which one you need to use. The following expression expresses |
| 1024 | 1083 | // that. |
| 1025 | Config->IsRela = M == EM_AARCH64 || M == EM_AMDGPU || M == EM_HEXAGON || | |
| 1026 | M == EM_PPC || M == EM_PPC64 || M == EM_RISCV || | |
| 1027 | M == EM_X86_64; | |
| 1084 | config->isRela = m == EM_AARCH64 || m == EM_AMDGPU || m == EM_HEXAGON || | |
| 1085 | m == EM_PPC || m == EM_PPC64 || m == EM_RISCV || | |
| 1086 | m == EM_X86_64; | |
| 1028 | 1087 | |
| 1029 | 1088 | // If the output uses REL relocations we must store the dynamic relocation |
| 1030 | 1089 | // addends to the output sections. We also store addends for RELA relocations |
| 1031 | 1090 | // if --apply-dynamic-relocs is used. |
| 1032 | 1091 | // We default to not writing the addends when using RELA relocations since |
| 1033 | 1092 | // any standard conforming tool can find it in r_addend. |
| 1034 | Config->WriteAddends = Args.hasFlag(OPT_apply_dynamic_relocs, | |
| 1093 | config->writeAddends = args.hasFlag(OPT_apply_dynamic_relocs, | |
| 1035 | 1094 | OPT_no_apply_dynamic_relocs, false) || |
| 1036 | !Config->IsRela; | |
| 1095 | !config->isRela; | |
| 1037 | 1096 | |
| 1038 | Config->TocOptimize = | |
| 1039 | Args.hasFlag(OPT_toc_optimize, OPT_no_toc_optimize, M == EM_PPC64); | |
| 1097 | config->tocOptimize = | |
| 1098 | args.hasFlag(OPT_toc_optimize, OPT_no_toc_optimize, m == EM_PPC64); | |
| 1040 | 1099 | } |
| 1041 | 1100 | |
| 1042 | 1101 | // Returns a value of "-format" option. |
| 1043 | static bool isFormatBinary(StringRef S) { | |
| 1044 | if (S == "binary") | |
| 1102 | static bool isFormatBinary(StringRef s) { | |
| 1103 | if (s == "binary") | |
| 1045 | 1104 | return true; |
| 1046 | if (S == "elf" || S == "default") | |
| 1105 | if (s == "elf" || s == "default") | |
| 1047 | 1106 | return false; |
| 1048 | error("unknown -format value: " + S + | |
| 1107 | error("unknown -format value: " + s + | |
| 1049 | 1108 | " (supported formats: elf, default, binary)"); |
| 1050 | 1109 | return false; |
| 1051 | 1110 | } |
| 1052 | 1111 | |
| 1053 | void LinkerDriver::createFiles(opt::InputArgList &Args) { | |
| 1112 | void LinkerDriver::createFiles(opt::InputArgList &args) { | |
| 1054 | 1113 | // For --{push,pop}-state. |
| 1055 | std::vector<std::tuple<bool, bool, bool>> Stack; | |
| 1114 | std::vector<std::tuple<bool, bool, bool>> stack; | |
| 1056 | 1115 | |
| 1057 | 1116 | // Iterate over argv to process input files and positional arguments. |
| 1058 | for (auto *Arg : Args) { | |
| 1059 | switch (Arg->getOption().getUnaliasedOption().getID()) { | |
| 1117 | for (auto *arg : args) { | |
| 1118 | switch (arg->getOption().getID()) { | |
| 1060 | 1119 | case OPT_library: |
| 1061 | addLibrary(Arg->getValue()); | |
| 1120 | addLibrary(arg->getValue()); | |
| 1062 | 1121 | break; |
| 1063 | 1122 | case OPT_INPUT: |
| 1064 | addFile(Arg->getValue(), /*WithLOption=*/false); | |
| 1123 | addFile(arg->getValue(), /*withLOption=*/false); | |
| 1065 | 1124 | break; |
| 1066 | 1125 | case OPT_defsym: { |
| 1067 | StringRef From; | |
| 1068 | StringRef To; | |
| 1069 | std::tie(From, To) = StringRef(Arg->getValue()).split('='); | |
| 1070 | if (From.empty() || To.empty()) | |
| 1071 | error("-defsym: syntax error: " + StringRef(Arg->getValue())); | |
| 1126 | StringRef from; | |
| 1127 | StringRef to; | |
| 1128 | std::tie(from, to) = StringRef(arg->getValue()).split('='); | |
| 1129 | if (from.empty() || to.empty()) | |
| 1130 | error("-defsym: syntax error: " + StringRef(arg->getValue())); | |
| 1072 | 1131 | else |
| 1073 | readDefsym(From, MemoryBufferRef(To, "-defsym")); | |
| 1132 | readDefsym(from, MemoryBufferRef(to, "-defsym")); | |
| 1074 | 1133 | break; |
| 1075 | 1134 | } |
| 1076 | 1135 | case OPT_script: |
| 1077 | if (Optional<std::string> Path = searchScript(Arg->getValue())) { | |
| 1078 | if (Optional<MemoryBufferRef> MB = readFile(*Path)) | |
| 1079 | readLinkerScript(*MB); | |
| 1136 | if (Optional<std::string> path = searchScript(arg->getValue())) { | |
| 1137 | if (Optional<MemoryBufferRef> mb = readFile(*path)) | |
| 1138 | readLinkerScript(*mb); | |
| 1080 | 1139 | break; |
| 1081 | 1140 | } |
| 1082 | error(Twine("cannot find linker script ") + Arg->getValue()); | |
| 1141 | error(Twine("cannot find linker script ") + arg->getValue()); | |
| 1083 | 1142 | break; |
| 1084 | 1143 | case OPT_as_needed: |
| 1085 | Config->AsNeeded = true; | |
| 1144 | config->asNeeded = true; | |
| 1086 | 1145 | break; |
| 1087 | 1146 | case OPT_format: |
| 1088 | Config->FormatBinary = isFormatBinary(Arg->getValue()); | |
| 1147 | config->formatBinary = isFormatBinary(arg->getValue()); | |
| 1089 | 1148 | break; |
| 1090 | 1149 | case OPT_no_as_needed: |
| 1091 | Config->AsNeeded = false; | |
| 1150 | config->asNeeded = false; | |
| 1092 | 1151 | break; |
| 1093 | 1152 | case OPT_Bstatic: |
| 1094 | Config->Static = true; | |
| 1153 | case OPT_omagic: | |
| 1154 | case OPT_nmagic: | |
| 1155 | config->isStatic = true; | |
| 1095 | 1156 | break; |
| 1096 | 1157 | case OPT_Bdynamic: |
| 1097 | Config->Static = false; | |
| 1158 | config->isStatic = false; | |
| 1098 | 1159 | break; |
| 1099 | 1160 | case OPT_whole_archive: |
| 1100 | InWholeArchive = true; | |
| 1161 | inWholeArchive = true; | |
| 1101 | 1162 | break; |
| 1102 | 1163 | case OPT_no_whole_archive: |
| 1103 | InWholeArchive = false; | |
| 1164 | inWholeArchive = false; | |
| 1104 | 1165 | break; |
| 1105 | 1166 | case OPT_just_symbols: |
| 1106 | if (Optional<MemoryBufferRef> MB = readFile(Arg->getValue())) { | |
| 1107 | Files.push_back(createObjectFile(*MB)); | |
| 1108 | Files.back()->JustSymbols = true; | |
| 1167 | if (Optional<MemoryBufferRef> mb = readFile(arg->getValue())) { | |
| 1168 | files.push_back(createObjectFile(*mb)); | |
| 1169 | files.back()->justSymbols = true; | |
| 1109 | 1170 | } |
| 1110 | 1171 | break; |
| 1111 | 1172 | case OPT_start_group: |
| 1112 | if (InputFile::IsInGroup) | |
| 1173 | if (InputFile::isInGroup) | |
| 1113 | 1174 | error("nested --start-group"); |
| 1114 | InputFile::IsInGroup = true; | |
| 1175 | InputFile::isInGroup = true; | |
| 1115 | 1176 | break; |
| 1116 | 1177 | case OPT_end_group: |
| 1117 | if (!InputFile::IsInGroup) | |
| 1178 | if (!InputFile::isInGroup) | |
| 1118 | 1179 | error("stray --end-group"); |
| 1119 | InputFile::IsInGroup = false; | |
| 1120 | ++InputFile::NextGroupId; | |
| 1180 | InputFile::isInGroup = false; | |
| 1181 | ++InputFile::nextGroupId; | |
| 1121 | 1182 | break; |
| 1122 | 1183 | case OPT_start_lib: |
| 1123 | if (InLib) | |
| 1184 | if (inLib) | |
| 1124 | 1185 | error("nested --start-lib"); |
| 1125 | if (InputFile::IsInGroup) | |
| 1186 | if (InputFile::isInGroup) | |
| 1126 | 1187 | error("may not nest --start-lib in --start-group"); |
| 1127 | InLib = true; | |
| 1128 | InputFile::IsInGroup = true; | |
| 1188 | inLib = true; | |
| 1189 | InputFile::isInGroup = true; | |
| 1129 | 1190 | break; |
| 1130 | 1191 | case OPT_end_lib: |
| 1131 | if (!InLib) | |
| 1192 | if (!inLib) | |
| 1132 | 1193 | error("stray --end-lib"); |
| 1133 | InLib = false; | |
| 1134 | InputFile::IsInGroup = false; | |
| 1135 | ++InputFile::NextGroupId; | |
| 1194 | inLib = false; | |
| 1195 | InputFile::isInGroup = false; | |
| 1196 | ++InputFile::nextGroupId; | |
| 1136 | 1197 | break; |
| 1137 | 1198 | case OPT_push_state: |
| 1138 | Stack.emplace_back(Config->AsNeeded, Config->Static, InWholeArchive); | |
| 1199 | stack.emplace_back(config->asNeeded, config->isStatic, inWholeArchive); | |
| 1139 | 1200 | break; |
| 1140 | 1201 | case OPT_pop_state: |
| 1141 | if (Stack.empty()) { | |
| 1202 | if (stack.empty()) { | |
| 1142 | 1203 | error("unbalanced --push-state/--pop-state"); |
| 1143 | 1204 | break; |
| 1144 | 1205 | } |
| 1145 | std::tie(Config->AsNeeded, Config->Static, InWholeArchive) = Stack.back(); | |
| 1146 | Stack.pop_back(); | |
| 1206 | std::tie(config->asNeeded, config->isStatic, inWholeArchive) = stack.back(); | |
| 1207 | stack.pop_back(); | |
| 1147 | 1208 | break; |
| 1148 | 1209 | } |
| 1149 | 1210 | } |
| 1150 | 1211 | |
| 1151 | if (Files.empty() && errorCount() == 0) | |
| 1212 | if (files.empty() && errorCount() == 0) | |
| 1152 | 1213 | error("no input files"); |
| 1153 | 1214 | } |
| 1154 | 1215 | |
| 1155 | 1216 | // If -m <machine_type> was not given, infer it from object files. |
| 1156 | 1217 | void LinkerDriver::inferMachineType() { |
| 1157 | if (Config->EKind != ELFNoneKind) | |
| 1218 | if (config->ekind != ELFNoneKind) | |
| 1158 | 1219 | return; |
| 1159 | 1220 | |
| 1160 | for (InputFile *F : Files) { | |
| 1161 | if (F->EKind == ELFNoneKind) | |
| 1221 | for (InputFile *f : files) { | |
| 1222 | if (f->ekind == ELFNoneKind) | |
| 1162 | 1223 | continue; |
| 1163 | Config->EKind = F->EKind; | |
| 1164 | Config->EMachine = F->EMachine; | |
| 1165 | Config->OSABI = F->OSABI; | |
| 1166 | Config->MipsN32Abi = Config->EMachine == EM_MIPS && isMipsN32Abi(F); | |
| 1224 | config->ekind = f->ekind; | |
| 1225 | config->emachine = f->emachine; | |
| 1226 | config->osabi = f->osabi; | |
| 1227 | config->mipsN32Abi = config->emachine == EM_MIPS && isMipsN32Abi(f); | |
| 1167 | 1228 | return; |
| 1168 | 1229 | } |
| 1169 | 1230 | error("target emulation unknown: -m or at least one .o file required"); |
| ... | ... | @@ -1171,49 +1232,72 @@ void LinkerDriver::inferMachineType() { |
| 1171 | 1232 | |
| 1172 | 1233 | // Parse -z max-page-size=<value>. The default value is defined by |
| 1173 | 1234 | // each target. |
| 1174 | static uint64_t getMaxPageSize(opt::InputArgList &Args) { | |
| 1175 | uint64_t Val = args::getZOptionValue(Args, OPT_z, "max-page-size", | |
| 1176 | Target->DefaultMaxPageSize); | |
| 1177 | if (!isPowerOf2_64(Val)) | |
| 1235 | static uint64_t getMaxPageSize(opt::InputArgList &args) { | |
| 1236 | uint64_t val = args::getZOptionValue(args, OPT_z, "max-page-size", | |
| 1237 | target->defaultMaxPageSize); | |
| 1238 | if (!isPowerOf2_64(val)) | |
| 1178 | 1239 | error("max-page-size: value isn't a power of 2"); |
| 1179 | return Val; | |
| 1240 | if (config->nmagic || config->omagic) { | |
| 1241 | if (val != target->defaultMaxPageSize) | |
| 1242 | warn("-z max-page-size set, but paging disabled by omagic or nmagic"); | |
| 1243 | return 1; | |
| 1244 | } | |
| 1245 | return val; | |
| 1246 | } | |
| 1247 | ||
| 1248 | // Parse -z common-page-size=<value>. The default value is defined by | |
| 1249 | // each target. | |
| 1250 | static uint64_t getCommonPageSize(opt::InputArgList &args) { | |
| 1251 | uint64_t val = args::getZOptionValue(args, OPT_z, "common-page-size", | |
| 1252 | target->defaultCommonPageSize); | |
| 1253 | if (!isPowerOf2_64(val)) | |
| 1254 | error("common-page-size: value isn't a power of 2"); | |
| 1255 | if (config->nmagic || config->omagic) { | |
| 1256 | if (val != target->defaultCommonPageSize) | |
| 1257 | warn("-z common-page-size set, but paging disabled by omagic or nmagic"); | |
| 1258 | return 1; | |
| 1259 | } | |
| 1260 | // commonPageSize can't be larger than maxPageSize. | |
| 1261 | if (val > config->maxPageSize) | |
| 1262 | val = config->maxPageSize; | |
| 1263 | return val; | |
| 1180 | 1264 | } |
| 1181 | 1265 | |
| 1182 | 1266 | // Parses -image-base option. |
| 1183 | static Optional<uint64_t> getImageBase(opt::InputArgList &Args) { | |
| 1184 | // Because we are using "Config->MaxPageSize" here, this function has to be | |
| 1267 | static Optional<uint64_t> getImageBase(opt::InputArgList &args) { | |
| 1268 | // Because we are using "Config->maxPageSize" here, this function has to be | |
| 1185 | 1269 | // called after the variable is initialized. |
| 1186 | auto *Arg = Args.getLastArg(OPT_image_base); | |
| 1187 | if (!Arg) | |
| 1270 | auto *arg = args.getLastArg(OPT_image_base); | |
| 1271 | if (!arg) | |
| 1188 | 1272 | return None; |
| 1189 | 1273 | |
| 1190 | StringRef S = Arg->getValue(); | |
| 1191 | uint64_t V; | |
| 1192 | if (!to_integer(S, V)) { | |
| 1193 | error("-image-base: number expected, but got " + S); | |
| 1274 | StringRef s = arg->getValue(); | |
| 1275 | uint64_t v; | |
| 1276 | if (!to_integer(s, v)) { | |
| 1277 | error("-image-base: number expected, but got " + s); | |
| 1194 | 1278 | return 0; |
| 1195 | 1279 | } |
| 1196 | if ((V % Config->MaxPageSize) != 0) | |
| 1197 | warn("-image-base: address isn't multiple of page size: " + S); | |
| 1198 | return V; | |
| 1280 | if ((v % config->maxPageSize) != 0) | |
| 1281 | warn("-image-base: address isn't multiple of page size: " + s); | |
| 1282 | return v; | |
| 1199 | 1283 | } |
| 1200 | 1284 | |
| 1201 | 1285 | // Parses `--exclude-libs=lib,lib,...`. |
| 1202 | 1286 | // The library names may be delimited by commas or colons. |
| 1203 | static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) { | |
| 1204 | DenseSet<StringRef> Ret; | |
| 1205 | for (auto *Arg : Args.filtered(OPT_exclude_libs)) { | |
| 1206 | StringRef S = Arg->getValue(); | |
| 1287 | static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &args) { | |
| 1288 | DenseSet<StringRef> ret; | |
| 1289 | for (auto *arg : args.filtered(OPT_exclude_libs)) { | |
| 1290 | StringRef s = arg->getValue(); | |
| 1207 | 1291 | for (;;) { |
| 1208 | size_t Pos = S.find_first_of(",:"); | |
| 1209 | if (Pos == StringRef::npos) | |
| 1292 | size_t pos = s.find_first_of(",:"); | |
| 1293 | if (pos == StringRef::npos) | |
| 1210 | 1294 | break; |
| 1211 | Ret.insert(S.substr(0, Pos)); | |
| 1212 | S = S.substr(Pos + 1); | |
| 1295 | ret.insert(s.substr(0, pos)); | |
| 1296 | s = s.substr(pos + 1); | |
| 1213 | 1297 | } |
| 1214 | Ret.insert(S); | |
| 1298 | ret.insert(s); | |
| 1215 | 1299 | } |
| 1216 | return Ret; | |
| 1300 | return ret; | |
| 1217 | 1301 | } |
| 1218 | 1302 | |
| 1219 | 1303 | // Handles the -exclude-libs option. If a static library file is specified |
| ... | ... | @@ -1222,139 +1306,247 @@ static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) { |
| 1222 | 1306 | // A special library name "ALL" means all archive files. |
| 1223 | 1307 | // |
| 1224 | 1308 | // This is not a popular option, but some programs such as bionic libc use it. |
| 1225 | template <class ELFT> | |
| 1226 | static void excludeLibs(opt::InputArgList &Args) { | |
| 1227 | DenseSet<StringRef> Libs = getExcludeLibs(Args); | |
| 1228 | bool All = Libs.count("ALL"); | |
| 1229 | ||
| 1230 | auto Visit = [&](InputFile *File) { | |
| 1231 | if (!File->ArchiveName.empty()) | |
| 1232 | if (All || Libs.count(path::filename(File->ArchiveName))) | |
| 1233 | for (Symbol *Sym : File->getSymbols()) | |
| 1234 | if (!Sym->isLocal() && Sym->File == File) | |
| 1235 | Sym->VersionId = VER_NDX_LOCAL; | |
| 1309 | static void excludeLibs(opt::InputArgList &args) { | |
| 1310 | DenseSet<StringRef> libs = getExcludeLibs(args); | |
| 1311 | bool all = libs.count("ALL"); | |
| 1312 | ||
| 1313 | auto visit = [&](InputFile *file) { | |
| 1314 | if (!file->archiveName.empty()) | |
| 1315 | if (all || libs.count(path::filename(file->archiveName))) | |
| 1316 | for (Symbol *sym : file->getSymbols()) | |
| 1317 | if (!sym->isLocal() && sym->file == file) | |
| 1318 | sym->versionId = VER_NDX_LOCAL; | |
| 1236 | 1319 | }; |
| 1237 | 1320 | |
| 1238 | for (InputFile *File : ObjectFiles) | |
| 1239 | Visit(File); | |
| 1321 | for (InputFile *file : objectFiles) | |
| 1322 | visit(file); | |
| 1240 | 1323 | |
| 1241 | for (BitcodeFile *File : BitcodeFiles) | |
| 1242 | Visit(File); | |
| 1324 | for (BitcodeFile *file : bitcodeFiles) | |
| 1325 | visit(file); | |
| 1243 | 1326 | } |
| 1244 | 1327 | |
| 1245 | 1328 | // Force Sym to be entered in the output. Used for -u or equivalent. |
| 1246 | template <class ELFT> static void handleUndefined(StringRef Name) { | |
| 1247 | Symbol *Sym = Symtab->find(Name); | |
| 1248 | if (!Sym) | |
| 1329 | static void handleUndefined(Symbol *sym) { | |
| 1330 | // Since a symbol may not be used inside the program, LTO may | |
| 1331 | // eliminate it. Mark the symbol as "used" to prevent it. | |
| 1332 | sym->isUsedInRegularObj = true; | |
| 1333 | ||
| 1334 | if (sym->isLazy()) | |
| 1335 | sym->fetch(); | |
| 1336 | } | |
| 1337 | ||
| 1338 | // As an extention to GNU linkers, lld supports a variant of `-u` | |
| 1339 | // which accepts wildcard patterns. All symbols that match a given | |
| 1340 | // pattern are handled as if they were given by `-u`. | |
| 1341 | static void handleUndefinedGlob(StringRef arg) { | |
| 1342 | Expected<GlobPattern> pat = GlobPattern::create(arg); | |
| 1343 | if (!pat) { | |
| 1344 | error("--undefined-glob: " + toString(pat.takeError())); | |
| 1249 | 1345 | return; |
| 1346 | } | |
| 1250 | 1347 | |
| 1251 | // Since symbol S may not be used inside the program, LTO may | |
| 1252 | // eliminate it. Mark the symbol as "used" to prevent it. | |
| 1253 | Sym->IsUsedInRegularObj = true; | |
| 1348 | std::vector<Symbol *> syms; | |
| 1349 | symtab->forEachSymbol([&](Symbol *sym) { | |
| 1350 | // Calling Sym->fetch() from here is not safe because it may | |
| 1351 | // add new symbols to the symbol table, invalidating the | |
| 1352 | // current iterator. So we just keep a note. | |
| 1353 | if (pat->match(sym->getName())) | |
| 1354 | syms.push_back(sym); | |
| 1355 | }); | |
| 1254 | 1356 | |
| 1255 | if (Sym->isLazy()) | |
| 1256 | Symtab->fetchLazy<ELFT>(Sym); | |
| 1357 | for (Symbol *sym : syms) | |
| 1358 | handleUndefined(sym); | |
| 1257 | 1359 | } |
| 1258 | 1360 | |
| 1259 | template <class ELFT> static void handleLibcall(StringRef Name) { | |
| 1260 | Symbol *Sym = Symtab->find(Name); | |
| 1261 | if (!Sym || !Sym->isLazy()) | |
| 1361 | static void handleLibcall(StringRef name) { | |
| 1362 | Symbol *sym = symtab->find(name); | |
| 1363 | if (!sym || !sym->isLazy()) | |
| 1262 | 1364 | return; |
| 1263 | 1365 | |
| 1264 | MemoryBufferRef MB; | |
| 1265 | if (auto *LO = dyn_cast<LazyObject>(Sym)) | |
| 1266 | MB = LO->File->MB; | |
| 1366 | MemoryBufferRef mb; | |
| 1367 | if (auto *lo = dyn_cast<LazyObject>(sym)) | |
| 1368 | mb = lo->file->mb; | |
| 1267 | 1369 | else |
| 1268 | MB = cast<LazyArchive>(Sym)->getMemberBuffer(); | |
| 1370 | mb = cast<LazyArchive>(sym)->getMemberBuffer(); | |
| 1269 | 1371 | |
| 1270 | if (isBitcode(MB)) | |
| 1271 | Symtab->fetchLazy<ELFT>(Sym); | |
| 1372 | if (isBitcode(mb)) | |
| 1373 | sym->fetch(); | |
| 1374 | } | |
| 1375 | ||
| 1376 | // Replaces common symbols with defined symbols reside in .bss sections. | |
| 1377 | // This function is called after all symbol names are resolved. As a | |
| 1378 | // result, the passes after the symbol resolution won't see any | |
| 1379 | // symbols of type CommonSymbol. | |
| 1380 | static void replaceCommonSymbols() { | |
| 1381 | symtab->forEachSymbol([](Symbol *sym) { | |
| 1382 | auto *s = dyn_cast<CommonSymbol>(sym); | |
| 1383 | if (!s) | |
| 1384 | return; | |
| 1385 | ||
| 1386 | auto *bss = make<BssSection>("COMMON", s->size, s->alignment); | |
| 1387 | bss->file = s->file; | |
| 1388 | bss->markDead(); | |
| 1389 | inputSections.push_back(bss); | |
| 1390 | s->replace(Defined{s->file, s->getName(), s->binding, s->stOther, s->type, | |
| 1391 | /*value=*/0, s->size, bss}); | |
| 1392 | }); | |
| 1272 | 1393 | } |
| 1273 | 1394 | |
| 1274 | 1395 | // If all references to a DSO happen to be weak, the DSO is not added |
| 1275 | 1396 | // to DT_NEEDED. If that happens, we need to eliminate shared symbols |
| 1276 | 1397 | // created from the DSO. Otherwise, they become dangling references |
| 1277 | 1398 | // that point to a non-existent DSO. |
| 1278 | template <class ELFT> static void demoteSharedSymbols() { | |
| 1279 | for (Symbol *Sym : Symtab->getSymbols()) { | |
| 1280 | if (auto *S = dyn_cast<SharedSymbol>(Sym)) { | |
| 1281 | if (!S->getFile<ELFT>().IsNeeded) { | |
| 1282 | bool Used = S->Used; | |
| 1283 | replaceSymbol<Undefined>(S, nullptr, S->getName(), STB_WEAK, S->StOther, | |
| 1284 | S->Type); | |
| 1285 | S->Used = Used; | |
| 1286 | } | |
| 1287 | } | |
| 1288 | } | |
| 1399 | static void demoteSharedSymbols() { | |
| 1400 | symtab->forEachSymbol([](Symbol *sym) { | |
| 1401 | auto *s = dyn_cast<SharedSymbol>(sym); | |
| 1402 | if (!s || s->getFile().isNeeded) | |
| 1403 | return; | |
| 1404 | ||
| 1405 | bool used = s->used; | |
| 1406 | s->replace(Undefined{nullptr, s->getName(), STB_WEAK, s->stOther, s->type}); | |
| 1407 | s->used = used; | |
| 1408 | }); | |
| 1289 | 1409 | } |
| 1290 | 1410 | |
| 1291 | // The section referred to by S is considered address-significant. Set the | |
| 1292 | // KeepUnique flag on the section if appropriate. | |
| 1293 | static void markAddrsig(Symbol *S) { | |
| 1294 | if (auto *D = dyn_cast_or_null<Defined>(S)) | |
| 1295 | if (D->Section) | |
| 1411 | // The section referred to by `s` is considered address-significant. Set the | |
| 1412 | // keepUnique flag on the section if appropriate. | |
| 1413 | static void markAddrsig(Symbol *s) { | |
| 1414 | if (auto *d = dyn_cast_or_null<Defined>(s)) | |
| 1415 | if (d->section) | |
| 1296 | 1416 | // We don't need to keep text sections unique under --icf=all even if they |
| 1297 | 1417 | // are address-significant. |
| 1298 | if (Config->ICF == ICFLevel::Safe || !(D->Section->Flags & SHF_EXECINSTR)) | |
| 1299 | D->Section->KeepUnique = true; | |
| 1418 | if (config->icf == ICFLevel::Safe || !(d->section->flags & SHF_EXECINSTR)) | |
| 1419 | d->section->keepUnique = true; | |
| 1300 | 1420 | } |
| 1301 | 1421 | |
| 1302 | 1422 | // Record sections that define symbols mentioned in --keep-unique <symbol> |
| 1303 | 1423 | // and symbols referred to by address-significance tables. These sections are |
| 1304 | 1424 | // ineligible for ICF. |
| 1305 | 1425 | template <class ELFT> |
| 1306 | static void findKeepUniqueSections(opt::InputArgList &Args) { | |
| 1307 | for (auto *Arg : Args.filtered(OPT_keep_unique)) { | |
| 1308 | StringRef Name = Arg->getValue(); | |
| 1309 | auto *D = dyn_cast_or_null<Defined>(Symtab->find(Name)); | |
| 1310 | if (!D || !D->Section) { | |
| 1311 | warn("could not find symbol " + Name + " to keep unique"); | |
| 1426 | static void findKeepUniqueSections(opt::InputArgList &args) { | |
| 1427 | for (auto *arg : args.filtered(OPT_keep_unique)) { | |
| 1428 | StringRef name = arg->getValue(); | |
| 1429 | auto *d = dyn_cast_or_null<Defined>(symtab->find(name)); | |
| 1430 | if (!d || !d->section) { | |
| 1431 | warn("could not find symbol " + name + " to keep unique"); | |
| 1312 | 1432 | continue; |
| 1313 | 1433 | } |
| 1314 | D->Section->KeepUnique = true; | |
| 1434 | d->section->keepUnique = true; | |
| 1315 | 1435 | } |
| 1316 | 1436 | |
| 1317 | 1437 | // --icf=all --ignore-data-address-equality means that we can ignore |
| 1318 | 1438 | // the dynsym and address-significance tables entirely. |
| 1319 | if (Config->ICF == ICFLevel::All && Config->IgnoreDataAddressEquality) | |
| 1439 | if (config->icf == ICFLevel::All && config->ignoreDataAddressEquality) | |
| 1320 | 1440 | return; |
| 1321 | 1441 | |
| 1322 | 1442 | // Symbols in the dynsym could be address-significant in other executables |
| 1323 | 1443 | // or DSOs, so we conservatively mark them as address-significant. |
| 1324 | for (Symbol *S : Symtab->getSymbols()) | |
| 1325 | if (S->includeInDynsym()) | |
| 1326 | markAddrsig(S); | |
| 1444 | symtab->forEachSymbol([&](Symbol *sym) { | |
| 1445 | if (sym->includeInDynsym()) | |
| 1446 | markAddrsig(sym); | |
| 1447 | }); | |
| 1327 | 1448 | |
| 1328 | 1449 | // Visit the address-significance table in each object file and mark each |
| 1329 | 1450 | // referenced symbol as address-significant. |
| 1330 | for (InputFile *F : ObjectFiles) { | |
| 1331 | auto *Obj = cast<ObjFile<ELFT>>(F); | |
| 1332 | ArrayRef<Symbol *> Syms = Obj->getSymbols(); | |
| 1333 | if (Obj->AddrsigSec) { | |
| 1334 | ArrayRef<uint8_t> Contents = | |
| 1335 | check(Obj->getObj().getSectionContents(Obj->AddrsigSec)); | |
| 1336 | const uint8_t *Cur = Contents.begin(); | |
| 1337 | while (Cur != Contents.end()) { | |
| 1338 | unsigned Size; | |
| 1339 | const char *Err; | |
| 1340 | uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err); | |
| 1341 | if (Err) | |
| 1342 | fatal(toString(F) + ": could not decode addrsig section: " + Err); | |
| 1343 | markAddrsig(Syms[SymIndex]); | |
| 1344 | Cur += Size; | |
| 1451 | for (InputFile *f : objectFiles) { | |
| 1452 | auto *obj = cast<ObjFile<ELFT>>(f); | |
| 1453 | ArrayRef<Symbol *> syms = obj->getSymbols(); | |
| 1454 | if (obj->addrsigSec) { | |
| 1455 | ArrayRef<uint8_t> contents = | |
| 1456 | check(obj->getObj().getSectionContents(obj->addrsigSec)); | |
| 1457 | const uint8_t *cur = contents.begin(); | |
| 1458 | while (cur != contents.end()) { | |
| 1459 | unsigned size; | |
| 1460 | const char *err; | |
| 1461 | uint64_t symIndex = decodeULEB128(cur, &size, contents.end(), &err); | |
| 1462 | if (err) | |
| 1463 | fatal(toString(f) + ": could not decode addrsig section: " + err); | |
| 1464 | markAddrsig(syms[symIndex]); | |
| 1465 | cur += size; | |
| 1345 | 1466 | } |
| 1346 | 1467 | } else { |
| 1347 | 1468 | // If an object file does not have an address-significance table, |
| 1348 | 1469 | // conservatively mark all of its symbols as address-significant. |
| 1349 | for (Symbol *S : Syms) | |
| 1350 | markAddrsig(S); | |
| 1470 | for (Symbol *s : syms) | |
| 1471 | markAddrsig(s); | |
| 1472 | } | |
| 1473 | } | |
| 1474 | } | |
| 1475 | ||
| 1476 | // This function reads a symbol partition specification section. These sections | |
| 1477 | // are used to control which partition a symbol is allocated to. See | |
| 1478 | // https://lld.llvm.org/Partitions.html for more details on partitions. | |
| 1479 | template <typename ELFT> | |
| 1480 | static void readSymbolPartitionSection(InputSectionBase *s) { | |
| 1481 | // Read the relocation that refers to the partition's entry point symbol. | |
| 1482 | Symbol *sym; | |
| 1483 | if (s->areRelocsRela) | |
| 1484 | sym = &s->getFile<ELFT>()->getRelocTargetSym(s->template relas<ELFT>()[0]); | |
| 1485 | else | |
| 1486 | sym = &s->getFile<ELFT>()->getRelocTargetSym(s->template rels<ELFT>()[0]); | |
| 1487 | if (!isa<Defined>(sym) || !sym->includeInDynsym()) | |
| 1488 | return; | |
| 1489 | ||
| 1490 | StringRef partName = reinterpret_cast<const char *>(s->data().data()); | |
| 1491 | for (Partition &part : partitions) { | |
| 1492 | if (part.name == partName) { | |
| 1493 | sym->partition = part.getNumber(); | |
| 1494 | return; | |
| 1351 | 1495 | } |
| 1352 | 1496 | } |
| 1497 | ||
| 1498 | // Forbid partitions from being used on incompatible targets, and forbid them | |
| 1499 | // from being used together with various linker features that assume a single | |
| 1500 | // set of output sections. | |
| 1501 | if (script->hasSectionsCommand) | |
| 1502 | error(toString(s->file) + | |
| 1503 | ": partitions cannot be used with the SECTIONS command"); | |
| 1504 | if (script->hasPhdrsCommands()) | |
| 1505 | error(toString(s->file) + | |
| 1506 | ": partitions cannot be used with the PHDRS command"); | |
| 1507 | if (!config->sectionStartMap.empty()) | |
| 1508 | error(toString(s->file) + ": partitions cannot be used with " | |
| 1509 | "--section-start, -Ttext, -Tdata or -Tbss"); | |
| 1510 | if (config->emachine == EM_MIPS) | |
| 1511 | error(toString(s->file) + ": partitions cannot be used on this target"); | |
| 1512 | ||
| 1513 | // Impose a limit of no more than 254 partitions. This limit comes from the | |
| 1514 | // sizes of the Partition fields in InputSectionBase and Symbol, as well as | |
| 1515 | // the amount of space devoted to the partition number in RankFlags. | |
| 1516 | if (partitions.size() == 254) | |
| 1517 | fatal("may not have more than 254 partitions"); | |
| 1518 | ||
| 1519 | partitions.emplace_back(); | |
| 1520 | Partition &newPart = partitions.back(); | |
| 1521 | newPart.name = partName; | |
| 1522 | sym->partition = newPart.getNumber(); | |
| 1353 | 1523 | } |
| 1354 | 1524 | |
| 1355 | template <class ELFT> static Symbol *addUndefined(StringRef Name) { | |
| 1356 | return Symtab->addUndefined<ELFT>(Name, STB_GLOBAL, STV_DEFAULT, 0, false, | |
| 1357 | nullptr); | |
| 1525 | static Symbol *addUndefined(StringRef name) { | |
| 1526 | return symtab->addSymbol( | |
| 1527 | Undefined{nullptr, name, STB_GLOBAL, STV_DEFAULT, 0}); | |
| 1528 | } | |
| 1529 | ||
| 1530 | // This function is where all the optimizations of link-time | |
| 1531 | // optimization takes place. When LTO is in use, some input files are | |
| 1532 | // not in native object file format but in the LLVM bitcode format. | |
| 1533 | // This function compiles bitcode files into a few big native files | |
| 1534 | // using LLVM functions and replaces bitcode symbols with the results. | |
| 1535 | // Because all bitcode files that the program consists of are passed to | |
| 1536 | // the compiler at once, it can do a whole-program optimization. | |
| 1537 | template <class ELFT> void LinkerDriver::compileBitcodeFiles() { | |
| 1538 | // Compile bitcode files and replace bitcode symbols. | |
| 1539 | lto.reset(new BitcodeCompiler); | |
| 1540 | for (BitcodeFile *file : bitcodeFiles) | |
| 1541 | lto->add(*file); | |
| 1542 | ||
| 1543 | for (InputFile *file : lto->compile()) { | |
| 1544 | auto *obj = cast<ObjFile<ELFT>>(file); | |
| 1545 | obj->parse(/*ignoreComdats=*/true); | |
| 1546 | for (Symbol *sym : obj->getGlobalSymbols()) | |
| 1547 | sym->parseSymbolVersion(); | |
| 1548 | objectFiles.push_back(file); | |
| 1549 | } | |
| 1358 | 1550 | } |
| 1359 | 1551 | |
| 1360 | 1552 | // The --wrap option is a feature to rename symbols so that you can write |
| ... | ... | @@ -1366,9 +1558,9 @@ template <class ELFT> static Symbol *addUndefined(StringRef Name) { |
| 1366 | 1558 | // |
| 1367 | 1559 | // This data structure is instantiated for each -wrap option. |
| 1368 | 1560 | struct WrappedSymbol { |
| 1369 | Symbol *Sym; | |
| 1370 | Symbol *Real; | |
| 1371 | Symbol *Wrap; | |
| 1561 | Symbol *sym; | |
| 1562 | Symbol *real; | |
| 1563 | Symbol *wrap; | |
| 1372 | 1564 | }; |
| 1373 | 1565 | |
| 1374 | 1566 | // Handles -wrap option. |
| ... | ... | @@ -1376,34 +1568,33 @@ struct WrappedSymbol { |
| 1376 | 1568 | // This function instantiates wrapper symbols. At this point, they seem |
| 1377 | 1569 | // like they are not being used at all, so we explicitly set some flags so |
| 1378 | 1570 | // that LTO won't eliminate them. |
| 1379 | template <class ELFT> | |
| 1380 | static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &Args) { | |
| 1381 | std::vector<WrappedSymbol> V; | |
| 1382 | DenseSet<StringRef> Seen; | |
| 1571 | static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) { | |
| 1572 | std::vector<WrappedSymbol> v; | |
| 1573 | DenseSet<StringRef> seen; | |
| 1383 | 1574 | |
| 1384 | for (auto *Arg : Args.filtered(OPT_wrap)) { | |
| 1385 | StringRef Name = Arg->getValue(); | |
| 1386 | if (!Seen.insert(Name).second) | |
| 1575 | for (auto *arg : args.filtered(OPT_wrap)) { | |
| 1576 | StringRef name = arg->getValue(); | |
| 1577 | if (!seen.insert(name).second) | |
| 1387 | 1578 | continue; |
| 1388 | 1579 | |
| 1389 | Symbol *Sym = Symtab->find(Name); | |
| 1390 | if (!Sym) | |
| 1580 | Symbol *sym = symtab->find(name); | |
| 1581 | if (!sym) | |
| 1391 | 1582 | continue; |
| 1392 | 1583 | |
| 1393 | Symbol *Real = addUndefined<ELFT>(Saver.save("__real_" + Name)); | |
| 1394 | Symbol *Wrap = addUndefined<ELFT>(Saver.save("__wrap_" + Name)); | |
| 1395 | V.push_back({Sym, Real, Wrap}); | |
| 1584 | Symbol *real = addUndefined(saver.save("__real_" + name)); | |
| 1585 | Symbol *wrap = addUndefined(saver.save("__wrap_" + name)); | |
| 1586 | v.push_back({sym, real, wrap}); | |
| 1396 | 1587 | |
| 1397 | 1588 | // We want to tell LTO not to inline symbols to be overwritten |
| 1398 | 1589 | // because LTO doesn't know the final symbol contents after renaming. |
| 1399 | Real->CanInline = false; | |
| 1400 | Sym->CanInline = false; | |
| 1590 | real->canInline = false; | |
| 1591 | sym->canInline = false; | |
| 1401 | 1592 | |
| 1402 | 1593 | // Tell LTO not to eliminate these symbols. |
| 1403 | Sym->IsUsedInRegularObj = true; | |
| 1404 | Wrap->IsUsedInRegularObj = true; | |
| 1594 | sym->isUsedInRegularObj = true; | |
| 1595 | wrap->isUsedInRegularObj = true; | |
| 1405 | 1596 | } |
| 1406 | return V; | |
| 1597 | return v; | |
| 1407 | 1598 | } |
| 1408 | 1599 | |
| 1409 | 1600 | // Do renaming for -wrap by updating pointers to symbols. |
| ... | ... | @@ -1411,27 +1602,63 @@ static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &Args) { |
| 1411 | 1602 | // When this function is executed, only InputFiles and symbol table |
| 1412 | 1603 | // contain pointers to symbol objects. We visit them to replace pointers, |
| 1413 | 1604 | // so that wrapped symbols are swapped as instructed by the command line. |
| 1414 | template <class ELFT> static void wrapSymbols(ArrayRef<WrappedSymbol> Wrapped) { | |
| 1415 | DenseMap<Symbol *, Symbol *> Map; | |
| 1416 | for (const WrappedSymbol &W : Wrapped) { | |
| 1417 | Map[W.Sym] = W.Wrap; | |
| 1418 | Map[W.Real] = W.Sym; | |
| 1605 | static void wrapSymbols(ArrayRef<WrappedSymbol> wrapped) { | |
| 1606 | DenseMap<Symbol *, Symbol *> map; | |
| 1607 | for (const WrappedSymbol &w : wrapped) { | |
| 1608 | map[w.sym] = w.wrap; | |
| 1609 | map[w.real] = w.sym; | |
| 1419 | 1610 | } |
| 1420 | 1611 | |
| 1421 | 1612 | // Update pointers in input files. |
| 1422 | parallelForEach(ObjectFiles, [&](InputFile *File) { | |
| 1423 | std::vector<Symbol *> &Syms = File->getMutableSymbols(); | |
| 1424 | for (size_t I = 0, E = Syms.size(); I != E; ++I) | |
| 1425 | if (Symbol *S = Map.lookup(Syms[I])) | |
| 1426 | Syms[I] = S; | |
| 1613 | parallelForEach(objectFiles, [&](InputFile *file) { | |
| 1614 | MutableArrayRef<Symbol *> syms = file->getMutableSymbols(); | |
| 1615 | for (size_t i = 0, e = syms.size(); i != e; ++i) | |
| 1616 | if (Symbol *s = map.lookup(syms[i])) | |
| 1617 | syms[i] = s; | |
| 1427 | 1618 | }); |
| 1428 | 1619 | |
| 1429 | 1620 | // Update pointers in the symbol table. |
| 1430 | for (const WrappedSymbol &W : Wrapped) | |
| 1431 | Symtab->wrap(W.Sym, W.Real, W.Wrap); | |
| 1621 | for (const WrappedSymbol &w : wrapped) | |
| 1622 | symtab->wrap(w.sym, w.real, w.wrap); | |
| 1432 | 1623 | } |
| 1433 | 1624 | |
| 1434 | static const char *LibcallRoutineNames[] = { | |
| 1625 | // To enable CET (x86's hardware-assited control flow enforcement), each | |
| 1626 | // source file must be compiled with -fcf-protection. Object files compiled | |
| 1627 | // with the flag contain feature flags indicating that they are compatible | |
| 1628 | // with CET. We enable the feature only when all object files are compatible | |
| 1629 | // with CET. | |
| 1630 | // | |
| 1631 | // This function returns the merged feature flags. If 0, we cannot enable CET. | |
| 1632 | // This is also the case with AARCH64's BTI and PAC which use the similar | |
| 1633 | // GNU_PROPERTY_AARCH64_FEATURE_1_AND mechanism. | |
| 1634 | // | |
| 1635 | // Note that the CET-aware PLT is not implemented yet. We do error | |
| 1636 | // check only. | |
| 1637 | template <class ELFT> static uint32_t getAndFeatures() { | |
| 1638 | if (config->emachine != EM_386 && config->emachine != EM_X86_64 && | |
| 1639 | config->emachine != EM_AARCH64) | |
| 1640 | return 0; | |
| 1641 | ||
| 1642 | uint32_t ret = -1; | |
| 1643 | for (InputFile *f : objectFiles) { | |
| 1644 | uint32_t features = cast<ObjFile<ELFT>>(f)->andFeatures; | |
| 1645 | if (config->forceBTI && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) { | |
| 1646 | warn(toString(f) + ": --force-bti: file does not have BTI property"); | |
| 1647 | features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI; | |
| 1648 | } else if (!features && config->requireCET) | |
| 1649 | error(toString(f) + ": --require-cet: file is not compatible with CET"); | |
| 1650 | ret &= features; | |
| 1651 | } | |
| 1652 | ||
| 1653 | // Force enable pointer authentication Plt, we don't warn in this case as | |
| 1654 | // this does not require support in the object for correctness. | |
| 1655 | if (config->pacPlt) | |
| 1656 | ret |= GNU_PROPERTY_AARCH64_FEATURE_1_PAC; | |
| 1657 | ||
| 1658 | return ret; | |
| 1659 | } | |
| 1660 | ||
| 1661 | static const char *libcallRoutineNames[] = { | |
| 1435 | 1662 | #define HANDLE_LIBCALL(code, name) name, |
| 1436 | 1663 | #include "llvm/IR/RuntimeLibcalls.def" |
| 1437 | 1664 | #undef HANDLE_LIBCALL |
| ... | ... | @@ -1439,53 +1666,48 @@ static const char *LibcallRoutineNames[] = { |
| 1439 | 1666 | |
| 1440 | 1667 | // Do actual linking. Note that when this function is called, |
| 1441 | 1668 | // all linker scripts have already been parsed. |
| 1442 | template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { | |
| 1443 | Target = getTarget(); | |
| 1444 | InX<ELFT>::VerSym = nullptr; | |
| 1445 | InX<ELFT>::VerNeed = nullptr; | |
| 1446 | ||
| 1447 | Config->MaxPageSize = getMaxPageSize(Args); | |
| 1448 | Config->ImageBase = getImageBase(Args); | |
| 1449 | ||
| 1669 | template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { | |
| 1450 | 1670 | // If a -hash-style option was not given, set to a default value, |
| 1451 | 1671 | // which varies depending on the target. |
| 1452 | if (!Args.hasArg(OPT_hash_style)) { | |
| 1453 | if (Config->EMachine == EM_MIPS) | |
| 1454 | Config->SysvHash = true; | |
| 1672 | if (!args.hasArg(OPT_hash_style)) { | |
| 1673 | if (config->emachine == EM_MIPS) | |
| 1674 | config->sysvHash = true; | |
| 1455 | 1675 | else |
| 1456 | Config->SysvHash = Config->GnuHash = true; | |
| 1676 | config->sysvHash = config->gnuHash = true; | |
| 1457 | 1677 | } |
| 1458 | 1678 | |
| 1459 | 1679 | // Default output filename is "a.out" by the Unix tradition. |
| 1460 | if (Config->OutputFile.empty()) | |
| 1461 | Config->OutputFile = "a.out"; | |
| 1680 | if (config->outputFile.empty()) | |
| 1681 | config->outputFile = "a.out"; | |
| 1462 | 1682 | |
| 1463 | 1683 | // Fail early if the output file or map file is not writable. If a user has a |
| 1464 | 1684 | // long link, e.g. due to a large LTO link, they do not wish to run it and |
| 1465 | 1685 | // find that it failed because there was a mistake in their command-line. |
| 1466 | if (auto E = tryCreateFile(Config->OutputFile)) | |
| 1467 | error("cannot open output file " + Config->OutputFile + ": " + E.message()); | |
| 1468 | if (auto E = tryCreateFile(Config->MapFile)) | |
| 1469 | error("cannot open map file " + Config->MapFile + ": " + E.message()); | |
| 1686 | if (auto e = tryCreateFile(config->outputFile)) | |
| 1687 | error("cannot open output file " + config->outputFile + ": " + e.message()); | |
| 1688 | if (auto e = tryCreateFile(config->mapFile)) | |
| 1689 | error("cannot open map file " + config->mapFile + ": " + e.message()); | |
| 1470 | 1690 | if (errorCount()) |
| 1471 | 1691 | return; |
| 1472 | 1692 | |
| 1473 | 1693 | // Use default entry point name if no name was given via the command |
| 1474 | 1694 | // line nor linker scripts. For some reason, MIPS entry point name is |
| 1475 | 1695 | // different from others. |
| 1476 | Config->WarnMissingEntry = | |
| 1477 | (!Config->Entry.empty() || (!Config->Shared && !Config->Relocatable)); | |
| 1478 | if (Config->Entry.empty() && !Config->Relocatable) | |
| 1479 | Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start"; | |
| 1696 | config->warnMissingEntry = | |
| 1697 | (!config->entry.empty() || (!config->shared && !config->relocatable)); | |
| 1698 | if (config->entry.empty() && !config->relocatable) | |
| 1699 | config->entry = (config->emachine == EM_MIPS) ? "__start" : "_start"; | |
| 1480 | 1700 | |
| 1481 | 1701 | // Handle --trace-symbol. |
| 1482 | for (auto *Arg : Args.filtered(OPT_trace_symbol)) | |
| 1483 | Symtab->trace(Arg->getValue()); | |
| 1702 | for (auto *arg : args.filtered(OPT_trace_symbol)) | |
| 1703 | symtab->insert(arg->getValue())->traced = true; | |
| 1484 | 1704 | |
| 1485 | 1705 | // Add all files to the symbol table. This will add almost all |
| 1486 | // symbols that we need to the symbol table. | |
| 1487 | for (InputFile *F : Files) | |
| 1488 | Symtab->addFile<ELFT>(F); | |
| 1706 | // symbols that we need to the symbol table. This process might | |
| 1707 | // add files to the link, via autolinking, these files are always | |
| 1708 | // appended to the Files vector. | |
| 1709 | for (size_t i = 0; i < files.size(); ++i) | |
| 1710 | parseFile(files[i]); | |
| 1489 | 1711 | |
| 1490 | 1712 | // Now that we have every file, we can decide if we will need a |
| 1491 | 1713 | // dynamic symbol table. |
| ... | ... | @@ -1493,20 +1715,26 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { |
| 1493 | 1715 | // producing a shared library. |
| 1494 | 1716 | // We also need one if any shared libraries are used and for pie executables |
| 1495 | 1717 | // (probably because the dynamic linker needs it). |
| 1496 | Config->HasDynSymTab = | |
| 1497 | !SharedFiles.empty() || Config->Pic || Config->ExportDynamic; | |
| 1718 | config->hasDynSymTab = | |
| 1719 | !sharedFiles.empty() || config->isPic || config->exportDynamic; | |
| 1498 | 1720 | |
| 1499 | 1721 | // Some symbols (such as __ehdr_start) are defined lazily only when there |
| 1500 | 1722 | // are undefined symbols for them, so we add these to trigger that logic. |
| 1501 | for (StringRef Name : Script->ReferencedSymbols) | |
| 1502 | addUndefined<ELFT>(Name); | |
| 1723 | for (StringRef name : script->referencedSymbols) | |
| 1724 | addUndefined(name); | |
| 1503 | 1725 | |
| 1504 | 1726 | // Handle the `--undefined <sym>` options. |
| 1505 | for (StringRef S : Config->Undefined) | |
| 1506 | handleUndefined<ELFT>(S); | |
| 1727 | for (StringRef arg : config->undefined) | |
| 1728 | if (Symbol *sym = symtab->find(arg)) | |
| 1729 | handleUndefined(sym); | |
| 1507 | 1730 | |
| 1508 | 1731 | // If an entry symbol is in a static archive, pull out that file now. |
| 1509 | handleUndefined<ELFT>(Config->Entry); | |
| 1732 | if (Symbol *sym = symtab->find(config->entry)) | |
| 1733 | handleUndefined(sym); | |
| 1734 | ||
| 1735 | // Handle the `--undefined-glob <pattern>` options. | |
| 1736 | for (StringRef pat : args::getStrings(args, OPT_undefined_glob)) | |
| 1737 | handleUndefinedGlob(pat); | |
| 1510 | 1738 | |
| 1511 | 1739 | // If any of our inputs are bitcode files, the LTO code generator may create |
| 1512 | 1740 | // references to certain library functions that might not be explicit in the |
| ... | ... | @@ -1525,9 +1753,9 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { |
| 1525 | 1753 | // to, i.e. if the symbol's definition is in bitcode. Any other required |
| 1526 | 1754 | // libcall symbols will be added to the link after LTO when we add the LTO |
| 1527 | 1755 | // object file to the link. |
| 1528 | if (!BitcodeFiles.empty()) | |
| 1529 | for (const char *S : LibcallRoutineNames) | |
| 1530 | handleLibcall<ELFT>(S); | |
| 1756 | if (!bitcodeFiles.empty()) | |
| 1757 | for (const char *s : libcallRoutineNames) | |
| 1758 | handleLibcall(s); | |
| 1531 | 1759 | |
| 1532 | 1760 | // Return if there were name resolution errors. |
| 1533 | 1761 | if (errorCount()) |
| ... | ... | @@ -1535,27 +1763,27 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { |
| 1535 | 1763 | |
| 1536 | 1764 | // Now when we read all script files, we want to finalize order of linker |
| 1537 | 1765 | // script commands, which can be not yet final because of INSERT commands. |
| 1538 | Script->processInsertCommands(); | |
| 1766 | script->processInsertCommands(); | |
| 1539 | 1767 | |
| 1540 | 1768 | // We want to declare linker script's symbols early, |
| 1541 | 1769 | // so that we can version them. |
| 1542 | 1770 | // They also might be exported if referenced by DSOs. |
| 1543 | Script->declareSymbols(); | |
| 1771 | script->declareSymbols(); | |
| 1544 | 1772 | |
| 1545 | 1773 | // Handle the -exclude-libs option. |
| 1546 | if (Args.hasArg(OPT_exclude_libs)) | |
| 1547 | excludeLibs<ELFT>(Args); | |
| 1774 | if (args.hasArg(OPT_exclude_libs)) | |
| 1775 | excludeLibs(args); | |
| 1548 | 1776 | |
| 1549 | // Create ElfHeader early. We need a dummy section in | |
| 1777 | // Create elfHeader early. We need a dummy section in | |
| 1550 | 1778 | // addReservedSymbols to mark the created symbols as not absolute. |
| 1551 | Out::ElfHeader = make<OutputSection>("", 0, SHF_ALLOC); | |
| 1552 | Out::ElfHeader->Size = sizeof(typename ELFT::Ehdr); | |
| 1779 | Out::elfHeader = make<OutputSection>("", 0, SHF_ALLOC); | |
| 1780 | Out::elfHeader->size = sizeof(typename ELFT::Ehdr); | |
| 1553 | 1781 | |
| 1554 | 1782 | // Create wrapped symbols for -wrap option. |
| 1555 | std::vector<WrappedSymbol> Wrapped = addWrappedSymbols<ELFT>(Args); | |
| 1783 | std::vector<WrappedSymbol> wrapped = addWrappedSymbols(args); | |
| 1556 | 1784 | |
| 1557 | 1785 | // We need to create some reserved symbols such as _end. Create them. |
| 1558 | if (!Config->Relocatable) | |
| 1786 | if (!config->relocatable) | |
| 1559 | 1787 | addReservedSymbols(); |
| 1560 | 1788 | |
| 1561 | 1789 | // Apply version scripts. |
| ... | ... | @@ -1563,84 +1791,118 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { |
| 1563 | 1791 | // For a relocatable output, version scripts don't make sense, and |
| 1564 | 1792 | // parsing a symbol version string (e.g. dropping "@ver1" from a symbol |
| 1565 | 1793 | // name "foo@ver1") rather do harm, so we don't call this if -r is given. |
| 1566 | if (!Config->Relocatable) | |
| 1567 | Symtab->scanVersionScript(); | |
| 1794 | if (!config->relocatable) | |
| 1795 | symtab->scanVersionScript(); | |
| 1568 | 1796 | |
| 1569 | 1797 | // Do link-time optimization if given files are LLVM bitcode files. |
| 1570 | 1798 | // This compiles bitcode files into real object files. |
| 1571 | 1799 | // |
| 1572 | 1800 | // With this the symbol table should be complete. After this, no new names |
| 1573 | 1801 | // except a few linker-synthesized ones will be added to the symbol table. |
| 1574 | Symtab->addCombinedLTOObject<ELFT>(); | |
| 1802 | compileBitcodeFiles<ELFT>(); | |
| 1575 | 1803 | if (errorCount()) |
| 1576 | 1804 | return; |
| 1577 | 1805 | |
| 1578 | 1806 | // If -thinlto-index-only is given, we should create only "index |
| 1579 | 1807 | // files" and not object files. Index file creation is already done |
| 1580 | 1808 | // in addCombinedLTOObject, so we are done if that's the case. |
| 1581 | if (Config->ThinLTOIndexOnly) | |
| 1809 | if (config->thinLTOIndexOnly) | |
| 1582 | 1810 | return; |
| 1583 | 1811 | |
| 1584 | 1812 | // Likewise, --plugin-opt=emit-llvm is an option to make LTO create |
| 1585 | 1813 | // an output file in bitcode and exit, so that you can just get a |
| 1586 | 1814 | // combined bitcode file. |
| 1587 | if (Config->EmitLLVM) | |
| 1815 | if (config->emitLLVM) | |
| 1588 | 1816 | return; |
| 1589 | 1817 | |
| 1590 | 1818 | // Apply symbol renames for -wrap. |
| 1591 | if (!Wrapped.empty()) | |
| 1592 | wrapSymbols<ELFT>(Wrapped); | |
| 1819 | if (!wrapped.empty()) | |
| 1820 | wrapSymbols(wrapped); | |
| 1593 | 1821 | |
| 1594 | 1822 | // Now that we have a complete list of input files. |
| 1595 | 1823 | // Beyond this point, no new files are added. |
| 1596 | 1824 | // Aggregate all input sections into one place. |
| 1597 | for (InputFile *F : ObjectFiles) | |
| 1598 | for (InputSectionBase *S : F->getSections()) | |
| 1599 | if (S && S != &InputSection::Discarded) | |
| 1600 | InputSections.push_back(S); | |
| 1601 | for (BinaryFile *F : BinaryFiles) | |
| 1602 | for (InputSectionBase *S : F->getSections()) | |
| 1603 | InputSections.push_back(cast<InputSection>(S)); | |
| 1604 | ||
| 1605 | // We do not want to emit debug sections if --strip-all | |
| 1606 | // or -strip-debug are given. | |
| 1607 | if (Config->Strip != StripPolicy::None) | |
| 1608 | llvm::erase_if(InputSections, [](InputSectionBase *S) { | |
| 1609 | return S->Name.startswith(".debug") || S->Name.startswith(".zdebug"); | |
| 1610 | }); | |
| 1611 | ||
| 1612 | Config->EFlags = Target->calcEFlags(); | |
| 1613 | ||
| 1614 | if (Config->EMachine == EM_ARM) { | |
| 1825 | for (InputFile *f : objectFiles) | |
| 1826 | for (InputSectionBase *s : f->getSections()) | |
| 1827 | if (s && s != &InputSection::discarded) | |
| 1828 | inputSections.push_back(s); | |
| 1829 | for (BinaryFile *f : binaryFiles) | |
| 1830 | for (InputSectionBase *s : f->getSections()) | |
| 1831 | inputSections.push_back(cast<InputSection>(s)); | |
| 1832 | ||
| 1833 | llvm::erase_if(inputSections, [](InputSectionBase *s) { | |
| 1834 | if (s->type == SHT_LLVM_SYMPART) { | |
| 1835 | readSymbolPartitionSection<ELFT>(s); | |
| 1836 | return true; | |
| 1837 | } | |
| 1838 | ||
| 1839 | // We do not want to emit debug sections if --strip-all | |
| 1840 | // or -strip-debug are given. | |
| 1841 | return config->strip != StripPolicy::None && | |
| 1842 | (s->name.startswith(".debug") || s->name.startswith(".zdebug")); | |
| 1843 | }); | |
| 1844 | ||
| 1845 | // Now that the number of partitions is fixed, save a pointer to the main | |
| 1846 | // partition. | |
| 1847 | mainPart = &partitions[0]; | |
| 1848 | ||
| 1849 | // Read .note.gnu.property sections from input object files which | |
| 1850 | // contain a hint to tweak linker's and loader's behaviors. | |
| 1851 | config->andFeatures = getAndFeatures<ELFT>(); | |
| 1852 | ||
| 1853 | // The Target instance handles target-specific stuff, such as applying | |
| 1854 | // relocations or writing a PLT section. It also contains target-dependent | |
| 1855 | // values such as a default image base address. | |
| 1856 | target = getTarget(); | |
| 1857 | ||
| 1858 | config->eflags = target->calcEFlags(); | |
| 1859 | // maxPageSize (sometimes called abi page size) is the maximum page size that | |
| 1860 | // the output can be run on. For example if the OS can use 4k or 64k page | |
| 1861 | // sizes then maxPageSize must be 64k for the output to be useable on both. | |
| 1862 | // All important alignment decisions must use this value. | |
| 1863 | config->maxPageSize = getMaxPageSize(args); | |
| 1864 | // commonPageSize is the most common page size that the output will be run on. | |
| 1865 | // For example if an OS can use 4k or 64k page sizes and 4k is more common | |
| 1866 | // than 64k then commonPageSize is set to 4k. commonPageSize can be used for | |
| 1867 | // optimizations such as DATA_SEGMENT_ALIGN in linker scripts. LLD's use of it | |
| 1868 | // is limited to writing trap instructions on the last executable segment. | |
| 1869 | config->commonPageSize = getCommonPageSize(args); | |
| 1870 | ||
| 1871 | config->imageBase = getImageBase(args); | |
| 1872 | ||
| 1873 | if (config->emachine == EM_ARM) { | |
| 1615 | 1874 | // FIXME: These warnings can be removed when lld only uses these features |
| 1616 | 1875 | // when the input objects have been compiled with an architecture that |
| 1617 | 1876 | // supports them. |
| 1618 | if (Config->ARMHasBlx == false) | |
| 1877 | if (config->armHasBlx == false) | |
| 1619 | 1878 | warn("lld uses blx instruction, no object with architecture supporting " |
| 1620 | 1879 | "feature detected"); |
| 1621 | 1880 | } |
| 1622 | 1881 | |
| 1623 | 1882 | // This adds a .comment section containing a version string. We have to add it |
| 1624 | 1883 | // before mergeSections because the .comment section is a mergeable section. |
| 1625 | if (!Config->Relocatable) | |
| 1626 | InputSections.push_back(createCommentSection()); | |
| 1884 | if (!config->relocatable) | |
| 1885 | inputSections.push_back(createCommentSection()); | |
| 1886 | ||
| 1887 | // Replace common symbols with regular symbols. | |
| 1888 | replaceCommonSymbols(); | |
| 1627 | 1889 | |
| 1628 | 1890 | // Do size optimizations: garbage collection, merging of SHF_MERGE sections |
| 1629 | 1891 | // and identical code folding. |
| 1630 | 1892 | splitSections<ELFT>(); |
| 1631 | 1893 | markLive<ELFT>(); |
| 1632 | demoteSharedSymbols<ELFT>(); | |
| 1894 | demoteSharedSymbols(); | |
| 1633 | 1895 | mergeSections(); |
| 1634 | if (Config->ICF != ICFLevel::None) { | |
| 1635 | findKeepUniqueSections<ELFT>(Args); | |
| 1896 | if (config->icf != ICFLevel::None) { | |
| 1897 | findKeepUniqueSections<ELFT>(args); | |
| 1636 | 1898 | doIcf<ELFT>(); |
| 1637 | 1899 | } |
| 1638 | 1900 | |
| 1639 | 1901 | // Read the callgraph now that we know what was gced or icfed |
| 1640 | if (Config->CallGraphProfileSort) { | |
| 1641 | if (auto *Arg = Args.getLastArg(OPT_call_graph_ordering_file)) | |
| 1642 | if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) | |
| 1643 | readCallGraph(*Buffer); | |
| 1902 | if (config->callGraphProfileSort) { | |
| 1903 | if (auto *arg = args.getLastArg(OPT_call_graph_ordering_file)) | |
| 1904 | if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue())) | |
| 1905 | readCallGraph(*buffer); | |
| 1644 | 1906 | readCallGraphsFromObjectFiles<ELFT>(); |
| 1645 | 1907 | } |
| 1646 | 1908 |
deps/lld/ELF/Driver.h+23-19| ... | ... | @@ -1,15 +1,15 @@ |
| 1 | 1 | //===- Driver.h -------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| 10 | 9 | #ifndef LLD_ELF_DRIVER_H |
| 11 | 10 | #define LLD_ELF_DRIVER_H |
| 12 | 11 | |
| 12 | #include "LTO.h" | |
| 13 | 13 | #include "SymbolTable.h" |
| 14 | 14 | #include "lld/Common/LLVM.h" |
| 15 | 15 | #include "lld/Common/Reproduce.h" |
| ... | ... | @@ -22,34 +22,37 @@ |
| 22 | 22 | namespace lld { |
| 23 | 23 | namespace elf { |
| 24 | 24 | |
| 25 | extern class LinkerDriver *Driver; | |
| 25 | extern class LinkerDriver *driver; | |
| 26 | 26 | |
| 27 | 27 | class LinkerDriver { |
| 28 | 28 | public: |
| 29 | void main(ArrayRef<const char *> Args); | |
| 30 | void addFile(StringRef Path, bool WithLOption); | |
| 31 | void addLibrary(StringRef Name); | |
| 29 | void main(ArrayRef<const char *> args); | |
| 30 | void addFile(StringRef path, bool withLOption); | |
| 31 | void addLibrary(StringRef name); | |
| 32 | 32 | |
| 33 | 33 | private: |
| 34 | void readConfigs(llvm::opt::InputArgList &Args); | |
| 35 | void createFiles(llvm::opt::InputArgList &Args); | |
| 34 | void createFiles(llvm::opt::InputArgList &args); | |
| 36 | 35 | void inferMachineType(); |
| 37 | template <class ELFT> void link(llvm::opt::InputArgList &Args); | |
| 36 | template <class ELFT> void link(llvm::opt::InputArgList &args); | |
| 37 | template <class ELFT> void compileBitcodeFiles(); | |
| 38 | 38 | |
| 39 | 39 | // True if we are in --whole-archive and --no-whole-archive. |
| 40 | bool InWholeArchive = false; | |
| 40 | bool inWholeArchive = false; | |
| 41 | 41 | |
| 42 | 42 | // True if we are in --start-lib and --end-lib. |
| 43 | bool InLib = false; | |
| 43 | bool inLib = false; | |
| 44 | ||
| 45 | // For LTO. | |
| 46 | std::unique_ptr<BitcodeCompiler> lto; | |
| 44 | 47 | |
| 45 | std::vector<InputFile *> Files; | |
| 48 | std::vector<InputFile *> files; | |
| 46 | 49 | }; |
| 47 | 50 | |
| 48 | 51 | // Parses command line options. |
| 49 | 52 | class ELFOptTable : public llvm::opt::OptTable { |
| 50 | 53 | public: |
| 51 | 54 | ELFOptTable(); |
| 52 | llvm::opt::InputArgList parse(ArrayRef<const char *> Argv); | |
| 55 | llvm::opt::InputArgList parse(ArrayRef<const char *> argv); | |
| 53 | 56 | }; |
| 54 | 57 | |
| 55 | 58 | // Create enum with OPT_xxx values for each option in Options.td |
| ... | ... | @@ -61,11 +64,12 @@ enum { |
| 61 | 64 | }; |
| 62 | 65 | |
| 63 | 66 | void printHelp(); |
| 64 | std::string createResponseFile(const llvm::opt::InputArgList &Args); | |
| 67 | std::string createResponseFile(const llvm::opt::InputArgList &args); | |
| 65 | 68 | |
| 66 | llvm::Optional<std::string> findFromSearchPaths(StringRef Path); | |
| 67 | llvm::Optional<std::string> searchScript(StringRef Path); | |
| 68 | llvm::Optional<std::string> searchLibrary(StringRef Path); | |
| 69 | llvm::Optional<std::string> findFromSearchPaths(StringRef path); | |
| 70 | llvm::Optional<std::string> searchScript(StringRef path); | |
| 71 | llvm::Optional<std::string> searchLibraryBaseName(StringRef path); | |
| 72 | llvm::Optional<std::string> searchLibrary(StringRef path); | |
| 69 | 73 | |
| 70 | 74 | } // namespace elf |
| 71 | 75 | } // namespace lld |
deps/lld/ELF/DriverUtils.cpp+105-90| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- DriverUtils.cpp ----------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -42,7 +41,7 @@ using namespace lld::elf; |
| 42 | 41 | #undef PREFIX |
| 43 | 42 | |
| 44 | 43 | // Create table mapping all options defined in Options.td |
| 45 | static const opt::OptTable::Info OptInfo[] = { | |
| 44 | static const opt::OptTable::Info optInfo[] = { | |
| 46 | 45 | #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ |
| 47 | 46 | {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ |
| 48 | 47 | X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, |
| ... | ... | @@ -50,36 +49,36 @@ static const opt::OptTable::Info OptInfo[] = { |
| 50 | 49 | #undef OPTION |
| 51 | 50 | }; |
| 52 | 51 | |
| 53 | ELFOptTable::ELFOptTable() : OptTable(OptInfo) {} | |
| 52 | ELFOptTable::ELFOptTable() : OptTable(optInfo) {} | |
| 54 | 53 | |
| 55 | 54 | // Set color diagnostics according to -color-diagnostics={auto,always,never} |
| 56 | 55 | // or -no-color-diagnostics flags. |
| 57 | static void handleColorDiagnostics(opt::InputArgList &Args) { | |
| 58 | auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, | |
| 56 | static void handleColorDiagnostics(opt::InputArgList &args) { | |
| 57 | auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, | |
| 59 | 58 | OPT_no_color_diagnostics); |
| 60 | if (!Arg) | |
| 59 | if (!arg) | |
| 61 | 60 | return; |
| 62 | if (Arg->getOption().getID() == OPT_color_diagnostics) { | |
| 63 | errorHandler().ColorDiagnostics = true; | |
| 64 | } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) { | |
| 65 | errorHandler().ColorDiagnostics = false; | |
| 61 | if (arg->getOption().getID() == OPT_color_diagnostics) { | |
| 62 | errorHandler().colorDiagnostics = true; | |
| 63 | } else if (arg->getOption().getID() == OPT_no_color_diagnostics) { | |
| 64 | errorHandler().colorDiagnostics = false; | |
| 66 | 65 | } else { |
| 67 | StringRef S = Arg->getValue(); | |
| 68 | if (S == "always") | |
| 69 | errorHandler().ColorDiagnostics = true; | |
| 70 | else if (S == "never") | |
| 71 | errorHandler().ColorDiagnostics = false; | |
| 72 | else if (S != "auto") | |
| 73 | error("unknown option: --color-diagnostics=" + S); | |
| 66 | StringRef s = arg->getValue(); | |
| 67 | if (s == "always") | |
| 68 | errorHandler().colorDiagnostics = true; | |
| 69 | else if (s == "never") | |
| 70 | errorHandler().colorDiagnostics = false; | |
| 71 | else if (s != "auto") | |
| 72 | error("unknown option: --color-diagnostics=" + s); | |
| 74 | 73 | } |
| 75 | 74 | } |
| 76 | 75 | |
| 77 | static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { | |
| 78 | if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) { | |
| 79 | StringRef S = Arg->getValue(); | |
| 80 | if (S != "windows" && S != "posix") | |
| 81 | error("invalid response file quoting: " + S); | |
| 82 | if (S == "windows") | |
| 76 | static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) { | |
| 77 | if (auto *arg = args.getLastArg(OPT_rsp_quoting)) { | |
| 78 | StringRef s = arg->getValue(); | |
| 79 | if (s != "windows" && s != "posix") | |
| 80 | error("invalid response file quoting: " + s); | |
| 81 | if (s == "windows") | |
| 83 | 82 | return cl::TokenizeWindowsCommandLine; |
| 84 | 83 | return cl::TokenizeGNUCommandLine; |
| 85 | 84 | } |
| ... | ... | @@ -97,50 +96,56 @@ static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { |
| 97 | 96 | // `--plugin-opt <foo>` is converted to `--plugin-opt=<foo>`. This is a |
| 98 | 97 | // bit hacky, but looks like it is still better than handling --plugin-opt |
| 99 | 98 | // options by hand. |
| 100 | static void concatLTOPluginOptions(SmallVectorImpl<const char *> &Args) { | |
| 101 | SmallVector<const char *, 256> V; | |
| 102 | for (size_t I = 0, E = Args.size(); I != E; ++I) { | |
| 103 | StringRef S = Args[I]; | |
| 104 | if ((S == "-plugin-opt" || S == "--plugin-opt") && I + 1 != E) { | |
| 105 | V.push_back(Saver.save(S + "=" + Args[I + 1]).data()); | |
| 106 | ++I; | |
| 99 | static void concatLTOPluginOptions(SmallVectorImpl<const char *> &args) { | |
| 100 | SmallVector<const char *, 256> v; | |
| 101 | for (size_t i = 0, e = args.size(); i != e; ++i) { | |
| 102 | StringRef s = args[i]; | |
| 103 | if ((s == "-plugin-opt" || s == "--plugin-opt") && i + 1 != e) { | |
| 104 | v.push_back(saver.save(s + "=" + args[i + 1]).data()); | |
| 105 | ++i; | |
| 107 | 106 | } else { |
| 108 | V.push_back(Args[I]); | |
| 107 | v.push_back(args[i]); | |
| 109 | 108 | } |
| 110 | 109 | } |
| 111 | Args = std::move(V); | |
| 110 | args = std::move(v); | |
| 112 | 111 | } |
| 113 | 112 | |
| 114 | 113 | // Parses a given list of options. |
| 115 | opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) { | |
| 114 | opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> argv) { | |
| 116 | 115 | // Make InputArgList from string vectors. |
| 117 | unsigned MissingIndex; | |
| 118 | unsigned MissingCount; | |
| 119 | SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size()); | |
| 116 | unsigned missingIndex; | |
| 117 | unsigned missingCount; | |
| 118 | SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size()); | |
| 120 | 119 | |
| 121 | 120 | // We need to get the quoting style for response files before parsing all |
| 122 | 121 | // options so we parse here before and ignore all the options but |
| 123 | 122 | // --rsp-quoting. |
| 124 | opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount); | |
| 123 | opt::InputArgList args = this->ParseArgs(vec, missingIndex, missingCount); | |
| 125 | 124 | |
| 126 | 125 | // Expand response files (arguments in the form of @<filename>) |
| 127 | 126 | // and then parse the argument again. |
| 128 | cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec); | |
| 129 | concatLTOPluginOptions(Vec); | |
| 130 | Args = this->ParseArgs(Vec, MissingIndex, MissingCount); | |
| 131 | ||
| 132 | handleColorDiagnostics(Args); | |
| 133 | if (MissingCount) | |
| 134 | error(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); | |
| 135 | ||
| 136 | for (auto *Arg : Args.filtered(OPT_UNKNOWN)) | |
| 137 | error("unknown argument: " + Arg->getSpelling()); | |
| 138 | return Args; | |
| 127 | cl::ExpandResponseFiles(saver, getQuotingStyle(args), vec); | |
| 128 | concatLTOPluginOptions(vec); | |
| 129 | args = this->ParseArgs(vec, missingIndex, missingCount); | |
| 130 | ||
| 131 | handleColorDiagnostics(args); | |
| 132 | if (missingCount) | |
| 133 | error(Twine(args.getArgString(missingIndex)) + ": missing argument"); | |
| 134 | ||
| 135 | for (auto *arg : args.filtered(OPT_UNKNOWN)) { | |
| 136 | std::string nearest; | |
| 137 | if (findNearest(arg->getAsString(args), nearest) > 1) | |
| 138 | error("unknown argument '" + arg->getAsString(args) + "'"); | |
| 139 | else | |
| 140 | error("unknown argument '" + arg->getAsString(args) + | |
| 141 | "', did you mean '" + nearest + "'"); | |
| 142 | } | |
| 143 | return args; | |
| 139 | 144 | } |
| 140 | 145 | |
| 141 | 146 | void elf::printHelp() { |
| 142 | 147 | ELFOptTable().PrintHelp( |
| 143 | outs(), (Config->ProgName + " [options] file...").str().c_str(), "lld", | |
| 148 | outs(), (config->progName + " [options] file...").str().c_str(), "lld", | |
| 144 | 149 | false /*ShowHidden*/, true /*ShowAllAliases*/); |
| 145 | 150 | outs() << "\n"; |
| 146 | 151 | |
| ... | ... | @@ -149,30 +154,36 @@ void elf::printHelp() { |
| 149 | 154 | // in a message for the -help option. If it doesn't match, the scripts |
| 150 | 155 | // assume that the linker doesn't support very basic features such as |
| 151 | 156 | // shared libraries. Therefore, we need to print out at least "elf". |
| 152 | outs() << Config->ProgName << ": supported targets: elf\n"; | |
| 157 | outs() << config->progName << ": supported targets: elf\n"; | |
| 158 | } | |
| 159 | ||
| 160 | static std::string rewritePath(StringRef s) { | |
| 161 | if (fs::exists(s)) | |
| 162 | return relativeToRoot(s); | |
| 163 | return s; | |
| 153 | 164 | } |
| 154 | 165 | |
| 155 | 166 | // Reconstructs command line arguments so that so that you can re-run |
| 156 | 167 | // the same command with the same inputs. This is for --reproduce. |
| 157 | std::string elf::createResponseFile(const opt::InputArgList &Args) { | |
| 158 | SmallString<0> Data; | |
| 159 | raw_svector_ostream OS(Data); | |
| 160 | OS << "--chroot .\n"; | |
| 168 | std::string elf::createResponseFile(const opt::InputArgList &args) { | |
| 169 | SmallString<0> data; | |
| 170 | raw_svector_ostream os(data); | |
| 171 | os << "--chroot .\n"; | |
| 161 | 172 | |
| 162 | 173 | // Copy the command line to the output while rewriting paths. |
| 163 | for (auto *Arg : Args) { | |
| 164 | switch (Arg->getOption().getUnaliasedOption().getID()) { | |
| 174 | for (auto *arg : args) { | |
| 175 | switch (arg->getOption().getID()) { | |
| 165 | 176 | case OPT_reproduce: |
| 166 | 177 | break; |
| 167 | 178 | case OPT_INPUT: |
| 168 | OS << quote(rewritePath(Arg->getValue())) << "\n"; | |
| 179 | os << quote(rewritePath(arg->getValue())) << "\n"; | |
| 169 | 180 | break; |
| 170 | 181 | case OPT_o: |
| 171 | 182 | // If -o path contains directories, "lld @response.txt" will likely |
| 172 | 183 | // fail because the archive we are creating doesn't contain empty |
| 173 | 184 | // directories for the output path (-o doesn't create directories). |
| 174 | 185 | // Strip directories to prevent the issue. |
| 175 | OS << "-o " << quote(sys::path::filename(Arg->getValue())) << "\n"; | |
| 186 | os << "-o " << quote(sys::path::filename(arg->getValue())) << "\n"; | |
| 176 | 187 | break; |
| 177 | 188 | case OPT_dynamic_list: |
| 178 | 189 | case OPT_library_path: |
| ... | ... | @@ -181,58 +192,62 @@ std::string elf::createResponseFile(const opt::InputArgList &Args) { |
| 181 | 192 | case OPT_symbol_ordering_file: |
| 182 | 193 | case OPT_sysroot: |
| 183 | 194 | case OPT_version_script: |
| 184 | OS << Arg->getSpelling() << " " << quote(rewritePath(Arg->getValue())) | |
| 195 | os << arg->getSpelling() << " " << quote(rewritePath(arg->getValue())) | |
| 185 | 196 | << "\n"; |
| 186 | 197 | break; |
| 187 | 198 | default: |
| 188 | OS << toString(*Arg) << "\n"; | |
| 199 | os << toString(*arg) << "\n"; | |
| 189 | 200 | } |
| 190 | 201 | } |
| 191 | return Data.str(); | |
| 202 | return data.str(); | |
| 192 | 203 | } |
| 193 | 204 | |
| 194 | 205 | // Find a file by concatenating given paths. If a resulting path |
| 195 | 206 | // starts with "=", the character is replaced with a --sysroot value. |
| 196 | static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) { | |
| 197 | SmallString<128> S; | |
| 198 | if (Path1.startswith("=")) | |
| 199 | path::append(S, Config->Sysroot, Path1.substr(1), Path2); | |
| 207 | static Optional<std::string> findFile(StringRef path1, const Twine &path2) { | |
| 208 | SmallString<128> s; | |
| 209 | if (path1.startswith("=")) | |
| 210 | path::append(s, config->sysroot, path1.substr(1), path2); | |
| 200 | 211 | else |
| 201 | path::append(S, Path1, Path2); | |
| 212 | path::append(s, path1, path2); | |
| 202 | 213 | |
| 203 | if (fs::exists(S)) | |
| 204 | return S.str().str(); | |
| 214 | if (fs::exists(s)) | |
| 215 | return s.str().str(); | |
| 205 | 216 | return None; |
| 206 | 217 | } |
| 207 | 218 | |
| 208 | Optional<std::string> elf::findFromSearchPaths(StringRef Path) { | |
| 209 | for (StringRef Dir : Config->SearchPaths) | |
| 210 | if (Optional<std::string> S = findFile(Dir, Path)) | |
| 211 | return S; | |
| 219 | Optional<std::string> elf::findFromSearchPaths(StringRef path) { | |
| 220 | for (StringRef dir : config->searchPaths) | |
| 221 | if (Optional<std::string> s = findFile(dir, path)) | |
| 222 | return s; | |
| 212 | 223 | return None; |
| 213 | 224 | } |
| 214 | 225 | |
| 215 | // This is for -lfoo. We'll look for libfoo.so or libfoo.a from | |
| 226 | // This is for -l<basename>. We'll look for lib<basename>.so or lib<basename>.a from | |
| 216 | 227 | // search paths. |
| 217 | Optional<std::string> elf::searchLibrary(StringRef Name) { | |
| 218 | if (Name.startswith(":")) | |
| 219 | return findFromSearchPaths(Name.substr(1)); | |
| 220 | ||
| 221 | for (StringRef Dir : Config->SearchPaths) { | |
| 222 | if (!Config->Static) | |
| 223 | if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".so")) | |
| 224 | return S; | |
| 225 | if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a")) | |
| 226 | return S; | |
| 228 | Optional<std::string> elf::searchLibraryBaseName(StringRef name) { | |
| 229 | for (StringRef dir : config->searchPaths) { | |
| 230 | if (!config->isStatic) | |
| 231 | if (Optional<std::string> s = findFile(dir, "lib" + name + ".so")) | |
| 232 | return s; | |
| 233 | if (Optional<std::string> s = findFile(dir, "lib" + name + ".a")) | |
| 234 | return s; | |
| 227 | 235 | } |
| 228 | 236 | return None; |
| 229 | 237 | } |
| 230 | 238 | |
| 239 | // This is for -l<namespec>. | |
| 240 | Optional<std::string> elf::searchLibrary(StringRef name) { | |
| 241 | if (name.startswith(":")) | |
| 242 | return findFromSearchPaths(name.substr(1)); | |
| 243 | return searchLibraryBaseName (name); | |
| 244 | } | |
| 245 | ||
| 231 | 246 | // If a linker/version script doesn't exist in the current directory, we also |
| 232 | 247 | // look for the script in the '-L' search paths. This matches the behaviour of |
| 233 | 248 | // '-T', --version-script=, and linker script INPUT() command in ld.bfd. |
| 234 | Optional<std::string> elf::searchScript(StringRef Name) { | |
| 235 | if (fs::exists(Name)) | |
| 236 | return Name.str(); | |
| 237 | return findFromSearchPaths(Name); | |
| 249 | Optional<std::string> elf::searchScript(StringRef name) { | |
| 250 | if (fs::exists(name)) | |
| 251 | return name.str(); | |
| 252 | return findFromSearchPaths(name); | |
| 238 | 253 | } |
deps/lld/ELF/EhFrame.cpp+68-69| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- EhFrame.cpp -------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -37,72 +36,72 @@ using namespace lld::elf; |
| 37 | 36 | namespace { |
| 38 | 37 | class EhReader { |
| 39 | 38 | public: |
| 40 | EhReader(InputSectionBase *S, ArrayRef<uint8_t> D) : IS(S), D(D) {} | |
| 39 | EhReader(InputSectionBase *s, ArrayRef<uint8_t> d) : isec(s), d(d) {} | |
| 41 | 40 | size_t readEhRecordSize(); |
| 42 | 41 | uint8_t getFdeEncoding(); |
| 43 | 42 | |
| 44 | 43 | private: |
| 45 | template <class P> void failOn(const P *Loc, const Twine &Msg) { | |
| 46 | fatal("corrupted .eh_frame: " + Msg + "\n>>> defined in " + | |
| 47 | IS->getObjMsg((const uint8_t *)Loc - IS->data().data())); | |
| 44 | template <class P> void failOn(const P *loc, const Twine &msg) { | |
| 45 | fatal("corrupted .eh_frame: " + msg + "\n>>> defined in " + | |
| 46 | isec->getObjMsg((const uint8_t *)loc - isec->data().data())); | |
| 48 | 47 | } |
| 49 | 48 | |
| 50 | 49 | uint8_t readByte(); |
| 51 | void skipBytes(size_t Count); | |
| 50 | void skipBytes(size_t count); | |
| 52 | 51 | StringRef readString(); |
| 53 | 52 | void skipLeb128(); |
| 54 | 53 | void skipAugP(); |
| 55 | 54 | |
| 56 | InputSectionBase *IS; | |
| 57 | ArrayRef<uint8_t> D; | |
| 55 | InputSectionBase *isec; | |
| 56 | ArrayRef<uint8_t> d; | |
| 58 | 57 | }; |
| 59 | 58 | } |
| 60 | 59 | |
| 61 | size_t elf::readEhRecordSize(InputSectionBase *S, size_t Off) { | |
| 62 | return EhReader(S, S->data().slice(Off)).readEhRecordSize(); | |
| 60 | size_t elf::readEhRecordSize(InputSectionBase *s, size_t off) { | |
| 61 | return EhReader(s, s->data().slice(off)).readEhRecordSize(); | |
| 63 | 62 | } |
| 64 | 63 | |
| 65 | 64 | // .eh_frame section is a sequence of records. Each record starts with |
| 66 | 65 | // a 4 byte length field. This function reads the length. |
| 67 | 66 | size_t EhReader::readEhRecordSize() { |
| 68 | if (D.size() < 4) | |
| 69 | failOn(D.data(), "CIE/FDE too small"); | |
| 67 | if (d.size() < 4) | |
| 68 | failOn(d.data(), "CIE/FDE too small"); | |
| 70 | 69 | |
| 71 | 70 | // First 4 bytes of CIE/FDE is the size of the record. |
| 72 | 71 | // If it is 0xFFFFFFFF, the next 8 bytes contain the size instead, |
| 73 | 72 | // but we do not support that format yet. |
| 74 | uint64_t V = read32(D.data()); | |
| 75 | if (V == UINT32_MAX) | |
| 76 | failOn(D.data(), "CIE/FDE too large"); | |
| 77 | uint64_t Size = V + 4; | |
| 78 | if (Size > D.size()) | |
| 79 | failOn(D.data(), "CIE/FDE ends past the end of the section"); | |
| 80 | return Size; | |
| 73 | uint64_t v = read32(d.data()); | |
| 74 | if (v == UINT32_MAX) | |
| 75 | failOn(d.data(), "CIE/FDE too large"); | |
| 76 | uint64_t size = v + 4; | |
| 77 | if (size > d.size()) | |
| 78 | failOn(d.data(), "CIE/FDE ends past the end of the section"); | |
| 79 | return size; | |
| 81 | 80 | } |
| 82 | 81 | |
| 83 | 82 | // Read a byte and advance D by one byte. |
| 84 | 83 | uint8_t EhReader::readByte() { |
| 85 | if (D.empty()) | |
| 86 | failOn(D.data(), "unexpected end of CIE"); | |
| 87 | uint8_t B = D.front(); | |
| 88 | D = D.slice(1); | |
| 89 | return B; | |
| 84 | if (d.empty()) | |
| 85 | failOn(d.data(), "unexpected end of CIE"); | |
| 86 | uint8_t b = d.front(); | |
| 87 | d = d.slice(1); | |
| 88 | return b; | |
| 90 | 89 | } |
| 91 | 90 | |
| 92 | void EhReader::skipBytes(size_t Count) { | |
| 93 | if (D.size() < Count) | |
| 94 | failOn(D.data(), "CIE is too small"); | |
| 95 | D = D.slice(Count); | |
| 91 | void EhReader::skipBytes(size_t count) { | |
| 92 | if (d.size() < count) | |
| 93 | failOn(d.data(), "CIE is too small"); | |
| 94 | d = d.slice(count); | |
| 96 | 95 | } |
| 97 | 96 | |
| 98 | 97 | // Read a null-terminated string. |
| 99 | 98 | StringRef EhReader::readString() { |
| 100 | const uint8_t *End = std::find(D.begin(), D.end(), '\0'); | |
| 101 | if (End == D.end()) | |
| 102 | failOn(D.data(), "corrupted CIE (failed to read string)"); | |
| 103 | StringRef S = toStringRef(D.slice(0, End - D.begin())); | |
| 104 | D = D.slice(S.size() + 1); | |
| 105 | return S; | |
| 99 | const uint8_t *end = llvm::find(d, '\0'); | |
| 100 | if (end == d.end()) | |
| 101 | failOn(d.data(), "corrupted CIE (failed to read string)"); | |
| 102 | StringRef s = toStringRef(d.slice(0, end - d.begin())); | |
| 103 | d = d.slice(s.size() + 1); | |
| 104 | return s; | |
| 106 | 105 | } |
| 107 | 106 | |
| 108 | 107 | // Skip an integer encoded in the LEB128 format. |
| ... | ... | @@ -110,21 +109,21 @@ StringRef EhReader::readString() { |
| 110 | 109 | // But we need to be at least able to skip it so that we can read |
| 111 | 110 | // the field that follows a LEB128 number. |
| 112 | 111 | void EhReader::skipLeb128() { |
| 113 | const uint8_t *ErrPos = D.data(); | |
| 114 | while (!D.empty()) { | |
| 115 | uint8_t Val = D.front(); | |
| 116 | D = D.slice(1); | |
| 117 | if ((Val & 0x80) == 0) | |
| 112 | const uint8_t *errPos = d.data(); | |
| 113 | while (!d.empty()) { | |
| 114 | uint8_t val = d.front(); | |
| 115 | d = d.slice(1); | |
| 116 | if ((val & 0x80) == 0) | |
| 118 | 117 | return; |
| 119 | 118 | } |
| 120 | failOn(ErrPos, "corrupted CIE (failed to read LEB128)"); | |
| 119 | failOn(errPos, "corrupted CIE (failed to read LEB128)"); | |
| 121 | 120 | } |
| 122 | 121 | |
| 123 | static size_t getAugPSize(unsigned Enc) { | |
| 124 | switch (Enc & 0x0f) { | |
| 122 | static size_t getAugPSize(unsigned enc) { | |
| 123 | switch (enc & 0x0f) { | |
| 125 | 124 | case DW_EH_PE_absptr: |
| 126 | 125 | case DW_EH_PE_signed: |
| 127 | return Config->Wordsize; | |
| 126 | return config->wordsize; | |
| 128 | 127 | case DW_EH_PE_udata2: |
| 129 | 128 | case DW_EH_PE_sdata2: |
| 130 | 129 | return 2; |
| ... | ... | @@ -139,29 +138,29 @@ static size_t getAugPSize(unsigned Enc) { |
| 139 | 138 | } |
| 140 | 139 | |
| 141 | 140 | void EhReader::skipAugP() { |
| 142 | uint8_t Enc = readByte(); | |
| 143 | if ((Enc & 0xf0) == DW_EH_PE_aligned) | |
| 144 | failOn(D.data() - 1, "DW_EH_PE_aligned encoding is not supported"); | |
| 145 | size_t Size = getAugPSize(Enc); | |
| 146 | if (Size == 0) | |
| 147 | failOn(D.data() - 1, "unknown FDE encoding"); | |
| 148 | if (Size >= D.size()) | |
| 149 | failOn(D.data() - 1, "corrupted CIE"); | |
| 150 | D = D.slice(Size); | |
| 141 | uint8_t enc = readByte(); | |
| 142 | if ((enc & 0xf0) == DW_EH_PE_aligned) | |
| 143 | failOn(d.data() - 1, "DW_EH_PE_aligned encoding is not supported"); | |
| 144 | size_t size = getAugPSize(enc); | |
| 145 | if (size == 0) | |
| 146 | failOn(d.data() - 1, "unknown FDE encoding"); | |
| 147 | if (size >= d.size()) | |
| 148 | failOn(d.data() - 1, "corrupted CIE"); | |
| 149 | d = d.slice(size); | |
| 151 | 150 | } |
| 152 | 151 | |
| 153 | uint8_t elf::getFdeEncoding(EhSectionPiece *P) { | |
| 154 | return EhReader(P->Sec, P->data()).getFdeEncoding(); | |
| 152 | uint8_t elf::getFdeEncoding(EhSectionPiece *p) { | |
| 153 | return EhReader(p->sec, p->data()).getFdeEncoding(); | |
| 155 | 154 | } |
| 156 | 155 | |
| 157 | 156 | uint8_t EhReader::getFdeEncoding() { |
| 158 | 157 | skipBytes(8); |
| 159 | int Version = readByte(); | |
| 160 | if (Version != 1 && Version != 3) | |
| 161 | failOn(D.data() - 1, | |
| 162 | "FDE version 1 or 3 expected, but got " + Twine(Version)); | |
| 158 | int version = readByte(); | |
| 159 | if (version != 1 && version != 3) | |
| 160 | failOn(d.data() - 1, | |
| 161 | "FDE version 1 or 3 expected, but got " + Twine(version)); | |
| 163 | 162 | |
| 164 | StringRef Aug = readString(); | |
| 163 | StringRef aug = readString(); | |
| 165 | 164 | |
| 166 | 165 | // Skip code and data alignment factors. |
| 167 | 166 | skipLeb128(); |
| ... | ... | @@ -169,7 +168,7 @@ uint8_t EhReader::getFdeEncoding() { |
| 169 | 168 | |
| 170 | 169 | // Skip the return address register. In CIE version 1 this is a single |
| 171 | 170 | // byte. In CIE version 3 this is an unsigned LEB128. |
| 172 | if (Version == 1) | |
| 171 | if (version == 1) | |
| 173 | 172 | readByte(); |
| 174 | 173 | else |
| 175 | 174 | skipLeb128(); |
| ... | ... | @@ -177,22 +176,22 @@ uint8_t EhReader::getFdeEncoding() { |
| 177 | 176 | // We only care about an 'R' value, but other records may precede an 'R' |
| 178 | 177 | // record. Unfortunately records are not in TLV (type-length-value) format, |
| 179 | 178 | // so we need to teach the linker how to skip records for each type. |
| 180 | for (char C : Aug) { | |
| 181 | if (C == 'R') | |
| 179 | for (char c : aug) { | |
| 180 | if (c == 'R') | |
| 182 | 181 | return readByte(); |
| 183 | if (C == 'z') { | |
| 182 | if (c == 'z') { | |
| 184 | 183 | skipLeb128(); |
| 185 | 184 | continue; |
| 186 | 185 | } |
| 187 | if (C == 'P') { | |
| 186 | if (c == 'P') { | |
| 188 | 187 | skipAugP(); |
| 189 | 188 | continue; |
| 190 | 189 | } |
| 191 | if (C == 'L') { | |
| 190 | if (c == 'L') { | |
| 192 | 191 | readByte(); |
| 193 | 192 | continue; |
| 194 | 193 | } |
| 195 | failOn(Aug.data(), "unknown .eh_frame augmentation string: " + Aug); | |
| 194 | failOn(aug.data(), "unknown .eh_frame augmentation string: " + aug); | |
| 196 | 195 | } |
| 197 | 196 | return DW_EH_PE_absptr; |
| 198 | 197 | } |
deps/lld/ELF/EhFrame.h+5-6| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- EhFrame.h ------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -17,8 +16,8 @@ namespace elf { |
| 17 | 16 | class InputSectionBase; |
| 18 | 17 | struct EhSectionPiece; |
| 19 | 18 | |
| 20 | size_t readEhRecordSize(InputSectionBase *S, size_t Off); | |
| 21 | uint8_t getFdeEncoding(EhSectionPiece *P); | |
| 19 | size_t readEhRecordSize(InputSectionBase *s, size_t off); | |
| 20 | uint8_t getFdeEncoding(EhSectionPiece *p); | |
| 22 | 21 | } // namespace elf |
| 23 | 22 | } // namespace lld |
| 24 | 23 |
deps/lld/ELF/Filesystem.cpp deleted-86| ... | ... | @@ -1,86 +0,0 @@ |
| 1 | //===- Filesystem.cpp -----------------------------------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | //===----------------------------------------------------------------------===// | |
| 9 | // | |
| 10 | // This file contains a few utility functions to handle files. | |
| 11 | // | |
| 12 | //===----------------------------------------------------------------------===// | |
| 13 | ||
| 14 | #include "Filesystem.h" | |
| 15 | #include "Config.h" | |
| 16 | #include "lld/Common/Threads.h" | |
| 17 | #include "llvm/Config/llvm-config.h" | |
| 18 | #include "llvm/Support/FileOutputBuffer.h" | |
| 19 | #include "llvm/Support/FileSystem.h" | |
| 20 | #if LLVM_ON_UNIX | |
| 21 | #include <unistd.h> | |
| 22 | #endif | |
| 23 | #include <thread> | |
| 24 | ||
| 25 | using namespace llvm; | |
| 26 | ||
| 27 | using namespace lld; | |
| 28 | using namespace lld::elf; | |
| 29 | ||
| 30 | // Removes a given file asynchronously. This is a performance hack, | |
| 31 | // so remove this when operating systems are improved. | |
| 32 | // | |
| 33 | // On Linux (and probably on other Unix-like systems), unlink(2) is a | |
| 34 | // noticeably slow system call. As of 2016, unlink takes 250 | |
| 35 | // milliseconds to remove a 1 GB file on ext4 filesystem on my machine. | |
| 36 | // | |
| 37 | // To create a new result file, we first remove existing file. So, if | |
| 38 | // you repeatedly link a 1 GB program in a regular compile-link-debug | |
| 39 | // cycle, every cycle wastes 250 milliseconds only to remove a file. | |
| 40 | // Since LLD can link a 1 GB binary in about 5 seconds, that waste | |
| 41 | // actually counts. | |
| 42 | // | |
| 43 | // This function spawns a background thread to remove the file. | |
| 44 | // The calling thread returns almost immediately. | |
| 45 | void elf::unlinkAsync(StringRef Path) { | |
| 46 | // Removing a file is async on windows. | |
| 47 | #if defined(_WIN32) | |
| 48 | sys::fs::remove(Path); | |
| 49 | #else | |
| 50 | if (!ThreadsEnabled || !sys::fs::exists(Path) || | |
| 51 | !sys::fs::is_regular_file(Path)) | |
| 52 | return; | |
| 53 | ||
| 54 | // We cannot just remove path from a different thread because we are now going | |
| 55 | // to create path as a new file. | |
| 56 | // Instead we open the file and unlink it on this thread. The unlink is fast | |
| 57 | // since the open fd guarantees that it is not removing the last reference. | |
| 58 | int FD; | |
| 59 | std::error_code EC = sys::fs::openFileForRead(Path, FD); | |
| 60 | sys::fs::remove(Path); | |
| 61 | ||
| 62 | // close and therefore remove TempPath in background. | |
| 63 | if (!EC) | |
| 64 | std::thread([=] { ::close(FD); }).detach(); | |
| 65 | #endif | |
| 66 | } | |
| 67 | ||
| 68 | // Simulate file creation to see if Path is writable. | |
| 69 | // | |
| 70 | // Determining whether a file is writable or not is amazingly hard, | |
| 71 | // and after all the only reliable way of doing that is to actually | |
| 72 | // create a file. But we don't want to do that in this function | |
| 73 | // because LLD shouldn't update any file if it will end in a failure. | |
| 74 | // We also don't want to reimplement heuristics to determine if a | |
| 75 | // file is writable. So we'll let FileOutputBuffer do the work. | |
| 76 | // | |
| 77 | // FileOutputBuffer doesn't touch a desitnation file until commit() | |
| 78 | // is called. We use that class without calling commit() to predict | |
| 79 | // if the given file is writable. | |
| 80 | std::error_code elf::tryCreateFile(StringRef Path) { | |
| 81 | if (Path.empty()) | |
| 82 | return std::error_code(); | |
| 83 | if (Path == "-") | |
| 84 | return std::error_code(); | |
| 85 | return errorToErrorCode(FileOutputBuffer::create(Path, 1).takeError()); | |
| 86 | } |
deps/lld/ELF/Filesystem.h deleted-23| ... | ... | @@ -1,23 +0,0 @@ |
| 1 | //===- Filesystem.h ---------------------------------------------*- C++ -*-===// | |
| 2 | // | |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | //===----------------------------------------------------------------------===// | |
| 9 | ||
| 10 | #ifndef LLD_ELF_FILESYSTEM_H | |
| 11 | #define LLD_ELF_FILESYSTEM_H | |
| 12 | ||
| 13 | #include "lld/Common/LLVM.h" | |
| 14 | #include <system_error> | |
| 15 | ||
| 16 | namespace lld { | |
| 17 | namespace elf { | |
| 18 | void unlinkAsync(StringRef Path); | |
| 19 | std::error_code tryCreateFile(StringRef Path); | |
| 20 | } // namespace elf | |
| 21 | } // namespace lld | |
| 22 | ||
| 23 | #endif |
deps/lld/ELF/ICF.cpp+166-168| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- ICF.cpp ------------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -99,33 +98,33 @@ public: |
| 99 | 98 | void run(); |
| 100 | 99 | |
| 101 | 100 | private: |
| 102 | void segregate(size_t Begin, size_t End, bool Constant); | |
| 101 | void segregate(size_t begin, size_t end, bool constant); | |
| 103 | 102 | |
| 104 | 103 | template <class RelTy> |
| 105 | bool constantEq(const InputSection *A, ArrayRef<RelTy> RelsA, | |
| 106 | const InputSection *B, ArrayRef<RelTy> RelsB); | |
| 104 | bool constantEq(const InputSection *a, ArrayRef<RelTy> relsA, | |
| 105 | const InputSection *b, ArrayRef<RelTy> relsB); | |
| 107 | 106 | |
| 108 | 107 | template <class RelTy> |
| 109 | bool variableEq(const InputSection *A, ArrayRef<RelTy> RelsA, | |
| 110 | const InputSection *B, ArrayRef<RelTy> RelsB); | |
| 108 | bool variableEq(const InputSection *a, ArrayRef<RelTy> relsA, | |
| 109 | const InputSection *b, ArrayRef<RelTy> relsB); | |
| 111 | 110 | |
| 112 | bool equalsConstant(const InputSection *A, const InputSection *B); | |
| 113 | bool equalsVariable(const InputSection *A, const InputSection *B); | |
| 111 | bool equalsConstant(const InputSection *a, const InputSection *b); | |
| 112 | bool equalsVariable(const InputSection *a, const InputSection *b); | |
| 114 | 113 | |
| 115 | size_t findBoundary(size_t Begin, size_t End); | |
| 114 | size_t findBoundary(size_t begin, size_t end); | |
| 116 | 115 | |
| 117 | void forEachClassRange(size_t Begin, size_t End, | |
| 118 | llvm::function_ref<void(size_t, size_t)> Fn); | |
| 116 | void forEachClassRange(size_t begin, size_t end, | |
| 117 | llvm::function_ref<void(size_t, size_t)> fn); | |
| 119 | 118 | |
| 120 | void forEachClass(llvm::function_ref<void(size_t, size_t)> Fn); | |
| 119 | void forEachClass(llvm::function_ref<void(size_t, size_t)> fn); | |
| 121 | 120 | |
| 122 | std::vector<InputSection *> Sections; | |
| 121 | std::vector<InputSection *> sections; | |
| 123 | 122 | |
| 124 | 123 | // We repeat the main loop while `Repeat` is true. |
| 125 | std::atomic<bool> Repeat; | |
| 124 | std::atomic<bool> repeat; | |
| 126 | 125 | |
| 127 | 126 | // The main loop counter. |
| 128 | int Cnt = 0; | |
| 127 | int cnt = 0; | |
| 129 | 128 | |
| 130 | 129 | // We have two locations for equivalence classes. On the first iteration |
| 131 | 130 | // of the main loop, Class[0] has a valid value, and Class[1] contains |
| ... | ... | @@ -151,42 +150,42 @@ private: |
| 151 | 150 | // because we can safely read the next class without worrying about race |
| 152 | 151 | // conditions. Using the same location makes this algorithm converge |
| 153 | 152 | // faster because it uses results of the same iteration earlier. |
| 154 | int Current = 0; | |
| 155 | int Next = 0; | |
| 153 | int current = 0; | |
| 154 | int next = 0; | |
| 156 | 155 | }; |
| 157 | 156 | } |
| 158 | 157 | |
| 159 | 158 | // Returns true if section S is subject of ICF. |
| 160 | static bool isEligible(InputSection *S) { | |
| 161 | if (!S->Live || S->KeepUnique || !(S->Flags & SHF_ALLOC)) | |
| 159 | static bool isEligible(InputSection *s) { | |
| 160 | if (!s->isLive() || s->keepUnique || !(s->flags & SHF_ALLOC)) | |
| 162 | 161 | return false; |
| 163 | 162 | |
| 164 | 163 | // Don't merge writable sections. .data.rel.ro sections are marked as writable |
| 165 | 164 | // but are semantically read-only. |
| 166 | if ((S->Flags & SHF_WRITE) && S->Name != ".data.rel.ro" && | |
| 167 | !S->Name.startswith(".data.rel.ro.")) | |
| 165 | if ((s->flags & SHF_WRITE) && s->name != ".data.rel.ro" && | |
| 166 | !s->name.startswith(".data.rel.ro.")) | |
| 168 | 167 | return false; |
| 169 | 168 | |
| 170 | 169 | // SHF_LINK_ORDER sections are ICF'd as a unit with their dependent sections, |
| 171 | 170 | // so we don't consider them for ICF individually. |
| 172 | if (S->Flags & SHF_LINK_ORDER) | |
| 171 | if (s->flags & SHF_LINK_ORDER) | |
| 173 | 172 | return false; |
| 174 | 173 | |
| 175 | 174 | // Don't merge synthetic sections as their Data member is not valid and empty. |
| 176 | 175 | // The Data member needs to be valid for ICF as it is used by ICF to determine |
| 177 | 176 | // the equality of section contents. |
| 178 | if (isa<SyntheticSection>(S)) | |
| 177 | if (isa<SyntheticSection>(s)) | |
| 179 | 178 | return false; |
| 180 | 179 | |
| 181 | 180 | // .init and .fini contains instructions that must be executed to initialize |
| 182 | 181 | // and finalize the process. They cannot and should not be merged. |
| 183 | if (S->Name == ".init" || S->Name == ".fini") | |
| 182 | if (s->name == ".init" || s->name == ".fini") | |
| 184 | 183 | return false; |
| 185 | 184 | |
| 186 | 185 | // A user program may enumerate sections named with a C identifier using |
| 187 | 186 | // __start_* and __stop_* symbols. We cannot ICF any such sections because |
| 188 | 187 | // that could change program semantics. |
| 189 | if (isValidCIdentifier(S->Name)) | |
| 188 | if (isValidCIdentifier(s->name)) | |
| 190 | 189 | return false; |
| 191 | 190 | |
| 192 | 191 | return true; |
| ... | ... | @@ -194,7 +193,7 @@ static bool isEligible(InputSection *S) { |
| 194 | 193 | |
| 195 | 194 | // Split an equivalence class into smaller classes. |
| 196 | 195 | template <class ELFT> |
| 197 | void ICF<ELFT>::segregate(size_t Begin, size_t End, bool Constant) { | |
| 196 | void ICF<ELFT>::segregate(size_t begin, size_t end, bool constant) { | |
| 198 | 197 | // This loop rearranges sections in [Begin, End) so that all sections |
| 199 | 198 | // that are equal in terms of equals{Constant,Variable} are contiguous |
| 200 | 199 | // in [Begin, End). |
| ... | ... | @@ -203,93 +202,93 @@ void ICF<ELFT>::segregate(size_t Begin, size_t End, bool Constant) { |
| 203 | 202 | // issue in practice because the number of the distinct sections in |
| 204 | 203 | // each range is usually very small. |
| 205 | 204 | |
| 206 | while (Begin < End) { | |
| 205 | while (begin < end) { | |
| 207 | 206 | // Divide [Begin, End) into two. Let Mid be the start index of the |
| 208 | 207 | // second group. |
| 209 | auto Bound = | |
| 210 | std::stable_partition(Sections.begin() + Begin + 1, | |
| 211 | Sections.begin() + End, [&](InputSection *S) { | |
| 212 | if (Constant) | |
| 213 | return equalsConstant(Sections[Begin], S); | |
| 214 | return equalsVariable(Sections[Begin], S); | |
| 208 | auto bound = | |
| 209 | std::stable_partition(sections.begin() + begin + 1, | |
| 210 | sections.begin() + end, [&](InputSection *s) { | |
| 211 | if (constant) | |
| 212 | return equalsConstant(sections[begin], s); | |
| 213 | return equalsVariable(sections[begin], s); | |
| 215 | 214 | }); |
| 216 | size_t Mid = Bound - Sections.begin(); | |
| 215 | size_t mid = bound - sections.begin(); | |
| 217 | 216 | |
| 218 | 217 | // Now we split [Begin, End) into [Begin, Mid) and [Mid, End) by |
| 219 | 218 | // updating the sections in [Begin, Mid). We use Mid as an equivalence |
| 220 | 219 | // class ID because every group ends with a unique index. |
| 221 | for (size_t I = Begin; I < Mid; ++I) | |
| 222 | Sections[I]->Class[Next] = Mid; | |
| 220 | for (size_t i = begin; i < mid; ++i) | |
| 221 | sections[i]->eqClass[next] = mid; | |
| 223 | 222 | |
| 224 | 223 | // If we created a group, we need to iterate the main loop again. |
| 225 | if (Mid != End) | |
| 226 | Repeat = true; | |
| 224 | if (mid != end) | |
| 225 | repeat = true; | |
| 227 | 226 | |
| 228 | Begin = Mid; | |
| 227 | begin = mid; | |
| 229 | 228 | } |
| 230 | 229 | } |
| 231 | 230 | |
| 232 | 231 | // Compare two lists of relocations. |
| 233 | 232 | template <class ELFT> |
| 234 | 233 | template <class RelTy> |
| 235 | bool ICF<ELFT>::constantEq(const InputSection *SecA, ArrayRef<RelTy> RA, | |
| 236 | const InputSection *SecB, ArrayRef<RelTy> RB) { | |
| 237 | for (size_t I = 0; I < RA.size(); ++I) { | |
| 238 | if (RA[I].r_offset != RB[I].r_offset || | |
| 239 | RA[I].getType(Config->IsMips64EL) != RB[I].getType(Config->IsMips64EL)) | |
| 234 | bool ICF<ELFT>::constantEq(const InputSection *secA, ArrayRef<RelTy> ra, | |
| 235 | const InputSection *secB, ArrayRef<RelTy> rb) { | |
| 236 | for (size_t i = 0; i < ra.size(); ++i) { | |
| 237 | if (ra[i].r_offset != rb[i].r_offset || | |
| 238 | ra[i].getType(config->isMips64EL) != rb[i].getType(config->isMips64EL)) | |
| 240 | 239 | return false; |
| 241 | 240 | |
| 242 | uint64_t AddA = getAddend<ELFT>(RA[I]); | |
| 243 | uint64_t AddB = getAddend<ELFT>(RB[I]); | |
| 241 | uint64_t addA = getAddend<ELFT>(ra[i]); | |
| 242 | uint64_t addB = getAddend<ELFT>(rb[i]); | |
| 244 | 243 | |
| 245 | Symbol &SA = SecA->template getFile<ELFT>()->getRelocTargetSym(RA[I]); | |
| 246 | Symbol &SB = SecB->template getFile<ELFT>()->getRelocTargetSym(RB[I]); | |
| 247 | if (&SA == &SB) { | |
| 248 | if (AddA == AddB) | |
| 244 | Symbol &sa = secA->template getFile<ELFT>()->getRelocTargetSym(ra[i]); | |
| 245 | Symbol &sb = secB->template getFile<ELFT>()->getRelocTargetSym(rb[i]); | |
| 246 | if (&sa == &sb) { | |
| 247 | if (addA == addB) | |
| 249 | 248 | continue; |
| 250 | 249 | return false; |
| 251 | 250 | } |
| 252 | 251 | |
| 253 | auto *DA = dyn_cast<Defined>(&SA); | |
| 254 | auto *DB = dyn_cast<Defined>(&SB); | |
| 252 | auto *da = dyn_cast<Defined>(&sa); | |
| 253 | auto *db = dyn_cast<Defined>(&sb); | |
| 255 | 254 | |
| 256 | 255 | // Placeholder symbols generated by linker scripts look the same now but |
| 257 | 256 | // may have different values later. |
| 258 | if (!DA || !DB || DA->ScriptDefined || DB->ScriptDefined) | |
| 257 | if (!da || !db || da->scriptDefined || db->scriptDefined) | |
| 259 | 258 | return false; |
| 260 | 259 | |
| 261 | 260 | // Relocations referring to absolute symbols are constant-equal if their |
| 262 | 261 | // values are equal. |
| 263 | if (!DA->Section && !DB->Section && DA->Value + AddA == DB->Value + AddB) | |
| 262 | if (!da->section && !db->section && da->value + addA == db->value + addB) | |
| 264 | 263 | continue; |
| 265 | if (!DA->Section || !DB->Section) | |
| 264 | if (!da->section || !db->section) | |
| 266 | 265 | return false; |
| 267 | 266 | |
| 268 | if (DA->Section->kind() != DB->Section->kind()) | |
| 267 | if (da->section->kind() != db->section->kind()) | |
| 269 | 268 | return false; |
| 270 | 269 | |
| 271 | 270 | // Relocations referring to InputSections are constant-equal if their |
| 272 | 271 | // section offsets are equal. |
| 273 | if (isa<InputSection>(DA->Section)) { | |
| 274 | if (DA->Value + AddA == DB->Value + AddB) | |
| 272 | if (isa<InputSection>(da->section)) { | |
| 273 | if (da->value + addA == db->value + addB) | |
| 275 | 274 | continue; |
| 276 | 275 | return false; |
| 277 | 276 | } |
| 278 | 277 | |
| 279 | 278 | // Relocations referring to MergeInputSections are constant-equal if their |
| 280 | 279 | // offsets in the output section are equal. |
| 281 | auto *X = dyn_cast<MergeInputSection>(DA->Section); | |
| 282 | if (!X) | |
| 280 | auto *x = dyn_cast<MergeInputSection>(da->section); | |
| 281 | if (!x) | |
| 283 | 282 | return false; |
| 284 | auto *Y = cast<MergeInputSection>(DB->Section); | |
| 285 | if (X->getParent() != Y->getParent()) | |
| 283 | auto *y = cast<MergeInputSection>(db->section); | |
| 284 | if (x->getParent() != y->getParent()) | |
| 286 | 285 | return false; |
| 287 | 286 | |
| 288 | uint64_t OffsetA = | |
| 289 | SA.isSection() ? X->getOffset(AddA) : X->getOffset(DA->Value) + AddA; | |
| 290 | uint64_t OffsetB = | |
| 291 | SB.isSection() ? Y->getOffset(AddB) : Y->getOffset(DB->Value) + AddB; | |
| 292 | if (OffsetA != OffsetB) | |
| 287 | uint64_t offsetA = | |
| 288 | sa.isSection() ? x->getOffset(addA) : x->getOffset(da->value) + addA; | |
| 289 | uint64_t offsetB = | |
| 290 | sb.isSection() ? y->getOffset(addB) : y->getOffset(db->value) + addB; | |
| 291 | if (offsetA != offsetB) | |
| 293 | 292 | return false; |
| 294 | 293 | } |
| 295 | 294 | |
| ... | ... | @@ -299,57 +298,57 @@ bool ICF<ELFT>::constantEq(const InputSection *SecA, ArrayRef<RelTy> RA, |
| 299 | 298 | // Compare "non-moving" part of two InputSections, namely everything |
| 300 | 299 | // except relocation targets. |
| 301 | 300 | template <class ELFT> |
| 302 | bool ICF<ELFT>::equalsConstant(const InputSection *A, const InputSection *B) { | |
| 303 | if (A->NumRelocations != B->NumRelocations || A->Flags != B->Flags || | |
| 304 | A->getSize() != B->getSize() || A->data() != B->data()) | |
| 301 | bool ICF<ELFT>::equalsConstant(const InputSection *a, const InputSection *b) { | |
| 302 | if (a->numRelocations != b->numRelocations || a->flags != b->flags || | |
| 303 | a->getSize() != b->getSize() || a->data() != b->data()) | |
| 305 | 304 | return false; |
| 306 | 305 | |
| 307 | 306 | // If two sections have different output sections, we cannot merge them. |
| 308 | 307 | // FIXME: This doesn't do the right thing in the case where there is a linker |
| 309 | 308 | // script. We probably need to move output section assignment before ICF to |
| 310 | 309 | // get the correct behaviour here. |
| 311 | if (getOutputSectionName(A) != getOutputSectionName(B)) | |
| 310 | if (getOutputSectionName(a) != getOutputSectionName(b)) | |
| 312 | 311 | return false; |
| 313 | 312 | |
| 314 | if (A->AreRelocsRela) | |
| 315 | return constantEq(A, A->template relas<ELFT>(), B, | |
| 316 | B->template relas<ELFT>()); | |
| 317 | return constantEq(A, A->template rels<ELFT>(), B, B->template rels<ELFT>()); | |
| 313 | if (a->areRelocsRela) | |
| 314 | return constantEq(a, a->template relas<ELFT>(), b, | |
| 315 | b->template relas<ELFT>()); | |
| 316 | return constantEq(a, a->template rels<ELFT>(), b, b->template rels<ELFT>()); | |
| 318 | 317 | } |
| 319 | 318 | |
| 320 | 319 | // Compare two lists of relocations. Returns true if all pairs of |
| 321 | 320 | // relocations point to the same section in terms of ICF. |
| 322 | 321 | template <class ELFT> |
| 323 | 322 | template <class RelTy> |
| 324 | bool ICF<ELFT>::variableEq(const InputSection *SecA, ArrayRef<RelTy> RA, | |
| 325 | const InputSection *SecB, ArrayRef<RelTy> RB) { | |
| 326 | assert(RA.size() == RB.size()); | |
| 323 | bool ICF<ELFT>::variableEq(const InputSection *secA, ArrayRef<RelTy> ra, | |
| 324 | const InputSection *secB, ArrayRef<RelTy> rb) { | |
| 325 | assert(ra.size() == rb.size()); | |
| 327 | 326 | |
| 328 | for (size_t I = 0; I < RA.size(); ++I) { | |
| 327 | for (size_t i = 0; i < ra.size(); ++i) { | |
| 329 | 328 | // The two sections must be identical. |
| 330 | Symbol &SA = SecA->template getFile<ELFT>()->getRelocTargetSym(RA[I]); | |
| 331 | Symbol &SB = SecB->template getFile<ELFT>()->getRelocTargetSym(RB[I]); | |
| 332 | if (&SA == &SB) | |
| 329 | Symbol &sa = secA->template getFile<ELFT>()->getRelocTargetSym(ra[i]); | |
| 330 | Symbol &sb = secB->template getFile<ELFT>()->getRelocTargetSym(rb[i]); | |
| 331 | if (&sa == &sb) | |
| 333 | 332 | continue; |
| 334 | 333 | |
| 335 | auto *DA = cast<Defined>(&SA); | |
| 336 | auto *DB = cast<Defined>(&SB); | |
| 334 | auto *da = cast<Defined>(&sa); | |
| 335 | auto *db = cast<Defined>(&sb); | |
| 337 | 336 | |
| 338 | 337 | // We already dealt with absolute and non-InputSection symbols in |
| 339 | 338 | // constantEq, and for InputSections we have already checked everything |
| 340 | 339 | // except the equivalence class. |
| 341 | if (!DA->Section) | |
| 340 | if (!da->section) | |
| 342 | 341 | continue; |
| 343 | auto *X = dyn_cast<InputSection>(DA->Section); | |
| 344 | if (!X) | |
| 342 | auto *x = dyn_cast<InputSection>(da->section); | |
| 343 | if (!x) | |
| 345 | 344 | continue; |
| 346 | auto *Y = cast<InputSection>(DB->Section); | |
| 345 | auto *y = cast<InputSection>(db->section); | |
| 347 | 346 | |
| 348 | 347 | // Ineligible sections are in the special equivalence class 0. |
| 349 | 348 | // They can never be the same in terms of the equivalence class. |
| 350 | if (X->Class[Current] == 0) | |
| 349 | if (x->eqClass[current] == 0) | |
| 351 | 350 | return false; |
| 352 | if (X->Class[Current] != Y->Class[Current]) | |
| 351 | if (x->eqClass[current] != y->eqClass[current]) | |
| 353 | 352 | return false; |
| 354 | 353 | }; |
| 355 | 354 | |
| ... | ... | @@ -358,19 +357,19 @@ bool ICF<ELFT>::variableEq(const InputSection *SecA, ArrayRef<RelTy> RA, |
| 358 | 357 | |
| 359 | 358 | // Compare "moving" part of two InputSections, namely relocation targets. |
| 360 | 359 | template <class ELFT> |
| 361 | bool ICF<ELFT>::equalsVariable(const InputSection *A, const InputSection *B) { | |
| 362 | if (A->AreRelocsRela) | |
| 363 | return variableEq(A, A->template relas<ELFT>(), B, | |
| 364 | B->template relas<ELFT>()); | |
| 365 | return variableEq(A, A->template rels<ELFT>(), B, B->template rels<ELFT>()); | |
| 360 | bool ICF<ELFT>::equalsVariable(const InputSection *a, const InputSection *b) { | |
| 361 | if (a->areRelocsRela) | |
| 362 | return variableEq(a, a->template relas<ELFT>(), b, | |
| 363 | b->template relas<ELFT>()); | |
| 364 | return variableEq(a, a->template rels<ELFT>(), b, b->template rels<ELFT>()); | |
| 366 | 365 | } |
| 367 | 366 | |
| 368 | template <class ELFT> size_t ICF<ELFT>::findBoundary(size_t Begin, size_t End) { | |
| 369 | uint32_t Class = Sections[Begin]->Class[Current]; | |
| 370 | for (size_t I = Begin + 1; I < End; ++I) | |
| 371 | if (Class != Sections[I]->Class[Current]) | |
| 372 | return I; | |
| 373 | return End; | |
| 367 | template <class ELFT> size_t ICF<ELFT>::findBoundary(size_t begin, size_t end) { | |
| 368 | uint32_t eqClass = sections[begin]->eqClass[current]; | |
| 369 | for (size_t i = begin + 1; i < end; ++i) | |
| 370 | if (eqClass != sections[i]->eqClass[current]) | |
| 371 | return i; | |
| 372 | return end; | |
| 374 | 373 | } |
| 375 | 374 | |
| 376 | 375 | // Sections in the same equivalence class are contiguous in Sections |
| ... | ... | @@ -379,126 +378,125 @@ template <class ELFT> size_t ICF<ELFT>::findBoundary(size_t Begin, size_t End) { |
| 379 | 378 | // |
| 380 | 379 | // This function calls Fn on every group within [Begin, End). |
| 381 | 380 | template <class ELFT> |
| 382 | void ICF<ELFT>::forEachClassRange(size_t Begin, size_t End, | |
| 383 | llvm::function_ref<void(size_t, size_t)> Fn) { | |
| 384 | while (Begin < End) { | |
| 385 | size_t Mid = findBoundary(Begin, End); | |
| 386 | Fn(Begin, Mid); | |
| 387 | Begin = Mid; | |
| 381 | void ICF<ELFT>::forEachClassRange(size_t begin, size_t end, | |
| 382 | llvm::function_ref<void(size_t, size_t)> fn) { | |
| 383 | while (begin < end) { | |
| 384 | size_t mid = findBoundary(begin, end); | |
| 385 | fn(begin, mid); | |
| 386 | begin = mid; | |
| 388 | 387 | } |
| 389 | 388 | } |
| 390 | 389 | |
| 391 | 390 | // Call Fn on each equivalence class. |
| 392 | 391 | template <class ELFT> |
| 393 | void ICF<ELFT>::forEachClass(llvm::function_ref<void(size_t, size_t)> Fn) { | |
| 392 | void ICF<ELFT>::forEachClass(llvm::function_ref<void(size_t, size_t)> fn) { | |
| 394 | 393 | // If threading is disabled or the number of sections are |
| 395 | 394 | // too small to use threading, call Fn sequentially. |
| 396 | if (!ThreadsEnabled || Sections.size() < 1024) { | |
| 397 | forEachClassRange(0, Sections.size(), Fn); | |
| 398 | ++Cnt; | |
| 395 | if (!threadsEnabled || sections.size() < 1024) { | |
| 396 | forEachClassRange(0, sections.size(), fn); | |
| 397 | ++cnt; | |
| 399 | 398 | return; |
| 400 | 399 | } |
| 401 | 400 | |
| 402 | Current = Cnt % 2; | |
| 403 | Next = (Cnt + 1) % 2; | |
| 401 | current = cnt % 2; | |
| 402 | next = (cnt + 1) % 2; | |
| 404 | 403 | |
| 405 | 404 | // Shard into non-overlapping intervals, and call Fn in parallel. |
| 406 | 405 | // The sharding must be completed before any calls to Fn are made |
| 407 | 406 | // so that Fn can modify the Chunks in its shard without causing data |
| 408 | 407 | // races. |
| 409 | const size_t NumShards = 256; | |
| 410 | size_t Step = Sections.size() / NumShards; | |
| 411 | size_t Boundaries[NumShards + 1]; | |
| 412 | Boundaries[0] = 0; | |
| 413 | Boundaries[NumShards] = Sections.size(); | |
| 414 | ||
| 415 | parallelForEachN(1, NumShards, [&](size_t I) { | |
| 416 | Boundaries[I] = findBoundary((I - 1) * Step, Sections.size()); | |
| 408 | const size_t numShards = 256; | |
| 409 | size_t step = sections.size() / numShards; | |
| 410 | size_t boundaries[numShards + 1]; | |
| 411 | boundaries[0] = 0; | |
| 412 | boundaries[numShards] = sections.size(); | |
| 413 | ||
| 414 | parallelForEachN(1, numShards, [&](size_t i) { | |
| 415 | boundaries[i] = findBoundary((i - 1) * step, sections.size()); | |
| 417 | 416 | }); |
| 418 | 417 | |
| 419 | parallelForEachN(1, NumShards + 1, [&](size_t I) { | |
| 420 | if (Boundaries[I - 1] < Boundaries[I]) | |
| 421 | forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn); | |
| 418 | parallelForEachN(1, numShards + 1, [&](size_t i) { | |
| 419 | if (boundaries[i - 1] < boundaries[i]) | |
| 420 | forEachClassRange(boundaries[i - 1], boundaries[i], fn); | |
| 422 | 421 | }); |
| 423 | ++Cnt; | |
| 422 | ++cnt; | |
| 424 | 423 | } |
| 425 | 424 | |
| 426 | 425 | // Combine the hashes of the sections referenced by the given section into its |
| 427 | 426 | // hash. |
| 428 | 427 | template <class ELFT, class RelTy> |
| 429 | static void combineRelocHashes(unsigned Cnt, InputSection *IS, | |
| 430 | ArrayRef<RelTy> Rels) { | |
| 431 | uint32_t Hash = IS->Class[Cnt % 2]; | |
| 432 | for (RelTy Rel : Rels) { | |
| 433 | Symbol &S = IS->template getFile<ELFT>()->getRelocTargetSym(Rel); | |
| 434 | if (auto *D = dyn_cast<Defined>(&S)) | |
| 435 | if (auto *RelSec = dyn_cast_or_null<InputSection>(D->Section)) | |
| 436 | Hash += RelSec->Class[Cnt % 2]; | |
| 428 | static void combineRelocHashes(unsigned cnt, InputSection *isec, | |
| 429 | ArrayRef<RelTy> rels) { | |
| 430 | uint32_t hash = isec->eqClass[cnt % 2]; | |
| 431 | for (RelTy rel : rels) { | |
| 432 | Symbol &s = isec->template getFile<ELFT>()->getRelocTargetSym(rel); | |
| 433 | if (auto *d = dyn_cast<Defined>(&s)) | |
| 434 | if (auto *relSec = dyn_cast_or_null<InputSection>(d->section)) | |
| 435 | hash += relSec->eqClass[cnt % 2]; | |
| 437 | 436 | } |
| 438 | 437 | // Set MSB to 1 to avoid collisions with non-hash IDs. |
| 439 | IS->Class[(Cnt + 1) % 2] = Hash | (1U << 31); | |
| 438 | isec->eqClass[(cnt + 1) % 2] = hash | (1U << 31); | |
| 440 | 439 | } |
| 441 | 440 | |
| 442 | static void print(const Twine &S) { | |
| 443 | if (Config->PrintIcfSections) | |
| 444 | message(S); | |
| 441 | static void print(const Twine &s) { | |
| 442 | if (config->printIcfSections) | |
| 443 | message(s); | |
| 445 | 444 | } |
| 446 | 445 | |
| 447 | 446 | // The main function of ICF. |
| 448 | 447 | template <class ELFT> void ICF<ELFT>::run() { |
| 449 | 448 | // Collect sections to merge. |
| 450 | for (InputSectionBase *Sec : InputSections) | |
| 451 | if (auto *S = dyn_cast<InputSection>(Sec)) | |
| 452 | if (isEligible(S)) | |
| 453 | Sections.push_back(S); | |
| 449 | for (InputSectionBase *sec : inputSections) | |
| 450 | if (auto *s = dyn_cast<InputSection>(sec)) | |
| 451 | if (isEligible(s)) | |
| 452 | sections.push_back(s); | |
| 454 | 453 | |
| 455 | 454 | // Initially, we use hash values to partition sections. |
| 456 | parallelForEach(Sections, [&](InputSection *S) { | |
| 457 | S->Class[0] = xxHash64(S->data()); | |
| 455 | parallelForEach(sections, [&](InputSection *s) { | |
| 456 | s->eqClass[0] = xxHash64(s->data()); | |
| 458 | 457 | }); |
| 459 | 458 | |
| 460 | for (unsigned Cnt = 0; Cnt != 2; ++Cnt) { | |
| 461 | parallelForEach(Sections, [&](InputSection *S) { | |
| 462 | if (S->AreRelocsRela) | |
| 463 | combineRelocHashes<ELFT>(Cnt, S, S->template relas<ELFT>()); | |
| 459 | for (unsigned cnt = 0; cnt != 2; ++cnt) { | |
| 460 | parallelForEach(sections, [&](InputSection *s) { | |
| 461 | if (s->areRelocsRela) | |
| 462 | combineRelocHashes<ELFT>(cnt, s, s->template relas<ELFT>()); | |
| 464 | 463 | else |
| 465 | combineRelocHashes<ELFT>(Cnt, S, S->template rels<ELFT>()); | |
| 464 | combineRelocHashes<ELFT>(cnt, s, s->template rels<ELFT>()); | |
| 466 | 465 | }); |
| 467 | 466 | } |
| 468 | 467 | |
| 469 | 468 | // From now on, sections in Sections vector are ordered so that sections |
| 470 | 469 | // in the same equivalence class are consecutive in the vector. |
| 471 | std::stable_sort(Sections.begin(), Sections.end(), | |
| 472 | [](InputSection *A, InputSection *B) { | |
| 473 | return A->Class[0] < B->Class[0]; | |
| 474 | }); | |
| 470 | llvm::stable_sort(sections, [](const InputSection *a, const InputSection *b) { | |
| 471 | return a->eqClass[0] < b->eqClass[0]; | |
| 472 | }); | |
| 475 | 473 | |
| 476 | 474 | // Compare static contents and assign unique IDs for each static content. |
| 477 | forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); }); | |
| 475 | forEachClass([&](size_t begin, size_t end) { segregate(begin, end, true); }); | |
| 478 | 476 | |
| 479 | 477 | // Split groups by comparing relocations until convergence is obtained. |
| 480 | 478 | do { |
| 481 | Repeat = false; | |
| 479 | repeat = false; | |
| 482 | 480 | forEachClass( |
| 483 | [&](size_t Begin, size_t End) { segregate(Begin, End, false); }); | |
| 484 | } while (Repeat); | |
| 481 | [&](size_t begin, size_t end) { segregate(begin, end, false); }); | |
| 482 | } while (repeat); | |
| 485 | 483 | |
| 486 | log("ICF needed " + Twine(Cnt) + " iterations"); | |
| 484 | log("ICF needed " + Twine(cnt) + " iterations"); | |
| 487 | 485 | |
| 488 | 486 | // Merge sections by the equivalence class. |
| 489 | forEachClassRange(0, Sections.size(), [&](size_t Begin, size_t End) { | |
| 490 | if (End - Begin == 1) | |
| 487 | forEachClassRange(0, sections.size(), [&](size_t begin, size_t end) { | |
| 488 | if (end - begin == 1) | |
| 491 | 489 | return; |
| 492 | print("selected section " + toString(Sections[Begin])); | |
| 493 | for (size_t I = Begin + 1; I < End; ++I) { | |
| 494 | print(" removing identical section " + toString(Sections[I])); | |
| 495 | Sections[Begin]->replace(Sections[I]); | |
| 490 | print("selected section " + toString(sections[begin])); | |
| 491 | for (size_t i = begin + 1; i < end; ++i) { | |
| 492 | print(" removing identical section " + toString(sections[i])); | |
| 493 | sections[begin]->replace(sections[i]); | |
| 496 | 494 | |
| 497 | 495 | // At this point we know sections merged are fully identical and hence |
| 498 | 496 | // we want to remove duplicate implicit dependencies such as link order |
| 499 | 497 | // and relocation sections. |
| 500 | for (InputSection *IS : Sections[I]->DependentSections) | |
| 501 | IS->Live = false; | |
| 498 | for (InputSection *isec : sections[i]->dependentSections) | |
| 499 | isec->markDead(); | |
| 502 | 500 | } |
| 503 | 501 | }); |
| 504 | 502 | } |
deps/lld/ELF/ICF.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- ICF.h --------------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/ELF/InputFiles.cpp+991-691| ... | ... | @@ -1,13 +1,13 @@ |
| 1 | 1 | //===- InputFiles.cpp -----------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| 10 | 9 | #include "InputFiles.h" |
| 10 | #include "Driver.h" | |
| 11 | 11 | #include "InputSection.h" |
| 12 | 12 | #include "LinkerScript.h" |
| 13 | 13 | #include "SymbolTable.h" |
| ... | ... | @@ -25,6 +25,7 @@ |
| 25 | 25 | #include "llvm/Object/ELFObjectFile.h" |
| 26 | 26 | #include "llvm/Support/ARMAttributeParser.h" |
| 27 | 27 | #include "llvm/Support/ARMBuildAttributes.h" |
| 28 | #include "llvm/Support/Endian.h" | |
| 28 | 29 | #include "llvm/Support/Path.h" |
| 29 | 30 | #include "llvm/Support/TarWriter.h" |
| 30 | 31 | #include "llvm/Support/raw_ostream.h" |
| ... | ... | @@ -34,145 +35,272 @@ using namespace llvm::ELF; |
| 34 | 35 | using namespace llvm::object; |
| 35 | 36 | using namespace llvm::sys; |
| 36 | 37 | using namespace llvm::sys::fs; |
| 38 | using namespace llvm::support::endian; | |
| 37 | 39 | |
| 38 | 40 | using namespace lld; |
| 39 | 41 | using namespace lld::elf; |
| 40 | 42 | |
| 41 | bool InputFile::IsInGroup; | |
| 42 | uint32_t InputFile::NextGroupId; | |
| 43 | std::vector<BinaryFile *> elf::BinaryFiles; | |
| 44 | std::vector<BitcodeFile *> elf::BitcodeFiles; | |
| 45 | std::vector<LazyObjFile *> elf::LazyObjFiles; | |
| 46 | std::vector<InputFile *> elf::ObjectFiles; | |
| 47 | std::vector<InputFile *> elf::SharedFiles; | |
| 48 | ||
| 49 | std::unique_ptr<TarWriter> elf::Tar; | |
| 43 | bool InputFile::isInGroup; | |
| 44 | uint32_t InputFile::nextGroupId; | |
| 45 | std::vector<BinaryFile *> elf::binaryFiles; | |
| 46 | std::vector<BitcodeFile *> elf::bitcodeFiles; | |
| 47 | std::vector<LazyObjFile *> elf::lazyObjFiles; | |
| 48 | std::vector<InputFile *> elf::objectFiles; | |
| 49 | std::vector<SharedFile *> elf::sharedFiles; | |
| 50 | ||
| 51 | std::unique_ptr<TarWriter> elf::tar; | |
| 52 | ||
| 53 | static ELFKind getELFKind(MemoryBufferRef mb, StringRef archiveName) { | |
| 54 | unsigned char size; | |
| 55 | unsigned char endian; | |
| 56 | std::tie(size, endian) = getElfArchType(mb.getBuffer()); | |
| 57 | ||
| 58 | auto report = [&](StringRef msg) { | |
| 59 | StringRef filename = mb.getBufferIdentifier(); | |
| 60 | if (archiveName.empty()) | |
| 61 | fatal(filename + ": " + msg); | |
| 62 | else | |
| 63 | fatal(archiveName + "(" + filename + "): " + msg); | |
| 64 | }; | |
| 65 | ||
| 66 | if (!mb.getBuffer().startswith(ElfMagic)) | |
| 67 | report("not an ELF file"); | |
| 68 | if (endian != ELFDATA2LSB && endian != ELFDATA2MSB) | |
| 69 | report("corrupted ELF file: invalid data encoding"); | |
| 70 | if (size != ELFCLASS32 && size != ELFCLASS64) | |
| 71 | report("corrupted ELF file: invalid file class"); | |
| 72 | ||
| 73 | size_t bufSize = mb.getBuffer().size(); | |
| 74 | if ((size == ELFCLASS32 && bufSize < sizeof(Elf32_Ehdr)) || | |
| 75 | (size == ELFCLASS64 && bufSize < sizeof(Elf64_Ehdr))) | |
| 76 | report("corrupted ELF file: file is too short"); | |
| 77 | ||
| 78 | if (size == ELFCLASS32) | |
| 79 | return (endian == ELFDATA2LSB) ? ELF32LEKind : ELF32BEKind; | |
| 80 | return (endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind; | |
| 81 | } | |
| 50 | 82 | |
| 51 | InputFile::InputFile(Kind K, MemoryBufferRef M) | |
| 52 | : MB(M), GroupId(NextGroupId), FileKind(K) { | |
| 83 | InputFile::InputFile(Kind k, MemoryBufferRef m) | |
| 84 | : mb(m), groupId(nextGroupId), fileKind(k) { | |
| 53 | 85 | // All files within the same --{start,end}-group get the same group ID. |
| 54 | 86 | // Otherwise, a new file will get a new group ID. |
| 55 | if (!IsInGroup) | |
| 56 | ++NextGroupId; | |
| 87 | if (!isInGroup) | |
| 88 | ++nextGroupId; | |
| 57 | 89 | } |
| 58 | 90 | |
| 59 | Optional<MemoryBufferRef> elf::readFile(StringRef Path) { | |
| 91 | Optional<MemoryBufferRef> elf::readFile(StringRef path) { | |
| 60 | 92 | // The --chroot option changes our virtual root directory. |
| 61 | 93 | // This is useful when you are dealing with files created by --reproduce. |
| 62 | if (!Config->Chroot.empty() && Path.startswith("/")) | |
| 63 | Path = Saver.save(Config->Chroot + Path); | |
| 94 | if (!config->chroot.empty() && path.startswith("/")) | |
| 95 | path = saver.save(config->chroot + path); | |
| 64 | 96 | |
| 65 | log(Path); | |
| 97 | log(path); | |
| 66 | 98 | |
| 67 | auto MBOrErr = MemoryBuffer::getFile(Path, -1, false); | |
| 68 | if (auto EC = MBOrErr.getError()) { | |
| 69 | error("cannot open " + Path + ": " + EC.message()); | |
| 99 | auto mbOrErr = MemoryBuffer::getFile(path, -1, false); | |
| 100 | if (auto ec = mbOrErr.getError()) { | |
| 101 | error("cannot open " + path + ": " + ec.message()); | |
| 70 | 102 | return None; |
| 71 | 103 | } |
| 72 | 104 | |
| 73 | std::unique_ptr<MemoryBuffer> &MB = *MBOrErr; | |
| 74 | MemoryBufferRef MBRef = MB->getMemBufferRef(); | |
| 75 | make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership | |
| 105 | std::unique_ptr<MemoryBuffer> &mb = *mbOrErr; | |
| 106 | MemoryBufferRef mbref = mb->getMemBufferRef(); | |
| 107 | make<std::unique_ptr<MemoryBuffer>>(std::move(mb)); // take MB ownership | |
| 108 | ||
| 109 | if (tar) | |
| 110 | tar->append(relativeToRoot(path), mbref.getBuffer()); | |
| 111 | return mbref; | |
| 112 | } | |
| 113 | ||
| 114 | // All input object files must be for the same architecture | |
| 115 | // (e.g. it does not make sense to link x86 object files with | |
| 116 | // MIPS object files.) This function checks for that error. | |
| 117 | static bool isCompatible(InputFile *file) { | |
| 118 | if (!file->isElf() && !isa<BitcodeFile>(file)) | |
| 119 | return true; | |
| 120 | ||
| 121 | if (file->ekind == config->ekind && file->emachine == config->emachine) { | |
| 122 | if (config->emachine != EM_MIPS) | |
| 123 | return true; | |
| 124 | if (isMipsN32Abi(file) == config->mipsN32Abi) | |
| 125 | return true; | |
| 126 | } | |
| 127 | ||
| 128 | if (!config->emulation.empty()) { | |
| 129 | error(toString(file) + " is incompatible with " + config->emulation); | |
| 130 | } else { | |
| 131 | InputFile *existing; | |
| 132 | if (!objectFiles.empty()) | |
| 133 | existing = objectFiles[0]; | |
| 134 | else if (!sharedFiles.empty()) | |
| 135 | existing = sharedFiles[0]; | |
| 136 | else | |
| 137 | existing = bitcodeFiles[0]; | |
| 138 | ||
| 139 | error(toString(file) + " is incompatible with " + toString(existing)); | |
| 140 | } | |
| 141 | ||
| 142 | return false; | |
| 143 | } | |
| 144 | ||
| 145 | template <class ELFT> static void doParseFile(InputFile *file) { | |
| 146 | if (!isCompatible(file)) | |
| 147 | return; | |
| 148 | ||
| 149 | // Binary file | |
| 150 | if (auto *f = dyn_cast<BinaryFile>(file)) { | |
| 151 | binaryFiles.push_back(f); | |
| 152 | f->parse(); | |
| 153 | return; | |
| 154 | } | |
| 155 | ||
| 156 | // .a file | |
| 157 | if (auto *f = dyn_cast<ArchiveFile>(file)) { | |
| 158 | f->parse(); | |
| 159 | return; | |
| 160 | } | |
| 161 | ||
| 162 | // Lazy object file | |
| 163 | if (auto *f = dyn_cast<LazyObjFile>(file)) { | |
| 164 | lazyObjFiles.push_back(f); | |
| 165 | f->parse<ELFT>(); | |
| 166 | return; | |
| 167 | } | |
| 168 | ||
| 169 | if (config->trace) | |
| 170 | message(toString(file)); | |
| 76 | 171 | |
| 77 | if (Tar) | |
| 78 | Tar->append(relativeToRoot(Path), MBRef.getBuffer()); | |
| 79 | return MBRef; | |
| 172 | // .so file | |
| 173 | if (auto *f = dyn_cast<SharedFile>(file)) { | |
| 174 | f->parse<ELFT>(); | |
| 175 | return; | |
| 176 | } | |
| 177 | ||
| 178 | // LLVM bitcode file | |
| 179 | if (auto *f = dyn_cast<BitcodeFile>(file)) { | |
| 180 | bitcodeFiles.push_back(f); | |
| 181 | f->parse<ELFT>(); | |
| 182 | return; | |
| 183 | } | |
| 184 | ||
| 185 | // Regular object file | |
| 186 | objectFiles.push_back(file); | |
| 187 | cast<ObjFile<ELFT>>(file)->parse(); | |
| 188 | } | |
| 189 | ||
| 190 | // Add symbols in File to the symbol table. | |
| 191 | void elf::parseFile(InputFile *file) { | |
| 192 | switch (config->ekind) { | |
| 193 | case ELF32LEKind: | |
| 194 | doParseFile<ELF32LE>(file); | |
| 195 | return; | |
| 196 | case ELF32BEKind: | |
| 197 | doParseFile<ELF32BE>(file); | |
| 198 | return; | |
| 199 | case ELF64LEKind: | |
| 200 | doParseFile<ELF64LE>(file); | |
| 201 | return; | |
| 202 | case ELF64BEKind: | |
| 203 | doParseFile<ELF64BE>(file); | |
| 204 | return; | |
| 205 | default: | |
| 206 | llvm_unreachable("unknown ELFT"); | |
| 207 | } | |
| 80 | 208 | } |
| 81 | 209 | |
| 82 | 210 | // Concatenates arguments to construct a string representing an error location. |
| 83 | static std::string createFileLineMsg(StringRef Path, unsigned Line) { | |
| 84 | std::string Filename = path::filename(Path); | |
| 85 | std::string Lineno = ":" + std::to_string(Line); | |
| 86 | if (Filename == Path) | |
| 87 | return Filename + Lineno; | |
| 88 | return Filename + Lineno + " (" + Path.str() + Lineno + ")"; | |
| 211 | static std::string createFileLineMsg(StringRef path, unsigned line) { | |
| 212 | std::string filename = path::filename(path); | |
| 213 | std::string lineno = ":" + std::to_string(line); | |
| 214 | if (filename == path) | |
| 215 | return filename + lineno; | |
| 216 | return filename + lineno + " (" + path.str() + lineno + ")"; | |
| 89 | 217 | } |
| 90 | 218 | |
| 91 | 219 | template <class ELFT> |
| 92 | static std::string getSrcMsgAux(ObjFile<ELFT> &File, const Symbol &Sym, | |
| 93 | InputSectionBase &Sec, uint64_t Offset) { | |
| 220 | static std::string getSrcMsgAux(ObjFile<ELFT> &file, const Symbol &sym, | |
| 221 | InputSectionBase &sec, uint64_t offset) { | |
| 94 | 222 | // In DWARF, functions and variables are stored to different places. |
| 95 | 223 | // First, lookup a function for a given offset. |
| 96 | if (Optional<DILineInfo> Info = File.getDILineInfo(&Sec, Offset)) | |
| 97 | return createFileLineMsg(Info->FileName, Info->Line); | |
| 224 | if (Optional<DILineInfo> info = file.getDILineInfo(&sec, offset)) | |
| 225 | return createFileLineMsg(info->FileName, info->Line); | |
| 98 | 226 | |
| 99 | 227 | // If it failed, lookup again as a variable. |
| 100 | if (Optional<std::pair<std::string, unsigned>> FileLine = | |
| 101 | File.getVariableLoc(Sym.getName())) | |
| 102 | return createFileLineMsg(FileLine->first, FileLine->second); | |
| 228 | if (Optional<std::pair<std::string, unsigned>> fileLine = | |
| 229 | file.getVariableLoc(sym.getName())) | |
| 230 | return createFileLineMsg(fileLine->first, fileLine->second); | |
| 103 | 231 | |
| 104 | // File.SourceFile contains STT_FILE symbol, and that is a last resort. | |
| 105 | return File.SourceFile; | |
| 232 | // File.sourceFile contains STT_FILE symbol, and that is a last resort. | |
| 233 | return file.sourceFile; | |
| 106 | 234 | } |
| 107 | 235 | |
| 108 | std::string InputFile::getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, | |
| 109 | uint64_t Offset) { | |
| 236 | std::string InputFile::getSrcMsg(const Symbol &sym, InputSectionBase &sec, | |
| 237 | uint64_t offset) { | |
| 110 | 238 | if (kind() != ObjKind) |
| 111 | 239 | return ""; |
| 112 | switch (Config->EKind) { | |
| 240 | switch (config->ekind) { | |
| 113 | 241 | default: |
| 114 | 242 | llvm_unreachable("Invalid kind"); |
| 115 | 243 | case ELF32LEKind: |
| 116 | return getSrcMsgAux(cast<ObjFile<ELF32LE>>(*this), Sym, Sec, Offset); | |
| 244 | return getSrcMsgAux(cast<ObjFile<ELF32LE>>(*this), sym, sec, offset); | |
| 117 | 245 | case ELF32BEKind: |
| 118 | return getSrcMsgAux(cast<ObjFile<ELF32BE>>(*this), Sym, Sec, Offset); | |
| 246 | return getSrcMsgAux(cast<ObjFile<ELF32BE>>(*this), sym, sec, offset); | |
| 119 | 247 | case ELF64LEKind: |
| 120 | return getSrcMsgAux(cast<ObjFile<ELF64LE>>(*this), Sym, Sec, Offset); | |
| 248 | return getSrcMsgAux(cast<ObjFile<ELF64LE>>(*this), sym, sec, offset); | |
| 121 | 249 | case ELF64BEKind: |
| 122 | return getSrcMsgAux(cast<ObjFile<ELF64BE>>(*this), Sym, Sec, Offset); | |
| 250 | return getSrcMsgAux(cast<ObjFile<ELF64BE>>(*this), sym, sec, offset); | |
| 123 | 251 | } |
| 124 | 252 | } |
| 125 | 253 | |
| 126 | 254 | template <class ELFT> void ObjFile<ELFT>::initializeDwarf() { |
| 127 | Dwarf = llvm::make_unique<DWARFContext>(make_unique<LLDDwarfObj<ELFT>>(this)); | |
| 128 | for (std::unique_ptr<DWARFUnit> &CU : Dwarf->compile_units()) { | |
| 129 | auto Report = [](Error Err) { | |
| 130 | handleAllErrors(std::move(Err), | |
| 131 | [](ErrorInfoBase &Info) { warn(Info.message()); }); | |
| 255 | dwarf = llvm::make_unique<DWARFContext>(make_unique<LLDDwarfObj<ELFT>>(this)); | |
| 256 | for (std::unique_ptr<DWARFUnit> &cu : dwarf->compile_units()) { | |
| 257 | auto report = [](Error err) { | |
| 258 | handleAllErrors(std::move(err), | |
| 259 | [](ErrorInfoBase &info) { warn(info.message()); }); | |
| 132 | 260 | }; |
| 133 | Expected<const DWARFDebugLine::LineTable *> ExpectedLT = | |
| 134 | Dwarf->getLineTableForUnit(CU.get(), Report); | |
| 135 | const DWARFDebugLine::LineTable *LT = nullptr; | |
| 136 | if (ExpectedLT) | |
| 137 | LT = *ExpectedLT; | |
| 261 | Expected<const DWARFDebugLine::LineTable *> expectedLT = | |
| 262 | dwarf->getLineTableForUnit(cu.get(), report); | |
| 263 | const DWARFDebugLine::LineTable *lt = nullptr; | |
| 264 | if (expectedLT) | |
| 265 | lt = *expectedLT; | |
| 138 | 266 | else |
| 139 | Report(ExpectedLT.takeError()); | |
| 140 | if (!LT) | |
| 267 | report(expectedLT.takeError()); | |
| 268 | if (!lt) | |
| 141 | 269 | continue; |
| 142 | LineTables.push_back(LT); | |
| 270 | lineTables.push_back(lt); | |
| 143 | 271 | |
| 144 | // Loop over variable records and insert them to VariableLoc. | |
| 145 | for (const auto &Entry : CU->dies()) { | |
| 146 | DWARFDie Die(CU.get(), &Entry); | |
| 272 | // Loop over variable records and insert them to variableLoc. | |
| 273 | for (const auto &entry : cu->dies()) { | |
| 274 | DWARFDie die(cu.get(), &entry); | |
| 147 | 275 | // Skip all tags that are not variables. |
| 148 | if (Die.getTag() != dwarf::DW_TAG_variable) | |
| 276 | if (die.getTag() != dwarf::DW_TAG_variable) | |
| 149 | 277 | continue; |
| 150 | 278 | |
| 151 | 279 | // Skip if a local variable because we don't need them for generating |
| 152 | 280 | // error messages. In general, only non-local symbols can fail to be |
| 153 | 281 | // linked. |
| 154 | if (!dwarf::toUnsigned(Die.find(dwarf::DW_AT_external), 0)) | |
| 282 | if (!dwarf::toUnsigned(die.find(dwarf::DW_AT_external), 0)) | |
| 155 | 283 | continue; |
| 156 | 284 | |
| 157 | 285 | // Get the source filename index for the variable. |
| 158 | unsigned File = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_file), 0); | |
| 159 | if (!LT->hasFileAtIndex(File)) | |
| 286 | unsigned file = dwarf::toUnsigned(die.find(dwarf::DW_AT_decl_file), 0); | |
| 287 | if (!lt->hasFileAtIndex(file)) | |
| 160 | 288 | continue; |
| 161 | 289 | |
| 162 | 290 | // Get the line number on which the variable is declared. |
| 163 | unsigned Line = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_line), 0); | |
| 291 | unsigned line = dwarf::toUnsigned(die.find(dwarf::DW_AT_decl_line), 0); | |
| 164 | 292 | |
| 165 | // Here we want to take the variable name to add it into VariableLoc. | |
| 293 | // Here we want to take the variable name to add it into variableLoc. | |
| 166 | 294 | // Variable can have regular and linkage name associated. At first, we try |
| 167 | 295 | // to get linkage name as it can be different, for example when we have |
| 168 | 296 | // two variables in different namespaces of the same object. Use common |
| 169 | 297 | // name otherwise, but handle the case when it also absent in case if the |
| 170 | 298 | // input object file lacks some debug info. |
| 171 | StringRef Name = | |
| 172 | dwarf::toString(Die.find(dwarf::DW_AT_linkage_name), | |
| 173 | dwarf::toString(Die.find(dwarf::DW_AT_name), "")); | |
| 174 | if (!Name.empty()) | |
| 175 | VariableLoc.insert({Name, {LT, File, Line}}); | |
| 299 | StringRef name = | |
| 300 | dwarf::toString(die.find(dwarf::DW_AT_linkage_name), | |
| 301 | dwarf::toString(die.find(dwarf::DW_AT_name), "")); | |
| 302 | if (!name.empty()) | |
| 303 | variableLoc.insert({name, {lt, file, line}}); | |
| 176 | 304 | } |
| 177 | 305 | } |
| 178 | 306 | } |
| ... | ... | @@ -181,112 +309,152 @@ template <class ELFT> void ObjFile<ELFT>::initializeDwarf() { |
| 181 | 309 | // object (variable, array, etc) definition. |
| 182 | 310 | template <class ELFT> |
| 183 | 311 | Optional<std::pair<std::string, unsigned>> |
| 184 | ObjFile<ELFT>::getVariableLoc(StringRef Name) { | |
| 185 | llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); | |
| 312 | ObjFile<ELFT>::getVariableLoc(StringRef name) { | |
| 313 | llvm::call_once(initDwarfLine, [this]() { initializeDwarf(); }); | |
| 186 | 314 | |
| 187 | 315 | // Return if we have no debug information about data object. |
| 188 | auto It = VariableLoc.find(Name); | |
| 189 | if (It == VariableLoc.end()) | |
| 316 | auto it = variableLoc.find(name); | |
| 317 | if (it == variableLoc.end()) | |
| 190 | 318 | return None; |
| 191 | 319 | |
| 192 | 320 | // Take file name string from line table. |
| 193 | std::string FileName; | |
| 194 | if (!It->second.LT->getFileNameByIndex( | |
| 195 | It->second.File, nullptr, | |
| 196 | DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FileName)) | |
| 321 | std::string fileName; | |
| 322 | if (!it->second.lt->getFileNameByIndex( | |
| 323 | it->second.file, {}, | |
| 324 | DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, fileName)) | |
| 197 | 325 | return None; |
| 198 | 326 | |
| 199 | return std::make_pair(FileName, It->second.Line); | |
| 327 | return std::make_pair(fileName, it->second.line); | |
| 200 | 328 | } |
| 201 | 329 | |
| 202 | 330 | // Returns source line information for a given offset |
| 203 | 331 | // using DWARF debug info. |
| 204 | 332 | template <class ELFT> |
| 205 | Optional<DILineInfo> ObjFile<ELFT>::getDILineInfo(InputSectionBase *S, | |
| 206 | uint64_t Offset) { | |
| 207 | llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); | |
| 333 | Optional<DILineInfo> ObjFile<ELFT>::getDILineInfo(InputSectionBase *s, | |
| 334 | uint64_t offset) { | |
| 335 | llvm::call_once(initDwarfLine, [this]() { initializeDwarf(); }); | |
| 336 | ||
| 337 | // Detect SectionIndex for specified section. | |
| 338 | uint64_t sectionIndex = object::SectionedAddress::UndefSection; | |
| 339 | ArrayRef<InputSectionBase *> sections = s->file->getSections(); | |
| 340 | for (uint64_t curIndex = 0; curIndex < sections.size(); ++curIndex) { | |
| 341 | if (s == sections[curIndex]) { | |
| 342 | sectionIndex = curIndex; | |
| 343 | break; | |
| 344 | } | |
| 345 | } | |
| 208 | 346 | |
| 209 | 347 | // Use fake address calcuated by adding section file offset and offset in |
| 210 | 348 | // section. See comments for ObjectInfo class. |
| 211 | DILineInfo Info; | |
| 212 | for (const llvm::DWARFDebugLine::LineTable *LT : LineTables) | |
| 213 | if (LT->getFileLineInfoForAddress( | |
| 214 | S->getOffsetInFile() + Offset, nullptr, | |
| 215 | DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info)) | |
| 216 | return Info; | |
| 349 | DILineInfo info; | |
| 350 | for (const llvm::DWARFDebugLine::LineTable *lt : lineTables) { | |
| 351 | if (lt->getFileLineInfoForAddress( | |
| 352 | {s->getOffsetInFile() + offset, sectionIndex}, nullptr, | |
| 353 | DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, info)) | |
| 354 | return info; | |
| 355 | } | |
| 217 | 356 | return None; |
| 218 | 357 | } |
| 219 | 358 | |
| 220 | 359 | // Returns "<internal>", "foo.a(bar.o)" or "baz.o". |
| 221 | std::string lld::toString(const InputFile *F) { | |
| 222 | if (!F) | |
| 360 | std::string lld::toString(const InputFile *f) { | |
| 361 | if (!f) | |
| 223 | 362 | return "<internal>"; |
| 224 | 363 | |
| 225 | if (F->ToStringCache.empty()) { | |
| 226 | if (F->ArchiveName.empty()) | |
| 227 | F->ToStringCache = F->getName(); | |
| 364 | if (f->toStringCache.empty()) { | |
| 365 | if (f->archiveName.empty()) | |
| 366 | f->toStringCache = f->getName(); | |
| 228 | 367 | else |
| 229 | F->ToStringCache = (F->ArchiveName + "(" + F->getName() + ")").str(); | |
| 368 | f->toStringCache = (f->archiveName + "(" + f->getName() + ")").str(); | |
| 230 | 369 | } |
| 231 | return F->ToStringCache; | |
| 370 | return f->toStringCache; | |
| 232 | 371 | } |
| 233 | 372 | |
| 234 | template <class ELFT> | |
| 235 | ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) { | |
| 236 | if (ELFT::TargetEndianness == support::little) | |
| 237 | EKind = ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind; | |
| 238 | else | |
| 239 | EKind = ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind; | |
| 373 | ELFFileBase::ELFFileBase(Kind k, MemoryBufferRef mb) : InputFile(k, mb) { | |
| 374 | ekind = getELFKind(mb, ""); | |
| 240 | 375 | |
| 241 | EMachine = getObj().getHeader()->e_machine; | |
| 242 | OSABI = getObj().getHeader()->e_ident[llvm::ELF::EI_OSABI]; | |
| 376 | switch (ekind) { | |
| 377 | case ELF32LEKind: | |
| 378 | init<ELF32LE>(); | |
| 379 | break; | |
| 380 | case ELF32BEKind: | |
| 381 | init<ELF32BE>(); | |
| 382 | break; | |
| 383 | case ELF64LEKind: | |
| 384 | init<ELF64LE>(); | |
| 385 | break; | |
| 386 | case ELF64BEKind: | |
| 387 | init<ELF64BE>(); | |
| 388 | break; | |
| 389 | default: | |
| 390 | llvm_unreachable("getELFKind"); | |
| 391 | } | |
| 243 | 392 | } |
| 244 | 393 | |
| 245 | template <class ELFT> | |
| 246 | typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalELFSyms() { | |
| 247 | return makeArrayRef(ELFSyms.begin() + FirstGlobal, ELFSyms.end()); | |
| 394 | template <typename Elf_Shdr> | |
| 395 | static const Elf_Shdr *findSection(ArrayRef<Elf_Shdr> sections, uint32_t type) { | |
| 396 | for (const Elf_Shdr &sec : sections) | |
| 397 | if (sec.sh_type == type) | |
| 398 | return &sec; | |
| 399 | return nullptr; | |
| 248 | 400 | } |
| 249 | 401 | |
| 250 | template <class ELFT> | |
| 251 | uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const { | |
| 252 | return CHECK(getObj().getSectionIndex(&Sym, ELFSyms, SymtabSHNDX), this); | |
| 253 | } | |
| 402 | template <class ELFT> void ELFFileBase::init() { | |
| 403 | using Elf_Shdr = typename ELFT::Shdr; | |
| 404 | using Elf_Sym = typename ELFT::Sym; | |
| 254 | 405 | |
| 255 | template <class ELFT> | |
| 256 | void ELFFileBase<ELFT>::initSymtab(ArrayRef<Elf_Shdr> Sections, | |
| 257 | const Elf_Shdr *Symtab) { | |
| 258 | FirstGlobal = Symtab->sh_info; | |
| 259 | ELFSyms = CHECK(getObj().symbols(Symtab), this); | |
| 260 | if (FirstGlobal == 0 || FirstGlobal > ELFSyms.size()) | |
| 406 | // Initialize trivial attributes. | |
| 407 | const ELFFile<ELFT> &obj = getObj<ELFT>(); | |
| 408 | emachine = obj.getHeader()->e_machine; | |
| 409 | osabi = obj.getHeader()->e_ident[llvm::ELF::EI_OSABI]; | |
| 410 | abiVersion = obj.getHeader()->e_ident[llvm::ELF::EI_ABIVERSION]; | |
| 411 | ||
| 412 | ArrayRef<Elf_Shdr> sections = CHECK(obj.sections(), this); | |
| 413 | ||
| 414 | // Find a symbol table. | |
| 415 | bool isDSO = | |
| 416 | (identify_magic(mb.getBuffer()) == file_magic::elf_shared_object); | |
| 417 | const Elf_Shdr *symtabSec = | |
| 418 | findSection(sections, isDSO ? SHT_DYNSYM : SHT_SYMTAB); | |
| 419 | ||
| 420 | if (!symtabSec) | |
| 421 | return; | |
| 422 | ||
| 423 | // Initialize members corresponding to a symbol table. | |
| 424 | firstGlobal = symtabSec->sh_info; | |
| 425 | ||
| 426 | ArrayRef<Elf_Sym> eSyms = CHECK(obj.symbols(symtabSec), this); | |
| 427 | if (firstGlobal == 0 || firstGlobal > eSyms.size()) | |
| 261 | 428 | fatal(toString(this) + ": invalid sh_info in symbol table"); |
| 262 | 429 | |
| 263 | StringTable = | |
| 264 | CHECK(getObj().getStringTableForSymtab(*Symtab, Sections), this); | |
| 430 | elfSyms = reinterpret_cast<const void *>(eSyms.data()); | |
| 431 | numELFSyms = eSyms.size(); | |
| 432 | stringTable = CHECK(obj.getStringTableForSymtab(*symtabSec, sections), this); | |
| 265 | 433 | } |
| 266 | 434 | |
| 267 | 435 | template <class ELFT> |
| 268 | ObjFile<ELFT>::ObjFile(MemoryBufferRef M, StringRef ArchiveName) | |
| 269 | : ELFFileBase<ELFT>(Base::ObjKind, M) { | |
| 270 | this->ArchiveName = ArchiveName; | |
| 436 | uint32_t ObjFile<ELFT>::getSectionIndex(const Elf_Sym &sym) const { | |
| 437 | return CHECK( | |
| 438 | this->getObj().getSectionIndex(&sym, getELFSyms<ELFT>(), shndxTable), | |
| 439 | this); | |
| 271 | 440 | } |
| 272 | 441 | |
| 273 | 442 | template <class ELFT> ArrayRef<Symbol *> ObjFile<ELFT>::getLocalSymbols() { |
| 274 | if (this->Symbols.empty()) | |
| 443 | if (this->symbols.empty()) | |
| 275 | 444 | return {}; |
| 276 | return makeArrayRef(this->Symbols).slice(1, this->FirstGlobal - 1); | |
| 445 | return makeArrayRef(this->symbols).slice(1, this->firstGlobal - 1); | |
| 277 | 446 | } |
| 278 | 447 | |
| 279 | 448 | template <class ELFT> ArrayRef<Symbol *> ObjFile<ELFT>::getGlobalSymbols() { |
| 280 | return makeArrayRef(this->Symbols).slice(this->FirstGlobal); | |
| 449 | return makeArrayRef(this->symbols).slice(this->firstGlobal); | |
| 281 | 450 | } |
| 282 | 451 | |
| 283 | template <class ELFT> | |
| 284 | void ObjFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) { | |
| 285 | // Read a section table. JustSymbols is usually false. | |
| 286 | if (this->JustSymbols) | |
| 452 | template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) { | |
| 453 | // Read a section table. justSymbols is usually false. | |
| 454 | if (this->justSymbols) | |
| 287 | 455 | initializeJustSymbols(); |
| 288 | 456 | else |
| 289 | initializeSections(ComdatGroups); | |
| 457 | initializeSections(ignoreComdats); | |
| 290 | 458 | |
| 291 | 459 | // Read a symbol table. |
| 292 | 460 | initializeSymbols(); |
| ... | ... | @@ -296,17 +464,13 @@ void ObjFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) { |
| 296 | 464 | // They are identified and deduplicated by group name. This function |
| 297 | 465 | // returns a group name. |
| 298 | 466 | template <class ELFT> |
| 299 | StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections, | |
| 300 | const Elf_Shdr &Sec) { | |
| 301 | // Group signatures are stored as symbol names in object files. | |
| 302 | // sh_info contains a symbol index, so we fetch a symbol and read its name. | |
| 303 | if (this->ELFSyms.empty()) | |
| 304 | this->initSymtab( | |
| 305 | Sections, CHECK(object::getSection<ELFT>(Sections, Sec.sh_link), this)); | |
| 306 | ||
| 307 | const Elf_Sym *Sym = | |
| 308 | CHECK(object::getSymbol<ELFT>(this->ELFSyms, Sec.sh_info), this); | |
| 309 | StringRef Signature = CHECK(Sym->getName(this->StringTable), this); | |
| 467 | StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> sections, | |
| 468 | const Elf_Shdr &sec) { | |
| 469 | typename ELFT::SymRange symbols = this->getELFSyms<ELFT>(); | |
| 470 | if (sec.sh_info >= symbols.size()) | |
| 471 | fatal(toString(this) + ": invalid symbol index"); | |
| 472 | const typename ELFT::Sym &sym = symbols[sec.sh_info]; | |
| 473 | StringRef signature = CHECK(sym.getName(this->stringTable), this); | |
| 310 | 474 | |
| 311 | 475 | // As a special case, if a symbol is a section symbol and has no name, |
| 312 | 476 | // we use a section name as a signature. |
| ... | ... | @@ -315,12 +479,12 @@ StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections, |
| 315 | 479 | // standard, but GNU gold 1.14 (the newest version as of July 2017) or |
| 316 | 480 | // older produce such sections as outputs for the -r option, so we need |
| 317 | 481 | // a bug-compatibility. |
| 318 | if (Signature.empty() && Sym->getType() == STT_SECTION) | |
| 319 | return getSectionName(Sec); | |
| 320 | return Signature; | |
| 482 | if (signature.empty() && sym.getType() == STT_SECTION) | |
| 483 | return getSectionName(sec); | |
| 484 | return signature; | |
| 321 | 485 | } |
| 322 | 486 | |
| 323 | template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { | |
| 487 | template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &sec) { | |
| 324 | 488 | // On a regular link we don't merge sections if -O0 (default is -O1). This |
| 325 | 489 | // sometimes makes the linker significantly faster, although the output will |
| 326 | 490 | // be bigger. |
| ... | ... | @@ -333,14 +497,14 @@ template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { |
| 333 | 497 | // SHF_MERGE sections based both on their name and sh_entsize, but that seems |
| 334 | 498 | // to be more trouble than it is worth. Instead, we just use the regular (-O1) |
| 335 | 499 | // logic for -r. |
| 336 | if (Config->Optimize == 0 && !Config->Relocatable) | |
| 500 | if (config->optimize == 0 && !config->relocatable) | |
| 337 | 501 | return false; |
| 338 | 502 | |
| 339 | 503 | // A mergeable section with size 0 is useless because they don't have |
| 340 | 504 | // any data to merge. A mergeable string section with size 0 can be |
| 341 | 505 | // argued as invalid because it doesn't end with a null character. |
| 342 | 506 | // We'll avoid a mess by handling them as if they were non-mergeable. |
| 343 | if (Sec.sh_size == 0) | |
| 507 | if (sec.sh_size == 0) | |
| 344 | 508 | return false; |
| 345 | 509 | |
| 346 | 510 | // Check for sh_entsize. The ELF spec is not clear about the zero |
| ... | ... | @@ -348,17 +512,17 @@ template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { |
| 348 | 512 | // the section does not hold a table of fixed-size entries". We know |
| 349 | 513 | // that Rust 1.13 produces a string mergeable section with a zero |
| 350 | 514 | // sh_entsize. Here we just accept it rather than being picky about it. |
| 351 | uint64_t EntSize = Sec.sh_entsize; | |
| 352 | if (EntSize == 0) | |
| 515 | uint64_t entSize = sec.sh_entsize; | |
| 516 | if (entSize == 0) | |
| 353 | 517 | return false; |
| 354 | if (Sec.sh_size % EntSize) | |
| 518 | if (sec.sh_size % entSize) | |
| 355 | 519 | fatal(toString(this) + |
| 356 | 520 | ": SHF_MERGE section size must be a multiple of sh_entsize"); |
| 357 | 521 | |
| 358 | uint64_t Flags = Sec.sh_flags; | |
| 359 | if (!(Flags & SHF_MERGE)) | |
| 522 | uint64_t flags = sec.sh_flags; | |
| 523 | if (!(flags & SHF_MERGE)) | |
| 360 | 524 | return false; |
| 361 | if (Flags & SHF_WRITE) | |
| 525 | if (flags & SHF_WRITE) | |
| 362 | 526 | fatal(toString(this) + ": writable SHF_MERGE section is not supported"); |
| 363 | 527 | |
| 364 | 528 | return true; |
| ... | ... | @@ -374,126 +538,138 @@ template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { |
| 374 | 538 | // When the option is given, we link "just symbols". The section table is |
| 375 | 539 | // initialized with null pointers. |
| 376 | 540 | template <class ELFT> void ObjFile<ELFT>::initializeJustSymbols() { |
| 377 | ArrayRef<Elf_Shdr> ObjSections = CHECK(this->getObj().sections(), this); | |
| 378 | this->Sections.resize(ObjSections.size()); | |
| 541 | ArrayRef<Elf_Shdr> sections = CHECK(this->getObj().sections(), this); | |
| 542 | this->sections.resize(sections.size()); | |
| 543 | } | |
| 379 | 544 | |
| 380 | for (const Elf_Shdr &Sec : ObjSections) { | |
| 381 | if (Sec.sh_type != SHT_SYMTAB) | |
| 382 | continue; | |
| 383 | this->initSymtab(ObjSections, &Sec); | |
| 545 | // An ELF object file may contain a `.deplibs` section. If it exists, the | |
| 546 | // section contains a list of library specifiers such as `m` for libm. This | |
| 547 | // function resolves a given name by finding the first matching library checking | |
| 548 | // the various ways that a library can be specified to LLD. This ELF extension | |
| 549 | // is a form of autolinking and is called `dependent libraries`. It is currently | |
| 550 | // unique to LLVM and lld. | |
| 551 | static void addDependentLibrary(StringRef specifier, const InputFile *f) { | |
| 552 | if (!config->dependentLibraries) | |
| 384 | 553 | return; |
| 385 | } | |
| 554 | if (fs::exists(specifier)) | |
| 555 | driver->addFile(specifier, /*withLOption=*/false); | |
| 556 | else if (Optional<std::string> s = findFromSearchPaths(specifier)) | |
| 557 | driver->addFile(*s, /*withLOption=*/true); | |
| 558 | else if (Optional<std::string> s = searchLibraryBaseName(specifier)) | |
| 559 | driver->addFile(*s, /*withLOption=*/true); | |
| 560 | else | |
| 561 | error(toString(f) + | |
| 562 | ": unable to find library from dependent library specifier: " + | |
| 563 | specifier); | |
| 386 | 564 | } |
| 387 | 565 | |
| 388 | 566 | template <class ELFT> |
| 389 | void ObjFile<ELFT>::initializeSections( | |
| 390 | DenseSet<CachedHashStringRef> &ComdatGroups) { | |
| 391 | const ELFFile<ELFT> &Obj = this->getObj(); | |
| 392 | ||
| 393 | ArrayRef<Elf_Shdr> ObjSections = CHECK(Obj.sections(), this); | |
| 394 | uint64_t Size = ObjSections.size(); | |
| 395 | this->Sections.resize(Size); | |
| 396 | this->SectionStringTable = | |
| 397 | CHECK(Obj.getSectionStringTable(ObjSections), this); | |
| 398 | ||
| 399 | for (size_t I = 0, E = ObjSections.size(); I < E; I++) { | |
| 400 | if (this->Sections[I] == &InputSection::Discarded) | |
| 567 | void ObjFile<ELFT>::initializeSections(bool ignoreComdats) { | |
| 568 | const ELFFile<ELFT> &obj = this->getObj(); | |
| 569 | ||
| 570 | ArrayRef<Elf_Shdr> objSections = CHECK(obj.sections(), this); | |
| 571 | uint64_t size = objSections.size(); | |
| 572 | this->sections.resize(size); | |
| 573 | this->sectionStringTable = | |
| 574 | CHECK(obj.getSectionStringTable(objSections), this); | |
| 575 | ||
| 576 | for (size_t i = 0, e = objSections.size(); i < e; i++) { | |
| 577 | if (this->sections[i] == &InputSection::discarded) | |
| 401 | 578 | continue; |
| 402 | const Elf_Shdr &Sec = ObjSections[I]; | |
| 579 | const Elf_Shdr &sec = objSections[i]; | |
| 403 | 580 | |
| 404 | if (Sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE) | |
| 405 | CGProfile = check( | |
| 406 | this->getObj().template getSectionContentsAsArray<Elf_CGProfile>( | |
| 407 | &Sec)); | |
| 581 | if (sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE) | |
| 582 | cgProfile = | |
| 583 | check(obj.template getSectionContentsAsArray<Elf_CGProfile>(&sec)); | |
| 408 | 584 | |
| 409 | 585 | // SHF_EXCLUDE'ed sections are discarded by the linker. However, |
| 410 | 586 | // if -r is given, we'll let the final link discard such sections. |
| 411 | 587 | // This is compatible with GNU. |
| 412 | if ((Sec.sh_flags & SHF_EXCLUDE) && !Config->Relocatable) { | |
| 413 | if (Sec.sh_type == SHT_LLVM_ADDRSIG) { | |
| 588 | if ((sec.sh_flags & SHF_EXCLUDE) && !config->relocatable) { | |
| 589 | if (sec.sh_type == SHT_LLVM_ADDRSIG) { | |
| 414 | 590 | // We ignore the address-significance table if we know that the object |
| 415 | 591 | // file was created by objcopy or ld -r. This is because these tools |
| 416 | 592 | // will reorder the symbols in the symbol table, invalidating the data |
| 417 | 593 | // in the address-significance table, which refers to symbols by index. |
| 418 | if (Sec.sh_link != 0) | |
| 419 | this->AddrsigSec = &Sec; | |
| 420 | else if (Config->ICF == ICFLevel::Safe) | |
| 594 | if (sec.sh_link != 0) | |
| 595 | this->addrsigSec = &sec; | |
| 596 | else if (config->icf == ICFLevel::Safe) | |
| 421 | 597 | warn(toString(this) + ": --icf=safe is incompatible with object " |
| 422 | 598 | "files created using objcopy or ld -r"); |
| 423 | 599 | } |
| 424 | this->Sections[I] = &InputSection::Discarded; | |
| 600 | this->sections[i] = &InputSection::discarded; | |
| 425 | 601 | continue; |
| 426 | 602 | } |
| 427 | 603 | |
| 428 | switch (Sec.sh_type) { | |
| 604 | switch (sec.sh_type) { | |
| 429 | 605 | case SHT_GROUP: { |
| 430 | 606 | // De-duplicate section groups by their signatures. |
| 431 | StringRef Signature = getShtGroupSignature(ObjSections, Sec); | |
| 432 | this->Sections[I] = &InputSection::Discarded; | |
| 607 | StringRef signature = getShtGroupSignature(objSections, sec); | |
| 608 | this->sections[i] = &InputSection::discarded; | |
| 433 | 609 | |
| 434 | 610 | |
| 435 | ArrayRef<Elf_Word> Entries = | |
| 436 | CHECK(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), this); | |
| 437 | if (Entries.empty()) | |
| 611 | ArrayRef<Elf_Word> entries = | |
| 612 | CHECK(obj.template getSectionContentsAsArray<Elf_Word>(&sec), this); | |
| 613 | if (entries.empty()) | |
| 438 | 614 | fatal(toString(this) + ": empty SHT_GROUP"); |
| 439 | 615 | |
| 440 | 616 | // The first word of a SHT_GROUP section contains flags. Currently, |
| 441 | 617 | // the standard defines only "GRP_COMDAT" flag for the COMDAT group. |
| 442 | 618 | // An group with the empty flag doesn't define anything; such sections |
| 443 | 619 | // are just skipped. |
| 444 | if (Entries[0] == 0) | |
| 620 | if (entries[0] == 0) | |
| 445 | 621 | continue; |
| 446 | 622 | |
| 447 | if (Entries[0] != GRP_COMDAT) | |
| 623 | if (entries[0] != GRP_COMDAT) | |
| 448 | 624 | fatal(toString(this) + ": unsupported SHT_GROUP format"); |
| 449 | 625 | |
| 450 | bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second; | |
| 451 | if (IsNew) { | |
| 452 | if (Config->Relocatable) | |
| 453 | this->Sections[I] = createInputSection(Sec); | |
| 454 | 	continue; | |
| 626 | bool isNew = | |
| 627 | ignoreComdats || | |
| 628 | symtab->comdatGroups.try_emplace(CachedHashStringRef(signature), this) | |
| 629 | .second; | |
| 630 | if (isNew) { | |
| 631 | if (config->relocatable) | |
| 632 | this->sections[i] = createInputSection(sec); | |
| 633 | continue; | |
| 455 | 634 | } |
| 456 | 635 | |
| 457 | ||
| 458 | 636 | // Otherwise, discard group members. |
| 459 | for (uint32_t SecIndex : Entries.slice(1)) { | |
| 460 | if (SecIndex >= Size) | |
| 637 | for (uint32_t secIndex : entries.slice(1)) { | |
| 638 | if (secIndex >= size) | |
| 461 | 639 | fatal(toString(this) + |
| 462 | ": invalid section index in group: " + Twine(SecIndex)); | |
| 463 | this->Sections[SecIndex] = &InputSection::Discarded; | |
| 640 | ": invalid section index in group: " + Twine(secIndex)); | |
| 641 | this->sections[secIndex] = &InputSection::discarded; | |
| 464 | 642 | } |
| 465 | 643 | break; |
| 466 | 644 | } |
| 467 | case SHT_SYMTAB: | |
| 468 | this->initSymtab(ObjSections, &Sec); | |
| 469 | break; | |
| 470 | 645 | case SHT_SYMTAB_SHNDX: |
| 471 | this->SymtabSHNDX = CHECK(Obj.getSHNDXTable(Sec, ObjSections), this); | |
| 646 | shndxTable = CHECK(obj.getSHNDXTable(sec, objSections), this); | |
| 472 | 647 | break; |
| 648 | case SHT_SYMTAB: | |
| 473 | 649 | case SHT_STRTAB: |
| 474 | 650 | case SHT_NULL: |
| 475 | 651 | break; |
| 476 | 652 | default: |
| 477 | this->Sections[I] = createInputSection(Sec); | |
| 653 | this->sections[i] = createInputSection(sec); | |
| 478 | 654 | } |
| 479 | 655 | |
| 480 | 656 | // .ARM.exidx sections have a reverse dependency on the InputSection they |
| 481 | 657 | // have a SHF_LINK_ORDER dependency, this is identified by the sh_link. |
| 482 | if (Sec.sh_flags & SHF_LINK_ORDER) { | |
| 483 | InputSectionBase *LinkSec = nullptr; | |
| 484 | if (Sec.sh_link < this->Sections.size()) | |
| 485 | LinkSec = this->Sections[Sec.sh_link]; | |
| 486 | if (!LinkSec) | |
| 658 | if (sec.sh_flags & SHF_LINK_ORDER) { | |
| 659 | InputSectionBase *linkSec = nullptr; | |
| 660 | if (sec.sh_link < this->sections.size()) | |
| 661 | linkSec = this->sections[sec.sh_link]; | |
| 662 | if (!linkSec) | |
| 487 | 663 | fatal(toString(this) + |
| 488 | ": invalid sh_link index: " + Twine(Sec.sh_link)); | |
| 664 | ": invalid sh_link index: " + Twine(sec.sh_link)); | |
| 489 | 665 | |
| 490 | InputSection *IS = cast<InputSection>(this->Sections[I]); | |
| 491 | LinkSec->DependentSections.push_back(IS); | |
| 492 | if (!isa<InputSection>(LinkSec)) | |
| 493 | error("a section " + IS->Name + | |
| 666 | InputSection *isec = cast<InputSection>(this->sections[i]); | |
| 667 | linkSec->dependentSections.push_back(isec); | |
| 668 | if (!isa<InputSection>(linkSec)) | |
| 669 | error("a section " + isec->name + | |
| 494 | 670 | " with SHF_LINK_ORDER should not refer a non-regular " |
| 495 | 671 | "section: " + |
| 496 | toString(LinkSec)); | |
| 672 | toString(linkSec)); | |
| 497 | 673 | } |
| 498 | 674 | } |
| 499 | 675 | } |
| ... | ... | @@ -501,9 +677,9 @@ void ObjFile<ELFT>::initializeSections( |
| 501 | 677 | // For ARM only, to set the EF_ARM_ABI_FLOAT_SOFT or EF_ARM_ABI_FLOAT_HARD |
| 502 | 678 | // flag in the ELF Header we need to look at Tag_ABI_VFP_args to find out how |
| 503 | 679 | // the input objects have been compiled. |
| 504 | static void updateARMVFPArgs(const ARMAttributeParser &Attributes, | |
| 505 | const InputFile *F) { | |
| 506 | if (!Attributes.hasAttribute(ARMBuildAttrs::ABI_VFP_args)) | |
| 680 | static void updateARMVFPArgs(const ARMAttributeParser &attributes, | |
| 681 | const InputFile *f) { | |
| 682 | if (!attributes.hasAttribute(ARMBuildAttrs::ABI_VFP_args)) | |
| 507 | 683 | // If an ABI tag isn't present then it is implicitly given the value of 0 |
| 508 | 684 | // which maps to ARMBuildAttrs::BaseAAPCS. However many assembler files, |
| 509 | 685 | // including some in glibc that don't use FP args (and should have value 3) |
| ... | ... | @@ -511,31 +687,31 @@ static void updateARMVFPArgs(const ARMAttributeParser &Attributes, |
| 511 | 687 | // as a clash. |
| 512 | 688 | return; |
| 513 | 689 | |
| 514 | unsigned VFPArgs = Attributes.getAttributeValue(ARMBuildAttrs::ABI_VFP_args); | |
| 515 | ARMVFPArgKind Arg; | |
| 516 | switch (VFPArgs) { | |
| 690 | unsigned vfpArgs = attributes.getAttributeValue(ARMBuildAttrs::ABI_VFP_args); | |
| 691 | ARMVFPArgKind arg; | |
| 692 | switch (vfpArgs) { | |
| 517 | 693 | case ARMBuildAttrs::BaseAAPCS: |
| 518 | Arg = ARMVFPArgKind::Base; | |
| 694 | arg = ARMVFPArgKind::Base; | |
| 519 | 695 | break; |
| 520 | 696 | case ARMBuildAttrs::HardFPAAPCS: |
| 521 | Arg = ARMVFPArgKind::VFP; | |
| 697 | arg = ARMVFPArgKind::VFP; | |
| 522 | 698 | break; |
| 523 | 699 | case ARMBuildAttrs::ToolChainFPPCS: |
| 524 | 700 | // Tool chain specific convention that conforms to neither AAPCS variant. |
| 525 | Arg = ARMVFPArgKind::ToolChain; | |
| 701 | arg = ARMVFPArgKind::ToolChain; | |
| 526 | 702 | break; |
| 527 | 703 | case ARMBuildAttrs::CompatibleFPAAPCS: |
| 528 | 704 | // Object compatible with all conventions. |
| 529 | 705 | return; |
| 530 | 706 | default: |
| 531 | error(toString(F) + ": unknown Tag_ABI_VFP_args value: " + Twine(VFPArgs)); | |
| 707 | error(toString(f) + ": unknown Tag_ABI_VFP_args value: " + Twine(vfpArgs)); | |
| 532 | 708 | return; |
| 533 | 709 | } |
| 534 | 710 | // Follow ld.bfd and error if there is a mix of calling conventions. |
| 535 | if (Config->ARMVFPArgs != Arg && Config->ARMVFPArgs != ARMVFPArgKind::Default) | |
| 536 | error(toString(F) + ": incompatible Tag_ABI_VFP_args"); | |
| 711 | if (config->armVFPArgs != arg && config->armVFPArgs != ARMVFPArgKind::Default) | |
| 712 | error(toString(f) + ": incompatible Tag_ABI_VFP_args"); | |
| 537 | 713 | else |
| 538 | Config->ARMVFPArgs = Arg; | |
| 714 | config->armVFPArgs = arg; | |
| 539 | 715 | } |
| 540 | 716 | |
| 541 | 717 | // The ARM support in lld makes some use of instructions that are not available |
| ... | ... | @@ -547,11 +723,11 @@ static void updateARMVFPArgs(const ARMAttributeParser &Attributes, |
| 547 | 723 | // at compile time. We follow the convention that if at least one input object |
| 548 | 724 | // is compiled with an architecture that supports these features then lld is |
| 549 | 725 | // permitted to use them. |
| 550 | static void updateSupportedARMFeatures(const ARMAttributeParser &Attributes) { | |
| 551 | if (!Attributes.hasAttribute(ARMBuildAttrs::CPU_arch)) | |
| 726 | static void updateSupportedARMFeatures(const ARMAttributeParser &attributes) { | |
| 727 | if (!attributes.hasAttribute(ARMBuildAttrs::CPU_arch)) | |
| 552 | 728 | return; |
| 553 | auto Arch = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch); | |
| 554 | switch (Arch) { | |
| 729 | auto arch = attributes.getAttributeValue(ARMBuildAttrs::CPU_arch); | |
| 730 | switch (arch) { | |
| 555 | 731 | case ARMBuildAttrs::Pre_v4: |
| 556 | 732 | case ARMBuildAttrs::v4: |
| 557 | 733 | case ARMBuildAttrs::v4T: |
| ... | ... | @@ -563,70 +739,156 @@ static void updateSupportedARMFeatures(const ARMAttributeParser &Attributes) { |
| 563 | 739 | case ARMBuildAttrs::v6: |
| 564 | 740 | case ARMBuildAttrs::v6KZ: |
| 565 | 741 | case ARMBuildAttrs::v6K: |
| 566 | Config->ARMHasBlx = true; | |
| 742 | config->armHasBlx = true; | |
| 567 | 743 | // Architectures used in pre-Cortex processors do not support |
| 568 | 744 | // The J1 = 1 J2 = 1 Thumb branch range extension, with the exception |
| 569 | 745 | // of Architecture v6T2 (arm1156t2-s and arm1156t2f-s) that do. |
| 570 | 746 | break; |
| 571 | 747 | default: |
| 572 | 748 | // All other Architectures have BLX and extended branch encoding |
| 573 | Config->ARMHasBlx = true; | |
| 574 | Config->ARMJ1J2BranchEncoding = true; | |
| 575 | if (Arch != ARMBuildAttrs::v6_M && Arch != ARMBuildAttrs::v6S_M) | |
| 749 | config->armHasBlx = true; | |
| 750 | config->armJ1J2BranchEncoding = true; | |
| 751 | if (arch != ARMBuildAttrs::v6_M && arch != ARMBuildAttrs::v6S_M) | |
| 576 | 752 | // All Architectures used in Cortex processors with the exception |
| 577 | 753 | // of v6-M and v6S-M have the MOVT and MOVW instructions. |
| 578 | Config->ARMHasMovtMovw = true; | |
| 754 | config->armHasMovtMovw = true; | |
| 579 | 755 | break; |
| 580 | 756 | } |
| 581 | 757 | } |
| 582 | 758 | |
| 759 | // If a source file is compiled with x86 hardware-assisted call flow control | |
| 760 | // enabled, the generated object file contains feature flags indicating that | |
| 761 | // fact. This function reads the feature flags and returns it. | |
| 762 | // | |
| 763 | // Essentially we want to read a single 32-bit value in this function, but this | |
| 764 | // function is rather complicated because the value is buried deep inside a | |
| 765 | // .note.gnu.property section. | |
| 766 | // | |
| 767 | // The section consists of one or more NOTE records. Each NOTE record consists | |
| 768 | // of zero or more type-length-value fields. We want to find a field of a | |
| 769 | // certain type. It seems a bit too much to just store a 32-bit value, perhaps | |
| 770 | // the ABI is unnecessarily complicated. | |
| 771 | template <class ELFT> | |
| 772 | static uint32_t readAndFeatures(ObjFile<ELFT> *obj, ArrayRef<uint8_t> data) { | |
| 773 | using Elf_Nhdr = typename ELFT::Nhdr; | |
| 774 | using Elf_Note = typename ELFT::Note; | |
| 775 | ||
| 776 | uint32_t featuresSet = 0; | |
| 777 | while (!data.empty()) { | |
| 778 | // Read one NOTE record. | |
| 779 | if (data.size() < sizeof(Elf_Nhdr)) | |
| 780 | fatal(toString(obj) + ": .note.gnu.property: section too short"); | |
| 781 | ||
| 782 | auto *nhdr = reinterpret_cast<const Elf_Nhdr *>(data.data()); | |
| 783 | if (data.size() < nhdr->getSize()) | |
| 784 | fatal(toString(obj) + ": .note.gnu.property: section too short"); | |
| 785 | ||
| 786 | Elf_Note note(*nhdr); | |
| 787 | if (nhdr->n_type != NT_GNU_PROPERTY_TYPE_0 || note.getName() != "GNU") { | |
| 788 | data = data.slice(nhdr->getSize()); | |
| 789 | continue; | |
| 790 | } | |
| 791 | ||
| 792 | uint32_t featureAndType = config->emachine == EM_AARCH64 | |
| 793 | ? GNU_PROPERTY_AARCH64_FEATURE_1_AND | |
| 794 | : GNU_PROPERTY_X86_FEATURE_1_AND; | |
| 795 | ||
| 796 | // Read a body of a NOTE record, which consists of type-length-value fields. | |
| 797 | ArrayRef<uint8_t> desc = note.getDesc(); | |
| 798 | while (!desc.empty()) { | |
| 799 | if (desc.size() < 8) | |
| 800 | fatal(toString(obj) + ": .note.gnu.property: section too short"); | |
| 801 | ||
| 802 | uint32_t type = read32le(desc.data()); | |
| 803 | uint32_t size = read32le(desc.data() + 4); | |
| 804 | ||
| 805 | if (type == featureAndType) { | |
| 806 | // We found a FEATURE_1_AND field. There may be more than one of these | |
| 807 | // in a .note.gnu.propery section, for a relocatable object we | |
| 808 | // accumulate the bits set. | |
| 809 | featuresSet |= read32le(desc.data() + 8); | |
| 810 | } | |
| 811 | ||
| 812 | // On 64-bit, a payload may be followed by a 4-byte padding to make its | |
| 813 | // size a multiple of 8. | |
| 814 | if (ELFT::Is64Bits) | |
| 815 | size = alignTo(size, 8); | |
| 816 | ||
| 817 | desc = desc.slice(size + 8); // +8 for Type and Size | |
| 818 | } | |
| 819 | ||
| 820 | // Go to next NOTE record to look for more FEATURE_1_AND descriptions. | |
| 821 | data = data.slice(nhdr->getSize()); | |
| 822 | } | |
| 823 | ||
| 824 | return featuresSet; | |
| 825 | } | |
| 826 | ||
| 583 | 827 | template <class ELFT> |
| 584 | InputSectionBase *ObjFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) { | |
| 585 | uint32_t Idx = Sec.sh_info; | |
| 586 | if (Idx >= this->Sections.size()) | |
| 587 | fatal(toString(this) + ": invalid relocated section index: " + Twine(Idx)); | |
| 588 | InputSectionBase *Target = this->Sections[Idx]; | |
| 828 | InputSectionBase *ObjFile<ELFT>::getRelocTarget(const Elf_Shdr &sec) { | |
| 829 | uint32_t idx = sec.sh_info; | |
| 830 | if (idx >= this->sections.size()) | |
| 831 | fatal(toString(this) + ": invalid relocated section index: " + Twine(idx)); | |
| 832 | InputSectionBase *target = this->sections[idx]; | |
| 589 | 833 | |
| 590 | 834 | // Strictly speaking, a relocation section must be included in the |
| 591 | 835 | // group of the section it relocates. However, LLVM 3.3 and earlier |
| 592 | 836 | // would fail to do so, so we gracefully handle that case. |
| 593 | if (Target == &InputSection::Discarded) | |
| 837 | if (target == &InputSection::discarded) | |
| 594 | 838 | return nullptr; |
| 595 | 839 | |
| 596 | if (!Target) | |
| 840 | if (!target) | |
| 597 | 841 | fatal(toString(this) + ": unsupported relocation reference"); |
| 598 | return Target; | |
| 842 | return target; | |
| 599 | 843 | } |
| 600 | 844 | |
| 601 | 845 | // Create a regular InputSection class that has the same contents |
| 602 | 846 | // as a given section. |
| 603 | static InputSection *toRegularSection(MergeInputSection *Sec) { | |
| 604 | return make<InputSection>(Sec->File, Sec->Flags, Sec->Type, Sec->Alignment, | |
| 605 | Sec->data(), Sec->Name); | |
| 847 | static InputSection *toRegularSection(MergeInputSection *sec) { | |
| 848 | return make<InputSection>(sec->file, sec->flags, sec->type, sec->alignment, | |
| 849 | sec->data(), sec->name); | |
| 606 | 850 | } |
| 607 | 851 | |
| 608 | 852 | template <class ELFT> |
| 609 | InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { | |
| 610 | StringRef Name = getSectionName(Sec); | |
| 853 | InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &sec) { | |
| 854 | StringRef name = getSectionName(sec); | |
| 611 | 855 | |
| 612 | switch (Sec.sh_type) { | |
| 856 | switch (sec.sh_type) { | |
| 613 | 857 | case SHT_ARM_ATTRIBUTES: { |
| 614 | if (Config->EMachine != EM_ARM) | |
| 858 | if (config->emachine != EM_ARM) | |
| 615 | 859 | break; |
| 616 | ARMAttributeParser Attributes; | |
| 617 | ArrayRef<uint8_t> Contents = check(this->getObj().getSectionContents(&Sec)); | |
| 618 | Attributes.Parse(Contents, /*isLittle*/ Config->EKind == ELF32LEKind); | |
| 619 | updateSupportedARMFeatures(Attributes); | |
| 620 | updateARMVFPArgs(Attributes, this); | |
| 860 | ARMAttributeParser attributes; | |
| 861 | ArrayRef<uint8_t> contents = check(this->getObj().getSectionContents(&sec)); | |
| 862 | attributes.Parse(contents, /*isLittle*/ config->ekind == ELF32LEKind); | |
| 863 | updateSupportedARMFeatures(attributes); | |
| 864 | updateARMVFPArgs(attributes, this); | |
| 621 | 865 | |
| 622 | 866 | // FIXME: Retain the first attribute section we see. The eglibc ARM |
| 623 | 867 | // dynamic loaders require the presence of an attribute section for dlopen |
| 624 | 868 | // to work. In a full implementation we would merge all attribute sections. |
| 625 | if (In.ARMAttributes == nullptr) { | |
| 626 | In.ARMAttributes = make<InputSection>(*this, Sec, Name); | |
| 627 | return In.ARMAttributes; | |
| 869 | if (in.armAttributes == nullptr) { | |
| 870 | in.armAttributes = make<InputSection>(*this, sec, name); | |
| 871 | return in.armAttributes; | |
| 872 | } | |
| 873 | return &InputSection::discarded; | |
| 874 | } | |
| 875 | case SHT_LLVM_DEPENDENT_LIBRARIES: { | |
| 876 | if (config->relocatable) | |
| 877 | break; | |
| 878 | ArrayRef<char> data = | |
| 879 | CHECK(this->getObj().template getSectionContentsAsArray<char>(&sec), this); | |
| 880 | if (!data.empty() && data.back() != '\0') { | |
| 881 | error(toString(this) + | |
| 882 | ": corrupted dependent libraries section (unterminated string): " + | |
| 883 | name); | |
| 884 | return &InputSection::discarded; | |
| 628 | 885 | } |
| 629 | return &InputSection::Discarded; | |
| 886 | for (const char *d = data.begin(), *e = data.end(); d < e;) { | |
| 887 | StringRef s(d); | |
| 888 | addDependentLibrary(s, this); | |
| 889 | d += s.size() + 1; | |
| 890 | } | |
| 891 | return &InputSection::discarded; | |
| 630 | 892 | } |
| 631 | 893 | case SHT_RELA: |
| 632 | 894 | case SHT_REL: { |
| ... | ... | @@ -635,25 +897,25 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { |
| 635 | 897 | // and the group is discarded, even though it's a violation of the |
| 636 | 898 | // spec. We handle that situation gracefully by discarding dangling |
| 637 | 899 | // relocation sections. |
| 638 | InputSectionBase *Target = getRelocTarget(Sec); | |
| 639 | if (!Target) | |
| 900 | InputSectionBase *target = getRelocTarget(sec); | |
| 901 | if (!target) | |
| 640 | 902 | return nullptr; |
| 641 | 903 | |
| 642 | 904 | // This section contains relocation information. |
| 643 | 905 | // If -r is given, we do not interpret or apply relocation |
| 644 | 906 | // but just copy relocation sections to output. |
| 645 | if (Config->Relocatable) { | |
| 646 | InputSection *RelocSec = make<InputSection>(*this, Sec, Name); | |
| 907 | if (config->relocatable) { | |
| 908 | InputSection *relocSec = make<InputSection>(*this, sec, name); | |
| 647 | 909 | // We want to add a dependency to target, similar like we do for |
| 648 | 910 | // -emit-relocs below. This is useful for the case when linker script |
| 649 | 911 | // contains the "/DISCARD/". It is perhaps uncommon to use a script with |
| 650 | 912 | // -r, but we faced it in the Linux kernel and have to handle such case |
| 651 | 913 | // and not to crash. |
| 652 | Target->DependentSections.push_back(RelocSec); | |
| 653 | return RelocSec; | |
| 914 | target->dependentSections.push_back(relocSec); | |
| 915 | return relocSec; | |
| 654 | 916 | } |
| 655 | 917 | |
| 656 | if (Target->FirstRelocation) | |
| 918 | if (target->firstRelocation) | |
| 657 | 919 | fatal(toString(this) + |
| 658 | 920 | ": multiple relocation sections to one section are not supported"); |
| 659 | 921 | |
| ... | ... | @@ -662,33 +924,33 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { |
| 662 | 924 | // because applying relocations at end of linking changes section |
| 663 | 925 | // contents. So, we simply handle such sections as non-mergeable ones. |
| 664 | 926 | // Degrading like this is acceptable because section merging is optional. |
| 665 | if (auto *MS = dyn_cast<MergeInputSection>(Target)) { | |
| 666 | Target = toRegularSection(MS); | |
| 667 | this->Sections[Sec.sh_info] = Target; | |
| 927 | if (auto *ms = dyn_cast<MergeInputSection>(target)) { | |
| 928 | target = toRegularSection(ms); | |
| 929 | this->sections[sec.sh_info] = target; | |
| 668 | 930 | } |
| 669 | 931 | |
| 670 | if (Sec.sh_type == SHT_RELA) { | |
| 671 | ArrayRef<Elf_Rela> Rels = CHECK(this->getObj().relas(&Sec), this); | |
| 672 | Target->FirstRelocation = Rels.begin(); | |
| 673 | Target->NumRelocations = Rels.size(); | |
| 674 | Target->AreRelocsRela = true; | |
| 932 | if (sec.sh_type == SHT_RELA) { | |
| 933 | ArrayRef<Elf_Rela> rels = CHECK(getObj().relas(&sec), this); | |
| 934 | target->firstRelocation = rels.begin(); | |
| 935 | target->numRelocations = rels.size(); | |
| 936 | target->areRelocsRela = true; | |
| 675 | 937 | } else { |
| 676 | ArrayRef<Elf_Rel> Rels = CHECK(this->getObj().rels(&Sec), this); | |
| 677 | Target->FirstRelocation = Rels.begin(); | |
| 678 | Target->NumRelocations = Rels.size(); | |
| 679 | Target->AreRelocsRela = false; | |
| 938 | ArrayRef<Elf_Rel> rels = CHECK(getObj().rels(&sec), this); | |
| 939 | target->firstRelocation = rels.begin(); | |
| 940 | target->numRelocations = rels.size(); | |
| 941 | target->areRelocsRela = false; | |
| 680 | 942 | } |
| 681 | assert(isUInt<31>(Target->NumRelocations)); | |
| 943 | assert(isUInt<31>(target->numRelocations)); | |
| 682 | 944 | |
| 683 | 945 | // Relocation sections processed by the linker are usually removed |
| 684 | 946 | // from the output, so returning `nullptr` for the normal case. |
| 685 | 947 | // However, if -emit-relocs is given, we need to leave them in the output. |
| 686 | 948 | // (Some post link analysis tools need this information.) |
| 687 | if (Config->EmitRelocs) { | |
| 688 | InputSection *RelocSec = make<InputSection>(*this, Sec, Name); | |
| 949 | if (config->emitRelocs) { | |
| 950 | InputSection *relocSec = make<InputSection>(*this, sec, name); | |
| 689 | 951 | // We will not emit relocation section if target was discarded. |
| 690 | Target->DependentSections.push_back(RelocSec); | |
| 691 | return RelocSec; | |
| 952 | target->dependentSections.push_back(relocSec); | |
| 953 | return relocSec; | |
| 692 | 954 | } |
| 693 | 955 | return nullptr; |
| 694 | 956 | } |
| ... | ... | @@ -707,28 +969,42 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { |
| 707 | 969 | // explicitly told to do otherwise (by -z execstack). Because the stack |
| 708 | 970 | // executable-ness is controlled solely by command line options, |
| 709 | 971 | // .note.GNU-stack sections are simply ignored. |
| 710 | if (Name == ".note.GNU-stack") | |
| 711 | return &InputSection::Discarded; | |
| 972 | if (name == ".note.GNU-stack") | |
| 973 | return &InputSection::discarded; | |
| 974 | ||
| 975 | // Object files that use processor features such as Intel Control-Flow | |
| 976 | // Enforcement (CET) or AArch64 Branch Target Identification BTI, use a | |
| 977 | // .note.gnu.property section containing a bitfield of feature bits like the | |
| 978 | // GNU_PROPERTY_X86_FEATURE_1_IBT flag. Read a bitmap containing the flag. | |
| 979 | // | |
| 980 | // Since we merge bitmaps from multiple object files to create a new | |
| 981 | // .note.gnu.property containing a single AND'ed bitmap, we discard an input | |
| 982 | // file's .note.gnu.property section. | |
| 983 | if (name == ".note.gnu.property") { | |
| 984 | ArrayRef<uint8_t> contents = check(this->getObj().getSectionContents(&sec)); | |
| 985 | this->andFeatures = readAndFeatures(this, contents); | |
| 986 | return &InputSection::discarded; | |
| 987 | } | |
| 712 | 988 | |
| 713 | 989 | // Split stacks is a feature to support a discontiguous stack, |
| 714 | 990 | // commonly used in the programming language Go. For the details, |
| 715 | 991 | // see https://gcc.gnu.org/wiki/SplitStacks. An object file compiled |
| 716 | 992 | // for split stack will include a .note.GNU-split-stack section. |
| 717 | if (Name == ".note.GNU-split-stack") { | |
| 718 | if (Config->Relocatable) { | |
| 993 | if (name == ".note.GNU-split-stack") { | |
| 994 | if (config->relocatable) { | |
| 719 | 995 | error("cannot mix split-stack and non-split-stack in a relocatable link"); |
| 720 | return &InputSection::Discarded; | |
| 996 | return &InputSection::discarded; | |
| 721 | 997 | } |
| 722 | this->SplitStack = true; | |
| 723 | return &InputSection::Discarded; | |
| 998 | this->splitStack = true; | |
| 999 | return &InputSection::discarded; | |
| 724 | 1000 | } |
| 725 | 1001 | |
| 726 | 1002 | // An object file cmpiled for split stack, but where some of the |
| 727 | 1003 | // functions were compiled with the no_split_stack_attribute will |
| 728 | 1004 | // include a .note.GNU-no-split-stack section. |
| 729 | if (Name == ".note.GNU-no-split-stack") { | |
| 730 | this->SomeNoSplitStack = true; | |
| 731 | return &InputSection::Discarded; | |
| 1005 | if (name == ".note.GNU-no-split-stack") { | |
| 1006 | this->someNoSplitStack = true; | |
| 1007 | return &InputSection::discarded; | |
| 732 | 1008 | } |
| 733 | 1009 | |
| 734 | 1010 | // The linkonce feature is a sort of proto-comdat. Some glibc i386 object |
| ... | ... | @@ -736,246 +1012,205 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { |
| 736 | 1012 | // sections. Drop those sections to avoid duplicate symbol errors. |
| 737 | 1013 | // FIXME: This is glibc PR20543, we should remove this hack once that has been |
| 738 | 1014 | // fixed for a while. |
| 739 | if (Name == ".gnu.linkonce.t.__x86.get_pc_thunk.bx" || | |
| 740 | Name == ".gnu.linkonce.t.__i686.get_pc_thunk.bx") | |
| 741 | return &InputSection::Discarded; | |
| 1015 | if (name == ".gnu.linkonce.t.__x86.get_pc_thunk.bx" || | |
| 1016 | name == ".gnu.linkonce.t.__i686.get_pc_thunk.bx") | |
| 1017 | return &InputSection::discarded; | |
| 742 | 1018 | |
| 743 | 1019 | // If we are creating a new .build-id section, strip existing .build-id |
| 744 | 1020 | // sections so that the output won't have more than one .build-id. |
| 745 | 1021 | // This is not usually a problem because input object files normally don't |
| 746 | 1022 | // have .build-id sections, but you can create such files by |
| 747 | 1023 | // "ld.{bfd,gold,lld} -r --build-id", and we want to guard against it. |
| 748 | if (Name == ".note.gnu.build-id" && Config->BuildId != BuildIdKind::None) | |
| 749 | return &InputSection::Discarded; | |
| 1024 | if (name == ".note.gnu.build-id" && config->buildId != BuildIdKind::None) | |
| 1025 | return &InputSection::discarded; | |
| 750 | 1026 | |
| 751 | 1027 | // The linker merges EH (exception handling) frames and creates a |
| 752 | 1028 | // .eh_frame_hdr section for runtime. So we handle them with a special |
| 753 | 1029 | // class. For relocatable outputs, they are just passed through. |
| 754 | if (Name == ".eh_frame" && !Config->Relocatable) | |
| 755 | return make<EhInputSection>(*this, Sec, Name); | |
| 1030 | if (name == ".eh_frame" && !config->relocatable) | |
| 1031 | return make<EhInputSection>(*this, sec, name); | |
| 756 | 1032 | |
| 757 | if (shouldMerge(Sec)) | |
| 758 | return make<MergeInputSection>(*this, Sec, Name); | |
| 759 | return make<InputSection>(*this, Sec, Name); | |
| 1033 | if (shouldMerge(sec)) | |
| 1034 | return make<MergeInputSection>(*this, sec, name); | |
| 1035 | return make<InputSection>(*this, sec, name); | |
| 760 | 1036 | } |
| 761 | 1037 | |
| 762 | 1038 | template <class ELFT> |
| 763 | StringRef ObjFile<ELFT>::getSectionName(const Elf_Shdr &Sec) { | |
| 764 | return CHECK(this->getObj().getSectionName(&Sec, SectionStringTable), this); | |
| 1039 | StringRef ObjFile<ELFT>::getSectionName(const Elf_Shdr &sec) { | |
| 1040 | return CHECK(getObj().getSectionName(&sec, sectionStringTable), this); | |
| 765 | 1041 | } |
| 766 | 1042 | |
| 1043 | // Initialize this->Symbols. this->Symbols is a parallel array as | |
| 1044 | // its corresponding ELF symbol table. | |
| 767 | 1045 | template <class ELFT> void ObjFile<ELFT>::initializeSymbols() { |
| 768 | this->Symbols.reserve(this->ELFSyms.size()); | |
| 769 | for (const Elf_Sym &Sym : this->ELFSyms) | |
| 770 | this->Symbols.push_back(createSymbol(&Sym)); | |
| 771 | } | |
| 772 | ||
| 773 | template <class ELFT> Symbol *ObjFile<ELFT>::createSymbol(const Elf_Sym *Sym) { | |
| 774 | int Binding = Sym->getBinding(); | |
| 775 | ||
| 776 | uint32_t SecIdx = this->getSectionIndex(*Sym); | |
| 777 | if (SecIdx >= this->Sections.size()) | |
| 778 | fatal(toString(this) + ": invalid section index: " + Twine(SecIdx)); | |
| 779 | ||
| 780 | InputSectionBase *Sec = this->Sections[SecIdx]; | |
| 781 | uint8_t StOther = Sym->st_other; | |
| 782 | uint8_t Type = Sym->getType(); | |
| 783 | uint64_t Value = Sym->st_value; | |
| 784 | uint64_t Size = Sym->st_size; | |
| 785 | ||
| 786 | if (Binding == STB_LOCAL) { | |
| 787 | if (Sym->getType() == STT_FILE) | |
| 788 | SourceFile = CHECK(Sym->getName(this->StringTable), this); | |
| 1046 | ArrayRef<Elf_Sym> eSyms = this->getELFSyms<ELFT>(); | |
| 1047 | this->symbols.resize(eSyms.size()); | |
| 1048 | ||
| 1049 | // Our symbol table may have already been partially initialized | |
| 1050 | // because of LazyObjFile. | |
| 1051 | for (size_t i = 0, end = eSyms.size(); i != end; ++i) | |
| 1052 | if (!this->symbols[i] && eSyms[i].getBinding() != STB_LOCAL) | |
| 1053 | this->symbols[i] = | |
| 1054 | symtab->insert(CHECK(eSyms[i].getName(this->stringTable), this)); | |
| 1055 | ||
| 1056 | // Fill this->Symbols. A symbol is either local or global. | |
| 1057 | for (size_t i = 0, end = eSyms.size(); i != end; ++i) { | |
| 1058 | const Elf_Sym &eSym = eSyms[i]; | |
| 1059 | ||
| 1060 | // Read symbol attributes. | |
| 1061 | uint32_t secIdx = getSectionIndex(eSym); | |
| 1062 | if (secIdx >= this->sections.size()) | |
| 1063 | fatal(toString(this) + ": invalid section index: " + Twine(secIdx)); | |
| 1064 | ||
| 1065 | InputSectionBase *sec = this->sections[secIdx]; | |
| 1066 | uint8_t binding = eSym.getBinding(); | |
| 1067 | uint8_t stOther = eSym.st_other; | |
| 1068 | uint8_t type = eSym.getType(); | |
| 1069 | uint64_t value = eSym.st_value; | |
| 1070 | uint64_t size = eSym.st_size; | |
| 1071 | StringRefZ name = this->stringTable.data() + eSym.st_name; | |
| 1072 | ||
| 1073 | // Handle local symbols. Local symbols are not added to the symbol | |
| 1074 | // table because they are not visible from other object files. We | |
| 1075 | // allocate symbol instances and add their pointers to Symbols. | |
| 1076 | if (binding == STB_LOCAL) { | |
| 1077 | if (eSym.getType() == STT_FILE) | |
| 1078 | sourceFile = CHECK(eSym.getName(this->stringTable), this); | |
| 1079 | ||
| 1080 | if (this->stringTable.size() <= eSym.st_name) | |
| 1081 | fatal(toString(this) + ": invalid symbol name offset"); | |
| 1082 | ||
| 1083 | if (eSym.st_shndx == SHN_UNDEF) | |
| 1084 | this->symbols[i] = make<Undefined>(this, name, binding, stOther, type); | |
| 1085 | else if (sec == &InputSection::discarded) | |
| 1086 | this->symbols[i] = make<Undefined>(this, name, binding, stOther, type, | |
| 1087 | /*DiscardedSecIdx=*/secIdx); | |
| 1088 | else | |
| 1089 | this->symbols[i] = | |
| 1090 | make<Defined>(this, name, binding, stOther, type, value, size, sec); | |
| 1091 | continue; | |
| 1092 | } | |
| 789 | 1093 | |
| 790 | if (this->StringTable.size() <= Sym->st_name) | |
| 791 | fatal(toString(this) + ": invalid symbol name offset"); | |
| 1094 | // Handle global undefined symbols. | |
| 1095 | if (eSym.st_shndx == SHN_UNDEF) { | |
| 1096 | this->symbols[i]->resolve(Undefined{this, name, binding, stOther, type}); | |
| 1097 | continue; | |
| 1098 | } | |
| 792 | 1099 | |
| 793 | StringRefZ Name = this->StringTable.data() + Sym->st_name; | |
| 794 | if (Sym->st_shndx == SHN_UNDEF) | |
| 795 | return make<Undefined>(this, Name, Binding, StOther, Type); | |
| 1100 | // Handle global common symbols. | |
| 1101 | if (eSym.st_shndx == SHN_COMMON) { | |
| 1102 | if (value == 0 || value >= UINT32_MAX) | |
| 1103 | fatal(toString(this) + ": common symbol '" + StringRef(name.data) + | |
| 1104 | "' has invalid alignment: " + Twine(value)); | |
| 1105 | this->symbols[i]->resolve( | |
| 1106 | CommonSymbol{this, name, binding, stOther, type, value, size}); | |
| 1107 | continue; | |
| 1108 | } | |
| 796 | 1109 | |
| 797 | return make<Defined>(this, Name, Binding, StOther, Type, Value, Size, Sec); | |
| 798 | } | |
| 1110 | // If a defined symbol is in a discarded section, handle it as if it | |
| 1111 | // were an undefined symbol. Such symbol doesn't comply with the | |
| 1112 | // standard, but in practice, a .eh_frame often directly refer | |
| 1113 | // COMDAT member sections, and if a comdat group is discarded, some | |
| 1114 | // defined symbol in a .eh_frame becomes dangling symbols. | |
| 1115 | if (sec == &InputSection::discarded) { | |
| 1116 | this->symbols[i]->resolve( | |
| 1117 | Undefined{this, name, binding, stOther, type, secIdx}); | |
| 1118 | continue; | |
| 1119 | } | |
| 799 | 1120 | |
| 800 | StringRef Name = CHECK(Sym->getName(this->StringTable), this); | |
| 801 | ||
| 802 | switch (Sym->st_shndx) { | |
| 803 | case SHN_UNDEF: | |
| 804 | return Symtab->addUndefined<ELFT>(Name, Binding, StOther, Type, | |
| 805 | /*CanOmitFromDynSym=*/false, this); | |
| 806 | case SHN_COMMON: | |
| 807 | if (Value == 0 || Value >= UINT32_MAX) | |
| 808 | fatal(toString(this) + ": common symbol '" + Name + | |
| 809 | "' has invalid alignment: " + Twine(Value)); | |
| 810 | return Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, *this); | |
| 811 | } | |
| 1121 | // Handle global defined symbols. | |
| 1122 | if (binding == STB_GLOBAL || binding == STB_WEAK || | |
| 1123 | binding == STB_GNU_UNIQUE) { | |
| 1124 | this->symbols[i]->resolve( | |
| 1125 | Defined{this, name, binding, stOther, type, value, size, sec}); | |
| 1126 | continue; | |
| 1127 | } | |
| 812 | 1128 | |
| 813 | switch (Binding) { | |
| 814 | default: | |
| 815 | fatal(toString(this) + ": unexpected binding: " + Twine(Binding)); | |
| 816 | case STB_GLOBAL: | |
| 817 | case STB_WEAK: | |
| 818 | case STB_GNU_UNIQUE: | |
| 819 | if (Sec == &InputSection::Discarded) | |
| 820 | return Symtab->addUndefined<ELFT>(Name, Binding, StOther, Type, | |
| 821 | /*CanOmitFromDynSym=*/false, this); | |
| 822 | return Symtab->addDefined(Name, StOther, Type, Value, Size, Binding, Sec, | |
| 823 | this); | |
| 1129 | fatal(toString(this) + ": unexpected binding: " + Twine((int)binding)); | |
| 824 | 1130 | } |
| 825 | 1131 | } |
| 826 | 1132 | |
| 827 | ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File) | |
| 828 | : InputFile(ArchiveKind, File->getMemoryBufferRef()), | |
| 829 | File(std::move(File)) {} | |
| 1133 | ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&file) | |
| 1134 | : InputFile(ArchiveKind, file->getMemoryBufferRef()), | |
| 1135 | file(std::move(file)) {} | |
| 830 | 1136 | |
| 831 | template <class ELFT> void ArchiveFile::parse() { | |
| 832 | for (const Archive::Symbol &Sym : File->symbols()) | |
| 833 | Symtab->addLazyArchive<ELFT>(Sym.getName(), *this, Sym); | |
| 1137 | void ArchiveFile::parse() { | |
| 1138 | for (const Archive::Symbol &sym : file->symbols()) | |
| 1139 | symtab->addSymbol(LazyArchive{*this, sym}); | |
| 834 | 1140 | } |
| 835 | 1141 | |
| 836 | 1142 | // Returns a buffer pointing to a member file containing a given symbol. |
| 837 | InputFile *ArchiveFile::fetch(const Archive::Symbol &Sym) { | |
| 838 | Archive::Child C = | |
| 839 | CHECK(Sym.getMember(), toString(this) + | |
| 1143 | void ArchiveFile::fetch(const Archive::Symbol &sym) { | |
| 1144 | Archive::Child c = | |
| 1145 | CHECK(sym.getMember(), toString(this) + | |
| 840 | 1146 | ": could not get the member for symbol " + |
| 841 | Sym.getName()); | |
| 1147 | sym.getName()); | |
| 842 | 1148 | |
| 843 | if (!Seen.insert(C.getChildOffset()).second) | |
| 844 | return nullptr; | |
| 1149 | if (!seen.insert(c.getChildOffset()).second) | |
| 1150 | return; | |
| 845 | 1151 | |
| 846 | MemoryBufferRef MB = | |
| 847 | CHECK(C.getMemoryBufferRef(), | |
| 1152 | MemoryBufferRef mb = | |
| 1153 | CHECK(c.getMemoryBufferRef(), | |
| 848 | 1154 | toString(this) + |
| 849 | 1155 | ": could not get the buffer for the member defining symbol " + |
| 850 | Sym.getName()); | |
| 851 | ||
| 852 | if (Tar && C.getParent()->isThin()) | |
| 853 | Tar->append(relativeToRoot(CHECK(C.getFullName(), this)), MB.getBuffer()); | |
| 854 | ||
| 855 | InputFile *File = createObjectFile( | |
| 856 | MB, getName(), C.getParent()->isThin() ? 0 : C.getChildOffset()); | |
| 857 | File->GroupId = GroupId; | |
| 858 | return File; | |
| 859 | } | |
| 860 | ||
| 861 | template <class ELFT> | |
| 862 | SharedFile<ELFT>::SharedFile(MemoryBufferRef M, StringRef DefaultSoName) | |
| 863 | : ELFFileBase<ELFT>(Base::SharedKind, M), SoName(DefaultSoName), | |
| 864 | IsNeeded(!Config->AsNeeded) {} | |
| 865 | ||
| 866 | // Partially parse the shared object file so that we can call | |
| 867 | // getSoName on this object. | |
| 868 | template <class ELFT> void SharedFile<ELFT>::parseSoName() { | |
| 869 | const Elf_Shdr *DynamicSec = nullptr; | |
| 870 | const ELFFile<ELFT> Obj = this->getObj(); | |
| 871 | ArrayRef<Elf_Shdr> Sections = CHECK(Obj.sections(), this); | |
| 872 | ||
| 873 | // Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d. | |
| 874 | for (const Elf_Shdr &Sec : Sections) { | |
| 875 | switch (Sec.sh_type) { | |
| 876 | default: | |
| 877 | continue; | |
| 878 | case SHT_DYNSYM: | |
| 879 | this->initSymtab(Sections, &Sec); | |
| 880 | break; | |
| 881 | case SHT_DYNAMIC: | |
| 882 | DynamicSec = &Sec; | |
| 883 | break; | |
| 884 | case SHT_SYMTAB_SHNDX: | |
| 885 | this->SymtabSHNDX = CHECK(Obj.getSHNDXTable(Sec, Sections), this); | |
| 886 | break; | |
| 887 | case SHT_GNU_versym: | |
| 888 | this->VersymSec = &Sec; | |
| 889 | break; | |
| 890 | case SHT_GNU_verdef: | |
| 891 | this->VerdefSec = &Sec; | |
| 892 | break; | |
| 893 | } | |
| 894 | } | |
| 1156 | sym.getName()); | |
| 895 | 1157 | |
| 896 | if (this->VersymSec && this->ELFSyms.empty()) | |
| 897 | error("SHT_GNU_versym should be associated with symbol table"); | |
| 1158 | if (tar && c.getParent()->isThin()) | |
| 1159 | tar->append(relativeToRoot(CHECK(c.getFullName(), this)), mb.getBuffer()); | |
| 898 | 1160 | |
| 899 | // Search for a DT_SONAME tag to initialize this->SoName. | |
| 900 | if (!DynamicSec) | |
| 901 | return; | |
| 902 | ArrayRef<Elf_Dyn> Arr = | |
| 903 | CHECK(Obj.template getSectionContentsAsArray<Elf_Dyn>(DynamicSec), this); | |
| 904 | for (const Elf_Dyn &Dyn : Arr) { | |
| 905 | if (Dyn.d_tag == DT_SONAME) { | |
| 906 | uint64_t Val = Dyn.getVal(); | |
| 907 | if (Val >= this->StringTable.size()) | |
| 908 | fatal(toString(this) + ": invalid DT_SONAME entry"); | |
| 909 | SoName = this->StringTable.data() + Val; | |
| 910 | return; | |
| 911 | } | |
| 912 | } | |
| 1161 | InputFile *file = createObjectFile( | |
| 1162 | mb, getName(), c.getParent()->isThin() ? 0 : c.getChildOffset()); | |
| 1163 | file->groupId = groupId; | |
| 1164 | parseFile(file); | |
| 913 | 1165 | } |
| 914 | 1166 | |
| 915 | // Parses ".gnu.version" section which is a parallel array for the symbol table. | |
| 916 | // If a given file doesn't have ".gnu.version" section, returns VER_NDX_GLOBAL. | |
| 917 | template <class ELFT> std::vector<uint32_t> SharedFile<ELFT>::parseVersyms() { | |
| 918 | size_t Size = this->ELFSyms.size() - this->FirstGlobal; | |
| 919 | if (!VersymSec) | |
| 920 | return std::vector<uint32_t>(Size, VER_NDX_GLOBAL); | |
| 921 | ||
| 922 | const char *Base = this->MB.getBuffer().data(); | |
| 923 | const Elf_Versym *Versym = | |
| 924 | reinterpret_cast<const Elf_Versym *>(Base + VersymSec->sh_offset) + | |
| 925 | this->FirstGlobal; | |
| 926 | ||
| 927 | std::vector<uint32_t> Ret(Size); | |
| 928 | for (size_t I = 0; I < Size; ++I) | |
| 929 | Ret[I] = Versym[I].vs_index; | |
| 930 | return Ret; | |
| 931 | } | |
| 1167 | unsigned SharedFile::vernauxNum; | |
| 932 | 1168 | |
| 933 | // Parse the version definitions in the object file if present. Returns a vector | |
| 934 | // whose nth element contains a pointer to the Elf_Verdef for version identifier | |
| 935 | // n. Version identifiers that are not definitions map to nullptr. | |
| 936 | template <class ELFT> | |
| 937 | std::vector<const typename ELFT::Verdef *> SharedFile<ELFT>::parseVerdefs() { | |
| 938 | if (!VerdefSec) | |
| 1169 | // Parse the version definitions in the object file if present, and return a | |
| 1170 | // vector whose nth element contains a pointer to the Elf_Verdef for version | |
| 1171 | // identifier n. Version identifiers that are not definitions map to nullptr. | |
| 1172 | template <typename ELFT> | |
| 1173 | static std::vector<const void *> parseVerdefs(const uint8_t *base, | |
| 1174 | const typename ELFT::Shdr *sec) { | |
| 1175 | if (!sec) | |
| 939 | 1176 | return {}; |
| 940 | 1177 | |
| 941 | 1178 | // We cannot determine the largest verdef identifier without inspecting |
| 942 | 1179 | // every Elf_Verdef, but both bfd and gold assign verdef identifiers |
| 943 | 1180 | // sequentially starting from 1, so we predict that the largest identifier |
| 944 | // will be VerdefCount. | |
| 945 | unsigned VerdefCount = VerdefSec->sh_info; | |
| 946 | std::vector<const Elf_Verdef *> Verdefs(VerdefCount + 1); | |
| 1181 | // will be verdefCount. | |
| 1182 | unsigned verdefCount = sec->sh_info; | |
| 1183 | std::vector<const void *> verdefs(verdefCount + 1); | |
| 947 | 1184 | |
| 948 | 1185 | // Build the Verdefs array by following the chain of Elf_Verdef objects |
| 949 | 1186 | // from the start of the .gnu.version_d section. |
| 950 | const char *Base = this->MB.getBuffer().data(); | |
| 951 | const char *Verdef = Base + VerdefSec->sh_offset; | |
| 952 | for (unsigned I = 0; I != VerdefCount; ++I) { | |
| 953 | auto *CurVerdef = reinterpret_cast<const Elf_Verdef *>(Verdef); | |
| 954 | Verdef += CurVerdef->vd_next; | |
| 955 | unsigned VerdefIndex = CurVerdef->vd_ndx; | |
| 956 | Verdefs.resize(VerdefIndex + 1); | |
| 957 | Verdefs[VerdefIndex] = CurVerdef; | |
| 1187 | const uint8_t *verdef = base + sec->sh_offset; | |
| 1188 | for (unsigned i = 0; i != verdefCount; ++i) { | |
| 1189 | auto *curVerdef = reinterpret_cast<const typename ELFT::Verdef *>(verdef); | |
| 1190 | verdef += curVerdef->vd_next; | |
| 1191 | unsigned verdefIndex = curVerdef->vd_ndx; | |
| 1192 | verdefs.resize(verdefIndex + 1); | |
| 1193 | verdefs[verdefIndex] = curVerdef; | |
| 958 | 1194 | } |
| 959 | ||
| 960 | return Verdefs; | |
| 1195 | return verdefs; | |
| 961 | 1196 | } |
| 962 | 1197 | |
| 963 | 1198 | // We do not usually care about alignments of data in shared object |
| 964 | 1199 | // files because the loader takes care of it. However, if we promote a |
| 965 | 1200 | // DSO symbol to point to .bss due to copy relocation, we need to keep |
| 966 | 1201 | // the original alignment requirements. We infer it in this function. |
| 967 | template <class ELFT> | |
| 968 | uint32_t SharedFile<ELFT>::getAlignment(ArrayRef<Elf_Shdr> Sections, | |
| 969 | const Elf_Sym &Sym) { | |
| 970 | uint64_t Ret = UINT64_MAX; | |
| 971 | if (Sym.st_value) | |
| 972 | Ret = 1ULL << countTrailingZeros((uint64_t)Sym.st_value); | |
| 973 | if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size()) | |
| 974 | Ret = std::min<uint64_t>(Ret, Sections[Sym.st_shndx].sh_addralign); | |
| 975 | return (Ret > UINT32_MAX) ? 0 : Ret; | |
| 1202 | template <typename ELFT> | |
| 1203 | static uint64_t getAlignment(ArrayRef<typename ELFT::Shdr> sections, | |
| 1204 | const typename ELFT::Sym &sym) { | |
| 1205 | uint64_t ret = UINT64_MAX; | |
| 1206 | if (sym.st_value) | |
| 1207 | ret = 1ULL << countTrailingZeros((uint64_t)sym.st_value); | |
| 1208 | if (0 < sym.st_shndx && sym.st_shndx < sections.size()) | |
| 1209 | ret = std::min<uint64_t>(ret, sections[sym.st_shndx].sh_addralign); | |
| 1210 | return (ret > UINT32_MAX) ? 0 : ret; | |
| 976 | 1211 | } |
| 977 | 1212 | |
| 978 | // Fully parse the shared object file. This must be called after parseSoName(). | |
| 1213 | // Fully parse the shared object file. | |
| 979 | 1214 | // |
| 980 | 1215 | // This function parses symbol versions. If a DSO has version information, |
| 981 | 1216 | // the file has a ".gnu.version_d" section which contains symbol version |
| ... | ... | @@ -990,80 +1225,163 @@ uint32_t SharedFile<ELFT>::getAlignment(ArrayRef<Elf_Shdr> Sections, |
| 990 | 1225 | // The file format for symbol versioning is perhaps a bit more complicated |
| 991 | 1226 | // than necessary, but you can easily understand the code if you wrap your |
| 992 | 1227 | // head around the data structure described above. |
| 993 | template <class ELFT> void SharedFile<ELFT>::parseRest() { | |
| 994 | Verdefs = parseVerdefs(); // parse .gnu.version_d | |
| 995 | std::vector<uint32_t> Versyms = parseVersyms(); // parse .gnu.version | |
| 996 | ArrayRef<Elf_Shdr> Sections = CHECK(this->getObj().sections(), this); | |
| 1228 | template <class ELFT> void SharedFile::parse() { | |
| 1229 | using Elf_Dyn = typename ELFT::Dyn; | |
| 1230 | using Elf_Shdr = typename ELFT::Shdr; | |
| 1231 | using Elf_Sym = typename ELFT::Sym; | |
| 1232 | using Elf_Verdef = typename ELFT::Verdef; | |
| 1233 | using Elf_Versym = typename ELFT::Versym; | |
| 1234 | ||
| 1235 | ArrayRef<Elf_Dyn> dynamicTags; | |
| 1236 | const ELFFile<ELFT> obj = this->getObj<ELFT>(); | |
| 1237 | ArrayRef<Elf_Shdr> sections = CHECK(obj.sections(), this); | |
| 1238 | ||
| 1239 | const Elf_Shdr *versymSec = nullptr; | |
| 1240 | const Elf_Shdr *verdefSec = nullptr; | |
| 1241 | ||
| 1242 | // Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d. | |
| 1243 | for (const Elf_Shdr &sec : sections) { | |
| 1244 | switch (sec.sh_type) { | |
| 1245 | default: | |
| 1246 | continue; | |
| 1247 | case SHT_DYNAMIC: | |
| 1248 | dynamicTags = | |
| 1249 | CHECK(obj.template getSectionContentsAsArray<Elf_Dyn>(&sec), this); | |
| 1250 | break; | |
| 1251 | case SHT_GNU_versym: | |
| 1252 | versymSec = &sec; | |
| 1253 | break; | |
| 1254 | case SHT_GNU_verdef: | |
| 1255 | verdefSec = &sec; | |
| 1256 | break; | |
| 1257 | } | |
| 1258 | } | |
| 1259 | ||
| 1260 | if (versymSec && numELFSyms == 0) { | |
| 1261 | error("SHT_GNU_versym should be associated with symbol table"); | |
| 1262 | return; | |
| 1263 | } | |
| 1264 | ||
| 1265 | // Search for a DT_SONAME tag to initialize this->soName. | |
| 1266 | for (const Elf_Dyn &dyn : dynamicTags) { | |
| 1267 | if (dyn.d_tag == DT_NEEDED) { | |
| 1268 | uint64_t val = dyn.getVal(); | |
| 1269 | if (val >= this->stringTable.size()) | |
| 1270 | fatal(toString(this) + ": invalid DT_NEEDED entry"); | |
| 1271 | dtNeeded.push_back(this->stringTable.data() + val); | |
| 1272 | } else if (dyn.d_tag == DT_SONAME) { | |
| 1273 | uint64_t val = dyn.getVal(); | |
| 1274 | if (val >= this->stringTable.size()) | |
| 1275 | fatal(toString(this) + ": invalid DT_SONAME entry"); | |
| 1276 | soName = this->stringTable.data() + val; | |
| 1277 | } | |
| 1278 | } | |
| 1279 | ||
| 1280 | // DSOs are uniquified not by filename but by soname. | |
| 1281 | DenseMap<StringRef, SharedFile *>::iterator it; | |
| 1282 | bool wasInserted; | |
| 1283 | std::tie(it, wasInserted) = symtab->soNames.try_emplace(soName, this); | |
| 1284 | ||
| 1285 | // If a DSO appears more than once on the command line with and without | |
| 1286 | // --as-needed, --no-as-needed takes precedence over --as-needed because a | |
| 1287 | // user can add an extra DSO with --no-as-needed to force it to be added to | |
| 1288 | // the dependency list. | |
| 1289 | it->second->isNeeded |= isNeeded; | |
| 1290 | if (!wasInserted) | |
| 1291 | return; | |
| 1292 | ||
| 1293 | sharedFiles.push_back(this); | |
| 1294 | ||
| 1295 | verdefs = parseVerdefs<ELFT>(obj.base(), verdefSec); | |
| 1296 | ||
| 1297 | // Parse ".gnu.version" section which is a parallel array for the symbol | |
| 1298 | // table. If a given file doesn't have a ".gnu.version" section, we use | |
| 1299 | // VER_NDX_GLOBAL. | |
| 1300 | size_t size = numELFSyms - firstGlobal; | |
| 1301 | std::vector<uint32_t> versyms(size, VER_NDX_GLOBAL); | |
| 1302 | if (versymSec) { | |
| 1303 | ArrayRef<Elf_Versym> versym = | |
| 1304 | CHECK(obj.template getSectionContentsAsArray<Elf_Versym>(versymSec), | |
| 1305 | this) | |
| 1306 | .slice(firstGlobal); | |
| 1307 | for (size_t i = 0; i < size; ++i) | |
| 1308 | versyms[i] = versym[i].vs_index; | |
| 1309 | } | |
| 997 | 1310 | |
| 998 | 1311 | // System libraries can have a lot of symbols with versions. Using a |
| 999 | 1312 | // fixed buffer for computing the versions name (foo@ver) can save a |
| 1000 | 1313 | // lot of allocations. |
| 1001 | SmallString<0> VersionedNameBuffer; | |
| 1314 | SmallString<0> versionedNameBuffer; | |
| 1002 | 1315 | |
| 1003 | 1316 | // Add symbols to the symbol table. |
| 1004 | ArrayRef<Elf_Sym> Syms = this->getGlobalELFSyms(); | |
| 1005 | for (size_t I = 0; I < Syms.size(); ++I) { | |
| 1006 | const Elf_Sym &Sym = Syms[I]; | |
| 1317 | ArrayRef<Elf_Sym> syms = this->getGlobalELFSyms<ELFT>(); | |
| 1318 | for (size_t i = 0; i < syms.size(); ++i) { | |
| 1319 | const Elf_Sym &sym = syms[i]; | |
| 1007 | 1320 | |
| 1008 | 1321 | // ELF spec requires that all local symbols precede weak or global |
| 1009 | 1322 | // symbols in each symbol table, and the index of first non-local symbol |
| 1010 | 1323 | // is stored to sh_info. If a local symbol appears after some non-local |
| 1011 | 1324 | // symbol, that's a violation of the spec. |
| 1012 | StringRef Name = CHECK(Sym.getName(this->StringTable), this); | |
| 1013 | if (Sym.getBinding() == STB_LOCAL) { | |
| 1014 | warn("found local symbol '" + Name + | |
| 1325 | StringRef name = CHECK(sym.getName(this->stringTable), this); | |
| 1326 | if (sym.getBinding() == STB_LOCAL) { | |
| 1327 | warn("found local symbol '" + name + | |
| 1015 | 1328 | "' in global part of symbol table in file " + toString(this)); |
| 1016 | 1329 | continue; |
| 1017 | 1330 | } |
| 1018 | 1331 | |
| 1019 | if (Sym.isUndefined()) { | |
| 1020 | Symbol *S = Symtab->addUndefined<ELFT>(Name, Sym.getBinding(), | |
| 1021 | Sym.st_other, Sym.getType(), | |
| 1022 | /*CanOmitFromDynSym=*/false, this); | |
| 1023 | S->ExportDynamic = true; | |
| 1332 | if (sym.isUndefined()) { | |
| 1333 | Symbol *s = symtab->addSymbol( | |
| 1334 | Undefined{this, name, sym.getBinding(), sym.st_other, sym.getType()}); | |
| 1335 | s->exportDynamic = true; | |
| 1024 | 1336 | continue; |
| 1025 | 1337 | } |
| 1026 | 1338 | |
| 1027 | 1339 | // MIPS BFD linker puts _gp_disp symbol into DSO files and incorrectly |
| 1028 | 1340 | // assigns VER_NDX_LOCAL to this section global symbol. Here is a |
| 1029 | 1341 | // workaround for this bug. |
| 1030 | uint32_t Idx = Versyms[I] & ~VERSYM_HIDDEN; | |
| 1031 | if (Config->EMachine == EM_MIPS && Idx == VER_NDX_LOCAL && | |
| 1032 | Name == "_gp_disp") | |
| 1342 | uint32_t idx = versyms[i] & ~VERSYM_HIDDEN; | |
| 1343 | if (config->emachine == EM_MIPS && idx == VER_NDX_LOCAL && | |
| 1344 | name == "_gp_disp") | |
| 1033 | 1345 | continue; |
| 1034 | 1346 | |
| 1035 | uint64_t Alignment = getAlignment(Sections, Sym); | |
| 1036 | if (!(Versyms[I] & VERSYM_HIDDEN)) | |
| 1037 | Symtab->addShared(Name, *this, Sym, Alignment, Idx); | |
| 1347 | uint32_t alignment = getAlignment<ELFT>(sections, sym); | |
| 1348 | if (!(versyms[i] & VERSYM_HIDDEN)) { | |
| 1349 | symtab->addSymbol(SharedSymbol{*this, name, sym.getBinding(), | |
| 1350 | sym.st_other, sym.getType(), sym.st_value, | |
| 1351 | sym.st_size, alignment, idx}); | |
| 1352 | } | |
| 1038 | 1353 | |
| 1039 | 1354 | // Also add the symbol with the versioned name to handle undefined symbols |
| 1040 | 1355 | // with explicit versions. |
| 1041 | if (Idx == VER_NDX_GLOBAL) | |
| 1356 | if (idx == VER_NDX_GLOBAL) | |
| 1042 | 1357 | continue; |
| 1043 | 1358 | |
| 1044 | if (Idx >= Verdefs.size() || Idx == VER_NDX_LOCAL) { | |
| 1045 | error("corrupt input file: version definition index " + Twine(Idx) + | |
| 1046 | " for symbol " + Name + " is out of bounds\n>>> defined in " + | |
| 1359 | if (idx >= verdefs.size() || idx == VER_NDX_LOCAL) { | |
| 1360 | error("corrupt input file: version definition index " + Twine(idx) + | |
| 1361 | " for symbol " + name + " is out of bounds\n>>> defined in " + | |
| 1047 | 1362 | toString(this)); |
| 1048 | 1363 | continue; |
| 1049 | 1364 | } |
| 1050 | 1365 | |
| 1051 | StringRef VerName = | |
| 1052 | this->StringTable.data() + Verdefs[Idx]->getAux()->vda_name; | |
| 1053 | VersionedNameBuffer.clear(); | |
| 1054 | Name = (Name + "@" + VerName).toStringRef(VersionedNameBuffer); | |
| 1055 | Symtab->addShared(Saver.save(Name), *this, Sym, Alignment, Idx); | |
| 1366 | StringRef verName = | |
| 1367 | this->stringTable.data() + | |
| 1368 | reinterpret_cast<const Elf_Verdef *>(verdefs[idx])->getAux()->vda_name; | |
| 1369 | versionedNameBuffer.clear(); | |
| 1370 | name = (name + "@" + verName).toStringRef(versionedNameBuffer); | |
| 1371 | symtab->addSymbol(SharedSymbol{*this, saver.save(name), sym.getBinding(), | |
| 1372 | sym.st_other, sym.getType(), sym.st_value, | |
| 1373 | sym.st_size, alignment, idx}); | |
| 1056 | 1374 | } |
| 1057 | 1375 | } |
| 1058 | 1376 | |
| 1059 | static ELFKind getBitcodeELFKind(const Triple &T) { | |
| 1060 | if (T.isLittleEndian()) | |
| 1061 | return T.isArch64Bit() ? ELF64LEKind : ELF32LEKind; | |
| 1062 | return T.isArch64Bit() ? ELF64BEKind : ELF32BEKind; | |
| 1377 | static ELFKind getBitcodeELFKind(const Triple &t) { | |
| 1378 | if (t.isLittleEndian()) | |
| 1379 | return t.isArch64Bit() ? ELF64LEKind : ELF32LEKind; | |
| 1380 | return t.isArch64Bit() ? ELF64BEKind : ELF32BEKind; | |
| 1063 | 1381 | } |
| 1064 | 1382 | |
| 1065 | static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) { | |
| 1066 | switch (T.getArch()) { | |
| 1383 | static uint8_t getBitcodeMachineKind(StringRef path, const Triple &t) { | |
| 1384 | switch (t.getArch()) { | |
| 1067 | 1385 | case Triple::aarch64: |
| 1068 | 1386 | return EM_AARCH64; |
| 1069 | 1387 | case Triple::amdgcn: |
| ... | ... | @@ -1086,25 +1404,28 @@ static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) { |
| 1086 | 1404 | case Triple::ppc64: |
| 1087 | 1405 | case Triple::ppc64le: |
| 1088 | 1406 | return EM_PPC64; |
| 1407 | case Triple::riscv32: | |
| 1408 | case Triple::riscv64: | |
| 1409 | return EM_RISCV; | |
| 1089 | 1410 | case Triple::x86: |
| 1090 | return T.isOSIAMCU() ? EM_IAMCU : EM_386; | |
| 1411 | return t.isOSIAMCU() ? EM_IAMCU : EM_386; | |
| 1091 | 1412 | case Triple::x86_64: |
| 1092 | 1413 | return EM_X86_64; |
| 1093 | 1414 | default: |
| 1094 | error(Path + ": could not infer e_machine from bitcode target triple " + | |
| 1095 | T.str()); | |
| 1415 | error(path + ": could not infer e_machine from bitcode target triple " + | |
| 1416 | t.str()); | |
| 1096 | 1417 | return EM_NONE; |
| 1097 | 1418 | } |
| 1098 | 1419 | } |
| 1099 | 1420 | |
| 1100 | BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName, | |
| 1101 | uint64_t OffsetInArchive) | |
| 1102 | : InputFile(BitcodeKind, MB) { | |
| 1103 | this->ArchiveName = ArchiveName; | |
| 1421 | BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName, | |
| 1422 | uint64_t offsetInArchive) | |
| 1423 | : InputFile(BitcodeKind, mb) { | |
| 1424 | this->archiveName = archiveName; | |
| 1104 | 1425 | |
| 1105 | std::string Path = MB.getBufferIdentifier().str(); | |
| 1106 | if (Config->ThinLTOIndexOnly) | |
| 1107 | Path = replaceThinLTOSuffix(MB.getBufferIdentifier()); | |
| 1426 | std::string path = mb.getBufferIdentifier().str(); | |
| 1427 | if (config->thinLTOIndexOnly) | |
| 1428 | path = replaceThinLTOSuffix(mb.getBufferIdentifier()); | |
| 1108 | 1429 | |
| 1109 | 1430 | // ThinLTO assumes that all MemoryBufferRefs given to it have a unique |
| 1110 | 1431 | // name. If two archives define two members with the same name, this |
| ... | ... | @@ -1112,20 +1433,21 @@ BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName, |
| 1112 | 1433 | // into consideration at LTO time (which very likely causes undefined |
| 1113 | 1434 | // symbols later in the link stage). So we append file offset to make |
| 1114 | 1435 | // filename unique. |
| 1115 | MemoryBufferRef MBRef( | |
| 1116 | MB.getBuffer(), | |
| 1117 | Saver.save(ArchiveName + Path + | |
| 1118 | (ArchiveName.empty() ? "" : utostr(OffsetInArchive)))); | |
| 1436 | StringRef name = archiveName.empty() | |
| 1437 | ? saver.save(path) | |
| 1438 | : saver.save(archiveName + "(" + path + " at " + | |
| 1439 | utostr(offsetInArchive) + ")"); | |
| 1440 | MemoryBufferRef mbref(mb.getBuffer(), name); | |
| 1119 | 1441 | |
| 1120 | Obj = CHECK(lto::InputFile::create(MBRef), this); | |
| 1442 | obj = CHECK(lto::InputFile::create(mbref), this); | |
| 1121 | 1443 | |
| 1122 | Triple T(Obj->getTargetTriple()); | |
| 1123 | EKind = getBitcodeELFKind(T); | |
| 1124 | EMachine = getBitcodeMachineKind(MB.getBufferIdentifier(), T); | |
| 1444 | Triple t(obj->getTargetTriple()); | |
| 1445 | ekind = getBitcodeELFKind(t); | |
| 1446 | emachine = getBitcodeMachineKind(mb.getBufferIdentifier(), t); | |
| 1125 | 1447 | } |
| 1126 | 1448 | |
| 1127 | static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) { | |
| 1128 | switch (GvVisibility) { | |
| 1449 | static uint8_t mapVisibility(GlobalValue::VisibilityTypes gvVisibility) { | |
| 1450 | switch (gvVisibility) { | |
| 1129 | 1451 | case GlobalValue::DefaultVisibility: |
| 1130 | 1452 | return STV_DEFAULT; |
| 1131 | 1453 | case GlobalValue::HiddenVisibility: |
| ... | ... | @@ -1137,209 +1459,187 @@ static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) { |
| 1137 | 1459 | } |
| 1138 | 1460 | |
| 1139 | 1461 | template <class ELFT> |
| 1140 | static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats, | |
| 1141 | const lto::InputFile::Symbol &ObjSym, | |
| 1142 | BitcodeFile &F) { | |
| 1143 | StringRef Name = Saver.save(ObjSym.getName()); | |
| 1144 | uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL; | |
| 1145 | ||
| 1146 | uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE; | |
| 1147 | uint8_t Visibility = mapVisibility(ObjSym.getVisibility()); | |
| 1148 | bool CanOmitFromDynSym = ObjSym.canBeOmittedFromSymbolTable(); | |
| 1149 | ||
| 1150 | int C = ObjSym.getComdatIndex(); | |
| 1151 | if (C != -1 && !KeptComdats[C]) | |
| 1152 | return Symtab->addUndefined<ELFT>(Name, Binding, Visibility, Type, | |
| 1153 | CanOmitFromDynSym, &F); | |
| 1154 | ||
| 1155 | if (ObjSym.isUndefined()) | |
| 1156 | return Symtab->addUndefined<ELFT>(Name, Binding, Visibility, Type, | |
| 1157 | CanOmitFromDynSym, &F); | |
| 1158 | ||
| 1159 | if (ObjSym.isCommon()) | |
| 1160 | return Symtab->addCommon(Name, ObjSym.getCommonSize(), | |
| 1161 | ObjSym.getCommonAlignment(), Binding, Visibility, | |
| 1162 | STT_OBJECT, F); | |
| 1163 | ||
| 1164 | return Symtab->addBitcode(Name, Binding, Visibility, Type, CanOmitFromDynSym, | |
| 1165 | F); | |
| 1166 | } | |
| 1462 | static Symbol *createBitcodeSymbol(const std::vector<bool> &keptComdats, | |
| 1463 | const lto::InputFile::Symbol &objSym, | |
| 1464 | BitcodeFile &f) { | |
| 1465 | StringRef name = saver.save(objSym.getName()); | |
| 1466 | uint8_t binding = objSym.isWeak() ? STB_WEAK : STB_GLOBAL; | |
| 1467 | uint8_t type = objSym.isTLS() ? STT_TLS : STT_NOTYPE; | |
| 1468 | uint8_t visibility = mapVisibility(objSym.getVisibility()); | |
| 1469 | bool canOmitFromDynSym = objSym.canBeOmittedFromSymbolTable(); | |
| 1470 | ||
| 1471 | int c = objSym.getComdatIndex(); | |
| 1472 | if (objSym.isUndefined() || (c != -1 && !keptComdats[c])) { | |
| 1473 | Undefined New(&f, name, binding, visibility, type); | |
| 1474 | if (canOmitFromDynSym) | |
| 1475 | New.exportDynamic = false; | |
| 1476 | return symtab->addSymbol(New); | |
| 1477 | } | |
| 1167 | 1478 | |
| 1168 | template <class ELFT> | |
| 1169 | void BitcodeFile::parse(DenseSet<CachedHashStringRef> &ComdatGroups) { | |
| 1170 | std::vector<bool> KeptComdats; | |
| 1171 | for (StringRef S : Obj->getComdatTable()) | |
| 1172 | KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second); | |
| 1479 | if (objSym.isCommon()) | |
| 1480 | return symtab->addSymbol( | |
| 1481 | CommonSymbol{&f, name, binding, visibility, STT_OBJECT, | |
| 1482 | objSym.getCommonAlignment(), objSym.getCommonSize()}); | |
| 1173 | 1483 | |
| 1174 | for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) | |
| 1175 | Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, *this)); | |
| 1484 | Defined New(&f, name, binding, visibility, type, 0, 0, nullptr); | |
| 1485 | if (canOmitFromDynSym) | |
| 1486 | New.exportDynamic = false; | |
| 1487 | return symtab->addSymbol(New); | |
| 1176 | 1488 | } |
| 1177 | 1489 | |
| 1178 | static ELFKind getELFKind(MemoryBufferRef MB) { | |
| 1179 | unsigned char Size; | |
| 1180 | unsigned char Endian; | |
| 1181 | std::tie(Size, Endian) = getElfArchType(MB.getBuffer()); | |
| 1182 | ||
| 1183 | if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB) | |
| 1184 | fatal(MB.getBufferIdentifier() + ": invalid data encoding"); | |
| 1185 | if (Size != ELFCLASS32 && Size != ELFCLASS64) | |
| 1186 | fatal(MB.getBufferIdentifier() + ": invalid file class"); | |
| 1490 | template <class ELFT> void BitcodeFile::parse() { | |
| 1491 | std::vector<bool> keptComdats; | |
| 1492 | for (StringRef s : obj->getComdatTable()) | |
| 1493 | keptComdats.push_back( | |
| 1494 | symtab->comdatGroups.try_emplace(CachedHashStringRef(s), this).second); | |
| 1187 | 1495 | |
| 1188 | size_t BufSize = MB.getBuffer().size(); | |
| 1189 | if ((Size == ELFCLASS32 && BufSize < sizeof(Elf32_Ehdr)) || | |
| 1190 | (Size == ELFCLASS64 && BufSize < sizeof(Elf64_Ehdr))) | |
| 1191 | fatal(MB.getBufferIdentifier() + ": file is too short"); | |
| 1496 | for (const lto::InputFile::Symbol &objSym : obj->symbols()) | |
| 1497 | symbols.push_back(createBitcodeSymbol<ELFT>(keptComdats, objSym, *this)); | |
| 1192 | 1498 | |
| 1193 | if (Size == ELFCLASS32) | |
| 1194 | return (Endian == ELFDATA2LSB) ? ELF32LEKind : ELF32BEKind; | |
| 1195 | return (Endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind; | |
| 1499 | for (auto l : obj->getDependentLibraries()) | |
| 1500 | addDependentLibrary(l, this); | |
| 1196 | 1501 | } |
| 1197 | 1502 | |
| 1198 | 1503 | void BinaryFile::parse() { |
| 1199 | ArrayRef<uint8_t> Data = arrayRefFromStringRef(MB.getBuffer()); | |
| 1200 | auto *Section = make<InputSection>(this, SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, | |
| 1201 | 8, Data, ".data"); | |
| 1202 | Sections.push_back(Section); | |
| 1504 | ArrayRef<uint8_t> data = arrayRefFromStringRef(mb.getBuffer()); | |
| 1505 | auto *section = make<InputSection>(this, SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, | |
| 1506 | 8, data, ".data"); | |
| 1507 | sections.push_back(section); | |
| 1203 | 1508 | |
| 1204 | 1509 | // For each input file foo that is embedded to a result as a binary |
| 1205 | 1510 | // blob, we define _binary_foo_{start,end,size} symbols, so that |
| 1206 | 1511 | // user programs can access blobs by name. Non-alphanumeric |
| 1207 | 1512 | // characters in a filename are replaced with underscore. |
| 1208 | std::string S = "_binary_" + MB.getBufferIdentifier().str(); | |
| 1209 | for (size_t I = 0; I < S.size(); ++I) | |
| 1210 | if (!isAlnum(S[I])) | |
| 1211 | S[I] = '_'; | |
| 1212 | ||
| 1213 | Symtab->addDefined(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, 0, 0, | |
| 1214 | STB_GLOBAL, Section, nullptr); | |
| 1215 | Symtab->addDefined(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT, | |
| 1216 | Data.size(), 0, STB_GLOBAL, Section, nullptr); | |
| 1217 | Symtab->addDefined(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT, | |
| 1218 | Data.size(), 0, STB_GLOBAL, nullptr, nullptr); | |
| 1513 | std::string s = "_binary_" + mb.getBufferIdentifier().str(); | |
| 1514 | for (size_t i = 0; i < s.size(); ++i) | |
| 1515 | if (!isAlnum(s[i])) | |
| 1516 | s[i] = '_'; | |
| 1517 | ||
| 1518 | symtab->addSymbol(Defined{nullptr, saver.save(s + "_start"), STB_GLOBAL, | |
| 1519 | STV_DEFAULT, STT_OBJECT, 0, 0, section}); | |
| 1520 | symtab->addSymbol(Defined{nullptr, saver.save(s + "_end"), STB_GLOBAL, | |
| 1521 | STV_DEFAULT, STT_OBJECT, data.size(), 0, section}); | |
| 1522 | symtab->addSymbol(Defined{nullptr, saver.save(s + "_size"), STB_GLOBAL, | |
| 1523 | STV_DEFAULT, STT_OBJECT, data.size(), 0, nullptr}); | |
| 1219 | 1524 | } |
| 1220 | 1525 | |
| 1221 | InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, | |
| 1222 | uint64_t OffsetInArchive) { | |
| 1223 | if (isBitcode(MB)) | |
| 1224 | return make<BitcodeFile>(MB, ArchiveName, OffsetInArchive); | |
| 1526 | InputFile *elf::createObjectFile(MemoryBufferRef mb, StringRef archiveName, | |
| 1527 | uint64_t offsetInArchive) { | |
| 1528 | if (isBitcode(mb)) | |
| 1529 | return make<BitcodeFile>(mb, archiveName, offsetInArchive); | |
| 1225 | 1530 | |
| 1226 | switch (getELFKind(MB)) { | |
| 1531 | switch (getELFKind(mb, archiveName)) { | |
| 1227 | 1532 | case ELF32LEKind: |
| 1228 | return make<ObjFile<ELF32LE>>(MB, ArchiveName); | |
| 1533 | return make<ObjFile<ELF32LE>>(mb, archiveName); | |
| 1229 | 1534 | case ELF32BEKind: |
| 1230 | return make<ObjFile<ELF32BE>>(MB, ArchiveName); | |
| 1535 | return make<ObjFile<ELF32BE>>(mb, archiveName); | |
| 1231 | 1536 | case ELF64LEKind: |
| 1232 | return make<ObjFile<ELF64LE>>(MB, ArchiveName); | |
| 1537 | return make<ObjFile<ELF64LE>>(mb, archiveName); | |
| 1233 | 1538 | case ELF64BEKind: |
| 1234 | return make<ObjFile<ELF64BE>>(MB, ArchiveName); | |
| 1539 | return make<ObjFile<ELF64BE>>(mb, archiveName); | |
| 1235 | 1540 | default: |
| 1236 | 1541 | llvm_unreachable("getELFKind"); |
| 1237 | 1542 | } |
| 1238 | 1543 | } |
| 1239 | 1544 | |
| 1240 | InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) { | |
| 1241 | switch (getELFKind(MB)) { | |
| 1242 | case ELF32LEKind: | |
| 1243 | return make<SharedFile<ELF32LE>>(MB, DefaultSoName); | |
| 1244 | case ELF32BEKind: | |
| 1245 | return make<SharedFile<ELF32BE>>(MB, DefaultSoName); | |
| 1246 | case ELF64LEKind: | |
| 1247 | return make<SharedFile<ELF64LE>>(MB, DefaultSoName); | |
| 1248 | case ELF64BEKind: | |
| 1249 | return make<SharedFile<ELF64BE>>(MB, DefaultSoName); | |
| 1250 | default: | |
| 1251 | llvm_unreachable("getELFKind"); | |
| 1252 | } | |
| 1253 | } | |
| 1545 | void LazyObjFile::fetch() { | |
| 1546 | if (mb.getBuffer().empty()) | |
| 1547 | return; | |
| 1254 | 1548 | |
| 1255 | MemoryBufferRef LazyObjFile::getBuffer() { | |
| 1256 | if (AddedToLink) | |
| 1257 | return MemoryBufferRef(); | |
| 1258 | AddedToLink = true; | |
| 1259 | return MB; | |
| 1260 | } | |
| 1549 | InputFile *file = createObjectFile(mb, archiveName, offsetInArchive); | |
| 1550 | file->groupId = groupId; | |
| 1261 | 1551 | |
| 1262 | InputFile *LazyObjFile::fetch() { | |
| 1263 | MemoryBufferRef MBRef = getBuffer(); | |
| 1264 | if (MBRef.getBuffer().empty()) | |
| 1265 | return nullptr; | |
| 1552 | mb = {}; | |
| 1553 | ||
| 1554 | // Copy symbol vector so that the new InputFile doesn't have to | |
| 1555 | // insert the same defined symbols to the symbol table again. | |
| 1556 | file->symbols = std::move(symbols); | |
| 1266 | 1557 | |
| 1267 | InputFile *File = createObjectFile(MBRef, ArchiveName, OffsetInArchive); | |
| 1268 | File->GroupId = GroupId; | |
| 1269 | return File; | |
| 1558 | parseFile(file); | |
| 1270 | 1559 | } |
| 1271 | 1560 | |
| 1272 | 1561 | template <class ELFT> void LazyObjFile::parse() { |
| 1562 | using Elf_Sym = typename ELFT::Sym; | |
| 1563 | ||
| 1273 | 1564 | // A lazy object file wraps either a bitcode file or an ELF file. |
| 1274 | if (isBitcode(this->MB)) { | |
| 1275 | std::unique_ptr<lto::InputFile> Obj = | |
| 1276 | CHECK(lto::InputFile::create(this->MB), this); | |
| 1277 | for (const lto::InputFile::Symbol &Sym : Obj->symbols()) | |
| 1278 | if (!Sym.isUndefined()) | |
| 1279 | Symtab->addLazyObject<ELFT>(Saver.save(Sym.getName()), *this); | |
| 1565 | if (isBitcode(this->mb)) { | |
| 1566 | std::unique_ptr<lto::InputFile> obj = | |
| 1567 | CHECK(lto::InputFile::create(this->mb), this); | |
| 1568 | for (const lto::InputFile::Symbol &sym : obj->symbols()) { | |
| 1569 | if (sym.isUndefined()) | |
| 1570 | continue; | |
| 1571 | symtab->addSymbol(LazyObject{*this, saver.save(sym.getName())}); | |
| 1572 | } | |
| 1280 | 1573 | return; |
| 1281 | 1574 | } |
| 1282 | 1575 | |
| 1283 | if (getELFKind(this->MB) != Config->EKind) { | |
| 1284 | error("incompatible file: " + this->MB.getBufferIdentifier()); | |
| 1576 | if (getELFKind(this->mb, archiveName) != config->ekind) { | |
| 1577 | error("incompatible file: " + this->mb.getBufferIdentifier()); | |
| 1285 | 1578 | return; |
| 1286 | 1579 | } |
| 1287 | 1580 | |
| 1288 | ELFFile<ELFT> Obj = check(ELFFile<ELFT>::create(MB.getBuffer())); | |
| 1289 | ArrayRef<typename ELFT::Shdr> Sections = CHECK(Obj.sections(), this); | |
| 1581 | // Find a symbol table. | |
| 1582 | ELFFile<ELFT> obj = check(ELFFile<ELFT>::create(mb.getBuffer())); | |
| 1583 | ArrayRef<typename ELFT::Shdr> sections = CHECK(obj.sections(), this); | |
| 1290 | 1584 | |
| 1291 | for (const typename ELFT::Shdr &Sec : Sections) { | |
| 1292 | if (Sec.sh_type != SHT_SYMTAB) | |
| 1585 | for (const typename ELFT::Shdr &sec : sections) { | |
| 1586 | if (sec.sh_type != SHT_SYMTAB) | |
| 1293 | 1587 | continue; |
| 1294 | 1588 | |
| 1295 | typename ELFT::SymRange Syms = CHECK(Obj.symbols(&Sec), this); | |
| 1296 | uint32_t FirstGlobal = Sec.sh_info; | |
| 1297 | StringRef StringTable = | |
| 1298 | CHECK(Obj.getStringTableForSymtab(Sec, Sections), this); | |
| 1589 | // A symbol table is found. | |
| 1590 | ArrayRef<Elf_Sym> eSyms = CHECK(obj.symbols(&sec), this); | |
| 1591 | uint32_t firstGlobal = sec.sh_info; | |
| 1592 | StringRef strtab = CHECK(obj.getStringTableForSymtab(sec, sections), this); | |
| 1593 | this->symbols.resize(eSyms.size()); | |
| 1594 | ||
| 1595 | // Get existing symbols or insert placeholder symbols. | |
| 1596 | for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i) | |
| 1597 | if (eSyms[i].st_shndx != SHN_UNDEF) | |
| 1598 | this->symbols[i] = symtab->insert(CHECK(eSyms[i].getName(strtab), this)); | |
| 1599 | ||
| 1600 | // Replace existing symbols with LazyObject symbols. | |
| 1601 | // | |
| 1602 | // resolve() may trigger this->fetch() if an existing symbol is an | |
| 1603 | // undefined symbol. If that happens, this LazyObjFile has served | |
| 1604 | // its purpose, and we can exit from the loop early. | |
| 1605 | for (Symbol *sym : this->symbols) { | |
| 1606 | if (!sym) | |
| 1607 | continue; | |
| 1608 | sym->resolve(LazyObject{*this, sym->getName()}); | |
| 1299 | 1609 | |
| 1300 | for (const typename ELFT::Sym &Sym : Syms.slice(FirstGlobal)) | |
| 1301 | if (Sym.st_shndx != SHN_UNDEF) | |
| 1302 | Symtab->addLazyObject<ELFT>(CHECK(Sym.getName(StringTable), this), | |
| 1303 | *this); | |
| 1610 | // MemoryBuffer is emptied if this file is instantiated as ObjFile. | |
| 1611 | if (mb.getBuffer().empty()) | |
| 1612 | return; | |
| 1613 | } | |
| 1304 | 1614 | return; |
| 1305 | 1615 | } |
| 1306 | 1616 | } |
| 1307 | 1617 | |
| 1308 | std::string elf::replaceThinLTOSuffix(StringRef Path) { | |
| 1309 | StringRef Suffix = Config->ThinLTOObjectSuffixReplace.first; | |
| 1310 | StringRef Repl = Config->ThinLTOObjectSuffixReplace.second; | |
| 1618 | std::string elf::replaceThinLTOSuffix(StringRef path) { | |
| 1619 | StringRef suffix = config->thinLTOObjectSuffixReplace.first; | |
| 1620 | StringRef repl = config->thinLTOObjectSuffixReplace.second; | |
| 1311 | 1621 | |
| 1312 | if (Path.consume_back(Suffix)) | |
| 1313 | return (Path + Repl).str(); | |
| 1314 | return Path; | |
| 1622 | if (path.consume_back(suffix)) | |
| 1623 | return (path + repl).str(); | |
| 1624 | return path; | |
| 1315 | 1625 | } |
| 1316 | 1626 | |
| 1317 | template void ArchiveFile::parse<ELF32LE>(); | |
| 1318 | template void ArchiveFile::parse<ELF32BE>(); | |
| 1319 | template void ArchiveFile::parse<ELF64LE>(); | |
| 1320 | template void ArchiveFile::parse<ELF64BE>(); | |
| 1321 | ||
| 1322 | template void BitcodeFile::parse<ELF32LE>(DenseSet<CachedHashStringRef> &); | |
| 1323 | template void BitcodeFile::parse<ELF32BE>(DenseSet<CachedHashStringRef> &); | |
| 1324 | template void BitcodeFile::parse<ELF64LE>(DenseSet<CachedHashStringRef> &); | |
| 1325 | template void BitcodeFile::parse<ELF64BE>(DenseSet<CachedHashStringRef> &); | |
| 1627 | template void BitcodeFile::parse<ELF32LE>(); | |
| 1628 | template void BitcodeFile::parse<ELF32BE>(); | |
| 1629 | template void BitcodeFile::parse<ELF64LE>(); | |
| 1630 | template void BitcodeFile::parse<ELF64BE>(); | |
| 1326 | 1631 | |
| 1327 | 1632 | template void LazyObjFile::parse<ELF32LE>(); |
| 1328 | 1633 | template void LazyObjFile::parse<ELF32BE>(); |
| 1329 | 1634 | template void LazyObjFile::parse<ELF64LE>(); |
| 1330 | 1635 | template void LazyObjFile::parse<ELF64BE>(); |
| 1331 | 1636 | |
| 1332 | template class elf::ELFFileBase<ELF32LE>; | |
| 1333 | template class elf::ELFFileBase<ELF32BE>; | |
| 1334 | template class elf::ELFFileBase<ELF64LE>; | |
| 1335 | template class elf::ELFFileBase<ELF64BE>; | |
| 1336 | ||
| 1337 | 1637 | template class elf::ObjFile<ELF32LE>; |
| 1338 | 1638 | template class elf::ObjFile<ELF32BE>; |
| 1339 | 1639 | template class elf::ObjFile<ELF64LE>; |
| 1340 | 1640 | template class elf::ObjFile<ELF64BE>; |
| 1341 | 1641 | |
| 1342 | template class elf::SharedFile<ELF32LE>; | |
| 1343 | template class elf::SharedFile<ELF32BE>; | |
| 1344 | template class elf::SharedFile<ELF64LE>; | |
| 1345 | template class elf::SharedFile<ELF64BE>; | |
| 1642 | template void SharedFile::parse<ELF32LE>(); | |
| 1643 | template void SharedFile::parse<ELF32BE>(); | |
| 1644 | template void SharedFile::parse<ELF64LE>(); | |
| 1645 | template void SharedFile::parse<ELF64BE>(); |
deps/lld/ELF/InputFiles.h+190-167| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- InputFiles.h ---------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -40,7 +39,7 @@ class InputSectionBase; |
| 40 | 39 | } |
| 41 | 40 | |
| 42 | 41 | // Returns "<internal>", "foo.a(bar.o)" or "baz.o". |
| 43 | std::string toString(const elf::InputFile *F); | |
| 42 | std::string toString(const elf::InputFile *f); | |
| 44 | 43 | |
| 45 | 44 | namespace elf { |
| 46 | 45 | |
| ... | ... | @@ -50,10 +49,13 @@ class Symbol; |
| 50 | 49 | |
| 51 | 50 | // If -reproduce option is given, all input files are written |
| 52 | 51 | // to this tar archive. |
| 53 | extern std::unique_ptr<llvm::TarWriter> Tar; | |
| 52 | extern std::unique_ptr<llvm::TarWriter> tar; | |
| 54 | 53 | |
| 55 | 54 | // Opens a given file. |
| 56 | llvm::Optional<MemoryBufferRef> readFile(StringRef Path); | |
| 55 | llvm::Optional<MemoryBufferRef> readFile(StringRef path); | |
| 56 | ||
| 57 | // Add symbols in File to the symbol table. | |
| 58 | void parseFile(InputFile *file); | |
| 57 | 59 | |
| 58 | 60 | // The root class of input files. |
| 59 | 61 | class InputFile { |
| ... | ... | @@ -67,191 +69,230 @@ public: |
| 67 | 69 | BinaryKind, |
| 68 | 70 | }; |
| 69 | 71 | |
| 70 | Kind kind() const { return FileKind; } | |
| 72 | Kind kind() const { return fileKind; } | |
| 71 | 73 | |
| 72 | 74 | bool isElf() const { |
| 73 | Kind K = kind(); | |
| 74 | return K == ObjKind || K == SharedKind; | |
| 75 | Kind k = kind(); | |
| 76 | return k == ObjKind || k == SharedKind; | |
| 75 | 77 | } |
| 76 | 78 | |
| 77 | StringRef getName() const { return MB.getBufferIdentifier(); } | |
| 78 | MemoryBufferRef MB; | |
| 79 | StringRef getName() const { return mb.getBufferIdentifier(); } | |
| 80 | MemoryBufferRef mb; | |
| 79 | 81 | |
| 80 | 82 | // Returns sections. It is a runtime error to call this function |
| 81 | 83 | // on files that don't have the notion of sections. |
| 82 | 84 | ArrayRef<InputSectionBase *> getSections() const { |
| 83 | assert(FileKind == ObjKind || FileKind == BinaryKind); | |
| 84 | return Sections; | |
| 85 | assert(fileKind == ObjKind || fileKind == BinaryKind); | |
| 86 | return sections; | |
| 85 | 87 | } |
| 86 | 88 | |
| 87 | 89 | // Returns object file symbols. It is a runtime error to call this |
| 88 | 90 | // function on files of other types. |
| 89 | 91 | ArrayRef<Symbol *> getSymbols() { return getMutableSymbols(); } |
| 90 | 92 | |
| 91 | std::vector<Symbol *> &getMutableSymbols() { | |
| 92 | assert(FileKind == BinaryKind || FileKind == ObjKind || | |
| 93 | FileKind == BitcodeKind); | |
| 94 | return Symbols; | |
| 93 | MutableArrayRef<Symbol *> getMutableSymbols() { | |
| 94 | assert(fileKind == BinaryKind || fileKind == ObjKind || | |
| 95 | fileKind == BitcodeKind); | |
| 96 | return symbols; | |
| 95 | 97 | } |
| 96 | 98 | |
| 97 | 99 | // Filename of .a which contained this file. If this file was |
| 98 | 100 | // not in an archive file, it is the empty string. We use this |
| 99 | 101 | // string for creating error messages. |
| 100 | std::string ArchiveName; | |
| 102 | std::string archiveName; | |
| 101 | 103 | |
| 102 | 104 | // If this is an architecture-specific file, the following members |
| 103 | 105 | // have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type. |
| 104 | ELFKind EKind = ELFNoneKind; | |
| 105 | uint16_t EMachine = llvm::ELF::EM_NONE; | |
| 106 | uint8_t OSABI = 0; | |
| 106 | ELFKind ekind = ELFNoneKind; | |
| 107 | uint16_t emachine = llvm::ELF::EM_NONE; | |
| 108 | uint8_t osabi = 0; | |
| 109 | uint8_t abiVersion = 0; | |
| 107 | 110 | |
| 108 | 111 | // Cache for toString(). Only toString() should use this member. |
| 109 | mutable std::string ToStringCache; | |
| 112 | mutable std::string toStringCache; | |
| 110 | 113 | |
| 111 | std::string getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, | |
| 112 | uint64_t Offset); | |
| 114 | std::string getSrcMsg(const Symbol &sym, InputSectionBase &sec, | |
| 115 | uint64_t offset); | |
| 113 | 116 | |
| 114 | 117 | // True if this is an argument for --just-symbols. Usually false. |
| 115 | bool JustSymbols = false; | |
| 116 | ||
| 117 | // GroupId is used for --warn-backrefs which is an optional error | |
| 118 | bool justSymbols = false; | |
| 119 | ||
| 120 | // outSecOff of .got2 in the current file. This is used by PPC32 -fPIC/-fPIE | |
| 121 | // to compute offsets in PLT call stubs. | |
| 122 | uint32_t ppc32Got2OutSecOff = 0; | |
| 123 | ||
| 124 | // On PPC64 we need to keep track of which files contain small code model | |
| 125 | // relocations that access the .toc section. To minimize the chance of a | |
| 126 | // relocation overflow, files that do contain said relocations should have | |
| 127 | // their .toc sections sorted closer to the .got section than files that do | |
| 128 | // not contain any small code model relocations. Thats because the toc-pointer | |
| 129 | // is defined to point at .got + 0x8000 and the instructions used with small | |
| 130 | // code model relocations support immediates in the range [-0x8000, 0x7FFC], | |
| 131 | // making the addressable range relative to the toc pointer | |
| 132 | // [.got, .got + 0xFFFC]. | |
| 133 | bool ppc64SmallCodeModelTocRelocs = false; | |
| 134 | ||
| 135 | // groupId is used for --warn-backrefs which is an optional error | |
| 118 | 136 | // checking feature. All files within the same --{start,end}-group or |
| 119 | 137 | // --{start,end}-lib get the same group ID. Otherwise, each file gets a new |
| 120 | 138 | // group ID. For more info, see checkDependency() in SymbolTable.cpp. |
| 121 | uint32_t GroupId; | |
| 122 | static bool IsInGroup; | |
| 123 | static uint32_t NextGroupId; | |
| 139 | uint32_t groupId; | |
| 140 | static bool isInGroup; | |
| 141 | static uint32_t nextGroupId; | |
| 124 | 142 | |
| 125 | 143 | // Index of MIPS GOT built for this file. |
| 126 | llvm::Optional<size_t> MipsGotIndex; | |
| 144 | llvm::Optional<size_t> mipsGotIndex; | |
| 145 | ||
| 146 | std::vector<Symbol *> symbols; | |
| 127 | 147 | |
| 128 | 148 | protected: |
| 129 | InputFile(Kind K, MemoryBufferRef M); | |
| 130 | std::vector<InputSectionBase *> Sections; | |
| 131 | std::vector<Symbol *> Symbols; | |
| 149 | InputFile(Kind k, MemoryBufferRef m); | |
| 150 | std::vector<InputSectionBase *> sections; | |
| 132 | 151 | |
| 133 | 152 | private: |
| 134 | const Kind FileKind; | |
| 153 | const Kind fileKind; | |
| 135 | 154 | }; |
| 136 | 155 | |
| 137 | template <typename ELFT> class ELFFileBase : public InputFile { | |
| 156 | class ELFFileBase : public InputFile { | |
| 138 | 157 | public: |
| 139 | typedef typename ELFT::Shdr Elf_Shdr; | |
| 140 | typedef typename ELFT::Sym Elf_Sym; | |
| 141 | typedef typename ELFT::Word Elf_Word; | |
| 142 | typedef typename ELFT::SymRange Elf_Sym_Range; | |
| 158 | ELFFileBase(Kind k, MemoryBufferRef m); | |
| 159 | static bool classof(const InputFile *f) { return f->isElf(); } | |
| 143 | 160 | |
| 144 | ELFFileBase(Kind K, MemoryBufferRef M); | |
| 145 | static bool classof(const InputFile *F) { return F->isElf(); } | |
| 146 | ||
| 147 | llvm::object::ELFFile<ELFT> getObj() const { | |
| 148 | return check(llvm::object::ELFFile<ELFT>::create(MB.getBuffer())); | |
| 161 | template <typename ELFT> llvm::object::ELFFile<ELFT> getObj() const { | |
| 162 | return check(llvm::object::ELFFile<ELFT>::create(mb.getBuffer())); | |
| 149 | 163 | } |
| 150 | 164 | |
| 151 | StringRef getStringTable() const { return StringTable; } | |
| 152 | ||
| 153 | uint32_t getSectionIndex(const Elf_Sym &Sym) const; | |
| 165 | StringRef getStringTable() const { return stringTable; } | |
| 154 | 166 | |
| 155 | Elf_Sym_Range getGlobalELFSyms(); | |
| 156 | Elf_Sym_Range getELFSyms() const { return ELFSyms; } | |
| 167 | template <typename ELFT> typename ELFT::SymRange getELFSyms() const { | |
| 168 | return typename ELFT::SymRange( | |
| 169 | reinterpret_cast<const typename ELFT::Sym *>(elfSyms), numELFSyms); | |
| 170 | } | |
| 171 | template <typename ELFT> typename ELFT::SymRange getGlobalELFSyms() const { | |
| 172 | return getELFSyms<ELFT>().slice(firstGlobal); | |
| 173 | } | |
| 157 | 174 | |
| 158 | 175 | protected: |
| 159 | ArrayRef<Elf_Sym> ELFSyms; | |
| 160 | uint32_t FirstGlobal = 0; | |
| 161 | ArrayRef<Elf_Word> SymtabSHNDX; | |
| 162 | StringRef StringTable; | |
| 163 | void initSymtab(ArrayRef<Elf_Shdr> Sections, const Elf_Shdr *Symtab); | |
| 176 | // Initializes this class's member variables. | |
| 177 | template <typename ELFT> void init(); | |
| 178 | ||
| 179 | const void *elfSyms = nullptr; | |
| 180 | size_t numELFSyms = 0; | |
| 181 | uint32_t firstGlobal = 0; | |
| 182 | StringRef stringTable; | |
| 164 | 183 | }; |
| 165 | 184 | |
| 166 | 185 | // .o file. |
| 167 | template <class ELFT> class ObjFile : public ELFFileBase<ELFT> { | |
| 168 | typedef ELFFileBase<ELFT> Base; | |
| 169 | typedef typename ELFT::Rel Elf_Rel; | |
| 170 | typedef typename ELFT::Rela Elf_Rela; | |
| 171 | typedef typename ELFT::Sym Elf_Sym; | |
| 172 | typedef typename ELFT::Shdr Elf_Shdr; | |
| 173 | typedef typename ELFT::Word Elf_Word; | |
| 174 | typedef typename ELFT::CGProfile Elf_CGProfile; | |
| 175 | ||
| 176 | StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> Sections, | |
| 177 | const Elf_Shdr &Sec); | |
| 186 | template <class ELFT> class ObjFile : public ELFFileBase { | |
| 187 | using Elf_Rel = typename ELFT::Rel; | |
| 188 | using Elf_Rela = typename ELFT::Rela; | |
| 189 | using Elf_Sym = typename ELFT::Sym; | |
| 190 | using Elf_Shdr = typename ELFT::Shdr; | |
| 191 | using Elf_Word = typename ELFT::Word; | |
| 192 | using Elf_CGProfile = typename ELFT::CGProfile; | |
| 178 | 193 | |
| 179 | 194 | public: |
| 180 | static bool classof(const InputFile *F) { return F->kind() == Base::ObjKind; } | |
| 195 | static bool classof(const InputFile *f) { return f->kind() == ObjKind; } | |
| 196 | ||
| 197 | llvm::object::ELFFile<ELFT> getObj() const { | |
| 198 | return this->ELFFileBase::getObj<ELFT>(); | |
| 199 | } | |
| 181 | 200 | |
| 182 | 201 | ArrayRef<Symbol *> getLocalSymbols(); |
| 183 | 202 | ArrayRef<Symbol *> getGlobalSymbols(); |
| 184 | 203 | |
| 185 | ObjFile(MemoryBufferRef M, StringRef ArchiveName); | |
| 186 | void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups); | |
| 204 | ObjFile(MemoryBufferRef m, StringRef archiveName) : ELFFileBase(ObjKind, m) { | |
| 205 | this->archiveName = archiveName; | |
| 206 | } | |
| 207 | ||
| 208 | void parse(bool ignoreComdats = false); | |
| 187 | 209 | |
| 188 | Symbol &getSymbol(uint32_t SymbolIndex) const { | |
| 189 | if (SymbolIndex >= this->Symbols.size()) | |
| 210 | StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> sections, | |
| 211 | const Elf_Shdr &sec); | |
| 212 | ||
| 213 | Symbol &getSymbol(uint32_t symbolIndex) const { | |
| 214 | if (symbolIndex >= this->symbols.size()) | |
| 190 | 215 | fatal(toString(this) + ": invalid symbol index"); |
| 191 | return *this->Symbols[SymbolIndex]; | |
| 216 | return *this->symbols[symbolIndex]; | |
| 192 | 217 | } |
| 193 | 218 | |
| 194 | template <typename RelT> Symbol &getRelocTargetSym(const RelT &Rel) const { | |
| 195 | uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); | |
| 196 | return getSymbol(SymIndex); | |
| 219 | uint32_t getSectionIndex(const Elf_Sym &sym) const; | |
| 220 | ||
| 221 | template <typename RelT> Symbol &getRelocTargetSym(const RelT &rel) const { | |
| 222 | uint32_t symIndex = rel.getSymbol(config->isMips64EL); | |
| 223 | return getSymbol(symIndex); | |
| 197 | 224 | } |
| 198 | 225 | |
| 199 | 226 | llvm::Optional<llvm::DILineInfo> getDILineInfo(InputSectionBase *, uint64_t); |
| 200 | llvm::Optional<std::pair<std::string, unsigned>> getVariableLoc(StringRef Name); | |
| 227 | llvm::Optional<std::pair<std::string, unsigned>> getVariableLoc(StringRef name); | |
| 201 | 228 | |
| 202 | 229 | // MIPS GP0 value defined by this file. This value represents the gp value |
| 203 | 230 | // used to create the relocatable object and required to support |
| 204 | 231 | // R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations. |
| 205 | uint32_t MipsGp0 = 0; | |
| 232 | uint32_t mipsGp0 = 0; | |
| 233 | ||
| 234 | uint32_t andFeatures = 0; | |
| 206 | 235 | |
| 207 | 236 | // Name of source file obtained from STT_FILE symbol value, |
| 208 | 237 | // or empty string if there is no such symbol in object file |
| 209 | 238 | // symbol table. |
| 210 | StringRef SourceFile; | |
| 239 | StringRef sourceFile; | |
| 211 | 240 | |
| 212 | 241 | // True if the file defines functions compiled with |
| 213 | 242 | // -fsplit-stack. Usually false. |
| 214 | bool SplitStack = false; | |
| 243 | bool splitStack = false; | |
| 215 | 244 | |
| 216 | 245 | // True if the file defines functions compiled with -fsplit-stack, |
| 217 | 246 | // but had one or more functions with the no_split_stack attribute. |
| 218 | bool SomeNoSplitStack = false; | |
| 247 | bool someNoSplitStack = false; | |
| 219 | 248 | |
| 220 | 249 | // Pointer to this input file's .llvm_addrsig section, if it has one. |
| 221 | const Elf_Shdr *AddrsigSec = nullptr; | |
| 250 | const Elf_Shdr *addrsigSec = nullptr; | |
| 222 | 251 | |
| 223 | 252 | // SHT_LLVM_CALL_GRAPH_PROFILE table |
| 224 | ArrayRef<Elf_CGProfile> CGProfile; | |
| 253 | ArrayRef<Elf_CGProfile> cgProfile; | |
| 225 | 254 | |
| 226 | 255 | private: |
| 227 | void | |
| 228 | initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups); | |
| 256 | void initializeSections(bool ignoreComdats); | |
| 229 | 257 | void initializeSymbols(); |
| 230 | 258 | void initializeJustSymbols(); |
| 231 | 259 | void initializeDwarf(); |
| 232 | InputSectionBase *getRelocTarget(const Elf_Shdr &Sec); | |
| 233 | InputSectionBase *createInputSection(const Elf_Shdr &Sec); | |
| 234 | StringRef getSectionName(const Elf_Shdr &Sec); | |
| 235 | ||
| 236 | bool shouldMerge(const Elf_Shdr &Sec); | |
| 237 | Symbol *createSymbol(const Elf_Sym *Sym); | |
| 260 | InputSectionBase *getRelocTarget(const Elf_Shdr &sec); | |
| 261 | InputSectionBase *createInputSection(const Elf_Shdr &sec); | |
| 262 | StringRef getSectionName(const Elf_Shdr &sec); | |
| 263 | ||
| 264 | bool shouldMerge(const Elf_Shdr &sec); | |
| 265 | ||
| 266 | // Each ELF symbol contains a section index which the symbol belongs to. | |
| 267 | // However, because the number of bits dedicated for that is limited, a | |
| 268 | // symbol can directly point to a section only when the section index is | |
| 269 | // equal to or smaller than 65280. | |
| 270 | // | |
| 271 | // If an object file contains more than 65280 sections, the file must | |
| 272 | // contain .symtab_shndx section. The section contains an array of | |
| 273 | // 32-bit integers whose size is the same as the number of symbols. | |
| 274 | // Nth symbol's section index is in the Nth entry of .symtab_shndx. | |
| 275 | // | |
| 276 | // The following variable contains the contents of .symtab_shndx. | |
| 277 | // If the section does not exist (which is common), the array is empty. | |
| 278 | ArrayRef<Elf_Word> shndxTable; | |
| 238 | 279 | |
| 239 | 280 | // .shstrtab contents. |
| 240 | StringRef SectionStringTable; | |
| 281 | StringRef sectionStringTable; | |
| 241 | 282 | |
| 242 | 283 | // Debugging information to retrieve source file and line for error |
| 243 | 284 | // reporting. Linker may find reasonable number of errors in a |
| 244 | 285 | // single object file, so we cache debugging information in order to |
| 245 | 286 | // parse it only once for each object file we link. |
| 246 | std::unique_ptr<llvm::DWARFContext> Dwarf; | |
| 247 | std::vector<const llvm::DWARFDebugLine::LineTable *> LineTables; | |
| 287 | std::unique_ptr<llvm::DWARFContext> dwarf; | |
| 288 | std::vector<const llvm::DWARFDebugLine::LineTable *> lineTables; | |
| 248 | 289 | struct VarLoc { |
| 249 | const llvm::DWARFDebugLine::LineTable *LT; | |
| 250 | unsigned File; | |
| 251 | unsigned Line; | |
| 290 | const llvm::DWARFDebugLine::LineTable *lt; | |
| 291 | unsigned file; | |
| 292 | unsigned line; | |
| 252 | 293 | }; |
| 253 | llvm::DenseMap<StringRef, VarLoc> VariableLoc; | |
| 254 | llvm::once_flag InitDwarfLine; | |
| 294 | llvm::DenseMap<StringRef, VarLoc> variableLoc; | |
| 295 | llvm::once_flag initDwarfLine; | |
| 255 | 296 | }; |
| 256 | 297 | |
| 257 | 298 | // LazyObjFile is analogous to ArchiveFile in the sense that |
| ... | ... | @@ -263,118 +304,100 @@ private: |
| 263 | 304 | // archive file semantics. |
| 264 | 305 | class LazyObjFile : public InputFile { |
| 265 | 306 | public: |
| 266 | LazyObjFile(MemoryBufferRef M, StringRef ArchiveName, | |
| 267 | uint64_t OffsetInArchive) | |
| 268 | : InputFile(LazyObjKind, M), OffsetInArchive(OffsetInArchive) { | |
| 269 | this->ArchiveName = ArchiveName; | |
| 307 | LazyObjFile(MemoryBufferRef m, StringRef archiveName, | |
| 308 | uint64_t offsetInArchive) | |
| 309 | : InputFile(LazyObjKind, m), offsetInArchive(offsetInArchive) { | |
| 310 | this->archiveName = archiveName; | |
| 270 | 311 | } |
| 271 | 312 | |
| 272 | static bool classof(const InputFile *F) { return F->kind() == LazyObjKind; } | |
| 313 | static bool classof(const InputFile *f) { return f->kind() == LazyObjKind; } | |
| 273 | 314 | |
| 274 | 315 | template <class ELFT> void parse(); |
| 275 | MemoryBufferRef getBuffer(); | |
| 276 | InputFile *fetch(); | |
| 277 | bool AddedToLink = false; | |
| 316 | void fetch(); | |
| 278 | 317 | |
| 279 | 318 | private: |
| 280 | uint64_t OffsetInArchive; | |
| 319 | uint64_t offsetInArchive; | |
| 281 | 320 | }; |
| 282 | 321 | |
| 283 | 322 | // An ArchiveFile object represents a .a file. |
| 284 | 323 | class ArchiveFile : public InputFile { |
| 285 | 324 | public: |
| 286 | explicit ArchiveFile(std::unique_ptr<Archive> &&File); | |
| 287 | static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } | |
| 288 | template <class ELFT> void parse(); | |
| 325 | explicit ArchiveFile(std::unique_ptr<Archive> &&file); | |
| 326 | static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; } | |
| 327 | void parse(); | |
| 289 | 328 | |
| 290 | 329 | // Pulls out an object file that contains a definition for Sym and |
| 291 | 330 | // returns it. If the same file was instantiated before, this |
| 292 | // function returns a nullptr (so we don't instantiate the same file | |
| 331 | // function does nothing (so we don't instantiate the same file | |
| 293 | 332 | // more than once.) |
| 294 | InputFile *fetch(const Archive::Symbol &Sym); | |
| 333 | void fetch(const Archive::Symbol &sym); | |
| 295 | 334 | |
| 296 | 335 | private: |
| 297 | std::unique_ptr<Archive> File; | |
| 298 | llvm::DenseSet<uint64_t> Seen; | |
| 336 | std::unique_ptr<Archive> file; | |
| 337 | llvm::DenseSet<uint64_t> seen; | |
| 299 | 338 | }; |
| 300 | 339 | |
| 301 | 340 | class BitcodeFile : public InputFile { |
| 302 | 341 | public: |
| 303 | BitcodeFile(MemoryBufferRef M, StringRef ArchiveName, | |
| 304 | uint64_t OffsetInArchive); | |
| 305 | static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } | |
| 306 | template <class ELFT> | |
| 307 | void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups); | |
| 308 | std::unique_ptr<llvm::lto::InputFile> Obj; | |
| 342 | BitcodeFile(MemoryBufferRef m, StringRef archiveName, | |
| 343 | uint64_t offsetInArchive); | |
| 344 | static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; } | |
| 345 | template <class ELFT> void parse(); | |
| 346 | std::unique_ptr<llvm::lto::InputFile> obj; | |
| 309 | 347 | }; |
| 310 | 348 | |
| 311 | 349 | // .so file. |
| 312 | template <class ELFT> class SharedFile : public ELFFileBase<ELFT> { | |
| 313 | typedef ELFFileBase<ELFT> Base; | |
| 314 | typedef typename ELFT::Dyn Elf_Dyn; | |
| 315 | typedef typename ELFT::Shdr Elf_Shdr; | |
| 316 | typedef typename ELFT::Sym Elf_Sym; | |
| 317 | typedef typename ELFT::SymRange Elf_Sym_Range; | |
| 318 | typedef typename ELFT::Verdef Elf_Verdef; | |
| 319 | typedef typename ELFT::Versym Elf_Versym; | |
| 320 | ||
| 321 | const Elf_Shdr *VersymSec = nullptr; | |
| 322 | const Elf_Shdr *VerdefSec = nullptr; | |
| 323 | ||
| 350 | class SharedFile : public ELFFileBase { | |
| 324 | 351 | public: |
| 325 | std::vector<const Elf_Verdef *> Verdefs; | |
| 326 | std::string SoName; | |
| 352 | SharedFile(MemoryBufferRef m, StringRef defaultSoName) | |
| 353 | : ELFFileBase(SharedKind, m), soName(defaultSoName), | |
| 354 | isNeeded(!config->asNeeded) {} | |
| 327 | 355 | |
| 328 | static bool classof(const InputFile *F) { | |
| 329 | return F->kind() == Base::SharedKind; | |
| 330 | } | |
| 356 | // This is actually a vector of Elf_Verdef pointers. | |
| 357 | std::vector<const void *> verdefs; | |
| 331 | 358 | |
| 332 | SharedFile(MemoryBufferRef M, StringRef DefaultSoName); | |
| 359 | // If the output file needs Elf_Verneed data structures for this file, this is | |
| 360 | // a vector of Elf_Vernaux version identifiers that map onto the entries in | |
| 361 | // Verdefs, otherwise it is empty. | |
| 362 | std::vector<unsigned> vernauxs; | |
| 333 | 363 | |
| 334 | void parseSoName(); | |
| 335 | void parseRest(); | |
| 336 | uint32_t getAlignment(ArrayRef<Elf_Shdr> Sections, const Elf_Sym &Sym); | |
| 337 | std::vector<const Elf_Verdef *> parseVerdefs(); | |
| 338 | std::vector<uint32_t> parseVersyms(); | |
| 364 | static unsigned vernauxNum; | |
| 339 | 365 | |
| 340 | struct NeededVer { | |
| 341 | // The string table offset of the version name in the output file. | |
| 342 | size_t StrTab; | |
| 366 | std::vector<StringRef> dtNeeded; | |
| 367 | std::string soName; | |
| 343 | 368 | |
| 344 | // The version identifier for this version name. | |
| 345 | uint16_t Index; | |
| 346 | }; | |
| 369 | static bool classof(const InputFile *f) { return f->kind() == SharedKind; } | |
| 370 | ||
| 371 | template <typename ELFT> void parse(); | |
| 347 | 372 | |
| 348 | // Mapping from Elf_Verdef data structures to information about Elf_Vernaux | |
| 349 | // data structures in the output file. | |
| 350 | std::map<const Elf_Verdef *, NeededVer> VerdefMap; | |
| 373 | // Used for --no-allow-shlib-undefined. | |
| 374 | bool allNeededIsKnown; | |
| 351 | 375 | |
| 352 | 376 | // Used for --as-needed |
| 353 | bool IsNeeded; | |
| 377 | bool isNeeded; | |
| 354 | 378 | }; |
| 355 | 379 | |
| 356 | 380 | class BinaryFile : public InputFile { |
| 357 | 381 | public: |
| 358 | explicit BinaryFile(MemoryBufferRef M) : InputFile(BinaryKind, M) {} | |
| 359 | static bool classof(const InputFile *F) { return F->kind() == BinaryKind; } | |
| 382 | explicit BinaryFile(MemoryBufferRef m) : InputFile(BinaryKind, m) {} | |
| 383 | static bool classof(const InputFile *f) { return f->kind() == BinaryKind; } | |
| 360 | 384 | void parse(); |
| 361 | 385 | }; |
| 362 | 386 | |
| 363 | InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "", | |
| 364 | uint64_t OffsetInArchive = 0); | |
| 365 | InputFile *createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName); | |
| 387 | InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName = "", | |
| 388 | uint64_t offsetInArchive = 0); | |
| 366 | 389 | |
| 367 | inline bool isBitcode(MemoryBufferRef MB) { | |
| 368 | return identify_magic(MB.getBuffer()) == llvm::file_magic::bitcode; | |
| 390 | inline bool isBitcode(MemoryBufferRef mb) { | |
| 391 | return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode; | |
| 369 | 392 | } |
| 370 | 393 | |
| 371 | std::string replaceThinLTOSuffix(StringRef Path); | |
| 394 | std::string replaceThinLTOSuffix(StringRef path); | |
| 372 | 395 | |
| 373 | extern std::vector<BinaryFile *> BinaryFiles; | |
| 374 | extern std::vector<BitcodeFile *> BitcodeFiles; | |
| 375 | extern std::vector<LazyObjFile *> LazyObjFiles; | |
| 376 | extern std::vector<InputFile *> ObjectFiles; | |
| 377 | extern std::vector<InputFile *> SharedFiles; | |
| 396 | extern std::vector<BinaryFile *> binaryFiles; | |
| 397 | extern std::vector<BitcodeFile *> bitcodeFiles; | |
| 398 | extern std::vector<LazyObjFile *> lazyObjFiles; | |
| 399 | extern std::vector<InputFile *> objectFiles; | |
| 400 | extern std::vector<SharedFile *> sharedFiles; | |
| 378 | 401 | |
| 379 | 402 | } // namespace elf |
| 380 | 403 | } // namespace lld |
deps/lld/ELF/InputSection.cpp+583-530| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- InputSection.cpp ---------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -41,52 +40,52 @@ using namespace llvm::sys; |
| 41 | 40 | using namespace lld; |
| 42 | 41 | using namespace lld::elf; |
| 43 | 42 | |
| 44 | std::vector<InputSectionBase *> elf::InputSections; | |
| 43 | std::vector<InputSectionBase *> elf::inputSections; | |
| 45 | 44 | |
| 46 | 45 | // Returns a string to construct an error message. |
| 47 | std::string lld::toString(const InputSectionBase *Sec) { | |
| 48 | return (toString(Sec->File) + ":(" + Sec->Name + ")").str(); | |
| 46 | std::string lld::toString(const InputSectionBase *sec) { | |
| 47 | return (toString(sec->file) + ":(" + sec->name + ")").str(); | |
| 49 | 48 | } |
| 50 | 49 | |
| 51 | 50 | template <class ELFT> |
| 52 | static ArrayRef<uint8_t> getSectionContents(ObjFile<ELFT> &File, | |
| 53 | const typename ELFT::Shdr &Hdr) { | |
| 54 | if (Hdr.sh_type == SHT_NOBITS) | |
| 55 | return makeArrayRef<uint8_t>(nullptr, Hdr.sh_size); | |
| 56 | return check(File.getObj().getSectionContents(&Hdr)); | |
| 51 | static ArrayRef<uint8_t> getSectionContents(ObjFile<ELFT> &file, | |
| 52 | const typename ELFT::Shdr &hdr) { | |
| 53 | if (hdr.sh_type == SHT_NOBITS) | |
| 54 | return makeArrayRef<uint8_t>(nullptr, hdr.sh_size); | |
| 55 | return check(file.getObj().getSectionContents(&hdr)); | |
| 57 | 56 | } |
| 58 | 57 | |
| 59 | InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags, | |
| 60 | uint32_t Type, uint64_t Entsize, | |
| 61 | uint32_t Link, uint32_t Info, | |
| 62 | uint32_t Alignment, ArrayRef<uint8_t> Data, | |
| 63 | StringRef Name, Kind SectionKind) | |
| 64 | : SectionBase(SectionKind, Name, Flags, Entsize, Alignment, Type, Info, | |
| 65 | Link), | |
| 66 | File(File), RawData(Data) { | |
| 58 | InputSectionBase::InputSectionBase(InputFile *file, uint64_t flags, | |
| 59 | uint32_t type, uint64_t entsize, | |
| 60 | uint32_t link, uint32_t info, | |
| 61 | uint32_t alignment, ArrayRef<uint8_t> data, | |
| 62 | StringRef name, Kind sectionKind) | |
| 63 | : SectionBase(sectionKind, name, flags, entsize, alignment, type, info, | |
| 64 | link), | |
| 65 | file(file), rawData(data) { | |
| 67 | 66 | // In order to reduce memory allocation, we assume that mergeable |
| 68 | 67 | // sections are smaller than 4 GiB, which is not an unreasonable |
| 69 | 68 | // assumption as of 2017. |
| 70 | if (SectionKind == SectionBase::Merge && RawData.size() > UINT32_MAX) | |
| 69 | if (sectionKind == SectionBase::Merge && rawData.size() > UINT32_MAX) | |
| 71 | 70 | error(toString(this) + ": section too large"); |
| 72 | 71 | |
| 73 | NumRelocations = 0; | |
| 74 | AreRelocsRela = false; | |
| 72 | numRelocations = 0; | |
| 73 | areRelocsRela = false; | |
| 75 | 74 | |
| 76 | 75 | // The ELF spec states that a value of 0 means the section has |
| 77 | 76 | // no alignment constraits. |
| 78 | uint32_t V = std::max<uint64_t>(Alignment, 1); | |
| 79 | if (!isPowerOf2_64(V)) | |
| 80 | fatal(toString(File) + ": section sh_addralign is not a power of 2"); | |
| 81 | this->Alignment = V; | |
| 77 | uint32_t v = std::max<uint32_t>(alignment, 1); | |
| 78 | if (!isPowerOf2_64(v)) | |
| 79 | fatal(toString(this) + ": sh_addralign is not a power of 2"); | |
| 80 | this->alignment = v; | |
| 82 | 81 | |
| 83 | 82 | // In ELF, each section can be compressed by zlib, and if compressed, |
| 84 | 83 | // section name may be mangled by appending "z" (e.g. ".zdebug_info"). |
| 85 | 84 | // If that's the case, demangle section name so that we can handle a |
| 86 | 85 | // section as if it weren't compressed. |
| 87 | if ((Flags & SHF_COMPRESSED) || Name.startswith(".zdebug")) { | |
| 86 | if ((flags & SHF_COMPRESSED) || name.startswith(".zdebug")) { | |
| 88 | 87 | if (!zlib::isAvailable()) |
| 89 | error(toString(File) + ": contains a compressed section, " + | |
| 88 | error(toString(file) + ": contains a compressed section, " + | |
| 90 | 89 | "but zlib is not available"); |
| 91 | 90 | parseCompressedHeader(); |
| 92 | 91 | } |
| ... | ... | @@ -95,11 +94,11 @@ InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags, |
| 95 | 94 | // Drop SHF_GROUP bit unless we are producing a re-linkable object file. |
| 96 | 95 | // SHF_GROUP is a marker that a section belongs to some comdat group. |
| 97 | 96 | // That flag doesn't make sense in an executable. |
| 98 | static uint64_t getFlags(uint64_t Flags) { | |
| 99 | Flags &= ~(uint64_t)SHF_INFO_LINK; | |
| 100 | if (!Config->Relocatable) | |
| 101 | Flags &= ~(uint64_t)SHF_GROUP; | |
| 102 | return Flags; | |
| 97 | static uint64_t getFlags(uint64_t flags) { | |
| 98 | flags &= ~(uint64_t)SHF_INFO_LINK; | |
| 99 | if (!config->relocatable) | |
| 100 | flags &= ~(uint64_t)SHF_GROUP; | |
| 101 | return flags; | |
| 103 | 102 | } |
| 104 | 103 | |
| 105 | 104 | // GNU assembler 2.24 and LLVM 4.0.0's MC (the newest release as of |
| ... | ... | @@ -112,205 +111,212 @@ static uint64_t getFlags(uint64_t Flags) { |
| 112 | 111 | // |
| 113 | 112 | // This function forces SHT_{INIT,FINI}_ARRAY so that we can handle |
| 114 | 113 | // incorrect inputs as if they were correct from the beginning. |
| 115 | static uint64_t getType(uint64_t Type, StringRef Name) { | |
| 116 | if (Type == SHT_PROGBITS && Name.startswith(".init_array.")) | |
| 114 | static uint64_t getType(uint64_t type, StringRef name) { | |
| 115 | if (type == SHT_PROGBITS && name.startswith(".init_array.")) | |
| 117 | 116 | return SHT_INIT_ARRAY; |
| 118 | if (Type == SHT_PROGBITS && Name.startswith(".fini_array.")) | |
| 117 | if (type == SHT_PROGBITS && name.startswith(".fini_array.")) | |
| 119 | 118 | return SHT_FINI_ARRAY; |
| 120 | return Type; | |
| 119 | return type; | |
| 121 | 120 | } |
| 122 | 121 | |
| 123 | 122 | template <class ELFT> |
| 124 | InputSectionBase::InputSectionBase(ObjFile<ELFT> &File, | |
| 125 | const typename ELFT::Shdr &Hdr, | |
| 126 | StringRef Name, Kind SectionKind) | |
| 127 | : InputSectionBase(&File, getFlags(Hdr.sh_flags), | |
| 128 | getType(Hdr.sh_type, Name), Hdr.sh_entsize, Hdr.sh_link, | |
| 129 | Hdr.sh_info, Hdr.sh_addralign, | |
| 130 | getSectionContents(File, Hdr), Name, SectionKind) { | |
| 123 | InputSectionBase::InputSectionBase(ObjFile<ELFT> &file, | |
| 124 | const typename ELFT::Shdr &hdr, | |
| 125 | StringRef name, Kind sectionKind) | |
| 126 | : InputSectionBase(&file, getFlags(hdr.sh_flags), | |
| 127 | getType(hdr.sh_type, name), hdr.sh_entsize, hdr.sh_link, | |
| 128 | hdr.sh_info, hdr.sh_addralign, | |
| 129 | getSectionContents(file, hdr), name, sectionKind) { | |
| 131 | 130 | // We reject object files having insanely large alignments even though |
| 132 | 131 | // they are allowed by the spec. I think 4GB is a reasonable limitation. |
| 133 | 132 | // We might want to relax this in the future. |
| 134 | if (Hdr.sh_addralign > UINT32_MAX) | |
| 135 | fatal(toString(&File) + ": section sh_addralign is too large"); | |
| 133 | if (hdr.sh_addralign > UINT32_MAX) | |
| 134 | fatal(toString(&file) + ": section sh_addralign is too large"); | |
| 136 | 135 | } |
| 137 | 136 | |
| 138 | 137 | size_t InputSectionBase::getSize() const { |
| 139 | if (auto *S = dyn_cast<SyntheticSection>(this)) | |
| 140 | return S->getSize(); | |
| 141 | if (UncompressedSize >= 0) | |
| 142 | return UncompressedSize; | |
| 143 | return RawData.size(); | |
| 138 | if (auto *s = dyn_cast<SyntheticSection>(this)) | |
| 139 | return s->getSize(); | |
| 140 | if (uncompressedSize >= 0) | |
| 141 | return uncompressedSize; | |
| 142 | return rawData.size(); | |
| 144 | 143 | } |
| 145 | 144 | |
| 146 | 145 | void InputSectionBase::uncompress() const { |
| 147 | size_t Size = UncompressedSize; | |
| 148 | UncompressedBuf.reset(new char[Size]); | |
| 146 | size_t size = uncompressedSize; | |
| 147 | char *uncompressedBuf; | |
| 148 | { | |
| 149 | static std::mutex mu; | |
| 150 | std::lock_guard<std::mutex> lock(mu); | |
| 151 | uncompressedBuf = bAlloc.Allocate<char>(size); | |
| 152 | } | |
| 149 | 153 | |
| 150 | if (Error E = | |
| 151 | zlib::uncompress(toStringRef(RawData), UncompressedBuf.get(), Size)) | |
| 154 | if (Error e = zlib::uncompress(toStringRef(rawData), uncompressedBuf, size)) | |
| 152 | 155 | fatal(toString(this) + |
| 153 | ": uncompress failed: " + llvm::toString(std::move(E))); | |
| 154 | RawData = makeArrayRef((uint8_t *)UncompressedBuf.get(), Size); | |
| 156 | ": uncompress failed: " + llvm::toString(std::move(e))); | |
| 157 | rawData = makeArrayRef((uint8_t *)uncompressedBuf, size); | |
| 158 | uncompressedSize = -1; | |
| 155 | 159 | } |
| 156 | 160 | |
| 157 | 161 | uint64_t InputSectionBase::getOffsetInFile() const { |
| 158 | const uint8_t *FileStart = (const uint8_t *)File->MB.getBufferStart(); | |
| 159 | const uint8_t *SecStart = data().begin(); | |
| 160 | return SecStart - FileStart; | |
| 162 | const uint8_t *fileStart = (const uint8_t *)file->mb.getBufferStart(); | |
| 163 | const uint8_t *secStart = data().begin(); | |
| 164 | return secStart - fileStart; | |
| 161 | 165 | } |
| 162 | 166 | |
| 163 | uint64_t SectionBase::getOffset(uint64_t Offset) const { | |
| 167 | uint64_t SectionBase::getOffset(uint64_t offset) const { | |
| 164 | 168 | switch (kind()) { |
| 165 | 169 | case Output: { |
| 166 | auto *OS = cast<OutputSection>(this); | |
| 170 | auto *os = cast<OutputSection>(this); | |
| 167 | 171 | // For output sections we treat offset -1 as the end of the section. |
| 168 | return Offset == uint64_t(-1) ? OS->Size : Offset; | |
| 172 | return offset == uint64_t(-1) ? os->size : offset; | |
| 169 | 173 | } |
| 170 | 174 | case Regular: |
| 171 | 175 | case Synthetic: |
| 172 | return cast<InputSection>(this)->getOffset(Offset); | |
| 176 | return cast<InputSection>(this)->getOffset(offset); | |
| 173 | 177 | case EHFrame: |
| 174 | 178 | // The file crtbeginT.o has relocations pointing to the start of an empty |
| 175 | 179 | // .eh_frame that is known to be the first in the link. It does that to |
| 176 | 180 | // identify the start of the output .eh_frame. |
| 177 | return Offset; | |
| 181 | return offset; | |
| 178 | 182 | case Merge: |
| 179 | const MergeInputSection *MS = cast<MergeInputSection>(this); | |
| 180 | if (InputSection *IS = MS->getParent()) | |
| 181 | return IS->getOffset(MS->getParentOffset(Offset)); | |
| 182 | return MS->getParentOffset(Offset); | |
| 183 | const MergeInputSection *ms = cast<MergeInputSection>(this); | |
| 184 | if (InputSection *isec = ms->getParent()) | |
| 185 | return isec->getOffset(ms->getParentOffset(offset)); | |
| 186 | return ms->getParentOffset(offset); | |
| 183 | 187 | } |
| 184 | 188 | llvm_unreachable("invalid section kind"); |
| 185 | 189 | } |
| 186 | 190 | |
| 187 | uint64_t SectionBase::getVA(uint64_t Offset) const { | |
| 188 | const OutputSection *Out = getOutputSection(); | |
| 189 | return (Out ? Out->Addr : 0) + getOffset(Offset); | |
| 191 | uint64_t SectionBase::getVA(uint64_t offset) const { | |
| 192 | const OutputSection *out = getOutputSection(); | |
| 193 | return (out ? out->addr : 0) + getOffset(offset); | |
| 190 | 194 | } |
| 191 | 195 | |
| 192 | 196 | OutputSection *SectionBase::getOutputSection() { |
| 193 | InputSection *Sec; | |
| 194 | if (auto *IS = dyn_cast<InputSection>(this)) | |
| 195 | Sec = IS; | |
| 196 | else if (auto *MS = dyn_cast<MergeInputSection>(this)) | |
| 197 | Sec = MS->getParent(); | |
| 198 | else if (auto *EH = dyn_cast<EhInputSection>(this)) | |
| 199 | Sec = EH->getParent(); | |
| 197 | InputSection *sec; | |
| 198 | if (auto *isec = dyn_cast<InputSection>(this)) | |
| 199 | sec = isec; | |
| 200 | else if (auto *ms = dyn_cast<MergeInputSection>(this)) | |
| 201 | sec = ms->getParent(); | |
| 202 | else if (auto *eh = dyn_cast<EhInputSection>(this)) | |
| 203 | sec = eh->getParent(); | |
| 200 | 204 | else |
| 201 | 205 | return cast<OutputSection>(this); |
| 202 | return Sec ? Sec->getParent() : nullptr; | |
| 206 | return sec ? sec->getParent() : nullptr; | |
| 203 | 207 | } |
| 204 | 208 | |
| 205 | // When a section is compressed, `RawData` consists with a header followed | |
| 209 | // When a section is compressed, `rawData` consists with a header followed | |
| 206 | 210 | // by zlib-compressed data. This function parses a header to initialize |
| 207 | // `UncompressedSize` member and remove the header from `RawData`. | |
| 211 | // `uncompressedSize` member and remove the header from `rawData`. | |
| 208 | 212 | void InputSectionBase::parseCompressedHeader() { |
| 209 | typedef typename ELF64LE::Chdr Chdr64; | |
| 210 | typedef typename ELF32LE::Chdr Chdr32; | |
| 213 | using Chdr64 = typename ELF64LE::Chdr; | |
| 214 | using Chdr32 = typename ELF32LE::Chdr; | |
| 211 | 215 | |
| 212 | 216 | // Old-style header |
| 213 | if (Name.startswith(".zdebug")) { | |
| 214 | if (!toStringRef(RawData).startswith("ZLIB")) { | |
| 217 | if (name.startswith(".zdebug")) { | |
| 218 | if (!toStringRef(rawData).startswith("ZLIB")) { | |
| 215 | 219 | error(toString(this) + ": corrupted compressed section header"); |
| 216 | 220 | return; |
| 217 | 221 | } |
| 218 | RawData = RawData.slice(4); | |
| 222 | rawData = rawData.slice(4); | |
| 219 | 223 | |
| 220 | if (RawData.size() < 8) { | |
| 224 | if (rawData.size() < 8) { | |
| 221 | 225 | error(toString(this) + ": corrupted compressed section header"); |
| 222 | 226 | return; |
| 223 | 227 | } |
| 224 | 228 | |
| 225 | UncompressedSize = read64be(RawData.data()); | |
| 226 | RawData = RawData.slice(8); | |
| 229 | uncompressedSize = read64be(rawData.data()); | |
| 230 | rawData = rawData.slice(8); | |
| 227 | 231 | |
| 228 | 232 | // Restore the original section name. |
| 229 | 233 | // (e.g. ".zdebug_info" -> ".debug_info") |
| 230 | Name = Saver.save("." + Name.substr(2)); | |
| 234 | name = saver.save("." + name.substr(2)); | |
| 231 | 235 | return; |
| 232 | 236 | } |
| 233 | 237 | |
| 234 | assert(Flags & SHF_COMPRESSED); | |
| 235 | Flags &= ~(uint64_t)SHF_COMPRESSED; | |
| 238 | assert(flags & SHF_COMPRESSED); | |
| 239 | flags &= ~(uint64_t)SHF_COMPRESSED; | |
| 236 | 240 | |
| 237 | 241 | // New-style 64-bit header |
| 238 | if (Config->Is64) { | |
| 239 | if (RawData.size() < sizeof(Chdr64)) { | |
| 242 | if (config->is64) { | |
| 243 | if (rawData.size() < sizeof(Chdr64)) { | |
| 240 | 244 | error(toString(this) + ": corrupted compressed section"); |
| 241 | 245 | return; |
| 242 | 246 | } |
| 243 | 247 | |
| 244 | auto *Hdr = reinterpret_cast<const Chdr64 *>(RawData.data()); | |
| 245 | if (Hdr->ch_type != ELFCOMPRESS_ZLIB) { | |
| 248 | auto *hdr = reinterpret_cast<const Chdr64 *>(rawData.data()); | |
| 249 | if (hdr->ch_type != ELFCOMPRESS_ZLIB) { | |
| 246 | 250 | error(toString(this) + ": unsupported compression type"); |
| 247 | 251 | return; |
| 248 | 252 | } |
| 249 | 253 | |
| 250 | UncompressedSize = Hdr->ch_size; | |
| 251 | RawData = RawData.slice(sizeof(*Hdr)); | |
| 254 | uncompressedSize = hdr->ch_size; | |
| 255 | alignment = std::max<uint32_t>(hdr->ch_addralign, 1); | |
| 256 | rawData = rawData.slice(sizeof(*hdr)); | |
| 252 | 257 | return; |
| 253 | 258 | } |
| 254 | 259 | |
| 255 | 260 | // New-style 32-bit header |
| 256 | if (RawData.size() < sizeof(Chdr32)) { | |
| 261 | if (rawData.size() < sizeof(Chdr32)) { | |
| 257 | 262 | error(toString(this) + ": corrupted compressed section"); |
| 258 | 263 | return; |
| 259 | 264 | } |
| 260 | 265 | |
| 261 | auto *Hdr = reinterpret_cast<const Chdr32 *>(RawData.data()); | |
| 262 | if (Hdr->ch_type != ELFCOMPRESS_ZLIB) { | |
| 266 | auto *hdr = reinterpret_cast<const Chdr32 *>(rawData.data()); | |
| 267 | if (hdr->ch_type != ELFCOMPRESS_ZLIB) { | |
| 263 | 268 | error(toString(this) + ": unsupported compression type"); |
| 264 | 269 | return; |
| 265 | 270 | } |
| 266 | 271 | |
| 267 | UncompressedSize = Hdr->ch_size; | |
| 268 | RawData = RawData.slice(sizeof(*Hdr)); | |
| 272 | uncompressedSize = hdr->ch_size; | |
| 273 | alignment = std::max<uint32_t>(hdr->ch_addralign, 1); | |
| 274 | rawData = rawData.slice(sizeof(*hdr)); | |
| 269 | 275 | } |
| 270 | 276 | |
| 271 | 277 | InputSection *InputSectionBase::getLinkOrderDep() const { |
| 272 | assert(Link); | |
| 273 | assert(Flags & SHF_LINK_ORDER); | |
| 274 | return cast<InputSection>(File->getSections()[Link]); | |
| 278 | assert(link); | |
| 279 | assert(flags & SHF_LINK_ORDER); | |
| 280 | return cast<InputSection>(file->getSections()[link]); | |
| 275 | 281 | } |
| 276 | 282 | |
| 277 | 283 | // Find a function symbol that encloses a given location. |
| 278 | 284 | template <class ELFT> |
| 279 | Defined *InputSectionBase::getEnclosingFunction(uint64_t Offset) { | |
| 280 | for (Symbol *B : File->getSymbols()) | |
| 281 | if (Defined *D = dyn_cast<Defined>(B)) | |
| 282 | if (D->Section == this && D->Type == STT_FUNC && D->Value <= Offset && | |
| 283 | Offset < D->Value + D->Size) | |
| 284 | return D; | |
| 285 | Defined *InputSectionBase::getEnclosingFunction(uint64_t offset) { | |
| 286 | for (Symbol *b : file->getSymbols()) | |
| 287 | if (Defined *d = dyn_cast<Defined>(b)) | |
| 288 | if (d->section == this && d->type == STT_FUNC && d->value <= offset && | |
| 289 | offset < d->value + d->size) | |
| 290 | return d; | |
| 285 | 291 | return nullptr; |
| 286 | 292 | } |
| 287 | 293 | |
| 288 | 294 | // Returns a source location string. Used to construct an error message. |
| 289 | 295 | template <class ELFT> |
| 290 | std::string InputSectionBase::getLocation(uint64_t Offset) { | |
| 291 | std::string SecAndOffset = (Name + "+0x" + utohexstr(Offset)).str(); | |
| 296 | std::string InputSectionBase::getLocation(uint64_t offset) { | |
| 297 | std::string secAndOffset = (name + "+0x" + utohexstr(offset)).str(); | |
| 292 | 298 | |
| 293 | 299 | // We don't have file for synthetic sections. |
| 294 | 300 | if (getFile<ELFT>() == nullptr) |
| 295 | return (Config->OutputFile + ":(" + SecAndOffset + ")") | |
| 301 | return (config->outputFile + ":(" + secAndOffset + ")") | |
| 296 | 302 | .str(); |
| 297 | 303 | |
| 298 | 304 | // First check if we can get desired values from debugging information. |
| 299 | if (Optional<DILineInfo> Info = getFile<ELFT>()->getDILineInfo(this, Offset)) | |
| 300 | return Info->FileName + ":" + std::to_string(Info->Line) + ":(" + | |
| 301 | SecAndOffset + ")"; | |
| 305 | if (Optional<DILineInfo> info = getFile<ELFT>()->getDILineInfo(this, offset)) | |
| 306 | return info->FileName + ":" + std::to_string(info->Line) + ":(" + | |
| 307 | secAndOffset + ")"; | |
| 302 | 308 | |
| 303 | // File->SourceFile contains STT_FILE symbol that contains a | |
| 309 | // File->sourceFile contains STT_FILE symbol that contains a | |
| 304 | 310 | // source file name. If it's missing, we use an object file name. |
| 305 | std::string SrcFile = getFile<ELFT>()->SourceFile; | |
| 306 | if (SrcFile.empty()) | |
| 307 | SrcFile = toString(File); | |
| 311 | std::string srcFile = getFile<ELFT>()->sourceFile; | |
| 312 | if (srcFile.empty()) | |
| 313 | srcFile = toString(file); | |
| 308 | 314 | |
| 309 | if (Defined *D = getEnclosingFunction<ELFT>(Offset)) | |
| 310 | return SrcFile + ":(function " + toString(*D) + ": " + SecAndOffset + ")"; | |
| 315 | if (Defined *d = getEnclosingFunction<ELFT>(offset)) | |
| 316 | return srcFile + ":(function " + toString(*d) + ": " + secAndOffset + ")"; | |
| 311 | 317 | |
| 312 | 318 | // If there's no symbol, print out the offset in the section. |
| 313 | return (SrcFile + ":(" + SecAndOffset + ")"); | |
| 319 | return (srcFile + ":(" + secAndOffset + ")"); | |
| 314 | 320 | } |
| 315 | 321 | |
| 316 | 322 | // This function is intended to be used for constructing an error message. |
| ... | ... | @@ -319,8 +325,8 @@ std::string InputSectionBase::getLocation(uint64_t Offset) { |
| 319 | 325 | // foo.c:42 (/home/alice/possibly/very/long/path/foo.c:42) |
| 320 | 326 | // |
| 321 | 327 | // Returns an empty string if there's no way to get line info. |
| 322 | std::string InputSectionBase::getSrcMsg(const Symbol &Sym, uint64_t Offset) { | |
| 323 | return File->getSrcMsg(Sym, *this, Offset); | |
| 328 | std::string InputSectionBase::getSrcMsg(const Symbol &sym, uint64_t offset) { | |
| 329 | return file->getSrcMsg(sym, *this, offset); | |
| 324 | 330 | } |
| 325 | 331 | |
| 326 | 332 | // Returns a filename string along with an optional section name. This |
| ... | ... | @@ -332,95 +338,96 @@ std::string InputSectionBase::getSrcMsg(const Symbol &Sym, uint64_t Offset) { |
| 332 | 338 | // or |
| 333 | 339 | // |
| 334 | 340 | // path/to/foo.o:(function bar) in archive path/to/bar.a |
| 335 | std::string InputSectionBase::getObjMsg(uint64_t Off) { | |
| 336 | std::string Filename = File->getName(); | |
| 341 | std::string InputSectionBase::getObjMsg(uint64_t off) { | |
| 342 | std::string filename = file->getName(); | |
| 337 | 343 | |
| 338 | std::string Archive; | |
| 339 | if (!File->ArchiveName.empty()) | |
| 340 | Archive = " in archive " + File->ArchiveName; | |
| 344 | std::string archive; | |
| 345 | if (!file->archiveName.empty()) | |
| 346 | archive = " in archive " + file->archiveName; | |
| 341 | 347 | |
| 342 | 348 | // Find a symbol that encloses a given location. |
| 343 | for (Symbol *B : File->getSymbols()) | |
| 344 | if (auto *D = dyn_cast<Defined>(B)) | |
| 345 | if (D->Section == this && D->Value <= Off && Off < D->Value + D->Size) | |
| 346 | return Filename + ":(" + toString(*D) + ")" + Archive; | |
| 349 | for (Symbol *b : file->getSymbols()) | |
| 350 | if (auto *d = dyn_cast<Defined>(b)) | |
| 351 | if (d->section == this && d->value <= off && off < d->value + d->size) | |
| 352 | return filename + ":(" + toString(*d) + ")" + archive; | |
| 347 | 353 | |
| 348 | 354 | // If there's no symbol, print out the offset in the section. |
| 349 | return (Filename + ":(" + Name + "+0x" + utohexstr(Off) + ")" + Archive) | |
| 355 | return (filename + ":(" + name + "+0x" + utohexstr(off) + ")" + archive) | |
| 350 | 356 | .str(); |
| 351 | 357 | } |
| 352 | 358 | |
| 353 | InputSection InputSection::Discarded(nullptr, 0, 0, 0, ArrayRef<uint8_t>(), ""); | |
| 359 | InputSection InputSection::discarded(nullptr, 0, 0, 0, ArrayRef<uint8_t>(), ""); | |
| 354 | 360 | |
| 355 | InputSection::InputSection(InputFile *F, uint64_t Flags, uint32_t Type, | |
| 356 | uint32_t Alignment, ArrayRef<uint8_t> Data, | |
| 357 | StringRef Name, Kind K) | |
| 358 | : InputSectionBase(F, Flags, Type, | |
| 359 | /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Alignment, Data, | |
| 360 | Name, K) {} | |
| 361 | InputSection::InputSection(InputFile *f, uint64_t flags, uint32_t type, | |
| 362 | uint32_t alignment, ArrayRef<uint8_t> data, | |
| 363 | StringRef name, Kind k) | |
| 364 | : InputSectionBase(f, flags, type, | |
| 365 | /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, alignment, data, | |
| 366 | name, k) {} | |
| 361 | 367 | |
| 362 | 368 | template <class ELFT> |
| 363 | InputSection::InputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header, | |
| 364 | StringRef Name) | |
| 365 | : InputSectionBase(F, Header, Name, InputSectionBase::Regular) {} | |
| 369 | InputSection::InputSection(ObjFile<ELFT> &f, const typename ELFT::Shdr &header, | |
| 370 | StringRef name) | |
| 371 | : InputSectionBase(f, header, name, InputSectionBase::Regular) {} | |
| 366 | 372 | |
| 367 | bool InputSection::classof(const SectionBase *S) { | |
| 368 | return S->kind() == SectionBase::Regular || | |
| 369 | S->kind() == SectionBase::Synthetic; | |
| 373 | bool InputSection::classof(const SectionBase *s) { | |
| 374 | return s->kind() == SectionBase::Regular || | |
| 375 | s->kind() == SectionBase::Synthetic; | |
| 370 | 376 | } |
| 371 | 377 | |
| 372 | 378 | OutputSection *InputSection::getParent() const { |
| 373 | return cast_or_null<OutputSection>(Parent); | |
| 379 | return cast_or_null<OutputSection>(parent); | |
| 374 | 380 | } |
| 375 | 381 | |
| 376 | 382 | // Copy SHT_GROUP section contents. Used only for the -r option. |
| 377 | template <class ELFT> void InputSection::copyShtGroup(uint8_t *Buf) { | |
| 383 | template <class ELFT> void InputSection::copyShtGroup(uint8_t *buf) { | |
| 378 | 384 | // ELFT::Word is the 32-bit integral type in the target endianness. |
| 379 | typedef typename ELFT::Word u32; | |
| 380 | ArrayRef<u32> From = getDataAs<u32>(); | |
| 381 | auto *To = reinterpret_cast<u32 *>(Buf); | |
| 385 | using u32 = typename ELFT::Word; | |
| 386 | ArrayRef<u32> from = getDataAs<u32>(); | |
| 387 | auto *to = reinterpret_cast<u32 *>(buf); | |
| 382 | 388 | |
| 383 | 389 | // The first entry is not a section number but a flag. |
| 384 | *To++ = From[0]; | |
| 390 | *to++ = from[0]; | |
| 385 | 391 | |
| 386 | 392 | // Adjust section numbers because section numbers in an input object |
| 387 | 393 | // files are different in the output. |
| 388 | ArrayRef<InputSectionBase *> Sections = File->getSections(); | |
| 389 | for (uint32_t Idx : From.slice(1)) | |
| 390 | *To++ = Sections[Idx]->getOutputSection()->SectionIndex; | |
| 394 | ArrayRef<InputSectionBase *> sections = file->getSections(); | |
| 395 | for (uint32_t idx : from.slice(1)) | |
| 396 | *to++ = sections[idx]->getOutputSection()->sectionIndex; | |
| 391 | 397 | } |
| 392 | 398 | |
| 393 | 399 | InputSectionBase *InputSection::getRelocatedSection() const { |
| 394 | if (!File || (Type != SHT_RELA && Type != SHT_REL)) | |
| 400 | if (!file || (type != SHT_RELA && type != SHT_REL)) | |
| 395 | 401 | return nullptr; |
| 396 | ArrayRef<InputSectionBase *> Sections = File->getSections(); | |
| 397 | return Sections[Info]; | |
| 402 | ArrayRef<InputSectionBase *> sections = file->getSections(); | |
| 403 | return sections[info]; | |
| 398 | 404 | } |
| 399 | 405 | |
| 400 | 406 | // This is used for -r and --emit-relocs. We can't use memcpy to copy |
| 401 | 407 | // relocations because we need to update symbol table offset and section index |
| 402 | 408 | // for each relocation. So we copy relocations one by one. |
| 403 | 409 | template <class ELFT, class RelTy> |
| 404 | void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { | |
| 405 | InputSectionBase *Sec = getRelocatedSection(); | |
| 410 | void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) { | |
| 411 | InputSectionBase *sec = getRelocatedSection(); | |
| 406 | 412 | |
| 407 | for (const RelTy &Rel : Rels) { | |
| 408 | RelType Type = Rel.getType(Config->IsMips64EL); | |
| 409 | Symbol &Sym = getFile<ELFT>()->getRelocTargetSym(Rel); | |
| 413 | for (const RelTy &rel : rels) { | |
| 414 | RelType type = rel.getType(config->isMips64EL); | |
| 415 | const ObjFile<ELFT> *file = getFile<ELFT>(); | |
| 416 | Symbol &sym = file->getRelocTargetSym(rel); | |
| 410 | 417 | |
| 411 | auto *P = reinterpret_cast<typename ELFT::Rela *>(Buf); | |
| 412 | Buf += sizeof(RelTy); | |
| 418 | auto *p = reinterpret_cast<typename ELFT::Rela *>(buf); | |
| 419 | buf += sizeof(RelTy); | |
| 413 | 420 | |
| 414 | 421 | if (RelTy::IsRela) |
| 415 | P->r_addend = getAddend<ELFT>(Rel); | |
| 422 | p->r_addend = getAddend<ELFT>(rel); | |
| 416 | 423 | |
| 417 | 424 | // Output section VA is zero for -r, so r_offset is an offset within the |
| 418 | 425 | // section, but for --emit-relocs it is an virtual address. |
| 419 | P->r_offset = Sec->getVA(Rel.r_offset); | |
| 420 | P->setSymbolAndType(In.SymTab->getSymbolIndex(&Sym), Type, | |
| 421 | Config->IsMips64EL); | |
| 426 | p->r_offset = sec->getVA(rel.r_offset); | |
| 427 | p->setSymbolAndType(in.symTab->getSymbolIndex(&sym), type, | |
| 428 | config->isMips64EL); | |
| 422 | 429 | |
| 423 | if (Sym.Type == STT_SECTION) { | |
| 430 | if (sym.type == STT_SECTION) { | |
| 424 | 431 | // We combine multiple section symbols into only one per |
| 425 | 432 | // section. This means we have to update the addend. That is |
| 426 | 433 | // trivial for Elf_Rela, but for Elf_Rel we have to write to the |
| ... | ... | @@ -429,25 +436,38 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { |
| 429 | 436 | // .eh_frame is horribly special and can reference discarded sections. To |
| 430 | 437 | // avoid having to parse and recreate .eh_frame, we just replace any |
| 431 | 438 | // relocation in it pointing to discarded sections with R_*_NONE, which |
| 432 | // hopefully creates a frame that is ignored at runtime. | |
| 433 | auto *D = dyn_cast<Defined>(&Sym); | |
| 434 | if (!D) { | |
| 435 | error("STT_SECTION symbol should be defined"); | |
| 439 | // hopefully creates a frame that is ignored at runtime. Also, don't warn | |
| 440 | // on .gcc_except_table and debug sections. | |
| 441 | // | |
| 442 | // See the comment in maybeReportUndefined for PPC64 .toc . | |
| 443 | auto *d = dyn_cast<Defined>(&sym); | |
| 444 | if (!d) { | |
| 445 | if (!sec->name.startswith(".debug") && | |
| 446 | !sec->name.startswith(".zdebug") && sec->name != ".eh_frame" && | |
| 447 | sec->name != ".gcc_except_table" && sec->name != ".toc") { | |
| 448 | uint32_t secIdx = cast<Undefined>(sym).discardedSecIdx; | |
| 449 | Elf_Shdr_Impl<ELFT> sec = | |
| 450 | CHECK(file->getObj().sections(), file)[secIdx]; | |
| 451 | warn("relocation refers to a discarded section: " + | |
| 452 | CHECK(file->getObj().getSectionName(&sec), file) + | |
| 453 | "\n>>> referenced by " + getObjMsg(p->r_offset)); | |
| 454 | } | |
| 455 | p->setSymbolAndType(0, 0, false); | |
| 436 | 456 | continue; |
| 437 | 457 | } |
| 438 | SectionBase *Section = D->Section->Repl; | |
| 439 | if (!Section->Live) { | |
| 440 | P->setSymbolAndType(0, 0, false); | |
| 458 | SectionBase *section = d->section->repl; | |
| 459 | if (!section->isLive()) { | |
| 460 | p->setSymbolAndType(0, 0, false); | |
| 441 | 461 | continue; |
| 442 | 462 | } |
| 443 | 463 | |
| 444 | int64_t Addend = getAddend<ELFT>(Rel); | |
| 445 | const uint8_t *BufLoc = Sec->data().begin() + Rel.r_offset; | |
| 464 | int64_t addend = getAddend<ELFT>(rel); | |
| 465 | const uint8_t *bufLoc = sec->data().begin() + rel.r_offset; | |
| 446 | 466 | if (!RelTy::IsRela) |
| 447 | Addend = Target->getImplicitAddend(BufLoc, Type); | |
| 467 | addend = target->getImplicitAddend(bufLoc, type); | |
| 448 | 468 | |
| 449 | if (Config->EMachine == EM_MIPS && Config->Relocatable && | |
| 450 | Target->getRelExpr(Type, Sym, BufLoc) == R_MIPS_GOTREL) { | |
| 469 | if (config->emachine == EM_MIPS && config->relocatable && | |
| 470 | target->getRelExpr(type, sym, bufLoc) == R_MIPS_GOTREL) { | |
| 451 | 471 | // Some MIPS relocations depend on "gp" value. By default, |
| 452 | 472 | // this value has 0x7ff0 offset from a .got section. But |
| 453 | 473 | // relocatable files produced by a complier or a linker |
| ... | ... | @@ -459,13 +479,13 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { |
| 459 | 479 | // individual "gp" values used by each input object file. |
| 460 | 480 | // As a workaround we add the "gp" value to the relocation |
| 461 | 481 | // addend and save it back to the file. |
| 462 | Addend += Sec->getFile<ELFT>()->MipsGp0; | |
| 482 | addend += sec->getFile<ELFT>()->mipsGp0; | |
| 463 | 483 | } |
| 464 | 484 | |
| 465 | 485 | if (RelTy::IsRela) |
| 466 | P->r_addend = Sym.getVA(Addend) - Section->getOutputSection()->Addr; | |
| 467 | else if (Config->Relocatable) | |
| 468 | Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset, Addend, &Sym}); | |
| 486 | p->r_addend = sym.getVA(addend) - section->getOutputSection()->addr; | |
| 487 | else if (config->relocatable && type != target->noneRel) | |
| 488 | sec->relocations.push_back({R_ABS, type, rel.r_offset, addend, &sym}); | |
| 469 | 489 | } |
| 470 | 490 | } |
| 471 | 491 | } |
| ... | ... | @@ -475,13 +495,13 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { |
| 475 | 495 | // this context is the address of the place P. A further special case is that |
| 476 | 496 | // branch relocations to an undefined weak reference resolve to the next |
| 477 | 497 | // instruction. |
| 478 | static uint32_t getARMUndefinedRelativeWeakVA(RelType Type, uint32_t A, | |
| 479 | uint32_t P) { | |
| 480 | switch (Type) { | |
| 498 | static uint32_t getARMUndefinedRelativeWeakVA(RelType type, uint32_t a, | |
| 499 | uint32_t p) { | |
| 500 | switch (type) { | |
| 481 | 501 | // Unresolved branch relocations to weak references resolve to next |
| 482 | 502 | // instruction, this will be either 2 or 4 bytes on from P. |
| 483 | 503 | case R_ARM_THM_JUMP11: |
| 484 | return P + 2 + A; | |
| 504 | return p + 2 + a; | |
| 485 | 505 | case R_ARM_CALL: |
| 486 | 506 | case R_ARM_JUMP24: |
| 487 | 507 | case R_ARM_PC24: |
| ... | ... | @@ -489,10 +509,10 @@ static uint32_t getARMUndefinedRelativeWeakVA(RelType Type, uint32_t A, |
| 489 | 509 | case R_ARM_PREL31: |
| 490 | 510 | case R_ARM_THM_JUMP19: |
| 491 | 511 | case R_ARM_THM_JUMP24: |
| 492 | return P + 4 + A; | |
| 512 | return p + 4 + a; | |
| 493 | 513 | case R_ARM_THM_CALL: |
| 494 | 514 | // We don't want an interworking BLX to ARM |
| 495 | return P + 5 + A; | |
| 515 | return p + 5 + a; | |
| 496 | 516 | // Unresolved non branch pc-relative relocations |
| 497 | 517 | // R_ARM_TARGET2 which can be resolved relatively is not present as it never |
| 498 | 518 | // targets a weak-reference. |
| ... | ... | @@ -501,29 +521,29 @@ static uint32_t getARMUndefinedRelativeWeakVA(RelType Type, uint32_t A, |
| 501 | 521 | case R_ARM_REL32: |
| 502 | 522 | case R_ARM_THM_MOVW_PREL_NC: |
| 503 | 523 | case R_ARM_THM_MOVT_PREL: |
| 504 | return P + A; | |
| 524 | return p + a; | |
| 505 | 525 | } |
| 506 | 526 | llvm_unreachable("ARM pc-relative relocation expected\n"); |
| 507 | 527 | } |
| 508 | 528 | |
| 509 | 529 | // The comment above getARMUndefinedRelativeWeakVA applies to this function. |
| 510 | static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A, | |
| 511 | uint64_t P) { | |
| 512 | switch (Type) { | |
| 530 | static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t type, uint64_t a, | |
| 531 | uint64_t p) { | |
| 532 | switch (type) { | |
| 513 | 533 | // Unresolved branch relocations to weak references resolve to next |
| 514 | 534 | // instruction, this is 4 bytes on from P. |
| 515 | 535 | case R_AARCH64_CALL26: |
| 516 | 536 | case R_AARCH64_CONDBR19: |
| 517 | 537 | case R_AARCH64_JUMP26: |
| 518 | 538 | case R_AARCH64_TSTBR14: |
| 519 | return P + 4 + A; | |
| 539 | return p + 4 + a; | |
| 520 | 540 | // Unresolved non branch pc-relative relocations |
| 521 | 541 | case R_AARCH64_PREL16: |
| 522 | 542 | case R_AARCH64_PREL32: |
| 523 | 543 | case R_AARCH64_PREL64: |
| 524 | 544 | case R_AARCH64_ADR_PREL_LO21: |
| 525 | 545 | case R_AARCH64_LD_PREL_LO19: |
| 526 | return P + A; | |
| 546 | return p + a; | |
| 527 | 547 | } |
| 528 | 548 | llvm_unreachable("AArch64 pc-relative relocation expected\n"); |
| 529 | 549 | } |
| ... | ... | @@ -535,11 +555,11 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A, |
| 535 | 555 | // The procedure call standard only defines a Read Write Position Independent |
| 536 | 556 | // RWPI variant so in practice we should expect the static base to be the base |
| 537 | 557 | // of the RW segment. |
| 538 | static uint64_t getARMStaticBase(const Symbol &Sym) { | |
| 539 | OutputSection *OS = Sym.getOutputSection(); | |
| 540 | if (!OS || !OS->PtLoad || !OS->PtLoad->FirstSec) | |
| 541 | fatal("SBREL relocation to " + Sym.getName() + " without static base"); | |
| 542 | return OS->PtLoad->FirstSec->Addr; | |
| 558 | static uint64_t getARMStaticBase(const Symbol &sym) { | |
| 559 | OutputSection *os = sym.getOutputSection(); | |
| 560 | if (!os || !os->ptLoad || !os->ptLoad->firstSec) | |
| 561 | fatal("SBREL relocation to " + sym.getName() + " without static base"); | |
| 562 | return os->ptLoad->firstSec->addr; | |
| 543 | 563 | } |
| 544 | 564 | |
| 545 | 565 | // For R_RISCV_PC_INDIRECT (R_RISCV_PCREL_LO12_{I,S}), the symbol actually |
| ... | ... | @@ -548,101 +568,115 @@ static uint64_t getARMStaticBase(const Symbol &Sym) { |
| 548 | 568 | // |
| 549 | 569 | // This function returns the R_RISCV_PCREL_HI20 relocation from |
| 550 | 570 | // R_RISCV_PCREL_LO12's symbol and addend. |
| 551 | static Relocation *getRISCVPCRelHi20(const Symbol *Sym, uint64_t Addend) { | |
| 552 | const Defined *D = cast<Defined>(Sym); | |
| 553 | InputSection *IS = cast<InputSection>(D->Section); | |
| 571 | static Relocation *getRISCVPCRelHi20(const Symbol *sym, uint64_t addend) { | |
| 572 | const Defined *d = cast<Defined>(sym); | |
| 573 | if (!d->section) { | |
| 574 | error("R_RISCV_PCREL_LO12 relocation points to an absolute symbol: " + | |
| 575 | sym->getName()); | |
| 576 | return nullptr; | |
| 577 | } | |
| 578 | InputSection *isec = cast<InputSection>(d->section); | |
| 554 | 579 | |
| 555 | if (Addend != 0) | |
| 580 | if (addend != 0) | |
| 556 | 581 | warn("Non-zero addend in R_RISCV_PCREL_LO12 relocation to " + |
| 557 | IS->getObjMsg(D->Value) + " is ignored"); | |
| 582 | isec->getObjMsg(d->value) + " is ignored"); | |
| 558 | 583 | |
| 559 | 584 | // Relocations are sorted by offset, so we can use std::equal_range to do |
| 560 | 585 | // binary search. |
| 561 | auto Range = std::equal_range(IS->Relocations.begin(), IS->Relocations.end(), | |
| 562 | D->Value, RelocationOffsetComparator{}); | |
| 563 | for (auto It = std::get<0>(Range); It != std::get<1>(Range); ++It) | |
| 564 | if (isRelExprOneOf<R_PC>(It->Expr)) | |
| 565 | return &*It; | |
| 566 | ||
| 567 | error("R_RISCV_PCREL_LO12 relocation points to " + IS->getObjMsg(D->Value) + | |
| 586 | Relocation r; | |
| 587 | r.offset = d->value; | |
| 588 | auto range = | |
| 589 | std::equal_range(isec->relocations.begin(), isec->relocations.end(), r, | |
| 590 | [](const Relocation &lhs, const Relocation &rhs) { | |
| 591 | return lhs.offset < rhs.offset; | |
| 592 | }); | |
| 593 | ||
| 594 | for (auto it = range.first; it != range.second; ++it) | |
| 595 | if (it->type == R_RISCV_PCREL_HI20 || it->type == R_RISCV_GOT_HI20 || | |
| 596 | it->type == R_RISCV_TLS_GD_HI20 || it->type == R_RISCV_TLS_GOT_HI20) | |
| 597 | return &*it; | |
| 598 | ||
| 599 | error("R_RISCV_PCREL_LO12 relocation points to " + isec->getObjMsg(d->value) + | |
| 568 | 600 | " without an associated R_RISCV_PCREL_HI20 relocation"); |
| 569 | 601 | return nullptr; |
| 570 | 602 | } |
| 571 | 603 | |
| 572 | 604 | // A TLS symbol's virtual address is relative to the TLS segment. Add a |
| 573 | 605 | // target-specific adjustment to produce a thread-pointer-relative offset. |
| 574 | static int64_t getTlsTpOffset() { | |
| 575 | switch (Config->EMachine) { | |
| 606 | static int64_t getTlsTpOffset(const Symbol &s) { | |
| 607 | // On targets that support TLSDESC, _TLS_MODULE_BASE_@tpoff = 0. | |
| 608 | if (&s == ElfSym::tlsModuleBase) | |
| 609 | return 0; | |
| 610 | ||
| 611 | switch (config->emachine) { | |
| 576 | 612 | case EM_ARM: |
| 577 | 613 | case EM_AARCH64: |
| 578 | 614 | // Variant 1. The thread pointer points to a TCB with a fixed 2-word size, |
| 579 | 615 | // followed by a variable amount of alignment padding, followed by the TLS |
| 580 | 616 | // segment. |
| 581 | // | |
| 582 | // NB: While the ARM/AArch64 ABI formally has a 2-word TCB size, lld | |
| 583 | // effectively increases the TCB size to 8 words for Android compatibility. | |
| 584 | // It accomplishes this by increasing the segment's alignment. | |
| 585 | return alignTo(Config->Wordsize * 2, Out::TlsPhdr->p_align); | |
| 617 | return s.getVA(0) + alignTo(config->wordsize * 2, Out::tlsPhdr->p_align); | |
| 586 | 618 | case EM_386: |
| 587 | 619 | case EM_X86_64: |
| 588 | 620 | // Variant 2. The TLS segment is located just before the thread pointer. |
| 589 | return -Out::TlsPhdr->p_memsz; | |
| 621 | return s.getVA(0) - alignTo(Out::tlsPhdr->p_memsz, Out::tlsPhdr->p_align); | |
| 622 | case EM_PPC: | |
| 590 | 623 | case EM_PPC64: |
| 591 | 624 | // The thread pointer points to a fixed offset from the start of the |
| 592 | 625 | // executable's TLS segment. An offset of 0x7000 allows a signed 16-bit |
| 593 | 626 | // offset to reach 0x1000 of TCB/thread-library data and 0xf000 of the |
| 594 | 627 | // program's TLS segment. |
| 595 | return -0x7000; | |
| 628 | return s.getVA(0) - 0x7000; | |
| 629 | case EM_RISCV: | |
| 630 | return s.getVA(0); | |
| 596 | 631 | default: |
| 597 | 632 | llvm_unreachable("unhandled Config->EMachine"); |
| 598 | 633 | } |
| 599 | 634 | } |
| 600 | 635 | |
| 601 | static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A, | |
| 602 | uint64_t P, const Symbol &Sym, RelExpr Expr) { | |
| 603 | switch (Expr) { | |
| 604 | case R_INVALID: | |
| 605 | return 0; | |
| 636 | static uint64_t getRelocTargetVA(const InputFile *file, RelType type, int64_t a, | |
| 637 | uint64_t p, const Symbol &sym, RelExpr expr) { | |
| 638 | switch (expr) { | |
| 606 | 639 | case R_ABS: |
| 640 | case R_DTPREL: | |
| 607 | 641 | case R_RELAX_TLS_LD_TO_LE_ABS: |
| 608 | 642 | case R_RELAX_GOT_PC_NOPIC: |
| 609 | return Sym.getVA(A); | |
| 643 | case R_RISCV_ADD: | |
| 644 | return sym.getVA(a); | |
| 610 | 645 | case R_ADDEND: |
| 611 | return A; | |
| 646 | return a; | |
| 612 | 647 | case R_ARM_SBREL: |
| 613 | return Sym.getVA(A) - getARMStaticBase(Sym); | |
| 648 | return sym.getVA(a) - getARMStaticBase(sym); | |
| 614 | 649 | case R_GOT: |
| 615 | case R_GOT_PLT: | |
| 616 | 650 | case R_RELAX_TLS_GD_TO_IE_ABS: |
| 617 | return Sym.getGotVA() + A; | |
| 651 | return sym.getGotVA() + a; | |
| 618 | 652 | case R_GOTONLY_PC: |
| 619 | return In.Got->getVA() + A - P; | |
| 620 | case R_GOTONLY_PC_FROM_END: | |
| 621 | return In.Got->getVA() + A - P + In.Got->getSize(); | |
| 653 | return in.got->getVA() + a - p; | |
| 654 | case R_GOTPLTONLY_PC: | |
| 655 | return in.gotPlt->getVA() + a - p; | |
| 622 | 656 | case R_GOTREL: |
| 623 | return Sym.getVA(A) - In.Got->getVA(); | |
| 624 | case R_GOTREL_FROM_END: | |
| 625 | return Sym.getVA(A) - In.Got->getVA() - In.Got->getSize(); | |
| 626 | case R_GOT_FROM_END: | |
| 627 | case R_RELAX_TLS_GD_TO_IE_END: | |
| 628 | return Sym.getGotOffset() + A - In.Got->getSize(); | |
| 657 | case R_PPC64_RELAX_TOC: | |
| 658 | return sym.getVA(a) - in.got->getVA(); | |
| 659 | case R_GOTPLTREL: | |
| 660 | return sym.getVA(a) - in.gotPlt->getVA(); | |
| 661 | case R_GOTPLT: | |
| 662 | case R_RELAX_TLS_GD_TO_IE_GOTPLT: | |
| 663 | return sym.getGotVA() + a - in.gotPlt->getVA(); | |
| 629 | 664 | case R_TLSLD_GOT_OFF: |
| 630 | 665 | case R_GOT_OFF: |
| 631 | 666 | case R_RELAX_TLS_GD_TO_IE_GOT_OFF: |
| 632 | return Sym.getGotOffset() + A; | |
| 667 | return sym.getGotOffset() + a; | |
| 633 | 668 | case R_AARCH64_GOT_PAGE_PC: |
| 634 | case R_AARCH64_GOT_PAGE_PC_PLT: | |
| 635 | 669 | case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC: |
| 636 | return getAArch64Page(Sym.getGotVA() + A) - getAArch64Page(P); | |
| 670 | return getAArch64Page(sym.getGotVA() + a) - getAArch64Page(p); | |
| 637 | 671 | case R_GOT_PC: |
| 638 | 672 | case R_RELAX_TLS_GD_TO_IE: |
| 639 | return Sym.getGotVA() + A - P; | |
| 673 | return sym.getGotVA() + a - p; | |
| 640 | 674 | case R_HEXAGON_GOT: |
| 641 | return Sym.getGotVA() - In.GotPlt->getVA(); | |
| 675 | return sym.getGotVA() - in.gotPlt->getVA(); | |
| 642 | 676 | case R_MIPS_GOTREL: |
| 643 | return Sym.getVA(A) - In.MipsGot->getGp(File); | |
| 677 | return sym.getVA(a) - in.mipsGot->getGp(file); | |
| 644 | 678 | case R_MIPS_GOT_GP: |
| 645 | return In.MipsGot->getGp(File) + A; | |
| 679 | return in.mipsGot->getGp(file) + a; | |
| 646 | 680 | case R_MIPS_GOT_GP_PC: { |
| 647 | 681 | // R_MIPS_LO16 expression has R_MIPS_GOT_GP_PC type iif the target |
| 648 | 682 | // is _gp_disp symbol. In that case we should use the following |
| ... | ... | @@ -651,73 +685,76 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A, |
| 651 | 685 | // microMIPS variants of these relocations use slightly different |
| 652 | 686 | // expressions: AHL + GP - P + 3 for %lo() and AHL + GP - P - 1 for %hi() |
| 653 | 687 | // to correctly handle less-sugnificant bit of the microMIPS symbol. |
| 654 | uint64_t V = In.MipsGot->getGp(File) + A - P; | |
| 655 | if (Type == R_MIPS_LO16 || Type == R_MICROMIPS_LO16) | |
| 656 | V += 4; | |
| 657 | if (Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_HI16) | |
| 658 | V -= 1; | |
| 659 | return V; | |
| 688 | uint64_t v = in.mipsGot->getGp(file) + a - p; | |
| 689 | if (type == R_MIPS_LO16 || type == R_MICROMIPS_LO16) | |
| 690 | v += 4; | |
| 691 | if (type == R_MICROMIPS_LO16 || type == R_MICROMIPS_HI16) | |
| 692 | v -= 1; | |
| 693 | return v; | |
| 660 | 694 | } |
| 661 | 695 | case R_MIPS_GOT_LOCAL_PAGE: |
| 662 | 696 | // If relocation against MIPS local symbol requires GOT entry, this entry |
| 663 | 697 | // should be initialized by 'page address'. This address is high 16-bits |
| 664 | 698 | // of sum the symbol's value and the addend. |
| 665 | return In.MipsGot->getVA() + In.MipsGot->getPageEntryOffset(File, Sym, A) - | |
| 666 | In.MipsGot->getGp(File); | |
| 699 | return in.mipsGot->getVA() + in.mipsGot->getPageEntryOffset(file, sym, a) - | |
| 700 | in.mipsGot->getGp(file); | |
| 667 | 701 | case R_MIPS_GOT_OFF: |
| 668 | 702 | case R_MIPS_GOT_OFF32: |
| 669 | 703 | // In case of MIPS if a GOT relocation has non-zero addend this addend |
| 670 | 704 | // should be applied to the GOT entry content not to the GOT entry offset. |
| 671 | 705 | // That is why we use separate expression type. |
| 672 | return In.MipsGot->getVA() + In.MipsGot->getSymEntryOffset(File, Sym, A) - | |
| 673 | In.MipsGot->getGp(File); | |
| 706 | return in.mipsGot->getVA() + in.mipsGot->getSymEntryOffset(file, sym, a) - | |
| 707 | in.mipsGot->getGp(file); | |
| 674 | 708 | case R_MIPS_TLSGD: |
| 675 | return In.MipsGot->getVA() + In.MipsGot->getGlobalDynOffset(File, Sym) - | |
| 676 | In.MipsGot->getGp(File); | |
| 709 | return in.mipsGot->getVA() + in.mipsGot->getGlobalDynOffset(file, sym) - | |
| 710 | in.mipsGot->getGp(file); | |
| 677 | 711 | case R_MIPS_TLSLD: |
| 678 | return In.MipsGot->getVA() + In.MipsGot->getTlsIndexOffset(File) - | |
| 679 | In.MipsGot->getGp(File); | |
| 712 | return in.mipsGot->getVA() + in.mipsGot->getTlsIndexOffset(file) - | |
| 713 | in.mipsGot->getGp(file); | |
| 680 | 714 | case R_AARCH64_PAGE_PC: { |
| 681 | uint64_t Val = Sym.isUndefWeak() ? P + A : Sym.getVA(A); | |
| 682 | return getAArch64Page(Val) - getAArch64Page(P); | |
| 683 | } | |
| 684 | case R_AARCH64_PLT_PAGE_PC: { | |
| 685 | uint64_t Val = Sym.isUndefWeak() ? P + A : Sym.getPltVA() + A; | |
| 686 | return getAArch64Page(Val) - getAArch64Page(P); | |
| 715 | uint64_t val = sym.isUndefWeak() ? p + a : sym.getVA(a); | |
| 716 | return getAArch64Page(val) - getAArch64Page(p); | |
| 687 | 717 | } |
| 688 | 718 | case R_RISCV_PC_INDIRECT: { |
| 689 | if (const Relocation *HiRel = getRISCVPCRelHi20(&Sym, A)) | |
| 690 | return getRelocTargetVA(File, HiRel->Type, HiRel->Addend, Sym.getVA(), | |
| 691 | *HiRel->Sym, HiRel->Expr); | |
| 719 | if (const Relocation *hiRel = getRISCVPCRelHi20(&sym, a)) | |
| 720 | return getRelocTargetVA(file, hiRel->type, hiRel->addend, sym.getVA(), | |
| 721 | *hiRel->sym, hiRel->expr); | |
| 692 | 722 | return 0; |
| 693 | 723 | } |
| 694 | 724 | case R_PC: { |
| 695 | uint64_t Dest; | |
| 696 | if (Sym.isUndefWeak()) { | |
| 725 | uint64_t dest; | |
| 726 | if (sym.isUndefWeak()) { | |
| 697 | 727 | // On ARM and AArch64 a branch to an undefined weak resolves to the |
| 698 | 728 | // next instruction, otherwise the place. |
| 699 | if (Config->EMachine == EM_ARM) | |
| 700 | Dest = getARMUndefinedRelativeWeakVA(Type, A, P); | |
| 701 | else if (Config->EMachine == EM_AARCH64) | |
| 702 | Dest = getAArch64UndefinedRelativeWeakVA(Type, A, P); | |
| 729 | if (config->emachine == EM_ARM) | |
| 730 | dest = getARMUndefinedRelativeWeakVA(type, a, p); | |
| 731 | else if (config->emachine == EM_AARCH64) | |
| 732 | dest = getAArch64UndefinedRelativeWeakVA(type, a, p); | |
| 733 | else if (config->emachine == EM_PPC) | |
| 734 | dest = p; | |
| 703 | 735 | else |
| 704 | Dest = Sym.getVA(A); | |
| 736 | dest = sym.getVA(a); | |
| 705 | 737 | } else { |
| 706 | Dest = Sym.getVA(A); | |
| 738 | dest = sym.getVA(a); | |
| 707 | 739 | } |
| 708 | return Dest - P; | |
| 740 | return dest - p; | |
| 709 | 741 | } |
| 710 | 742 | case R_PLT: |
| 711 | return Sym.getPltVA() + A; | |
| 743 | return sym.getPltVA() + a; | |
| 712 | 744 | case R_PLT_PC: |
| 713 | case R_PPC_CALL_PLT: | |
| 714 | return Sym.getPltVA() + A - P; | |
| 715 | case R_PPC_CALL: { | |
| 716 | uint64_t SymVA = Sym.getVA(A); | |
| 745 | case R_PPC64_CALL_PLT: | |
| 746 | return sym.getPltVA() + a - p; | |
| 747 | case R_PPC32_PLTREL: | |
| 748 | // R_PPC_PLTREL24 uses the addend (usually 0 or 0x8000) to indicate r30 | |
| 749 | // stores _GLOBAL_OFFSET_TABLE_ or .got2+0x8000. The addend is ignored for | |
| 750 | // target VA compuation. | |
| 751 | return sym.getPltVA() - p; | |
| 752 | case R_PPC64_CALL: { | |
| 753 | uint64_t symVA = sym.getVA(a); | |
| 717 | 754 | // If we have an undefined weak symbol, we might get here with a symbol |
| 718 | 755 | // address of zero. That could overflow, but the code must be unreachable, |
| 719 | 756 | // so don't bother doing anything at all. |
| 720 | if (!SymVA) | |
| 757 | if (!symVA) | |
| 721 | 758 | return 0; |
| 722 | 759 | |
| 723 | 760 | // PPC64 V2 ABI describes two entry points to a function. The global entry |
| ... | ... | @@ -726,46 +763,49 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A, |
| 726 | 763 | // the callee. For local calls the caller and callee share the same |
| 727 | 764 | // TOC base and so the TOC pointer initialization code should be skipped by |
| 728 | 765 | // branching to the local entry point. |
| 729 | return SymVA - P + getPPC64GlobalEntryToLocalEntryOffset(Sym.StOther); | |
| 766 | return symVA - p + getPPC64GlobalEntryToLocalEntryOffset(sym.stOther); | |
| 730 | 767 | } |
| 731 | case R_PPC_TOC: | |
| 732 | return getPPC64TocBase() + A; | |
| 768 | case R_PPC64_TOCBASE: | |
| 769 | return getPPC64TocBase() + a; | |
| 733 | 770 | case R_RELAX_GOT_PC: |
| 734 | return Sym.getVA(A) - P; | |
| 771 | return sym.getVA(a) - p; | |
| 735 | 772 | case R_RELAX_TLS_GD_TO_LE: |
| 736 | 773 | case R_RELAX_TLS_IE_TO_LE: |
| 737 | 774 | case R_RELAX_TLS_LD_TO_LE: |
| 738 | 775 | case R_TLS: |
| 739 | // A weak undefined TLS symbol resolves to the base of the TLS | |
| 740 | // block, i.e. gets a value of zero. If we pass --gc-sections to | |
| 741 | // lld and .tbss is not referenced, it gets reclaimed and we don't | |
| 742 | // create a TLS program header. Therefore, we resolve this | |
| 743 | // statically to zero. | |
| 744 | if (Sym.isTls() && Sym.isUndefWeak()) | |
| 745 | return 0; | |
| 746 | return Sym.getVA(A) + getTlsTpOffset(); | |
| 776 | // It is not very clear what to return if the symbol is undefined. With | |
| 777 | // --noinhibit-exec, even a non-weak undefined reference may reach here. | |
| 778 | // Just return A, which matches R_ABS, and the behavior of some dynamic | |
| 779 | // loaders. | |
| 780 | if (sym.isUndefined()) | |
| 781 | return a; | |
| 782 | return getTlsTpOffset(sym) + a; | |
| 747 | 783 | case R_RELAX_TLS_GD_TO_LE_NEG: |
| 748 | 784 | case R_NEG_TLS: |
| 749 | return Out::TlsPhdr->p_memsz - Sym.getVA(A); | |
| 785 | if (sym.isUndefined()) | |
| 786 | return a; | |
| 787 | return -getTlsTpOffset(sym) + a; | |
| 750 | 788 | case R_SIZE: |
| 751 | return Sym.getSize() + A; | |
| 789 | return sym.getSize() + a; | |
| 752 | 790 | case R_TLSDESC: |
| 753 | return In.Got->getGlobalDynAddr(Sym) + A; | |
| 791 | return in.got->getGlobalDynAddr(sym) + a; | |
| 792 | case R_TLSDESC_PC: | |
| 793 | return in.got->getGlobalDynAddr(sym) + a - p; | |
| 754 | 794 | case R_AARCH64_TLSDESC_PAGE: |
| 755 | return getAArch64Page(In.Got->getGlobalDynAddr(Sym) + A) - | |
| 756 | getAArch64Page(P); | |
| 795 | return getAArch64Page(in.got->getGlobalDynAddr(sym) + a) - | |
| 796 | getAArch64Page(p); | |
| 757 | 797 | case R_TLSGD_GOT: |
| 758 | return In.Got->getGlobalDynOffset(Sym) + A; | |
| 759 | case R_TLSGD_GOT_FROM_END: | |
| 760 | return In.Got->getGlobalDynOffset(Sym) + A - In.Got->getSize(); | |
| 798 | return in.got->getGlobalDynOffset(sym) + a; | |
| 799 | case R_TLSGD_GOTPLT: | |
| 800 | return in.got->getVA() + in.got->getGlobalDynOffset(sym) + a - in.gotPlt->getVA(); | |
| 761 | 801 | case R_TLSGD_PC: |
| 762 | return In.Got->getGlobalDynAddr(Sym) + A - P; | |
| 763 | case R_TLSLD_GOT_FROM_END: | |
| 764 | return In.Got->getTlsIndexOff() + A - In.Got->getSize(); | |
| 802 | return in.got->getGlobalDynAddr(sym) + a - p; | |
| 803 | case R_TLSLD_GOTPLT: | |
| 804 | return in.got->getVA() + in.got->getTlsIndexOff() + a - in.gotPlt->getVA(); | |
| 765 | 805 | case R_TLSLD_GOT: |
| 766 | return In.Got->getTlsIndexOff() + A; | |
| 806 | return in.got->getTlsIndexOff() + a; | |
| 767 | 807 | case R_TLSLD_PC: |
| 768 | return In.Got->getTlsIndexVA() + A - P; | |
| 808 | return in.got->getTlsIndexVA() + a - p; | |
| 769 | 809 | default: |
| 770 | 810 | llvm_unreachable("invalid expression"); |
| 771 | 811 | } |
| ... | ... | @@ -779,36 +819,36 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A, |
| 779 | 819 | // So, we handle relocations for non-alloc sections directly in this |
| 780 | 820 | // function as a performance optimization. |
| 781 | 821 | template <class ELFT, class RelTy> |
| 782 | void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) { | |
| 783 | const unsigned Bits = sizeof(typename ELFT::uint) * 8; | |
| 822 | void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) { | |
| 823 | const unsigned bits = sizeof(typename ELFT::uint) * 8; | |
| 784 | 824 | |
| 785 | for (const RelTy &Rel : Rels) { | |
| 786 | RelType Type = Rel.getType(Config->IsMips64EL); | |
| 825 | for (const RelTy &rel : rels) { | |
| 826 | RelType type = rel.getType(config->isMips64EL); | |
| 787 | 827 | |
| 788 | 828 | // GCC 8.0 or earlier have a bug that they emit R_386_GOTPC relocations |
| 789 | 829 | // against _GLOBAL_OFFSET_TABLE_ for .debug_info. The bug has been fixed |
| 790 | 830 | // in 2017 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82630), but we |
| 791 | 831 | // need to keep this bug-compatible code for a while. |
| 792 | if (Config->EMachine == EM_386 && Type == R_386_GOTPC) | |
| 832 | if (config->emachine == EM_386 && type == R_386_GOTPC) | |
| 793 | 833 | continue; |
| 794 | 834 | |
| 795 | uint64_t Offset = getOffset(Rel.r_offset); | |
| 796 | uint8_t *BufLoc = Buf + Offset; | |
| 797 | int64_t Addend = getAddend<ELFT>(Rel); | |
| 835 | uint64_t offset = getOffset(rel.r_offset); | |
| 836 | uint8_t *bufLoc = buf + offset; | |
| 837 | int64_t addend = getAddend<ELFT>(rel); | |
| 798 | 838 | if (!RelTy::IsRela) |
| 799 | Addend += Target->getImplicitAddend(BufLoc, Type); | |
| 839 | addend += target->getImplicitAddend(bufLoc, type); | |
| 800 | 840 | |
| 801 | Symbol &Sym = getFile<ELFT>()->getRelocTargetSym(Rel); | |
| 802 | RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc); | |
| 803 | if (Expr == R_NONE) | |
| 841 | Symbol &sym = getFile<ELFT>()->getRelocTargetSym(rel); | |
| 842 | RelExpr expr = target->getRelExpr(type, sym, bufLoc); | |
| 843 | if (expr == R_NONE) | |
| 804 | 844 | continue; |
| 805 | 845 | |
| 806 | if (Expr != R_ABS) { | |
| 807 | std::string Msg = getLocation<ELFT>(Offset) + | |
| 808 | ": has non-ABS relocation " + toString(Type) + | |
| 809 | " against symbol '" + toString(Sym) + "'"; | |
| 810 | if (Expr != R_PC) { | |
| 811 | error(Msg); | |
| 846 | if (expr != R_ABS && expr != R_DTPREL && expr != R_RISCV_ADD) { | |
| 847 | std::string msg = getLocation<ELFT>(offset) + | |
| 848 | ": has non-ABS relocation " + toString(type) + | |
| 849 | " against symbol '" + toString(sym) + "'"; | |
| 850 | if (expr != R_PC) { | |
| 851 | error(msg); | |
| 812 | 852 | return; |
| 813 | 853 | } |
| 814 | 854 | |
| ... | ... | @@ -819,16 +859,16 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) { |
| 819 | 859 | // relocations without any errors and relocate them as if they were at |
| 820 | 860 | // address 0. For bug-compatibilty, we accept them with warnings. We |
| 821 | 861 | // know Steel Bank Common Lisp as of 2018 have this bug. |
| 822 | warn(Msg); | |
| 823 | Target->relocateOne(BufLoc, Type, | |
| 824 | SignExtend64<Bits>(Sym.getVA(Addend - Offset))); | |
| 862 | warn(msg); | |
| 863 | target->relocateOne(bufLoc, type, | |
| 864 | SignExtend64<bits>(sym.getVA(addend - offset))); | |
| 825 | 865 | continue; |
| 826 | 866 | } |
| 827 | 867 | |
| 828 | if (Sym.isTls() && !Out::TlsPhdr) | |
| 829 | Target->relocateOne(BufLoc, Type, 0); | |
| 868 | if (sym.isTls() && !Out::tlsPhdr) | |
| 869 | target->relocateOne(bufLoc, type, 0); | |
| 830 | 870 | else |
| 831 | Target->relocateOne(BufLoc, Type, SignExtend64<Bits>(Sym.getVA(Addend))); | |
| 871 | target->relocateOne(bufLoc, type, SignExtend64<bits>(sym.getVA(addend))); | |
| 832 | 872 | } |
| 833 | 873 | } |
| 834 | 874 | |
| ... | ... | @@ -837,96 +877,100 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) { |
| 837 | 877 | // relocations aimed to update addends. They are handled in relocateAlloc() |
| 838 | 878 | // for allocatable sections, and this function does the same for |
| 839 | 879 | // non-allocatable sections, such as sections with debug information. |
| 840 | static void relocateNonAllocForRelocatable(InputSection *Sec, uint8_t *Buf) { | |
| 841 | const unsigned Bits = Config->Is64 ? 64 : 32; | |
| 880 | static void relocateNonAllocForRelocatable(InputSection *sec, uint8_t *buf) { | |
| 881 | const unsigned bits = config->is64 ? 64 : 32; | |
| 842 | 882 | |
| 843 | for (const Relocation &Rel : Sec->Relocations) { | |
| 883 | for (const Relocation &rel : sec->relocations) { | |
| 844 | 884 | // InputSection::copyRelocations() adds only R_ABS relocations. |
| 845 | assert(Rel.Expr == R_ABS); | |
| 846 | uint8_t *BufLoc = Buf + Rel.Offset + Sec->OutSecOff; | |
| 847 | uint64_t TargetVA = SignExtend64(Rel.Sym->getVA(Rel.Addend), Bits); | |
| 848 | Target->relocateOne(BufLoc, Rel.Type, TargetVA); | |
| 885 | assert(rel.expr == R_ABS); | |
| 886 | uint8_t *bufLoc = buf + rel.offset + sec->outSecOff; | |
| 887 | uint64_t targetVA = SignExtend64(rel.sym->getVA(rel.addend), bits); | |
| 888 | target->relocateOne(bufLoc, rel.type, targetVA); | |
| 849 | 889 | } |
| 850 | 890 | } |
| 851 | 891 | |
| 852 | 892 | template <class ELFT> |
| 853 | void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) { | |
| 854 | if (Flags & SHF_EXECINSTR) | |
| 855 | adjustSplitStackFunctionPrologues<ELFT>(Buf, BufEnd); | |
| 893 | void InputSectionBase::relocate(uint8_t *buf, uint8_t *bufEnd) { | |
| 894 | if (flags & SHF_EXECINSTR) | |
| 895 | adjustSplitStackFunctionPrologues<ELFT>(buf, bufEnd); | |
| 856 | 896 | |
| 857 | if (Flags & SHF_ALLOC) { | |
| 858 | relocateAlloc(Buf, BufEnd); | |
| 897 | if (flags & SHF_ALLOC) { | |
| 898 | relocateAlloc(buf, bufEnd); | |
| 859 | 899 | return; |
| 860 | 900 | } |
| 861 | 901 | |
| 862 | auto *Sec = cast<InputSection>(this); | |
| 863 | if (Config->Relocatable) | |
| 864 | relocateNonAllocForRelocatable(Sec, Buf); | |
| 865 | else if (Sec->AreRelocsRela) | |
| 866 | Sec->relocateNonAlloc<ELFT>(Buf, Sec->template relas<ELFT>()); | |
| 902 | auto *sec = cast<InputSection>(this); | |
| 903 | if (config->relocatable) | |
| 904 | relocateNonAllocForRelocatable(sec, buf); | |
| 905 | else if (sec->areRelocsRela) | |
| 906 | sec->relocateNonAlloc<ELFT>(buf, sec->template relas<ELFT>()); | |
| 867 | 907 | else |
| 868 | Sec->relocateNonAlloc<ELFT>(Buf, Sec->template rels<ELFT>()); | |
| 908 | sec->relocateNonAlloc<ELFT>(buf, sec->template rels<ELFT>()); | |
| 869 | 909 | } |
| 870 | 910 | |
| 871 | void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { | |
| 872 | assert(Flags & SHF_ALLOC); | |
| 873 | const unsigned Bits = Config->Wordsize * 8; | |
| 911 | void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) { | |
| 912 | assert(flags & SHF_ALLOC); | |
| 913 | const unsigned bits = config->wordsize * 8; | |
| 874 | 914 | |
| 875 | for (const Relocation &Rel : Relocations) { | |
| 876 | uint64_t Offset = Rel.Offset; | |
| 877 | if (auto *Sec = dyn_cast<InputSection>(this)) | |
| 878 | Offset += Sec->OutSecOff; | |
| 879 | uint8_t *BufLoc = Buf + Offset; | |
| 880 | RelType Type = Rel.Type; | |
| 915 | for (const Relocation &rel : relocations) { | |
| 916 | uint64_t offset = rel.offset; | |
| 917 | if (auto *sec = dyn_cast<InputSection>(this)) | |
| 918 | offset += sec->outSecOff; | |
| 919 | uint8_t *bufLoc = buf + offset; | |
| 920 | RelType type = rel.type; | |
| 881 | 921 | |
| 882 | uint64_t AddrLoc = getOutputSection()->Addr + Offset; | |
| 883 | RelExpr Expr = Rel.Expr; | |
| 884 | uint64_t TargetVA = SignExtend64( | |
| 885 | getRelocTargetVA(File, Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), | |
| 886 | Bits); | |
| 922 | uint64_t addrLoc = getOutputSection()->addr + offset; | |
| 923 | RelExpr expr = rel.expr; | |
| 924 | uint64_t targetVA = SignExtend64( | |
| 925 | getRelocTargetVA(file, type, rel.addend, addrLoc, *rel.sym, expr), | |
| 926 | bits); | |
| 887 | 927 | |
| 888 | switch (Expr) { | |
| 928 | switch (expr) { | |
| 889 | 929 | case R_RELAX_GOT_PC: |
| 890 | 930 | case R_RELAX_GOT_PC_NOPIC: |
| 891 | Target->relaxGot(BufLoc, TargetVA); | |
| 931 | target->relaxGot(bufLoc, type, targetVA); | |
| 932 | break; | |
| 933 | case R_PPC64_RELAX_TOC: | |
| 934 | if (!tryRelaxPPC64TocIndirection(type, rel, bufLoc)) | |
| 935 | target->relocateOne(bufLoc, type, targetVA); | |
| 892 | 936 | break; |
| 893 | 937 | case R_RELAX_TLS_IE_TO_LE: |
| 894 | Target->relaxTlsIeToLe(BufLoc, Type, TargetVA); | |
| 938 | target->relaxTlsIeToLe(bufLoc, type, targetVA); | |
| 895 | 939 | break; |
| 896 | 940 | case R_RELAX_TLS_LD_TO_LE: |
| 897 | 941 | case R_RELAX_TLS_LD_TO_LE_ABS: |
| 898 | Target->relaxTlsLdToLe(BufLoc, Type, TargetVA); | |
| 942 | target->relaxTlsLdToLe(bufLoc, type, targetVA); | |
| 899 | 943 | break; |
| 900 | 944 | case R_RELAX_TLS_GD_TO_LE: |
| 901 | 945 | case R_RELAX_TLS_GD_TO_LE_NEG: |
| 902 | Target->relaxTlsGdToLe(BufLoc, Type, TargetVA); | |
| 946 | target->relaxTlsGdToLe(bufLoc, type, targetVA); | |
| 903 | 947 | break; |
| 904 | 948 | case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC: |
| 905 | 949 | case R_RELAX_TLS_GD_TO_IE: |
| 906 | 950 | case R_RELAX_TLS_GD_TO_IE_ABS: |
| 907 | 951 | case R_RELAX_TLS_GD_TO_IE_GOT_OFF: |
| 908 | case R_RELAX_TLS_GD_TO_IE_END: | |
| 909 | Target->relaxTlsGdToIe(BufLoc, Type, TargetVA); | |
| 952 | case R_RELAX_TLS_GD_TO_IE_GOTPLT: | |
| 953 | target->relaxTlsGdToIe(bufLoc, type, targetVA); | |
| 910 | 954 | break; |
| 911 | case R_PPC_CALL: | |
| 955 | case R_PPC64_CALL: | |
| 912 | 956 | // If this is a call to __tls_get_addr, it may be part of a TLS |
| 913 | 957 | // sequence that has been relaxed and turned into a nop. In this |
| 914 | 958 | // case, we don't want to handle it as a call. |
| 915 | if (read32(BufLoc) == 0x60000000) // nop | |
| 959 | if (read32(bufLoc) == 0x60000000) // nop | |
| 916 | 960 | break; |
| 917 | 961 | |
| 918 | 962 | // Patch a nop (0x60000000) to a ld. |
| 919 | if (Rel.Sym->NeedsTocRestore) { | |
| 920 | if (BufLoc + 8 > BufEnd || read32(BufLoc + 4) != 0x60000000) { | |
| 921 | error(getErrorLocation(BufLoc) + "call lacks nop, can't restore toc"); | |
| 963 | if (rel.sym->needsTocRestore) { | |
| 964 | if (bufLoc + 8 > bufEnd || read32(bufLoc + 4) != 0x60000000) { | |
| 965 | error(getErrorLocation(bufLoc) + "call lacks nop, can't restore toc"); | |
| 922 | 966 | break; |
| 923 | 967 | } |
| 924 | write32(BufLoc + 4, 0xe8410018); // ld %r2, 24(%r1) | |
| 968 | write32(bufLoc + 4, 0xe8410018); // ld %r2, 24(%r1) | |
| 925 | 969 | } |
| 926 | Target->relocateOne(BufLoc, Type, TargetVA); | |
| 970 | target->relocateOne(bufLoc, type, targetVA); | |
| 927 | 971 | break; |
| 928 | 972 | default: |
| 929 | Target->relocateOne(BufLoc, Type, TargetVA); | |
| 973 | target->relocateOne(bufLoc, type, targetVA); | |
| 930 | 974 | break; |
| 931 | 975 | } |
| 932 | 976 | } |
| ... | ... | @@ -935,44 +979,44 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { |
| 935 | 979 | // For each function-defining prologue, find any calls to __morestack, |
| 936 | 980 | // and replace them with calls to __morestack_non_split. |
| 937 | 981 | static void switchMorestackCallsToMorestackNonSplit( |
| 938 | DenseSet<Defined *> &Prologues, std::vector<Relocation *> &MorestackCalls) { | |
| 982 | DenseSet<Defined *> &prologues, std::vector<Relocation *> &morestackCalls) { | |
| 939 | 983 | |
| 940 | 984 | // If the target adjusted a function's prologue, all calls to |
| 941 | 985 | // __morestack inside that function should be switched to |
| 942 | 986 | // __morestack_non_split. |
| 943 | Symbol *MoreStackNonSplit = Symtab->find("__morestack_non_split"); | |
| 944 | if (!MoreStackNonSplit) { | |
| 987 | Symbol *moreStackNonSplit = symtab->find("__morestack_non_split"); | |
| 988 | if (!moreStackNonSplit) { | |
| 945 | 989 | error("Mixing split-stack objects requires a definition of " |
| 946 | 990 | "__morestack_non_split"); |
| 947 | 991 | return; |
| 948 | 992 | } |
| 949 | 993 | |
| 950 | 994 | // Sort both collections to compare addresses efficiently. |
| 951 | llvm::sort(MorestackCalls, [](const Relocation *L, const Relocation *R) { | |
| 952 | return L->Offset < R->Offset; | |
| 995 | llvm::sort(morestackCalls, [](const Relocation *l, const Relocation *r) { | |
| 996 | return l->offset < r->offset; | |
| 953 | 997 | }); |
| 954 | std::vector<Defined *> Functions(Prologues.begin(), Prologues.end()); | |
| 955 | llvm::sort(Functions, [](const Defined *L, const Defined *R) { | |
| 956 | return L->Value < R->Value; | |
| 998 | std::vector<Defined *> functions(prologues.begin(), prologues.end()); | |
| 999 | llvm::sort(functions, [](const Defined *l, const Defined *r) { | |
| 1000 | return l->value < r->value; | |
| 957 | 1001 | }); |
| 958 | 1002 | |
| 959 | auto It = MorestackCalls.begin(); | |
| 960 | for (Defined *F : Functions) { | |
| 1003 | auto it = morestackCalls.begin(); | |
| 1004 | for (Defined *f : functions) { | |
| 961 | 1005 | // Find the first call to __morestack within the function. |
| 962 | while (It != MorestackCalls.end() && (*It)->Offset < F->Value) | |
| 963 | ++It; | |
| 1006 | while (it != morestackCalls.end() && (*it)->offset < f->value) | |
| 1007 | ++it; | |
| 964 | 1008 | // Adjust all calls inside the function. |
| 965 | while (It != MorestackCalls.end() && (*It)->Offset < F->Value + F->Size) { | |
| 966 | (*It)->Sym = MoreStackNonSplit; | |
| 967 | ++It; | |
| 1009 | while (it != morestackCalls.end() && (*it)->offset < f->value + f->size) { | |
| 1010 | (*it)->sym = moreStackNonSplit; | |
| 1011 | ++it; | |
| 968 | 1012 | } |
| 969 | 1013 | } |
| 970 | 1014 | } |
| 971 | 1015 | |
| 972 | static bool enclosingPrologueAttempted(uint64_t Offset, | |
| 973 | const DenseSet<Defined *> &Prologues) { | |
| 974 | for (Defined *F : Prologues) | |
| 975 | if (F->Value <= Offset && Offset < F->Value + F->Size) | |
| 1016 | static bool enclosingPrologueAttempted(uint64_t offset, | |
| 1017 | const DenseSet<Defined *> &prologues) { | |
| 1018 | for (Defined *f : prologues) | |
| 1019 | if (f->value <= offset && offset < f->value + f->size) | |
| 976 | 1020 | return true; |
| 977 | 1021 | return false; |
| 978 | 1022 | } |
| ... | ... | @@ -982,30 +1026,30 @@ static bool enclosingPrologueAttempted(uint64_t Offset, |
| 982 | 1026 | // adjusted to ensure that the called function will have enough stack |
| 983 | 1027 | // available. Find those functions, and adjust their prologues. |
| 984 | 1028 | template <class ELFT> |
| 985 | void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf, | |
| 986 | uint8_t *End) { | |
| 987 | if (!getFile<ELFT>()->SplitStack) | |
| 1029 | void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *buf, | |
| 1030 | uint8_t *end) { | |
| 1031 | if (!getFile<ELFT>()->splitStack) | |
| 988 | 1032 | return; |
| 989 | DenseSet<Defined *> Prologues; | |
| 990 | std::vector<Relocation *> MorestackCalls; | |
| 1033 | DenseSet<Defined *> prologues; | |
| 1034 | std::vector<Relocation *> morestackCalls; | |
| 991 | 1035 | |
| 992 | for (Relocation &Rel : Relocations) { | |
| 1036 | for (Relocation &rel : relocations) { | |
| 993 | 1037 | // Local symbols can't possibly be cross-calls, and should have been |
| 994 | 1038 | // resolved long before this line. |
| 995 | if (Rel.Sym->isLocal()) | |
| 1039 | if (rel.sym->isLocal()) | |
| 996 | 1040 | continue; |
| 997 | 1041 | |
| 998 | 1042 | // Ignore calls into the split-stack api. |
| 999 | if (Rel.Sym->getName().startswith("__morestack")) { | |
| 1000 | if (Rel.Sym->getName().equals("__morestack")) | |
| 1001 | MorestackCalls.push_back(&Rel); | |
| 1043 | if (rel.sym->getName().startswith("__morestack")) { | |
| 1044 | if (rel.sym->getName().equals("__morestack")) | |
| 1045 | morestackCalls.push_back(&rel); | |
| 1002 | 1046 | continue; |
| 1003 | 1047 | } |
| 1004 | 1048 | |
| 1005 | 1049 | // A relocation to non-function isn't relevant. Sometimes |
| 1006 | 1050 | // __morestack is not marked as a function, so this check comes |
| 1007 | 1051 | // after the name check. |
| 1008 | if (Rel.Sym->Type != STT_FUNC) | |
| 1052 | if (rel.sym->type != STT_FUNC) | |
| 1009 | 1053 | continue; |
| 1010 | 1054 | |
| 1011 | 1055 | // If the callee's-file was compiled with split stack, nothing to do. In |
| ... | ... | @@ -1013,106 +1057,117 @@ void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf, |
| 1013 | 1057 | // being produced". So an "undefined" symbol might be provided by a shared |
| 1014 | 1058 | // library. It is not possible to tell how such symbols were compiled, so be |
| 1015 | 1059 | // conservative. |
| 1016 | if (Defined *D = dyn_cast<Defined>(Rel.Sym)) | |
| 1017 | if (InputSection *IS = cast_or_null<InputSection>(D->Section)) | |
| 1018 | if (!IS || !IS->getFile<ELFT>() || IS->getFile<ELFT>()->SplitStack) | |
| 1060 | if (Defined *d = dyn_cast<Defined>(rel.sym)) | |
| 1061 | if (InputSection *isec = cast_or_null<InputSection>(d->section)) | |
| 1062 | if (!isec || !isec->getFile<ELFT>() || isec->getFile<ELFT>()->splitStack) | |
| 1019 | 1063 | continue; |
| 1020 | 1064 | |
| 1021 | if (enclosingPrologueAttempted(Rel.Offset, Prologues)) | |
| 1065 | if (enclosingPrologueAttempted(rel.offset, prologues)) | |
| 1022 | 1066 | continue; |
| 1023 | 1067 | |
| 1024 | if (Defined *F = getEnclosingFunction<ELFT>(Rel.Offset)) { | |
| 1025 | Prologues.insert(F); | |
| 1026 | if (Target->adjustPrologueForCrossSplitStack(Buf + getOffset(F->Value), | |
| 1027 | End, F->StOther)) | |
| 1068 | if (Defined *f = getEnclosingFunction<ELFT>(rel.offset)) { | |
| 1069 | prologues.insert(f); | |
| 1070 | if (target->adjustPrologueForCrossSplitStack(buf + getOffset(f->value), | |
| 1071 | end, f->stOther)) | |
| 1028 | 1072 | continue; |
| 1029 | if (!getFile<ELFT>()->SomeNoSplitStack) | |
| 1030 | error(lld::toString(this) + ": " + F->getName() + | |
| 1031 | " (with -fsplit-stack) calls " + Rel.Sym->getName() + | |
| 1073 | if (!getFile<ELFT>()->someNoSplitStack) | |
| 1074 | error(lld::toString(this) + ": " + f->getName() + | |
| 1075 | " (with -fsplit-stack) calls " + rel.sym->getName() + | |
| 1032 | 1076 | " (without -fsplit-stack), but couldn't adjust its prologue"); |
| 1033 | 1077 | } |
| 1034 | 1078 | } |
| 1035 | 1079 | |
| 1036 | if (Target->NeedsMoreStackNonSplit) | |
| 1037 | switchMorestackCallsToMorestackNonSplit(Prologues, MorestackCalls); | |
| 1080 | if (target->needsMoreStackNonSplit) | |
| 1081 | switchMorestackCallsToMorestackNonSplit(prologues, morestackCalls); | |
| 1038 | 1082 | } |
| 1039 | 1083 | |
| 1040 | template <class ELFT> void InputSection::writeTo(uint8_t *Buf) { | |
| 1041 | if (Type == SHT_NOBITS) | |
| 1084 | template <class ELFT> void InputSection::writeTo(uint8_t *buf) { | |
| 1085 | if (type == SHT_NOBITS) | |
| 1042 | 1086 | return; |
| 1043 | 1087 | |
| 1044 | if (auto *S = dyn_cast<SyntheticSection>(this)) { | |
| 1045 | S->writeTo(Buf + OutSecOff); | |
| 1088 | if (auto *s = dyn_cast<SyntheticSection>(this)) { | |
| 1089 | s->writeTo(buf + outSecOff); | |
| 1046 | 1090 | return; |
| 1047 | 1091 | } |
| 1048 | 1092 | |
| 1049 | 1093 | // If -r or --emit-relocs is given, then an InputSection |
| 1050 | 1094 | // may be a relocation section. |
| 1051 | if (Type == SHT_RELA) { | |
| 1052 | copyRelocations<ELFT>(Buf + OutSecOff, getDataAs<typename ELFT::Rela>()); | |
| 1095 | if (type == SHT_RELA) { | |
| 1096 | copyRelocations<ELFT>(buf + outSecOff, getDataAs<typename ELFT::Rela>()); | |
| 1053 | 1097 | return; |
| 1054 | 1098 | } |
| 1055 | if (Type == SHT_REL) { | |
| 1056 | copyRelocations<ELFT>(Buf + OutSecOff, getDataAs<typename ELFT::Rel>()); | |
| 1099 | if (type == SHT_REL) { | |
| 1100 | copyRelocations<ELFT>(buf + outSecOff, getDataAs<typename ELFT::Rel>()); | |
| 1057 | 1101 | return; |
| 1058 | 1102 | } |
| 1059 | 1103 | |
| 1060 | 1104 | // If -r is given, we may have a SHT_GROUP section. |
| 1061 | if (Type == SHT_GROUP) { | |
| 1062 | copyShtGroup<ELFT>(Buf + OutSecOff); | |
| 1105 | if (type == SHT_GROUP) { | |
| 1106 | copyShtGroup<ELFT>(buf + outSecOff); | |
| 1063 | 1107 | return; |
| 1064 | 1108 | } |
| 1065 | 1109 | |
| 1066 | 1110 | // If this is a compressed section, uncompress section contents directly |
| 1067 | 1111 | // to the buffer. |
| 1068 | if (UncompressedSize >= 0 && !UncompressedBuf) { | |
| 1069 | size_t Size = UncompressedSize; | |
| 1070 | if (Error E = zlib::uncompress(toStringRef(RawData), | |
| 1071 | (char *)(Buf + OutSecOff), Size)) | |
| 1112 | if (uncompressedSize >= 0) { | |
| 1113 | size_t size = uncompressedSize; | |
| 1114 | if (Error e = zlib::uncompress(toStringRef(rawData), | |
| 1115 | (char *)(buf + outSecOff), size)) | |
| 1072 | 1116 | fatal(toString(this) + |
| 1073 | ": uncompress failed: " + llvm::toString(std::move(E))); | |
| 1074 | uint8_t *BufEnd = Buf + OutSecOff + Size; | |
| 1075 | relocate<ELFT>(Buf, BufEnd); | |
| 1117 | ": uncompress failed: " + llvm::toString(std::move(e))); | |
| 1118 | uint8_t *bufEnd = buf + outSecOff + size; | |
| 1119 | relocate<ELFT>(buf, bufEnd); | |
| 1076 | 1120 | return; |
| 1077 | 1121 | } |
| 1078 | 1122 | |
| 1079 | 1123 | // Copy section contents from source object file to output file |
| 1080 | 1124 | // and then apply relocations. |
| 1081 | memcpy(Buf + OutSecOff, data().data(), data().size()); | |
| 1082 | uint8_t *BufEnd = Buf + OutSecOff + data().size(); | |
| 1083 | relocate<ELFT>(Buf, BufEnd); | |
| 1125 | memcpy(buf + outSecOff, data().data(), data().size()); | |
| 1126 | uint8_t *bufEnd = buf + outSecOff + data().size(); | |
| 1127 | relocate<ELFT>(buf, bufEnd); | |
| 1084 | 1128 | } |
| 1085 | 1129 | |
| 1086 | void InputSection::replace(InputSection *Other) { | |
| 1087 | Alignment = std::max(Alignment, Other->Alignment); | |
| 1088 | Other->Repl = Repl; | |
| 1089 | Other->Live = false; | |
| 1130 | void InputSection::replace(InputSection *other) { | |
| 1131 | alignment = std::max(alignment, other->alignment); | |
| 1132 | ||
| 1133 | // When a section is replaced with another section that was allocated to | |
| 1134 | // another partition, the replacement section (and its associated sections) | |
| 1135 | // need to be placed in the main partition so that both partitions will be | |
| 1136 | // able to access it. | |
| 1137 | if (partition != other->partition) { | |
| 1138 | partition = 1; | |
| 1139 | for (InputSection *isec : dependentSections) | |
| 1140 | isec->partition = 1; | |
| 1141 | } | |
| 1142 | ||
| 1143 | other->repl = repl; | |
| 1144 | other->markDead(); | |
| 1090 | 1145 | } |
| 1091 | 1146 | |
| 1092 | 1147 | template <class ELFT> |
| 1093 | EhInputSection::EhInputSection(ObjFile<ELFT> &F, | |
| 1094 | const typename ELFT::Shdr &Header, | |
| 1095 | StringRef Name) | |
| 1096 | : InputSectionBase(F, Header, Name, InputSectionBase::EHFrame) {} | |
| 1148 | EhInputSection::EhInputSection(ObjFile<ELFT> &f, | |
| 1149 | const typename ELFT::Shdr &header, | |
| 1150 | StringRef name) | |
| 1151 | : InputSectionBase(f, header, name, InputSectionBase::EHFrame) {} | |
| 1097 | 1152 | |
| 1098 | 1153 | SyntheticSection *EhInputSection::getParent() const { |
| 1099 | return cast_or_null<SyntheticSection>(Parent); | |
| 1154 | return cast_or_null<SyntheticSection>(parent); | |
| 1100 | 1155 | } |
| 1101 | 1156 | |
| 1102 | 1157 | // Returns the index of the first relocation that points to a region between |
| 1103 | 1158 | // Begin and Begin+Size. |
| 1104 | 1159 | template <class IntTy, class RelTy> |
| 1105 | static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels, | |
| 1106 | unsigned &RelocI) { | |
| 1160 | static unsigned getReloc(IntTy begin, IntTy size, const ArrayRef<RelTy> &rels, | |
| 1161 | unsigned &relocI) { | |
| 1107 | 1162 | // Start search from RelocI for fast access. That works because the |
| 1108 | 1163 | // relocations are sorted in .eh_frame. |
| 1109 | for (unsigned N = Rels.size(); RelocI < N; ++RelocI) { | |
| 1110 | const RelTy &Rel = Rels[RelocI]; | |
| 1111 | if (Rel.r_offset < Begin) | |
| 1164 | for (unsigned n = rels.size(); relocI < n; ++relocI) { | |
| 1165 | const RelTy &rel = rels[relocI]; | |
| 1166 | if (rel.r_offset < begin) | |
| 1112 | 1167 | continue; |
| 1113 | 1168 | |
| 1114 | if (Rel.r_offset < Begin + Size) | |
| 1115 | return RelocI; | |
| 1169 | if (rel.r_offset < begin + size) | |
| 1170 | return relocI; | |
| 1116 | 1171 | return -1; |
| 1117 | 1172 | } |
| 1118 | 1173 | return -1; |
| ... | ... | @@ -1121,84 +1176,84 @@ static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels, |
| 1121 | 1176 | // .eh_frame is a sequence of CIE or FDE records. |
| 1122 | 1177 | // This function splits an input section into records and returns them. |
| 1123 | 1178 | template <class ELFT> void EhInputSection::split() { |
| 1124 | if (AreRelocsRela) | |
| 1179 | if (areRelocsRela) | |
| 1125 | 1180 | split<ELFT>(relas<ELFT>()); |
| 1126 | 1181 | else |
| 1127 | 1182 | split<ELFT>(rels<ELFT>()); |
| 1128 | 1183 | } |
| 1129 | 1184 | |
| 1130 | 1185 | template <class ELFT, class RelTy> |
| 1131 | void EhInputSection::split(ArrayRef<RelTy> Rels) { | |
| 1132 | unsigned RelI = 0; | |
| 1133 | for (size_t Off = 0, End = data().size(); Off != End;) { | |
| 1134 | size_t Size = readEhRecordSize(this, Off); | |
| 1135 | Pieces.emplace_back(Off, this, Size, getReloc(Off, Size, Rels, RelI)); | |
| 1186 | void EhInputSection::split(ArrayRef<RelTy> rels) { | |
| 1187 | unsigned relI = 0; | |
| 1188 | for (size_t off = 0, end = data().size(); off != end;) { | |
| 1189 | size_t size = readEhRecordSize(this, off); | |
| 1190 | pieces.emplace_back(off, this, size, getReloc(off, size, rels, relI)); | |
| 1136 | 1191 | // The empty record is the end marker. |
| 1137 | if (Size == 4) | |
| 1192 | if (size == 4) | |
| 1138 | 1193 | break; |
| 1139 | Off += Size; | |
| 1194 | off += size; | |
| 1140 | 1195 | } |
| 1141 | 1196 | } |
| 1142 | 1197 | |
| 1143 | static size_t findNull(StringRef S, size_t EntSize) { | |
| 1198 | static size_t findNull(StringRef s, size_t entSize) { | |
| 1144 | 1199 | // Optimize the common case. |
| 1145 | if (EntSize == 1) | |
| 1146 | return S.find(0); | |
| 1200 | if (entSize == 1) | |
| 1201 | return s.find(0); | |
| 1147 | 1202 | |
| 1148 | for (unsigned I = 0, N = S.size(); I != N; I += EntSize) { | |
| 1149 | const char *B = S.begin() + I; | |
| 1150 | if (std::all_of(B, B + EntSize, [](char C) { return C == 0; })) | |
| 1151 | return I; | |
| 1203 | for (unsigned i = 0, n = s.size(); i != n; i += entSize) { | |
| 1204 | const char *b = s.begin() + i; | |
| 1205 | if (std::all_of(b, b + entSize, [](char c) { return c == 0; })) | |
| 1206 | return i; | |
| 1152 | 1207 | } |
| 1153 | 1208 | return StringRef::npos; |
| 1154 | 1209 | } |
| 1155 | 1210 | |
| 1156 | 1211 | SyntheticSection *MergeInputSection::getParent() const { |
| 1157 | return cast_or_null<SyntheticSection>(Parent); | |
| 1212 | return cast_or_null<SyntheticSection>(parent); | |
| 1158 | 1213 | } |
| 1159 | 1214 | |
| 1160 | 1215 | // Split SHF_STRINGS section. Such section is a sequence of |
| 1161 | 1216 | // null-terminated strings. |
| 1162 | void MergeInputSection::splitStrings(ArrayRef<uint8_t> Data, size_t EntSize) { | |
| 1163 | size_t Off = 0; | |
| 1164 | bool IsAlloc = Flags & SHF_ALLOC; | |
| 1165 | StringRef S = toStringRef(Data); | |
| 1166 | ||
| 1167 | while (!S.empty()) { | |
| 1168 | size_t End = findNull(S, EntSize); | |
| 1169 | if (End == StringRef::npos) | |
| 1217 | void MergeInputSection::splitStrings(ArrayRef<uint8_t> data, size_t entSize) { | |
| 1218 | size_t off = 0; | |
| 1219 | bool isAlloc = flags & SHF_ALLOC; | |
| 1220 | StringRef s = toStringRef(data); | |
| 1221 | ||
| 1222 | while (!s.empty()) { | |
| 1223 | size_t end = findNull(s, entSize); | |
| 1224 | if (end == StringRef::npos) | |
| 1170 | 1225 | fatal(toString(this) + ": string is not null terminated"); |
| 1171 | size_t Size = End + EntSize; | |
| 1226 | size_t size = end + entSize; | |
| 1172 | 1227 | |
| 1173 | Pieces.emplace_back(Off, xxHash64(S.substr(0, Size)), !IsAlloc); | |
| 1174 | S = S.substr(Size); | |
| 1175 | Off += Size; | |
| 1228 | pieces.emplace_back(off, xxHash64(s.substr(0, size)), !isAlloc); | |
| 1229 | s = s.substr(size); | |
| 1230 | off += size; | |
| 1176 | 1231 | } |
| 1177 | 1232 | } |
| 1178 | 1233 | |
| 1179 | 1234 | // Split non-SHF_STRINGS section. Such section is a sequence of |
| 1180 | 1235 | // fixed size records. |
| 1181 | void MergeInputSection::splitNonStrings(ArrayRef<uint8_t> Data, | |
| 1182 | size_t EntSize) { | |
| 1183 | size_t Size = Data.size(); | |
| 1184 | assert((Size % EntSize) == 0); | |
| 1185 | bool IsAlloc = Flags & SHF_ALLOC; | |
| 1186 | ||
| 1187 | for (size_t I = 0; I != Size; I += EntSize) | |
| 1188 | Pieces.emplace_back(I, xxHash64(Data.slice(I, EntSize)), !IsAlloc); | |
| 1236 | void MergeInputSection::splitNonStrings(ArrayRef<uint8_t> data, | |
| 1237 | size_t entSize) { | |
| 1238 | size_t size = data.size(); | |
| 1239 | assert((size % entSize) == 0); | |
| 1240 | bool isAlloc = flags & SHF_ALLOC; | |
| 1241 | ||
| 1242 | for (size_t i = 0; i != size; i += entSize) | |
| 1243 | pieces.emplace_back(i, xxHash64(data.slice(i, entSize)), !isAlloc); | |
| 1189 | 1244 | } |
| 1190 | 1245 | |
| 1191 | 1246 | template <class ELFT> |
| 1192 | MergeInputSection::MergeInputSection(ObjFile<ELFT> &F, | |
| 1193 | const typename ELFT::Shdr &Header, | |
| 1194 | StringRef Name) | |
| 1195 | : InputSectionBase(F, Header, Name, InputSectionBase::Merge) {} | |
| 1247 | MergeInputSection::MergeInputSection(ObjFile<ELFT> &f, | |
| 1248 | const typename ELFT::Shdr &header, | |
| 1249 | StringRef name) | |
| 1250 | : InputSectionBase(f, header, name, InputSectionBase::Merge) {} | |
| 1196 | 1251 | |
| 1197 | MergeInputSection::MergeInputSection(uint64_t Flags, uint32_t Type, | |
| 1198 | uint64_t Entsize, ArrayRef<uint8_t> Data, | |
| 1199 | StringRef Name) | |
| 1200 | : InputSectionBase(nullptr, Flags, Type, Entsize, /*Link*/ 0, /*Info*/ 0, | |
| 1201 | /*Alignment*/ Entsize, Data, Name, SectionBase::Merge) {} | |
| 1252 | MergeInputSection::MergeInputSection(uint64_t flags, uint32_t type, | |
| 1253 | uint64_t entsize, ArrayRef<uint8_t> data, | |
| 1254 | StringRef name) | |
| 1255 | : InputSectionBase(nullptr, flags, type, entsize, /*Link*/ 0, /*Info*/ 0, | |
| 1256 | /*Alignment*/ entsize, data, name, SectionBase::Merge) {} | |
| 1202 | 1257 | |
| 1203 | 1258 | // This function is called after we obtain a complete list of input sections |
| 1204 | 1259 | // that need to be linked. This is responsible to split section contents |
| ... | ... | @@ -1207,37 +1262,35 @@ MergeInputSection::MergeInputSection(uint64_t Flags, uint32_t Type, |
| 1207 | 1262 | // Note that this function is called from parallelForEach. This must be |
| 1208 | 1263 | // thread-safe (i.e. no memory allocation from the pools). |
| 1209 | 1264 | void MergeInputSection::splitIntoPieces() { |
| 1210 | assert(Pieces.empty()); | |
| 1265 | assert(pieces.empty()); | |
| 1211 | 1266 | |
| 1212 | if (Flags & SHF_STRINGS) | |
| 1213 | splitStrings(data(), Entsize); | |
| 1267 | if (flags & SHF_STRINGS) | |
| 1268 | splitStrings(data(), entsize); | |
| 1214 | 1269 | else |
| 1215 | splitNonStrings(data(), Entsize); | |
| 1270 | splitNonStrings(data(), entsize); | |
| 1216 | 1271 | } |
| 1217 | 1272 | |
| 1218 | SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) { | |
| 1219 | if (this->data().size() <= Offset) | |
| 1273 | SectionPiece *MergeInputSection::getSectionPiece(uint64_t offset) { | |
| 1274 | if (this->data().size() <= offset) | |
| 1220 | 1275 | fatal(toString(this) + ": offset is outside the section"); |
| 1221 | 1276 | |
| 1222 | 1277 | // If Offset is not at beginning of a section piece, it is not in the map. |
| 1223 | 1278 | // In that case we need to do a binary search of the original section piece vector. |
| 1224 | auto It2 = | |
| 1225 | llvm::upper_bound(Pieces, Offset, [](uint64_t Offset, SectionPiece P) { | |
| 1226 | return Offset < P.InputOff; | |
| 1227 | }); | |
| 1228 | return &It2[-1]; | |
| 1279 | auto it = partition_point( | |
| 1280 | pieces, [=](SectionPiece p) { return p.inputOff <= offset; }); | |
| 1281 | return &it[-1]; | |
| 1229 | 1282 | } |
| 1230 | 1283 | |
| 1231 | 1284 | // Returns the offset in an output section for a given input offset. |
| 1232 | 1285 | // Because contents of a mergeable section is not contiguous in output, |
| 1233 | 1286 | // it is not just an addition to a base output offset. |
| 1234 | uint64_t MergeInputSection::getParentOffset(uint64_t Offset) const { | |
| 1287 | uint64_t MergeInputSection::getParentOffset(uint64_t offset) const { | |
| 1235 | 1288 | // If Offset is not at beginning of a section piece, it is not in the map. |
| 1236 | 1289 | // In that case we need to search from the original section piece vector. |
| 1237 | const SectionPiece &Piece = | |
| 1238 | *(const_cast<MergeInputSection *>(this)->getSectionPiece (Offset)); | |
| 1239 | uint64_t Addend = Offset - Piece.InputOff; | |
| 1240 | return Piece.OutputOff + Addend; | |
| 1290 | const SectionPiece &piece = | |
| 1291 | *(const_cast<MergeInputSection *>(this)->getSectionPiece (offset)); | |
| 1292 | uint64_t addend = offset - piece.inputOff; | |
| 1293 | return piece.outputOff + addend; | |
| 1241 | 1294 | } |
| 1242 | 1295 | |
| 1243 | 1296 | template InputSection::InputSection(ObjFile<ELF32LE> &, const ELF32LE::Shdr &, |
deps/lld/ELF/InputSection.h+143-135| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- InputSection.h -------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -26,11 +25,14 @@ class Symbol; |
| 26 | 25 | struct SectionPiece; |
| 27 | 26 | |
| 28 | 27 | class Defined; |
| 28 | struct Partition; | |
| 29 | 29 | class SyntheticSection; |
| 30 | 30 | class MergeSyntheticSection; |
| 31 | 31 | template <class ELFT> class ObjFile; |
| 32 | 32 | class OutputSection; |
| 33 | 33 | |
| 34 | extern std::vector<Partition> partitions; | |
| 35 | ||
| 34 | 36 | // This is the base class of all sections that lld handles. Some are sections in |
| 35 | 37 | // input files, some are sections in the produced output file and some exist |
| 36 | 38 | // just as a convenience for implementing special ways of combining some |
| ... | ... | @@ -39,38 +41,53 @@ class SectionBase { |
| 39 | 41 | public: |
| 40 | 42 | enum Kind { Regular, EHFrame, Merge, Synthetic, Output }; |
| 41 | 43 | |
| 42 | Kind kind() const { return (Kind)SectionKind; } | |
| 44 | Kind kind() const { return (Kind)sectionKind; } | |
| 43 | 45 | |
| 44 | StringRef Name; | |
| 46 | StringRef name; | |
| 45 | 47 | |
| 46 | 48 | // This pointer points to the "real" instance of this instance. |
| 47 | 49 | // Usually Repl == this. However, if ICF merges two sections, |
| 48 | 50 | // Repl pointer of one section points to another section. So, |
| 49 | 51 | // if you need to get a pointer to this instance, do not use |
| 50 | 52 | // this but instead this->Repl. |
| 51 | SectionBase *Repl; | |
| 53 | SectionBase *repl; | |
| 52 | 54 | |
| 53 | unsigned SectionKind : 3; | |
| 55 | unsigned sectionKind : 3; | |
| 54 | 56 | |
| 55 | // The next two bit fields are only used by InputSectionBase, but we | |
| 57 | // The next three bit fields are only used by InputSectionBase, but we | |
| 56 | 58 | // put them here so the struct packs better. |
| 57 | 59 | |
| 58 | // The garbage collector sets sections' Live bits. | |
| 59 | // If GC is disabled, all sections are considered live by default. | |
| 60 | unsigned Live : 1; | |
| 60 | // True if this section has already been placed to a linker script | |
| 61 | // output section. This is needed because, in a linker script, you | |
| 62 | // can refer to the same section more than once. For example, in | |
| 63 | // the following linker script, | |
| 64 | // | |
| 65 | // .foo : { *(.text) } | |
| 66 | // .bar : { *(.text) } | |
| 67 | // | |
| 68 | // .foo takes all .text sections, and .bar becomes empty. To achieve | |
| 69 | // this, we need to memorize whether a section has been placed or | |
| 70 | // not for each input section. | |
| 71 | unsigned assigned : 1; | |
| 61 | 72 | |
| 62 | unsigned Bss : 1; | |
| 73 | unsigned bss : 1; | |
| 63 | 74 | |
| 64 | 75 | // Set for sections that should not be folded by ICF. |
| 65 | unsigned KeepUnique : 1; | |
| 76 | unsigned keepUnique : 1; | |
| 77 | ||
| 78 | // The 1-indexed partition that this section is assigned to by the garbage | |
| 79 | // collector, or 0 if this section is dead. Normally there is only one | |
| 80 | // partition, so this will either be 0 or 1. | |
| 81 | uint8_t partition; | |
| 82 | elf::Partition &getPartition() const; | |
| 66 | 83 | |
| 67 | 84 | // These corresponds to the fields in Elf_Shdr. |
| 68 | uint32_t Alignment; | |
| 69 | uint64_t Flags; | |
| 70 | uint64_t Entsize; | |
| 71 | uint32_t Type; | |
| 72 | uint32_t Link; | |
| 73 | uint32_t Info; | |
| 85 | uint32_t alignment; | |
| 86 | uint64_t flags; | |
| 87 | uint64_t entsize; | |
| 88 | uint32_t type; | |
| 89 | uint32_t link; | |
| 90 | uint32_t info; | |
| 74 | 91 | |
| 75 | 92 | OutputSection *getOutputSection(); |
| 76 | 93 | const OutputSection *getOutputSection() const { |
| ... | ... | @@ -79,90 +96,81 @@ public: |
| 79 | 96 | |
| 80 | 97 | // Translate an offset in the input section to an offset in the output |
| 81 | 98 | // section. |
| 82 | uint64_t getOffset(uint64_t Offset) const; | |
| 99 | uint64_t getOffset(uint64_t offset) const; | |
| 83 | 100 | |
| 84 | uint64_t getVA(uint64_t Offset = 0) const; | |
| 101 | uint64_t getVA(uint64_t offset = 0) const; | |
| 102 | ||
| 103 | bool isLive() const { return partition != 0; } | |
| 104 | void markLive() { partition = 1; } | |
| 105 | void markDead() { partition = 0; } | |
| 85 | 106 | |
| 86 | 107 | protected: |
| 87 | SectionBase(Kind SectionKind, StringRef Name, uint64_t Flags, | |
| 88 | uint64_t Entsize, uint64_t Alignment, uint32_t Type, | |
| 89 | uint32_t Info, uint32_t Link) | |
| 90 | : Name(Name), Repl(this), SectionKind(SectionKind), Live(false), | |
| 91 | Bss(false), KeepUnique(false), Alignment(Alignment), Flags(Flags), | |
| 92 | Entsize(Entsize), Type(Type), Link(Link), Info(Info) {} | |
| 108 | SectionBase(Kind sectionKind, StringRef name, uint64_t flags, | |
| 109 | uint64_t entsize, uint64_t alignment, uint32_t type, | |
| 110 | uint32_t info, uint32_t link) | |
| 111 | : name(name), repl(this), sectionKind(sectionKind), assigned(false), | |
| 112 | bss(false), keepUnique(false), partition(0), alignment(alignment), | |
| 113 | flags(flags), entsize(entsize), type(type), link(link), info(info) {} | |
| 93 | 114 | }; |
| 94 | 115 | |
| 95 | 116 | // This corresponds to a section of an input file. |
| 96 | 117 | class InputSectionBase : public SectionBase { |
| 97 | 118 | public: |
| 98 | 119 | template <class ELFT> |
| 99 | InputSectionBase(ObjFile<ELFT> &File, const typename ELFT::Shdr &Header, | |
| 100 | StringRef Name, Kind SectionKind); | |
| 120 | InputSectionBase(ObjFile<ELFT> &file, const typename ELFT::Shdr &header, | |
| 121 | StringRef name, Kind sectionKind); | |
| 122 | ||
| 123 | InputSectionBase(InputFile *file, uint64_t flags, uint32_t type, | |
| 124 | uint64_t entsize, uint32_t link, uint32_t info, | |
| 125 | uint32_t alignment, ArrayRef<uint8_t> data, StringRef name, | |
| 126 | Kind sectionKind); | |
| 101 | 127 | |
| 102 | InputSectionBase(InputFile *File, uint64_t Flags, uint32_t Type, | |
| 103 | uint64_t Entsize, uint32_t Link, uint32_t Info, | |
| 104 | uint32_t Alignment, ArrayRef<uint8_t> Data, StringRef Name, | |
| 105 | Kind SectionKind); | |
| 128 | static bool classof(const SectionBase *s) { return s->kind() != Output; } | |
| 106 | 129 | |
| 107 | static bool classof(const SectionBase *S) { return S->kind() != Output; } | |
| 130 | // Relocations that refer to this section. | |
| 131 | unsigned numRelocations : 31; | |
| 132 | unsigned areRelocsRela : 1; | |
| 133 | const void *firstRelocation = nullptr; | |
| 108 | 134 | |
| 109 | 135 | // The file which contains this section. Its dynamic type is always |
| 110 | 136 | // ObjFile<ELFT>, but in order to avoid ELFT, we use InputFile as |
| 111 | 137 | // its static type. |
| 112 | InputFile *File; | |
| 138 | InputFile *file; | |
| 113 | 139 | |
| 114 | 140 | template <class ELFT> ObjFile<ELFT> *getFile() const { |
| 115 | return cast_or_null<ObjFile<ELFT>>(File); | |
| 141 | return cast_or_null<ObjFile<ELFT>>(file); | |
| 116 | 142 | } |
| 117 | 143 | |
| 118 | 144 | ArrayRef<uint8_t> data() const { |
| 119 | if (UncompressedSize >= 0 && !UncompressedBuf) | |
| 145 | if (uncompressedSize >= 0) | |
| 120 | 146 | uncompress(); |
| 121 | return RawData; | |
| 147 | return rawData; | |
| 122 | 148 | } |
| 123 | 149 | |
| 124 | 150 | uint64_t getOffsetInFile() const; |
| 125 | 151 | |
| 126 | // True if this section has already been placed to a linker script | |
| 127 | // output section. This is needed because, in a linker script, you | |
| 128 | // can refer to the same section more than once. For example, in | |
| 129 | // the following linker script, | |
| 130 | // | |
| 131 | // .foo : { *(.text) } | |
| 132 | // .bar : { *(.text) } | |
| 133 | // | |
| 134 | // .foo takes all .text sections, and .bar becomes empty. To achieve | |
| 135 | // this, we need to memorize whether a section has been placed or | |
| 136 | // not for each input section. | |
| 137 | bool Assigned = false; | |
| 138 | ||
| 139 | 152 | // Input sections are part of an output section. Special sections |
| 140 | 153 | // like .eh_frame and merge sections are first combined into a |
| 141 | 154 | // synthetic section that is then added to an output section. In all |
| 142 | 155 | // cases this points one level up. |
| 143 | SectionBase *Parent = nullptr; | |
| 144 | ||
| 145 | // Relocations that refer to this section. | |
| 146 | const void *FirstRelocation = nullptr; | |
| 147 | unsigned NumRelocations : 31; | |
| 148 | unsigned AreRelocsRela : 1; | |
| 156 | SectionBase *parent = nullptr; | |
| 149 | 157 | |
| 150 | 158 | template <class ELFT> ArrayRef<typename ELFT::Rel> rels() const { |
| 151 | assert(!AreRelocsRela); | |
| 159 | assert(!areRelocsRela); | |
| 152 | 160 | return llvm::makeArrayRef( |
| 153 | static_cast<const typename ELFT::Rel *>(FirstRelocation), | |
| 154 | NumRelocations); | |
| 161 | static_cast<const typename ELFT::Rel *>(firstRelocation), | |
| 162 | numRelocations); | |
| 155 | 163 | } |
| 156 | 164 | |
| 157 | 165 | template <class ELFT> ArrayRef<typename ELFT::Rela> relas() const { |
| 158 | assert(AreRelocsRela); | |
| 166 | assert(areRelocsRela); | |
| 159 | 167 | return llvm::makeArrayRef( |
| 160 | static_cast<const typename ELFT::Rela *>(FirstRelocation), | |
| 161 | NumRelocations); | |
| 168 | static_cast<const typename ELFT::Rela *>(firstRelocation), | |
| 169 | numRelocations); | |
| 162 | 170 | } |
| 163 | 171 | |
| 164 | 172 | // InputSections that are dependent on us (reverse dependency for GC) |
| 165 | llvm::TinyPtrVector<InputSection *> DependentSections; | |
| 173 | llvm::TinyPtrVector<InputSection *> dependentSections; | |
| 166 | 174 | |
| 167 | 175 | // Returns the size of this section (even if this is a common or BSS.) |
| 168 | 176 | size_t getSize() const; |
| ... | ... | @@ -172,23 +180,23 @@ public: |
| 172 | 180 | // Get the function symbol that encloses this offset from within the |
| 173 | 181 | // section. |
| 174 | 182 | template <class ELFT> |
| 175 | Defined *getEnclosingFunction(uint64_t Offset); | |
| 183 | Defined *getEnclosingFunction(uint64_t offset); | |
| 176 | 184 | |
| 177 | 185 | // Returns a source location string. Used to construct an error message. |
| 178 | template <class ELFT> std::string getLocation(uint64_t Offset); | |
| 179 | std::string getSrcMsg(const Symbol &Sym, uint64_t Offset); | |
| 180 | std::string getObjMsg(uint64_t Offset); | |
| 186 | template <class ELFT> std::string getLocation(uint64_t offset); | |
| 187 | std::string getSrcMsg(const Symbol &sym, uint64_t offset); | |
| 188 | std::string getObjMsg(uint64_t offset); | |
| 181 | 189 | |
| 182 | 190 | // Each section knows how to relocate itself. These functions apply |
| 183 | 191 | // relocations, assuming that Buf points to this section's copy in |
| 184 | 192 | // the mmap'ed output buffer. |
| 185 | template <class ELFT> void relocate(uint8_t *Buf, uint8_t *BufEnd); | |
| 186 | void relocateAlloc(uint8_t *Buf, uint8_t *BufEnd); | |
| 193 | template <class ELFT> void relocate(uint8_t *buf, uint8_t *bufEnd); | |
| 194 | void relocateAlloc(uint8_t *buf, uint8_t *bufEnd); | |
| 187 | 195 | |
| 188 | 196 | // The native ELF reloc data type is not very convenient to handle. |
| 189 | 197 | // So we convert ELF reloc records to our own records in Relocations.cpp. |
| 190 | 198 | // This vector contains such "cooked" relocations. |
| 191 | std::vector<Relocation> Relocations; | |
| 199 | std::vector<Relocation> relocations; | |
| 192 | 200 | |
| 193 | 201 | // A function compiled with -fsplit-stack calling a function |
| 194 | 202 | // compiled without -fsplit-stack needs its prologue adjusted. Find |
| ... | ... | @@ -196,25 +204,26 @@ public: |
| 196 | 204 | // to relocation. See https://gcc.gnu.org/wiki/SplitStacks for more |
| 197 | 205 | // information. |
| 198 | 206 | template <typename ELFT> |
| 199 | void adjustSplitStackFunctionPrologues(uint8_t *Buf, uint8_t *End); | |
| 207 | void adjustSplitStackFunctionPrologues(uint8_t *buf, uint8_t *end); | |
| 200 | 208 | |
| 201 | 209 | |
| 202 | 210 | template <typename T> llvm::ArrayRef<T> getDataAs() const { |
| 203 | size_t S = data().size(); | |
| 204 | assert(S % sizeof(T) == 0); | |
| 205 | return llvm::makeArrayRef<T>((const T *)data().data(), S / sizeof(T)); | |
| 211 | size_t s = data().size(); | |
| 212 | assert(s % sizeof(T) == 0); | |
| 213 | return llvm::makeArrayRef<T>((const T *)data().data(), s / sizeof(T)); | |
| 206 | 214 | } |
| 207 | 215 | |
| 208 | 216 | protected: |
| 209 | 217 | void parseCompressedHeader(); |
| 210 | 218 | void uncompress() const; |
| 211 | 219 | |
| 212 | mutable ArrayRef<uint8_t> RawData; | |
| 220 | mutable ArrayRef<uint8_t> rawData; | |
| 213 | 221 | |
| 214 | // A pointer that owns uncompressed data if a section is compressed by zlib. | |
| 215 | // Since the feature is not used often, this is usually a nullptr. | |
| 216 | mutable std::unique_ptr<char[]> UncompressedBuf; | |
| 217 | int64_t UncompressedSize = -1; | |
| 222 | // This field stores the uncompressed size of the compressed data in rawData, | |
| 223 | // or -1 if rawData is not compressed (either because the section wasn't | |
| 224 | // compressed in the first place, or because we ended up uncompressing it). | |
| 225 | // Since the feature is not used often, this is usually -1. | |
| 226 | mutable int64_t uncompressedSize = -1; | |
| 218 | 227 | }; |
| 219 | 228 | |
| 220 | 229 | // SectionPiece represents a piece of splittable section contents. |
| ... | ... | @@ -222,14 +231,13 @@ protected: |
| 222 | 231 | // have to be as compact as possible, which is why we don't store the size (can |
| 223 | 232 | // be found by looking at the next one). |
| 224 | 233 | struct SectionPiece { |
| 225 | SectionPiece(size_t Off, uint32_t Hash, bool Live) | |
| 226 | : InputOff(Off), Hash(Hash), OutputOff(0), | |
| 227 | Live(Live || !Config->GcSections) {} | |
| 228 | ||
| 229 | uint32_t InputOff; | |
| 230 | uint32_t Hash; | |
| 231 | int64_t OutputOff : 63; | |
| 232 | uint64_t Live : 1; | |
| 234 | SectionPiece(size_t off, uint32_t hash, bool live) | |
| 235 | : inputOff(off), live(live || !config->gcSections), hash(hash >> 1) {} | |
| 236 | ||
| 237 | uint32_t inputOff; | |
| 238 | uint32_t live : 1; | |
| 239 | uint32_t hash : 31; | |
| 240 | uint64_t outputOff = 0; | |
| 233 | 241 | }; |
| 234 | 242 | |
| 235 | 243 | static_assert(sizeof(SectionPiece) == 16, "SectionPiece is too big"); |
| ... | ... | @@ -238,74 +246,74 @@ static_assert(sizeof(SectionPiece) == 16, "SectionPiece is too big"); |
| 238 | 246 | class MergeInputSection : public InputSectionBase { |
| 239 | 247 | public: |
| 240 | 248 | template <class ELFT> |
| 241 | MergeInputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header, | |
| 242 | StringRef Name); | |
| 243 | MergeInputSection(uint64_t Flags, uint32_t Type, uint64_t Entsize, | |
| 244 | ArrayRef<uint8_t> Data, StringRef Name); | |
| 249 | MergeInputSection(ObjFile<ELFT> &f, const typename ELFT::Shdr &header, | |
| 250 | StringRef name); | |
| 251 | MergeInputSection(uint64_t flags, uint32_t type, uint64_t entsize, | |
| 252 | ArrayRef<uint8_t> data, StringRef name); | |
| 245 | 253 | |
| 246 | static bool classof(const SectionBase *S) { return S->kind() == Merge; } | |
| 254 | static bool classof(const SectionBase *s) { return s->kind() == Merge; } | |
| 247 | 255 | void splitIntoPieces(); |
| 248 | 256 | |
| 249 | 257 | // Translate an offset in the input section to an offset in the parent |
| 250 | 258 | // MergeSyntheticSection. |
| 251 | uint64_t getParentOffset(uint64_t Offset) const; | |
| 259 | uint64_t getParentOffset(uint64_t offset) const; | |
| 252 | 260 | |
| 253 | 261 | // Splittable sections are handled as a sequence of data |
| 254 | 262 | // rather than a single large blob of data. |
| 255 | std::vector<SectionPiece> Pieces; | |
| 263 | std::vector<SectionPiece> pieces; | |
| 256 | 264 | |
| 257 | 265 | // Returns I'th piece's data. This function is very hot when |
| 258 | 266 | // string merging is enabled, so we want to inline. |
| 259 | 267 | LLVM_ATTRIBUTE_ALWAYS_INLINE |
| 260 | llvm::CachedHashStringRef getData(size_t I) const { | |
| 261 | size_t Begin = Pieces[I].InputOff; | |
| 262 | size_t End = | |
| 263 | (Pieces.size() - 1 == I) ? data().size() : Pieces[I + 1].InputOff; | |
| 264 | return {toStringRef(data().slice(Begin, End - Begin)), Pieces[I].Hash}; | |
| 268 | llvm::CachedHashStringRef getData(size_t i) const { | |
| 269 | size_t begin = pieces[i].inputOff; | |
| 270 | size_t end = | |
| 271 | (pieces.size() - 1 == i) ? data().size() : pieces[i + 1].inputOff; | |
| 272 | return {toStringRef(data().slice(begin, end - begin)), pieces[i].hash}; | |
| 265 | 273 | } |
| 266 | 274 | |
| 267 | 275 | // Returns the SectionPiece at a given input section offset. |
| 268 | SectionPiece *getSectionPiece(uint64_t Offset); | |
| 269 | const SectionPiece *getSectionPiece(uint64_t Offset) const { | |
| 270 | return const_cast<MergeInputSection *>(this)->getSectionPiece(Offset); | |
| 276 | SectionPiece *getSectionPiece(uint64_t offset); | |
| 277 | const SectionPiece *getSectionPiece(uint64_t offset) const { | |
| 278 | return const_cast<MergeInputSection *>(this)->getSectionPiece(offset); | |
| 271 | 279 | } |
| 272 | 280 | |
| 273 | 281 | SyntheticSection *getParent() const; |
| 274 | 282 | |
| 275 | 283 | private: |
| 276 | void splitStrings(ArrayRef<uint8_t> A, size_t Size); | |
| 277 | void splitNonStrings(ArrayRef<uint8_t> A, size_t Size); | |
| 284 | void splitStrings(ArrayRef<uint8_t> a, size_t size); | |
| 285 | void splitNonStrings(ArrayRef<uint8_t> a, size_t size); | |
| 278 | 286 | }; |
| 279 | 287 | |
| 280 | 288 | struct EhSectionPiece { |
| 281 | EhSectionPiece(size_t Off, InputSectionBase *Sec, uint32_t Size, | |
| 282 | unsigned FirstRelocation) | |
| 283 | : InputOff(Off), Sec(Sec), Size(Size), FirstRelocation(FirstRelocation) {} | |
| 289 | EhSectionPiece(size_t off, InputSectionBase *sec, uint32_t size, | |
| 290 | unsigned firstRelocation) | |
| 291 | : inputOff(off), sec(sec), size(size), firstRelocation(firstRelocation) {} | |
| 284 | 292 | |
| 285 | 293 | ArrayRef<uint8_t> data() { |
| 286 | return {Sec->data().data() + this->InputOff, Size}; | |
| 294 | return {sec->data().data() + this->inputOff, size}; | |
| 287 | 295 | } |
| 288 | 296 | |
| 289 | size_t InputOff; | |
| 290 | ssize_t OutputOff = -1; | |
| 291 | InputSectionBase *Sec; | |
| 292 | uint32_t Size; | |
| 293 | unsigned FirstRelocation; | |
| 297 | size_t inputOff; | |
| 298 | ssize_t outputOff = -1; | |
| 299 | InputSectionBase *sec; | |
| 300 | uint32_t size; | |
| 301 | unsigned firstRelocation; | |
| 294 | 302 | }; |
| 295 | 303 | |
| 296 | 304 | // This corresponds to a .eh_frame section of an input file. |
| 297 | 305 | class EhInputSection : public InputSectionBase { |
| 298 | 306 | public: |
| 299 | 307 | template <class ELFT> |
| 300 | EhInputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header, | |
| 301 | StringRef Name); | |
| 302 | static bool classof(const SectionBase *S) { return S->kind() == EHFrame; } | |
| 308 | EhInputSection(ObjFile<ELFT> &f, const typename ELFT::Shdr &header, | |
| 309 | StringRef name); | |
| 310 | static bool classof(const SectionBase *s) { return s->kind() == EHFrame; } | |
| 303 | 311 | template <class ELFT> void split(); |
| 304 | template <class ELFT, class RelTy> void split(ArrayRef<RelTy> Rels); | |
| 312 | template <class ELFT, class RelTy> void split(ArrayRef<RelTy> rels); | |
| 305 | 313 | |
| 306 | 314 | // Splittable sections are handled as a sequence of data |
| 307 | 315 | // rather than a single large blob of data. |
| 308 | std::vector<EhSectionPiece> Pieces; | |
| 316 | std::vector<EhSectionPiece> pieces; | |
| 309 | 317 | |
| 310 | 318 | SyntheticSection *getParent() const; |
| 311 | 319 | }; |
| ... | ... | @@ -316,17 +324,17 @@ public: |
| 316 | 324 | // .eh_frame. It also includes the synthetic sections themselves. |
| 317 | 325 | class InputSection : public InputSectionBase { |
| 318 | 326 | public: |
| 319 | InputSection(InputFile *F, uint64_t Flags, uint32_t Type, uint32_t Alignment, | |
| 320 | ArrayRef<uint8_t> Data, StringRef Name, Kind K = Regular); | |
| 327 | InputSection(InputFile *f, uint64_t flags, uint32_t type, uint32_t alignment, | |
| 328 | ArrayRef<uint8_t> data, StringRef name, Kind k = Regular); | |
| 321 | 329 | template <class ELFT> |
| 322 | InputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header, | |
| 323 | StringRef Name); | |
| 330 | InputSection(ObjFile<ELFT> &f, const typename ELFT::Shdr &header, | |
| 331 | StringRef name); | |
| 324 | 332 | |
| 325 | 333 | // Write this section to a mmap'ed file, assuming Buf is pointing to |
| 326 | 334 | // beginning of the output section. |
| 327 | template <class ELFT> void writeTo(uint8_t *Buf); | |
| 335 | template <class ELFT> void writeTo(uint8_t *buf); | |
| 328 | 336 | |
| 329 | uint64_t getOffset(uint64_t Offset) const { return OutSecOff + Offset; } | |
| 337 | uint64_t getOffset(uint64_t offset) const { return outSecOff + offset; } | |
| 330 | 338 | |
| 331 | 339 | OutputSection *getParent() const; |
| 332 | 340 | |
| ... | ... | @@ -334,32 +342,32 @@ public: |
| 334 | 342 | // OutputSection's InputSection list, and is used when ordering SHF_LINK_ORDER |
| 335 | 343 | // sections. After assignAddresses is called, it represents the offset from |
| 336 | 344 | // the beginning of the output section this section was assigned to. |
| 337 | uint64_t OutSecOff = 0; | |
| 345 | uint64_t outSecOff = 0; | |
| 338 | 346 | |
| 339 | static bool classof(const SectionBase *S); | |
| 347 | static bool classof(const SectionBase *s); | |
| 340 | 348 | |
| 341 | 349 | InputSectionBase *getRelocatedSection() const; |
| 342 | 350 | |
| 343 | 351 | template <class ELFT, class RelTy> |
| 344 | void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels); | |
| 352 | void relocateNonAlloc(uint8_t *buf, llvm::ArrayRef<RelTy> rels); | |
| 345 | 353 | |
| 346 | 354 | // Used by ICF. |
| 347 | uint32_t Class[2] = {0, 0}; | |
| 355 | uint32_t eqClass[2] = {0, 0}; | |
| 348 | 356 | |
| 349 | 357 | // Called by ICF to merge two input sections. |
| 350 | void replace(InputSection *Other); | |
| 358 | void replace(InputSection *other); | |
| 351 | 359 | |
| 352 | static InputSection Discarded; | |
| 360 | static InputSection discarded; | |
| 353 | 361 | |
| 354 | 362 | private: |
| 355 | 363 | template <class ELFT, class RelTy> |
| 356 | void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels); | |
| 364 | void copyRelocations(uint8_t *buf, llvm::ArrayRef<RelTy> rels); | |
| 357 | 365 | |
| 358 | template <class ELFT> void copyShtGroup(uint8_t *Buf); | |
| 366 | template <class ELFT> void copyShtGroup(uint8_t *buf); | |
| 359 | 367 | }; |
| 360 | 368 | |
| 361 | 369 | // The list of all input sections. |
| 362 | extern std::vector<InputSectionBase *> InputSections; | |
| 370 | extern std::vector<InputSectionBase *> inputSections; | |
| 363 | 371 | |
| 364 | 372 | } // namespace elf |
| 365 | 373 |
deps/lld/ELF/LTO.cpp+167-160| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- LTO.cpp ------------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -13,6 +12,7 @@ |
| 13 | 12 | #include "LinkerScript.h" |
| 14 | 13 | #include "SymbolTable.h" |
| 15 | 14 | #include "Symbols.h" |
| 15 | #include "lld/Common/Args.h" | |
| 16 | 16 | #include "lld/Common/ErrorHandler.h" |
| 17 | 17 | #include "lld/Common/TargetOptionsCommandFlags.h" |
| 18 | 18 | #include "llvm/ADT/STLExtras.h" |
| ... | ... | @@ -47,134 +47,135 @@ using namespace lld::elf; |
| 47 | 47 | |
| 48 | 48 | // Creates an empty file to store a list of object files for final |
| 49 | 49 | // linking of distributed ThinLTO. |
| 50 | static std::unique_ptr<raw_fd_ostream> openFile(StringRef File) { | |
| 51 | std::error_code EC; | |
| 52 | auto Ret = | |
| 53 | llvm::make_unique<raw_fd_ostream>(File, EC, sys::fs::OpenFlags::F_None); | |
| 54 | if (EC) { | |
| 55 | error("cannot open " + File + ": " + EC.message()); | |
| 50 | static std::unique_ptr<raw_fd_ostream> openFile(StringRef file) { | |
| 51 | std::error_code ec; | |
| 52 | auto ret = | |
| 53 | llvm::make_unique<raw_fd_ostream>(file, ec, sys::fs::OpenFlags::F_None); | |
| 54 | if (ec) { | |
| 55 | error("cannot open " + file + ": " + ec.message()); | |
| 56 | 56 | return nullptr; |
| 57 | 57 | } |
| 58 | return Ret; | |
| 58 | return ret; | |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | static std::string getThinLTOOutputFile(StringRef ModulePath) { | |
| 62 | return lto::getThinLTOOutputFile(ModulePath, | |
| 63 | Config->ThinLTOPrefixReplace.first, | |
| 64 | Config->ThinLTOPrefixReplace.second); | |
| 61 | static std::string getThinLTOOutputFile(StringRef modulePath) { | |
| 62 | return lto::getThinLTOOutputFile(modulePath, | |
| 63 | config->thinLTOPrefixReplace.first, | |
| 64 | config->thinLTOPrefixReplace.second); | |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | 67 | static lto::Config createConfig() { |
| 68 | lto::Config C; | |
| 68 | lto::Config c; | |
| 69 | 69 | |
| 70 | 70 | // LLD supports the new relocations and address-significance tables. |
| 71 | C.Options = InitTargetOptionsFromCodeGenFlags(); | |
| 72 | C.Options.RelaxELFRelocations = true; | |
| 73 | C.Options.EmitAddrsig = true; | |
| 71 | c.Options = initTargetOptionsFromCodeGenFlags(); | |
| 72 | c.Options.RelaxELFRelocations = true; | |
| 73 | c.Options.EmitAddrsig = true; | |
| 74 | 74 | |
| 75 | 75 | // Always emit a section per function/datum with LTO. |
| 76 | C.Options.FunctionSections = true; | |
| 77 | C.Options.DataSections = true; | |
| 76 | c.Options.FunctionSections = true; | |
| 77 | c.Options.DataSections = true; | |
| 78 | 78 | |
| 79 | if (Config->Relocatable) | |
| 80 | C.RelocModel = None; | |
| 81 | else if (Config->Pic) | |
| 82 | C.RelocModel = Reloc::PIC_; | |
| 79 | if (config->relocatable) | |
| 80 | c.RelocModel = None; | |
| 81 | else if (config->isPic) | |
| 82 | c.RelocModel = Reloc::PIC_; | |
| 83 | 83 | else |
| 84 | C.RelocModel = Reloc::Static; | |
| 84 | c.RelocModel = Reloc::Static; | |
| 85 | 85 | |
| 86 | C.CodeModel = GetCodeModelFromCMModel(); | |
| 87 | C.DisableVerify = Config->DisableVerify; | |
| 88 | C.DiagHandler = diagnosticHandler; | |
| 89 | C.OptLevel = Config->LTOO; | |
| 90 | C.CPU = GetCPUStr(); | |
| 91 | C.MAttrs = GetMAttrs(); | |
| 86 | c.CodeModel = getCodeModelFromCMModel(); | |
| 87 | c.DisableVerify = config->disableVerify; | |
| 88 | c.DiagHandler = diagnosticHandler; | |
| 89 | c.OptLevel = config->ltoo; | |
| 90 | c.CPU = getCPUStr(); | |
| 91 | c.MAttrs = getMAttrs(); | |
| 92 | c.CGOptLevel = args::getCGOptLevel(config->ltoo); | |
| 92 | 93 | |
| 93 | 94 | // Set up a custom pipeline if we've been asked to. |
| 94 | C.OptPipeline = Config->LTONewPmPasses; | |
| 95 | C.AAPipeline = Config->LTOAAPipeline; | |
| 95 | c.OptPipeline = config->ltoNewPmPasses; | |
| 96 | c.AAPipeline = config->ltoAAPipeline; | |
| 96 | 97 | |
| 97 | 98 | // Set up optimization remarks if we've been asked to. |
| 98 | C.RemarksFilename = Config->OptRemarksFilename; | |
| 99 | C.RemarksWithHotness = Config->OptRemarksWithHotness; | |
| 100 | ||
| 101 | C.SampleProfile = Config->LTOSampleProfile; | |
| 102 | C.UseNewPM = Config->LTONewPassManager; | |
| 103 | C.DebugPassManager = Config->LTODebugPassManager; | |
| 104 | C.DwoDir = Config->DwoDir; | |
| 105 | ||
| 106 | if (Config->EmitLLVM) { | |
| 107 | C.PostInternalizeModuleHook = [](size_t Task, const Module &M) { | |
| 108 | if (std::unique_ptr<raw_fd_ostream> OS = openFile(Config->OutputFile)) | |
| 109 | WriteBitcodeToFile(M, *OS, false); | |
| 99 | c.RemarksFilename = config->optRemarksFilename; | |
| 100 | c.RemarksPasses = config->optRemarksPasses; | |
| 101 | c.RemarksWithHotness = config->optRemarksWithHotness; | |
| 102 | c.RemarksFormat = config->optRemarksFormat; | |
| 103 | ||
| 104 | c.SampleProfile = config->ltoSampleProfile; | |
| 105 | c.UseNewPM = config->ltoNewPassManager; | |
| 106 | c.DebugPassManager = config->ltoDebugPassManager; | |
| 107 | c.DwoDir = config->dwoDir; | |
| 108 | ||
| 109 | c.CSIRProfile = config->ltoCSProfileFile; | |
| 110 | c.RunCSIRInstr = config->ltoCSProfileGenerate; | |
| 111 | ||
| 112 | if (config->emitLLVM) { | |
| 113 | c.PostInternalizeModuleHook = [](size_t task, const Module &m) { | |
| 114 | if (std::unique_ptr<raw_fd_ostream> os = openFile(config->outputFile)) | |
| 115 | WriteBitcodeToFile(m, *os, false); | |
| 110 | 116 | return false; |
| 111 | 117 | }; |
| 112 | 118 | } |
| 113 | 119 | |
| 114 | if (Config->SaveTemps) | |
| 115 | checkError(C.addSaveTemps(Config->OutputFile.str() + ".", | |
| 120 | if (config->saveTemps) | |
| 121 | checkError(c.addSaveTemps(config->outputFile.str() + ".", | |
| 116 | 122 | /*UseInputModulePath*/ true)); |
| 117 | return C; | |
| 123 | return c; | |
| 118 | 124 | } |
| 119 | 125 | |
| 120 | 126 | BitcodeCompiler::BitcodeCompiler() { |
| 121 | // Initialize IndexFile. | |
| 122 | if (!Config->ThinLTOIndexOnlyArg.empty()) | |
| 123 | IndexFile = openFile(Config->ThinLTOIndexOnlyArg); | |
| 124 | ||
| 125 | // Initialize LTOObj. | |
| 126 | lto::ThinBackend Backend; | |
| 127 | if (Config->ThinLTOIndexOnly) { | |
| 128 | auto OnIndexWrite = [&](StringRef S) { ThinIndices.erase(S); }; | |
| 129 | Backend = lto::createWriteIndexesThinBackend( | |
| 130 | Config->ThinLTOPrefixReplace.first, Config->ThinLTOPrefixReplace.second, | |
| 131 | Config->ThinLTOEmitImportsFiles, IndexFile.get(), OnIndexWrite); | |
| 132 | } else if (Config->ThinLTOJobs != -1U) { | |
| 133 | Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs); | |
| 127 | // Initialize indexFile. | |
| 128 | if (!config->thinLTOIndexOnlyArg.empty()) | |
| 129 | indexFile = openFile(config->thinLTOIndexOnlyArg); | |
| 130 | ||
| 131 | // Initialize ltoObj. | |
| 132 | lto::ThinBackend backend; | |
| 133 | if (config->thinLTOIndexOnly) { | |
| 134 | auto onIndexWrite = [&](StringRef s) { thinIndices.erase(s); }; | |
| 135 | backend = lto::createWriteIndexesThinBackend( | |
| 136 | config->thinLTOPrefixReplace.first, config->thinLTOPrefixReplace.second, | |
| 137 | config->thinLTOEmitImportsFiles, indexFile.get(), onIndexWrite); | |
| 138 | } else if (config->thinLTOJobs != -1U) { | |
| 139 | backend = lto::createInProcessThinBackend(config->thinLTOJobs); | |
| 134 | 140 | } |
| 135 | 141 | |
| 136 | LTOObj = llvm::make_unique<lto::LTO>(createConfig(), Backend, | |
| 137 | Config->LTOPartitions); | |
| 142 | ltoObj = llvm::make_unique<lto::LTO>(createConfig(), backend, | |
| 143 | config->ltoPartitions); | |
| 138 | 144 | |
| 139 | // Initialize UsedStartStop. | |
| 140 | for (Symbol *Sym : Symtab->getSymbols()) { | |
| 141 | StringRef S = Sym->getName(); | |
| 142 | for (StringRef Prefix : {"__start_", "__stop_"}) | |
| 143 | if (S.startswith(Prefix)) | |
| 144 | UsedStartStop.insert(S.substr(Prefix.size())); | |
| 145 | } | |
| 145 | // Initialize usedStartStop. | |
| 146 | symtab->forEachSymbol([&](Symbol *sym) { | |
| 147 | StringRef s = sym->getName(); | |
| 148 | for (StringRef prefix : {"__start_", "__stop_"}) | |
| 149 | if (s.startswith(prefix)) | |
| 150 | usedStartStop.insert(s.substr(prefix.size())); | |
| 151 | }); | |
| 146 | 152 | } |
| 147 | 153 | |
| 148 | 154 | BitcodeCompiler::~BitcodeCompiler() = default; |
| 149 | 155 | |
| 150 | static void undefine(Symbol *S) { | |
| 151 | replaceSymbol<Undefined>(S, nullptr, S->getName(), STB_GLOBAL, STV_DEFAULT, | |
| 152 | S->Type); | |
| 153 | } | |
| 154 | ||
| 155 | void BitcodeCompiler::add(BitcodeFile &F) { | |
| 156 | lto::InputFile &Obj = *F.Obj; | |
| 157 | bool IsExec = !Config->Shared && !Config->Relocatable; | |
| 156 | void BitcodeCompiler::add(BitcodeFile &f) { | |
| 157 | lto::InputFile &obj = *f.obj; | |
| 158 | bool isExec = !config->shared && !config->relocatable; | |
| 158 | 159 | |
| 159 | if (Config->ThinLTOIndexOnly) | |
| 160 | ThinIndices.insert(Obj.getName()); | |
| 160 | if (config->thinLTOIndexOnly) | |
| 161 | thinIndices.insert(obj.getName()); | |
| 161 | 162 | |
| 162 | ArrayRef<Symbol *> Syms = F.getSymbols(); | |
| 163 | ArrayRef<lto::InputFile::Symbol> ObjSyms = Obj.symbols(); | |
| 164 | std::vector<lto::SymbolResolution> Resols(Syms.size()); | |
| 163 | ArrayRef<Symbol *> syms = f.getSymbols(); | |
| 164 | ArrayRef<lto::InputFile::Symbol> objSyms = obj.symbols(); | |
| 165 | std::vector<lto::SymbolResolution> resols(syms.size()); | |
| 165 | 166 | |
| 166 | 167 | // Provide a resolution to the LTO API for each symbol. |
| 167 | for (size_t I = 0, E = Syms.size(); I != E; ++I) { | |
| 168 | Symbol *Sym = Syms[I]; | |
| 169 | const lto::InputFile::Symbol &ObjSym = ObjSyms[I]; | |
| 170 | lto::SymbolResolution &R = Resols[I]; | |
| 168 | for (size_t i = 0, e = syms.size(); i != e; ++i) { | |
| 169 | Symbol *sym = syms[i]; | |
| 170 | const lto::InputFile::Symbol &objSym = objSyms[i]; | |
| 171 | lto::SymbolResolution &r = resols[i]; | |
| 171 | 172 | |
| 172 | 173 | // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile |
| 173 | 174 | // reports two symbols for module ASM defined. Without this check, lld |
| 174 | 175 | // flags an undefined in IR with a definition in ASM as prevailing. |
| 175 | 176 | // Once IRObjectFile is fixed to report only one symbol this hack can |
| 176 | 177 | // be removed. |
| 177 | R.Prevailing = !ObjSym.isUndefined() && Sym->File == &F; | |
| 178 | r.Prevailing = !objSym.isUndefined() && sym->file == &f; | |
| 178 | 179 | |
| 179 | 180 | // We ask LTO to preserve following global symbols: |
| 180 | 181 | // 1) All symbols when doing relocatable link, so that them can be used |
| ... | ... | @@ -182,115 +183,121 @@ void BitcodeCompiler::add(BitcodeFile &F) { |
| 182 | 183 | // 2) Symbols that are used in regular objects. |
| 183 | 184 | // 3) C named sections if we have corresponding __start_/__stop_ symbol. |
| 184 | 185 | // 4) Symbols that are defined in bitcode files and used for dynamic linking. |
| 185 | R.VisibleToRegularObj = Config->Relocatable || Sym->IsUsedInRegularObj || | |
| 186 | (R.Prevailing && Sym->includeInDynsym()) || | |
| 187 | UsedStartStop.count(ObjSym.getSectionName()); | |
| 188 | const auto *DR = dyn_cast<Defined>(Sym); | |
| 189 | R.FinalDefinitionInLinkageUnit = | |
| 190 | (IsExec || Sym->Visibility != STV_DEFAULT) && DR && | |
| 186 | r.VisibleToRegularObj = config->relocatable || sym->isUsedInRegularObj || | |
| 187 | (r.Prevailing && sym->includeInDynsym()) || | |
| 188 | usedStartStop.count(objSym.getSectionName()); | |
| 189 | const auto *dr = dyn_cast<Defined>(sym); | |
| 190 | r.FinalDefinitionInLinkageUnit = | |
| 191 | (isExec || sym->visibility != STV_DEFAULT) && dr && | |
| 191 | 192 | // Skip absolute symbols from ELF objects, otherwise PC-rel relocations |
| 192 | 193 | // will be generated by for them, triggering linker errors. |
| 193 | 194 | // Symbol section is always null for bitcode symbols, hence the check |
| 194 | 195 | // for isElf(). Skip linker script defined symbols as well: they have |
| 195 | 196 | // no File defined. |
| 196 | !(DR->Section == nullptr && (!Sym->File || Sym->File->isElf())); | |
| 197 | !(dr->section == nullptr && (!sym->file || sym->file->isElf())); | |
| 197 | 198 | |
| 198 | if (R.Prevailing) | |
| 199 | undefine(Sym); | |
| 199 | if (r.Prevailing) | |
| 200 | sym->replace(Undefined{nullptr, sym->getName(), STB_GLOBAL, STV_DEFAULT, | |
| 201 | sym->type}); | |
| 200 | 202 | |
| 201 | 203 | // We tell LTO to not apply interprocedural optimization for wrapped |
| 202 | 204 | // (with --wrap) symbols because otherwise LTO would inline them while |
| 203 | 205 | // their values are still not final. |
| 204 | R.LinkerRedefined = !Sym->CanInline; | |
| 206 | r.LinkerRedefined = !sym->canInline; | |
| 205 | 207 | } |
| 206 | checkError(LTOObj->add(std::move(F.Obj), Resols)); | |
| 208 | checkError(ltoObj->add(std::move(f.obj), resols)); | |
| 207 | 209 | } |
| 208 | 210 | |
| 209 | static void createEmptyIndex(StringRef ModulePath) { | |
| 210 | std::string Path = replaceThinLTOSuffix(getThinLTOOutputFile(ModulePath)); | |
| 211 | std::unique_ptr<raw_fd_ostream> OS = openFile(Path + ".thinlto.bc"); | |
| 212 | if (!OS) | |
| 213 | return; | |
| 214 | ||
| 215 | ModuleSummaryIndex M(/*HaveGVs*/ false); | |
| 216 | M.setSkipModuleByDistributedBackend(); | |
| 217 | WriteIndexToFile(M, *OS); | |
| 211 | // If LazyObjFile has not been added to link, emit empty index files. | |
| 212 | // This is needed because this is what GNU gold plugin does and we have a | |
| 213 | // distributed build system that depends on that behavior. | |
| 214 | static void thinLTOCreateEmptyIndexFiles() { | |
| 215 | for (LazyObjFile *f : lazyObjFiles) { | |
| 216 | if (!isBitcode(f->mb)) | |
| 217 | continue; | |
| 218 | std::string path = replaceThinLTOSuffix(getThinLTOOutputFile(f->getName())); | |
| 219 | std::unique_ptr<raw_fd_ostream> os = openFile(path + ".thinlto.bc"); | |
| 220 | if (!os) | |
| 221 | continue; | |
| 218 | 222 | |
| 219 | if (Config->ThinLTOEmitImportsFiles) | |
| 220 | openFile(Path + ".imports"); | |
| 223 | ModuleSummaryIndex m(/*HaveGVs*/ false); | |
| 224 | m.setSkipModuleByDistributedBackend(); | |
| 225 | WriteIndexToFile(m, *os); | |
| 226 | if (config->thinLTOEmitImportsFiles) | |
| 227 | openFile(path + ".imports"); | |
| 228 | } | |
| 221 | 229 | } |
| 222 | 230 | |
| 223 | 231 | // Merge all the bitcode files we have seen, codegen the result |
| 224 | 232 | // and return the resulting ObjectFile(s). |
| 225 | 233 | std::vector<InputFile *> BitcodeCompiler::compile() { |
| 226 | unsigned MaxTasks = LTOObj->getMaxTasks(); | |
| 227 | Buf.resize(MaxTasks); | |
| 228 | Files.resize(MaxTasks); | |
| 234 | unsigned maxTasks = ltoObj->getMaxTasks(); | |
| 235 | buf.resize(maxTasks); | |
| 236 | files.resize(maxTasks); | |
| 229 | 237 | |
| 230 | 238 | // The --thinlto-cache-dir option specifies the path to a directory in which |
| 231 | 239 | // to cache native object files for ThinLTO incremental builds. If a path was |
| 232 | 240 | // specified, configure LTO to use it as the cache directory. |
| 233 | lto::NativeObjectCache Cache; | |
| 234 | if (!Config->ThinLTOCacheDir.empty()) | |
| 235 | Cache = check( | |
| 236 | lto::localCache(Config->ThinLTOCacheDir, | |
| 237 | [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) { | |
| 238 | Files[Task] = std::move(MB); | |
| 241 | lto::NativeObjectCache cache; | |
| 242 | if (!config->thinLTOCacheDir.empty()) | |
| 243 | cache = check( | |
| 244 | lto::localCache(config->thinLTOCacheDir, | |
| 245 | [&](size_t task, std::unique_ptr<MemoryBuffer> mb) { | |
| 246 | files[task] = std::move(mb); | |
| 239 | 247 | })); |
| 240 | 248 | |
| 241 | checkError(LTOObj->run( | |
| 242 | [&](size_t Task) { | |
| 243 | return llvm::make_unique<lto::NativeObjectStream>( | |
| 244 | llvm::make_unique<raw_svector_ostream>(Buf[Task])); | |
| 245 | }, | |
| 246 | Cache)); | |
| 249 | if (!bitcodeFiles.empty()) | |
| 250 | checkError(ltoObj->run( | |
| 251 | [&](size_t task) { | |
| 252 | return llvm::make_unique<lto::NativeObjectStream>( | |
| 253 | llvm::make_unique<raw_svector_ostream>(buf[task])); | |
| 254 | }, | |
| 255 | cache)); | |
| 247 | 256 | |
| 248 | 257 | // Emit empty index files for non-indexed files |
| 249 | for (StringRef S : ThinIndices) { | |
| 250 | std::string Path = getThinLTOOutputFile(S); | |
| 251 | openFile(Path + ".thinlto.bc"); | |
| 252 | if (Config->ThinLTOEmitImportsFiles) | |
| 253 | openFile(Path + ".imports"); | |
| 258 | for (StringRef s : thinIndices) { | |
| 259 | std::string path = getThinLTOOutputFile(s); | |
| 260 | openFile(path + ".thinlto.bc"); | |
| 261 | if (config->thinLTOEmitImportsFiles) | |
| 262 | openFile(path + ".imports"); | |
| 254 | 263 | } |
| 255 | 264 | |
| 256 | // If LazyObjFile has not been added to link, emit empty index files. | |
| 257 | // This is needed because this is what GNU gold plugin does and we have a | |
| 258 | // distributed build system that depends on that behavior. | |
| 259 | if (Config->ThinLTOIndexOnly) { | |
| 260 | for (LazyObjFile *F : LazyObjFiles) | |
| 261 | if (!F->AddedToLink && isBitcode(F->MB)) | |
| 262 | createEmptyIndex(F->getName()); | |
| 265 | if (config->thinLTOIndexOnly) { | |
| 266 | thinLTOCreateEmptyIndexFiles(); | |
| 263 | 267 | |
| 264 | if (!Config->LTOObjPath.empty()) | |
| 265 | saveBuffer(Buf[0], Config->LTOObjPath); | |
| 268 | if (!config->ltoObjPath.empty()) | |
| 269 | saveBuffer(buf[0], config->ltoObjPath); | |
| 266 | 270 | |
| 267 | 271 | // ThinLTO with index only option is required to generate only the index |
| 268 | 272 | // files. After that, we exit from linker and ThinLTO backend runs in a |
| 269 | 273 | // distributed environment. |
| 270 | if (IndexFile) | |
| 271 | IndexFile->close(); | |
| 274 | if (indexFile) | |
| 275 | indexFile->close(); | |
| 272 | 276 | return {}; |
| 273 | 277 | } |
| 274 | 278 | |
| 275 | if (!Config->ThinLTOCacheDir.empty()) | |
| 276 | pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy); | |
| 279 | if (!config->thinLTOCacheDir.empty()) | |
| 280 | pruneCache(config->thinLTOCacheDir, config->thinLTOCachePolicy); | |
| 277 | 281 | |
| 278 | std::vector<InputFile *> Ret; | |
| 279 | for (unsigned I = 0; I != MaxTasks; ++I) { | |
| 280 | if (Buf[I].empty()) | |
| 281 | continue; | |
| 282 | if (Config->SaveTemps) { | |
| 283 | if (I == 0) | |
| 284 | saveBuffer(Buf[I], Config->OutputFile + ".lto.o"); | |
| 285 | else | |
| 286 | saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.o"); | |
| 287 | } | |
| 288 | InputFile *Obj = createObjectFile(MemoryBufferRef(Buf[I], "lto.tmp")); | |
| 289 | Ret.push_back(Obj); | |
| 282 | if (!config->ltoObjPath.empty()) { | |
| 283 | saveBuffer(buf[0], config->ltoObjPath); | |
| 284 | for (unsigned i = 1; i != maxTasks; ++i) | |
| 285 | saveBuffer(buf[i], config->ltoObjPath + Twine(i)); | |
| 290 | 286 | } |
| 291 | 287 | |
| 292 | for (std::unique_ptr<MemoryBuffer> &File : Files) | |
| 293 | if (File) | |
| 294 | Ret.push_back(createObjectFile(*File)); | |
| 295 | return Ret; | |
| 288 | if (config->saveTemps) { | |
| 289 | saveBuffer(buf[0], config->outputFile + ".lto.o"); | |
| 290 | for (unsigned i = 1; i != maxTasks; ++i) | |
| 291 | saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.o"); | |
| 292 | } | |
| 293 | ||
| 294 | std::vector<InputFile *> ret; | |
| 295 | for (unsigned i = 0; i != maxTasks; ++i) | |
| 296 | if (!buf[i].empty()) | |
| 297 | ret.push_back(createObjectFile(MemoryBufferRef(buf[i], "lto.tmp"))); | |
| 298 | ||
| 299 | for (std::unique_ptr<MemoryBuffer> &file : files) | |
| 300 | if (file) | |
| 301 | ret.push_back(createObjectFile(*file)); | |
| 302 | return ret; | |
| 296 | 303 | } |
deps/lld/ELF/LTO.h+10-11| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- LTO.h ----------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -46,16 +45,16 @@ public: |
| 46 | 45 | BitcodeCompiler(); |
| 47 | 46 | ~BitcodeCompiler(); |
| 48 | 47 | |
| 49 | void add(BitcodeFile &F); | |
| 48 | void add(BitcodeFile &f); | |
| 50 | 49 | std::vector<InputFile *> compile(); |
| 51 | 50 | |
| 52 | 51 | private: |
| 53 | std::unique_ptr<llvm::lto::LTO> LTOObj; | |
| 54 | std::vector<SmallString<0>> Buf; | |
| 55 | std::vector<std::unique_ptr<MemoryBuffer>> Files; | |
| 56 | llvm::DenseSet<StringRef> UsedStartStop; | |
| 57 | std::unique_ptr<llvm::raw_fd_ostream> IndexFile; | |
| 58 | llvm::DenseSet<StringRef> ThinIndices; | |
| 52 | std::unique_ptr<llvm::lto::LTO> ltoObj; | |
| 53 | std::vector<SmallString<0>> buf; | |
| 54 | std::vector<std::unique_ptr<MemoryBuffer>> files; | |
| 55 | llvm::DenseSet<StringRef> usedStartStop; | |
| 56 | std::unique_ptr<llvm::raw_fd_ostream> indexFile; | |
| 57 | llvm::DenseSet<StringRef> thinIndices; | |
| 59 | 58 | }; |
| 60 | 59 | } // namespace elf |
| 61 | 60 | } // namespace lld |
deps/lld/ELF/LinkerScript.cpp+516-502| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- LinkerScript.cpp ---------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -47,26 +46,26 @@ using namespace llvm::support::endian; |
| 47 | 46 | using namespace lld; |
| 48 | 47 | using namespace lld::elf; |
| 49 | 48 | |
| 50 | LinkerScript *elf::Script; | |
| 49 | LinkerScript *elf::script; | |
| 51 | 50 | |
| 52 | static uint64_t getOutputSectionVA(SectionBase *InputSec, StringRef Loc) { | |
| 53 | if (OutputSection *OS = InputSec->getOutputSection()) | |
| 54 | return OS->Addr; | |
| 55 | error(Loc + ": unable to evaluate expression: input section " + | |
| 56 | InputSec->Name + " has no output section assigned"); | |
| 51 | static uint64_t getOutputSectionVA(SectionBase *inputSec, StringRef loc) { | |
| 52 | if (OutputSection *os = inputSec->getOutputSection()) | |
| 53 | return os->addr; | |
| 54 | error(loc + ": unable to evaluate expression: input section " + | |
| 55 | inputSec->name + " has no output section assigned"); | |
| 57 | 56 | return 0; |
| 58 | 57 | } |
| 59 | 58 | |
| 60 | 59 | uint64_t ExprValue::getValue() const { |
| 61 | if (Sec) | |
| 62 | return alignTo(Sec->getOffset(Val) + getOutputSectionVA(Sec, Loc), | |
| 63 | Alignment); | |
| 64 | return alignTo(Val, Alignment); | |
| 60 | if (sec) | |
| 61 | return alignTo(sec->getOffset(val) + getOutputSectionVA(sec, loc), | |
| 62 | alignment); | |
| 63 | return alignTo(val, alignment); | |
| 65 | 64 | } |
| 66 | 65 | |
| 67 | 66 | uint64_t ExprValue::getSecAddr() const { |
| 68 | if (Sec) | |
| 69 | return Sec->getOffset(0) + getOutputSectionVA(Sec, Loc); | |
| 67 | if (sec) | |
| 68 | return sec->getOffset(0) + getOutputSectionVA(sec, loc); | |
| 70 | 69 | return 0; |
| 71 | 70 | } |
| 72 | 71 | |
| ... | ... | @@ -74,106 +73,100 @@ uint64_t ExprValue::getSectionOffset() const { |
| 74 | 73 | // If the alignment is trivial, we don't have to compute the full |
| 75 | 74 | // value to know the offset. This allows this function to succeed in |
| 76 | 75 | // cases where the output section is not yet known. |
| 77 | if (Alignment == 1 && (!Sec || !Sec->getOutputSection())) | |
| 78 | return Val; | |
| 76 | if (alignment == 1 && (!sec || !sec->getOutputSection())) | |
| 77 | return val; | |
| 79 | 78 | return getValue() - getSecAddr(); |
| 80 | 79 | } |
| 81 | 80 | |
| 82 | OutputSection *LinkerScript::createOutputSection(StringRef Name, | |
| 83 | StringRef Location) { | |
| 84 | OutputSection *&SecRef = NameToOutputSection[Name]; | |
| 85 | OutputSection *Sec; | |
| 86 | if (SecRef && SecRef->Location.empty()) { | |
| 81 | OutputSection *LinkerScript::createOutputSection(StringRef name, | |
| 82 | StringRef location) { | |
| 83 | OutputSection *&secRef = nameToOutputSection[name]; | |
| 84 | OutputSection *sec; | |
| 85 | if (secRef && secRef->location.empty()) { | |
| 87 | 86 | // There was a forward reference. |
| 88 | Sec = SecRef; | |
| 87 | sec = secRef; | |
| 89 | 88 | } else { |
| 90 | Sec = make<OutputSection>(Name, SHT_NOBITS, 0); | |
| 91 | if (!SecRef) | |
| 92 | SecRef = Sec; | |
| 89 | sec = make<OutputSection>(name, SHT_PROGBITS, 0); | |
| 90 | if (!secRef) | |
| 91 | secRef = sec; | |
| 93 | 92 | } |
| 94 | Sec->Location = Location; | |
| 95 | return Sec; | |
| 93 | sec->location = location; | |
| 94 | return sec; | |
| 96 | 95 | } |
| 97 | 96 | |
| 98 | OutputSection *LinkerScript::getOrCreateOutputSection(StringRef Name) { | |
| 99 | OutputSection *&CmdRef = NameToOutputSection[Name]; | |
| 100 | if (!CmdRef) | |
| 101 | CmdRef = make<OutputSection>(Name, SHT_PROGBITS, 0); | |
| 102 | return CmdRef; | |
| 97 | OutputSection *LinkerScript::getOrCreateOutputSection(StringRef name) { | |
| 98 | OutputSection *&cmdRef = nameToOutputSection[name]; | |
| 99 | if (!cmdRef) | |
| 100 | cmdRef = make<OutputSection>(name, SHT_PROGBITS, 0); | |
| 101 | return cmdRef; | |
| 103 | 102 | } |
| 104 | 103 | |
| 105 | 104 | // Expands the memory region by the specified size. |
| 106 | static void expandMemoryRegion(MemoryRegion *MemRegion, uint64_t Size, | |
| 107 | StringRef RegionName, StringRef SecName) { | |
| 108 | MemRegion->CurPos += Size; | |
| 109 | uint64_t NewSize = MemRegion->CurPos - MemRegion->Origin; | |
| 110 | if (NewSize > MemRegion->Length) | |
| 111 | error("section '" + SecName + "' will not fit in region '" + RegionName + | |
| 112 | "': overflowed by " + Twine(NewSize - MemRegion->Length) + " bytes"); | |
| 105 | static void expandMemoryRegion(MemoryRegion *memRegion, uint64_t size, | |
| 106 | StringRef regionName, StringRef secName) { | |
| 107 | memRegion->curPos += size; | |
| 108 | uint64_t newSize = memRegion->curPos - memRegion->origin; | |
| 109 | if (newSize > memRegion->length) | |
| 110 | error("section '" + secName + "' will not fit in region '" + regionName + | |
| 111 | "': overflowed by " + Twine(newSize - memRegion->length) + " bytes"); | |
| 113 | 112 | } |
| 114 | 113 | |
| 115 | void LinkerScript::expandMemoryRegions(uint64_t Size) { | |
| 116 | if (Ctx->MemRegion) | |
| 117 | expandMemoryRegion(Ctx->MemRegion, Size, Ctx->MemRegion->Name, | |
| 118 | Ctx->OutSec->Name); | |
| 119 | // Only expand the LMARegion if it is different from MemRegion. | |
| 120 | if (Ctx->LMARegion && Ctx->MemRegion != Ctx->LMARegion) | |
| 121 | expandMemoryRegion(Ctx->LMARegion, Size, Ctx->LMARegion->Name, | |
| 122 | Ctx->OutSec->Name); | |
| 114 | void LinkerScript::expandMemoryRegions(uint64_t size) { | |
| 115 | if (ctx->memRegion) | |
| 116 | expandMemoryRegion(ctx->memRegion, size, ctx->memRegion->name, | |
| 117 | ctx->outSec->name); | |
| 118 | // Only expand the LMARegion if it is different from memRegion. | |
| 119 | if (ctx->lmaRegion && ctx->memRegion != ctx->lmaRegion) | |
| 120 | expandMemoryRegion(ctx->lmaRegion, size, ctx->lmaRegion->name, | |
| 121 | ctx->outSec->name); | |
| 123 | 122 | } |
| 124 | 123 | |
| 125 | void LinkerScript::expandOutputSection(uint64_t Size) { | |
| 126 | Ctx->OutSec->Size += Size; | |
| 127 | expandMemoryRegions(Size); | |
| 124 | void LinkerScript::expandOutputSection(uint64_t size) { | |
| 125 | ctx->outSec->size += size; | |
| 126 | expandMemoryRegions(size); | |
| 128 | 127 | } |
| 129 | 128 | |
| 130 | void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { | |
| 131 | uint64_t Val = E().getValue(); | |
| 132 | if (Val < Dot && InSec) | |
| 133 | error(Loc + ": unable to move location counter backward for: " + | |
| 134 | Ctx->OutSec->Name); | |
| 129 | void LinkerScript::setDot(Expr e, const Twine &loc, bool inSec) { | |
| 130 | uint64_t val = e().getValue(); | |
| 131 | if (val < dot && inSec) | |
| 132 | error(loc + ": unable to move location counter backward for: " + | |
| 133 | ctx->outSec->name); | |
| 135 | 134 | |
| 136 | 135 | // Update to location counter means update to section size. |
| 137 | if (InSec) | |
| 138 | expandOutputSection(Val - Dot); | |
| 139 | else | |
| 140 | expandMemoryRegions(Val - Dot); | |
| 136 | if (inSec) | |
| 137 | expandOutputSection(val - dot); | |
| 141 | 138 | |
| 142 | Dot = Val; | |
| 139 | dot = val; | |
| 143 | 140 | } |
| 144 | 141 | |
| 145 | 142 | // Used for handling linker symbol assignments, for both finalizing |
| 146 | 143 | // their values and doing early declarations. Returns true if symbol |
| 147 | 144 | // should be defined from linker script. |
| 148 | static bool shouldDefineSym(SymbolAssignment *Cmd) { | |
| 149 | if (Cmd->Name == ".") | |
| 145 | static bool shouldDefineSym(SymbolAssignment *cmd) { | |
| 146 | if (cmd->name == ".") | |
| 150 | 147 | return false; |
| 151 | 148 | |
| 152 | if (!Cmd->Provide) | |
| 149 | if (!cmd->provide) | |
| 153 | 150 | return true; |
| 154 | 151 | |
| 155 | 152 | // If a symbol was in PROVIDE(), we need to define it only |
| 156 | 153 | // when it is a referenced undefined symbol. |
| 157 | Symbol *B = Symtab->find(Cmd->Name); | |
| 158 | if (B && !B->isDefined()) | |
| 154 | Symbol *b = symtab->find(cmd->name); | |
| 155 | if (b && !b->isDefined()) | |
| 159 | 156 | return true; |
| 160 | 157 | return false; |
| 161 | 158 | } |
| 162 | 159 | |
| 163 | 160 | // This function is called from processSectionCommands, |
| 164 | 161 | // while we are fixing the output section layout. |
| 165 | void LinkerScript::addSymbol(SymbolAssignment *Cmd) { | |
| 166 | if (!shouldDefineSym(Cmd)) | |
| 162 | void LinkerScript::addSymbol(SymbolAssignment *cmd) { | |
| 163 | if (!shouldDefineSym(cmd)) | |
| 167 | 164 | return; |
| 168 | 165 | |
| 169 | 166 | // Define a symbol. |
| 170 | Symbol *Sym; | |
| 171 | uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; | |
| 172 | std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, Visibility, | |
| 173 | /*CanOmitFromDynSym*/ false, | |
| 174 | /*File*/ nullptr); | |
| 175 | ExprValue Value = Cmd->Expression(); | |
| 176 | SectionBase *Sec = Value.isAbsolute() ? nullptr : Value.Sec; | |
| 167 | ExprValue value = cmd->expression(); | |
| 168 | SectionBase *sec = value.isAbsolute() ? nullptr : value.sec; | |
| 169 | uint8_t visibility = cmd->hidden ? STV_HIDDEN : STV_DEFAULT; | |
| 177 | 170 | |
| 178 | 171 | // When this function is called, section addresses have not been |
| 179 | 172 | // fixed yet. So, we may or may not know the value of the RHS |
| ... | ... | @@ -186,68 +179,73 @@ void LinkerScript::addSymbol(SymbolAssignment *Cmd) { |
| 186 | 179 | // We want to set symbol values early if we can. This allows us to |
| 187 | 180 | // use symbols as variables in linker scripts. Doing so allows us to |
| 188 | 181 | // write expressions like this: `alignment = 16; . = ALIGN(., alignment)`. |
| 189 | uint64_t SymValue = Value.Sec ? 0 : Value.getValue(); | |
| 182 | uint64_t symValue = value.sec ? 0 : value.getValue(); | |
| 183 | ||
| 184 | Defined New(nullptr, cmd->name, STB_GLOBAL, visibility, STT_NOTYPE, symValue, | |
| 185 | 0, sec); | |
| 190 | 186 | |
| 191 | replaceSymbol<Defined>(Sym, nullptr, Cmd->Name, STB_GLOBAL, Visibility, | |
| 192 | STT_NOTYPE, SymValue, 0, Sec); | |
| 193 | Cmd->Sym = cast<Defined>(Sym); | |
| 187 | Symbol *sym = symtab->insert(cmd->name); | |
| 188 | sym->mergeProperties(New); | |
| 189 | sym->replace(New); | |
| 190 | cmd->sym = cast<Defined>(sym); | |
| 194 | 191 | } |
| 195 | 192 | |
| 196 | 193 | // This function is called from LinkerScript::declareSymbols. |
| 197 | 194 | // It creates a placeholder symbol if needed. |
| 198 | static void declareSymbol(SymbolAssignment *Cmd) { | |
| 199 | if (!shouldDefineSym(Cmd)) | |
| 195 | static void declareSymbol(SymbolAssignment *cmd) { | |
| 196 | if (!shouldDefineSym(cmd)) | |
| 200 | 197 | return; |
| 201 | 198 | |
| 199 | uint8_t visibility = cmd->hidden ? STV_HIDDEN : STV_DEFAULT; | |
| 200 | Defined New(nullptr, cmd->name, STB_GLOBAL, visibility, STT_NOTYPE, 0, 0, | |
| 201 | nullptr); | |
| 202 | ||
| 202 | 203 | // We can't calculate final value right now. |
| 203 | Symbol *Sym; | |
| 204 | uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; | |
| 205 | std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, Visibility, | |
| 206 | /*CanOmitFromDynSym*/ false, | |
| 207 | /*File*/ nullptr); | |
| 208 | replaceSymbol<Defined>(Sym, nullptr, Cmd->Name, STB_GLOBAL, Visibility, | |
| 209 | STT_NOTYPE, 0, 0, nullptr); | |
| 210 | Cmd->Sym = cast<Defined>(Sym); | |
| 211 | Cmd->Provide = false; | |
| 212 | Sym->ScriptDefined = true; | |
| 204 | Symbol *sym = symtab->insert(cmd->name); | |
| 205 | sym->mergeProperties(New); | |
| 206 | sym->replace(New); | |
| 207 | ||
| 208 | cmd->sym = cast<Defined>(sym); | |
| 209 | cmd->provide = false; | |
| 210 | sym->scriptDefined = true; | |
| 213 | 211 | } |
| 214 | 212 | |
| 215 | 213 | // This method is used to handle INSERT AFTER statement. Here we rebuild |
| 216 | 214 | // the list of script commands to mix sections inserted into. |
| 217 | 215 | void LinkerScript::processInsertCommands() { |
| 218 | std::vector<BaseCommand *> V; | |
| 219 | auto Insert = [&](std::vector<BaseCommand *> &From) { | |
| 220 | V.insert(V.end(), From.begin(), From.end()); | |
| 221 | From.clear(); | |
| 216 | std::vector<BaseCommand *> v; | |
| 217 | auto insert = [&](std::vector<BaseCommand *> &from) { | |
| 218 | v.insert(v.end(), from.begin(), from.end()); | |
| 219 | from.clear(); | |
| 222 | 220 | }; |
| 223 | 221 | |
| 224 | for (BaseCommand *Base : SectionCommands) { | |
| 225 | if (auto *OS = dyn_cast<OutputSection>(Base)) { | |
| 226 | Insert(InsertBeforeCommands[OS->Name]); | |
| 227 | V.push_back(Base); | |
| 228 | Insert(InsertAfterCommands[OS->Name]); | |
| 222 | for (BaseCommand *base : sectionCommands) { | |
| 223 | if (auto *os = dyn_cast<OutputSection>(base)) { | |
| 224 | insert(insertBeforeCommands[os->name]); | |
| 225 | v.push_back(base); | |
| 226 | insert(insertAfterCommands[os->name]); | |
| 229 | 227 | continue; |
| 230 | 228 | } |
| 231 | V.push_back(Base); | |
| 229 | v.push_back(base); | |
| 232 | 230 | } |
| 233 | 231 | |
| 234 | for (auto &Cmds : {InsertBeforeCommands, InsertAfterCommands}) | |
| 235 | for (const std::pair<StringRef, std::vector<BaseCommand *>> &P : Cmds) | |
| 236 | if (!P.second.empty()) | |
| 237 | error("unable to INSERT AFTER/BEFORE " + P.first + | |
| 232 | for (auto &cmds : {insertBeforeCommands, insertAfterCommands}) | |
| 233 | for (const std::pair<StringRef, std::vector<BaseCommand *>> &p : cmds) | |
| 234 | if (!p.second.empty()) | |
| 235 | error("unable to INSERT AFTER/BEFORE " + p.first + | |
| 238 | 236 | ": section not defined"); |
| 239 | 237 | |
| 240 | SectionCommands = std::move(V); | |
| 238 | sectionCommands = std::move(v); | |
| 241 | 239 | } |
| 242 | 240 | |
| 243 | 241 | // Symbols defined in script should not be inlined by LTO. At the same time |
| 244 | 242 | // we don't know their final values until late stages of link. Here we scan |
| 245 | 243 | // over symbol assignment commands and create placeholder symbols if needed. |
| 246 | 244 | void LinkerScript::declareSymbols() { |
| 247 | assert(!Ctx); | |
| 248 | for (BaseCommand *Base : SectionCommands) { | |
| 249 | if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { | |
| 250 | declareSymbol(Cmd); | |
| 245 | assert(!ctx); | |
| 246 | for (BaseCommand *base : sectionCommands) { | |
| 247 | if (auto *cmd = dyn_cast<SymbolAssignment>(base)) { | |
| 248 | declareSymbol(cmd); | |
| 251 | 249 | continue; |
| 252 | 250 | } |
| 253 | 251 | |
| ... | ... | @@ -255,75 +253,75 @@ void LinkerScript::declareSymbols() { |
| 255 | 253 | // we can't say for sure if it is going to be included or not. |
| 256 | 254 | // Skip such sections for now. Improve the checks if we ever |
| 257 | 255 | // need symbols from that sections to be declared early. |
| 258 | auto *Sec = cast<OutputSection>(Base); | |
| 259 | if (Sec->Constraint != ConstraintKind::NoConstraint) | |
| 256 | auto *sec = cast<OutputSection>(base); | |
| 257 | if (sec->constraint != ConstraintKind::NoConstraint) | |
| 260 | 258 | continue; |
| 261 | for (BaseCommand *Base2 : Sec->SectionCommands) | |
| 262 | if (auto *Cmd = dyn_cast<SymbolAssignment>(Base2)) | |
| 263 | declareSymbol(Cmd); | |
| 259 | for (BaseCommand *base2 : sec->sectionCommands) | |
| 260 | if (auto *cmd = dyn_cast<SymbolAssignment>(base2)) | |
| 261 | declareSymbol(cmd); | |
| 264 | 262 | } |
| 265 | 263 | } |
| 266 | 264 | |
| 267 | 265 | // This function is called from assignAddresses, while we are |
| 268 | 266 | // fixing the output section addresses. This function is supposed |
| 269 | 267 | // to set the final value for a given symbol assignment. |
| 270 | void LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) { | |
| 271 | if (Cmd->Name == ".") { | |
| 272 | setDot(Cmd->Expression, Cmd->Location, InSec); | |
| 268 | void LinkerScript::assignSymbol(SymbolAssignment *cmd, bool inSec) { | |
| 269 | if (cmd->name == ".") { | |
| 270 | setDot(cmd->expression, cmd->location, inSec); | |
| 273 | 271 | return; |
| 274 | 272 | } |
| 275 | 273 | |
| 276 | if (!Cmd->Sym) | |
| 274 | if (!cmd->sym) | |
| 277 | 275 | return; |
| 278 | 276 | |
| 279 | ExprValue V = Cmd->Expression(); | |
| 280 | if (V.isAbsolute()) { | |
| 281 | Cmd->Sym->Section = nullptr; | |
| 282 | Cmd->Sym->Value = V.getValue(); | |
| 277 | ExprValue v = cmd->expression(); | |
| 278 | if (v.isAbsolute()) { | |
| 279 | cmd->sym->section = nullptr; | |
| 280 | cmd->sym->value = v.getValue(); | |
| 283 | 281 | } else { |
| 284 | Cmd->Sym->Section = V.Sec; | |
| 285 | Cmd->Sym->Value = V.getSectionOffset(); | |
| 282 | cmd->sym->section = v.sec; | |
| 283 | cmd->sym->value = v.getSectionOffset(); | |
| 286 | 284 | } |
| 287 | 285 | } |
| 288 | 286 | |
| 289 | static std::string getFilename(InputFile *File) { | |
| 290 | if (!File) | |
| 287 | static std::string getFilename(InputFile *file) { | |
| 288 | if (!file) | |
| 291 | 289 | return ""; |
| 292 | if (File->ArchiveName.empty()) | |
| 293 | return File->getName(); | |
| 294 | return (File->ArchiveName + "(" + File->getName() + ")").str(); | |
| 290 | if (file->archiveName.empty()) | |
| 291 | return file->getName(); | |
| 292 | return (file->archiveName + "(" + file->getName() + ")").str(); | |
| 295 | 293 | } |
| 296 | 294 | |
| 297 | bool LinkerScript::shouldKeep(InputSectionBase *S) { | |
| 298 | if (KeptSections.empty()) | |
| 295 | bool LinkerScript::shouldKeep(InputSectionBase *s) { | |
| 296 | if (keptSections.empty()) | |
| 299 | 297 | return false; |
| 300 | std::string Filename = getFilename(S->File); | |
| 301 | for (InputSectionDescription *ID : KeptSections) | |
| 302 | if (ID->FilePat.match(Filename)) | |
| 303 | for (SectionPattern &P : ID->SectionPatterns) | |
| 304 | if (P.SectionPat.match(S->Name)) | |
| 298 | std::string filename = getFilename(s->file); | |
| 299 | for (InputSectionDescription *id : keptSections) | |
| 300 | if (id->filePat.match(filename)) | |
| 301 | for (SectionPattern &p : id->sectionPatterns) | |
| 302 | if (p.sectionPat.match(s->name)) | |
| 305 | 303 | return true; |
| 306 | 304 | return false; |
| 307 | 305 | } |
| 308 | 306 | |
| 309 | 307 | // A helper function for the SORT() command. |
| 310 | 308 | static std::function<bool(InputSectionBase *, InputSectionBase *)> |
| 311 | getComparator(SortSectionPolicy K) { | |
| 312 | switch (K) { | |
| 309 | getComparator(SortSectionPolicy k) { | |
| 310 | switch (k) { | |
| 313 | 311 | case SortSectionPolicy::Alignment: |
| 314 | return [](InputSectionBase *A, InputSectionBase *B) { | |
| 312 | return [](InputSectionBase *a, InputSectionBase *b) { | |
| 315 | 313 | // ">" is not a mistake. Sections with larger alignments are placed |
| 316 | 314 | // before sections with smaller alignments in order to reduce the |
| 317 | 315 | // amount of padding necessary. This is compatible with GNU. |
| 318 | return A->Alignment > B->Alignment; | |
| 316 | return a->alignment > b->alignment; | |
| 319 | 317 | }; |
| 320 | 318 | case SortSectionPolicy::Name: |
| 321 | return [](InputSectionBase *A, InputSectionBase *B) { | |
| 322 | return A->Name < B->Name; | |
| 319 | return [](InputSectionBase *a, InputSectionBase *b) { | |
| 320 | return a->name < b->name; | |
| 323 | 321 | }; |
| 324 | 322 | case SortSectionPolicy::Priority: |
| 325 | return [](InputSectionBase *A, InputSectionBase *B) { | |
| 326 | return getPriority(A->Name) < getPriority(B->Name); | |
| 323 | return [](InputSectionBase *a, InputSectionBase *b) { | |
| 324 | return getPriority(a->name) < getPriority(b->name); | |
| 327 | 325 | }; |
| 328 | 326 | default: |
| 329 | 327 | llvm_unreachable("unknown sort policy"); |
| ... | ... | @@ -331,22 +329,22 @@ getComparator(SortSectionPolicy K) { |
| 331 | 329 | } |
| 332 | 330 | |
| 333 | 331 | // A helper function for the SORT() command. |
| 334 | static bool matchConstraints(ArrayRef<InputSection *> Sections, | |
| 335 | ConstraintKind Kind) { | |
| 336 | if (Kind == ConstraintKind::NoConstraint) | |
| 332 | static bool matchConstraints(ArrayRef<InputSection *> sections, | |
| 333 | ConstraintKind kind) { | |
| 334 | if (kind == ConstraintKind::NoConstraint) | |
| 337 | 335 | return true; |
| 338 | 336 | |
| 339 | bool IsRW = llvm::any_of( | |
| 340 | Sections, [](InputSection *Sec) { return Sec->Flags & SHF_WRITE; }); | |
| 337 | bool isRW = llvm::any_of( | |
| 338 | sections, [](InputSection *sec) { return sec->flags & SHF_WRITE; }); | |
| 341 | 339 | |
| 342 | return (IsRW && Kind == ConstraintKind::ReadWrite) || | |
| 343 | (!IsRW && Kind == ConstraintKind::ReadOnly); | |
| 340 | return (isRW && kind == ConstraintKind::ReadWrite) || | |
| 341 | (!isRW && kind == ConstraintKind::ReadOnly); | |
| 344 | 342 | } |
| 345 | 343 | |
| 346 | static void sortSections(MutableArrayRef<InputSection *> Vec, | |
| 347 | SortSectionPolicy K) { | |
| 348 | if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None) | |
| 349 | std::stable_sort(Vec.begin(), Vec.end(), getComparator(K)); | |
| 344 | static void sortSections(MutableArrayRef<InputSection *> vec, | |
| 345 | SortSectionPolicy k) { | |
| 346 | if (k != SortSectionPolicy::Default && k != SortSectionPolicy::None) | |
| 347 | llvm::stable_sort(vec, getComparator(k)); | |
| 350 | 348 | } |
| 351 | 349 | |
| 352 | 350 | // Sort sections as instructed by SORT-family commands and --sort-section |
| ... | ... | @@ -360,29 +358,29 @@ static void sortSections(MutableArrayRef<InputSection *> Vec, |
| 360 | 358 | // --sort-section is handled as an inner SORT command. |
| 361 | 359 | // 3. If one SORT command is given, and if it is SORT_NONE, don't sort. |
| 362 | 360 | // 4. If no SORT command is given, sort according to --sort-section. |
| 363 | static void sortInputSections(MutableArrayRef<InputSection *> Vec, | |
| 364 | const SectionPattern &Pat) { | |
| 365 | if (Pat.SortOuter == SortSectionPolicy::None) | |
| 361 | static void sortInputSections(MutableArrayRef<InputSection *> vec, | |
| 362 | const SectionPattern &pat) { | |
| 363 | if (pat.sortOuter == SortSectionPolicy::None) | |
| 366 | 364 | return; |
| 367 | 365 | |
| 368 | if (Pat.SortInner == SortSectionPolicy::Default) | |
| 369 | sortSections(Vec, Config->SortSection); | |
| 366 | if (pat.sortInner == SortSectionPolicy::Default) | |
| 367 | sortSections(vec, config->sortSection); | |
| 370 | 368 | else |
| 371 | sortSections(Vec, Pat.SortInner); | |
| 372 | sortSections(Vec, Pat.SortOuter); | |
| 369 | sortSections(vec, pat.sortInner); | |
| 370 | sortSections(vec, pat.sortOuter); | |
| 373 | 371 | } |
| 374 | 372 | |
| 375 | 373 | // Compute and remember which sections the InputSectionDescription matches. |
| 376 | 374 | std::vector<InputSection *> |
| 377 | LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { | |
| 378 | std::vector<InputSection *> Ret; | |
| 375 | LinkerScript::computeInputSections(const InputSectionDescription *cmd) { | |
| 376 | std::vector<InputSection *> ret; | |
| 379 | 377 | |
| 380 | 378 | // Collects all sections that satisfy constraints of Cmd. |
| 381 | for (const SectionPattern &Pat : Cmd->SectionPatterns) { | |
| 382 | size_t SizeBefore = Ret.size(); | |
| 379 | for (const SectionPattern &pat : cmd->sectionPatterns) { | |
| 380 | size_t sizeBefore = ret.size(); | |
| 383 | 381 | |
| 384 | for (InputSectionBase *Sec : InputSections) { | |
| 385 | if (!Sec->Live || Sec->Assigned) | |
| 382 | for (InputSectionBase *sec : inputSections) { | |
| 383 | if (!sec->isLive() || sec->assigned) | |
| 386 | 384 | continue; |
| 387 | 385 | |
| 388 | 386 | // For -emit-relocs we have to ignore entries like |
| ... | ... | @@ -390,59 +388,59 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { |
| 390 | 388 | // which are common because they are in the default bfd script. |
| 391 | 389 | // We do not ignore SHT_REL[A] linker-synthesized sections here because |
| 392 | 390 | // want to support scripts that do custom layout for them. |
| 393 | if (auto *IS = dyn_cast<InputSection>(Sec)) | |
| 394 | if (IS->getRelocatedSection()) | |
| 391 | if (auto *isec = dyn_cast<InputSection>(sec)) | |
| 392 | if (isec->getRelocatedSection()) | |
| 395 | 393 | continue; |
| 396 | 394 | |
| 397 | std::string Filename = getFilename(Sec->File); | |
| 398 | if (!Cmd->FilePat.match(Filename) || | |
| 399 | Pat.ExcludedFilePat.match(Filename) || | |
| 400 | !Pat.SectionPat.match(Sec->Name)) | |
| 395 | std::string filename = getFilename(sec->file); | |
| 396 | if (!cmd->filePat.match(filename) || | |
| 397 | pat.excludedFilePat.match(filename) || | |
| 398 | !pat.sectionPat.match(sec->name)) | |
| 401 | 399 | continue; |
| 402 | 400 | |
| 403 | 401 | // It is safe to assume that Sec is an InputSection |
| 404 | 402 | // because mergeable or EH input sections have already been |
| 405 | 403 | // handled and eliminated. |
| 406 | Ret.push_back(cast<InputSection>(Sec)); | |
| 407 | Sec->Assigned = true; | |
| 404 | ret.push_back(cast<InputSection>(sec)); | |
| 405 | sec->assigned = true; | |
| 408 | 406 | } |
| 409 | 407 | |
| 410 | sortInputSections(MutableArrayRef<InputSection *>(Ret).slice(SizeBefore), | |
| 411 | Pat); | |
| 408 | sortInputSections(MutableArrayRef<InputSection *>(ret).slice(sizeBefore), | |
| 409 | pat); | |
| 412 | 410 | } |
| 413 | return Ret; | |
| 411 | return ret; | |
| 414 | 412 | } |
| 415 | 413 | |
| 416 | void LinkerScript::discard(ArrayRef<InputSection *> V) { | |
| 417 | for (InputSection *S : V) { | |
| 418 | if (S == In.ShStrTab || S == In.RelaDyn || S == In.RelrDyn) | |
| 419 | error("discarding " + S->Name + " section is not allowed"); | |
| 414 | void LinkerScript::discard(ArrayRef<InputSection *> v) { | |
| 415 | for (InputSection *s : v) { | |
| 416 | if (s == in.shStrTab || s == mainPart->relaDyn || s == mainPart->relrDyn) | |
| 417 | error("discarding " + s->name + " section is not allowed"); | |
| 420 | 418 | |
| 421 | 419 | // You can discard .hash and .gnu.hash sections by linker scripts. Since |
| 422 | 420 | // they are synthesized sections, we need to handle them differently than |
| 423 | 421 | // other regular sections. |
| 424 | if (S == In.GnuHashTab) | |
| 425 | In.GnuHashTab = nullptr; | |
| 426 | if (S == In.HashTab) | |
| 427 | In.HashTab = nullptr; | |
| 428 | ||
| 429 | S->Assigned = false; | |
| 430 | S->Live = false; | |
| 431 | discard(S->DependentSections); | |
| 422 | if (s == mainPart->gnuHashTab) | |
| 423 | mainPart->gnuHashTab = nullptr; | |
| 424 | if (s == mainPart->hashTab) | |
| 425 | mainPart->hashTab = nullptr; | |
| 426 | ||
| 427 | s->assigned = false; | |
| 428 | s->markDead(); | |
| 429 | discard(s->dependentSections); | |
| 432 | 430 | } |
| 433 | 431 | } |
| 434 | 432 | |
| 435 | 433 | std::vector<InputSection *> |
| 436 | LinkerScript::createInputSectionList(OutputSection &OutCmd) { | |
| 437 | std::vector<InputSection *> Ret; | |
| 434 | LinkerScript::createInputSectionList(OutputSection &outCmd) { | |
| 435 | std::vector<InputSection *> ret; | |
| 438 | 436 | |
| 439 | for (BaseCommand *Base : OutCmd.SectionCommands) { | |
| 440 | if (auto *Cmd = dyn_cast<InputSectionDescription>(Base)) { | |
| 441 | Cmd->Sections = computeInputSections(Cmd); | |
| 442 | Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end()); | |
| 437 | for (BaseCommand *base : outCmd.sectionCommands) { | |
| 438 | if (auto *cmd = dyn_cast<InputSectionDescription>(base)) { | |
| 439 | cmd->sections = computeInputSections(cmd); | |
| 440 | ret.insert(ret.end(), cmd->sections.begin(), cmd->sections.end()); | |
| 443 | 441 | } |
| 444 | 442 | } |
| 445 | return Ret; | |
| 443 | return ret; | |
| 446 | 444 | } |
| 447 | 445 | |
| 448 | 446 | void LinkerScript::processSectionCommands() { |
| ... | ... | @@ -455,34 +453,34 @@ void LinkerScript::processSectionCommands() { |
| 455 | 453 | // To handle that, create a dummy aether section that fills the void before |
| 456 | 454 | // the linker scripts switches to another section. It has an index of one |
| 457 | 455 | // which will map to whatever the first actual section is. |
| 458 | Aether = make<OutputSection>("", 0, SHF_ALLOC); | |
| 459 | Aether->SectionIndex = 1; | |
| 456 | aether = make<OutputSection>("", 0, SHF_ALLOC); | |
| 457 | aether->sectionIndex = 1; | |
| 460 | 458 | |
| 461 | 459 | // Ctx captures the local AddressState and makes it accessible deliberately. |
| 462 | 460 | // This is needed as there are some cases where we cannot just |
| 463 | 461 | // thread the current state through to a lambda function created by the |
| 464 | 462 | // script parser. |
| 465 | auto Deleter = make_unique<AddressState>(); | |
| 466 | Ctx = Deleter.get(); | |
| 467 | Ctx->OutSec = Aether; | |
| 463 | auto deleter = make_unique<AddressState>(); | |
| 464 | ctx = deleter.get(); | |
| 465 | ctx->outSec = aether; | |
| 468 | 466 | |
| 469 | size_t I = 0; | |
| 467 | size_t i = 0; | |
| 470 | 468 | // Add input sections to output sections. |
| 471 | for (BaseCommand *Base : SectionCommands) { | |
| 469 | for (BaseCommand *base : sectionCommands) { | |
| 472 | 470 | // Handle symbol assignments outside of any output section. |
| 473 | if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { | |
| 474 | addSymbol(Cmd); | |
| 471 | if (auto *cmd = dyn_cast<SymbolAssignment>(base)) { | |
| 472 | addSymbol(cmd); | |
| 475 | 473 | continue; |
| 476 | 474 | } |
| 477 | 475 | |
| 478 | if (auto *Sec = dyn_cast<OutputSection>(Base)) { | |
| 479 | std::vector<InputSection *> V = createInputSectionList(*Sec); | |
| 476 | if (auto *sec = dyn_cast<OutputSection>(base)) { | |
| 477 | std::vector<InputSection *> v = createInputSectionList(*sec); | |
| 480 | 478 | |
| 481 | 479 | // The output section name `/DISCARD/' is special. |
| 482 | 480 | // Any input section assigned to it is discarded. |
| 483 | if (Sec->Name == "/DISCARD/") { | |
| 484 | discard(V); | |
| 485 | Sec->SectionCommands.clear(); | |
| 481 | if (sec->name == "/DISCARD/") { | |
| 482 | discard(v); | |
| 483 | sec->sectionCommands.clear(); | |
| 486 | 484 | continue; |
| 487 | 485 | } |
| 488 | 486 | |
| ... | ... | @@ -493,60 +491,61 @@ void LinkerScript::processSectionCommands() { |
| 493 | 491 | // |
| 494 | 492 | // Because we'll iterate over SectionCommands many more times, the easy |
| 495 | 493 | // way to "make it as if it wasn't present" is to make it empty. |
| 496 | if (!matchConstraints(V, Sec->Constraint)) { | |
| 497 | for (InputSectionBase *S : V) | |
| 498 | S->Assigned = false; | |
| 499 | Sec->SectionCommands.clear(); | |
| 494 | if (!matchConstraints(v, sec->constraint)) { | |
| 495 | for (InputSectionBase *s : v) | |
| 496 | s->assigned = false; | |
| 497 | sec->sectionCommands.clear(); | |
| 500 | 498 | continue; |
| 501 | 499 | } |
| 502 | 500 | |
| 503 | 501 | // A directive may contain symbol definitions like this: |
| 504 | 502 | // ".foo : { ...; bar = .; }". Handle them. |
| 505 | for (BaseCommand *Base : Sec->SectionCommands) | |
| 506 | if (auto *OutCmd = dyn_cast<SymbolAssignment>(Base)) | |
| 507 | addSymbol(OutCmd); | |
| 503 | for (BaseCommand *base : sec->sectionCommands) | |
| 504 | if (auto *outCmd = dyn_cast<SymbolAssignment>(base)) | |
| 505 | addSymbol(outCmd); | |
| 508 | 506 | |
| 509 | 507 | // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign |
| 510 | 508 | // is given, input sections are aligned to that value, whether the |
| 511 | 509 | // given value is larger or smaller than the original section alignment. |
| 512 | if (Sec->SubalignExpr) { | |
| 513 | uint32_t Subalign = Sec->SubalignExpr().getValue(); | |
| 514 | for (InputSectionBase *S : V) | |
| 515 | S->Alignment = Subalign; | |
| 510 | if (sec->subalignExpr) { | |
| 511 | uint32_t subalign = sec->subalignExpr().getValue(); | |
| 512 | for (InputSectionBase *s : v) | |
| 513 | s->alignment = subalign; | |
| 516 | 514 | } |
| 517 | 515 | |
| 518 | 516 | // Add input sections to an output section. |
| 519 | for (InputSection *S : V) | |
| 520 | Sec->addSection(S); | |
| 521 | ||
| 522 | Sec->SectionIndex = I++; | |
| 523 | if (Sec->Noload) | |
| 524 | Sec->Type = SHT_NOBITS; | |
| 525 | if (Sec->NonAlloc) | |
| 526 | Sec->Flags &= ~(uint64_t)SHF_ALLOC; | |
| 517 | for (InputSection *s : v) | |
| 518 | sec->addSection(s); | |
| 519 | ||
| 520 | sec->sectionIndex = i++; | |
| 521 | if (sec->noload) | |
| 522 | sec->type = SHT_NOBITS; | |
| 523 | if (sec->nonAlloc) | |
| 524 | sec->flags &= ~(uint64_t)SHF_ALLOC; | |
| 527 | 525 | } |
| 528 | 526 | } |
| 529 | Ctx = nullptr; | |
| 527 | ctx = nullptr; | |
| 530 | 528 | } |
| 531 | 529 | |
| 532 | static OutputSection *findByName(ArrayRef<BaseCommand *> Vec, | |
| 533 | StringRef Name) { | |
| 534 | for (BaseCommand *Base : Vec) | |
| 535 | if (auto *Sec = dyn_cast<OutputSection>(Base)) | |
| 536 | if (Sec->Name == Name) | |
| 537 | return Sec; | |
| 530 | static OutputSection *findByName(ArrayRef<BaseCommand *> vec, | |
| 531 | StringRef name) { | |
| 532 | for (BaseCommand *base : vec) | |
| 533 | if (auto *sec = dyn_cast<OutputSection>(base)) | |
| 534 | if (sec->name == name) | |
| 535 | return sec; | |
| 538 | 536 | return nullptr; |
| 539 | 537 | } |
| 540 | 538 | |
| 541 | static OutputSection *createSection(InputSectionBase *IS, | |
| 542 | StringRef OutsecName) { | |
| 543 | OutputSection *Sec = Script->createOutputSection(OutsecName, "<internal>"); | |
| 544 | Sec->addSection(cast<InputSection>(IS)); | |
| 545 | return Sec; | |
| 539 | static OutputSection *createSection(InputSectionBase *isec, | |
| 540 | StringRef outsecName) { | |
| 541 | OutputSection *sec = script->createOutputSection(outsecName, "<internal>"); | |
| 542 | sec->addSection(cast<InputSection>(isec)); | |
| 543 | return sec; | |
| 546 | 544 | } |
| 547 | 545 | |
| 548 | static OutputSection *addInputSec(StringMap<OutputSection *> &Map, | |
| 549 | InputSectionBase *IS, StringRef OutsecName) { | |
| 546 | static OutputSection * | |
| 547 | addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map, | |
| 548 | InputSectionBase *isec, StringRef outsecName) { | |
| 550 | 549 | // Sections with SHT_GROUP or SHF_GROUP attributes reach here only when the -r |
| 551 | 550 | // option is given. A section with SHT_GROUP defines a "section group", and |
| 552 | 551 | // its members have SHF_GROUP attribute. Usually these flags have already been |
| ... | ... | @@ -554,8 +553,8 @@ static OutputSection *addInputSec(StringMap<OutputSection *> &Map, |
| 554 | 553 | // However, for the -r option, we want to pass through all section groups |
| 555 | 554 | // as-is because adding/removing members or merging them with other groups |
| 556 | 555 | // change their semantics. |
| 557 | if (IS->Type == SHT_GROUP || (IS->Flags & SHF_GROUP)) | |
| 558 | return createSection(IS, OutsecName); | |
| 556 | if (isec->type == SHT_GROUP || (isec->flags & SHF_GROUP)) | |
| 557 | return createSection(isec, outsecName); | |
| 559 | 558 | |
| 560 | 559 | // Imagine .zed : { *(.foo) *(.bar) } script. Both foo and bar may have |
| 561 | 560 | // relocation sections .rela.foo and .rela.bar for example. Most tools do |
| ... | ... | @@ -563,25 +562,25 @@ static OutputSection *addInputSec(StringMap<OutputSection *> &Map, |
| 563 | 562 | // should combine these relocation sections into single output. |
| 564 | 563 | // We skip synthetic sections because it can be .rela.dyn/.rela.plt or any |
| 565 | 564 | // other REL[A] sections created by linker itself. |
| 566 | if (!isa<SyntheticSection>(IS) && | |
| 567 | (IS->Type == SHT_REL || IS->Type == SHT_RELA)) { | |
| 568 | auto *Sec = cast<InputSection>(IS); | |
| 569 | OutputSection *Out = Sec->getRelocatedSection()->getOutputSection(); | |
| 565 | if (!isa<SyntheticSection>(isec) && | |
| 566 | (isec->type == SHT_REL || isec->type == SHT_RELA)) { | |
| 567 | auto *sec = cast<InputSection>(isec); | |
| 568 | OutputSection *out = sec->getRelocatedSection()->getOutputSection(); | |
| 570 | 569 | |
| 571 | if (Out->RelocationSection) { | |
| 572 | Out->RelocationSection->addSection(Sec); | |
| 570 | if (out->relocationSection) { | |
| 571 | out->relocationSection->addSection(sec); | |
| 573 | 572 | return nullptr; |
| 574 | 573 | } |
| 575 | 574 | |
| 576 | Out->RelocationSection = createSection(IS, OutsecName); | |
| 577 | return Out->RelocationSection; | |
| 575 | out->relocationSection = createSection(isec, outsecName); | |
| 576 | return out->relocationSection; | |
| 578 | 577 | } |
| 579 | 578 | |
| 580 | 579 | // When control reaches here, mergeable sections have already been merged into |
| 581 | 580 | // synthetic sections. For relocatable case we want to create one output |
| 582 | 581 | // section per syntetic section so that they have a valid sh_entsize. |
| 583 | if (Config->Relocatable && (IS->Flags & SHF_MERGE)) | |
| 584 | return createSection(IS, OutsecName); | |
| 582 | if (config->relocatable && (isec->flags & SHF_MERGE)) | |
| 583 | return createSection(isec, outsecName); | |
| 585 | 584 | |
| 586 | 585 | // The ELF spec just says |
| 587 | 586 | // ---------------------------------------------------------------- |
| ... | ... | @@ -625,159 +624,161 @@ static OutputSection *addInputSec(StringMap<OutputSection *> &Map, |
| 625 | 624 | // |
| 626 | 625 | // Given the above issues, we instead merge sections by name and error on |
| 627 | 626 | // incompatible types and flags. |
| 628 | OutputSection *&Sec = Map[OutsecName]; | |
| 629 | if (Sec) { | |
| 630 | Sec->addSection(cast<InputSection>(IS)); | |
| 627 | TinyPtrVector<OutputSection *> &v = map[outsecName]; | |
| 628 | for (OutputSection *sec : v) { | |
| 629 | if (sec->partition != isec->partition) | |
| 630 | continue; | |
| 631 | sec->addSection(cast<InputSection>(isec)); | |
| 631 | 632 | return nullptr; |
| 632 | 633 | } |
| 633 | 634 | |
| 634 | Sec = createSection(IS, OutsecName); | |
| 635 | return Sec; | |
| 635 | OutputSection *sec = createSection(isec, outsecName); | |
| 636 | v.push_back(sec); | |
| 637 | return sec; | |
| 636 | 638 | } |
| 637 | 639 | |
| 638 | 640 | // Add sections that didn't match any sections command. |
| 639 | 641 | void LinkerScript::addOrphanSections() { |
| 640 | unsigned End = SectionCommands.size(); | |
| 641 | StringMap<OutputSection *> Map; | |
| 642 | std::vector<OutputSection *> V; | |
| 642 | StringMap<TinyPtrVector<OutputSection *>> map; | |
| 643 | std::vector<OutputSection *> v; | |
| 643 | 644 | |
| 644 | auto Add = [&](InputSectionBase *S) { | |
| 645 | if (!S->Live || S->Parent) | |
| 645 | auto add = [&](InputSectionBase *s) { | |
| 646 | if (!s->isLive() || s->parent) | |
| 646 | 647 | return; |
| 647 | 648 | |
| 648 | StringRef Name = getOutputSectionName(S); | |
| 649 | StringRef name = getOutputSectionName(s); | |
| 649 | 650 | |
| 650 | if (Config->OrphanHandling == OrphanHandlingPolicy::Error) | |
| 651 | error(toString(S) + " is being placed in '" + Name + "'"); | |
| 652 | else if (Config->OrphanHandling == OrphanHandlingPolicy::Warn) | |
| 653 | warn(toString(S) + " is being placed in '" + Name + "'"); | |
| 651 | if (config->orphanHandling == OrphanHandlingPolicy::Error) | |
| 652 | error(toString(s) + " is being placed in '" + name + "'"); | |
| 653 | else if (config->orphanHandling == OrphanHandlingPolicy::Warn) | |
| 654 | warn(toString(s) + " is being placed in '" + name + "'"); | |
| 654 | 655 | |
| 655 | if (OutputSection *Sec = | |
| 656 | findByName(makeArrayRef(SectionCommands).slice(0, End), Name)) { | |
| 657 | Sec->addSection(cast<InputSection>(S)); | |
| 656 | if (OutputSection *sec = findByName(sectionCommands, name)) { | |
| 657 | sec->addSection(cast<InputSection>(s)); | |
| 658 | 658 | return; |
| 659 | 659 | } |
| 660 | 660 | |
| 661 | if (OutputSection *OS = addInputSec(Map, S, Name)) | |
| 662 | V.push_back(OS); | |
| 663 | assert(S->getOutputSection()->SectionIndex == UINT32_MAX); | |
| 661 | if (OutputSection *os = addInputSec(map, s, name)) | |
| 662 | v.push_back(os); | |
| 663 | assert(s->getOutputSection()->sectionIndex == UINT32_MAX); | |
| 664 | 664 | }; |
| 665 | 665 | |
| 666 | 666 | // For futher --emit-reloc handling code we need target output section |
| 667 | 667 | // to be created before we create relocation output section, so we want |
| 668 | 668 | // to create target sections first. We do not want priority handling |
| 669 | 669 | // for synthetic sections because them are special. |
| 670 | for (InputSectionBase *IS : InputSections) { | |
| 671 | if (auto *Sec = dyn_cast<InputSection>(IS)) | |
| 672 | if (InputSectionBase *Rel = Sec->getRelocatedSection()) | |
| 673 | if (auto *RelIS = dyn_cast_or_null<InputSectionBase>(Rel->Parent)) | |
| 674 | Add(RelIS); | |
| 675 | Add(IS); | |
| 670 | for (InputSectionBase *isec : inputSections) { | |
| 671 | if (auto *sec = dyn_cast<InputSection>(isec)) | |
| 672 | if (InputSectionBase *rel = sec->getRelocatedSection()) | |
| 673 | if (auto *relIS = dyn_cast_or_null<InputSectionBase>(rel->parent)) | |
| 674 | add(relIS); | |
| 675 | add(isec); | |
| 676 | 676 | } |
| 677 | 677 | |
| 678 | 678 | // If no SECTIONS command was given, we should insert sections commands |
| 679 | 679 | // before others, so that we can handle scripts which refers them, |
| 680 | 680 | // for example: "foo = ABSOLUTE(ADDR(.text)));". |
| 681 | 681 | // When SECTIONS command is present we just add all orphans to the end. |
| 682 | if (HasSectionsCommand) | |
| 683 | SectionCommands.insert(SectionCommands.end(), V.begin(), V.end()); | |
| 682 | if (hasSectionsCommand) | |
| 683 | sectionCommands.insert(sectionCommands.end(), v.begin(), v.end()); | |
| 684 | 684 | else |
| 685 | SectionCommands.insert(SectionCommands.begin(), V.begin(), V.end()); | |
| 685 | sectionCommands.insert(sectionCommands.begin(), v.begin(), v.end()); | |
| 686 | 686 | } |
| 687 | 687 | |
| 688 | uint64_t LinkerScript::advance(uint64_t Size, unsigned Alignment) { | |
| 689 | bool IsTbss = | |
| 690 | (Ctx->OutSec->Flags & SHF_TLS) && Ctx->OutSec->Type == SHT_NOBITS; | |
| 691 | uint64_t Start = IsTbss ? Dot + Ctx->ThreadBssOffset : Dot; | |
| 692 | Start = alignTo(Start, Alignment); | |
| 693 | uint64_t End = Start + Size; | |
| 688 | uint64_t LinkerScript::advance(uint64_t size, unsigned alignment) { | |
| 689 | bool isTbss = | |
| 690 | (ctx->outSec->flags & SHF_TLS) && ctx->outSec->type == SHT_NOBITS; | |
| 691 | uint64_t start = isTbss ? dot + ctx->threadBssOffset : dot; | |
| 692 | start = alignTo(start, alignment); | |
| 693 | uint64_t end = start + size; | |
| 694 | 694 | |
| 695 | if (IsTbss) | |
| 696 | Ctx->ThreadBssOffset = End - Dot; | |
| 695 | if (isTbss) | |
| 696 | ctx->threadBssOffset = end - dot; | |
| 697 | 697 | else |
| 698 | Dot = End; | |
| 699 | return End; | |
| 698 | dot = end; | |
| 699 | return end; | |
| 700 | 700 | } |
| 701 | 701 | |
| 702 | void LinkerScript::output(InputSection *S) { | |
| 703 | assert(Ctx->OutSec == S->getParent()); | |
| 704 | uint64_t Before = advance(0, 1); | |
| 705 | uint64_t Pos = advance(S->getSize(), S->Alignment); | |
| 706 | S->OutSecOff = Pos - S->getSize() - Ctx->OutSec->Addr; | |
| 702 | void LinkerScript::output(InputSection *s) { | |
| 703 | assert(ctx->outSec == s->getParent()); | |
| 704 | uint64_t before = advance(0, 1); | |
| 705 | uint64_t pos = advance(s->getSize(), s->alignment); | |
| 706 | s->outSecOff = pos - s->getSize() - ctx->outSec->addr; | |
| 707 | 707 | |
| 708 | 708 | // Update output section size after adding each section. This is so that |
| 709 | 709 | // SIZEOF works correctly in the case below: |
| 710 | 710 | // .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) } |
| 711 | expandOutputSection(Pos - Before); | |
| 711 | expandOutputSection(pos - before); | |
| 712 | 712 | } |
| 713 | 713 | |
| 714 | void LinkerScript::switchTo(OutputSection *Sec) { | |
| 715 | Ctx->OutSec = Sec; | |
| 714 | void LinkerScript::switchTo(OutputSection *sec) { | |
| 715 | ctx->outSec = sec; | |
| 716 | 716 | |
| 717 | uint64_t Before = advance(0, 1); | |
| 718 | Ctx->OutSec->Addr = advance(0, Ctx->OutSec->Alignment); | |
| 719 | expandMemoryRegions(Ctx->OutSec->Addr - Before); | |
| 717 | uint64_t before = advance(0, 1); | |
| 718 | ctx->outSec->addr = advance(0, ctx->outSec->alignment); | |
| 719 | expandMemoryRegions(ctx->outSec->addr - before); | |
| 720 | 720 | } |
| 721 | 721 | |
| 722 | 722 | // This function searches for a memory region to place the given output |
| 723 | 723 | // section in. If found, a pointer to the appropriate memory region is |
| 724 | 724 | // returned. Otherwise, a nullptr is returned. |
| 725 | MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *Sec) { | |
| 725 | MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *sec) { | |
| 726 | 726 | // If a memory region name was specified in the output section command, |
| 727 | 727 | // then try to find that region first. |
| 728 | if (!Sec->MemoryRegionName.empty()) { | |
| 729 | if (MemoryRegion *M = MemoryRegions.lookup(Sec->MemoryRegionName)) | |
| 730 | return M; | |
| 731 | error("memory region '" + Sec->MemoryRegionName + "' not declared"); | |
| 728 | if (!sec->memoryRegionName.empty()) { | |
| 729 | if (MemoryRegion *m = memoryRegions.lookup(sec->memoryRegionName)) | |
| 730 | return m; | |
| 731 | error("memory region '" + sec->memoryRegionName + "' not declared"); | |
| 732 | 732 | return nullptr; |
| 733 | 733 | } |
| 734 | 734 | |
| 735 | 735 | // If at least one memory region is defined, all sections must |
| 736 | 736 | // belong to some memory region. Otherwise, we don't need to do |
| 737 | 737 | // anything for memory regions. |
| 738 | if (MemoryRegions.empty()) | |
| 738 | if (memoryRegions.empty()) | |
| 739 | 739 | return nullptr; |
| 740 | 740 | |
| 741 | 741 | // See if a region can be found by matching section flags. |
| 742 | for (auto &Pair : MemoryRegions) { | |
| 743 | MemoryRegion *M = Pair.second; | |
| 744 | if ((M->Flags & Sec->Flags) && (M->NegFlags & Sec->Flags) == 0) | |
| 745 | return M; | |
| 742 | for (auto &pair : memoryRegions) { | |
| 743 | MemoryRegion *m = pair.second; | |
| 744 | if ((m->flags & sec->flags) && (m->negFlags & sec->flags) == 0) | |
| 745 | return m; | |
| 746 | 746 | } |
| 747 | 747 | |
| 748 | 748 | // Otherwise, no suitable region was found. |
| 749 | if (Sec->Flags & SHF_ALLOC) | |
| 750 | error("no memory region specified for section '" + Sec->Name + "'"); | |
| 749 | if (sec->flags & SHF_ALLOC) | |
| 750 | error("no memory region specified for section '" + sec->name + "'"); | |
| 751 | 751 | return nullptr; |
| 752 | 752 | } |
| 753 | 753 | |
| 754 | static OutputSection *findFirstSection(PhdrEntry *Load) { | |
| 755 | for (OutputSection *Sec : OutputSections) | |
| 756 | if (Sec->PtLoad == Load) | |
| 757 | return Sec; | |
| 754 | static OutputSection *findFirstSection(PhdrEntry *load) { | |
| 755 | for (OutputSection *sec : outputSections) | |
| 756 | if (sec->ptLoad == load) | |
| 757 | return sec; | |
| 758 | 758 | return nullptr; |
| 759 | 759 | } |
| 760 | 760 | |
| 761 | 761 | // This function assigns offsets to input sections and an output section |
| 762 | 762 | // for a single sections command (e.g. ".text { *(.text); }"). |
| 763 | void LinkerScript::assignOffsets(OutputSection *Sec) { | |
| 764 | if (!(Sec->Flags & SHF_ALLOC)) | |
| 765 | Dot = 0; | |
| 766 | else if (Sec->AddrExpr) | |
| 767 | setDot(Sec->AddrExpr, Sec->Location, false); | |
| 763 | void LinkerScript::assignOffsets(OutputSection *sec) { | |
| 764 | if (!(sec->flags & SHF_ALLOC)) | |
| 765 | dot = 0; | |
| 768 | 766 | |
| 769 | Ctx->MemRegion = Sec->MemRegion; | |
| 770 | Ctx->LMARegion = Sec->LMARegion; | |
| 771 | if (Ctx->MemRegion) | |
| 772 | Dot = Ctx->MemRegion->CurPos; | |
| 767 | ctx->memRegion = sec->memRegion; | |
| 768 | ctx->lmaRegion = sec->lmaRegion; | |
| 769 | if (ctx->memRegion) | |
| 770 | dot = ctx->memRegion->curPos; | |
| 773 | 771 | |
| 774 | switchTo(Sec); | |
| 772 | if ((sec->flags & SHF_ALLOC) && sec->addrExpr) | |
| 773 | setDot(sec->addrExpr, sec->location, false); | |
| 775 | 774 | |
| 776 | if (Sec->LMAExpr) | |
| 777 | Ctx->LMAOffset = Sec->LMAExpr().getValue() - Dot; | |
| 775 | switchTo(sec); | |
| 778 | 776 | |
| 779 | if (MemoryRegion *MR = Sec->LMARegion) | |
| 780 | Ctx->LMAOffset = MR->CurPos - Dot; | |
| 777 | if (sec->lmaExpr) | |
| 778 | ctx->lmaOffset = sec->lmaExpr().getValue() - dot; | |
| 779 | ||
| 780 | if (MemoryRegion *mr = sec->lmaRegion) | |
| 781 | ctx->lmaOffset = mr->curPos - dot; | |
| 781 | 782 | |
| 782 | 783 | // If neither AT nor AT> is specified for an allocatable section, the linker |
| 783 | 784 | // will set the LMA such that the difference between VMA and LMA for the |
| ... | ... | @@ -785,62 +786,71 @@ void LinkerScript::assignOffsets(OutputSection *Sec) { |
| 785 | 786 | // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html |
| 786 | 787 | // This, however, should only be done by the first "non-header" section |
| 787 | 788 | // in the segment. |
| 788 | if (PhdrEntry *L = Ctx->OutSec->PtLoad) | |
| 789 | if (Sec == findFirstSection(L)) | |
| 790 | L->LMAOffset = Ctx->LMAOffset; | |
| 789 | if (PhdrEntry *l = ctx->outSec->ptLoad) | |
| 790 | if (sec == findFirstSection(l)) | |
| 791 | l->lmaOffset = ctx->lmaOffset; | |
| 791 | 792 | |
| 792 | 793 | // We can call this method multiple times during the creation of |
| 793 | 794 | // thunks and want to start over calculation each time. |
| 794 | Sec->Size = 0; | |
| 795 | sec->size = 0; | |
| 795 | 796 | |
| 796 | 797 | // We visited SectionsCommands from processSectionCommands to |
| 797 | 798 | // layout sections. Now, we visit SectionsCommands again to fix |
| 798 | 799 | // section offsets. |
| 799 | for (BaseCommand *Base : Sec->SectionCommands) { | |
| 800 | for (BaseCommand *base : sec->sectionCommands) { | |
| 800 | 801 | // This handles the assignments to symbol or to the dot. |
| 801 | if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { | |
| 802 | Cmd->Addr = Dot; | |
| 803 | assignSymbol(Cmd, true); | |
| 804 | Cmd->Size = Dot - Cmd->Addr; | |
| 802 | if (auto *cmd = dyn_cast<SymbolAssignment>(base)) { | |
| 803 | cmd->addr = dot; | |
| 804 | assignSymbol(cmd, true); | |
| 805 | cmd->size = dot - cmd->addr; | |
| 805 | 806 | continue; |
| 806 | 807 | } |
| 807 | 808 | |
| 808 | 809 | // Handle BYTE(), SHORT(), LONG(), or QUAD(). |
| 809 | if (auto *Cmd = dyn_cast<ByteCommand>(Base)) { | |
| 810 | Cmd->Offset = Dot - Ctx->OutSec->Addr; | |
| 811 | Dot += Cmd->Size; | |
| 812 | expandOutputSection(Cmd->Size); | |
| 810 | if (auto *cmd = dyn_cast<ByteCommand>(base)) { | |
| 811 | cmd->offset = dot - ctx->outSec->addr; | |
| 812 | dot += cmd->size; | |
| 813 | expandOutputSection(cmd->size); | |
| 813 | 814 | continue; |
| 814 | 815 | } |
| 815 | 816 | |
| 816 | 817 | // Handle a single input section description command. |
| 817 | 818 | // It calculates and assigns the offsets for each section and also |
| 818 | 819 | // updates the output section size. |
| 819 | for (InputSection *Sec : cast<InputSectionDescription>(Base)->Sections) | |
| 820 | output(Sec); | |
| 820 | for (InputSection *sec : cast<InputSectionDescription>(base)->sections) | |
| 821 | output(sec); | |
| 821 | 822 | } |
| 822 | 823 | } |
| 823 | 824 | |
| 824 | static bool isDiscardable(OutputSection &Sec) { | |
| 825 | static bool isDiscardable(OutputSection &sec) { | |
| 826 | if (sec.name == "/DISCARD/") | |
| 827 | return true; | |
| 828 | ||
| 825 | 829 | // We do not remove empty sections that are explicitly |
| 826 | 830 | // assigned to any segment. |
| 827 | if (!Sec.Phdrs.empty()) | |
| 831 | if (!sec.phdrs.empty()) | |
| 828 | 832 | return false; |
| 829 | 833 | |
| 830 | // We do not want to remove sections that reference symbols in address and | |
| 831 | // other expressions. We add script symbols as undefined, and want to ensure | |
| 832 | // all of them are defined in the output, hence have to keep them. | |
| 833 | if (Sec.ExpressionsUseSymbols) | |
| 834 | // We do not want to remove OutputSections with expressions that reference | |
| 835 | // symbols even if the OutputSection is empty. We want to ensure that the | |
| 836 | // expressions can be evaluated and report an error if they cannot. | |
| 837 | if (sec.expressionsUseSymbols) | |
| 834 | 838 | return false; |
| 835 | 839 | |
| 836 | for (BaseCommand *Base : Sec.SectionCommands) { | |
| 837 | if (auto Cmd = dyn_cast<SymbolAssignment>(Base)) | |
| 840 | // OutputSections may be referenced by name in ADDR and LOADADDR expressions, | |
| 841 | // as an empty Section can has a valid VMA and LMA we keep the OutputSection | |
| 842 | // to maintain the integrity of the other Expression. | |
| 843 | if (sec.usedInExpression) | |
| 844 | return false; | |
| 845 | ||
| 846 | for (BaseCommand *base : sec.sectionCommands) { | |
| 847 | if (auto cmd = dyn_cast<SymbolAssignment>(base)) | |
| 838 | 848 | // Don't create empty output sections just for unreferenced PROVIDE |
| 839 | 849 | // symbols. |
| 840 | if (Cmd->Name != "." && !Cmd->Sym) | |
| 850 | if (cmd->name != "." && !cmd->sym) | |
| 841 | 851 | continue; |
| 842 | 852 | |
| 843 | if (!isa<InputSectionDescription>(*Base)) | |
| 853 | if (!isa<InputSectionDescription>(*base)) | |
| 844 | 854 | return false; |
| 845 | 855 | } |
| 846 | 856 | return true; |
| ... | ... | @@ -867,33 +877,35 @@ void LinkerScript::adjustSectionsBeforeSorting() { |
| 867 | 877 | // The other option is to pick flags that minimize the impact the section |
| 868 | 878 | // will have on the rest of the linker. That is why we copy the flags from |
| 869 | 879 | // the previous sections. Only a few flags are needed to keep the impact low. |
| 870 | uint64_t Flags = SHF_ALLOC; | |
| 880 | uint64_t flags = SHF_ALLOC; | |
| 871 | 881 | |
| 872 | for (BaseCommand *&Cmd : SectionCommands) { | |
| 873 | auto *Sec = dyn_cast<OutputSection>(Cmd); | |
| 874 | if (!Sec) | |
| 882 | for (BaseCommand *&cmd : sectionCommands) { | |
| 883 | auto *sec = dyn_cast<OutputSection>(cmd); | |
| 884 | if (!sec) | |
| 875 | 885 | continue; |
| 876 | 886 | |
| 877 | 887 | // Handle align (e.g. ".foo : ALIGN(16) { ... }"). |
| 878 | if (Sec->AlignExpr) | |
| 879 | Sec->Alignment = | |
| 880 | std::max<uint32_t>(Sec->Alignment, Sec->AlignExpr().getValue()); | |
| 888 | if (sec->alignExpr) | |
| 889 | sec->alignment = | |
| 890 | std::max<uint32_t>(sec->alignment, sec->alignExpr().getValue()); | |
| 881 | 891 | |
| 882 | // A live output section means that some input section was added to it. It | |
| 883 | // might have been removed (if it was empty synthetic section), but we at | |
| 884 | // least know the flags. | |
| 885 | if (Sec->Live) | |
| 886 | Flags = Sec->Flags; | |
| 892 | // The input section might have been removed (if it was an empty synthetic | |
| 893 | // section), but we at least know the flags. | |
| 894 | if (sec->hasInputSections) | |
| 895 | flags = sec->flags; | |
| 887 | 896 | |
| 888 | 897 | // We do not want to keep any special flags for output section |
| 889 | 898 | // in case it is empty. |
| 890 | bool IsEmpty = getInputSections(Sec).empty(); | |
| 891 | if (IsEmpty) | |
| 892 | Sec->Flags = Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR); | |
| 893 | ||
| 894 | if (IsEmpty && isDiscardable(*Sec)) { | |
| 895 | Sec->Live = false; | |
| 896 | Cmd = nullptr; | |
| 899 | bool isEmpty = getInputSections(sec).empty(); | |
| 900 | if (isEmpty) | |
| 901 | sec->flags = flags & ((sec->nonAlloc ? 0 : (uint64_t)SHF_ALLOC) | | |
| 902 | SHF_WRITE | SHF_EXECINSTR); | |
| 903 | ||
| 904 | if (isEmpty && isDiscardable(*sec)) { | |
| 905 | sec->markDead(); | |
| 906 | cmd = nullptr; | |
| 907 | } else if (!sec->isLive()) { | |
| 908 | sec->markLive(); | |
| 897 | 909 | } |
| 898 | 910 | } |
| 899 | 911 | |
| ... | ... | @@ -903,20 +915,20 @@ void LinkerScript::adjustSectionsBeforeSorting() { |
| 903 | 915 | // clutter the output. |
| 904 | 916 | // We instead remove trivially empty sections. The bfd linker seems even |
| 905 | 917 | // more aggressive at removing them. |
| 906 | llvm::erase_if(SectionCommands, [&](BaseCommand *Base) { return !Base; }); | |
| 918 | llvm::erase_if(sectionCommands, [&](BaseCommand *base) { return !base; }); | |
| 907 | 919 | } |
| 908 | 920 | |
| 909 | 921 | void LinkerScript::adjustSectionsAfterSorting() { |
| 910 | 922 | // Try and find an appropriate memory region to assign offsets in. |
| 911 | for (BaseCommand *Base : SectionCommands) { | |
| 912 | if (auto *Sec = dyn_cast<OutputSection>(Base)) { | |
| 913 | if (!Sec->LMARegionName.empty()) { | |
| 914 | if (MemoryRegion *M = MemoryRegions.lookup(Sec->LMARegionName)) | |
| 915 | Sec->LMARegion = M; | |
| 923 | for (BaseCommand *base : sectionCommands) { | |
| 924 | if (auto *sec = dyn_cast<OutputSection>(base)) { | |
| 925 | if (!sec->lmaRegionName.empty()) { | |
| 926 | if (MemoryRegion *m = memoryRegions.lookup(sec->lmaRegionName)) | |
| 927 | sec->lmaRegion = m; | |
| 916 | 928 | else |
| 917 | error("memory region '" + Sec->LMARegionName + "' not declared"); | |
| 929 | error("memory region '" + sec->lmaRegionName + "' not declared"); | |
| 918 | 930 | } |
| 919 | Sec->MemRegion = findMemoryRegion(Sec); | |
| 931 | sec->memRegion = findMemoryRegion(sec); | |
| 920 | 932 | } |
| 921 | 933 | } |
| 922 | 934 | |
| ... | ... | @@ -926,38 +938,38 @@ void LinkerScript::adjustSectionsAfterSorting() { |
| 926 | 938 | // Below is an example of such linker script: |
| 927 | 939 | // PHDRS { seg PT_LOAD; } |
| 928 | 940 | // SECTIONS { .aaa : { *(.aaa) } } |
| 929 | std::vector<StringRef> DefPhdrs; | |
| 930 | auto FirstPtLoad = llvm::find_if(PhdrsCommands, [](const PhdrsCommand &Cmd) { | |
| 931 | return Cmd.Type == PT_LOAD; | |
| 941 | std::vector<StringRef> defPhdrs; | |
| 942 | auto firstPtLoad = llvm::find_if(phdrsCommands, [](const PhdrsCommand &cmd) { | |
| 943 | return cmd.type == PT_LOAD; | |
| 932 | 944 | }); |
| 933 | if (FirstPtLoad != PhdrsCommands.end()) | |
| 934 | DefPhdrs.push_back(FirstPtLoad->Name); | |
| 945 | if (firstPtLoad != phdrsCommands.end()) | |
| 946 | defPhdrs.push_back(firstPtLoad->name); | |
| 935 | 947 | |
| 936 | 948 | // Walk the commands and propagate the program headers to commands that don't |
| 937 | 949 | // explicitly specify them. |
| 938 | for (BaseCommand *Base : SectionCommands) { | |
| 939 | auto *Sec = dyn_cast<OutputSection>(Base); | |
| 940 | if (!Sec) | |
| 950 | for (BaseCommand *base : sectionCommands) { | |
| 951 | auto *sec = dyn_cast<OutputSection>(base); | |
| 952 | if (!sec) | |
| 941 | 953 | continue; |
| 942 | 954 | |
| 943 | if (Sec->Phdrs.empty()) { | |
| 955 | if (sec->phdrs.empty()) { | |
| 944 | 956 | // To match the bfd linker script behaviour, only propagate program |
| 945 | 957 | // headers to sections that are allocated. |
| 946 | if (Sec->Flags & SHF_ALLOC) | |
| 947 | Sec->Phdrs = DefPhdrs; | |
| 958 | if (sec->flags & SHF_ALLOC) | |
| 959 | sec->phdrs = defPhdrs; | |
| 948 | 960 | } else { |
| 949 | DefPhdrs = Sec->Phdrs; | |
| 961 | defPhdrs = sec->phdrs; | |
| 950 | 962 | } |
| 951 | 963 | } |
| 952 | 964 | } |
| 953 | 965 | |
| 954 | static uint64_t computeBase(uint64_t Min, bool AllocateHeaders) { | |
| 966 | static uint64_t computeBase(uint64_t min, bool allocateHeaders) { | |
| 955 | 967 | // If there is no SECTIONS or if the linkerscript is explicit about program |
| 956 | 968 | // headers, do our best to allocate them. |
| 957 | if (!Script->HasSectionsCommand || AllocateHeaders) | |
| 969 | if (!script->hasSectionsCommand || allocateHeaders) | |
| 958 | 970 | return 0; |
| 959 | 971 | // Otherwise only allocate program headers if that would not add a page. |
| 960 | return alignDown(Min, Config->MaxPageSize); | |
| 972 | return alignDown(min, config->maxPageSize); | |
| 961 | 973 | } |
| 962 | 974 | |
| 963 | 975 | // Try to find an address for the file and program headers output sections, |
| ... | ... | @@ -971,118 +983,120 @@ static uint64_t computeBase(uint64_t Min, bool AllocateHeaders) { |
| 971 | 983 | // |
| 972 | 984 | // If there isn't enough space for these sections, we'll remove them from the |
| 973 | 985 | // PT_LOAD segment, and we'll also remove the PT_PHDR segment. |
| 974 | void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &Phdrs) { | |
| 975 | uint64_t Min = std::numeric_limits<uint64_t>::max(); | |
| 976 | for (OutputSection *Sec : OutputSections) | |
| 977 | if (Sec->Flags & SHF_ALLOC) | |
| 978 | Min = std::min<uint64_t>(Min, Sec->Addr); | |
| 979 | ||
| 980 | auto It = llvm::find_if( | |
| 981 | Phdrs, [](const PhdrEntry *E) { return E->p_type == PT_LOAD; }); | |
| 982 | if (It == Phdrs.end()) | |
| 986 | void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &phdrs) { | |
| 987 | uint64_t min = std::numeric_limits<uint64_t>::max(); | |
| 988 | for (OutputSection *sec : outputSections) | |
| 989 | if (sec->flags & SHF_ALLOC) | |
| 990 | min = std::min<uint64_t>(min, sec->addr); | |
| 991 | ||
| 992 | auto it = llvm::find_if( | |
| 993 | phdrs, [](const PhdrEntry *e) { return e->p_type == PT_LOAD; }); | |
| 994 | if (it == phdrs.end()) | |
| 983 | 995 | return; |
| 984 | PhdrEntry *FirstPTLoad = *It; | |
| 996 | PhdrEntry *firstPTLoad = *it; | |
| 985 | 997 | |
| 986 | bool HasExplicitHeaders = | |
| 987 | llvm::any_of(PhdrsCommands, [](const PhdrsCommand &Cmd) { | |
| 988 | return Cmd.HasPhdrs || Cmd.HasFilehdr; | |
| 998 | bool hasExplicitHeaders = | |
| 999 | llvm::any_of(phdrsCommands, [](const PhdrsCommand &cmd) { | |
| 1000 | return cmd.hasPhdrs || cmd.hasFilehdr; | |
| 989 | 1001 | }); |
| 990 | uint64_t HeaderSize = getHeaderSize(); | |
| 991 | if (HeaderSize <= Min - computeBase(Min, HasExplicitHeaders)) { | |
| 992 | Min = alignDown(Min - HeaderSize, Config->MaxPageSize); | |
| 993 | Out::ElfHeader->Addr = Min; | |
| 994 | Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size; | |
| 1002 | bool paged = !config->omagic && !config->nmagic; | |
| 1003 | uint64_t headerSize = getHeaderSize(); | |
| 1004 | if ((paged || hasExplicitHeaders) && | |
| 1005 | headerSize <= min - computeBase(min, hasExplicitHeaders)) { | |
| 1006 | min = alignDown(min - headerSize, config->maxPageSize); | |
| 1007 | Out::elfHeader->addr = min; | |
| 1008 | Out::programHeaders->addr = min + Out::elfHeader->size; | |
| 995 | 1009 | return; |
| 996 | 1010 | } |
| 997 | 1011 | |
| 998 | 1012 | // Error if we were explicitly asked to allocate headers. |
| 999 | if (HasExplicitHeaders) | |
| 1013 | if (hasExplicitHeaders) | |
| 1000 | 1014 | error("could not allocate headers"); |
| 1001 | 1015 | |
| 1002 | Out::ElfHeader->PtLoad = nullptr; | |
| 1003 | Out::ProgramHeaders->PtLoad = nullptr; | |
| 1004 | FirstPTLoad->FirstSec = findFirstSection(FirstPTLoad); | |
| 1016 | Out::elfHeader->ptLoad = nullptr; | |
| 1017 | Out::programHeaders->ptLoad = nullptr; | |
| 1018 | firstPTLoad->firstSec = findFirstSection(firstPTLoad); | |
| 1005 | 1019 | |
| 1006 | llvm::erase_if(Phdrs, | |
| 1007 | [](const PhdrEntry *E) { return E->p_type == PT_PHDR; }); | |
| 1020 | llvm::erase_if(phdrs, | |
| 1021 | [](const PhdrEntry *e) { return e->p_type == PT_PHDR; }); | |
| 1008 | 1022 | } |
| 1009 | 1023 | |
| 1010 | 1024 | LinkerScript::AddressState::AddressState() { |
| 1011 | for (auto &MRI : Script->MemoryRegions) { | |
| 1012 | MemoryRegion *MR = MRI.second; | |
| 1013 | MR->CurPos = MR->Origin; | |
| 1025 | for (auto &mri : script->memoryRegions) { | |
| 1026 | MemoryRegion *mr = mri.second; | |
| 1027 | mr->curPos = mr->origin; | |
| 1014 | 1028 | } |
| 1015 | 1029 | } |
| 1016 | 1030 | |
| 1017 | 1031 | static uint64_t getInitialDot() { |
| 1018 | 1032 | // By default linker scripts use an initial value of 0 for '.', |
| 1019 | 1033 | // but prefer -image-base if set. |
| 1020 | if (Script->HasSectionsCommand) | |
| 1021 | return Config->ImageBase ? *Config->ImageBase : 0; | |
| 1034 | if (script->hasSectionsCommand) | |
| 1035 | return config->imageBase ? *config->imageBase : 0; | |
| 1022 | 1036 | |
| 1023 | uint64_t StartAddr = UINT64_MAX; | |
| 1024 | // The Sections with -T<section> have been sorted in order of ascending | |
| 1025 | // address. We must lower StartAddr if the lowest -T<section address> as | |
| 1037 | uint64_t startAddr = UINT64_MAX; | |
| 1038 | // The sections with -T<section> have been sorted in order of ascending | |
| 1039 | // address. We must lower startAddr if the lowest -T<section address> as | |
| 1026 | 1040 | // calls to setDot() must be monotonically increasing. |
| 1027 | for (auto &KV : Config->SectionStartMap) | |
| 1028 | StartAddr = std::min(StartAddr, KV.second); | |
| 1029 | return std::min(StartAddr, Target->getImageBase() + elf::getHeaderSize()); | |
| 1041 | for (auto &kv : config->sectionStartMap) | |
| 1042 | startAddr = std::min(startAddr, kv.second); | |
| 1043 | return std::min(startAddr, target->getImageBase() + elf::getHeaderSize()); | |
| 1030 | 1044 | } |
| 1031 | 1045 | |
| 1032 | 1046 | // Here we assign addresses as instructed by linker script SECTIONS |
| 1033 | 1047 | // sub-commands. Doing that allows us to use final VA values, so here |
| 1034 | 1048 | // we also handle rest commands like symbol assignments and ASSERTs. |
| 1035 | 1049 | void LinkerScript::assignAddresses() { |
| 1036 | Dot = getInitialDot(); | |
| 1037 | ||
| 1038 | auto Deleter = make_unique<AddressState>(); | |
| 1039 | Ctx = Deleter.get(); | |
| 1040 | ErrorOnMissingSection = true; | |
| 1041 | switchTo(Aether); | |
| 1042 | ||
| 1043 | for (BaseCommand *Base : SectionCommands) { | |
| 1044 | if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { | |
| 1045 | Cmd->Addr = Dot; | |
| 1046 | assignSymbol(Cmd, false); | |
| 1047 | Cmd->Size = Dot - Cmd->Addr; | |
| 1050 | dot = getInitialDot(); | |
| 1051 | ||
| 1052 | auto deleter = make_unique<AddressState>(); | |
| 1053 | ctx = deleter.get(); | |
| 1054 | errorOnMissingSection = true; | |
| 1055 | switchTo(aether); | |
| 1056 | ||
| 1057 | for (BaseCommand *base : sectionCommands) { | |
| 1058 | if (auto *cmd = dyn_cast<SymbolAssignment>(base)) { | |
| 1059 | cmd->addr = dot; | |
| 1060 | assignSymbol(cmd, false); | |
| 1061 | cmd->size = dot - cmd->addr; | |
| 1048 | 1062 | continue; |
| 1049 | 1063 | } |
| 1050 | assignOffsets(cast<OutputSection>(Base)); | |
| 1064 | assignOffsets(cast<OutputSection>(base)); | |
| 1051 | 1065 | } |
| 1052 | Ctx = nullptr; | |
| 1066 | ctx = nullptr; | |
| 1053 | 1067 | } |
| 1054 | 1068 | |
| 1055 | 1069 | // Creates program headers as instructed by PHDRS linker script command. |
| 1056 | 1070 | std::vector<PhdrEntry *> LinkerScript::createPhdrs() { |
| 1057 | std::vector<PhdrEntry *> Ret; | |
| 1071 | std::vector<PhdrEntry *> ret; | |
| 1058 | 1072 | |
| 1059 | 1073 | // Process PHDRS and FILEHDR keywords because they are not |
| 1060 | 1074 | // real output sections and cannot be added in the following loop. |
| 1061 | for (const PhdrsCommand &Cmd : PhdrsCommands) { | |
| 1062 | PhdrEntry *Phdr = make<PhdrEntry>(Cmd.Type, Cmd.Flags ? *Cmd.Flags : PF_R); | |
| 1075 | for (const PhdrsCommand &cmd : phdrsCommands) { | |
| 1076 | PhdrEntry *phdr = make<PhdrEntry>(cmd.type, cmd.flags ? *cmd.flags : PF_R); | |
| 1063 | 1077 | |
| 1064 | if (Cmd.HasFilehdr) | |
| 1065 | Phdr->add(Out::ElfHeader); | |
| 1066 | if (Cmd.HasPhdrs) | |
| 1067 | Phdr->add(Out::ProgramHeaders); | |
| 1078 | if (cmd.hasFilehdr) | |
| 1079 | phdr->add(Out::elfHeader); | |
| 1080 | if (cmd.hasPhdrs) | |
| 1081 | phdr->add(Out::programHeaders); | |
| 1068 | 1082 | |
| 1069 | if (Cmd.LMAExpr) { | |
| 1070 | Phdr->p_paddr = Cmd.LMAExpr().getValue(); | |
| 1071 | Phdr->HasLMA = true; | |
| 1083 | if (cmd.lmaExpr) { | |
| 1084 | phdr->p_paddr = cmd.lmaExpr().getValue(); | |
| 1085 | phdr->hasLMA = true; | |
| 1072 | 1086 | } |
| 1073 | Ret.push_back(Phdr); | |
| 1087 | ret.push_back(phdr); | |
| 1074 | 1088 | } |
| 1075 | 1089 | |
| 1076 | 1090 | // Add output sections to program headers. |
| 1077 | for (OutputSection *Sec : OutputSections) { | |
| 1091 | for (OutputSection *sec : outputSections) { | |
| 1078 | 1092 | // Assign headers specified by linker script |
| 1079 | for (size_t Id : getPhdrIndices(Sec)) { | |
| 1080 | Ret[Id]->add(Sec); | |
| 1081 | if (!PhdrsCommands[Id].Flags.hasValue()) | |
| 1082 | Ret[Id]->p_flags |= Sec->getPhdrFlags(); | |
| 1093 | for (size_t id : getPhdrIndices(sec)) { | |
| 1094 | ret[id]->add(sec); | |
| 1095 | if (!phdrsCommands[id].flags.hasValue()) | |
| 1096 | ret[id]->p_flags |= sec->getPhdrFlags(); | |
| 1083 | 1097 | } |
| 1084 | 1098 | } |
| 1085 | return Ret; | |
| 1099 | return ret; | |
| 1086 | 1100 | } |
| 1087 | 1101 | |
| 1088 | 1102 | // Returns true if we should emit an .interp section. |
| ... | ... | @@ -1091,54 +1105,54 @@ std::vector<PhdrEntry *> LinkerScript::createPhdrs() { |
| 1091 | 1105 | // no PT_INTERP is there, there's no place to emit an |
| 1092 | 1106 | // .interp, so we don't do that in that case. |
| 1093 | 1107 | bool LinkerScript::needsInterpSection() { |
| 1094 | if (PhdrsCommands.empty()) | |
| 1108 | if (phdrsCommands.empty()) | |
| 1095 | 1109 | return true; |
| 1096 | for (PhdrsCommand &Cmd : PhdrsCommands) | |
| 1097 | if (Cmd.Type == PT_INTERP) | |
| 1110 | for (PhdrsCommand &cmd : phdrsCommands) | |
| 1111 | if (cmd.type == PT_INTERP) | |
| 1098 | 1112 | return true; |
| 1099 | 1113 | return false; |
| 1100 | 1114 | } |
| 1101 | 1115 | |
| 1102 | ExprValue LinkerScript::getSymbolValue(StringRef Name, const Twine &Loc) { | |
| 1103 | if (Name == ".") { | |
| 1104 | if (Ctx) | |
| 1105 | return {Ctx->OutSec, false, Dot - Ctx->OutSec->Addr, Loc}; | |
| 1106 | error(Loc + ": unable to get location counter value"); | |
| 1116 | ExprValue LinkerScript::getSymbolValue(StringRef name, const Twine &loc) { | |
| 1117 | if (name == ".") { | |
| 1118 | if (ctx) | |
| 1119 | return {ctx->outSec, false, dot - ctx->outSec->addr, loc}; | |
| 1120 | error(loc + ": unable to get location counter value"); | |
| 1107 | 1121 | return 0; |
| 1108 | 1122 | } |
| 1109 | 1123 | |
| 1110 | if (Symbol *Sym = Symtab->find(Name)) { | |
| 1111 | if (auto *DS = dyn_cast<Defined>(Sym)) | |
| 1112 | return {DS->Section, false, DS->Value, Loc}; | |
| 1113 | if (isa<SharedSymbol>(Sym)) | |
| 1114 | if (!ErrorOnMissingSection) | |
| 1115 | return {nullptr, false, 0, Loc}; | |
| 1124 | if (Symbol *sym = symtab->find(name)) { | |
| 1125 | if (auto *ds = dyn_cast<Defined>(sym)) | |
| 1126 | return {ds->section, false, ds->value, loc}; | |
| 1127 | if (isa<SharedSymbol>(sym)) | |
| 1128 | if (!errorOnMissingSection) | |
| 1129 | return {nullptr, false, 0, loc}; | |
| 1116 | 1130 | } |
| 1117 | 1131 | |
| 1118 | error(Loc + ": symbol not found: " + Name); | |
| 1132 | error(loc + ": symbol not found: " + name); | |
| 1119 | 1133 | return 0; |
| 1120 | 1134 | } |
| 1121 | 1135 | |
| 1122 | 1136 | // Returns the index of the segment named Name. |
| 1123 | static Optional<size_t> getPhdrIndex(ArrayRef<PhdrsCommand> Vec, | |
| 1124 | StringRef Name) { | |
| 1125 | for (size_t I = 0; I < Vec.size(); ++I) | |
| 1126 | if (Vec[I].Name == Name) | |
| 1127 | return I; | |
| 1137 | static Optional<size_t> getPhdrIndex(ArrayRef<PhdrsCommand> vec, | |
| 1138 | StringRef name) { | |
| 1139 | for (size_t i = 0; i < vec.size(); ++i) | |
| 1140 | if (vec[i].name == name) | |
| 1141 | return i; | |
| 1128 | 1142 | return None; |
| 1129 | 1143 | } |
| 1130 | 1144 | |
| 1131 | 1145 | // Returns indices of ELF headers containing specific section. Each index is a |
| 1132 | 1146 | // zero based number of ELF header listed within PHDRS {} script block. |
| 1133 | std::vector<size_t> LinkerScript::getPhdrIndices(OutputSection *Cmd) { | |
| 1134 | std::vector<size_t> Ret; | |
| 1135 | ||
| 1136 | for (StringRef S : Cmd->Phdrs) { | |
| 1137 | if (Optional<size_t> Idx = getPhdrIndex(PhdrsCommands, S)) | |
| 1138 | Ret.push_back(*Idx); | |
| 1139 | else if (S != "NONE") | |
| 1140 | error(Cmd->Location + ": section header '" + S + | |
| 1147 | std::vector<size_t> LinkerScript::getPhdrIndices(OutputSection *cmd) { | |
| 1148 | std::vector<size_t> ret; | |
| 1149 | ||
| 1150 | for (StringRef s : cmd->phdrs) { | |
| 1151 | if (Optional<size_t> idx = getPhdrIndex(phdrsCommands, s)) | |
| 1152 | ret.push_back(*idx); | |
| 1153 | else if (s != "NONE") | |
| 1154 | error(cmd->location + ": section header '" + s + | |
| 1141 | 1155 | "' is not listed in PHDRS"); |
| 1142 | 1156 | } |
| 1143 | return Ret; | |
| 1157 | return ret; | |
| 1144 | 1158 | } |
deps/lld/ELF/LinkerScript.h+110-112| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- LinkerScript.h -------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -32,7 +31,6 @@ namespace elf { |
| 32 | 31 | class Defined; |
| 33 | 32 | class InputSection; |
| 34 | 33 | class InputSectionBase; |
| 35 | class InputSectionBase; | |
| 36 | 34 | class OutputSection; |
| 37 | 35 | class SectionBase; |
| 38 | 36 | class Symbol; |
| ... | ... | @@ -40,35 +38,35 @@ class ThunkSection; |
| 40 | 38 | |
| 41 | 39 | // This represents an r-value in the linker script. |
| 42 | 40 | struct ExprValue { |
| 43 | ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val, | |
| 44 | const Twine &Loc) | |
| 45 | : Sec(Sec), ForceAbsolute(ForceAbsolute), Val(Val), Loc(Loc.str()) {} | |
| 41 | ExprValue(SectionBase *sec, bool forceAbsolute, uint64_t val, | |
| 42 | const Twine &loc) | |
| 43 | : sec(sec), forceAbsolute(forceAbsolute), val(val), loc(loc.str()) {} | |
| 46 | 44 | |
| 47 | ExprValue(uint64_t Val) : ExprValue(nullptr, false, Val, "") {} | |
| 45 | ExprValue(uint64_t val) : ExprValue(nullptr, false, val, "") {} | |
| 48 | 46 | |
| 49 | bool isAbsolute() const { return ForceAbsolute || Sec == nullptr; } | |
| 47 | bool isAbsolute() const { return forceAbsolute || sec == nullptr; } | |
| 50 | 48 | uint64_t getValue() const; |
| 51 | 49 | uint64_t getSecAddr() const; |
| 52 | 50 | uint64_t getSectionOffset() const; |
| 53 | 51 | |
| 54 | 52 | // If a value is relative to a section, it has a non-null Sec. |
| 55 | SectionBase *Sec; | |
| 53 | SectionBase *sec; | |
| 56 | 54 | |
| 57 | 55 | // True if this expression is enclosed in ABSOLUTE(). |
| 58 | 56 | // This flag affects the return value of getValue(). |
| 59 | bool ForceAbsolute; | |
| 57 | bool forceAbsolute; | |
| 60 | 58 | |
| 61 | uint64_t Val; | |
| 62 | uint64_t Alignment = 1; | |
| 59 | uint64_t val; | |
| 60 | uint64_t alignment = 1; | |
| 63 | 61 | |
| 64 | 62 | // Original source location. Used for error messages. |
| 65 | std::string Loc; | |
| 63 | std::string loc; | |
| 66 | 64 | }; |
| 67 | 65 | |
| 68 | 66 | // This represents an expression in the linker script. |
| 69 | 67 | // ScriptParser::readExpr reads an expression and returns an Expr. |
| 70 | 68 | // Later, we evaluate the expression by calling the function. |
| 71 | typedef std::function<ExprValue()> Expr; | |
| 69 | using Expr = std::function<ExprValue()>; | |
| 72 | 70 | |
| 73 | 71 | // This enum is used to implement linker script SECTIONS command. |
| 74 | 72 | // https://sourceware.org/binutils/docs/ld/SECTIONS.html#SECTIONS |
| ... | ... | @@ -80,42 +78,42 @@ enum SectionsCommandKind { |
| 80 | 78 | }; |
| 81 | 79 | |
| 82 | 80 | struct BaseCommand { |
| 83 | BaseCommand(int K) : Kind(K) {} | |
| 84 | int Kind; | |
| 81 | BaseCommand(int k) : kind(k) {} | |
| 82 | int kind; | |
| 85 | 83 | }; |
| 86 | 84 | |
| 87 | 85 | // This represents ". = <expr>" or "<symbol> = <expr>". |
| 88 | 86 | struct SymbolAssignment : BaseCommand { |
| 89 | SymbolAssignment(StringRef Name, Expr E, std::string Loc) | |
| 90 | : BaseCommand(AssignmentKind), Name(Name), Expression(E), Location(Loc) {} | |
| 87 | SymbolAssignment(StringRef name, Expr e, std::string loc) | |
| 88 | : BaseCommand(AssignmentKind), name(name), expression(e), location(loc) {} | |
| 91 | 89 | |
| 92 | static bool classof(const BaseCommand *C) { | |
| 93 | return C->Kind == AssignmentKind; | |
| 90 | static bool classof(const BaseCommand *c) { | |
| 91 | return c->kind == AssignmentKind; | |
| 94 | 92 | } |
| 95 | 93 | |
| 96 | 94 | // The LHS of an expression. Name is either a symbol name or ".". |
| 97 | StringRef Name; | |
| 98 | Defined *Sym = nullptr; | |
| 95 | StringRef name; | |
| 96 | Defined *sym = nullptr; | |
| 99 | 97 | |
| 100 | 98 | // The RHS of an expression. |
| 101 | Expr Expression; | |
| 99 | Expr expression; | |
| 102 | 100 | |
| 103 | 101 | // Command attributes for PROVIDE, HIDDEN and PROVIDE_HIDDEN. |
| 104 | bool Provide = false; | |
| 105 | bool Hidden = false; | |
| 102 | bool provide = false; | |
| 103 | bool hidden = false; | |
| 106 | 104 | |
| 107 | 105 | // Holds file name and line number for error reporting. |
| 108 | std::string Location; | |
| 106 | std::string location; | |
| 109 | 107 | |
| 110 | 108 | // A string representation of this command. We use this for -Map. |
| 111 | std::string CommandString; | |
| 109 | std::string commandString; | |
| 112 | 110 | |
| 113 | 111 | // Address of this assignment command. |
| 114 | unsigned Addr; | |
| 112 | unsigned addr; | |
| 115 | 113 | |
| 116 | 114 | // Size of this assignment command. This is usually 0, but if |
| 117 | 115 | // you move '.' this may be greater than 0. |
| 118 | unsigned Size; | |
| 116 | unsigned size; | |
| 119 | 117 | }; |
| 120 | 118 | |
| 121 | 119 | // Linker scripts allow additional constraints to be put on ouput sections. |
| ... | ... | @@ -128,83 +126,83 @@ enum class ConstraintKind { NoConstraint, ReadOnly, ReadWrite }; |
| 128 | 126 | // target memory. Instances of the struct are created by parsing the |
| 129 | 127 | // MEMORY command. |
| 130 | 128 | struct MemoryRegion { |
| 131 | MemoryRegion(StringRef Name, uint64_t Origin, uint64_t Length, uint32_t Flags, | |
| 132 | uint32_t NegFlags) | |
| 133 | : Name(Name), Origin(Origin), Length(Length), Flags(Flags), | |
| 134 | NegFlags(NegFlags) {} | |
| 135 | ||
| 136 | std::string Name; | |
| 137 | uint64_t Origin; | |
| 138 | uint64_t Length; | |
| 139 | uint32_t Flags; | |
| 140 | uint32_t NegFlags; | |
| 141 | uint64_t CurPos = 0; | |
| 129 | MemoryRegion(StringRef name, uint64_t origin, uint64_t length, uint32_t flags, | |
| 130 | uint32_t negFlags) | |
| 131 | : name(name), origin(origin), length(length), flags(flags), | |
| 132 | negFlags(negFlags) {} | |
| 133 | ||
| 134 | std::string name; | |
| 135 | uint64_t origin; | |
| 136 | uint64_t length; | |
| 137 | uint32_t flags; | |
| 138 | uint32_t negFlags; | |
| 139 | uint64_t curPos = 0; | |
| 142 | 140 | }; |
| 143 | 141 | |
| 144 | 142 | // This struct represents one section match pattern in SECTIONS() command. |
| 145 | 143 | // It can optionally have negative match pattern for EXCLUDED_FILE command. |
| 146 | 144 | // Also it may be surrounded with SORT() command, so contains sorting rules. |
| 147 | 145 | struct SectionPattern { |
| 148 | SectionPattern(StringMatcher &&Pat1, StringMatcher &&Pat2) | |
| 149 | : ExcludedFilePat(Pat1), SectionPat(Pat2), | |
| 150 | SortOuter(SortSectionPolicy::Default), | |
| 151 | SortInner(SortSectionPolicy::Default) {} | |
| 152 | ||
| 153 | StringMatcher ExcludedFilePat; | |
| 154 | StringMatcher SectionPat; | |
| 155 | SortSectionPolicy SortOuter; | |
| 156 | SortSectionPolicy SortInner; | |
| 146 | SectionPattern(StringMatcher &&pat1, StringMatcher &&pat2) | |
| 147 | : excludedFilePat(pat1), sectionPat(pat2), | |
| 148 | sortOuter(SortSectionPolicy::Default), | |
| 149 | sortInner(SortSectionPolicy::Default) {} | |
| 150 | ||
| 151 | StringMatcher excludedFilePat; | |
| 152 | StringMatcher sectionPat; | |
| 153 | SortSectionPolicy sortOuter; | |
| 154 | SortSectionPolicy sortInner; | |
| 157 | 155 | }; |
| 158 | 156 | |
| 159 | 157 | struct InputSectionDescription : BaseCommand { |
| 160 | InputSectionDescription(StringRef FilePattern) | |
| 161 | : BaseCommand(InputSectionKind), FilePat(FilePattern) {} | |
| 158 | InputSectionDescription(StringRef filePattern) | |
| 159 | : BaseCommand(InputSectionKind), filePat(filePattern) {} | |
| 162 | 160 | |
| 163 | static bool classof(const BaseCommand *C) { | |
| 164 | return C->Kind == InputSectionKind; | |
| 161 | static bool classof(const BaseCommand *c) { | |
| 162 | return c->kind == InputSectionKind; | |
| 165 | 163 | } |
| 166 | 164 | |
| 167 | StringMatcher FilePat; | |
| 165 | StringMatcher filePat; | |
| 168 | 166 | |
| 169 | 167 | // Input sections that matches at least one of SectionPatterns |
| 170 | 168 | // will be associated with this InputSectionDescription. |
| 171 | std::vector<SectionPattern> SectionPatterns; | |
| 169 | std::vector<SectionPattern> sectionPatterns; | |
| 172 | 170 | |
| 173 | std::vector<InputSection *> Sections; | |
| 171 | std::vector<InputSection *> sections; | |
| 174 | 172 | |
| 175 | 173 | // Temporary record of synthetic ThunkSection instances and the pass that |
| 176 | 174 | // they were created in. This is used to insert newly created ThunkSections |
| 177 | 175 | // into Sections at the end of a createThunks() pass. |
| 178 | std::vector<std::pair<ThunkSection *, uint32_t>> ThunkSections; | |
| 176 | std::vector<std::pair<ThunkSection *, uint32_t>> thunkSections; | |
| 179 | 177 | }; |
| 180 | 178 | |
| 181 | 179 | // Represents BYTE(), SHORT(), LONG(), or QUAD(). |
| 182 | 180 | struct ByteCommand : BaseCommand { |
| 183 | ByteCommand(Expr E, unsigned Size, std::string CommandString) | |
| 184 | : BaseCommand(ByteKind), CommandString(CommandString), Expression(E), | |
| 185 | Size(Size) {} | |
| 181 | ByteCommand(Expr e, unsigned size, std::string commandString) | |
| 182 | : BaseCommand(ByteKind), commandString(commandString), expression(e), | |
| 183 | size(size) {} | |
| 186 | 184 | |
| 187 | static bool classof(const BaseCommand *C) { return C->Kind == ByteKind; } | |
| 185 | static bool classof(const BaseCommand *c) { return c->kind == ByteKind; } | |
| 188 | 186 | |
| 189 | 187 | // Keeps string representing the command. Used for -Map" is perhaps better. |
| 190 | std::string CommandString; | |
| 188 | std::string commandString; | |
| 191 | 189 | |
| 192 | Expr Expression; | |
| 190 | Expr expression; | |
| 193 | 191 | |
| 194 | 192 | // This is just an offset of this assignment command in the output section. |
| 195 | unsigned Offset; | |
| 193 | unsigned offset; | |
| 196 | 194 | |
| 197 | 195 | // Size of this data command. |
| 198 | unsigned Size; | |
| 196 | unsigned size; | |
| 199 | 197 | }; |
| 200 | 198 | |
| 201 | 199 | struct PhdrsCommand { |
| 202 | StringRef Name; | |
| 203 | unsigned Type = llvm::ELF::PT_NULL; | |
| 204 | bool HasFilehdr = false; | |
| 205 | bool HasPhdrs = false; | |
| 206 | llvm::Optional<unsigned> Flags; | |
| 207 | Expr LMAExpr = nullptr; | |
| 200 | StringRef name; | |
| 201 | unsigned type = llvm::ELF::PT_NULL; | |
| 202 | bool hasFilehdr = false; | |
| 203 | bool hasPhdrs = false; | |
| 204 | llvm::Optional<unsigned> flags; | |
| 205 | Expr lmaExpr = nullptr; | |
| 208 | 206 | }; |
| 209 | 207 | |
| 210 | 208 | class LinkerScript final { |
| ... | ... | @@ -213,35 +211,35 @@ class LinkerScript final { |
| 213 | 211 | // not be used outside of the scope of a call to the above functions. |
| 214 | 212 | struct AddressState { |
| 215 | 213 | AddressState(); |
| 216 | uint64_t ThreadBssOffset = 0; | |
| 217 | OutputSection *OutSec = nullptr; | |
| 218 | MemoryRegion *MemRegion = nullptr; | |
| 219 | MemoryRegion *LMARegion = nullptr; | |
| 220 | uint64_t LMAOffset = 0; | |
| 214 | uint64_t threadBssOffset = 0; | |
| 215 | OutputSection *outSec = nullptr; | |
| 216 | MemoryRegion *memRegion = nullptr; | |
| 217 | MemoryRegion *lmaRegion = nullptr; | |
| 218 | uint64_t lmaOffset = 0; | |
| 221 | 219 | }; |
| 222 | 220 | |
| 223 | llvm::DenseMap<StringRef, OutputSection *> NameToOutputSection; | |
| 221 | llvm::DenseMap<StringRef, OutputSection *> nameToOutputSection; | |
| 224 | 222 | |
| 225 | void addSymbol(SymbolAssignment *Cmd); | |
| 226 | void assignSymbol(SymbolAssignment *Cmd, bool InSec); | |
| 227 | void setDot(Expr E, const Twine &Loc, bool InSec); | |
| 228 | void expandOutputSection(uint64_t Size); | |
| 229 | void expandMemoryRegions(uint64_t Size); | |
| 223 | void addSymbol(SymbolAssignment *cmd); | |
| 224 | void assignSymbol(SymbolAssignment *cmd, bool inSec); | |
| 225 | void setDot(Expr e, const Twine &loc, bool inSec); | |
| 226 | void expandOutputSection(uint64_t size); | |
| 227 | void expandMemoryRegions(uint64_t size); | |
| 230 | 228 | |
| 231 | 229 | std::vector<InputSection *> |
| 232 | 230 | computeInputSections(const InputSectionDescription *); |
| 233 | 231 | |
| 234 | std::vector<InputSection *> createInputSectionList(OutputSection &Cmd); | |
| 232 | std::vector<InputSection *> createInputSectionList(OutputSection &cmd); | |
| 235 | 233 | |
| 236 | std::vector<size_t> getPhdrIndices(OutputSection *Sec); | |
| 234 | std::vector<size_t> getPhdrIndices(OutputSection *sec); | |
| 237 | 235 | |
| 238 | MemoryRegion *findMemoryRegion(OutputSection *Sec); | |
| 236 | MemoryRegion *findMemoryRegion(OutputSection *sec); | |
| 239 | 237 | |
| 240 | void switchTo(OutputSection *Sec); | |
| 241 | uint64_t advance(uint64_t Size, unsigned Align); | |
| 242 | void output(InputSection *Sec); | |
| 238 | void switchTo(OutputSection *sec); | |
| 239 | uint64_t advance(uint64_t size, unsigned align); | |
| 240 | void output(InputSection *sec); | |
| 243 | 241 | |
| 244 | void assignOffsets(OutputSection *Sec); | |
| 242 | void assignOffsets(OutputSection *sec); | |
| 245 | 243 | |
| 246 | 244 | // Ctx captures the local AddressState and makes it accessible |
| 247 | 245 | // deliberately. This is needed as there are some cases where we cannot just |
| ... | ... | @@ -249,21 +247,21 @@ class LinkerScript final { |
| 249 | 247 | // script parser. |
| 250 | 248 | // This should remain a plain pointer as its lifetime is smaller than |
| 251 | 249 | // LinkerScript. |
| 252 | AddressState *Ctx = nullptr; | |
| 250 | AddressState *ctx = nullptr; | |
| 253 | 251 | |
| 254 | OutputSection *Aether; | |
| 252 | OutputSection *aether; | |
| 255 | 253 | |
| 256 | uint64_t Dot; | |
| 254 | uint64_t dot; | |
| 257 | 255 | |
| 258 | 256 | public: |
| 259 | OutputSection *createOutputSection(StringRef Name, StringRef Location); | |
| 260 | OutputSection *getOrCreateOutputSection(StringRef Name); | |
| 257 | OutputSection *createOutputSection(StringRef name, StringRef location); | |
| 258 | OutputSection *getOrCreateOutputSection(StringRef name); | |
| 261 | 259 | |
| 262 | bool hasPhdrsCommands() { return !PhdrsCommands.empty(); } | |
| 263 | uint64_t getDot() { return Dot; } | |
| 264 | void discard(ArrayRef<InputSection *> V); | |
| 260 | bool hasPhdrsCommands() { return !phdrsCommands.empty(); } | |
| 261 | uint64_t getDot() { return dot; } | |
| 262 | void discard(ArrayRef<InputSection *> v); | |
| 265 | 263 | |
| 266 | ExprValue getSymbolValue(StringRef Name, const Twine &Loc); | |
| 264 | ExprValue getSymbolValue(StringRef name, const Twine &loc); | |
| 267 | 265 | |
| 268 | 266 | void addOrphanSections(); |
| 269 | 267 | void adjustSectionsBeforeSorting(); |
| ... | ... | @@ -272,9 +270,9 @@ public: |
| 272 | 270 | std::vector<PhdrEntry *> createPhdrs(); |
| 273 | 271 | bool needsInterpSection(); |
| 274 | 272 | |
| 275 | bool shouldKeep(InputSectionBase *S); | |
| 273 | bool shouldKeep(InputSectionBase *s); | |
| 276 | 274 | void assignAddresses(); |
| 277 | void allocateHeaders(std::vector<PhdrEntry *> &Phdrs); | |
| 275 | void allocateHeaders(std::vector<PhdrEntry *> &phdrs); | |
| 278 | 276 | void processSectionCommands(); |
| 279 | 277 | void declareSymbols(); |
| 280 | 278 | |
| ... | ... | @@ -282,31 +280,31 @@ public: |
| 282 | 280 | void processInsertCommands(); |
| 283 | 281 | |
| 284 | 282 | // SECTIONS command list. |
| 285 | std::vector<BaseCommand *> SectionCommands; | |
| 283 | std::vector<BaseCommand *> sectionCommands; | |
| 286 | 284 | |
| 287 | 285 | // PHDRS command list. |
| 288 | std::vector<PhdrsCommand> PhdrsCommands; | |
| 286 | std::vector<PhdrsCommand> phdrsCommands; | |
| 289 | 287 | |
| 290 | bool HasSectionsCommand = false; | |
| 291 | bool ErrorOnMissingSection = false; | |
| 288 | bool hasSectionsCommand = false; | |
| 289 | bool errorOnMissingSection = false; | |
| 292 | 290 | |
| 293 | 291 | // List of section patterns specified with KEEP commands. They will |
| 294 | 292 | // be kept even if they are unused and --gc-sections is specified. |
| 295 | std::vector<InputSectionDescription *> KeptSections; | |
| 293 | std::vector<InputSectionDescription *> keptSections; | |
| 296 | 294 | |
| 297 | 295 | // A map from memory region name to a memory region descriptor. |
| 298 | llvm::MapVector<llvm::StringRef, MemoryRegion *> MemoryRegions; | |
| 296 | llvm::MapVector<llvm::StringRef, MemoryRegion *> memoryRegions; | |
| 299 | 297 | |
| 300 | 298 | // A list of symbols referenced by the script. |
| 301 | std::vector<llvm::StringRef> ReferencedSymbols; | |
| 299 | std::vector<llvm::StringRef> referencedSymbols; | |
| 302 | 300 | |
| 303 | 301 | // Used to implement INSERT [AFTER|BEFORE]. Contains commands that need |
| 304 | 302 | // to be inserted into SECTIONS commands list. |
| 305 | llvm::DenseMap<StringRef, std::vector<BaseCommand *>> InsertAfterCommands; | |
| 306 | llvm::DenseMap<StringRef, std::vector<BaseCommand *>> InsertBeforeCommands; | |
| 303 | llvm::DenseMap<StringRef, std::vector<BaseCommand *>> insertAfterCommands; | |
| 304 | llvm::DenseMap<StringRef, std::vector<BaseCommand *>> insertBeforeCommands; | |
| 307 | 305 | }; |
| 308 | 306 | |
| 309 | extern LinkerScript *Script; | |
| 307 | extern LinkerScript *script; | |
| 310 | 308 | |
| 311 | 309 | } // end namespace elf |
| 312 | 310 | } // end namespace lld |
deps/lld/ELF/MapFile.cpp+116-118| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- MapFile.cpp --------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -38,69 +37,67 @@ using namespace llvm::object; |
| 38 | 37 | using namespace lld; |
| 39 | 38 | using namespace lld::elf; |
| 40 | 39 | |
| 41 | typedef DenseMap<const SectionBase *, SmallVector<Defined *, 4>> SymbolMapTy; | |
| 40 | using SymbolMapTy = DenseMap<const SectionBase *, SmallVector<Defined *, 4>>; | |
| 42 | 41 | |
| 43 | static const std::string Indent8 = " "; // 8 spaces | |
| 44 | static const std::string Indent16 = " "; // 16 spaces | |
| 42 | static const std::string indent8 = " "; // 8 spaces | |
| 43 | static const std::string indent16 = " "; // 16 spaces | |
| 45 | 44 | |
| 46 | 45 | // Print out the first three columns of a line. |
| 47 | static void writeHeader(raw_ostream &OS, uint64_t VMA, uint64_t LMA, | |
| 48 | uint64_t Size, uint64_t Align) { | |
| 49 | if (Config->Is64) | |
| 50 | OS << format("%16llx %16llx %8llx %5lld ", VMA, LMA, Size, Align); | |
| 46 | static void writeHeader(raw_ostream &os, uint64_t vma, uint64_t lma, | |
| 47 | uint64_t size, uint64_t align) { | |
| 48 | if (config->is64) | |
| 49 | os << format("%16llx %16llx %8llx %5lld ", vma, lma, size, align); | |
| 51 | 50 | else |
| 52 | OS << format("%8llx %8llx %8llx %5lld ", VMA, LMA, Size, Align); | |
| 51 | os << format("%8llx %8llx %8llx %5lld ", vma, lma, size, align); | |
| 53 | 52 | } |
| 54 | 53 | |
| 55 | 54 | // Returns a list of all symbols that we want to print out. |
| 56 | 55 | static std::vector<Defined *> getSymbols() { |
| 57 | std::vector<Defined *> V; | |
| 58 | for (InputFile *File : ObjectFiles) | |
| 59 | for (Symbol *B : File->getSymbols()) | |
| 60 | if (auto *DR = dyn_cast<Defined>(B)) | |
| 61 | if (!DR->isSection() && DR->Section && DR->Section->Live && | |
| 62 | (DR->File == File || DR->NeedsPltAddr || DR->Section->Bss)) | |
| 63 | V.push_back(DR); | |
| 64 | return V; | |
| 56 | std::vector<Defined *> v; | |
| 57 | for (InputFile *file : objectFiles) | |
| 58 | for (Symbol *b : file->getSymbols()) | |
| 59 | if (auto *dr = dyn_cast<Defined>(b)) | |
| 60 | if (!dr->isSection() && dr->section && dr->section->isLive() && | |
| 61 | (dr->file == file || dr->needsPltAddr || dr->section->bss)) | |
| 62 | v.push_back(dr); | |
| 63 | return v; | |
| 65 | 64 | } |
| 66 | 65 | |
| 67 | 66 | // Returns a map from sections to their symbols. |
| 68 | static SymbolMapTy getSectionSyms(ArrayRef<Defined *> Syms) { | |
| 69 | SymbolMapTy Ret; | |
| 70 | for (Defined *DR : Syms) | |
| 71 | Ret[DR->Section].push_back(DR); | |
| 67 | static SymbolMapTy getSectionSyms(ArrayRef<Defined *> syms) { | |
| 68 | SymbolMapTy ret; | |
| 69 | for (Defined *dr : syms) | |
| 70 | ret[dr->section].push_back(dr); | |
| 72 | 71 | |
| 73 | 72 | // Sort symbols by address. We want to print out symbols in the |
| 74 | 73 | // order in the output file rather than the order they appeared |
| 75 | 74 | // in the input files. |
| 76 | for (auto &It : Ret) { | |
| 77 | SmallVectorImpl<Defined *> &V = It.second; | |
| 78 | std::stable_sort(V.begin(), V.end(), [](Defined *A, Defined *B) { | |
| 79 | return A->getVA() < B->getVA(); | |
| 75 | for (auto &it : ret) | |
| 76 | llvm::stable_sort(it.second, [](Defined *a, Defined *b) { | |
| 77 | return a->getVA() < b->getVA(); | |
| 80 | 78 | }); |
| 81 | } | |
| 82 | return Ret; | |
| 79 | return ret; | |
| 83 | 80 | } |
| 84 | 81 | |
| 85 | 82 | // Construct a map from symbols to their stringified representations. |
| 86 | 83 | // Demangling symbols (which is what toString() does) is slow, so |
| 87 | 84 | // we do that in batch using parallel-for. |
| 88 | 85 | static DenseMap<Symbol *, std::string> |
| 89 | getSymbolStrings(ArrayRef<Defined *> Syms) { | |
| 90 | std::vector<std::string> Str(Syms.size()); | |
| 91 | parallelForEachN(0, Syms.size(), [&](size_t I) { | |
| 92 | raw_string_ostream OS(Str[I]); | |
| 93 | OutputSection *OSec = Syms[I]->getOutputSection(); | |
| 94 | uint64_t VMA = Syms[I]->getVA(); | |
| 95 | uint64_t LMA = OSec ? OSec->getLMA() + VMA - OSec->getVA(0) : 0; | |
| 96 | writeHeader(OS, VMA, LMA, Syms[I]->getSize(), 1); | |
| 97 | OS << Indent16 << toString(*Syms[I]); | |
| 86 | getSymbolStrings(ArrayRef<Defined *> syms) { | |
| 87 | std::vector<std::string> str(syms.size()); | |
| 88 | parallelForEachN(0, syms.size(), [&](size_t i) { | |
| 89 | raw_string_ostream os(str[i]); | |
| 90 | OutputSection *osec = syms[i]->getOutputSection(); | |
| 91 | uint64_t vma = syms[i]->getVA(); | |
| 92 | uint64_t lma = osec ? osec->getLMA() + vma - osec->getVA(0) : 0; | |
| 93 | writeHeader(os, vma, lma, syms[i]->getSize(), 1); | |
| 94 | os << indent16 << toString(*syms[i]); | |
| 98 | 95 | }); |
| 99 | 96 | |
| 100 | DenseMap<Symbol *, std::string> Ret; | |
| 101 | for (size_t I = 0, E = Syms.size(); I < E; ++I) | |
| 102 | Ret[Syms[I]] = std::move(Str[I]); | |
| 103 | return Ret; | |
| 97 | DenseMap<Symbol *, std::string> ret; | |
| 98 | for (size_t i = 0, e = syms.size(); i < e; ++i) | |
| 99 | ret[syms[i]] = std::move(str[i]); | |
| 100 | return ret; | |
| 104 | 101 | } |
| 105 | 102 | |
| 106 | 103 | // Print .eh_frame contents. Since the section consists of EhSectionPieces, |
| ... | ... | @@ -109,114 +106,115 @@ getSymbolStrings(ArrayRef<Defined *> Syms) { |
| 109 | 106 | // .eh_frame tend to contain a lot of section pieces that are contiguous |
| 110 | 107 | // both in input file and output file. Such pieces are squashed before |
| 111 | 108 | // being displayed to make output compact. |
| 112 | static void printEhFrame(raw_ostream &OS, OutputSection *OSec) { | |
| 113 | std::vector<EhSectionPiece> Pieces; | |
| 109 | static void printEhFrame(raw_ostream &os, const EhFrameSection *sec) { | |
| 110 | std::vector<EhSectionPiece> pieces; | |
| 114 | 111 | |
| 115 | auto Add = [&](const EhSectionPiece &P) { | |
| 112 | auto add = [&](const EhSectionPiece &p) { | |
| 116 | 113 | // If P is adjacent to Last, squash the two. |
| 117 | if (!Pieces.empty()) { | |
| 118 | EhSectionPiece &Last = Pieces.back(); | |
| 119 | if (Last.Sec == P.Sec && Last.InputOff + Last.Size == P.InputOff && | |
| 120 | Last.OutputOff + Last.Size == P.OutputOff) { | |
| 121 | Last.Size += P.Size; | |
| 114 | if (!pieces.empty()) { | |
| 115 | EhSectionPiece &last = pieces.back(); | |
| 116 | if (last.sec == p.sec && last.inputOff + last.size == p.inputOff && | |
| 117 | last.outputOff + last.size == p.outputOff) { | |
| 118 | last.size += p.size; | |
| 122 | 119 | return; |
| 123 | 120 | } |
| 124 | 121 | } |
| 125 | Pieces.push_back(P); | |
| 122 | pieces.push_back(p); | |
| 126 | 123 | }; |
| 127 | 124 | |
| 128 | 125 | // Gather section pieces. |
| 129 | for (const CieRecord *Rec : In.EhFrame->getCieRecords()) { | |
| 130 | Add(*Rec->Cie); | |
| 131 | for (const EhSectionPiece *Fde : Rec->Fdes) | |
| 132 | Add(*Fde); | |
| 126 | for (const CieRecord *rec : sec->getCieRecords()) { | |
| 127 | add(*rec->cie); | |
| 128 | for (const EhSectionPiece *fde : rec->fdes) | |
| 129 | add(*fde); | |
| 133 | 130 | } |
| 134 | 131 | |
| 135 | 132 | // Print out section pieces. |
| 136 | for (EhSectionPiece &P : Pieces) { | |
| 137 | writeHeader(OS, OSec->Addr + P.OutputOff, OSec->getLMA() + P.OutputOff, | |
| 138 | P.Size, 1); | |
| 139 | OS << Indent8 << toString(P.Sec->File) << ":(" << P.Sec->Name << "+0x" | |
| 140 | << Twine::utohexstr(P.InputOff) + ")\n"; | |
| 133 | const OutputSection *osec = sec->getOutputSection(); | |
| 134 | for (EhSectionPiece &p : pieces) { | |
| 135 | writeHeader(os, osec->addr + p.outputOff, osec->getLMA() + p.outputOff, | |
| 136 | p.size, 1); | |
| 137 | os << indent8 << toString(p.sec->file) << ":(" << p.sec->name << "+0x" | |
| 138 | << Twine::utohexstr(p.inputOff) + ")\n"; | |
| 141 | 139 | } |
| 142 | 140 | } |
| 143 | 141 | |
| 144 | 142 | void elf::writeMapFile() { |
| 145 | if (Config->MapFile.empty()) | |
| 143 | if (config->mapFile.empty()) | |
| 146 | 144 | return; |
| 147 | 145 | |
| 148 | 146 | // Open a map file for writing. |
| 149 | std::error_code EC; | |
| 150 | raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None); | |
| 151 | if (EC) { | |
| 152 | error("cannot open " + Config->MapFile + ": " + EC.message()); | |
| 147 | std::error_code ec; | |
| 148 | raw_fd_ostream os(config->mapFile, ec, sys::fs::F_None); | |
| 149 | if (ec) { | |
| 150 | error("cannot open " + config->mapFile + ": " + ec.message()); | |
| 153 | 151 | return; |
| 154 | 152 | } |
| 155 | 153 | |
| 156 | 154 | // Collect symbol info that we want to print out. |
| 157 | std::vector<Defined *> Syms = getSymbols(); | |
| 158 | SymbolMapTy SectionSyms = getSectionSyms(Syms); | |
| 159 | DenseMap<Symbol *, std::string> SymStr = getSymbolStrings(Syms); | |
| 155 | std::vector<Defined *> syms = getSymbols(); | |
| 156 | SymbolMapTy sectionSyms = getSectionSyms(syms); | |
| 157 | DenseMap<Symbol *, std::string> symStr = getSymbolStrings(syms); | |
| 160 | 158 | |
| 161 | 159 | // Print out the header line. |
| 162 | int W = Config->Is64 ? 16 : 8; | |
| 163 | OS << right_justify("VMA", W) << ' ' << right_justify("LMA", W) | |
| 160 | int w = config->is64 ? 16 : 8; | |
| 161 | os << right_justify("VMA", w) << ' ' << right_justify("LMA", w) | |
| 164 | 162 | << " Size Align Out In Symbol\n"; |
| 165 | 163 | |
| 166 | OutputSection* OSec = nullptr; | |
| 167 | for (BaseCommand *Base : Script->SectionCommands) { | |
| 168 | if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { | |
| 169 | if (Cmd->Provide && !Cmd->Sym) | |
| 164 | OutputSection* osec = nullptr; | |
| 165 | for (BaseCommand *base : script->sectionCommands) { | |
| 166 | if (auto *cmd = dyn_cast<SymbolAssignment>(base)) { | |
| 167 | if (cmd->provide && !cmd->sym) | |
| 170 | 168 | continue; |
| 171 | uint64_t LMA = OSec ? OSec->getLMA() + Cmd->Addr - OSec->getVA(0) : 0; | |
| 172 | writeHeader(OS, Cmd->Addr, LMA, Cmd->Size, 1); | |
| 173 | OS << Cmd->CommandString << '\n'; | |
| 169 | uint64_t lma = osec ? osec->getLMA() + cmd->addr - osec->getVA(0) : 0; | |
| 170 | writeHeader(os, cmd->addr, lma, cmd->size, 1); | |
| 171 | os << cmd->commandString << '\n'; | |
| 174 | 172 | continue; |
| 175 | 173 | } |
| 176 | 174 | |
| 177 | OSec = cast<OutputSection>(Base); | |
| 178 | writeHeader(OS, OSec->Addr, OSec->getLMA(), OSec->Size, OSec->Alignment); | |
| 179 | OS << OSec->Name << '\n'; | |
| 175 | osec = cast<OutputSection>(base); | |
| 176 | writeHeader(os, osec->addr, osec->getLMA(), osec->size, osec->alignment); | |
| 177 | os << osec->name << '\n'; | |
| 180 | 178 | |
| 181 | 179 | // Dump symbols for each input section. |
| 182 | for (BaseCommand *Base : OSec->SectionCommands) { | |
| 183 | if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) { | |
| 184 | for (InputSection *IS : ISD->Sections) { | |
| 185 | if (IS == In.EhFrame) { | |
| 186 | printEhFrame(OS, OSec); | |
| 180 | for (BaseCommand *base : osec->sectionCommands) { | |
| 181 | if (auto *isd = dyn_cast<InputSectionDescription>(base)) { | |
| 182 | for (InputSection *isec : isd->sections) { | |
| 183 | if (auto *ehSec = dyn_cast<EhFrameSection>(isec)) { | |
| 184 | printEhFrame(os, ehSec); | |
| 187 | 185 | continue; |
| 188 | 186 | } |
| 189 | 187 | |
| 190 | writeHeader(OS, IS->getVA(0), OSec->getLMA() + IS->getOffset(0), | |
| 191 | IS->getSize(), IS->Alignment); | |
| 192 | OS << Indent8 << toString(IS) << '\n'; | |
| 193 | for (Symbol *Sym : SectionSyms[IS]) | |
| 194 | OS << SymStr[Sym] << '\n'; | |
| 188 | writeHeader(os, isec->getVA(0), osec->getLMA() + isec->getOffset(0), | |
| 189 | isec->getSize(), isec->alignment); | |
| 190 | os << indent8 << toString(isec) << '\n'; | |
| 191 | for (Symbol *sym : sectionSyms[isec]) | |
| 192 | os << symStr[sym] << '\n'; | |
| 195 | 193 | } |
| 196 | 194 | continue; |
| 197 | 195 | } |
| 198 | 196 | |
| 199 | if (auto *Cmd = dyn_cast<ByteCommand>(Base)) { | |
| 200 | writeHeader(OS, OSec->Addr + Cmd->Offset, OSec->getLMA() + Cmd->Offset, | |
| 201 | Cmd->Size, 1); | |
| 202 | OS << Indent8 << Cmd->CommandString << '\n'; | |
| 197 | if (auto *cmd = dyn_cast<ByteCommand>(base)) { | |
| 198 | writeHeader(os, osec->addr + cmd->offset, osec->getLMA() + cmd->offset, | |
| 199 | cmd->size, 1); | |
| 200 | os << indent8 << cmd->commandString << '\n'; | |
| 203 | 201 | continue; |
| 204 | 202 | } |
| 205 | 203 | |
| 206 | if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { | |
| 207 | if (Cmd->Provide && !Cmd->Sym) | |
| 204 | if (auto *cmd = dyn_cast<SymbolAssignment>(base)) { | |
| 205 | if (cmd->provide && !cmd->sym) | |
| 208 | 206 | continue; |
| 209 | writeHeader(OS, Cmd->Addr, OSec->getLMA() + Cmd->Addr - OSec->getVA(0), | |
| 210 | Cmd->Size, 1); | |
| 211 | OS << Indent8 << Cmd->CommandString << '\n'; | |
| 207 | writeHeader(os, cmd->addr, osec->getLMA() + cmd->addr - osec->getVA(0), | |
| 208 | cmd->size, 1); | |
| 209 | os << indent8 << cmd->commandString << '\n'; | |
| 212 | 210 | continue; |
| 213 | 211 | } |
| 214 | 212 | } |
| 215 | 213 | } |
| 216 | 214 | } |
| 217 | 215 | |
| 218 | static void print(StringRef A, StringRef B) { | |
| 219 | outs() << left_justify(A, 49) << " " << B << "\n"; | |
| 216 | static void print(StringRef a, StringRef b) { | |
| 217 | outs() << left_justify(a, 49) << " " << b << "\n"; | |
| 220 | 218 | } |
| 221 | 219 | |
| 222 | 220 | // Output a cross reference table to stdout. This is for --cref. |
| ... | ... | @@ -231,18 +229,18 @@ static void print(StringRef A, StringRef B) { |
| 231 | 229 | // In this case, strlen is defined by libc.so.6 and used by other two |
| 232 | 230 | // files. |
| 233 | 231 | void elf::writeCrossReferenceTable() { |
| 234 | if (!Config->Cref) | |
| 232 | if (!config->cref) | |
| 235 | 233 | return; |
| 236 | 234 | |
| 237 | 235 | // Collect symbols and files. |
| 238 | MapVector<Symbol *, SetVector<InputFile *>> Map; | |
| 239 | for (InputFile *File : ObjectFiles) { | |
| 240 | for (Symbol *Sym : File->getSymbols()) { | |
| 241 | if (isa<SharedSymbol>(Sym)) | |
| 242 | Map[Sym].insert(File); | |
| 243 | if (auto *D = dyn_cast<Defined>(Sym)) | |
| 244 | if (!D->isLocal() && (!D->Section || D->Section->Live)) | |
| 245 | Map[D].insert(File); | |
| 236 | MapVector<Symbol *, SetVector<InputFile *>> map; | |
| 237 | for (InputFile *file : objectFiles) { | |
| 238 | for (Symbol *sym : file->getSymbols()) { | |
| 239 | if (isa<SharedSymbol>(sym)) | |
| 240 | map[sym].insert(file); | |
| 241 | if (auto *d = dyn_cast<Defined>(sym)) | |
| 242 | if (!d->isLocal() && (!d->section || d->section->isLive())) | |
| 243 | map[d].insert(file); | |
| 246 | 244 | } |
| 247 | 245 | } |
| 248 | 246 | |
| ... | ... | @@ -251,13 +249,13 @@ void elf::writeCrossReferenceTable() { |
| 251 | 249 | print("Symbol", "File"); |
| 252 | 250 | |
| 253 | 251 | // Print out a table. |
| 254 | for (auto KV : Map) { | |
| 255 | Symbol *Sym = KV.first; | |
| 256 | SetVector<InputFile *> &Files = KV.second; | |
| 252 | for (auto kv : map) { | |
| 253 | Symbol *sym = kv.first; | |
| 254 | SetVector<InputFile *> &files = kv.second; | |
| 257 | 255 | |
| 258 | print(toString(*Sym), toString(Sym->File)); | |
| 259 | for (InputFile *File : Files) | |
| 260 | if (File != Sym->File) | |
| 261 | print("", toString(File)); | |
| 256 | print(toString(*sym), toString(sym->file)); | |
| 257 | for (InputFile *file : files) | |
| 258 | if (file != sym->file) | |
| 259 | print("", toString(file)); | |
| 262 | 260 | } |
| 263 | 261 | } |
deps/lld/ELF/MapFile.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- MapFile.h ------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/ELF/MarkLive.cpp+217-168| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- MarkLive.cpp -------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -26,6 +25,7 @@ |
| 26 | 25 | #include "OutputSections.h" |
| 27 | 26 | #include "SymbolTable.h" |
| 28 | 27 | #include "Symbols.h" |
| 28 | #include "SyntheticSections.h" | |
| 29 | 29 | #include "Target.h" |
| 30 | 30 | #include "lld/Common/Memory.h" |
| 31 | 31 | #include "lld/Common/Strings.h" |
| ... | ... | @@ -42,66 +42,79 @@ using namespace llvm::support::endian; |
| 42 | 42 | using namespace lld; |
| 43 | 43 | using namespace lld::elf; |
| 44 | 44 | |
| 45 | namespace { | |
| 46 | template <class ELFT> class MarkLive { | |
| 47 | public: | |
| 48 | MarkLive(unsigned partition) : partition(partition) {} | |
| 49 | ||
| 50 | void run(); | |
| 51 | void moveToMain(); | |
| 52 | ||
| 53 | private: | |
| 54 | void enqueue(InputSectionBase *sec, uint64_t offset); | |
| 55 | void markSymbol(Symbol *sym); | |
| 56 | void mark(); | |
| 57 | ||
| 58 | template <class RelTy> | |
| 59 | void resolveReloc(InputSectionBase &sec, RelTy &rel, bool isLSDA); | |
| 60 | ||
| 61 | template <class RelTy> | |
| 62 | void scanEhFrameSection(EhInputSection &eh, ArrayRef<RelTy> rels); | |
| 63 | ||
| 64 | // The index of the partition that we are currently processing. | |
| 65 | unsigned partition; | |
| 66 | ||
| 67 | // A list of sections to visit. | |
| 68 | SmallVector<InputSection *, 256> queue; | |
| 69 | ||
| 70 | // There are normally few input sections whose names are valid C | |
| 71 | // identifiers, so we just store a std::vector instead of a multimap. | |
| 72 | DenseMap<StringRef, std::vector<InputSectionBase *>> cNamedSections; | |
| 73 | }; | |
| 74 | } // namespace | |
| 75 | ||
| 45 | 76 | template <class ELFT> |
| 46 | static typename ELFT::uint getAddend(InputSectionBase &Sec, | |
| 47 | const typename ELFT::Rel &Rel) { | |
| 48 | return Target->getImplicitAddend(Sec.data().begin() + Rel.r_offset, | |
| 49 | Rel.getType(Config->IsMips64EL)); | |
| 77 | static uint64_t getAddend(InputSectionBase &sec, | |
| 78 | const typename ELFT::Rel &rel) { | |
| 79 | return target->getImplicitAddend(sec.data().begin() + rel.r_offset, | |
| 80 | rel.getType(config->isMips64EL)); | |
| 50 | 81 | } |
| 51 | 82 | |
| 52 | 83 | template <class ELFT> |
| 53 | static typename ELFT::uint getAddend(InputSectionBase &Sec, | |
| 54 | const typename ELFT::Rela &Rel) { | |
| 55 | return Rel.r_addend; | |
| 84 | static uint64_t getAddend(InputSectionBase &sec, | |
| 85 | const typename ELFT::Rela &rel) { | |
| 86 | return rel.r_addend; | |
| 56 | 87 | } |
| 57 | 88 | |
| 58 | // There are normally few input sections whose names are valid C | |
| 59 | // identifiers, so we just store a std::vector instead of a multimap. | |
| 60 | static DenseMap<StringRef, std::vector<InputSectionBase *>> CNamedSections; | |
| 61 | ||
| 62 | template <class ELFT, class RelT> | |
| 63 | static void | |
| 64 | resolveReloc(InputSectionBase &Sec, RelT &Rel, | |
| 65 | llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) { | |
| 66 | Symbol &B = Sec.getFile<ELFT>()->getRelocTargetSym(Rel); | |
| 89 | template <class ELFT> | |
| 90 | template <class RelTy> | |
| 91 | void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel, | |
| 92 | bool isLSDA) { | |
| 93 | Symbol &sym = sec.getFile<ELFT>()->getRelocTargetSym(rel); | |
| 67 | 94 | |
| 68 | 95 | // If a symbol is referenced in a live section, it is used. |
| 69 | B.Used = true; | |
| 70 | if (auto *SS = dyn_cast<SharedSymbol>(&B)) | |
| 71 | if (!SS->isWeak()) | |
| 72 | SS->getFile<ELFT>().IsNeeded = true; | |
| 73 | ||
| 74 | if (auto *D = dyn_cast<Defined>(&B)) { | |
| 75 | auto *RelSec = dyn_cast_or_null<InputSectionBase>(D->Section); | |
| 76 | if (!RelSec) | |
| 96 | sym.used = true; | |
| 97 | ||
| 98 | if (auto *d = dyn_cast<Defined>(&sym)) { | |
| 99 | auto *relSec = dyn_cast_or_null<InputSectionBase>(d->section); | |
| 100 | if (!relSec) | |
| 77 | 101 | return; |
| 78 | uint64_t Offset = D->Value; | |
| 79 | if (D->isSection()) | |
| 80 | Offset += getAddend<ELFT>(Sec, Rel); | |
| 81 | Fn(RelSec, Offset); | |
| 82 | return; | |
| 83 | } | |
| 84 | 102 | |
| 85 | if (!B.isDefined()) | |
| 86 | for (InputSectionBase *Sec : CNamedSections.lookup(B.getName())) | |
| 87 | Fn(Sec, 0); | |
| 88 | } | |
| 103 | uint64_t offset = d->value; | |
| 104 | if (d->isSection()) | |
| 105 | offset += getAddend<ELFT>(sec, rel); | |
| 89 | 106 | |
| 90 | // Calls Fn for each section that Sec refers to via relocations. | |
| 91 | template <class ELFT> | |
| 92 | static void | |
| 93 | forEachSuccessor(InputSection &Sec, | |
| 94 | llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) { | |
| 95 | if (Sec.AreRelocsRela) { | |
| 96 | for (const typename ELFT::Rela &Rel : Sec.template relas<ELFT>()) | |
| 97 | resolveReloc<ELFT>(Sec, Rel, Fn); | |
| 98 | } else { | |
| 99 | for (const typename ELFT::Rel &Rel : Sec.template rels<ELFT>()) | |
| 100 | resolveReloc<ELFT>(Sec, Rel, Fn); | |
| 107 | if (!isLSDA || !(relSec->flags & SHF_EXECINSTR)) | |
| 108 | enqueue(relSec, offset); | |
| 109 | return; | |
| 101 | 110 | } |
| 102 | 111 | |
| 103 | for (InputSectionBase *IS : Sec.DependentSections) | |
| 104 | Fn(IS, 0); | |
| 112 | if (auto *ss = dyn_cast<SharedSymbol>(&sym)) | |
| 113 | if (!ss->isWeak()) | |
| 114 | ss->getFile().isNeeded = true; | |
| 115 | ||
| 116 | for (InputSectionBase *sec : cNamedSections.lookup(sym.getName())) | |
| 117 | enqueue(sec, 0); | |
| 105 | 118 | } |
| 106 | 119 | |
| 107 | 120 | // The .eh_frame section is an unfortunate special case. |
| ... | ... | @@ -118,175 +131,203 @@ forEachSuccessor(InputSection &Sec, |
| 118 | 131 | // A possible improvement would be to fully process .eh_frame in the middle of |
| 119 | 132 | // the gc pass. With that we would be able to also gc some sections holding |
| 120 | 133 | // LSDAs and personality functions if we found that they were unused. |
| 121 | template <class ELFT, class RelTy> | |
| 122 | static void | |
| 123 | scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels, | |
| 124 | llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) { | |
| 125 | const endianness E = ELFT::TargetEndianness; | |
| 126 | ||
| 127 | for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) { | |
| 128 | EhSectionPiece &Piece = EH.Pieces[I]; | |
| 129 | unsigned FirstRelI = Piece.FirstRelocation; | |
| 130 | if (FirstRelI == (unsigned)-1) | |
| 134 | template <class ELFT> | |
| 135 | template <class RelTy> | |
| 136 | void MarkLive<ELFT>::scanEhFrameSection(EhInputSection &eh, | |
| 137 | ArrayRef<RelTy> rels) { | |
| 138 | for (size_t i = 0, end = eh.pieces.size(); i < end; ++i) { | |
| 139 | EhSectionPiece &piece = eh.pieces[i]; | |
| 140 | size_t firstRelI = piece.firstRelocation; | |
| 141 | if (firstRelI == (unsigned)-1) | |
| 131 | 142 | continue; |
| 132 | if (read32<E>(Piece.data().data() + 4) == 0) { | |
| 143 | ||
| 144 | if (read32<ELFT::TargetEndianness>(piece.data().data() + 4) == 0) { | |
| 133 | 145 | // This is a CIE, we only need to worry about the first relocation. It is |
| 134 | 146 | // known to point to the personality function. |
| 135 | resolveReloc<ELFT>(EH, Rels[FirstRelI], Fn); | |
| 147 | resolveReloc(eh, rels[firstRelI], false); | |
| 136 | 148 | continue; |
| 137 | 149 | } |
| 150 | ||
| 138 | 151 | // This is a FDE. The relocations point to the described function or to |
| 139 | 152 | // a LSDA. We only need to keep the LSDA alive, so ignore anything that |
| 140 | 153 | // points to executable sections. |
| 141 | typename ELFT::uint PieceEnd = Piece.InputOff + Piece.Size; | |
| 142 | for (unsigned I2 = FirstRelI, N2 = Rels.size(); I2 < N2; ++I2) { | |
| 143 | const RelTy &Rel = Rels[I2]; | |
| 144 | if (Rel.r_offset >= PieceEnd) | |
| 145 | break; | |
| 146 | resolveReloc<ELFT>(EH, Rels[I2], | |
| 147 | [&](InputSectionBase *Sec, uint64_t Offset) { | |
| 148 | if (Sec && Sec != &InputSection::Discarded && | |
| 149 | !(Sec->Flags & SHF_EXECINSTR)) | |
| 150 | Fn(Sec, 0); | |
| 151 | }); | |
| 152 | } | |
| 154 | uint64_t pieceEnd = piece.inputOff + piece.size; | |
| 155 | for (size_t j = firstRelI, end2 = rels.size(); j < end2; ++j) | |
| 156 | if (rels[j].r_offset < pieceEnd) | |
| 157 | resolveReloc(eh, rels[j], true); | |
| 153 | 158 | } |
| 154 | 159 | } |
| 155 | 160 | |
| 156 | template <class ELFT> | |
| 157 | static void | |
| 158 | scanEhFrameSection(EhInputSection &EH, | |
| 159 | llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) { | |
| 160 | if (!EH.NumRelocations) | |
| 161 | return; | |
| 162 | ||
| 163 | if (EH.AreRelocsRela) | |
| 164 | scanEhFrameSection<ELFT>(EH, EH.template relas<ELFT>(), Fn); | |
| 165 | else | |
| 166 | scanEhFrameSection<ELFT>(EH, EH.template rels<ELFT>(), Fn); | |
| 167 | } | |
| 168 | ||
| 169 | 161 | // Some sections are used directly by the loader, so they should never be |
| 170 | 162 | // garbage-collected. This function returns true if a given section is such |
| 171 | 163 | // section. |
| 172 | template <class ELFT> static bool isReserved(InputSectionBase *Sec) { | |
| 173 | switch (Sec->Type) { | |
| 164 | static bool isReserved(InputSectionBase *sec) { | |
| 165 | switch (sec->type) { | |
| 174 | 166 | case SHT_FINI_ARRAY: |
| 175 | 167 | case SHT_INIT_ARRAY: |
| 176 | 168 | case SHT_NOTE: |
| 177 | 169 | case SHT_PREINIT_ARRAY: |
| 178 | 170 | return true; |
| 179 | 171 | default: |
| 180 | StringRef S = Sec->Name; | |
| 181 | return S.startswith(".ctors") || S.startswith(".dtors") || | |
| 182 | S.startswith(".init") || S.startswith(".fini") || | |
| 183 | S.startswith(".jcr"); | |
| 172 | StringRef s = sec->name; | |
| 173 | return s.startswith(".ctors") || s.startswith(".dtors") || | |
| 174 | s.startswith(".init") || s.startswith(".fini") || | |
| 175 | s.startswith(".jcr"); | |
| 184 | 176 | } |
| 185 | 177 | } |
| 186 | 178 | |
| 187 | // This is the main function of the garbage collector. | |
| 188 | // Starting from GC-root sections, this function visits all reachable | |
| 189 | // sections to set their "Live" bits. | |
| 190 | template <class ELFT> static void doGcSections() { | |
| 191 | SmallVector<InputSection *, 256> Q; | |
| 192 | CNamedSections.clear(); | |
| 193 | ||
| 194 | auto Enqueue = [&](InputSectionBase *Sec, uint64_t Offset) { | |
| 195 | // Skip over discarded sections. This in theory shouldn't happen, because | |
| 196 | // the ELF spec doesn't allow a relocation to point to a deduplicated | |
| 197 | // COMDAT section directly. Unfortunately this happens in practice (e.g. | |
| 198 | // .eh_frame) so we need to add a check. | |
| 199 | if (Sec == &InputSection::Discarded) | |
| 200 | return; | |
| 201 | ||
| 179 | template <class ELFT> | |
| 180 | void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset) { | |
| 181 | // Skip over discarded sections. This in theory shouldn't happen, because | |
| 182 | // the ELF spec doesn't allow a relocation to point to a deduplicated | |
| 183 | // COMDAT section directly. Unfortunately this happens in practice (e.g. | |
| 184 | // .eh_frame) so we need to add a check. | |
| 185 | if (sec == &InputSection::discarded) | |
| 186 | return; | |
| 202 | 187 | |
| 203 | // Usually, a whole section is marked as live or dead, but in mergeable | |
| 204 | // (splittable) sections, each piece of data has independent liveness bit. | |
| 205 | // So we explicitly tell it which offset is in use. | |
| 206 | if (auto *MS = dyn_cast<MergeInputSection>(Sec)) | |
| 207 | MS->getSectionPiece(Offset)->Live = true; | |
| 188 | // Usually, a whole section is marked as live or dead, but in mergeable | |
| 189 | // (splittable) sections, each piece of data has independent liveness bit. | |
| 190 | // So we explicitly tell it which offset is in use. | |
| 191 | if (auto *ms = dyn_cast<MergeInputSection>(sec)) | |
| 192 | ms->getSectionPiece(offset)->live = true; | |
| 208 | 193 | |
| 209 | if (Sec->Live) | |
| 210 | return; | |
| 211 | Sec->Live = true; | |
| 194 | // Set Sec->Partition to the meet (i.e. the "minimum") of Partition and | |
| 195 | // Sec->Partition in the following lattice: 1 < other < 0. If Sec->Partition | |
| 196 | // doesn't change, we don't need to do anything. | |
| 197 | if (sec->partition == 1 || sec->partition == partition) | |
| 198 | return; | |
| 199 | sec->partition = sec->partition ? 1 : partition; | |
| 212 | 200 | |
| 213 | // Add input section to the queue. | |
| 214 | if (InputSection *S = dyn_cast<InputSection>(Sec)) | |
| 215 | Q.push_back(S); | |
| 216 | }; | |
| 201 | // Add input section to the queue. | |
| 202 | if (InputSection *s = dyn_cast<InputSection>(sec)) | |
| 203 | queue.push_back(s); | |
| 204 | } | |
| 217 | 205 | |
| 218 | auto MarkSymbol = [&](Symbol *Sym) { | |
| 219 | if (auto *D = dyn_cast_or_null<Defined>(Sym)) | |
| 220 | if (auto *IS = dyn_cast_or_null<InputSectionBase>(D->Section)) | |
| 221 | Enqueue(IS, D->Value); | |
| 222 | }; | |
| 206 | template <class ELFT> void MarkLive<ELFT>::markSymbol(Symbol *sym) { | |
| 207 | if (auto *d = dyn_cast_or_null<Defined>(sym)) | |
| 208 | if (auto *isec = dyn_cast_or_null<InputSectionBase>(d->section)) | |
| 209 | enqueue(isec, d->value); | |
| 210 | } | |
| 223 | 211 | |
| 212 | // This is the main function of the garbage collector. | |
| 213 | // Starting from GC-root sections, this function visits all reachable | |
| 214 | // sections to set their "Live" bits. | |
| 215 | template <class ELFT> void MarkLive<ELFT>::run() { | |
| 224 | 216 | // Add GC root symbols. |
| 225 | MarkSymbol(Symtab->find(Config->Entry)); | |
| 226 | MarkSymbol(Symtab->find(Config->Init)); | |
| 227 | MarkSymbol(Symtab->find(Config->Fini)); | |
| 228 | for (StringRef S : Config->Undefined) | |
| 229 | MarkSymbol(Symtab->find(S)); | |
| 230 | for (StringRef S : Script->ReferencedSymbols) | |
| 231 | MarkSymbol(Symtab->find(S)); | |
| 232 | 217 | |
| 233 | 218 | // Preserve externally-visible symbols if the symbols defined by this |
| 234 | 219 | // file can interrupt other ELF file's symbols at runtime. |
| 235 | for (Symbol *S : Symtab->getSymbols()) | |
| 236 | if (S->includeInDynsym()) | |
| 237 | MarkSymbol(S); | |
| 220 | symtab->forEachSymbol([&](Symbol *sym) { | |
| 221 | if (sym->includeInDynsym() && sym->partition == partition) | |
| 222 | markSymbol(sym); | |
| 223 | }); | |
| 224 | ||
| 225 | // If this isn't the main partition, that's all that we need to preserve. | |
| 226 | if (partition != 1) { | |
| 227 | mark(); | |
| 228 | return; | |
| 229 | } | |
| 230 | ||
| 231 | markSymbol(symtab->find(config->entry)); | |
| 232 | markSymbol(symtab->find(config->init)); | |
| 233 | markSymbol(symtab->find(config->fini)); | |
| 234 | for (StringRef s : config->undefined) | |
| 235 | markSymbol(symtab->find(s)); | |
| 236 | for (StringRef s : script->referencedSymbols) | |
| 237 | markSymbol(symtab->find(s)); | |
| 238 | 238 | |
| 239 | 239 | // Preserve special sections and those which are specified in linker |
| 240 | 240 | // script KEEP command. |
| 241 | for (InputSectionBase *Sec : InputSections) { | |
| 241 | for (InputSectionBase *sec : inputSections) { | |
| 242 | 242 | // Mark .eh_frame sections as live because there are usually no relocations |
| 243 | 243 | // that point to .eh_frames. Otherwise, the garbage collector would drop |
| 244 | 244 | // all of them. We also want to preserve personality routines and LSDA |
| 245 | 245 | // referenced by .eh_frame sections, so we scan them for that here. |
| 246 | if (auto *EH = dyn_cast<EhInputSection>(Sec)) { | |
| 247 | EH->Live = true; | |
| 248 | scanEhFrameSection<ELFT>(*EH, Enqueue); | |
| 246 | if (auto *eh = dyn_cast<EhInputSection>(sec)) { | |
| 247 | eh->markLive(); | |
| 248 | if (!eh->numRelocations) | |
| 249 | continue; | |
| 250 | ||
| 251 | if (eh->areRelocsRela) | |
| 252 | scanEhFrameSection(*eh, eh->template relas<ELFT>()); | |
| 253 | else | |
| 254 | scanEhFrameSection(*eh, eh->template rels<ELFT>()); | |
| 249 | 255 | } |
| 250 | 256 | |
| 251 | if (Sec->Flags & SHF_LINK_ORDER) | |
| 257 | if (sec->flags & SHF_LINK_ORDER) | |
| 252 | 258 | continue; |
| 253 | 259 | |
| 254 | if (isReserved<ELFT>(Sec) || Script->shouldKeep(Sec)) { | |
| 255 | Enqueue(Sec, 0); | |
| 256 | } else if (isValidCIdentifier(Sec->Name)) { | |
| 257 | CNamedSections[Saver.save("__start_" + Sec->Name)].push_back(Sec); | |
| 258 | CNamedSections[Saver.save("__stop_" + Sec->Name)].push_back(Sec); | |
| 260 | if (isReserved(sec) || script->shouldKeep(sec)) { | |
| 261 | enqueue(sec, 0); | |
| 262 | } else if (isValidCIdentifier(sec->name)) { | |
| 263 | cNamedSections[saver.save("__start_" + sec->name)].push_back(sec); | |
| 264 | cNamedSections[saver.save("__stop_" + sec->name)].push_back(sec); | |
| 259 | 265 | } |
| 260 | 266 | } |
| 261 | 267 | |
| 268 | mark(); | |
| 269 | } | |
| 270 | ||
| 271 | template <class ELFT> void MarkLive<ELFT>::mark() { | |
| 262 | 272 | // Mark all reachable sections. |
| 263 | while (!Q.empty()) | |
| 264 | forEachSuccessor<ELFT>(*Q.pop_back_val(), Enqueue); | |
| 273 | while (!queue.empty()) { | |
| 274 | InputSectionBase &sec = *queue.pop_back_val(); | |
| 275 | ||
| 276 | if (sec.areRelocsRela) { | |
| 277 | for (const typename ELFT::Rela &rel : sec.template relas<ELFT>()) | |
| 278 | resolveReloc(sec, rel, false); | |
| 279 | } else { | |
| 280 | for (const typename ELFT::Rel &rel : sec.template rels<ELFT>()) | |
| 281 | resolveReloc(sec, rel, false); | |
| 282 | } | |
| 283 | ||
| 284 | for (InputSectionBase *isec : sec.dependentSections) | |
| 285 | enqueue(isec, 0); | |
| 286 | } | |
| 287 | } | |
| 288 | ||
| 289 | // Move the sections for some symbols to the main partition, specifically ifuncs | |
| 290 | // (because they can result in an IRELATIVE being added to the main partition's | |
| 291 | // GOT, which means that the ifunc must be available when the main partition is | |
| 292 | // loaded) and TLS symbols (because we only know how to correctly process TLS | |
| 293 | // relocations for the main partition). | |
| 294 | template <class ELFT> void MarkLive<ELFT>::moveToMain() { | |
| 295 | for (InputFile *file : objectFiles) | |
| 296 | for (Symbol *s : file->getSymbols()) | |
| 297 | if (auto *d = dyn_cast<Defined>(s)) | |
| 298 | if ((d->type == STT_GNU_IFUNC || d->type == STT_TLS) && d->section && | |
| 299 | d->section->isLive()) | |
| 300 | markSymbol(s); | |
| 301 | ||
| 302 | mark(); | |
| 265 | 303 | } |
| 266 | 304 | |
| 267 | 305 | // Before calling this function, Live bits are off for all |
| 268 | 306 | // input sections. This function make some or all of them on |
| 269 | 307 | // so that they are emitted to the output file. |
| 270 | 308 | template <class ELFT> void elf::markLive() { |
| 271 | if (!Config->GcSections) { | |
| 272 | // If -gc-sections is missing, no sections are removed. | |
| 273 | for (InputSectionBase *Sec : InputSections) | |
| 274 | Sec->Live = true; | |
| 309 | // If -gc-sections is not given, no sections are removed. | |
| 310 | if (!config->gcSections) { | |
| 311 | for (InputSectionBase *sec : inputSections) | |
| 312 | sec->markLive(); | |
| 275 | 313 | |
| 276 | 314 | // If a DSO defines a symbol referenced in a regular object, it is needed. |
| 277 | for (Symbol *Sym : Symtab->getSymbols()) | |
| 278 | if (auto *S = dyn_cast<SharedSymbol>(Sym)) | |
| 279 | if (S->IsUsedInRegularObj && !S->isWeak()) | |
| 280 | S->getFile<ELFT>().IsNeeded = true; | |
| 315 | symtab->forEachSymbol([](Symbol *sym) { | |
| 316 | if (auto *s = dyn_cast<SharedSymbol>(sym)) | |
| 317 | if (s->isUsedInRegularObj && !s->isWeak()) | |
| 318 | s->getFile().isNeeded = true; | |
| 319 | }); | |
| 281 | 320 | return; |
| 282 | 321 | } |
| 283 | 322 | |
| 323 | // Otheriwse, do mark-sweep GC. | |
| 324 | // | |
| 284 | 325 | // The -gc-sections option works only for SHF_ALLOC sections |
| 285 | 326 | // (sections that are memory-mapped at runtime). So we can |
| 286 | 327 | // unconditionally make non-SHF_ALLOC sections alive except |
| 287 | 328 | // SHF_LINK_ORDER and SHT_REL/SHT_RELA sections. |
| 288 | 329 | // |
| 289 | // Usually, SHF_ALLOC sections are not removed even if they are | |
| 330 | // Usually, non-SHF_ALLOC sections are not removed even if they are | |
| 290 | 331 | // unreachable through relocations because reachability is not |
| 291 | 332 | // a good signal whether they are garbage or not (e.g. there is |
| 292 | 333 | // usually no section referring to a .comment section, but we |
| ... | ... | @@ -300,22 +341,30 @@ template <class ELFT> void elf::markLive() { |
| 300 | 341 | // or -emit-reloc were given. And they are subject of garbage |
| 301 | 342 | // collection because, if we remove a text section, we also |
| 302 | 343 | // remove its relocation section. |
| 303 | for (InputSectionBase *Sec : InputSections) { | |
| 304 | bool IsAlloc = (Sec->Flags & SHF_ALLOC); | |
| 305 | bool IsLinkOrder = (Sec->Flags & SHF_LINK_ORDER); | |
| 306 | bool IsRel = (Sec->Type == SHT_REL || Sec->Type == SHT_RELA); | |
| 307 | if (!IsAlloc && !IsLinkOrder && !IsRel) | |
| 308 | Sec->Live = true; | |
| 344 | for (InputSectionBase *sec : inputSections) { | |
| 345 | bool isAlloc = (sec->flags & SHF_ALLOC); | |
| 346 | bool isLinkOrder = (sec->flags & SHF_LINK_ORDER); | |
| 347 | bool isRel = (sec->type == SHT_REL || sec->type == SHT_RELA); | |
| 348 | ||
| 349 | if (!isAlloc && !isLinkOrder && !isRel) | |
| 350 | sec->markLive(); | |
| 309 | 351 | } |
| 310 | 352 | |
| 311 | 353 | // Follow the graph to mark all live sections. |
| 312 | doGcSections<ELFT>(); | |
| 354 | for (unsigned curPart = 1; curPart <= partitions.size(); ++curPart) | |
| 355 | MarkLive<ELFT>(curPart).run(); | |
| 356 | ||
| 357 | // If we have multiple partitions, some sections need to live in the main | |
| 358 | // partition even if they were allocated to a loadable partition. Move them | |
| 359 | // there now. | |
| 360 | if (partitions.size() != 1) | |
| 361 | MarkLive<ELFT>(1).moveToMain(); | |
| 313 | 362 | |
| 314 | 363 | // Report garbage-collected sections. |
| 315 | if (Config->PrintGcSections) | |
| 316 | for (InputSectionBase *Sec : InputSections) | |
| 317 | if (!Sec->Live) | |
| 318 | message("removing unused section " + toString(Sec)); | |
| 364 | if (config->printGcSections) | |
| 365 | for (InputSectionBase *sec : inputSections) | |
| 366 | if (!sec->isLive()) | |
| 367 | message("removing unused section " + toString(sec)); | |
| 319 | 368 | } |
| 320 | 369 | |
| 321 | 370 | template void elf::markLive<ELF32LE>(); |
deps/lld/ELF/MarkLive.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- MarkLive.h -----------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/ELF/Options.td+51-4| ... | ... | @@ -63,10 +63,18 @@ defm allow_multiple_definition: B<"allow-multiple-definition", |
| 63 | 63 | "Allow multiple definitions", |
| 64 | 64 | "Do not allow multiple definitions (default)">; |
| 65 | 65 | |
| 66 | defm allow_shlib_undefined: B<"allow-shlib-undefined", | |
| 67 | "Allow unresolved references in shared libraries (default when linking a shared library)", | |
| 68 | "Do not allow unresolved references in shared libraries (default when linking an executable)">; | |
| 69 | ||
| 66 | 70 | defm apply_dynamic_relocs: B<"apply-dynamic-relocs", |
| 67 | 71 | "Apply link-time values for dynamic relocations", |
| 68 | 72 | "Do not apply link-time values for dynamic relocations (default)">; |
| 69 | 73 | |
| 74 | defm dependent_libraries: B<"dependent-libraries", | |
| 75 | "Process dependent library specifiers from input files (default)", | |
| 76 | "Ignore dependent library specifiers from input files">; | |
| 77 | ||
| 70 | 78 | defm as_needed: B<"as-needed", |
| 71 | 79 | "Only set DT_NEEDED for shared libraries if used", |
| 72 | 80 | "Always set DT_NEEDED for shared libraries (default)">; |
| ... | ... | @@ -163,6 +171,13 @@ defm fini: Eq<"fini", "Specify a finalizer function">, MetaVarName<"<symbol>">; |
| 163 | 171 | def fix_cortex_a53_843419: F<"fix-cortex-a53-843419">, |
| 164 | 172 | HelpText<"Apply fixes for AArch64 Cortex-A53 erratum 843419">; |
| 165 | 173 | |
| 174 | // This option is intentionally hidden from the user as the implementation | |
| 175 | // is not complete. | |
| 176 | def require_cet: F<"require-cet">; | |
| 177 | ||
| 178 | def force_bti: F<"force-bti">, | |
| 179 | HelpText<"Force enable AArch64 BTI in PLT, warn if Input ELF file does not have GNU_PROPERTY_AARCH64_FEATURE_1_BTI property">; | |
| 180 | ||
| 166 | 181 | defm format: Eq<"format", "Change the input format of the inputs following this option">, |
| 167 | 182 | MetaVarName<"[default,elf,binary]">; |
| 168 | 183 | |
| ... | ... | @@ -214,6 +229,9 @@ defm merge_exidx_entries: B<"merge-exidx-entries", |
| 214 | 229 | "Enable merging .ARM.exidx entries (default)", |
| 215 | 230 | "Disable merging .ARM.exidx entries">; |
| 216 | 231 | |
| 232 | def nmagic: F<"nmagic">, MetaVarName<"<magic>">, | |
| 233 | HelpText<"Do not page align sections, link against static libraries.">; | |
| 234 | ||
| 217 | 235 | def nostdlib: F<"nostdlib">, |
| 218 | 236 | HelpText<"Only search directories specified on the command line">; |
| 219 | 237 | |
| ... | ... | @@ -226,8 +244,11 @@ def no_dynamic_linker: F<"no-dynamic-linker">, |
| 226 | 244 | def noinhibit_exec: F<"noinhibit-exec">, |
| 227 | 245 | HelpText<"Retain the executable output file whenever it is still usable">; |
| 228 | 246 | |
| 247 | def no_nmagic: F<"no-nmagic">, MetaVarName<"<magic>">, | |
| 248 | HelpText<"Page align sections (default)">; | |
| 249 | ||
| 229 | 250 | def no_omagic: F<"no-omagic">, MetaVarName<"<magic>">, |
| 230 | HelpText<"Do not set the text data sections to be writable">; | |
| 251 | HelpText<"Do not set the text data sections to be writable, page align sections (default)">; | |
| 231 | 252 | |
| 232 | 253 | def no_rosegment: F<"no-rosegment">, |
| 233 | 254 | HelpText<"Do not put read-only non-executable sections in their own segment">; |
| ... | ... | @@ -242,7 +263,7 @@ def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">, |
| 242 | 263 | HelpText<"Specify the binary format for the output object file">; |
| 243 | 264 | |
| 244 | 265 | def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">, |
| 245 | HelpText<"Set the text and data sections to be readable and writable">; | |
| 266 | HelpText<"Set the text and data sections to be readable and writable, do not page align sections, link against static libraries">; | |
| 246 | 267 | |
| 247 | 268 | defm orphan_handling: |
| 248 | 269 | Eq<"orphan-handling", "Control how orphan sections are handled when linker script used">; |
| ... | ... | @@ -251,6 +272,9 @@ defm pack_dyn_relocs: |
| 251 | 272 | Eq<"pack-dyn-relocs", "Pack dynamic relocations in the given format">, |
| 252 | 273 | MetaVarName<"[none,android,relr,android+relr]">; |
| 253 | 274 | |
| 275 | def pac_plt: F<"pac-plt">, | |
| 276 | HelpText<"AArch64 only, use pointer authentication in PLT">; | |
| 277 | ||
| 254 | 278 | defm use_android_relr_tags: B<"use-android-relr-tags", |
| 255 | 279 | "Use SHT_ANDROID_RELR / DT_ANDROID_RELR* tags instead of SHT_RELR / DT_RELR*", |
| 256 | 280 | "Use SHT_RELR / DT_RELR* tags (default)">; |
| ... | ... | @@ -270,6 +294,9 @@ defm print_icf_sections: B<"print-icf-sections", |
| 270 | 294 | "List identical folded sections", |
| 271 | 295 | "Do not list identical folded sections (default)">; |
| 272 | 296 | |
| 297 | defm print_symbol_order: Eq<"print-symbol-order", | |
| 298 | "Print a symbol order specified by --call-graph-ordering-file into the speficied file">; | |
| 299 | ||
| 273 | 300 | def pop_state: F<"pop-state">, |
| 274 | 301 | HelpText<"Undo the effect of -push-state">; |
| 275 | 302 | |
| ... | ... | @@ -339,6 +366,9 @@ defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">; |
| 339 | 366 | defm undefined: Eq<"undefined", "Force undefined symbol during linking">, |
| 340 | 367 | MetaVarName<"<symbol>">; |
| 341 | 368 | |
| 369 | defm undefined_glob: Eq<"undefined-glob", "Force undefined symbol during linking">, | |
| 370 | MetaVarName<"<pattern>">; | |
| 371 | ||
| 342 | 372 | defm unresolved_symbols: |
| 343 | 373 | Eq<"unresolved-symbols", "Determine how to handle unresolved symbols">; |
| 344 | 374 | |
| ... | ... | @@ -386,6 +416,9 @@ defm wrap: Eq<"wrap", "Use wrapper functions for symbol">, |
| 386 | 416 | def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">, |
| 387 | 417 | HelpText<"Linker option extensions">; |
| 388 | 418 | |
| 419 | def visual_studio_diagnostics_format : F<"vs-diagnostics">, | |
| 420 | HelpText<"Format diagnostics for Visual Studio compatiblity">; | |
| 421 | ||
| 389 | 422 | // Aliases |
| 390 | 423 | def: Separate<["-"], "f">, Alias<auxiliary>, HelpText<"Alias for --auxiliary">; |
| 391 | 424 | def: F<"call_shared">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">; |
| ... | ... | @@ -407,6 +440,7 @@ def: Separate<["-"], "b">, Alias<format>, HelpText<"Alias for --format">; |
| 407 | 440 | def: JoinedOrSeparate<["-"], "l">, Alias<library>, HelpText<"Alias for --library">; |
| 408 | 441 | def: JoinedOrSeparate<["-"], "L">, Alias<library_path>, HelpText<"Alias for --library-path">; |
| 409 | 442 | def: F<"no-pic-executable">, Alias<no_pie>, HelpText<"Alias for --no-pie">; |
| 443 | def: Flag<["-"], "n">, Alias<nmagic>, HelpText<"Alias for --nmagic">; | |
| 410 | 444 | def: Flag<["-"], "N">, Alias<omagic>, HelpText<"Alias for --omagic">; |
| 411 | 445 | def: Joined<["--"], "output=">, Alias<o>, HelpText<"Alias for -o">; |
| 412 | 446 | def: Separate<["--"], "output">, Alias<o>, HelpText<"Alias for -o">; |
| ... | ... | @@ -440,14 +474,22 @@ def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">, |
| 440 | 474 | HelpText<"Optimization level for LTO">; |
| 441 | 475 | def lto_partitions: J<"lto-partitions=">, |
| 442 | 476 | HelpText<"Number of LTO codegen partitions">; |
| 477 | def lto_cs_profile_generate: F<"lto-cs-profile-generate">, | |
| 478 | HelpText<"Perform context senstive PGO instrumentation">; | |
| 479 | def lto_cs_profile_file: J<"lto-cs-profile-file=">, | |
| 480 | HelpText<"Context sensitive profile file path">; | |
| 443 | 481 | def lto_sample_profile: J<"lto-sample-profile=">, |
| 444 | 482 | HelpText<"Sample profile file path">; |
| 445 | 483 | def disable_verify: F<"disable-verify">; |
| 446 | 484 | defm mllvm: Eq<"mllvm", "Additional arguments to forward to LLVM's option processing">; |
| 447 | 485 | def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">, |
| 448 | 486 | HelpText<"YAML output file for optimization remarks">; |
| 487 | def opt_remarks_passes: Separate<["--"], "opt-remarks-passes">, | |
| 488 | HelpText<"Regex for the passes that need to be serialized to the output file">; | |
| 449 | 489 | def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">, |
| 450 | 490 | HelpText<"Include hotness information in the optimization remarks file">; |
| 491 | def opt_remarks_format: Separate<["--"], "opt-remarks-format">, | |
| 492 | HelpText<"The format used for serializing remarks (default: YAML)">; | |
| 451 | 493 | defm plugin_opt: Eq<"plugin-opt", "specifies LTO options for compatibility with GNU linkers">; |
| 452 | 494 | def save_temps: F<"save-temps">; |
| 453 | 495 | def thinlto_cache_dir: J<"thinlto-cache-dir=">, |
| ... | ... | @@ -468,6 +510,10 @@ def plugin_opt_mcpu_eq: J<"plugin-opt=mcpu=">; |
| 468 | 510 | def: F<"plugin-opt=new-pass-manager">, |
| 469 | 511 | Alias<lto_new_pass_manager>, HelpText<"Alias for -lto-new-pass-manager">; |
| 470 | 512 | def plugin_opt_obj_path_eq: J<"plugin-opt=obj-path=">; |
| 513 | def: F<"plugin-opt=cs-profile-generate">, | |
| 514 | Alias<lto_cs_profile_generate>, HelpText<"Alias for -lto-cs-profile-generate">; | |
| 515 | def: J<"plugin-opt=cs-profile-path=">, | |
| 516 | Alias<lto_cs_profile_file>, HelpText<"Alias for -lto-cs-profile-file">; | |
| 471 | 517 | def: J<"plugin-opt=sample-profile=">, |
| 472 | 518 | Alias<lto_sample_profile>, HelpText<"Alias for -lto-sample-profile">; |
| 473 | 519 | def: F<"plugin-opt=save-temps">, Alias<save_temps>, HelpText<"Alias for -save-temps">; |
| ... | ... | @@ -492,19 +538,20 @@ def plugin_opt_thinlto: J<"plugin-opt=thinlto">; |
| 492 | 538 | def plugin_opt_slash: J<"plugin-opt=/">; |
| 493 | 539 | |
| 494 | 540 | // Options listed below are silently ignored for now for compatibility. |
| 495 | def: F<"allow-shlib-undefined">; | |
| 496 | 541 | def: F<"detect-odr-violations">; |
| 497 | 542 | def: Flag<["-"], "g">; |
| 498 | 543 | def: F<"long-plt">; |
| 499 | 544 | def: F<"no-add-needed">; |
| 500 | def: F<"no-allow-shlib-undefined">; | |
| 501 | 545 | def: F<"no-copy-dt-needed-entries">; |
| 502 | 546 | def: F<"no-ctors-in-init-array">; |
| 503 | 547 | def: F<"no-keep-memory">; |
| 504 | 548 | def: F<"no-mmap-output-file">; |
| 549 | def: F<"no-pipeline-knowledge">; | |
| 505 | 550 | def: F<"no-warn-mismatch">; |
| 551 | def: Flag<["-"], "p">; | |
| 506 | 552 | def: Separate<["--", "-"], "rpath-link">; |
| 507 | 553 | def: J<"rpath-link=">; |
| 554 | def: F<"secure-plt">; | |
| 508 | 555 | def: F<"sort-common">; |
| 509 | 556 | def: F<"stats">; |
| 510 | 557 | def: F<"warn-execstack">; |
deps/lld/ELF/OutputSections.cpp+213-229| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- OutputSections.cpp -------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -31,47 +30,46 @@ using namespace llvm::ELF; |
| 31 | 30 | using namespace lld; |
| 32 | 31 | using namespace lld::elf; |
| 33 | 32 | |
| 34 | uint8_t Out::First; | |
| 35 | PhdrEntry *Out::TlsPhdr; | |
| 36 | OutputSection *Out::ElfHeader; | |
| 37 | OutputSection *Out::ProgramHeaders; | |
| 38 | OutputSection *Out::PreinitArray; | |
| 39 | OutputSection *Out::InitArray; | |
| 40 | OutputSection *Out::FiniArray; | |
| 33 | uint8_t *Out::bufferStart; | |
| 34 | uint8_t Out::first; | |
| 35 | PhdrEntry *Out::tlsPhdr; | |
| 36 | OutputSection *Out::elfHeader; | |
| 37 | OutputSection *Out::programHeaders; | |
| 38 | OutputSection *Out::preinitArray; | |
| 39 | OutputSection *Out::initArray; | |
| 40 | OutputSection *Out::finiArray; | |
| 41 | 41 | |
| 42 | std::vector<OutputSection *> elf::OutputSections; | |
| 42 | std::vector<OutputSection *> elf::outputSections; | |
| 43 | 43 | |
| 44 | 44 | uint32_t OutputSection::getPhdrFlags() const { |
| 45 | uint32_t Ret = 0; | |
| 46 | if (Config->EMachine != EM_ARM || !(Flags & SHF_ARM_PURECODE)) | |
| 47 | Ret |= PF_R; | |
| 48 | if (Flags & SHF_WRITE) | |
| 49 | Ret |= PF_W; | |
| 50 | if (Flags & SHF_EXECINSTR) | |
| 51 | Ret |= PF_X; | |
| 52 | return Ret; | |
| 45 | uint32_t ret = 0; | |
| 46 | if (config->emachine != EM_ARM || !(flags & SHF_ARM_PURECODE)) | |
| 47 | ret |= PF_R; | |
| 48 | if (flags & SHF_WRITE) | |
| 49 | ret |= PF_W; | |
| 50 | if (flags & SHF_EXECINSTR) | |
| 51 | ret |= PF_X; | |
| 52 | return ret; | |
| 53 | 53 | } |
| 54 | 54 | |
| 55 | 55 | template <class ELFT> |
| 56 | void OutputSection::writeHeaderTo(typename ELFT::Shdr *Shdr) { | |
| 57 | Shdr->sh_entsize = Entsize; | |
| 58 | Shdr->sh_addralign = Alignment; | |
| 59 | Shdr->sh_type = Type; | |
| 60 | Shdr->sh_offset = Offset; | |
| 61 | Shdr->sh_flags = Flags; | |
| 62 | Shdr->sh_info = Info; | |
| 63 | Shdr->sh_link = Link; | |
| 64 | Shdr->sh_addr = Addr; | |
| 65 | Shdr->sh_size = Size; | |
| 66 | Shdr->sh_name = ShName; | |
| 56 | void OutputSection::writeHeaderTo(typename ELFT::Shdr *shdr) { | |
| 57 | shdr->sh_entsize = entsize; | |
| 58 | shdr->sh_addralign = alignment; | |
| 59 | shdr->sh_type = type; | |
| 60 | shdr->sh_offset = offset; | |
| 61 | shdr->sh_flags = flags; | |
| 62 | shdr->sh_info = info; | |
| 63 | shdr->sh_link = link; | |
| 64 | shdr->sh_addr = addr; | |
| 65 | shdr->sh_size = size; | |
| 66 | shdr->sh_name = shName; | |
| 67 | 67 | } |
| 68 | 68 | |
| 69 | OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags) | |
| 69 | OutputSection::OutputSection(StringRef name, uint32_t type, uint64_t flags) | |
| 70 | 70 | : BaseCommand(OutputSectionKind), |
| 71 | SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type, | |
| 72 | /*Info*/ 0, /*Link*/ 0) { | |
| 73 | Live = false; | |
| 74 | } | |
| 71 | SectionBase(Output, name, flags, /*Entsize*/ 0, /*Alignment*/ 1, type, | |
| 72 | /*Info*/ 0, /*Link*/ 0) {} | |
| 75 | 73 | |
| 76 | 74 | // We allow sections of types listed below to merged into a |
| 77 | 75 | // single progbits section. This is typically done by linker |
| ... | ... | @@ -79,257 +77,248 @@ OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags) |
| 79 | 77 | // to be allocated for nobits sections. Other ones don't require |
| 80 | 78 | // any special treatment on top of progbits, so there doesn't |
| 81 | 79 | // seem to be a harm in merging them. |
| 82 | static bool canMergeToProgbits(unsigned Type) { | |
| 83 | return Type == SHT_NOBITS || Type == SHT_PROGBITS || Type == SHT_INIT_ARRAY || | |
| 84 | Type == SHT_PREINIT_ARRAY || Type == SHT_FINI_ARRAY || | |
| 85 | Type == SHT_NOTE; | |
| 80 | static bool canMergeToProgbits(unsigned type) { | |
| 81 | return type == SHT_NOBITS || type == SHT_PROGBITS || type == SHT_INIT_ARRAY || | |
| 82 | type == SHT_PREINIT_ARRAY || type == SHT_FINI_ARRAY || | |
| 83 | type == SHT_NOTE; | |
| 86 | 84 | } |
| 87 | 85 | |
| 88 | void OutputSection::addSection(InputSection *IS) { | |
| 89 | if (!Live) { | |
| 86 | void OutputSection::addSection(InputSection *isec) { | |
| 87 | if (!hasInputSections) { | |
| 90 | 88 | // If IS is the first section to be added to this section, |
| 91 | // initialize Type, Entsize and flags from IS. | |
| 92 | Live = true; | |
| 93 | Type = IS->Type; | |
| 94 | Entsize = IS->Entsize; | |
| 95 | Flags = IS->Flags; | |
| 89 | // initialize Partition, Type, Entsize and flags from IS. | |
| 90 | hasInputSections = true; | |
| 91 | partition = isec->partition; | |
| 92 | type = isec->type; | |
| 93 | entsize = isec->entsize; | |
| 94 | flags = isec->flags; | |
| 96 | 95 | } else { |
| 97 | 96 | // Otherwise, check if new type or flags are compatible with existing ones. |
| 98 | unsigned Mask = SHF_TLS | SHF_LINK_ORDER; | |
| 99 | if ((Flags & Mask) != (IS->Flags & Mask)) | |
| 100 | error("incompatible section flags for " + Name + "\n>>> " + toString(IS) + | |
| 101 | ": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Name + | |
| 102 | ": 0x" + utohexstr(Flags)); | |
| 103 | ||
| 104 | if (Type != IS->Type) { | |
| 105 | if (!canMergeToProgbits(Type) || !canMergeToProgbits(IS->Type)) | |
| 106 | error("section type mismatch for " + IS->Name + "\n>>> " + | |
| 107 | toString(IS) + ": " + | |
| 108 | getELFSectionTypeName(Config->EMachine, IS->Type) + | |
| 109 | "\n>>> output section " + Name + ": " + | |
| 110 | getELFSectionTypeName(Config->EMachine, Type)); | |
| 111 | Type = SHT_PROGBITS; | |
| 97 | unsigned mask = SHF_TLS | SHF_LINK_ORDER; | |
| 98 | if ((flags & mask) != (isec->flags & mask)) | |
| 99 | error("incompatible section flags for " + name + "\n>>> " + toString(isec) + | |
| 100 | ": 0x" + utohexstr(isec->flags) + "\n>>> output section " + name + | |
| 101 | ": 0x" + utohexstr(flags)); | |
| 102 | ||
| 103 | if (type != isec->type) { | |
| 104 | if (!canMergeToProgbits(type) || !canMergeToProgbits(isec->type)) | |
| 105 | error("section type mismatch for " + isec->name + "\n>>> " + | |
| 106 | toString(isec) + ": " + | |
| 107 | getELFSectionTypeName(config->emachine, isec->type) + | |
| 108 | "\n>>> output section " + name + ": " + | |
| 109 | getELFSectionTypeName(config->emachine, type)); | |
| 110 | type = SHT_PROGBITS; | |
| 112 | 111 | } |
| 113 | 112 | } |
| 114 | 113 | |
| 115 | IS->Parent = this; | |
| 116 | uint64_t AndMask = | |
| 117 | Config->EMachine == EM_ARM ? (uint64_t)SHF_ARM_PURECODE : 0; | |
| 118 | uint64_t OrMask = ~AndMask; | |
| 119 | uint64_t AndFlags = (Flags & IS->Flags) & AndMask; | |
| 120 | uint64_t OrFlags = (Flags | IS->Flags) & OrMask; | |
| 121 | Flags = AndFlags | OrFlags; | |
| 114 | isec->parent = this; | |
| 115 | uint64_t andMask = | |
| 116 | config->emachine == EM_ARM ? (uint64_t)SHF_ARM_PURECODE : 0; | |
| 117 | uint64_t orMask = ~andMask; | |
| 118 | uint64_t andFlags = (flags & isec->flags) & andMask; | |
| 119 | uint64_t orFlags = (flags | isec->flags) & orMask; | |
| 120 | flags = andFlags | orFlags; | |
| 122 | 121 | |
| 123 | Alignment = std::max(Alignment, IS->Alignment); | |
| 122 | alignment = std::max(alignment, isec->alignment); | |
| 124 | 123 | |
| 125 | 124 | // If this section contains a table of fixed-size entries, sh_entsize |
| 126 | 125 | // holds the element size. If it contains elements of different size we |
| 127 | 126 | // set sh_entsize to 0. |
| 128 | if (Entsize != IS->Entsize) | |
| 129 | Entsize = 0; | |
| 130 | ||
| 131 | if (!IS->Assigned) { | |
| 132 | IS->Assigned = true; | |
| 133 | if (SectionCommands.empty() || | |
| 134 | !isa<InputSectionDescription>(SectionCommands.back())) | |
| 135 | SectionCommands.push_back(make<InputSectionDescription>("")); | |
| 136 | auto *ISD = cast<InputSectionDescription>(SectionCommands.back()); | |
| 137 | ISD->Sections.push_back(IS); | |
| 127 | if (entsize != isec->entsize) | |
| 128 | entsize = 0; | |
| 129 | ||
| 130 | if (!isec->assigned) { | |
| 131 | isec->assigned = true; | |
| 132 | if (sectionCommands.empty() || | |
| 133 | !isa<InputSectionDescription>(sectionCommands.back())) | |
| 134 | sectionCommands.push_back(make<InputSectionDescription>("")); | |
| 135 | auto *isd = cast<InputSectionDescription>(sectionCommands.back()); | |
| 136 | isd->sections.push_back(isec); | |
| 138 | 137 | } |
| 139 | 138 | } |
| 140 | 139 | |
| 141 | static void sortByOrder(MutableArrayRef<InputSection *> In, | |
| 142 | llvm::function_ref<int(InputSectionBase *S)> Order) { | |
| 143 | typedef std::pair<int, InputSection *> Pair; | |
| 144 | auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; | |
| 140 | static void sortByOrder(MutableArrayRef<InputSection *> in, | |
| 141 | llvm::function_ref<int(InputSectionBase *s)> order) { | |
| 142 | std::vector<std::pair<int, InputSection *>> v; | |
| 143 | for (InputSection *s : in) | |
| 144 | v.push_back({order(s), s}); | |
| 145 | llvm::stable_sort(v, less_first()); | |
| 145 | 146 | |
| 146 | std::vector<Pair> V; | |
| 147 | for (InputSection *S : In) | |
| 148 | V.push_back({Order(S), S}); | |
| 149 | std::stable_sort(V.begin(), V.end(), Comp); | |
| 150 | ||
| 151 | for (size_t I = 0; I < V.size(); ++I) | |
| 152 | In[I] = V[I].second; | |
| 147 | for (size_t i = 0; i < v.size(); ++i) | |
| 148 | in[i] = v[i].second; | |
| 153 | 149 | } |
| 154 | 150 | |
| 155 | 151 | uint64_t elf::getHeaderSize() { |
| 156 | if (Config->OFormatBinary) | |
| 152 | if (config->oFormatBinary) | |
| 157 | 153 | return 0; |
| 158 | return Out::ElfHeader->Size + Out::ProgramHeaders->Size; | |
| 154 | return Out::elfHeader->size + Out::programHeaders->size; | |
| 159 | 155 | } |
| 160 | 156 | |
| 161 | bool OutputSection::classof(const BaseCommand *C) { | |
| 162 | return C->Kind == OutputSectionKind; | |
| 157 | bool OutputSection::classof(const BaseCommand *c) { | |
| 158 | return c->kind == OutputSectionKind; | |
| 163 | 159 | } |
| 164 | 160 | |
| 165 | void OutputSection::sort(llvm::function_ref<int(InputSectionBase *S)> Order) { | |
| 166 | assert(Live); | |
| 167 | for (BaseCommand *B : SectionCommands) | |
| 168 | if (auto *ISD = dyn_cast<InputSectionDescription>(B)) | |
| 169 | sortByOrder(ISD->Sections, Order); | |
| 161 | void OutputSection::sort(llvm::function_ref<int(InputSectionBase *s)> order) { | |
| 162 | assert(isLive()); | |
| 163 | for (BaseCommand *b : sectionCommands) | |
| 164 | if (auto *isd = dyn_cast<InputSectionDescription>(b)) | |
| 165 | sortByOrder(isd->sections, order); | |
| 170 | 166 | } |
| 171 | 167 | |
| 172 | 168 | // Fill [Buf, Buf + Size) with Filler. |
| 173 | 169 | // This is used for linker script "=fillexp" command. |
| 174 | static void fill(uint8_t *Buf, size_t Size, | |
| 175 | const std::array<uint8_t, 4> &Filler) { | |
| 176 | size_t I = 0; | |
| 177 | for (; I + 4 < Size; I += 4) | |
| 178 | memcpy(Buf + I, Filler.data(), 4); | |
| 179 | memcpy(Buf + I, Filler.data(), Size - I); | |
| 170 | static void fill(uint8_t *buf, size_t size, | |
| 171 | const std::array<uint8_t, 4> &filler) { | |
| 172 | size_t i = 0; | |
| 173 | for (; i + 4 < size; i += 4) | |
| 174 | memcpy(buf + i, filler.data(), 4); | |
| 175 | memcpy(buf + i, filler.data(), size - i); | |
| 180 | 176 | } |
| 181 | 177 | |
| 182 | 178 | // Compress section contents if this section contains debug info. |
| 183 | 179 | template <class ELFT> void OutputSection::maybeCompress() { |
| 184 | typedef typename ELFT::Chdr Elf_Chdr; | |
| 180 | using Elf_Chdr = typename ELFT::Chdr; | |
| 185 | 181 | |
| 186 | 182 | // Compress only DWARF debug sections. |
| 187 | if (!Config->CompressDebugSections || (Flags & SHF_ALLOC) || | |
| 188 | !Name.startswith(".debug_")) | |
| 183 | if (!config->compressDebugSections || (flags & SHF_ALLOC) || | |
| 184 | !name.startswith(".debug_")) | |
| 189 | 185 | return; |
| 190 | 186 | |
| 191 | 187 | // Create a section header. |
| 192 | ZDebugHeader.resize(sizeof(Elf_Chdr)); | |
| 193 | auto *Hdr = reinterpret_cast<Elf_Chdr *>(ZDebugHeader.data()); | |
| 194 | Hdr->ch_type = ELFCOMPRESS_ZLIB; | |
| 195 | Hdr->ch_size = Size; | |
| 196 | Hdr->ch_addralign = Alignment; | |
| 188 | zDebugHeader.resize(sizeof(Elf_Chdr)); | |
| 189 | auto *hdr = reinterpret_cast<Elf_Chdr *>(zDebugHeader.data()); | |
| 190 | hdr->ch_type = ELFCOMPRESS_ZLIB; | |
| 191 | hdr->ch_size = size; | |
| 192 | hdr->ch_addralign = alignment; | |
| 197 | 193 | |
| 198 | 194 | // Write section contents to a temporary buffer and compress it. |
| 199 | std::vector<uint8_t> Buf(Size); | |
| 200 | writeTo<ELFT>(Buf.data()); | |
| 201 | if (Error E = zlib::compress(toStringRef(Buf), CompressedData)) | |
| 202 | fatal("compress failed: " + llvm::toString(std::move(E))); | |
| 195 | std::vector<uint8_t> buf(size); | |
| 196 | writeTo<ELFT>(buf.data()); | |
| 197 | if (Error e = zlib::compress(toStringRef(buf), compressedData)) | |
| 198 | fatal("compress failed: " + llvm::toString(std::move(e))); | |
| 203 | 199 | |
| 204 | 200 | // Update section headers. |
| 205 | Size = sizeof(Elf_Chdr) + CompressedData.size(); | |
| 206 | Flags |= SHF_COMPRESSED; | |
| 201 | size = sizeof(Elf_Chdr) + compressedData.size(); | |
| 202 | flags |= SHF_COMPRESSED; | |
| 207 | 203 | } |
| 208 | 204 | |
| 209 | static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { | |
| 210 | if (Size == 1) | |
| 211 | *Buf = Data; | |
| 212 | else if (Size == 2) | |
| 213 | write16(Buf, Data); | |
| 214 | else if (Size == 4) | |
| 215 | write32(Buf, Data); | |
| 216 | else if (Size == 8) | |
| 217 | write64(Buf, Data); | |
| 205 | static void writeInt(uint8_t *buf, uint64_t data, uint64_t size) { | |
| 206 | if (size == 1) | |
| 207 | *buf = data; | |
| 208 | else if (size == 2) | |
| 209 | write16(buf, data); | |
| 210 | else if (size == 4) | |
| 211 | write32(buf, data); | |
| 212 | else if (size == 8) | |
| 213 | write64(buf, data); | |
| 218 | 214 | else |
| 219 | 215 | llvm_unreachable("unsupported Size argument"); |
| 220 | 216 | } |
| 221 | 217 | |
| 222 | template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) { | |
| 223 | if (Type == SHT_NOBITS) | |
| 218 | template <class ELFT> void OutputSection::writeTo(uint8_t *buf) { | |
| 219 | if (type == SHT_NOBITS) | |
| 224 | 220 | return; |
| 225 | 221 | |
| 226 | Loc = Buf; | |
| 227 | ||
| 228 | 222 | // If -compress-debug-section is specified and if this is a debug seciton, |
| 229 | 223 | // we've already compressed section contents. If that's the case, |
| 230 | 224 | // just write it down. |
| 231 | if (!CompressedData.empty()) { | |
| 232 | memcpy(Buf, ZDebugHeader.data(), ZDebugHeader.size()); | |
| 233 | memcpy(Buf + ZDebugHeader.size(), CompressedData.data(), | |
| 234 | CompressedData.size()); | |
| 225 | if (!compressedData.empty()) { | |
| 226 | memcpy(buf, zDebugHeader.data(), zDebugHeader.size()); | |
| 227 | memcpy(buf + zDebugHeader.size(), compressedData.data(), | |
| 228 | compressedData.size()); | |
| 235 | 229 | return; |
| 236 | 230 | } |
| 237 | 231 | |
| 238 | 232 | // Write leading padding. |
| 239 | std::vector<InputSection *> Sections = getInputSections(this); | |
| 240 | std::array<uint8_t, 4> Filler = getFiller(); | |
| 241 | bool NonZeroFiller = read32(Filler.data()) != 0; | |
| 242 | if (NonZeroFiller) | |
| 243 | fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler); | |
| 233 | std::vector<InputSection *> sections = getInputSections(this); | |
| 234 | std::array<uint8_t, 4> filler = getFiller(); | |
| 235 | bool nonZeroFiller = read32(filler.data()) != 0; | |
| 236 | if (nonZeroFiller) | |
| 237 | fill(buf, sections.empty() ? size : sections[0]->outSecOff, filler); | |
| 244 | 238 | |
| 245 | parallelForEachN(0, Sections.size(), [&](size_t I) { | |
| 246 | InputSection *IS = Sections[I]; | |
| 247 | IS->writeTo<ELFT>(Buf); | |
| 239 | parallelForEachN(0, sections.size(), [&](size_t i) { | |
| 240 | InputSection *isec = sections[i]; | |
| 241 | isec->writeTo<ELFT>(buf); | |
| 248 | 242 | |
| 249 | 243 | // Fill gaps between sections. |
| 250 | if (NonZeroFiller) { | |
| 251 | uint8_t *Start = Buf + IS->OutSecOff + IS->getSize(); | |
| 252 | uint8_t *End; | |
| 253 | if (I + 1 == Sections.size()) | |
| 254 | End = Buf + Size; | |
| 244 | if (nonZeroFiller) { | |
| 245 | uint8_t *start = buf + isec->outSecOff + isec->getSize(); | |
| 246 | uint8_t *end; | |
| 247 | if (i + 1 == sections.size()) | |
| 248 | end = buf + size; | |
| 255 | 249 | else |
| 256 | End = Buf + Sections[I + 1]->OutSecOff; | |
| 257 | fill(Start, End - Start, Filler); | |
| 250 | end = buf + sections[i + 1]->outSecOff; | |
| 251 | fill(start, end - start, filler); | |
| 258 | 252 | } |
| 259 | 253 | }); |
| 260 | 254 | |
| 261 | 255 | // Linker scripts may have BYTE()-family commands with which you |
| 262 | 256 | // can write arbitrary bytes to the output. Process them if any. |
| 263 | for (BaseCommand *Base : SectionCommands) | |
| 264 | if (auto *Data = dyn_cast<ByteCommand>(Base)) | |
| 265 | writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); | |
| 257 | for (BaseCommand *base : sectionCommands) | |
| 258 | if (auto *data = dyn_cast<ByteCommand>(base)) | |
| 259 | writeInt(buf + data->offset, data->expression().getValue(), data->size); | |
| 266 | 260 | } |
| 267 | 261 | |
| 268 | template <class ELFT> | |
| 269 | static void finalizeShtGroup(OutputSection *OS, | |
| 270 | InputSection *Section) { | |
| 271 | assert(Config->Relocatable); | |
| 262 | static void finalizeShtGroup(OutputSection *os, | |
| 263 | InputSection *section) { | |
| 264 | assert(config->relocatable); | |
| 272 | 265 | |
| 273 | 266 | // sh_link field for SHT_GROUP sections should contain the section index of |
| 274 | 267 | // the symbol table. |
| 275 | OS->Link = In.SymTab->getParent()->SectionIndex; | |
| 268 | os->link = in.symTab->getParent()->sectionIndex; | |
| 276 | 269 | |
| 277 | 270 | // sh_info then contain index of an entry in symbol table section which |
| 278 | 271 | // provides signature of the section group. |
| 279 | ObjFile<ELFT> *Obj = Section->getFile<ELFT>(); | |
| 280 | ArrayRef<Symbol *> Symbols = Obj->getSymbols(); | |
| 281 | OS->Info = In.SymTab->getSymbolIndex(Symbols[Section->Info]); | |
| 272 | ArrayRef<Symbol *> symbols = section->file->getSymbols(); | |
| 273 | os->info = in.symTab->getSymbolIndex(symbols[section->info]); | |
| 282 | 274 | } |
| 283 | 275 | |
| 284 | template <class ELFT> void OutputSection::finalize() { | |
| 285 | if (Type == SHT_NOBITS) | |
| 286 | for (BaseCommand *Base : SectionCommands) | |
| 287 | if (isa<ByteCommand>(Base)) | |
| 288 | Type = SHT_PROGBITS; | |
| 289 | ||
| 290 | std::vector<InputSection *> V = getInputSections(this); | |
| 291 | InputSection *First = V.empty() ? nullptr : V[0]; | |
| 276 | void OutputSection::finalize() { | |
| 277 | std::vector<InputSection *> v = getInputSections(this); | |
| 278 | InputSection *first = v.empty() ? nullptr : v[0]; | |
| 292 | 279 | |
| 293 | if (Flags & SHF_LINK_ORDER) { | |
| 280 | if (flags & SHF_LINK_ORDER) { | |
| 294 | 281 | // We must preserve the link order dependency of sections with the |
| 295 | 282 | // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We |
| 296 | 283 | // need to translate the InputSection sh_link to the OutputSection sh_link, |
| 297 | 284 | // all InputSections in the OutputSection have the same dependency. |
| 298 | if (auto *D = First->getLinkOrderDep()) | |
| 299 | Link = D->getParent()->SectionIndex; | |
| 285 | if (auto *ex = dyn_cast<ARMExidxSyntheticSection>(first)) | |
| 286 | link = ex->getLinkOrderDep()->getParent()->sectionIndex; | |
| 287 | else if (auto *d = first->getLinkOrderDep()) | |
| 288 | link = d->getParent()->sectionIndex; | |
| 300 | 289 | } |
| 301 | 290 | |
| 302 | if (Type == SHT_GROUP) { | |
| 303 | finalizeShtGroup<ELFT>(this, First); | |
| 291 | if (type == SHT_GROUP) { | |
| 292 | finalizeShtGroup(this, first); | |
| 304 | 293 | return; |
| 305 | 294 | } |
| 306 | 295 | |
| 307 | if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL)) | |
| 296 | if (!config->copyRelocs || (type != SHT_RELA && type != SHT_REL)) | |
| 308 | 297 | return; |
| 309 | 298 | |
| 310 | if (isa<SyntheticSection>(First)) | |
| 299 | if (isa<SyntheticSection>(first)) | |
| 311 | 300 | return; |
| 312 | 301 | |
| 313 | Link = In.SymTab->getParent()->SectionIndex; | |
| 302 | link = in.symTab->getParent()->sectionIndex; | |
| 314 | 303 | // sh_info for SHT_REL[A] sections should contain the section header index of |
| 315 | 304 | // the section to which the relocation applies. |
| 316 | InputSectionBase *S = First->getRelocatedSection(); | |
| 317 | Info = S->getOutputSection()->SectionIndex; | |
| 318 | Flags |= SHF_INFO_LINK; | |
| 305 | InputSectionBase *s = first->getRelocatedSection(); | |
| 306 | info = s->getOutputSection()->sectionIndex; | |
| 307 | flags |= SHF_INFO_LINK; | |
| 319 | 308 | } |
| 320 | 309 | |
| 321 | 310 | // Returns true if S matches /Filename.?\.o$/. |
| 322 | static bool isCrtBeginEnd(StringRef S, StringRef Filename) { | |
| 323 | if (!S.endswith(".o")) | |
| 311 | static bool isCrtBeginEnd(StringRef s, StringRef filename) { | |
| 312 | if (!s.endswith(".o")) | |
| 324 | 313 | return false; |
| 325 | S = S.drop_back(2); | |
| 326 | if (S.endswith(Filename)) | |
| 314 | s = s.drop_back(2); | |
| 315 | if (s.endswith(filename)) | |
| 327 | 316 | return true; |
| 328 | return !S.empty() && S.drop_back().endswith(Filename); | |
| 317 | return !s.empty() && s.drop_back().endswith(filename); | |
| 329 | 318 | } |
| 330 | 319 | |
| 331 | static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); } | |
| 332 | static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); } | |
| 320 | static bool isCrtbegin(StringRef s) { return isCrtBeginEnd(s, "crtbegin"); } | |
| 321 | static bool isCrtend(StringRef s) { return isCrtBeginEnd(s, "crtend"); } | |
| 333 | 322 | |
| 334 | 323 | // .ctors and .dtors are sorted by this priority from highest to lowest. |
| 335 | 324 | // |
| ... | ... | @@ -349,52 +338,52 @@ static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); } |
| 349 | 338 | // .ctors are duplicate features (and .init_array is newer.) However, there |
| 350 | 339 | // are too many real-world use cases of .ctors, so we had no choice to |
| 351 | 340 | // support that with this rather ad-hoc semantics. |
| 352 | static bool compCtors(const InputSection *A, const InputSection *B) { | |
| 353 | bool BeginA = isCrtbegin(A->File->getName()); | |
| 354 | bool BeginB = isCrtbegin(B->File->getName()); | |
| 355 | if (BeginA != BeginB) | |
| 356 | return BeginA; | |
| 357 | bool EndA = isCrtend(A->File->getName()); | |
| 358 | bool EndB = isCrtend(B->File->getName()); | |
| 359 | if (EndA != EndB) | |
| 360 | return EndB; | |
| 361 | StringRef X = A->Name; | |
| 362 | StringRef Y = B->Name; | |
| 363 | assert(X.startswith(".ctors") || X.startswith(".dtors")); | |
| 364 | assert(Y.startswith(".ctors") || Y.startswith(".dtors")); | |
| 365 | X = X.substr(6); | |
| 366 | Y = Y.substr(6); | |
| 367 | return X < Y; | |
| 341 | static bool compCtors(const InputSection *a, const InputSection *b) { | |
| 342 | bool beginA = isCrtbegin(a->file->getName()); | |
| 343 | bool beginB = isCrtbegin(b->file->getName()); | |
| 344 | if (beginA != beginB) | |
| 345 | return beginA; | |
| 346 | bool endA = isCrtend(a->file->getName()); | |
| 347 | bool endB = isCrtend(b->file->getName()); | |
| 348 | if (endA != endB) | |
| 349 | return endB; | |
| 350 | StringRef x = a->name; | |
| 351 | StringRef y = b->name; | |
| 352 | assert(x.startswith(".ctors") || x.startswith(".dtors")); | |
| 353 | assert(y.startswith(".ctors") || y.startswith(".dtors")); | |
| 354 | x = x.substr(6); | |
| 355 | y = y.substr(6); | |
| 356 | return x < y; | |
| 368 | 357 | } |
| 369 | 358 | |
| 370 | 359 | // Sorts input sections by the special rules for .ctors and .dtors. |
| 371 | 360 | // Unfortunately, the rules are different from the one for .{init,fini}_array. |
| 372 | 361 | // Read the comment above. |
| 373 | 362 | void OutputSection::sortCtorsDtors() { |
| 374 | assert(SectionCommands.size() == 1); | |
| 375 | auto *ISD = cast<InputSectionDescription>(SectionCommands[0]); | |
| 376 | std::stable_sort(ISD->Sections.begin(), ISD->Sections.end(), compCtors); | |
| 363 | assert(sectionCommands.size() == 1); | |
| 364 | auto *isd = cast<InputSectionDescription>(sectionCommands[0]); | |
| 365 | llvm::stable_sort(isd->sections, compCtors); | |
| 377 | 366 | } |
| 378 | 367 | |
| 379 | 368 | // If an input string is in the form of "foo.N" where N is a number, |
| 380 | 369 | // return N. Otherwise, returns 65536, which is one greater than the |
| 381 | 370 | // lowest priority. |
| 382 | int elf::getPriority(StringRef S) { | |
| 383 | size_t Pos = S.rfind('.'); | |
| 384 | if (Pos == StringRef::npos) | |
| 371 | int elf::getPriority(StringRef s) { | |
| 372 | size_t pos = s.rfind('.'); | |
| 373 | if (pos == StringRef::npos) | |
| 385 | 374 | return 65536; |
| 386 | int V; | |
| 387 | if (!to_integer(S.substr(Pos + 1), V, 10)) | |
| 375 | int v; | |
| 376 | if (!to_integer(s.substr(pos + 1), v, 10)) | |
| 388 | 377 | return 65536; |
| 389 | return V; | |
| 378 | return v; | |
| 390 | 379 | } |
| 391 | 380 | |
| 392 | std::vector<InputSection *> elf::getInputSections(OutputSection *OS) { | |
| 393 | std::vector<InputSection *> Ret; | |
| 394 | for (BaseCommand *Base : OS->SectionCommands) | |
| 395 | if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) | |
| 396 | Ret.insert(Ret.end(), ISD->Sections.begin(), ISD->Sections.end()); | |
| 397 | return Ret; | |
| 381 | std::vector<InputSection *> elf::getInputSections(OutputSection *os) { | |
| 382 | std::vector<InputSection *> ret; | |
| 383 | for (BaseCommand *base : os->sectionCommands) | |
| 384 | if (auto *isd = dyn_cast<InputSectionDescription>(base)) | |
| 385 | ret.insert(ret.end(), isd->sections.begin(), isd->sections.end()); | |
| 386 | return ret; | |
| 398 | 387 | } |
| 399 | 388 | |
| 400 | 389 | // Sorts input sections by section name suffixes, so that .foo.N comes |
| ... | ... | @@ -405,14 +394,14 @@ std::vector<InputSection *> elf::getInputSections(OutputSection *OS) { |
| 405 | 394 | // For more detail, read the section of the GCC's manual about init_priority. |
| 406 | 395 | void OutputSection::sortInitFini() { |
| 407 | 396 | // Sort sections by priority. |
| 408 | sort([](InputSectionBase *S) { return getPriority(S->Name); }); | |
| 397 | sort([](InputSectionBase *s) { return getPriority(s->name); }); | |
| 409 | 398 | } |
| 410 | 399 | |
| 411 | 400 | std::array<uint8_t, 4> OutputSection::getFiller() { |
| 412 | if (Filler) | |
| 413 | return *Filler; | |
| 414 | if (Flags & SHF_EXECINSTR) | |
| 415 | return Target->TrapInstr; | |
| 401 | if (filler) | |
| 402 | return *filler; | |
| 403 | if (flags & SHF_EXECINSTR) | |
| 404 | return target->trapInstr; | |
| 416 | 405 | return {0, 0, 0, 0}; |
| 417 | 406 | } |
| 418 | 407 | |
| ... | ... | @@ -430,8 +419,3 @@ template void OutputSection::maybeCompress<ELF32LE>(); |
| 430 | 419 | template void OutputSection::maybeCompress<ELF32BE>(); |
| 431 | 420 | template void OutputSection::maybeCompress<ELF64LE>(); |
| 432 | 421 | template void OutputSection::maybeCompress<ELF64BE>(); |
| 433 | ||
| 434 | template void OutputSection::finalize<ELF32LE>(); | |
| 435 | template void OutputSection::finalize<ELF32BE>(); | |
| 436 | template void OutputSection::finalize<ELF64LE>(); | |
| 437 | template void OutputSection::finalize<ELF64BE>(); |
deps/lld/ELF/OutputSections.h+58-64| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- OutputSections.h -----------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -23,17 +22,8 @@ namespace lld { |
| 23 | 22 | namespace elf { |
| 24 | 23 | |
| 25 | 24 | struct PhdrEntry; |
| 26 | class Symbol; | |
| 27 | struct EhSectionPiece; | |
| 28 | class EhInputSection; | |
| 29 | 25 | class InputSection; |
| 30 | 26 | class InputSectionBase; |
| 31 | class MergeInputSection; | |
| 32 | class OutputSection; | |
| 33 | template <class ELFT> class ObjFile; | |
| 34 | template <class ELFT> class SharedFile; | |
| 35 | class SharedSymbol; | |
| 36 | class Defined; | |
| 37 | 27 | |
| 38 | 28 | // This represents a section in an output file. |
| 39 | 29 | // It is composed of multiple InputSections. |
| ... | ... | @@ -41,19 +31,19 @@ class Defined; |
| 41 | 31 | // non-overlapping file offsets and VAs. |
| 42 | 32 | class OutputSection final : public BaseCommand, public SectionBase { |
| 43 | 33 | public: |
| 44 | OutputSection(StringRef Name, uint32_t Type, uint64_t Flags); | |
| 34 | OutputSection(StringRef name, uint32_t type, uint64_t flags); | |
| 45 | 35 | |
| 46 | static bool classof(const SectionBase *S) { | |
| 47 | return S->kind() == SectionBase::Output; | |
| 36 | static bool classof(const SectionBase *s) { | |
| 37 | return s->kind() == SectionBase::Output; | |
| 48 | 38 | } |
| 49 | 39 | |
| 50 | static bool classof(const BaseCommand *C); | |
| 40 | static bool classof(const BaseCommand *c); | |
| 51 | 41 | |
| 52 | uint64_t getLMA() const { return PtLoad ? Addr + PtLoad->LMAOffset : Addr; } | |
| 53 | template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *SHdr); | |
| 42 | uint64_t getLMA() const { return ptLoad ? addr + ptLoad->lmaOffset : addr; } | |
| 43 | template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *sHdr); | |
| 54 | 44 | |
| 55 | uint32_t SectionIndex = UINT32_MAX; | |
| 56 | unsigned SortRank; | |
| 45 | uint32_t sectionIndex = UINT32_MAX; | |
| 46 | unsigned sortRank; | |
| 57 | 47 | |
| 58 | 48 | uint32_t getPhdrFlags() const; |
| 59 | 49 | |
| ... | ... | @@ -64,78 +54,82 @@ public: |
| 64 | 54 | // section offset we use the following formula: Off = Off_first + VA - |
| 65 | 55 | // VA_first, where Off_first and VA_first is file offset and VA of first |
| 66 | 56 | // section in PT_LOAD. |
| 67 | PhdrEntry *PtLoad = nullptr; | |
| 57 | PhdrEntry *ptLoad = nullptr; | |
| 68 | 58 | |
| 69 | 59 | // Pointer to a relocation section for this section. Usually nullptr because |
| 70 | 60 | // we consume relocations, but if --emit-relocs is specified (which is rare), |
| 71 | 61 | // it may have a non-null value. |
| 72 | OutputSection *RelocationSection = nullptr; | |
| 62 | OutputSection *relocationSection = nullptr; | |
| 73 | 63 | |
| 74 | 64 | // Initially this field is the number of InputSections that have been added to |
| 75 | 65 | // the OutputSection so far. Later on, after a call to assignAddresses, it |
| 76 | 66 | // corresponds to the Elf_Shdr member. |
| 77 | uint64_t Size = 0; | |
| 67 | uint64_t size = 0; | |
| 78 | 68 | |
| 79 | 69 | // The following fields correspond to Elf_Shdr members. |
| 80 | uint64_t Offset = 0; | |
| 81 | uint64_t Addr = 0; | |
| 82 | uint32_t ShName = 0; | |
| 83 | ||
| 84 | void addSection(InputSection *IS); | |
| 70 | uint64_t offset = 0; | |
| 71 | uint64_t addr = 0; | |
| 72 | uint32_t shName = 0; | |
| 85 | 73 | |
| 86 | // Location in the output buffer. | |
| 87 | uint8_t *Loc = nullptr; | |
| 74 | void addSection(InputSection *isec); | |
| 88 | 75 | |
| 89 | 76 | // The following members are normally only used in linker scripts. |
| 90 | MemoryRegion *MemRegion = nullptr; | |
| 91 | MemoryRegion *LMARegion = nullptr; | |
| 92 | Expr AddrExpr; | |
| 93 | Expr AlignExpr; | |
| 94 | Expr LMAExpr; | |
| 95 | Expr SubalignExpr; | |
| 96 | std::vector<BaseCommand *> SectionCommands; | |
| 97 | std::vector<StringRef> Phdrs; | |
| 98 | llvm::Optional<std::array<uint8_t, 4>> Filler; | |
| 99 | ConstraintKind Constraint = ConstraintKind::NoConstraint; | |
| 100 | std::string Location; | |
| 101 | std::string MemoryRegionName; | |
| 102 | std::string LMARegionName; | |
| 103 | bool NonAlloc = false; | |
| 104 | bool Noload = false; | |
| 105 | bool ExpressionsUseSymbols = false; | |
| 106 | bool InOverlay = false; | |
| 107 | ||
| 108 | template <class ELFT> void finalize(); | |
| 109 | template <class ELFT> void writeTo(uint8_t *Buf); | |
| 77 | MemoryRegion *memRegion = nullptr; | |
| 78 | MemoryRegion *lmaRegion = nullptr; | |
| 79 | Expr addrExpr; | |
| 80 | Expr alignExpr; | |
| 81 | Expr lmaExpr; | |
| 82 | Expr subalignExpr; | |
| 83 | std::vector<BaseCommand *> sectionCommands; | |
| 84 | std::vector<StringRef> phdrs; | |
| 85 | llvm::Optional<std::array<uint8_t, 4>> filler; | |
| 86 | ConstraintKind constraint = ConstraintKind::NoConstraint; | |
| 87 | std::string location; | |
| 88 | std::string memoryRegionName; | |
| 89 | std::string lmaRegionName; | |
| 90 | bool nonAlloc = false; | |
| 91 | bool noload = false; | |
| 92 | bool expressionsUseSymbols = false; | |
| 93 | bool usedInExpression = false; | |
| 94 | bool inOverlay = false; | |
| 95 | ||
| 96 | // Tracks whether the section has ever had an input section added to it, even | |
| 97 | // if the section was later removed (e.g. because it is a synthetic section | |
| 98 | // that wasn't needed). This is needed for orphan placement. | |
| 99 | bool hasInputSections = false; | |
| 100 | ||
| 101 | void finalize(); | |
| 102 | template <class ELFT> void writeTo(uint8_t *buf); | |
| 110 | 103 | template <class ELFT> void maybeCompress(); |
| 111 | 104 | |
| 112 | void sort(llvm::function_ref<int(InputSectionBase *S)> Order); | |
| 105 | void sort(llvm::function_ref<int(InputSectionBase *s)> order); | |
| 113 | 106 | void sortInitFini(); |
| 114 | 107 | void sortCtorsDtors(); |
| 115 | 108 | |
| 116 | 109 | private: |
| 117 | 110 | // Used for implementation of --compress-debug-sections option. |
| 118 | std::vector<uint8_t> ZDebugHeader; | |
| 119 | llvm::SmallVector<char, 1> CompressedData; | |
| 111 | std::vector<uint8_t> zDebugHeader; | |
| 112 | llvm::SmallVector<char, 1> compressedData; | |
| 120 | 113 | |
| 121 | 114 | std::array<uint8_t, 4> getFiller(); |
| 122 | 115 | }; |
| 123 | 116 | |
| 124 | int getPriority(StringRef S); | |
| 117 | int getPriority(StringRef s); | |
| 125 | 118 | |
| 126 | std::vector<InputSection *> getInputSections(OutputSection* OS); | |
| 119 | std::vector<InputSection *> getInputSections(OutputSection* os); | |
| 127 | 120 | |
| 128 | 121 | // All output sections that are handled by the linker specially are |
| 129 | 122 | // globally accessible. Writer initializes them, so don't use them |
| 130 | 123 | // until Writer is initialized. |
| 131 | 124 | struct Out { |
| 132 | static uint8_t First; | |
| 133 | static PhdrEntry *TlsPhdr; | |
| 134 | static OutputSection *ElfHeader; | |
| 135 | static OutputSection *ProgramHeaders; | |
| 136 | static OutputSection *PreinitArray; | |
| 137 | static OutputSection *InitArray; | |
| 138 | static OutputSection *FiniArray; | |
| 125 | static uint8_t *bufferStart; | |
| 126 | static uint8_t first; | |
| 127 | static PhdrEntry *tlsPhdr; | |
| 128 | static OutputSection *elfHeader; | |
| 129 | static OutputSection *programHeaders; | |
| 130 | static OutputSection *preinitArray; | |
| 131 | static OutputSection *initArray; | |
| 132 | static OutputSection *finiArray; | |
| 139 | 133 | }; |
| 140 | 134 | |
| 141 | 135 | } // namespace elf |
| ... | ... | @@ -146,7 +140,7 @@ namespace elf { |
| 146 | 140 | |
| 147 | 141 | uint64_t getHeaderSize(); |
| 148 | 142 | |
| 149 | extern std::vector<OutputSection *> OutputSections; | |
| 143 | extern std::vector<OutputSection *> outputSections; | |
| 150 | 144 | } // namespace elf |
| 151 | 145 | } // namespace lld |
| 152 | 146 |
deps/lld/ELF/Relocations.cpp+985-678| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Relocations.cpp ----------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -66,11 +65,11 @@ using namespace llvm::support::endian; |
| 66 | 65 | using namespace lld; |
| 67 | 66 | using namespace lld::elf; |
| 68 | 67 | |
| 69 | static Optional<std::string> getLinkerScriptLocation(const Symbol &Sym) { | |
| 70 | for (BaseCommand *Base : Script->SectionCommands) | |
| 71 | if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) | |
| 72 | if (Cmd->Sym == &Sym) | |
| 73 | return Cmd->Location; | |
| 68 | static Optional<std::string> getLinkerScriptLocation(const Symbol &sym) { | |
| 69 | for (BaseCommand *base : script->sectionCommands) | |
| 70 | if (auto *cmd = dyn_cast<SymbolAssignment>(base)) | |
| 71 | if (cmd->sym == &sym) | |
| 72 | return cmd->location; | |
| 74 | 73 | return None; |
| 75 | 74 | } |
| 76 | 75 | |
| ... | ... | @@ -79,19 +78,51 @@ static Optional<std::string> getLinkerScriptLocation(const Symbol &Sym) { |
| 79 | 78 | // >>> defined in /home/alice/src/foo.o |
| 80 | 79 | // >>> referenced by bar.c:12 (/home/alice/src/bar.c:12) |
| 81 | 80 | // >>> /home/alice/src/bar.o:(.text+0x1) |
| 82 | static std::string getLocation(InputSectionBase &S, const Symbol &Sym, | |
| 83 | uint64_t Off) { | |
| 84 | std::string Msg = "\n>>> defined in "; | |
| 85 | if (Sym.File) | |
| 86 | Msg += toString(Sym.File); | |
| 87 | else if (Optional<std::string> Loc = getLinkerScriptLocation(Sym)) | |
| 88 | Msg += *Loc; | |
| 89 | ||
| 90 | Msg += "\n>>> referenced by "; | |
| 91 | std::string Src = S.getSrcMsg(Sym, Off); | |
| 92 | if (!Src.empty()) | |
| 93 | Msg += Src + "\n>>> "; | |
| 94 | return Msg + S.getObjMsg(Off); | |
| 81 | static std::string getLocation(InputSectionBase &s, const Symbol &sym, | |
| 82 | uint64_t off) { | |
| 83 | std::string msg = "\n>>> defined in "; | |
| 84 | if (sym.file) | |
| 85 | msg += toString(sym.file); | |
| 86 | else if (Optional<std::string> loc = getLinkerScriptLocation(sym)) | |
| 87 | msg += *loc; | |
| 88 | ||
| 89 | msg += "\n>>> referenced by "; | |
| 90 | std::string src = s.getSrcMsg(sym, off); | |
| 91 | if (!src.empty()) | |
| 92 | msg += src + "\n>>> "; | |
| 93 | return msg + s.getObjMsg(off); | |
| 94 | } | |
| 95 | ||
| 96 | namespace { | |
| 97 | // Build a bitmask with one bit set for each RelExpr. | |
| 98 | // | |
| 99 | // Constexpr function arguments can't be used in static asserts, so we | |
| 100 | // use template arguments to build the mask. | |
| 101 | // But function template partial specializations don't exist (needed | |
| 102 | // for base case of the recursion), so we need a dummy struct. | |
| 103 | template <RelExpr... Exprs> struct RelExprMaskBuilder { | |
| 104 | static inline uint64_t build() { return 0; } | |
| 105 | }; | |
| 106 | ||
| 107 | // Specialization for recursive case. | |
| 108 | template <RelExpr Head, RelExpr... Tail> | |
| 109 | struct RelExprMaskBuilder<Head, Tail...> { | |
| 110 | static inline uint64_t build() { | |
| 111 | static_assert(0 <= Head && Head < 64, | |
| 112 | "RelExpr is too large for 64-bit mask!"); | |
| 113 | return (uint64_t(1) << Head) | RelExprMaskBuilder<Tail...>::build(); | |
| 114 | } | |
| 115 | }; | |
| 116 | } // namespace | |
| 117 | ||
| 118 | // Return true if `Expr` is one of `Exprs`. | |
| 119 | // There are fewer than 64 RelExpr's, so we can represent any set of | |
| 120 | // RelExpr's as a constant bit mask and test for membership with a | |
| 121 | // couple cheap bitwise operations. | |
| 122 | template <RelExpr... Exprs> bool oneof(RelExpr expr) { | |
| 123 | assert(0 <= expr && (int)expr < 64 && | |
| 124 | "RelExpr is too large for 64-bit mask!"); | |
| 125 | return (uint64_t(1) << expr) & RelExprMaskBuilder<Exprs...>::build(); | |
| 95 | 126 | } |
| 96 | 127 | |
| 97 | 128 | // This function is similar to the `handleTlsRelocation`. MIPS does not |
| ... | ... | @@ -100,204 +131,173 @@ static std::string getLocation(InputSectionBase &S, const Symbol &Sym, |
| 100 | 131 | // pollute other `handleTlsRelocation` by MIPS `ifs` statements. |
| 101 | 132 | // Mips has a custom MipsGotSection that handles the writing of GOT entries |
| 102 | 133 | // without dynamic relocations. |
| 103 | static unsigned handleMipsTlsRelocation(RelType Type, Symbol &Sym, | |
| 104 | InputSectionBase &C, uint64_t Offset, | |
| 105 | int64_t Addend, RelExpr Expr) { | |
| 106 | if (Expr == R_MIPS_TLSLD) { | |
| 107 | In.MipsGot->addTlsIndex(*C.File); | |
| 108 | C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | |
| 134 | static unsigned handleMipsTlsRelocation(RelType type, Symbol &sym, | |
| 135 | InputSectionBase &c, uint64_t offset, | |
| 136 | int64_t addend, RelExpr expr) { | |
| 137 | if (expr == R_MIPS_TLSLD) { | |
| 138 | in.mipsGot->addTlsIndex(*c.file); | |
| 139 | c.relocations.push_back({expr, type, offset, addend, &sym}); | |
| 109 | 140 | return 1; |
| 110 | 141 | } |
| 111 | if (Expr == R_MIPS_TLSGD) { | |
| 112 | In.MipsGot->addDynTlsEntry(*C.File, Sym); | |
| 113 | C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | |
| 142 | if (expr == R_MIPS_TLSGD) { | |
| 143 | in.mipsGot->addDynTlsEntry(*c.file, sym); | |
| 144 | c.relocations.push_back({expr, type, offset, addend, &sym}); | |
| 114 | 145 | return 1; |
| 115 | 146 | } |
| 116 | 147 | return 0; |
| 117 | 148 | } |
| 118 | 149 | |
| 119 | // This function is similar to the `handleMipsTlsRelocation`. ARM also does not | |
| 120 | // support any relaxations for TLS relocations. ARM is logically similar to Mips | |
| 121 | // in how it handles TLS, but Mips uses its own custom GOT which handles some | |
| 122 | // of the cases that ARM uses GOT relocations for. | |
| 123 | // | |
| 124 | // We look for TLS global dynamic and local dynamic relocations, these may | |
| 125 | // require the generation of a pair of GOT entries that have associated | |
| 126 | // dynamic relocations. When the results of the dynamic relocations can be | |
| 127 | // resolved at static link time we do so. This is necessary for static linking | |
| 128 | // as there will be no dynamic loader to resolve them at load-time. | |
| 150 | // Notes about General Dynamic and Local Dynamic TLS models below. They may | |
| 151 | // require the generation of a pair of GOT entries that have associated dynamic | |
| 152 | // relocations. The pair of GOT entries created are of the form GOT[e0] Module | |
| 153 | // Index (Used to find pointer to TLS block at run-time) GOT[e1] Offset of | |
| 154 | // symbol in TLS block. | |
| 129 | 155 | // |
| 130 | // The pair of GOT entries created are of the form | |
| 131 | // GOT[e0] Module Index (Used to find pointer to TLS block at run-time) | |
| 132 | // GOT[e1] Offset of symbol in TLS block | |
| 133 | template <class ELFT> | |
| 134 | static unsigned handleARMTlsRelocation(RelType Type, Symbol &Sym, | |
| 135 | InputSectionBase &C, uint64_t Offset, | |
| 136 | int64_t Addend, RelExpr Expr) { | |
| 137 | // The Dynamic TLS Module Index Relocation for a symbol defined in an | |
| 138 | // executable is always 1. If the target Symbol is not preemptible then | |
| 139 | // we know the offset into the TLS block at static link time. | |
| 140 | bool NeedDynId = Sym.IsPreemptible || Config->Shared; | |
| 141 | bool NeedDynOff = Sym.IsPreemptible; | |
| 142 | ||
| 143 | auto AddTlsReloc = [&](uint64_t Off, RelType Type, Symbol *Dest, bool Dyn) { | |
| 144 | if (Dyn) | |
| 145 | In.RelaDyn->addReloc(Type, In.Got, Off, Dest); | |
| 146 | else | |
| 147 | In.Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest}); | |
| 148 | }; | |
| 149 | ||
| 150 | // Local Dynamic is for access to module local TLS variables, while still | |
| 151 | // being suitable for being dynamically loaded via dlopen. | |
| 152 | // GOT[e0] is the module index, with a special value of 0 for the current | |
| 153 | // module. GOT[e1] is unused. There only needs to be one module index entry. | |
| 154 | if (Expr == R_TLSLD_PC && In.Got->addTlsIndex()) { | |
| 155 | AddTlsReloc(In.Got->getTlsIndexOff(), Target->TlsModuleIndexRel, | |
| 156 | NeedDynId ? nullptr : &Sym, NeedDynId); | |
| 157 | C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | |
| 158 | return 1; | |
| 159 | } | |
| 160 | ||
| 161 | // Global Dynamic is the most general purpose access model. When we know | |
| 162 | // the module index and offset of symbol in TLS block we can fill these in | |
| 163 | // using static GOT relocations. | |
| 164 | if (Expr == R_TLSGD_PC) { | |
| 165 | if (In.Got->addDynTlsEntry(Sym)) { | |
| 166 | uint64_t Off = In.Got->getGlobalDynOffset(Sym); | |
| 167 | AddTlsReloc(Off, Target->TlsModuleIndexRel, &Sym, NeedDynId); | |
| 168 | AddTlsReloc(Off + Config->Wordsize, Target->TlsOffsetRel, &Sym, | |
| 169 | NeedDynOff); | |
| 170 | } | |
| 171 | C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | |
| 172 | return 1; | |
| 173 | } | |
| 174 | return 0; | |
| 175 | } | |
| 176 | ||
| 177 | 156 | // Returns the number of relocations processed. |
| 178 | 157 | template <class ELFT> |
| 179 | 158 | static unsigned |
| 180 | handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, | |
| 181 | typename ELFT::uint Offset, int64_t Addend, RelExpr Expr) { | |
| 182 | if (!Sym.isTls()) | |
| 159 | handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c, | |
| 160 | typename ELFT::uint offset, int64_t addend, RelExpr expr) { | |
| 161 | if (!sym.isTls()) | |
| 183 | 162 | return 0; |
| 184 | 163 | |
| 185 | if (Config->EMachine == EM_ARM) | |
| 186 | return handleARMTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr); | |
| 187 | if (Config->EMachine == EM_MIPS) | |
| 188 | return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr); | |
| 189 | ||
| 190 | if (isRelExprOneOf<R_TLSDESC, R_AARCH64_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) && | |
| 191 | Config->Shared) { | |
| 192 | if (In.Got->addDynTlsEntry(Sym)) { | |
| 193 | uint64_t Off = In.Got->getGlobalDynOffset(Sym); | |
| 194 | In.RelaDyn->addReloc( | |
| 195 | {Target->TlsDescRel, In.Got, Off, !Sym.IsPreemptible, &Sym, 0}); | |
| 164 | if (config->emachine == EM_MIPS) | |
| 165 | return handleMipsTlsRelocation(type, sym, c, offset, addend, expr); | |
| 166 | ||
| 167 | if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC>( | |
| 168 | expr) && | |
| 169 | config->shared) { | |
| 170 | if (in.got->addDynTlsEntry(sym)) { | |
| 171 | uint64_t off = in.got->getGlobalDynOffset(sym); | |
| 172 | mainPart->relaDyn->addReloc( | |
| 173 | {target->tlsDescRel, in.got, off, !sym.isPreemptible, &sym, 0}); | |
| 196 | 174 | } |
| 197 | if (Expr != R_TLSDESC_CALL) | |
| 198 | C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | |
| 175 | if (expr != R_TLSDESC_CALL) | |
| 176 | c.relocations.push_back({expr, type, offset, addend, &sym}); | |
| 199 | 177 | return 1; |
| 200 | 178 | } |
| 201 | 179 | |
| 202 | if (isRelExprOneOf<R_TLSLD_GOT, R_TLSLD_GOT_FROM_END, R_TLSLD_PC, | |
| 203 | R_TLSLD_HINT>(Expr)) { | |
| 180 | bool canRelax = config->emachine != EM_ARM && config->emachine != EM_RISCV; | |
| 181 | ||
| 182 | // If we are producing an executable and the symbol is non-preemptable, it | |
| 183 | // must be defined and the code sequence can be relaxed to use Local-Exec. | |
| 184 | // | |
| 185 | // ARM and RISC-V do not support any relaxations for TLS relocations, however, | |
| 186 | // we can omit the DTPMOD dynamic relocations and resolve them at link time | |
| 187 | // because them are always 1. This may be necessary for static linking as | |
| 188 | // DTPMOD may not be expected at load time. | |
| 189 | bool isLocalInExecutable = !sym.isPreemptible && !config->shared; | |
| 190 | ||
| 191 | // Local Dynamic is for access to module local TLS variables, while still | |
| 192 | // being suitable for being dynamically loaded via dlopen. GOT[e0] is the | |
| 193 | // module index, with a special value of 0 for the current module. GOT[e1] is | |
| 194 | // unused. There only needs to be one module index entry. | |
| 195 | if (oneof<R_TLSLD_GOT, R_TLSLD_GOTPLT, R_TLSLD_PC, R_TLSLD_HINT>( | |
| 196 | expr)) { | |
| 204 | 197 | // Local-Dynamic relocs can be relaxed to Local-Exec. |
| 205 | if (!Config->Shared) { | |
| 206 | C.Relocations.push_back( | |
| 207 | {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type, | |
| 208 | Offset, Addend, &Sym}); | |
| 209 | return Target->TlsGdRelaxSkip; | |
| 198 | if (canRelax && !config->shared) { | |
| 199 | c.relocations.push_back( | |
| 200 | {target->adjustRelaxExpr(type, nullptr, R_RELAX_TLS_LD_TO_LE), type, | |
| 201 | offset, addend, &sym}); | |
| 202 | return target->getTlsGdRelaxSkip(type); | |
| 210 | 203 | } |
| 211 | if (Expr == R_TLSLD_HINT) | |
| 204 | if (expr == R_TLSLD_HINT) | |
| 212 | 205 | return 1; |
| 213 | if (In.Got->addTlsIndex()) | |
| 214 | In.RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, | |
| 215 | In.Got->getTlsIndexOff(), nullptr); | |
| 216 | C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | |
| 206 | if (in.got->addTlsIndex()) { | |
| 207 | if (isLocalInExecutable) | |
| 208 | in.got->relocations.push_back( | |
| 209 | {R_ADDEND, target->symbolicRel, in.got->getTlsIndexOff(), 1, &sym}); | |
| 210 | else | |
| 211 | mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, in.got, | |
| 212 | in.got->getTlsIndexOff(), nullptr); | |
| 213 | } | |
| 214 | c.relocations.push_back({expr, type, offset, addend, &sym}); | |
| 217 | 215 | return 1; |
| 218 | 216 | } |
| 219 | 217 | |
| 220 | 218 | // Local-Dynamic relocs can be relaxed to Local-Exec. |
| 221 | if (Expr == R_ABS && !Config->Shared) { | |
| 222 | C.Relocations.push_back( | |
| 223 | {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type, | |
| 224 | Offset, Addend, &Sym}); | |
| 219 | if (expr == R_DTPREL && !config->shared) { | |
| 220 | c.relocations.push_back( | |
| 221 | {target->adjustRelaxExpr(type, nullptr, R_RELAX_TLS_LD_TO_LE), type, | |
| 222 | offset, addend, &sym}); | |
| 225 | 223 | return 1; |
| 226 | 224 | } |
| 227 | 225 | |
| 228 | 226 | // Local-Dynamic sequence where offset of tls variable relative to dynamic |
| 229 | // thread pointer is stored in the got. | |
| 230 | if (Expr == R_TLSLD_GOT_OFF) { | |
| 231 | // Local-Dynamic relocs can be relaxed to local-exec | |
| 232 | if (!Config->Shared) { | |
| 233 | C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym}); | |
| 234 | return 1; | |
| 227 | // thread pointer is stored in the got. This cannot be relaxed to Local-Exec. | |
| 228 | if (expr == R_TLSLD_GOT_OFF) { | |
| 229 | if (!sym.isInGot()) { | |
| 230 | in.got->addEntry(sym); | |
| 231 | uint64_t off = sym.getGotOffset(); | |
| 232 | in.got->relocations.push_back( | |
| 233 | {R_ABS, target->tlsOffsetRel, off, 0, &sym}); | |
| 235 | 234 | } |
| 236 | if (!Sym.isInGot()) { | |
| 237 | In.Got->addEntry(Sym); | |
| 238 | uint64_t Off = Sym.getGotOffset(); | |
| 239 | In.Got->Relocations.push_back( | |
| 240 | {R_ABS, Target->TlsOffsetRel, Off, 0, &Sym}); | |
| 241 | } | |
| 242 | C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | |
| 235 | c.relocations.push_back({expr, type, offset, addend, &sym}); | |
| 243 | 236 | return 1; |
| 244 | 237 | } |
| 245 | 238 | |
| 246 | if (isRelExprOneOf<R_TLSDESC, R_AARCH64_TLSDESC_PAGE, R_TLSDESC_CALL, | |
| 247 | R_TLSGD_GOT, R_TLSGD_GOT_FROM_END, R_TLSGD_PC>(Expr)) { | |
| 248 | if (Config->Shared) { | |
| 249 | if (In.Got->addDynTlsEntry(Sym)) { | |
| 250 | uint64_t Off = In.Got->getGlobalDynOffset(Sym); | |
| 251 | In.RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, Off, &Sym); | |
| 239 | if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC, | |
| 240 | R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC>(expr)) { | |
| 241 | if (!canRelax || config->shared) { | |
| 242 | if (in.got->addDynTlsEntry(sym)) { | |
| 243 | uint64_t off = in.got->getGlobalDynOffset(sym); | |
| 244 | ||
| 245 | if (isLocalInExecutable) | |
| 246 | // Write one to the GOT slot. | |
| 247 | in.got->relocations.push_back( | |
| 248 | {R_ADDEND, target->symbolicRel, off, 1, &sym}); | |
| 249 | else | |
| 250 | mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, in.got, off, &sym); | |
| 252 | 251 | |
| 253 | 252 | // If the symbol is preemptible we need the dynamic linker to write |
| 254 | 253 | // the offset too. |
| 255 | uint64_t OffsetOff = Off + Config->Wordsize; | |
| 256 | if (Sym.IsPreemptible) | |
| 257 | In.RelaDyn->addReloc(Target->TlsOffsetRel, In.Got, OffsetOff, &Sym); | |
| 254 | uint64_t offsetOff = off + config->wordsize; | |
| 255 | if (sym.isPreemptible) | |
| 256 | mainPart->relaDyn->addReloc(target->tlsOffsetRel, in.got, offsetOff, | |
| 257 | &sym); | |
| 258 | 258 | else |
| 259 | In.Got->Relocations.push_back( | |
| 260 | {R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Sym}); | |
| 259 | in.got->relocations.push_back( | |
| 260 | {R_ABS, target->tlsOffsetRel, offsetOff, 0, &sym}); | |
| 261 | 261 | } |
| 262 | C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | |
| 262 | c.relocations.push_back({expr, type, offset, addend, &sym}); | |
| 263 | 263 | return 1; |
| 264 | 264 | } |
| 265 | 265 | |
| 266 | 266 | // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec |
| 267 | 267 | // depending on the symbol being locally defined or not. |
| 268 | if (Sym.IsPreemptible) { | |
| 269 | C.Relocations.push_back( | |
| 270 | {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type, | |
| 271 | Offset, Addend, &Sym}); | |
| 272 | if (!Sym.isInGot()) { | |
| 273 | In.Got->addEntry(Sym); | |
| 274 | In.RelaDyn->addReloc(Target->TlsGotRel, In.Got, Sym.getGotOffset(), | |
| 275 | &Sym); | |
| 268 | if (sym.isPreemptible) { | |
| 269 | c.relocations.push_back( | |
| 270 | {target->adjustRelaxExpr(type, nullptr, R_RELAX_TLS_GD_TO_IE), type, | |
| 271 | offset, addend, &sym}); | |
| 272 | if (!sym.isInGot()) { | |
| 273 | in.got->addEntry(sym); | |
| 274 | mainPart->relaDyn->addReloc(target->tlsGotRel, in.got, sym.getGotOffset(), | |
| 275 | &sym); | |
| 276 | 276 | } |
| 277 | 277 | } else { |
| 278 | C.Relocations.push_back( | |
| 279 | {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type, | |
| 280 | Offset, Addend, &Sym}); | |
| 278 | c.relocations.push_back( | |
| 279 | {target->adjustRelaxExpr(type, nullptr, R_RELAX_TLS_GD_TO_LE), type, | |
| 280 | offset, addend, &sym}); | |
| 281 | 281 | } |
| 282 | return Target->TlsGdRelaxSkip; | |
| 282 | return target->getTlsGdRelaxSkip(type); | |
| 283 | 283 | } |
| 284 | 284 | |
| 285 | 285 | // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally |
| 286 | 286 | // defined. |
| 287 | if (isRelExprOneOf<R_GOT, R_GOT_FROM_END, R_GOT_PC, R_AARCH64_GOT_PAGE_PC, | |
| 288 | R_GOT_OFF, R_TLSIE_HINT>(Expr) && | |
| 289 | !Config->Shared && !Sym.IsPreemptible) { | |
| 290 | C.Relocations.push_back({R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Sym}); | |
| 287 | if (oneof<R_GOT, R_GOTPLT, R_GOT_PC, R_AARCH64_GOT_PAGE_PC, R_GOT_OFF, | |
| 288 | R_TLSIE_HINT>(expr) && | |
| 289 | canRelax && isLocalInExecutable) { | |
| 290 | c.relocations.push_back({R_RELAX_TLS_IE_TO_LE, type, offset, addend, &sym}); | |
| 291 | 291 | return 1; |
| 292 | 292 | } |
| 293 | 293 | |
| 294 | if (Expr == R_TLSIE_HINT) | |
| 294 | if (expr == R_TLSIE_HINT) | |
| 295 | 295 | return 1; |
| 296 | 296 | return 0; |
| 297 | 297 | } |
| 298 | 298 | |
| 299 | static RelType getMipsPairType(RelType Type, bool IsLocal) { | |
| 300 | switch (Type) { | |
| 299 | static RelType getMipsPairType(RelType type, bool isLocal) { | |
| 300 | switch (type) { | |
| 301 | 301 | case R_MIPS_HI16: |
| 302 | 302 | return R_MIPS_LO16; |
| 303 | 303 | case R_MIPS_GOT16: |
| ... | ... | @@ -309,9 +309,9 @@ static RelType getMipsPairType(RelType Type, bool IsLocal) { |
| 309 | 309 | // the high 16 bits of the symbol's value. A paired R_MIPS_LO16 |
| 310 | 310 | // relocations handle low 16 bits of the address. That allows |
| 311 | 311 | // to allocate only one GOT entry for every 64 KBytes of local data. |
| 312 | return IsLocal ? R_MIPS_LO16 : R_MIPS_NONE; | |
| 312 | return isLocal ? R_MIPS_LO16 : R_MIPS_NONE; | |
| 313 | 313 | case R_MICROMIPS_GOT16: |
| 314 | return IsLocal ? R_MICROMIPS_LO16 : R_MIPS_NONE; | |
| 314 | return isLocal ? R_MICROMIPS_LO16 : R_MIPS_NONE; | |
| 315 | 315 | case R_MIPS_PCHI16: |
| 316 | 316 | return R_MIPS_PCLO16; |
| 317 | 317 | case R_MICROMIPS_HI16: |
| ... | ... | @@ -323,40 +323,38 @@ static RelType getMipsPairType(RelType Type, bool IsLocal) { |
| 323 | 323 | |
| 324 | 324 | // True if non-preemptable symbol always has the same value regardless of where |
| 325 | 325 | // the DSO is loaded. |
| 326 | static bool isAbsolute(const Symbol &Sym) { | |
| 327 | if (Sym.isUndefWeak()) | |
| 326 | static bool isAbsolute(const Symbol &sym) { | |
| 327 | if (sym.isUndefWeak()) | |
| 328 | 328 | return true; |
| 329 | if (const auto *DR = dyn_cast<Defined>(&Sym)) | |
| 330 | return DR->Section == nullptr; // Absolute symbol. | |
| 329 | if (const auto *dr = dyn_cast<Defined>(&sym)) | |
| 330 | return dr->section == nullptr; // Absolute symbol. | |
| 331 | 331 | return false; |
| 332 | 332 | } |
| 333 | 333 | |
| 334 | static bool isAbsoluteValue(const Symbol &Sym) { | |
| 335 | return isAbsolute(Sym) || Sym.isTls(); | |
| 334 | static bool isAbsoluteValue(const Symbol &sym) { | |
| 335 | return isAbsolute(sym) || sym.isTls(); | |
| 336 | 336 | } |
| 337 | 337 | |
| 338 | 338 | // Returns true if Expr refers a PLT entry. |
| 339 | static bool needsPlt(RelExpr Expr) { | |
| 340 | return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_AARCH64_PLT_PAGE_PC, | |
| 341 | R_GOT_PLT, R_AARCH64_GOT_PAGE_PC_PLT>(Expr); | |
| 339 | static bool needsPlt(RelExpr expr) { | |
| 340 | return oneof<R_PLT_PC, R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PLT>(expr); | |
| 342 | 341 | } |
| 343 | 342 | |
| 344 | 343 | // Returns true if Expr refers a GOT entry. Note that this function |
| 345 | 344 | // returns false for TLS variables even though they need GOT, because |
| 346 | 345 | // TLS variables uses GOT differently than the regular variables. |
| 347 | static bool needsGot(RelExpr Expr) { | |
| 348 | return isRelExprOneOf<R_GOT, R_GOT_OFF, R_HEXAGON_GOT, R_MIPS_GOT_LOCAL_PAGE, | |
| 349 | R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC, | |
| 350 | R_AARCH64_GOT_PAGE_PC_PLT, R_GOT_PC, R_GOT_FROM_END, | |
| 351 | R_GOT_PLT>(Expr); | |
| 346 | static bool needsGot(RelExpr expr) { | |
| 347 | return oneof<R_GOT, R_GOT_OFF, R_HEXAGON_GOT, R_MIPS_GOT_LOCAL_PAGE, | |
| 348 | R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC, | |
| 349 | R_GOT_PC, R_GOTPLT>(expr); | |
| 352 | 350 | } |
| 353 | 351 | |
| 354 | 352 | // True if this expression is of the form Sym - X, where X is a position in the |
| 355 | 353 | // file (PC, or GOT for example). |
| 356 | static bool isRelExpr(RelExpr Expr) { | |
| 357 | return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL, | |
| 358 | R_PPC_CALL, R_PPC_CALL_PLT, R_AARCH64_PAGE_PC, | |
| 359 | R_AARCH64_PLT_PAGE_PC, R_RELAX_GOT_PC>(Expr); | |
| 354 | static bool isRelExpr(RelExpr expr) { | |
| 355 | return oneof<R_PC, R_GOTREL, R_GOTPLTREL, R_MIPS_GOTREL, R_PPC64_CALL, | |
| 356 | R_PPC64_RELAX_TOC, R_AARCH64_PAGE_PC, R_RELAX_GOT_PC, | |
| 357 | R_RISCV_PC_INDIRECT>(expr); | |
| 360 | 358 | } |
| 361 | 359 | |
| 362 | 360 | // Returns true if a given relocation can be computed at link-time. |
| ... | ... | @@ -368,43 +366,43 @@ static bool isRelExpr(RelExpr Expr) { |
| 368 | 366 | // |
| 369 | 367 | // If this function returns false, that means we need to emit a |
| 370 | 368 | // dynamic relocation so that the relocation will be fixed at load-time. |
| 371 | static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym, | |
| 372 | InputSectionBase &S, uint64_t RelOff) { | |
| 369 | static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym, | |
| 370 | InputSectionBase &s, uint64_t relOff) { | |
| 373 | 371 | // These expressions always compute a constant |
| 374 | if (isRelExprOneOf<R_GOT_FROM_END, R_GOT_OFF, R_HEXAGON_GOT, R_TLSLD_GOT_OFF, | |
| 375 | R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOTREL, R_MIPS_GOT_OFF, | |
| 376 | R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, R_MIPS_TLSGD, | |
| 377 | R_AARCH64_GOT_PAGE_PC, R_AARCH64_GOT_PAGE_PC_PLT, R_GOT_PC, | |
| 378 | R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT, | |
| 379 | R_TLSGD_GOT_FROM_END, R_TLSGD_PC, R_PPC_CALL_PLT, | |
| 380 | R_TLSDESC_CALL, R_AARCH64_TLSDESC_PAGE, R_HINT, | |
| 381 | R_TLSLD_HINT, R_TLSIE_HINT>(E)) | |
| 372 | if (oneof<R_DTPREL, R_GOTPLT, R_GOT_OFF, R_HEXAGON_GOT, R_TLSLD_GOT_OFF, | |
| 373 | R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOTREL, R_MIPS_GOT_OFF, | |
| 374 | R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, R_MIPS_TLSGD, | |
| 375 | R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC, | |
| 376 | R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC, R_PPC32_PLTREL, | |
| 377 | R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD, R_TLSDESC_CALL, | |
| 378 | R_TLSDESC_PC, R_AARCH64_TLSDESC_PAGE, R_HINT, R_TLSLD_HINT, | |
| 379 | R_TLSIE_HINT>(e)) | |
| 382 | 380 | return true; |
| 383 | 381 | |
| 384 | 382 | // These never do, except if the entire file is position dependent or if |
| 385 | 383 | // only the low bits are used. |
| 386 | if (E == R_GOT || E == R_GOT_PLT || E == R_PLT || E == R_TLSDESC) | |
| 387 | return Target->usesOnlyLowPageBits(Type) || !Config->Pic; | |
| 384 | if (e == R_GOT || e == R_PLT || e == R_TLSDESC) | |
| 385 | return target->usesOnlyLowPageBits(type) || !config->isPic; | |
| 388 | 386 | |
| 389 | if (Sym.IsPreemptible) | |
| 387 | if (sym.isPreemptible) | |
| 390 | 388 | return false; |
| 391 | if (!Config->Pic) | |
| 389 | if (!config->isPic) | |
| 392 | 390 | return true; |
| 393 | 391 | |
| 394 | 392 | // The size of a non preemptible symbol is a constant. |
| 395 | if (E == R_SIZE) | |
| 393 | if (e == R_SIZE) | |
| 396 | 394 | return true; |
| 397 | 395 | |
| 398 | 396 | // For the target and the relocation, we want to know if they are |
| 399 | 397 | // absolute or relative. |
| 400 | bool AbsVal = isAbsoluteValue(Sym); | |
| 401 | bool RelE = isRelExpr(E); | |
| 402 | if (AbsVal && !RelE) | |
| 398 | bool absVal = isAbsoluteValue(sym); | |
| 399 | bool relE = isRelExpr(e); | |
| 400 | if (absVal && !relE) | |
| 403 | 401 | return true; |
| 404 | if (!AbsVal && RelE) | |
| 402 | if (!absVal && relE) | |
| 405 | 403 | return true; |
| 406 | if (!AbsVal && !RelE) | |
| 407 | return Target->usesOnlyLowPageBits(Type); | |
| 404 | if (!absVal && !relE) | |
| 405 | return target->usesOnlyLowPageBits(type); | |
| 408 | 406 | |
| 409 | 407 | // Relative relocation to an absolute value. This is normally unrepresentable, |
| 410 | 408 | // but if the relocation refers to a weak undefined symbol, we allow it to |
| ... | ... | @@ -414,59 +412,60 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym, |
| 414 | 412 | // Another special case is MIPS _gp_disp symbol which represents offset |
| 415 | 413 | // between start of a function and '_gp' value and defined as absolute just |
| 416 | 414 | // to simplify the code. |
| 417 | assert(AbsVal && RelE); | |
| 418 | if (Sym.isUndefWeak()) | |
| 415 | assert(absVal && relE); | |
| 416 | if (sym.isUndefWeak()) | |
| 419 | 417 | return true; |
| 420 | 418 | |
| 421 | error("relocation " + toString(Type) + " cannot refer to absolute symbol: " + | |
| 422 | toString(Sym) + getLocation(S, Sym, RelOff)); | |
| 419 | // We set the final symbols values for linker script defined symbols later. | |
| 420 | // They always can be computed as a link time constant. | |
| 421 | if (sym.scriptDefined) | |
| 422 | return true; | |
| 423 | ||
| 424 | error("relocation " + toString(type) + " cannot refer to absolute symbol: " + | |
| 425 | toString(sym) + getLocation(s, sym, relOff)); | |
| 423 | 426 | return true; |
| 424 | 427 | } |
| 425 | 428 | |
| 426 | static RelExpr toPlt(RelExpr Expr) { | |
| 427 | switch (Expr) { | |
| 428 | case R_PPC_CALL: | |
| 429 | return R_PPC_CALL_PLT; | |
| 429 | static RelExpr toPlt(RelExpr expr) { | |
| 430 | switch (expr) { | |
| 431 | case R_PPC64_CALL: | |
| 432 | return R_PPC64_CALL_PLT; | |
| 430 | 433 | case R_PC: |
| 431 | 434 | return R_PLT_PC; |
| 432 | case R_AARCH64_PAGE_PC: | |
| 433 | return R_AARCH64_PLT_PAGE_PC; | |
| 434 | case R_AARCH64_GOT_PAGE_PC: | |
| 435 | return R_AARCH64_GOT_PAGE_PC_PLT; | |
| 436 | 435 | case R_ABS: |
| 437 | 436 | return R_PLT; |
| 438 | case R_GOT: | |
| 439 | return R_GOT_PLT; | |
| 440 | 437 | default: |
| 441 | return Expr; | |
| 438 | return expr; | |
| 442 | 439 | } |
| 443 | 440 | } |
| 444 | 441 | |
| 445 | static RelExpr fromPlt(RelExpr Expr) { | |
| 442 | static RelExpr fromPlt(RelExpr expr) { | |
| 446 | 443 | // We decided not to use a plt. Optimize a reference to the plt to a |
| 447 | 444 | // reference to the symbol itself. |
| 448 | switch (Expr) { | |
| 445 | switch (expr) { | |
| 449 | 446 | case R_PLT_PC: |
| 447 | case R_PPC32_PLTREL: | |
| 450 | 448 | return R_PC; |
| 451 | case R_PPC_CALL_PLT: | |
| 452 | return R_PPC_CALL; | |
| 449 | case R_PPC64_CALL_PLT: | |
| 450 | return R_PPC64_CALL; | |
| 453 | 451 | case R_PLT: |
| 454 | 452 | return R_ABS; |
| 455 | 453 | default: |
| 456 | return Expr; | |
| 454 | return expr; | |
| 457 | 455 | } |
| 458 | 456 | } |
| 459 | 457 | |
| 460 | 458 | // Returns true if a given shared symbol is in a read-only segment in a DSO. |
| 461 | template <class ELFT> static bool isReadOnly(SharedSymbol &SS) { | |
| 462 | typedef typename ELFT::Phdr Elf_Phdr; | |
| 459 | template <class ELFT> static bool isReadOnly(SharedSymbol &ss) { | |
| 460 | using Elf_Phdr = typename ELFT::Phdr; | |
| 463 | 461 | |
| 464 | 462 | // Determine if the symbol is read-only by scanning the DSO's program headers. |
| 465 | const SharedFile<ELFT> &File = SS.getFile<ELFT>(); | |
| 466 | for (const Elf_Phdr &Phdr : check(File.getObj().program_headers())) | |
| 467 | if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) && | |
| 468 | !(Phdr.p_flags & ELF::PF_W) && SS.Value >= Phdr.p_vaddr && | |
| 469 | SS.Value < Phdr.p_vaddr + Phdr.p_memsz) | |
| 463 | const SharedFile &file = ss.getFile(); | |
| 464 | for (const Elf_Phdr &phdr : | |
| 465 | check(file.template getObj<ELFT>().program_headers())) | |
| 466 | if ((phdr.p_type == ELF::PT_LOAD || phdr.p_type == ELF::PT_GNU_RELRO) && | |
| 467 | !(phdr.p_flags & ELF::PF_W) && ss.value >= phdr.p_vaddr && | |
| 468 | ss.value < phdr.p_vaddr + phdr.p_memsz) | |
| 470 | 469 | return true; |
| 471 | 470 | return false; |
| 472 | 471 | } |
| ... | ... | @@ -477,22 +476,22 @@ template <class ELFT> static bool isReadOnly(SharedSymbol &SS) { |
| 477 | 476 | // them are copied by a copy relocation, all of them need to be copied. |
| 478 | 477 | // Otherwise, they would refer to different places at runtime. |
| 479 | 478 | template <class ELFT> |
| 480 | static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &SS) { | |
| 481 | typedef typename ELFT::Sym Elf_Sym; | |
| 479 | static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &ss) { | |
| 480 | using Elf_Sym = typename ELFT::Sym; | |
| 482 | 481 | |
| 483 | SharedFile<ELFT> &File = SS.getFile<ELFT>(); | |
| 482 | SharedFile &file = ss.getFile(); | |
| 484 | 483 | |
| 485 | SmallSet<SharedSymbol *, 4> Ret; | |
| 486 | for (const Elf_Sym &S : File.getGlobalELFSyms()) { | |
| 487 | if (S.st_shndx == SHN_UNDEF || S.st_shndx == SHN_ABS || | |
| 488 | S.getType() == STT_TLS || S.st_value != SS.Value) | |
| 484 | SmallSet<SharedSymbol *, 4> ret; | |
| 485 | for (const Elf_Sym &s : file.template getGlobalELFSyms<ELFT>()) { | |
| 486 | if (s.st_shndx == SHN_UNDEF || s.st_shndx == SHN_ABS || | |
| 487 | s.getType() == STT_TLS || s.st_value != ss.value) | |
| 489 | 488 | continue; |
| 490 | StringRef Name = check(S.getName(File.getStringTable())); | |
| 491 | Symbol *Sym = Symtab->find(Name); | |
| 492 | if (auto *Alias = dyn_cast_or_null<SharedSymbol>(Sym)) | |
| 493 | Ret.insert(Alias); | |
| 489 | StringRef name = check(s.getName(file.getStringTable())); | |
| 490 | Symbol *sym = symtab->find(name); | |
| 491 | if (auto *alias = dyn_cast_or_null<SharedSymbol>(sym)) | |
| 492 | ret.insert(alias); | |
| 494 | 493 | } |
| 495 | return Ret; | |
| 494 | return ret; | |
| 496 | 495 | } |
| 497 | 496 | |
| 498 | 497 | // When a symbol is copy relocated or we create a canonical plt entry, it is |
| ... | ... | @@ -500,19 +499,21 @@ static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &SS) { |
| 500 | 499 | // in .bss and in the case of a canonical plt entry it is in .plt. This function |
| 501 | 500 | // replaces the existing symbol with a Defined pointing to the appropriate |
| 502 | 501 | // location. |
| 503 | static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value, | |
| 504 | uint64_t Size) { | |
| 505 | Symbol Old = Sym; | |
| 506 | replaceSymbol<Defined>(&Sym, Sym.File, Sym.getName(), Sym.Binding, | |
| 507 | Sym.StOther, Sym.Type, Value, Size, Sec); | |
| 508 | Sym.PltIndex = Old.PltIndex; | |
| 509 | Sym.GotIndex = Old.GotIndex; | |
| 510 | Sym.VerdefIndex = Old.VerdefIndex; | |
| 511 | Sym.PPC64BranchltIndex = Old.PPC64BranchltIndex; | |
| 512 | Sym.IsPreemptible = true; | |
| 513 | Sym.ExportDynamic = true; | |
| 514 | Sym.IsUsedInRegularObj = true; | |
| 515 | Sym.Used = true; | |
| 502 | static void replaceWithDefined(Symbol &sym, SectionBase *sec, uint64_t value, | |
| 503 | uint64_t size) { | |
| 504 | Symbol old = sym; | |
| 505 | ||
| 506 | sym.replace(Defined{sym.file, sym.getName(), sym.binding, sym.stOther, | |
| 507 | sym.type, value, size, sec}); | |
| 508 | ||
| 509 | sym.pltIndex = old.pltIndex; | |
| 510 | sym.gotIndex = old.gotIndex; | |
| 511 | sym.verdefIndex = old.verdefIndex; | |
| 512 | sym.ppc64BranchltIndex = old.ppc64BranchltIndex; | |
| 513 | sym.isPreemptible = true; | |
| 514 | sym.exportDynamic = true; | |
| 515 | sym.isUsedInRegularObj = true; | |
| 516 | sym.used = true; | |
| 516 | 517 | } |
| 517 | 518 | |
| 518 | 519 | // Reserve space in .bss or .bss.rel.ro for copy relocation. |
| ... | ... | @@ -557,29 +558,29 @@ static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value, |
| 557 | 558 | // to the variable in .bss. This kind of issue is sometimes very hard to |
| 558 | 559 | // debug. What's a solution? Instead of exporting a varaible V from a DSO, |
| 559 | 560 | // define an accessor getV(). |
| 560 | template <class ELFT> static void addCopyRelSymbol(SharedSymbol &SS) { | |
| 561 | template <class ELFT> static void addCopyRelSymbol(SharedSymbol &ss) { | |
| 561 | 562 | // Copy relocation against zero-sized symbol doesn't make sense. |
| 562 | uint64_t SymSize = SS.getSize(); | |
| 563 | if (SymSize == 0 || SS.Alignment == 0) | |
| 564 | fatal("cannot create a copy relocation for symbol " + toString(SS)); | |
| 563 | uint64_t symSize = ss.getSize(); | |
| 564 | if (symSize == 0 || ss.alignment == 0) | |
| 565 | fatal("cannot create a copy relocation for symbol " + toString(ss)); | |
| 565 | 566 | |
| 566 | 567 | // See if this symbol is in a read-only segment. If so, preserve the symbol's |
| 567 | 568 | // memory protection by reserving space in the .bss.rel.ro section. |
| 568 | bool IsReadOnly = isReadOnly<ELFT>(SS); | |
| 569 | BssSection *Sec = make<BssSection>(IsReadOnly ? ".bss.rel.ro" : ".bss", | |
| 570 | SymSize, SS.Alignment); | |
| 571 | if (IsReadOnly) | |
| 572 | In.BssRelRo->getParent()->addSection(Sec); | |
| 569 | bool isRO = isReadOnly<ELFT>(ss); | |
| 570 | BssSection *sec = | |
| 571 | make<BssSection>(isRO ? ".bss.rel.ro" : ".bss", symSize, ss.alignment); | |
| 572 | if (isRO) | |
| 573 | in.bssRelRo->getParent()->addSection(sec); | |
| 573 | 574 | else |
| 574 | In.Bss->getParent()->addSection(Sec); | |
| 575 | in.bss->getParent()->addSection(sec); | |
| 575 | 576 | |
| 576 | 577 | // Look through the DSO's dynamic symbol table for aliases and create a |
| 577 | 578 | // dynamic symbol for each one. This causes the copy relocation to correctly |
| 578 | 579 | // interpose any aliases. |
| 579 | for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) | |
| 580 | replaceWithDefined(*Sym, Sec, 0, Sym->Size); | |
| 580 | for (SharedSymbol *sym : getSymbolsAt<ELFT>(ss)) | |
| 581 | replaceWithDefined(*sym, sec, 0, sym->size); | |
| 581 | 582 | |
| 582 | In.RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS); | |
| 583 | mainPart->relaDyn->addReloc(target->copyRel, sec, 0, &ss); | |
| 583 | 584 | } |
| 584 | 585 | |
| 585 | 586 | // MIPS has an odd notion of "paired" relocations to calculate addends. |
| ... | ... | @@ -587,34 +588,34 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol &SS) { |
| 587 | 588 | // R_MIPS_LO16 relocation after that, and an addend is calculated using |
| 588 | 589 | // the two relocations. |
| 589 | 590 | template <class ELFT, class RelTy> |
| 590 | static int64_t computeMipsAddend(const RelTy &Rel, const RelTy *End, | |
| 591 | InputSectionBase &Sec, RelExpr Expr, | |
| 592 | bool IsLocal) { | |
| 593 | if (Expr == R_MIPS_GOTREL && IsLocal) | |
| 594 | return Sec.getFile<ELFT>()->MipsGp0; | |
| 591 | static int64_t computeMipsAddend(const RelTy &rel, const RelTy *end, | |
| 592 | InputSectionBase &sec, RelExpr expr, | |
| 593 | bool isLocal) { | |
| 594 | if (expr == R_MIPS_GOTREL && isLocal) | |
| 595 | return sec.getFile<ELFT>()->mipsGp0; | |
| 595 | 596 | |
| 596 | 597 | // The ABI says that the paired relocation is used only for REL. |
| 597 | 598 | // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf |
| 598 | 599 | if (RelTy::IsRela) |
| 599 | 600 | return 0; |
| 600 | 601 | |
| 601 | RelType Type = Rel.getType(Config->IsMips64EL); | |
| 602 | uint32_t PairTy = getMipsPairType(Type, IsLocal); | |
| 603 | if (PairTy == R_MIPS_NONE) | |
| 602 | RelType type = rel.getType(config->isMips64EL); | |
| 603 | uint32_t pairTy = getMipsPairType(type, isLocal); | |
| 604 | if (pairTy == R_MIPS_NONE) | |
| 604 | 605 | return 0; |
| 605 | 606 | |
| 606 | const uint8_t *Buf = Sec.data().data(); | |
| 607 | uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); | |
| 607 | const uint8_t *buf = sec.data().data(); | |
| 608 | uint32_t symIndex = rel.getSymbol(config->isMips64EL); | |
| 608 | 609 | |
| 609 | 610 | // To make things worse, paired relocations might not be contiguous in |
| 610 | 611 | // the relocation table, so we need to do linear search. *sigh* |
| 611 | for (const RelTy *RI = &Rel; RI != End; ++RI) | |
| 612 | if (RI->getType(Config->IsMips64EL) == PairTy && | |
| 613 | RI->getSymbol(Config->IsMips64EL) == SymIndex) | |
| 614 | return Target->getImplicitAddend(Buf + RI->r_offset, PairTy); | |
| 612 | for (const RelTy *ri = &rel; ri != end; ++ri) | |
| 613 | if (ri->getType(config->isMips64EL) == pairTy && | |
| 614 | ri->getSymbol(config->isMips64EL) == symIndex) | |
| 615 | return target->getImplicitAddend(buf + ri->r_offset, pairTy); | |
| 615 | 616 | |
| 616 | warn("can't find matching " + toString(PairTy) + " relocation for " + | |
| 617 | toString(Type)); | |
| 617 | warn("can't find matching " + toString(pairTy) + " relocation for " + | |
| 618 | toString(type)); | |
| 618 | 619 | return 0; |
| 619 | 620 | } |
| 620 | 621 | |
| ... | ... | @@ -622,59 +623,174 @@ static int64_t computeMipsAddend(const RelTy &Rel, const RelTy *End, |
| 622 | 623 | // is in a relocation itself. If it is REL, we need to read it from an |
| 623 | 624 | // input section. |
| 624 | 625 | template <class ELFT, class RelTy> |
| 625 | static int64_t computeAddend(const RelTy &Rel, const RelTy *End, | |
| 626 | InputSectionBase &Sec, RelExpr Expr, | |
| 627 | bool IsLocal) { | |
| 628 | int64_t Addend; | |
| 629 | RelType Type = Rel.getType(Config->IsMips64EL); | |
| 626 | static int64_t computeAddend(const RelTy &rel, const RelTy *end, | |
| 627 | InputSectionBase &sec, RelExpr expr, | |
| 628 | bool isLocal) { | |
| 629 | int64_t addend; | |
| 630 | RelType type = rel.getType(config->isMips64EL); | |
| 630 | 631 | |
| 631 | 632 | if (RelTy::IsRela) { |
| 632 | Addend = getAddend<ELFT>(Rel); | |
| 633 | addend = getAddend<ELFT>(rel); | |
| 633 | 634 | } else { |
| 634 | const uint8_t *Buf = Sec.data().data(); | |
| 635 | Addend = Target->getImplicitAddend(Buf + Rel.r_offset, Type); | |
| 635 | const uint8_t *buf = sec.data().data(); | |
| 636 | addend = target->getImplicitAddend(buf + rel.r_offset, type); | |
| 636 | 637 | } |
| 637 | 638 | |
| 638 | if (Config->EMachine == EM_PPC64 && Config->Pic && Type == R_PPC64_TOC) | |
| 639 | Addend += getPPC64TocBase(); | |
| 640 | if (Config->EMachine == EM_MIPS) | |
| 641 | Addend += computeMipsAddend<ELFT>(Rel, End, Sec, Expr, IsLocal); | |
| 639 | if (config->emachine == EM_PPC64 && config->isPic && type == R_PPC64_TOC) | |
| 640 | addend += getPPC64TocBase(); | |
| 641 | if (config->emachine == EM_MIPS) | |
| 642 | addend += computeMipsAddend<ELFT>(rel, end, sec, expr, isLocal); | |
| 642 | 643 | |
| 643 | return Addend; | |
| 644 | return addend; | |
| 644 | 645 | } |
| 645 | 646 | |
| 646 | // Report an undefined symbol if necessary. | |
| 647 | // Returns true if this function printed out an error message. | |
| 648 | static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec, | |
| 649 | uint64_t Offset) { | |
| 650 | if (Sym.isLocal() || !Sym.isUndefined() || Sym.isWeak()) | |
| 651 | return false; | |
| 647 | // Custom error message if Sym is defined in a discarded section. | |
| 648 | template <class ELFT> | |
| 649 | static std::string maybeReportDiscarded(Undefined &sym) { | |
| 650 | auto *file = dyn_cast_or_null<ObjFile<ELFT>>(sym.file); | |
| 651 | if (!file || !sym.discardedSecIdx || | |
| 652 | file->getSections()[sym.discardedSecIdx] != &InputSection::discarded) | |
| 653 | return ""; | |
| 654 | ArrayRef<Elf_Shdr_Impl<ELFT>> objSections = | |
| 655 | CHECK(file->getObj().sections(), file); | |
| 656 | ||
| 657 | std::string msg; | |
| 658 | if (sym.type == ELF::STT_SECTION) { | |
| 659 | msg = "relocation refers to a discarded section: "; | |
| 660 | msg += CHECK( | |
| 661 | file->getObj().getSectionName(&objSections[sym.discardedSecIdx]), file); | |
| 662 | } else { | |
| 663 | msg = "relocation refers to a symbol in a discarded section: " + | |
| 664 | toString(sym); | |
| 665 | } | |
| 666 | msg += "\n>>> defined in " + toString(file); | |
| 667 | ||
| 668 | Elf_Shdr_Impl<ELFT> elfSec = objSections[sym.discardedSecIdx - 1]; | |
| 669 | if (elfSec.sh_type != SHT_GROUP) | |
| 670 | return msg; | |
| 671 | ||
| 672 | // If the discarded section is a COMDAT. | |
| 673 | StringRef signature = file->getShtGroupSignature(objSections, elfSec); | |
| 674 | if (const InputFile *prevailing = | |
| 675 | symtab->comdatGroups.lookup(CachedHashStringRef(signature))) | |
| 676 | msg += "\n>>> section group signature: " + signature.str() + | |
| 677 | "\n>>> prevailing definition is in " + toString(prevailing); | |
| 678 | return msg; | |
| 679 | } | |
| 652 | 680 | |
| 653 | bool CanBeExternal = | |
| 654 | Sym.computeBinding() != STB_LOCAL && Sym.Visibility == STV_DEFAULT; | |
| 655 | if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal) | |
| 656 | return false; | |
| 681 | // Undefined diagnostics are collected in a vector and emitted once all of | |
| 682 | // them are known, so that some postprocessing on the list of undefined symbols | |
| 683 | // can happen before lld emits diagnostics. | |
| 684 | struct UndefinedDiag { | |
| 685 | Symbol *sym; | |
| 686 | struct Loc { | |
| 687 | InputSectionBase *sec; | |
| 688 | uint64_t offset; | |
| 689 | }; | |
| 690 | std::vector<Loc> locs; | |
| 691 | bool isWarning; | |
| 692 | }; | |
| 693 | ||
| 694 | static std::vector<UndefinedDiag> undefs; | |
| 695 | ||
| 696 | template <class ELFT> | |
| 697 | static void reportUndefinedSymbol(const UndefinedDiag &undef) { | |
| 698 | Symbol &sym = *undef.sym; | |
| 699 | ||
| 700 | auto visibility = [&]() -> std::string { | |
| 701 | switch (sym.visibility) { | |
| 702 | case STV_INTERNAL: | |
| 703 | return "internal "; | |
| 704 | case STV_HIDDEN: | |
| 705 | return "hidden "; | |
| 706 | case STV_PROTECTED: | |
| 707 | return "protected "; | |
| 708 | default: | |
| 709 | return ""; | |
| 710 | } | |
| 711 | }; | |
| 657 | 712 | |
| 658 | std::string Msg = | |
| 659 | "undefined symbol: " + toString(Sym) + "\n>>> referenced by "; | |
| 713 | std::string msg = maybeReportDiscarded<ELFT>(cast<Undefined>(sym)); | |
| 714 | if (msg.empty()) | |
| 715 | msg = "undefined " + visibility() + "symbol: " + toString(sym); | |
| 716 | ||
| 717 | const size_t maxUndefReferences = 10; | |
| 718 | size_t i = 0; | |
| 719 | for (UndefinedDiag::Loc l : undef.locs) { | |
| 720 | if (i >= maxUndefReferences) | |
| 721 | break; | |
| 722 | InputSectionBase &sec = *l.sec; | |
| 723 | uint64_t offset = l.offset; | |
| 724 | ||
| 725 | msg += "\n>>> referenced by "; | |
| 726 | std::string src = sec.getSrcMsg(sym, offset); | |
| 727 | if (!src.empty()) | |
| 728 | msg += src + "\n>>> "; | |
| 729 | msg += sec.getObjMsg(offset); | |
| 730 | i++; | |
| 731 | } | |
| 660 | 732 | |
| 661 | std::string Src = Sec.getSrcMsg(Sym, Offset); | |
| 662 | if (!Src.empty()) | |
| 663 | Msg += Src + "\n>>> "; | |
| 664 | Msg += Sec.getObjMsg(Offset); | |
| 733 | if (i < undef.locs.size()) | |
| 734 | msg += ("\n>>> referenced " + Twine(undef.locs.size() - i) + " more times") | |
| 735 | .str(); | |
| 665 | 736 | |
| 666 | if (Sym.getName().startswith("_ZTV")) | |
| 667 | Msg += "\nthe vtable symbol may be undefined because the class is missing " | |
| 737 | if (sym.getName().startswith("_ZTV")) | |
| 738 | msg += "\nthe vtable symbol may be undefined because the class is missing " | |
| 668 | 739 | "its key function (see https://lld.llvm.org/missingkeyfunction)"; |
| 669 | 740 | |
| 670 | if ((Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal) || | |
| 671 | Config->NoinhibitExec) { | |
| 672 | warn(Msg); | |
| 673 | return false; | |
| 741 | if (undef.isWarning) | |
| 742 | warn(msg); | |
| 743 | else | |
| 744 | error(msg); | |
| 745 | } | |
| 746 | ||
| 747 | template <class ELFT> void elf::reportUndefinedSymbols() { | |
| 748 | // Find the first "undefined symbol" diagnostic for each diagnostic, and | |
| 749 | // collect all "referenced from" lines at the first diagnostic. | |
| 750 | DenseMap<Symbol *, UndefinedDiag *> firstRef; | |
| 751 | for (UndefinedDiag &undef : undefs) { | |
| 752 | assert(undef.locs.size() == 1); | |
| 753 | if (UndefinedDiag *canon = firstRef.lookup(undef.sym)) { | |
| 754 | canon->locs.push_back(undef.locs[0]); | |
| 755 | undef.locs.clear(); | |
| 756 | } else | |
| 757 | firstRef[undef.sym] = &undef; | |
| 674 | 758 | } |
| 675 | 759 | |
| 676 | error(Msg); | |
| 677 | return true; | |
| 760 | for (const UndefinedDiag &undef : undefs) { | |
| 761 | if (!undef.locs.empty()) | |
| 762 | reportUndefinedSymbol<ELFT>(undef); | |
| 763 | } | |
| 764 | undefs.clear(); | |
| 765 | } | |
| 766 | ||
| 767 | // Report an undefined symbol if necessary. | |
| 768 | // Returns true if the undefined symbol will produce an error message. | |
| 769 | template <class ELFT> | |
| 770 | static bool maybeReportUndefined(Symbol &sym, InputSectionBase &sec, | |
| 771 | uint64_t offset) { | |
| 772 | if (!sym.isUndefined() || sym.isWeak()) | |
| 773 | return false; | |
| 774 | ||
| 775 | bool canBeExternal = !sym.isLocal() && sym.computeBinding() != STB_LOCAL && | |
| 776 | sym.visibility == STV_DEFAULT; | |
| 777 | if (config->unresolvedSymbols == UnresolvedPolicy::Ignore && canBeExternal) | |
| 778 | return false; | |
| 779 | ||
| 780 | // clang (as of 2019-06-12) / gcc (as of 8.2.1) PPC64 may emit a .rela.toc | |
| 781 | // which references a switch table in a discarded .rodata/.text section. The | |
| 782 | // .toc and the .rela.toc are incorrectly not placed in the comdat. The ELF | |
| 783 | // spec says references from outside the group to a STB_LOCAL symbol are not | |
| 784 | // allowed. Work around the bug. | |
| 785 | if (config->emachine == EM_PPC64 && | |
| 786 | cast<Undefined>(sym).discardedSecIdx != 0 && sec.name == ".toc") | |
| 787 | return false; | |
| 788 | ||
| 789 | bool isWarning = | |
| 790 | (config->unresolvedSymbols == UnresolvedPolicy::Warn && canBeExternal) || | |
| 791 | config->noinhibitExec; | |
| 792 | undefs.push_back({&sym, {{&sec, offset}}, isWarning}); | |
| 793 | return !isWarning; | |
| 678 | 794 | } |
| 679 | 795 | |
| 680 | 796 | // MIPS N32 ABI treats series of successive relocations with the same offset |
| ... | ... | @@ -682,14 +798,14 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec, |
| 682 | 798 | // packs all relocations into the single relocation record. Here we emulate |
| 683 | 799 | // this for the N32 ABI. Iterate over relocation with the same offset and put |
| 684 | 800 | // theirs types into the single bit-set. |
| 685 | template <class RelTy> static RelType getMipsN32RelType(RelTy *&Rel, RelTy *End) { | |
| 686 | RelType Type = 0; | |
| 687 | uint64_t Offset = Rel->r_offset; | |
| 688 | ||
| 689 | int N = 0; | |
| 690 | while (Rel != End && Rel->r_offset == Offset) | |
| 691 | Type |= (Rel++)->getType(Config->IsMips64EL) << (8 * N++); | |
| 692 | return Type; | |
| 801 | template <class RelTy> static RelType getMipsN32RelType(RelTy *&rel, RelTy *end) { | |
| 802 | RelType type = 0; | |
| 803 | uint64_t offset = rel->r_offset; | |
| 804 | ||
| 805 | int n = 0; | |
| 806 | while (rel != end && rel->r_offset == offset) | |
| 807 | type |= (rel++)->getType(config->isMips64EL) << (8 * n++); | |
| 808 | return type; | |
| 693 | 809 | } |
| 694 | 810 | |
| 695 | 811 | // .eh_frame sections are mergeable input sections, so their input |
| ... | ... | @@ -706,77 +822,72 @@ template <class RelTy> static RelType getMipsN32RelType(RelTy *&Rel, RelTy *End) |
| 706 | 822 | namespace { |
| 707 | 823 | class OffsetGetter { |
| 708 | 824 | public: |
| 709 | explicit OffsetGetter(InputSectionBase &Sec) { | |
| 710 | if (auto *Eh = dyn_cast<EhInputSection>(&Sec)) | |
| 711 | Pieces = Eh->Pieces; | |
| 825 | explicit OffsetGetter(InputSectionBase &sec) { | |
| 826 | if (auto *eh = dyn_cast<EhInputSection>(&sec)) | |
| 827 | pieces = eh->pieces; | |
| 712 | 828 | } |
| 713 | 829 | |
| 714 | 830 | // Translates offsets in input sections to offsets in output sections. |
| 715 | 831 | // Given offset must increase monotonically. We assume that Piece is |
| 716 | // sorted by InputOff. | |
| 717 | uint64_t get(uint64_t Off) { | |
| 718 | if (Pieces.empty()) | |
| 719 | return Off; | |
| 720 | ||
| 721 | while (I != Pieces.size() && Pieces[I].InputOff + Pieces[I].Size <= Off) | |
| 722 | ++I; | |
| 723 | if (I == Pieces.size()) | |
| 832 | // sorted by inputOff. | |
| 833 | uint64_t get(uint64_t off) { | |
| 834 | if (pieces.empty()) | |
| 835 | return off; | |
| 836 | ||
| 837 | while (i != pieces.size() && pieces[i].inputOff + pieces[i].size <= off) | |
| 838 | ++i; | |
| 839 | if (i == pieces.size()) | |
| 724 | 840 | fatal(".eh_frame: relocation is not in any piece"); |
| 725 | 841 | |
| 726 | 842 | // Pieces must be contiguous, so there must be no holes in between. |
| 727 | assert(Pieces[I].InputOff <= Off && "Relocation not in any piece"); | |
| 843 | assert(pieces[i].inputOff <= off && "Relocation not in any piece"); | |
| 728 | 844 | |
| 729 | 845 | // Offset -1 means that the piece is dead (i.e. garbage collected). |
| 730 | if (Pieces[I].OutputOff == -1) | |
| 846 | if (pieces[i].outputOff == -1) | |
| 731 | 847 | return -1; |
| 732 | return Pieces[I].OutputOff + Off - Pieces[I].InputOff; | |
| 848 | return pieces[i].outputOff + off - pieces[i].inputOff; | |
| 733 | 849 | } |
| 734 | 850 | |
| 735 | 851 | private: |
| 736 | ArrayRef<EhSectionPiece> Pieces; | |
| 737 | size_t I = 0; | |
| 852 | ArrayRef<EhSectionPiece> pieces; | |
| 853 | size_t i = 0; | |
| 738 | 854 | }; |
| 739 | 855 | } // namespace |
| 740 | 856 | |
| 741 | static void addRelativeReloc(InputSectionBase *IS, uint64_t OffsetInSec, | |
| 742 | Symbol *Sym, int64_t Addend, RelExpr Expr, | |
| 743 | RelType Type) { | |
| 744 | // Add a relative relocation. If RelrDyn section is enabled, and the | |
| 857 | static void addRelativeReloc(InputSectionBase *isec, uint64_t offsetInSec, | |
| 858 | Symbol *sym, int64_t addend, RelExpr expr, | |
| 859 | RelType type) { | |
| 860 | Partition &part = isec->getPartition(); | |
| 861 | ||
| 862 | // Add a relative relocation. If relrDyn section is enabled, and the | |
| 745 | 863 | // relocation offset is guaranteed to be even, add the relocation to |
| 746 | // the RelrDyn section, otherwise add it to the RelaDyn section. | |
| 747 | // RelrDyn sections don't support odd offsets. Also, RelrDyn sections | |
| 864 | // the relrDyn section, otherwise add it to the relaDyn section. | |
| 865 | // relrDyn sections don't support odd offsets. Also, relrDyn sections | |
| 748 | 866 | // don't store the addend values, so we must write it to the relocated |
| 749 | 867 | // address. |
| 750 | if (In.RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) { | |
| 751 | IS->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym}); | |
| 752 | In.RelrDyn->Relocs.push_back({IS, OffsetInSec}); | |
| 868 | if (part.relrDyn && isec->alignment >= 2 && offsetInSec % 2 == 0) { | |
| 869 | isec->relocations.push_back({expr, type, offsetInSec, addend, sym}); | |
| 870 | part.relrDyn->relocs.push_back({isec, offsetInSec}); | |
| 753 | 871 | return; |
| 754 | 872 | } |
| 755 | In.RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend, Expr, | |
| 756 | Type); | |
| 873 | part.relaDyn->addReloc(target->relativeRel, isec, offsetInSec, sym, addend, | |
| 874 | expr, type); | |
| 757 | 875 | } |
| 758 | 876 | |
| 759 | 877 | template <class ELFT, class GotPltSection> |
| 760 | static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt, | |
| 761 | RelocationBaseSection *Rel, RelType Type, Symbol &Sym) { | |
| 762 | Plt->addEntry<ELFT>(Sym); | |
| 763 | GotPlt->addEntry(Sym); | |
| 764 | Rel->addReloc( | |
| 765 | {Type, GotPlt, Sym.getGotPltOffset(), !Sym.IsPreemptible, &Sym, 0}); | |
| 878 | static void addPltEntry(PltSection *plt, GotPltSection *gotPlt, | |
| 879 | RelocationBaseSection *rel, RelType type, Symbol &sym) { | |
| 880 | plt->addEntry<ELFT>(sym); | |
| 881 | gotPlt->addEntry(sym); | |
| 882 | rel->addReloc( | |
| 883 | {type, gotPlt, sym.getGotPltOffset(), !sym.isPreemptible, &sym, 0}); | |
| 766 | 884 | } |
| 767 | 885 | |
| 768 | template <class ELFT> static void addGotEntry(Symbol &Sym) { | |
| 769 | In.Got->addEntry(Sym); | |
| 770 | ||
| 771 | RelExpr Expr; | |
| 772 | if (Sym.isTls()) | |
| 773 | Expr = R_TLS; | |
| 774 | else if (Sym.isGnuIFunc()) | |
| 775 | Expr = R_PLT; | |
| 776 | else | |
| 777 | Expr = R_ABS; | |
| 886 | static void addGotEntry(Symbol &sym) { | |
| 887 | in.got->addEntry(sym); | |
| 778 | 888 | |
| 779 | uint64_t Off = Sym.getGotOffset(); | |
| 889 | RelExpr expr = sym.isTls() ? R_TLS : R_ABS; | |
| 890 | uint64_t off = sym.getGotOffset(); | |
| 780 | 891 | |
| 781 | 892 | // If a GOT slot value can be calculated at link-time, which is now, |
| 782 | 893 | // we can just fill that out. |
| ... | ... | @@ -785,42 +896,42 @@ template <class ELFT> static void addGotEntry(Symbol &Sym) { |
| 785 | 896 | // add a static relocation to a Relocations vector so that |
| 786 | 897 | // InputSection::relocate will do the work for us. We may be able |
| 787 | 898 | // to just write a value now, but it is a TODO.) |
| 788 | bool IsLinkTimeConstant = | |
| 789 | !Sym.IsPreemptible && (!Config->Pic || isAbsolute(Sym)); | |
| 790 | if (IsLinkTimeConstant) { | |
| 791 | In.Got->Relocations.push_back({Expr, Target->GotRel, Off, 0, &Sym}); | |
| 899 | bool isLinkTimeConstant = | |
| 900 | !sym.isPreemptible && (!config->isPic || isAbsolute(sym)); | |
| 901 | if (isLinkTimeConstant) { | |
| 902 | in.got->relocations.push_back({expr, target->symbolicRel, off, 0, &sym}); | |
| 792 | 903 | return; |
| 793 | 904 | } |
| 794 | 905 | |
| 795 | 906 | // Otherwise, we emit a dynamic relocation to .rel[a].dyn so that |
| 796 | 907 | // the GOT slot will be fixed at load-time. |
| 797 | if (!Sym.isTls() && !Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym)) { | |
| 798 | addRelativeReloc(In.Got, Off, &Sym, 0, R_ABS, Target->GotRel); | |
| 908 | if (!sym.isTls() && !sym.isPreemptible && config->isPic && !isAbsolute(sym)) { | |
| 909 | addRelativeReloc(in.got, off, &sym, 0, R_ABS, target->symbolicRel); | |
| 799 | 910 | return; |
| 800 | 911 | } |
| 801 | In.RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel, In.Got, | |
| 802 | Off, &Sym, 0, Sym.IsPreemptible ? R_ADDEND : R_ABS, | |
| 803 | Target->GotRel); | |
| 912 | mainPart->relaDyn->addReloc( | |
| 913 | sym.isTls() ? target->tlsGotRel : target->gotRel, in.got, off, &sym, 0, | |
| 914 | sym.isPreemptible ? R_ADDEND : R_ABS, target->symbolicRel); | |
| 804 | 915 | } |
| 805 | 916 | |
| 806 | 917 | // Return true if we can define a symbol in the executable that |
| 807 | 918 | // contains the value/function of a symbol defined in a shared |
| 808 | 919 | // library. |
| 809 | static bool canDefineSymbolInExecutable(Symbol &Sym) { | |
| 920 | static bool canDefineSymbolInExecutable(Symbol &sym) { | |
| 810 | 921 | // If the symbol has default visibility the symbol defined in the |
| 811 | 922 | // executable will preempt it. |
| 812 | 923 | // Note that we want the visibility of the shared symbol itself, not |
| 813 | 924 | // the visibility of the symbol in the output file we are producing. That is |
| 814 | // why we use Sym.StOther. | |
| 815 | if ((Sym.StOther & 0x3) == STV_DEFAULT) | |
| 925 | // why we use Sym.stOther. | |
| 926 | if ((sym.stOther & 0x3) == STV_DEFAULT) | |
| 816 | 927 | return true; |
| 817 | 928 | |
| 818 | 929 | // If we are allowed to break address equality of functions, defining |
| 819 | 930 | // a plt entry will allow the program to call the function in the |
| 820 | 931 | // .so, but the .so and the executable will no agree on the address |
| 821 | 932 | // of the function. Similar logic for objects. |
| 822 | return ((Sym.isFunc() && Config->IgnoreFunctionAddressEquality) || | |
| 823 | (Sym.isObject() && Config->IgnoreDataAddressEquality)); | |
| 933 | return ((sym.isFunc() && config->ignoreFunctionAddressEquality) || | |
| 934 | (sym.isObject() && config->ignoreDataAddressEquality)); | |
| 824 | 935 | } |
| 825 | 936 | |
| 826 | 937 | // The reason we have to do this early scan is as follows |
| ... | ... | @@ -837,23 +948,33 @@ static bool canDefineSymbolInExecutable(Symbol &Sym) { |
| 837 | 948 | // complicates things for the dynamic linker and means we would have to reserve |
| 838 | 949 | // space for the extra PT_LOAD even if we end up not using it. |
| 839 | 950 | template <class ELFT, class RelTy> |
| 840 | static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type, | |
| 841 | uint64_t Offset, Symbol &Sym, const RelTy &Rel, | |
| 842 | int64_t Addend) { | |
| 843 | if (isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Offset)) { | |
| 844 | Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | |
| 951 | static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type, | |
| 952 | uint64_t offset, Symbol &sym, const RelTy &rel, | |
| 953 | int64_t addend) { | |
| 954 | // If the relocation is known to be a link-time constant, we know no dynamic | |
| 955 | // relocation will be created, pass the control to relocateAlloc() or | |
| 956 | // relocateNonAlloc() to resolve it. | |
| 957 | // | |
| 958 | // The behavior of an undefined weak reference is implementation defined. If | |
| 959 | // the relocation is to a weak undef, and we are producing an executable, let | |
| 960 | // relocate{,Non}Alloc() resolve it. | |
| 961 | if (isStaticLinkTimeConstant(expr, type, sym, sec, offset) || | |
| 962 | (!config->shared && sym.isUndefWeak())) { | |
| 963 | sec.relocations.push_back({expr, type, offset, addend, &sym}); | |
| 845 | 964 | return; |
| 846 | 965 | } |
| 847 | bool CanWrite = (Sec.Flags & SHF_WRITE) || !Config->ZText; | |
| 848 | if (CanWrite) { | |
| 849 | // R_GOT refers to a position in the got, even if the symbol is preemptible. | |
| 850 | bool IsPreemptibleValue = Sym.IsPreemptible && Expr != R_GOT; | |
| 851 | 966 | |
| 852 | if (!IsPreemptibleValue) { | |
| 853 | addRelativeReloc(&Sec, Offset, &Sym, Addend, Expr, Type); | |
| 967 | bool canWrite = (sec.flags & SHF_WRITE) || !config->zText; | |
| 968 | if (canWrite) { | |
| 969 | RelType rel = target->getDynRel(type); | |
| 970 | if (expr == R_GOT || (rel == target->symbolicRel && !sym.isPreemptible)) { | |
| 971 | addRelativeReloc(&sec, offset, &sym, addend, expr, type); | |
| 854 | 972 | return; |
| 855 | } else if (RelType Rel = Target->getDynRel(Type)) { | |
| 856 | In.RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type); | |
| 973 | } else if (rel != 0) { | |
| 974 | if (config->emachine == EM_MIPS && rel == target->symbolicRel) | |
| 975 | rel = target->relativeRel; | |
| 976 | sec.getPartition().relaDyn->addReloc(rel, &sec, offset, &sym, addend, | |
| 977 | R_ADDEND, type); | |
| 857 | 978 | |
| 858 | 979 | // MIPS ABI turns using of GOT and dynamic relocations inside out. |
| 859 | 980 | // While regular ABI uses dynamic relocations to fill up GOT entries |
| ... | ... | @@ -870,62 +991,62 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type, |
| 870 | 991 | // to the GOT entry and reads the GOT entry when it needs to perform |
| 871 | 992 | // a dynamic relocation. |
| 872 | 993 | // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19 |
| 873 | if (Config->EMachine == EM_MIPS) | |
| 874 | In.MipsGot->addEntry(*Sec.File, Sym, Addend, Expr); | |
| 994 | if (config->emachine == EM_MIPS) | |
| 995 | in.mipsGot->addEntry(*sec.file, sym, addend, expr); | |
| 875 | 996 | return; |
| 876 | 997 | } |
| 877 | 998 | } |
| 878 | 999 | |
| 879 | // If the relocation is to a weak undef, and we are producing | |
| 880 | // executable, give up on it and produce a non preemptible 0. | |
| 881 | if (!Config->Shared && Sym.isUndefWeak()) { | |
| 882 | Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | |
| 883 | return; | |
| 884 | } | |
| 885 | ||
| 886 | if (!CanWrite && (Config->Pic && !isRelExpr(Expr))) { | |
| 1000 | if (!canWrite && (config->isPic && !isRelExpr(expr))) { | |
| 887 | 1001 | error( |
| 888 | "can't create dynamic relocation " + toString(Type) + " against " + | |
| 889 | (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) + | |
| 1002 | "can't create dynamic relocation " + toString(type) + " against " + | |
| 1003 | (sym.getName().empty() ? "local symbol" : "symbol: " + toString(sym)) + | |
| 890 | 1004 | " in readonly segment; recompile object files with -fPIC " |
| 891 | 1005 | "or pass '-Wl,-z,notext' to allow text relocations in the output" + |
| 892 | getLocation(Sec, Sym, Offset)); | |
| 1006 | getLocation(sec, sym, offset)); | |
| 893 | 1007 | return; |
| 894 | 1008 | } |
| 895 | 1009 | |
| 896 | // Copy relocations are only possible if we are creating an executable. | |
| 897 | if (Config->Shared) { | |
| 898 | errorOrWarn("relocation " + toString(Type) + | |
| 899 | " cannot be used against symbol " + toString(Sym) + | |
| 900 | "; recompile with -fPIC" + getLocation(Sec, Sym, Offset)); | |
| 1010 | // Copy relocations (for STT_OBJECT) and canonical PLT (for STT_FUNC) are only | |
| 1011 | // possible in an executable. | |
| 1012 | // | |
| 1013 | // Among R_ABS relocatoin types, symbolicRel has the same size as the word | |
| 1014 | // size. Others have fewer bits and may cause runtime overflow in -pie/-shared | |
| 1015 | // mode. Disallow them. | |
| 1016 | if (config->shared || | |
| 1017 | (config->pie && expr == R_ABS && type != target->symbolicRel)) { | |
| 1018 | errorOrWarn( | |
| 1019 | "relocation " + toString(type) + " cannot be used against " + | |
| 1020 | (sym.getName().empty() ? "local symbol" : "symbol " + toString(sym)) + | |
| 1021 | "; recompile with -fPIC" + getLocation(sec, sym, offset)); | |
| 901 | 1022 | return; |
| 902 | 1023 | } |
| 903 | 1024 | |
| 904 | 1025 | // If the symbol is undefined we already reported any relevant errors. |
| 905 | if (Sym.isUndefined()) | |
| 1026 | if (sym.isUndefined()) | |
| 906 | 1027 | return; |
| 907 | 1028 | |
| 908 | if (!canDefineSymbolInExecutable(Sym)) { | |
| 909 | error("cannot preempt symbol: " + toString(Sym) + | |
| 910 | getLocation(Sec, Sym, Offset)); | |
| 1029 | if (!canDefineSymbolInExecutable(sym)) { | |
| 1030 | error("cannot preempt symbol: " + toString(sym) + | |
| 1031 | getLocation(sec, sym, offset)); | |
| 911 | 1032 | return; |
| 912 | 1033 | } |
| 913 | 1034 | |
| 914 | if (Sym.isObject()) { | |
| 1035 | if (sym.isObject()) { | |
| 915 | 1036 | // Produce a copy relocation. |
| 916 | if (auto *SS = dyn_cast<SharedSymbol>(&Sym)) { | |
| 917 | if (!Config->ZCopyreloc) | |
| 918 | error("unresolvable relocation " + toString(Type) + | |
| 919 | " against symbol '" + toString(*SS) + | |
| 1037 | if (auto *ss = dyn_cast<SharedSymbol>(&sym)) { | |
| 1038 | if (!config->zCopyreloc) | |
| 1039 | error("unresolvable relocation " + toString(type) + | |
| 1040 | " against symbol '" + toString(*ss) + | |
| 920 | 1041 | "'; recompile with -fPIC or remove '-z nocopyreloc'" + |
| 921 | getLocation(Sec, Sym, Offset)); | |
| 922 | addCopyRelSymbol<ELFT>(*SS); | |
| 1042 | getLocation(sec, sym, offset)); | |
| 1043 | addCopyRelSymbol<ELFT>(*ss); | |
| 923 | 1044 | } |
| 924 | Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | |
| 1045 | sec.relocations.push_back({expr, type, offset, addend, &sym}); | |
| 925 | 1046 | return; |
| 926 | 1047 | } |
| 927 | 1048 | |
| 928 | if (Sym.isFunc()) { | |
| 1049 | if (sym.isFunc()) { | |
| 929 | 1050 | // This handles a non PIC program call to function in a shared library. In |
| 930 | 1051 | // an ideal world, we could just report an error saying the relocation can |
| 931 | 1052 | // overflow at runtime. In the real world with glibc, crt1.o has a |
| ... | ... | @@ -953,167 +1074,333 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type, |
| 953 | 1074 | // compiled without -fPIE/-fPIC and doesn't maintain ebx. |
| 954 | 1075 | // * If a library definition gets preempted to the executable, it will have |
| 955 | 1076 | // the wrong ebx value. |
| 956 | if (Config->Pie && Config->EMachine == EM_386) | |
| 957 | errorOrWarn("symbol '" + toString(Sym) + | |
| 1077 | if (config->pie && config->emachine == EM_386) | |
| 1078 | errorOrWarn("symbol '" + toString(sym) + | |
| 958 | 1079 | "' cannot be preempted; recompile with -fPIE" + |
| 959 | getLocation(Sec, Sym, Offset)); | |
| 960 | if (!Sym.isInPlt()) | |
| 961 | addPltEntry<ELFT>(In.Plt, In.GotPlt, In.RelaPlt, Target->PltRel, Sym); | |
| 962 | if (!Sym.isDefined()) | |
| 963 | replaceWithDefined(Sym, In.Plt, getPltEntryOffset(Sym.PltIndex), 0); | |
| 964 | Sym.NeedsPltAddr = true; | |
| 965 | Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | |
| 1080 | getLocation(sec, sym, offset)); | |
| 1081 | if (!sym.isInPlt()) | |
| 1082 | addPltEntry<ELFT>(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym); | |
| 1083 | if (!sym.isDefined()) | |
| 1084 | replaceWithDefined( | |
| 1085 | sym, in.plt, | |
| 1086 | target->pltHeaderSize + target->pltEntrySize * sym.pltIndex, 0); | |
| 1087 | sym.needsPltAddr = true; | |
| 1088 | sec.relocations.push_back({expr, type, offset, addend, &sym}); | |
| 966 | 1089 | return; |
| 967 | 1090 | } |
| 968 | 1091 | |
| 969 | errorOrWarn("symbol '" + toString(Sym) + "' has no type" + | |
| 970 | getLocation(Sec, Sym, Offset)); | |
| 1092 | errorOrWarn("symbol '" + toString(sym) + "' has no type" + | |
| 1093 | getLocation(sec, sym, offset)); | |
| 971 | 1094 | } |
| 972 | 1095 | |
| 1096 | struct IRelativeReloc { | |
| 1097 | RelType type; | |
| 1098 | InputSectionBase *sec; | |
| 1099 | uint64_t offset; | |
| 1100 | Symbol *sym; | |
| 1101 | }; | |
| 1102 | ||
| 1103 | static std::vector<IRelativeReloc> iRelativeRelocs; | |
| 1104 | ||
| 973 | 1105 | template <class ELFT, class RelTy> |
| 974 | static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I, | |
| 975 | RelTy *End) { | |
| 976 | const RelTy &Rel = *I; | |
| 977 | Symbol &Sym = Sec.getFile<ELFT>()->getRelocTargetSym(Rel); | |
| 978 | RelType Type; | |
| 1106 | static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i, | |
| 1107 | RelTy *end) { | |
| 1108 | const RelTy &rel = *i; | |
| 1109 | uint32_t symIndex = rel.getSymbol(config->isMips64EL); | |
| 1110 | Symbol &sym = sec.getFile<ELFT>()->getSymbol(symIndex); | |
| 1111 | RelType type; | |
| 979 | 1112 | |
| 980 | 1113 | // Deal with MIPS oddity. |
| 981 | if (Config->MipsN32Abi) { | |
| 982 | Type = getMipsN32RelType(I, End); | |
| 1114 | if (config->mipsN32Abi) { | |
| 1115 | type = getMipsN32RelType(i, end); | |
| 983 | 1116 | } else { |
| 984 | Type = Rel.getType(Config->IsMips64EL); | |
| 985 | ++I; | |
| 1117 | type = rel.getType(config->isMips64EL); | |
| 1118 | ++i; | |
| 986 | 1119 | } |
| 987 | 1120 | |
| 988 | 1121 | // Get an offset in an output section this relocation is applied to. |
| 989 | uint64_t Offset = GetOffset.get(Rel.r_offset); | |
| 990 | if (Offset == uint64_t(-1)) | |
| 1122 | uint64_t offset = getOffset.get(rel.r_offset); | |
| 1123 | if (offset == uint64_t(-1)) | |
| 991 | 1124 | return; |
| 992 | 1125 | |
| 993 | // Skip if the target symbol is an erroneous undefined symbol. | |
| 994 | if (maybeReportUndefined(Sym, Sec, Rel.r_offset)) | |
| 1126 | // Error if the target symbol is undefined. Symbol index 0 may be used by | |
| 1127 | // marker relocations, e.g. R_*_NONE and R_ARM_V4BX. Don't error on them. | |
| 1128 | if (symIndex != 0 && maybeReportUndefined<ELFT>(sym, sec, rel.r_offset)) | |
| 995 | 1129 | return; |
| 996 | 1130 | |
| 997 | const uint8_t *RelocatedAddr = Sec.data().begin() + Rel.r_offset; | |
| 998 | RelExpr Expr = Target->getRelExpr(Type, Sym, RelocatedAddr); | |
| 1131 | const uint8_t *relocatedAddr = sec.data().begin() + rel.r_offset; | |
| 1132 | RelExpr expr = target->getRelExpr(type, sym, relocatedAddr); | |
| 999 | 1133 | |
| 1000 | 1134 | // Ignore "hint" relocations because they are only markers for relaxation. |
| 1001 | if (isRelExprOneOf<R_HINT, R_NONE>(Expr)) | |
| 1135 | if (oneof<R_HINT, R_NONE>(expr)) | |
| 1002 | 1136 | return; |
| 1003 | 1137 | |
| 1004 | // Strenghten or relax relocations. | |
| 1005 | // | |
| 1006 | // GNU ifunc symbols must be accessed via PLT because their addresses | |
| 1007 | // are determined by runtime. | |
| 1138 | // We can separate the small code model relocations into 2 categories: | |
| 1139 | // 1) Those that access the compiler generated .toc sections. | |
| 1140 | // 2) Those that access the linker allocated got entries. | |
| 1141 | // lld allocates got entries to symbols on demand. Since we don't try to sort | |
| 1142 | // the got entries in any way, we don't have to track which objects have | |
| 1143 | // got-based small code model relocs. The .toc sections get placed after the | |
| 1144 | // end of the linker allocated .got section and we do sort those so sections | |
| 1145 | // addressed with small code model relocations come first. | |
| 1146 | if (config->emachine == EM_PPC64 && isPPC64SmallCodeModelTocReloc(type)) | |
| 1147 | sec.file->ppc64SmallCodeModelTocRelocs = true; | |
| 1148 | ||
| 1149 | if (sym.isGnuIFunc() && !config->zText && config->warnIfuncTextrel) { | |
| 1150 | warn("using ifunc symbols when text relocations are allowed may produce " | |
| 1151 | "a binary that will segfault, if the object file is linked with " | |
| 1152 | "old version of glibc (glibc 2.28 and earlier). If this applies to " | |
| 1153 | "you, consider recompiling the object files without -fPIC and " | |
| 1154 | "without -Wl,-z,notext option. Use -no-warn-ifunc-textrel to " | |
| 1155 | "turn off this warning." + | |
| 1156 | getLocation(sec, sym, offset)); | |
| 1157 | } | |
| 1158 | ||
| 1159 | // Read an addend. | |
| 1160 | int64_t addend = computeAddend<ELFT>(rel, end, sec, expr, sym.isLocal()); | |
| 1161 | ||
| 1162 | // Relax relocations. | |
| 1008 | 1163 | // |
| 1009 | // On the other hand, if we know that a PLT entry will be resolved within | |
| 1010 | // the same ELF module, we can skip PLT access and directly jump to the | |
| 1011 | // destination function. For example, if we are linking a main exectuable, | |
| 1012 | // all dynamic symbols that can be resolved within the executable will | |
| 1013 | // actually be resolved that way at runtime, because the main exectuable | |
| 1014 | // is always at the beginning of a search list. We can leverage that fact. | |
| 1015 | if (Sym.isGnuIFunc()) { | |
| 1016 | if (!Config->ZText && Config->WarnIfuncTextrel) { | |
| 1017 | warn("using ifunc symbols when text relocations are allowed may produce " | |
| 1018 | "a binary that will segfault, if the object file is linked with " | |
| 1019 | "old version of glibc (glibc 2.28 and earlier). If this applies to " | |
| 1020 | "you, consider recompiling the object files without -fPIC and " | |
| 1021 | "without -Wl,-z,notext option. Use -no-warn-ifunc-textrel to " | |
| 1022 | "turn off this warning." + | |
| 1023 | getLocation(Sec, Sym, Offset)); | |
| 1164 | // If we know that a PLT entry will be resolved within the same ELF module, we | |
| 1165 | // can skip PLT access and directly jump to the destination function. For | |
| 1166 | // example, if we are linking a main exectuable, all dynamic symbols that can | |
| 1167 | // be resolved within the executable will actually be resolved that way at | |
| 1168 | // runtime, because the main exectuable is always at the beginning of a search | |
| 1169 | // list. We can leverage that fact. | |
| 1170 | if (!sym.isPreemptible && (!sym.isGnuIFunc() || config->zIfuncNoplt)) { | |
| 1171 | if (expr == R_GOT_PC && !isAbsoluteValue(sym)) { | |
| 1172 | expr = target->adjustRelaxExpr(type, relocatedAddr, expr); | |
| 1173 | } else { | |
| 1174 | // Addend of R_PPC_PLTREL24 is used to choose call stub type. It should be | |
| 1175 | // ignored if optimized to R_PC. | |
| 1176 | if (config->emachine == EM_PPC && expr == R_PPC32_PLTREL) | |
| 1177 | addend = 0; | |
| 1178 | expr = fromPlt(expr); | |
| 1024 | 1179 | } |
| 1025 | Expr = toPlt(Expr); | |
| 1026 | } else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) { | |
| 1027 | Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr); | |
| 1028 | } else if (!Sym.IsPreemptible) { | |
| 1029 | Expr = fromPlt(Expr); | |
| 1030 | 1180 | } |
| 1031 | 1181 | |
| 1032 | // This relocation does not require got entry, but it is relative to got and | |
| 1033 | // needs it to be created. Here we request for that. | |
| 1034 | if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL, | |
| 1035 | R_GOTREL_FROM_END, R_PPC_TOC>(Expr)) | |
| 1036 | In.Got->HasGotOffRel = true; | |
| 1037 | ||
| 1038 | // Read an addend. | |
| 1039 | int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal()); | |
| 1182 | // If the relocation does not emit a GOT or GOTPLT entry but its computation | |
| 1183 | // uses their addresses, we need GOT or GOTPLT to be created. | |
| 1184 | // | |
| 1185 | // The 4 types that relative GOTPLT are all x86 and x86-64 specific. | |
| 1186 | if (oneof<R_GOTPLTONLY_PC, R_GOTPLTREL, R_GOTPLT, R_TLSGD_GOTPLT>(expr)) { | |
| 1187 | in.gotPlt->hasGotPltOffRel = true; | |
| 1188 | } else if (oneof<R_GOTONLY_PC, R_GOTREL, R_PPC64_TOCBASE, R_PPC64_RELAX_TOC>( | |
| 1189 | expr)) { | |
| 1190 | in.got->hasGotOffRel = true; | |
| 1191 | } | |
| 1040 | 1192 | |
| 1041 | 1193 | // Process some TLS relocations, including relaxing TLS relocations. |
| 1042 | 1194 | // Note that this function does not handle all TLS relocations. |
| 1043 | if (unsigned Processed = | |
| 1044 | handleTlsRelocation<ELFT>(Type, Sym, Sec, Offset, Addend, Expr)) { | |
| 1045 | I += (Processed - 1); | |
| 1195 | if (unsigned processed = | |
| 1196 | handleTlsRelocation<ELFT>(type, sym, sec, offset, addend, expr)) { | |
| 1197 | i += (processed - 1); | |
| 1046 | 1198 | return; |
| 1047 | 1199 | } |
| 1048 | 1200 | |
| 1049 | // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol. | |
| 1050 | if (needsPlt(Expr) && !Sym.isInPlt()) { | |
| 1051 | if (Sym.isGnuIFunc() && !Sym.IsPreemptible) | |
| 1052 | addPltEntry<ELFT>(In.Iplt, In.IgotPlt, In.RelaIplt, Target->IRelativeRel, | |
| 1053 | Sym); | |
| 1054 | else | |
| 1055 | addPltEntry<ELFT>(In.Plt, In.GotPlt, In.RelaPlt, Target->PltRel, Sym); | |
| 1201 | // We were asked not to generate PLT entries for ifuncs. Instead, pass the | |
| 1202 | // direct relocation on through. | |
| 1203 | if (sym.isGnuIFunc() && config->zIfuncNoplt) { | |
| 1204 | sym.exportDynamic = true; | |
| 1205 | mainPart->relaDyn->addReloc(type, &sec, offset, &sym, addend, R_ADDEND, type); | |
| 1206 | return; | |
| 1056 | 1207 | } |
| 1057 | 1208 | |
| 1058 | // Create a GOT slot if a relocation needs GOT. | |
| 1059 | if (needsGot(Expr)) { | |
| 1060 | if (Config->EMachine == EM_MIPS) { | |
| 1061 | // MIPS ABI has special rules to process GOT entries and doesn't | |
| 1062 | // require relocation entries for them. A special case is TLS | |
| 1063 | // relocations. In that case dynamic loader applies dynamic | |
| 1064 | // relocations to initialize TLS GOT entries. | |
| 1065 | // See "Global Offset Table" in Chapter 5 in the following document | |
| 1066 | // for detailed description: | |
| 1067 | // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf | |
| 1068 | In.MipsGot->addEntry(*Sec.File, Sym, Addend, Expr); | |
| 1069 | } else if (!Sym.isInGot()) { | |
| 1070 | addGotEntry<ELFT>(Sym); | |
| 1209 | // Non-preemptible ifuncs require special handling. First, handle the usual | |
| 1210 | // case where the symbol isn't one of these. | |
| 1211 | if (!sym.isGnuIFunc() || sym.isPreemptible) { | |
| 1212 | // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol. | |
| 1213 | if (needsPlt(expr) && !sym.isInPlt()) | |
| 1214 | addPltEntry<ELFT>(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym); | |
| 1215 | ||
| 1216 | // Create a GOT slot if a relocation needs GOT. | |
| 1217 | if (needsGot(expr)) { | |
| 1218 | if (config->emachine == EM_MIPS) { | |
| 1219 | // MIPS ABI has special rules to process GOT entries and doesn't | |
| 1220 | // require relocation entries for them. A special case is TLS | |
| 1221 | // relocations. In that case dynamic loader applies dynamic | |
| 1222 | // relocations to initialize TLS GOT entries. | |
| 1223 | // See "Global Offset Table" in Chapter 5 in the following document | |
| 1224 | // for detailed description: | |
| 1225 | // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf | |
| 1226 | in.mipsGot->addEntry(*sec.file, sym, addend, expr); | |
| 1227 | } else if (!sym.isInGot()) { | |
| 1228 | addGotEntry(sym); | |
| 1229 | } | |
| 1230 | } | |
| 1231 | } else { | |
| 1232 | // Handle a reference to a non-preemptible ifunc. These are special in a | |
| 1233 | // few ways: | |
| 1234 | // | |
| 1235 | // - Unlike most non-preemptible symbols, non-preemptible ifuncs do not have | |
| 1236 | // a fixed value. But assuming that all references to the ifunc are | |
| 1237 | // GOT-generating or PLT-generating, the handling of an ifunc is | |
| 1238 | // relatively straightforward. We create a PLT entry in Iplt, which is | |
| 1239 | // usually at the end of .plt, which makes an indirect call using a | |
| 1240 | // matching GOT entry in igotPlt, which is usually at the end of .got.plt. | |
| 1241 | // The GOT entry is relocated using an IRELATIVE relocation in relaIplt, | |
| 1242 | // which is usually at the end of .rela.plt. Unlike most relocations in | |
| 1243 | // .rela.plt, which may be evaluated lazily without -z now, dynamic | |
| 1244 | // loaders evaluate IRELATIVE relocs eagerly, which means that for | |
| 1245 | // IRELATIVE relocs only, GOT-generating relocations can point directly to | |
| 1246 | // .got.plt without requiring a separate GOT entry. | |
| 1247 | // | |
| 1248 | // - Despite the fact that an ifunc does not have a fixed value, compilers | |
| 1249 | // that are not passed -fPIC will assume that they do, and will emit | |
| 1250 | // direct (non-GOT-generating, non-PLT-generating) relocations to the | |
| 1251 | // symbol. This means that if a direct relocation to the symbol is | |
| 1252 | // seen, the linker must set a value for the symbol, and this value must | |
| 1253 | // be consistent no matter what type of reference is made to the symbol. | |
| 1254 | // This can be done by creating a PLT entry for the symbol in the way | |
| 1255 | // described above and making it canonical, that is, making all references | |
| 1256 | // point to the PLT entry instead of the resolver. In lld we also store | |
| 1257 | // the address of the PLT entry in the dynamic symbol table, which means | |
| 1258 | // that the symbol will also have the same value in other modules. | |
| 1259 | // Because the value loaded from the GOT needs to be consistent with | |
| 1260 | // the value computed using a direct relocation, a non-preemptible ifunc | |
| 1261 | // may end up with two GOT entries, one in .got.plt that points to the | |
| 1262 | // address returned by the resolver and is used only by the PLT entry, | |
| 1263 | // and another in .got that points to the PLT entry and is used by | |
| 1264 | // GOT-generating relocations. | |
| 1265 | // | |
| 1266 | // - The fact that these symbols do not have a fixed value makes them an | |
| 1267 | // exception to the general rule that a statically linked executable does | |
| 1268 | // not require any form of dynamic relocation. To handle these relocations | |
| 1269 | // correctly, the IRELATIVE relocations are stored in an array which a | |
| 1270 | // statically linked executable's startup code must enumerate using the | |
| 1271 | // linker-defined symbols __rela?_iplt_{start,end}. | |
| 1272 | // | |
| 1273 | // - An absolute relocation to a non-preemptible ifunc (such as a global | |
| 1274 | // variable containing a pointer to the ifunc) needs to be relocated in | |
| 1275 | // the exact same way as a GOT entry, so we can avoid needing to make the | |
| 1276 | // PLT entry canonical by translating such relocations into IRELATIVE | |
| 1277 | // relocations in the relaIplt. | |
| 1278 | if (!sym.isInPlt()) { | |
| 1279 | // Create PLT and GOTPLT slots for the symbol. | |
| 1280 | sym.isInIplt = true; | |
| 1281 | ||
| 1282 | // Create a copy of the symbol to use as the target of the IRELATIVE | |
| 1283 | // relocation in the igotPlt. This is in case we make the PLT canonical | |
| 1284 | // later, which would overwrite the original symbol. | |
| 1285 | // | |
| 1286 | // FIXME: Creating a copy of the symbol here is a bit of a hack. All | |
| 1287 | // that's really needed to create the IRELATIVE is the section and value, | |
| 1288 | // so ideally we should just need to copy those. | |
| 1289 | auto *directSym = make<Defined>(cast<Defined>(sym)); | |
| 1290 | addPltEntry<ELFT>(in.iplt, in.igotPlt, in.relaIplt, target->iRelativeRel, | |
| 1291 | *directSym); | |
| 1292 | sym.pltIndex = directSym->pltIndex; | |
| 1293 | } | |
| 1294 | if (expr == R_ABS && addend == 0 && (sec.flags & SHF_WRITE)) { | |
| 1295 | // We might be able to represent this as an IRELATIVE. But we don't know | |
| 1296 | // yet whether some later relocation will make the symbol point to a | |
| 1297 | // canonical PLT, which would make this either a dynamic RELATIVE (PIC) or | |
| 1298 | // static (non-PIC) relocation. So we keep a record of the information | |
| 1299 | // required to process the relocation, and after scanRelocs() has been | |
| 1300 | // called on all relocations, the relocation is resolved by | |
| 1301 | // addIRelativeRelocs(). | |
| 1302 | iRelativeRelocs.push_back({type, &sec, offset, &sym}); | |
| 1303 | return; | |
| 1304 | } | |
| 1305 | if (needsGot(expr)) { | |
| 1306 | // Redirect GOT accesses to point to the Igot. | |
| 1307 | // | |
| 1308 | // This field is also used to keep track of whether we ever needed a GOT | |
| 1309 | // entry. If we did and we make the PLT canonical later, we'll need to | |
| 1310 | // create a GOT entry pointing to the PLT entry for Sym. | |
| 1311 | sym.gotInIgot = true; | |
| 1312 | } else if (!needsPlt(expr)) { | |
| 1313 | // Make the ifunc's PLT entry canonical by changing the value of its | |
| 1314 | // symbol to redirect all references to point to it. | |
| 1315 | unsigned entryOffset = sym.pltIndex * target->pltEntrySize; | |
| 1316 | if (config->zRetpolineplt) | |
| 1317 | entryOffset += target->pltHeaderSize; | |
| 1318 | ||
| 1319 | auto &d = cast<Defined>(sym); | |
| 1320 | d.section = in.iplt; | |
| 1321 | d.value = entryOffset; | |
| 1322 | d.size = 0; | |
| 1323 | // It's important to set the symbol type here so that dynamic loaders | |
| 1324 | // don't try to call the PLT as if it were an ifunc resolver. | |
| 1325 | d.type = STT_FUNC; | |
| 1326 | ||
| 1327 | if (sym.gotInIgot) { | |
| 1328 | // We previously encountered a GOT generating reference that we | |
| 1329 | // redirected to the Igot. Now that the PLT entry is canonical we must | |
| 1330 | // clear the redirection to the Igot and add a GOT entry. As we've | |
| 1331 | // changed the symbol type to STT_FUNC future GOT generating references | |
| 1332 | // will naturally use this GOT entry. | |
| 1333 | // | |
| 1334 | // We don't need to worry about creating a MIPS GOT here because ifuncs | |
| 1335 | // aren't a thing on MIPS. | |
| 1336 | sym.gotInIgot = false; | |
| 1337 | addGotEntry(sym); | |
| 1338 | } | |
| 1071 | 1339 | } |
| 1072 | 1340 | } |
| 1073 | 1341 | |
| 1074 | processRelocAux<ELFT>(Sec, Expr, Type, Offset, Sym, Rel, Addend); | |
| 1342 | processRelocAux<ELFT>(sec, expr, type, offset, sym, rel, addend); | |
| 1075 | 1343 | } |
| 1076 | 1344 | |
| 1077 | 1345 | template <class ELFT, class RelTy> |
| 1078 | static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { | |
| 1079 | OffsetGetter GetOffset(Sec); | |
| 1346 | static void scanRelocs(InputSectionBase &sec, ArrayRef<RelTy> rels) { | |
| 1347 | OffsetGetter getOffset(sec); | |
| 1080 | 1348 | |
| 1081 | 1349 | // Not all relocations end up in Sec.Relocations, but a lot do. |
| 1082 | Sec.Relocations.reserve(Rels.size()); | |
| 1083 | ||
| 1084 | for (auto I = Rels.begin(), End = Rels.end(); I != End;) | |
| 1085 | scanReloc<ELFT>(Sec, GetOffset, I, End); | |
| 1086 | ||
| 1087 | // Sort relocations by offset to binary search for R_RISCV_PCREL_HI20 | |
| 1088 | if (Config->EMachine == EM_RISCV) | |
| 1089 | std::stable_sort(Sec.Relocations.begin(), Sec.Relocations.end(), | |
| 1090 | RelocationOffsetComparator{}); | |
| 1350 | sec.relocations.reserve(rels.size()); | |
| 1351 | ||
| 1352 | for (auto i = rels.begin(), end = rels.end(); i != end;) | |
| 1353 | scanReloc<ELFT>(sec, getOffset, i, end); | |
| 1354 | ||
| 1355 | // Sort relocations by offset for more efficient searching for | |
| 1356 | // R_RISCV_PCREL_HI20 and R_PPC64_ADDR64. | |
| 1357 | if (config->emachine == EM_RISCV || | |
| 1358 | (config->emachine == EM_PPC64 && sec.name == ".toc")) | |
| 1359 | llvm::stable_sort(sec.relocations, | |
| 1360 | [](const Relocation &lhs, const Relocation &rhs) { | |
| 1361 | return lhs.offset < rhs.offset; | |
| 1362 | }); | |
| 1091 | 1363 | } |
| 1092 | 1364 | |
| 1093 | template <class ELFT> void elf::scanRelocations(InputSectionBase &S) { | |
| 1094 | if (S.AreRelocsRela) | |
| 1095 | scanRelocs<ELFT>(S, S.relas<ELFT>()); | |
| 1365 | template <class ELFT> void elf::scanRelocations(InputSectionBase &s) { | |
| 1366 | if (s.areRelocsRela) | |
| 1367 | scanRelocs<ELFT>(s, s.relas<ELFT>()); | |
| 1096 | 1368 | else |
| 1097 | scanRelocs<ELFT>(S, S.rels<ELFT>()); | |
| 1369 | scanRelocs<ELFT>(s, s.rels<ELFT>()); | |
| 1370 | } | |
| 1371 | ||
| 1372 | // Figure out which representation to use for any absolute relocs to | |
| 1373 | // non-preemptible ifuncs that we visited during scanRelocs(). | |
| 1374 | void elf::addIRelativeRelocs() { | |
| 1375 | for (IRelativeReloc &r : iRelativeRelocs) { | |
| 1376 | if (r.sym->type == STT_GNU_IFUNC) | |
| 1377 | in.relaIplt->addReloc( | |
| 1378 | {target->iRelativeRel, r.sec, r.offset, true, r.sym, 0}); | |
| 1379 | else if (config->isPic) | |
| 1380 | addRelativeReloc(r.sec, r.offset, r.sym, 0, R_ABS, r.type); | |
| 1381 | else | |
| 1382 | r.sec->relocations.push_back({R_ABS, r.type, r.offset, 0, r.sym}); | |
| 1383 | } | |
| 1384 | iRelativeRelocs.clear(); | |
| 1098 | 1385 | } |
| 1099 | 1386 | |
| 1100 | static bool mergeCmp(const InputSection *A, const InputSection *B) { | |
| 1387 | static bool mergeCmp(const InputSection *a, const InputSection *b) { | |
| 1101 | 1388 | // std::merge requires a strict weak ordering. |
| 1102 | if (A->OutSecOff < B->OutSecOff) | |
| 1389 | if (a->outSecOff < b->outSecOff) | |
| 1103 | 1390 | return true; |
| 1104 | 1391 | |
| 1105 | if (A->OutSecOff == B->OutSecOff) { | |
| 1106 | auto *TA = dyn_cast<ThunkSection>(A); | |
| 1107 | auto *TB = dyn_cast<ThunkSection>(B); | |
| 1392 | if (a->outSecOff == b->outSecOff) { | |
| 1393 | auto *ta = dyn_cast<ThunkSection>(a); | |
| 1394 | auto *tb = dyn_cast<ThunkSection>(b); | |
| 1108 | 1395 | |
| 1109 | 1396 | // Check if Thunk is immediately before any specific Target |
| 1110 | 1397 | // InputSection for example Mips LA25 Thunks. |
| 1111 | if (TA && TA->getTargetInputSection() == B) | |
| 1398 | if (ta && ta->getTargetInputSection() == b) | |
| 1112 | 1399 | return true; |
| 1113 | 1400 | |
| 1114 | 1401 | // Place Thunk Sections without specific targets before |
| 1115 | 1402 | // non-Thunk Sections. |
| 1116 | if (TA && !TB && !TA->getTargetInputSection()) | |
| 1403 | if (ta && !tb && !ta->getTargetInputSection()) | |
| 1117 | 1404 | return true; |
| 1118 | 1405 | } |
| 1119 | 1406 | |
| ... | ... | @@ -1123,14 +1410,14 @@ static bool mergeCmp(const InputSection *A, const InputSection *B) { |
| 1123 | 1410 | // Call Fn on every executable InputSection accessed via the linker script |
| 1124 | 1411 | // InputSectionDescription::Sections. |
| 1125 | 1412 | static void forEachInputSectionDescription( |
| 1126 | ArrayRef<OutputSection *> OutputSections, | |
| 1127 | llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn) { | |
| 1128 | for (OutputSection *OS : OutputSections) { | |
| 1129 | if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR)) | |
| 1413 | ArrayRef<OutputSection *> outputSections, | |
| 1414 | llvm::function_ref<void(OutputSection *, InputSectionDescription *)> fn) { | |
| 1415 | for (OutputSection *os : outputSections) { | |
| 1416 | if (!(os->flags & SHF_ALLOC) || !(os->flags & SHF_EXECINSTR)) | |
| 1130 | 1417 | continue; |
| 1131 | for (BaseCommand *BC : OS->SectionCommands) | |
| 1132 | if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) | |
| 1133 | Fn(OS, ISD); | |
| 1418 | for (BaseCommand *bc : os->sectionCommands) | |
| 1419 | if (auto *isd = dyn_cast<InputSectionDescription>(bc)) | |
| 1420 | fn(os, isd); | |
| 1134 | 1421 | } |
| 1135 | 1422 | } |
| 1136 | 1423 | |
| ... | ... | @@ -1225,54 +1512,54 @@ static void forEachInputSectionDescription( |
| 1225 | 1512 | // in the Sections vector, and recalculate the InputSection output section |
| 1226 | 1513 | // offsets. |
| 1227 | 1514 | // This may invalidate any output section offsets stored outside of InputSection |
| 1228 | void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> OutputSections) { | |
| 1515 | void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> outputSections) { | |
| 1229 | 1516 | forEachInputSectionDescription( |
| 1230 | OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) { | |
| 1231 | if (ISD->ThunkSections.empty()) | |
| 1517 | outputSections, [&](OutputSection *os, InputSectionDescription *isd) { | |
| 1518 | if (isd->thunkSections.empty()) | |
| 1232 | 1519 | return; |
| 1233 | 1520 | |
| 1234 | 1521 | // Remove any zero sized precreated Thunks. |
| 1235 | llvm::erase_if(ISD->ThunkSections, | |
| 1236 | [](const std::pair<ThunkSection *, uint32_t> &TS) { | |
| 1237 | return TS.first->getSize() == 0; | |
| 1522 | llvm::erase_if(isd->thunkSections, | |
| 1523 | [](const std::pair<ThunkSection *, uint32_t> &ts) { | |
| 1524 | return ts.first->getSize() == 0; | |
| 1238 | 1525 | }); |
| 1239 | 1526 | |
| 1240 | 1527 | // ISD->ThunkSections contains all created ThunkSections, including |
| 1241 | 1528 | // those inserted in previous passes. Extract the Thunks created this |
| 1242 | // pass and order them in ascending OutSecOff. | |
| 1243 | std::vector<ThunkSection *> NewThunks; | |
| 1244 | for (const std::pair<ThunkSection *, uint32_t> TS : ISD->ThunkSections) | |
| 1245 | if (TS.second == Pass) | |
| 1246 | NewThunks.push_back(TS.first); | |
| 1247 | std::stable_sort(NewThunks.begin(), NewThunks.end(), | |
| 1248 | [](const ThunkSection *A, const ThunkSection *B) { | |
| 1249 | return A->OutSecOff < B->OutSecOff; | |
| 1250 | }); | |
| 1251 | ||
| 1252 | // Merge sorted vectors of Thunks and InputSections by OutSecOff | |
| 1253 | std::vector<InputSection *> Tmp; | |
| 1254 | Tmp.reserve(ISD->Sections.size() + NewThunks.size()); | |
| 1255 | ||
| 1256 | std::merge(ISD->Sections.begin(), ISD->Sections.end(), | |
| 1257 | NewThunks.begin(), NewThunks.end(), std::back_inserter(Tmp), | |
| 1529 | // pass and order them in ascending outSecOff. | |
| 1530 | std::vector<ThunkSection *> newThunks; | |
| 1531 | for (const std::pair<ThunkSection *, uint32_t> ts : isd->thunkSections) | |
| 1532 | if (ts.second == pass) | |
| 1533 | newThunks.push_back(ts.first); | |
| 1534 | llvm::stable_sort(newThunks, | |
| 1535 | [](const ThunkSection *a, const ThunkSection *b) { | |
| 1536 | return a->outSecOff < b->outSecOff; | |
| 1537 | }); | |
| 1538 | ||
| 1539 | // Merge sorted vectors of Thunks and InputSections by outSecOff | |
| 1540 | std::vector<InputSection *> tmp; | |
| 1541 | tmp.reserve(isd->sections.size() + newThunks.size()); | |
| 1542 | ||
| 1543 | std::merge(isd->sections.begin(), isd->sections.end(), | |
| 1544 | newThunks.begin(), newThunks.end(), std::back_inserter(tmp), | |
| 1258 | 1545 | mergeCmp); |
| 1259 | 1546 | |
| 1260 | ISD->Sections = std::move(Tmp); | |
| 1547 | isd->sections = std::move(tmp); | |
| 1261 | 1548 | }); |
| 1262 | 1549 | } |
| 1263 | 1550 | |
| 1264 | 1551 | // Find or create a ThunkSection within the InputSectionDescription (ISD) that |
| 1265 | 1552 | // is in range of Src. An ISD maps to a range of InputSections described by a |
| 1266 | 1553 | // linker script section pattern such as { .text .text.* }. |
| 1267 | ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *OS, InputSection *IS, | |
| 1268 | InputSectionDescription *ISD, | |
| 1269 | uint32_t Type, uint64_t Src) { | |
| 1270 | for (std::pair<ThunkSection *, uint32_t> TP : ISD->ThunkSections) { | |
| 1271 | ThunkSection *TS = TP.first; | |
| 1272 | uint64_t TSBase = OS->Addr + TS->OutSecOff; | |
| 1273 | uint64_t TSLimit = TSBase + TS->getSize(); | |
| 1274 | if (Target->inBranchRange(Type, Src, (Src > TSLimit) ? TSBase : TSLimit)) | |
| 1275 | return TS; | |
| 1554 | ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *os, InputSection *isec, | |
| 1555 | InputSectionDescription *isd, | |
| 1556 | uint32_t type, uint64_t src) { | |
| 1557 | for (std::pair<ThunkSection *, uint32_t> tp : isd->thunkSections) { | |
| 1558 | ThunkSection *ts = tp.first; | |
| 1559 | uint64_t tsBase = os->addr + ts->outSecOff; | |
| 1560 | uint64_t tsLimit = tsBase + ts->getSize(); | |
| 1561 | if (target->inBranchRange(type, src, (src > tsLimit) ? tsBase : tsLimit)) | |
| 1562 | return ts; | |
| 1276 | 1563 | } |
| 1277 | 1564 | |
| 1278 | 1565 | // No suitable ThunkSection exists. This can happen when there is a branch |
| ... | ... | @@ -1280,40 +1567,40 @@ ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *OS, InputSection *IS, |
| 1280 | 1567 | // many Thunks. Create a new ThunkSection as close to the InputSection as |
| 1281 | 1568 | // possible. Error if InputSection is so large we cannot place ThunkSection |
| 1282 | 1569 | // anywhere in Range. |
| 1283 | uint64_t ThunkSecOff = IS->OutSecOff; | |
| 1284 | if (!Target->inBranchRange(Type, Src, OS->Addr + ThunkSecOff)) { | |
| 1285 | ThunkSecOff = IS->OutSecOff + IS->getSize(); | |
| 1286 | if (!Target->inBranchRange(Type, Src, OS->Addr + ThunkSecOff)) | |
| 1570 | uint64_t thunkSecOff = isec->outSecOff; | |
| 1571 | if (!target->inBranchRange(type, src, os->addr + thunkSecOff)) { | |
| 1572 | thunkSecOff = isec->outSecOff + isec->getSize(); | |
| 1573 | if (!target->inBranchRange(type, src, os->addr + thunkSecOff)) | |
| 1287 | 1574 | fatal("InputSection too large for range extension thunk " + |
| 1288 | IS->getObjMsg(Src - (OS->Addr + IS->OutSecOff))); | |
| 1575 | isec->getObjMsg(src - (os->addr + isec->outSecOff))); | |
| 1289 | 1576 | } |
| 1290 | return addThunkSection(OS, ISD, ThunkSecOff); | |
| 1577 | return addThunkSection(os, isd, thunkSecOff); | |
| 1291 | 1578 | } |
| 1292 | 1579 | |
| 1293 | 1580 | // Add a Thunk that needs to be placed in a ThunkSection that immediately |
| 1294 | 1581 | // precedes its Target. |
| 1295 | ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS) { | |
| 1296 | ThunkSection *TS = ThunkedSections.lookup(IS); | |
| 1297 | if (TS) | |
| 1298 | return TS; | |
| 1582 | ThunkSection *ThunkCreator::getISThunkSec(InputSection *isec) { | |
| 1583 | ThunkSection *ts = thunkedSections.lookup(isec); | |
| 1584 | if (ts) | |
| 1585 | return ts; | |
| 1299 | 1586 | |
| 1300 | 1587 | // Find InputSectionRange within Target Output Section (TOS) that the |
| 1301 | 1588 | // InputSection (IS) that we need to precede is in. |
| 1302 | OutputSection *TOS = IS->getParent(); | |
| 1303 | for (BaseCommand *BC : TOS->SectionCommands) { | |
| 1304 | auto *ISD = dyn_cast<InputSectionDescription>(BC); | |
| 1305 | if (!ISD || ISD->Sections.empty()) | |
| 1589 | OutputSection *tos = isec->getParent(); | |
| 1590 | for (BaseCommand *bc : tos->sectionCommands) { | |
| 1591 | auto *isd = dyn_cast<InputSectionDescription>(bc); | |
| 1592 | if (!isd || isd->sections.empty()) | |
| 1306 | 1593 | continue; |
| 1307 | 1594 | |
| 1308 | InputSection *First = ISD->Sections.front(); | |
| 1309 | InputSection *Last = ISD->Sections.back(); | |
| 1595 | InputSection *first = isd->sections.front(); | |
| 1596 | InputSection *last = isd->sections.back(); | |
| 1310 | 1597 | |
| 1311 | if (IS->OutSecOff < First->OutSecOff || Last->OutSecOff < IS->OutSecOff) | |
| 1598 | if (isec->outSecOff < first->outSecOff || last->outSecOff < isec->outSecOff) | |
| 1312 | 1599 | continue; |
| 1313 | 1600 | |
| 1314 | TS = addThunkSection(TOS, ISD, IS->OutSecOff); | |
| 1315 | ThunkedSections[IS] = TS; | |
| 1316 | return TS; | |
| 1601 | ts = addThunkSection(tos, isd, isec->outSecOff); | |
| 1602 | thunkedSections[isec] = ts; | |
| 1603 | return ts; | |
| 1317 | 1604 | } |
| 1318 | 1605 | |
| 1319 | 1606 | return nullptr; |
| ... | ... | @@ -1336,82 +1623,93 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS) { |
| 1336 | 1623 | // distance from a thunk to its target will be sufficiently small to |
| 1337 | 1624 | // allow for the creation of a short thunk. |
| 1338 | 1625 | void ThunkCreator::createInitialThunkSections( |
| 1339 | ArrayRef<OutputSection *> OutputSections) { | |
| 1340 | uint32_t ThunkSectionSpacing = Target->getThunkSectionSpacing(); | |
| 1626 | ArrayRef<OutputSection *> outputSections) { | |
| 1627 | uint32_t thunkSectionSpacing = target->getThunkSectionSpacing(); | |
| 1341 | 1628 | |
| 1342 | 1629 | forEachInputSectionDescription( |
| 1343 | OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) { | |
| 1344 | if (ISD->Sections.empty()) | |
| 1630 | outputSections, [&](OutputSection *os, InputSectionDescription *isd) { | |
| 1631 | if (isd->sections.empty()) | |
| 1345 | 1632 | return; |
| 1346 | 1633 | |
| 1347 | uint32_t ISDBegin = ISD->Sections.front()->OutSecOff; | |
| 1348 | uint32_t ISDEnd = | |
| 1349 | ISD->Sections.back()->OutSecOff + ISD->Sections.back()->getSize(); | |
| 1350 | uint32_t LastThunkLowerBound = -1; | |
| 1351 | if (ISDEnd - ISDBegin > ThunkSectionSpacing * 2) | |
| 1352 | LastThunkLowerBound = ISDEnd - ThunkSectionSpacing; | |
| 1353 | ||
| 1354 | uint32_t ISLimit; | |
| 1355 | uint32_t PrevISLimit = ISDBegin; | |
| 1356 | uint32_t ThunkUpperBound = ISDBegin + ThunkSectionSpacing; | |
| 1357 | ||
| 1358 | for (const InputSection *IS : ISD->Sections) { | |
| 1359 | ISLimit = IS->OutSecOff + IS->getSize(); | |
| 1360 | if (ISLimit > ThunkUpperBound) { | |
| 1361 | addThunkSection(OS, ISD, PrevISLimit); | |
| 1362 | ThunkUpperBound = PrevISLimit + ThunkSectionSpacing; | |
| 1634 | uint32_t isdBegin = isd->sections.front()->outSecOff; | |
| 1635 | uint32_t isdEnd = | |
| 1636 | isd->sections.back()->outSecOff + isd->sections.back()->getSize(); | |
| 1637 | uint32_t lastThunkLowerBound = -1; | |
| 1638 | if (isdEnd - isdBegin > thunkSectionSpacing * 2) | |
| 1639 | lastThunkLowerBound = isdEnd - thunkSectionSpacing; | |
| 1640 | ||
| 1641 | uint32_t isecLimit; | |
| 1642 | uint32_t prevIsecLimit = isdBegin; | |
| 1643 | uint32_t thunkUpperBound = isdBegin + thunkSectionSpacing; | |
| 1644 | ||
| 1645 | for (const InputSection *isec : isd->sections) { | |
| 1646 | isecLimit = isec->outSecOff + isec->getSize(); | |
| 1647 | if (isecLimit > thunkUpperBound) { | |
| 1648 | addThunkSection(os, isd, prevIsecLimit); | |
| 1649 | thunkUpperBound = prevIsecLimit + thunkSectionSpacing; | |
| 1363 | 1650 | } |
| 1364 | if (ISLimit > LastThunkLowerBound) | |
| 1651 | if (isecLimit > lastThunkLowerBound) | |
| 1365 | 1652 | break; |
| 1366 | PrevISLimit = ISLimit; | |
| 1653 | prevIsecLimit = isecLimit; | |
| 1367 | 1654 | } |
| 1368 | addThunkSection(OS, ISD, ISLimit); | |
| 1655 | addThunkSection(os, isd, isecLimit); | |
| 1369 | 1656 | }); |
| 1370 | 1657 | } |
| 1371 | 1658 | |
| 1372 | ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS, | |
| 1373 | InputSectionDescription *ISD, | |
| 1374 | uint64_t Off) { | |
| 1375 | auto *TS = make<ThunkSection>(OS, Off); | |
| 1376 | ISD->ThunkSections.push_back({TS, Pass}); | |
| 1377 | return TS; | |
| 1659 | ThunkSection *ThunkCreator::addThunkSection(OutputSection *os, | |
| 1660 | InputSectionDescription *isd, | |
| 1661 | uint64_t off) { | |
| 1662 | auto *ts = make<ThunkSection>(os, off); | |
| 1663 | ts->partition = os->partition; | |
| 1664 | isd->thunkSections.push_back({ts, pass}); | |
| 1665 | return ts; | |
| 1378 | 1666 | } |
| 1379 | 1667 | |
| 1380 | std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type, | |
| 1381 | uint64_t Src) { | |
| 1382 | std::vector<Thunk *> *ThunkVec = nullptr; | |
| 1668 | static bool isThunkSectionCompatible(InputSection *source, | |
| 1669 | SectionBase *target) { | |
| 1670 | // We can't reuse thunks in different loadable partitions because they might | |
| 1671 | // not be loaded. But partition 1 (the main partition) will always be loaded. | |
| 1672 | if (source->partition != target->partition) | |
| 1673 | return target->partition == 1; | |
| 1674 | return true; | |
| 1675 | } | |
| 1676 | ||
| 1677 | std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec, | |
| 1678 | Relocation &rel, uint64_t src) { | |
| 1679 | std::vector<Thunk *> *thunkVec = nullptr; | |
| 1383 | 1680 | |
| 1384 | 1681 | // We use (section, offset) pair to find the thunk position if possible so |
| 1385 | 1682 | // that we create only one thunk for aliased symbols or ICFed sections. |
| 1386 | if (auto *D = dyn_cast<Defined>(&Sym)) | |
| 1387 | if (!D->isInPlt() && D->Section) | |
| 1388 | ThunkVec = &ThunkedSymbolsBySection[{D->Section->Repl, D->Value}]; | |
| 1389 | if (!ThunkVec) | |
| 1390 | ThunkVec = &ThunkedSymbols[&Sym]; | |
| 1683 | if (auto *d = dyn_cast<Defined>(rel.sym)) | |
| 1684 | if (!d->isInPlt() && d->section) | |
| 1685 | thunkVec = &thunkedSymbolsBySection[{d->section->repl, d->value}]; | |
| 1686 | if (!thunkVec) | |
| 1687 | thunkVec = &thunkedSymbols[rel.sym]; | |
| 1391 | 1688 | |
| 1392 | 1689 | // Check existing Thunks for Sym to see if they can be reused |
| 1393 | for (Thunk *T : *ThunkVec) | |
| 1394 | if (T->isCompatibleWith(Type) && | |
| 1395 | Target->inBranchRange(Type, Src, T->getThunkTargetSym()->getVA())) | |
| 1396 | return std::make_pair(T, false); | |
| 1690 | for (Thunk *t : *thunkVec) | |
| 1691 | if (isThunkSectionCompatible(isec, t->getThunkTargetSym()->section) && | |
| 1692 | t->isCompatibleWith(*isec, rel) && | |
| 1693 | target->inBranchRange(rel.type, src, t->getThunkTargetSym()->getVA())) | |
| 1694 | return std::make_pair(t, false); | |
| 1397 | 1695 | |
| 1398 | 1696 | // No existing compatible Thunk in range, create a new one |
| 1399 | Thunk *T = addThunk(Type, Sym); | |
| 1400 | ThunkVec->push_back(T); | |
| 1401 | return std::make_pair(T, true); | |
| 1697 | Thunk *t = addThunk(*isec, rel); | |
| 1698 | thunkVec->push_back(t); | |
| 1699 | return std::make_pair(t, true); | |
| 1402 | 1700 | } |
| 1403 | 1701 | |
| 1404 | 1702 | // Return true if the relocation target is an in range Thunk. |
| 1405 | 1703 | // Return false if the relocation is not to a Thunk. If the relocation target |
| 1406 | 1704 | // was originally to a Thunk, but is no longer in range we revert the |
| 1407 | 1705 | // relocation back to its original non-Thunk target. |
| 1408 | bool ThunkCreator::normalizeExistingThunk(Relocation &Rel, uint64_t Src) { | |
| 1409 | if (Thunk *T = Thunks.lookup(Rel.Sym)) { | |
| 1410 | if (Target->inBranchRange(Rel.Type, Src, Rel.Sym->getVA())) | |
| 1706 | bool ThunkCreator::normalizeExistingThunk(Relocation &rel, uint64_t src) { | |
| 1707 | if (Thunk *t = thunks.lookup(rel.sym)) { | |
| 1708 | if (target->inBranchRange(rel.type, src, rel.sym->getVA())) | |
| 1411 | 1709 | return true; |
| 1412 | Rel.Sym = &T->Destination; | |
| 1413 | if (Rel.Sym->isInPlt()) | |
| 1414 | Rel.Expr = toPlt(Rel.Expr); | |
| 1710 | rel.sym = &t->destination; | |
| 1711 | if (rel.sym->isInPlt()) | |
| 1712 | rel.expr = toPlt(rel.expr); | |
| 1415 | 1713 | } |
| 1416 | 1714 | return false; |
| 1417 | 1715 | } |
| ... | ... | @@ -1441,15 +1739,15 @@ bool ThunkCreator::normalizeExistingThunk(Relocation &Rel, uint64_t Src) { |
| 1441 | 1739 | // made no changes. If the target requires range extension thunks, currently |
| 1442 | 1740 | // ARM, then any future change in offset between caller and callee risks a |
| 1443 | 1741 | // relocation out of range error. |
| 1444 | bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) { | |
| 1445 | bool AddressesChanged = false; | |
| 1742 | bool ThunkCreator::createThunks(ArrayRef<OutputSection *> outputSections) { | |
| 1743 | bool addressesChanged = false; | |
| 1446 | 1744 | |
| 1447 | if (Pass == 0 && Target->getThunkSectionSpacing()) | |
| 1448 | createInitialThunkSections(OutputSections); | |
| 1745 | if (pass == 0 && target->getThunkSectionSpacing()) | |
| 1746 | createInitialThunkSections(outputSections); | |
| 1449 | 1747 | |
| 1450 | 1748 | // With Thunk Size much smaller than branch range we expect to |
| 1451 | 1749 | // converge quickly; if we get to 10 something has gone wrong. |
| 1452 | if (Pass == 10) | |
| 1750 | if (pass == 10) | |
| 1453 | 1751 | fatal("thunk creation not converged"); |
| 1454 | 1752 | |
| 1455 | 1753 | // Create all the Thunks and insert them into synthetic ThunkSections. The |
| ... | ... | @@ -1458,55 +1756,64 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) { |
| 1458 | 1756 | // ThunkSections as ThunkSections are not always inserted into the same |
| 1459 | 1757 | // InputSectionDescription as the caller. |
| 1460 | 1758 | forEachInputSectionDescription( |
| 1461 | OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) { | |
| 1462 | for (InputSection *IS : ISD->Sections) | |
| 1463 | for (Relocation &Rel : IS->Relocations) { | |
| 1464 | uint64_t Src = IS->getVA(Rel.Offset); | |
| 1759 | outputSections, [&](OutputSection *os, InputSectionDescription *isd) { | |
| 1760 | for (InputSection *isec : isd->sections) | |
| 1761 | for (Relocation &rel : isec->relocations) { | |
| 1762 | uint64_t src = isec->getVA(rel.offset); | |
| 1465 | 1763 | |
| 1466 | 1764 | // If we are a relocation to an existing Thunk, check if it is |
| 1467 | 1765 | // still in range. If not then Rel will be altered to point to its |
| 1468 | 1766 | // original target so another Thunk can be generated. |
| 1469 | if (Pass > 0 && normalizeExistingThunk(Rel, Src)) | |
| 1767 | if (pass > 0 && normalizeExistingThunk(rel, src)) | |
| 1470 | 1768 | continue; |
| 1471 | 1769 | |
| 1472 | if (!Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Src, | |
| 1473 | *Rel.Sym)) | |
| 1770 | if (!target->needsThunk(rel.expr, rel.type, isec->file, src, | |
| 1771 | *rel.sym)) | |
| 1474 | 1772 | continue; |
| 1475 | 1773 | |
| 1476 | Thunk *T; | |
| 1477 | bool IsNew; | |
| 1478 | std::tie(T, IsNew) = getThunk(*Rel.Sym, Rel.Type, Src); | |
| 1774 | Thunk *t; | |
| 1775 | bool isNew; | |
| 1776 | std::tie(t, isNew) = getThunk(isec, rel, src); | |
| 1479 | 1777 | |
| 1480 | if (IsNew) { | |
| 1778 | if (isNew) { | |
| 1481 | 1779 | // Find or create a ThunkSection for the new Thunk |
| 1482 | ThunkSection *TS; | |
| 1483 | if (auto *TIS = T->getTargetInputSection()) | |
| 1484 | TS = getISThunkSec(TIS); | |
| 1780 | ThunkSection *ts; | |
| 1781 | if (auto *tis = t->getTargetInputSection()) | |
| 1782 | ts = getISThunkSec(tis); | |
| 1485 | 1783 | else |
| 1486 | TS = getISDThunkSec(OS, IS, ISD, Rel.Type, Src); | |
| 1487 | TS->addThunk(T); | |
| 1488 | Thunks[T->getThunkTargetSym()] = T; | |
| 1784 | ts = getISDThunkSec(os, isec, isd, rel.type, src); | |
| 1785 | ts->addThunk(t); | |
| 1786 | thunks[t->getThunkTargetSym()] = t; | |
| 1489 | 1787 | } |
| 1490 | 1788 | |
| 1491 | 1789 | // Redirect relocation to Thunk, we never go via the PLT to a Thunk |
| 1492 | Rel.Sym = T->getThunkTargetSym(); | |
| 1493 | Rel.Expr = fromPlt(Rel.Expr); | |
| 1790 | rel.sym = t->getThunkTargetSym(); | |
| 1791 | rel.expr = fromPlt(rel.expr); | |
| 1792 | ||
| 1793 | // The addend of R_PPC_PLTREL24 should be ignored after changing to | |
| 1794 | // R_PC. | |
| 1795 | if (config->emachine == EM_PPC && rel.type == R_PPC_PLTREL24) | |
| 1796 | rel.addend = 0; | |
| 1494 | 1797 | } |
| 1495 | 1798 | |
| 1496 | for (auto &P : ISD->ThunkSections) | |
| 1497 | AddressesChanged |= P.first->assignOffsets(); | |
| 1799 | for (auto &p : isd->thunkSections) | |
| 1800 | addressesChanged |= p.first->assignOffsets(); | |
| 1498 | 1801 | }); |
| 1499 | 1802 | |
| 1500 | for (auto &P : ThunkedSections) | |
| 1501 | AddressesChanged |= P.second->assignOffsets(); | |
| 1803 | for (auto &p : thunkedSections) | |
| 1804 | addressesChanged |= p.second->assignOffsets(); | |
| 1502 | 1805 | |
| 1503 | 1806 | // Merge all created synthetic ThunkSections back into OutputSection |
| 1504 | mergeThunks(OutputSections); | |
| 1505 | ++Pass; | |
| 1506 | return AddressesChanged; | |
| 1807 | mergeThunks(outputSections); | |
| 1808 | ++pass; | |
| 1809 | return addressesChanged; | |
| 1507 | 1810 | } |
| 1508 | 1811 | |
| 1509 | 1812 | template void elf::scanRelocations<ELF32LE>(InputSectionBase &); |
| 1510 | 1813 | template void elf::scanRelocations<ELF32BE>(InputSectionBase &); |
| 1511 | 1814 | template void elf::scanRelocations<ELF64LE>(InputSectionBase &); |
| 1512 | 1815 | template void elf::scanRelocations<ELF64BE>(InputSectionBase &); |
| 1816 | template void elf::reportUndefinedSymbols<ELF32LE>(); | |
| 1817 | template void elf::reportUndefinedSymbols<ELF32BE>(); | |
| 1818 | template void elf::reportUndefinedSymbols<ELF64LE>(); | |
| 1819 | template void elf::reportUndefinedSymbols<ELF64BE>(); |
deps/lld/ELF/Relocations.h+71-107| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Relocations.h -------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -24,136 +23,100 @@ class OutputSection; |
| 24 | 23 | class SectionBase; |
| 25 | 24 | |
| 26 | 25 | // Represents a relocation type, such as R_X86_64_PC32 or R_ARM_THM_CALL. |
| 27 | typedef uint32_t RelType; | |
| 26 | using RelType = uint32_t; | |
| 28 | 27 | |
| 29 | 28 | // List of target-independent relocation types. Relocations read |
| 30 | 29 | // from files are converted to these types so that the main code |
| 31 | 30 | // doesn't have to know about architecture-specific details. |
| 32 | 31 | enum RelExpr { |
| 33 | R_INVALID, | |
| 34 | 32 | R_ABS, |
| 35 | 33 | R_ADDEND, |
| 36 | R_AARCH64_GOT_PAGE_PC, | |
| 37 | // The expression is used for IFUNC support. Describes PC-relative | |
| 38 | // address of the memory page of GOT entry. This entry is used for | |
| 39 | // a redirection to IPLT. | |
| 40 | R_AARCH64_GOT_PAGE_PC_PLT, | |
| 41 | R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC, | |
| 42 | R_AARCH64_PAGE_PC, | |
| 43 | R_AARCH64_PLT_PAGE_PC, | |
| 44 | R_AARCH64_TLSDESC_PAGE, | |
| 45 | R_ARM_SBREL, | |
| 34 | R_DTPREL, | |
| 46 | 35 | R_GOT, |
| 47 | // The expression is used for IFUNC support. Evaluates to GOT entry, | |
| 48 | // containing redirection to the IPLT. | |
| 49 | R_GOT_PLT, | |
| 50 | R_GOTONLY_PC, | |
| 51 | R_GOTONLY_PC_FROM_END, | |
| 52 | R_GOTREL, | |
| 53 | R_GOTREL_FROM_END, | |
| 54 | R_GOT_FROM_END, | |
| 55 | 36 | R_GOT_OFF, |
| 56 | 37 | R_GOT_PC, |
| 57 | R_HEXAGON_GOT, | |
| 38 | R_GOTONLY_PC, | |
| 39 | R_GOTPLTONLY_PC, | |
| 40 | R_GOTPLT, | |
| 41 | R_GOTPLTREL, | |
| 42 | R_GOTREL, | |
| 58 | 43 | R_HINT, |
| 59 | R_MIPS_GOTREL, | |
| 60 | R_MIPS_GOT_GP, | |
| 61 | R_MIPS_GOT_GP_PC, | |
| 62 | R_MIPS_GOT_LOCAL_PAGE, | |
| 63 | R_MIPS_GOT_OFF, | |
| 64 | R_MIPS_GOT_OFF32, | |
| 65 | R_MIPS_TLSGD, | |
| 66 | R_MIPS_TLSLD, | |
| 67 | 44 | R_NEG_TLS, |
| 68 | 45 | R_NONE, |
| 69 | 46 | R_PC, |
| 70 | 47 | R_PLT, |
| 71 | 48 | R_PLT_PC, |
| 72 | R_PPC_CALL, | |
| 73 | R_PPC_CALL_PLT, | |
| 74 | R_PPC_TOC, | |
| 75 | 49 | R_RELAX_GOT_PC, |
| 76 | 50 | R_RELAX_GOT_PC_NOPIC, |
| 77 | 51 | R_RELAX_TLS_GD_TO_IE, |
| 78 | 52 | R_RELAX_TLS_GD_TO_IE_ABS, |
| 79 | R_RELAX_TLS_GD_TO_IE_END, | |
| 80 | 53 | R_RELAX_TLS_GD_TO_IE_GOT_OFF, |
| 54 | R_RELAX_TLS_GD_TO_IE_GOTPLT, | |
| 81 | 55 | R_RELAX_TLS_GD_TO_LE, |
| 82 | 56 | R_RELAX_TLS_GD_TO_LE_NEG, |
| 83 | 57 | R_RELAX_TLS_IE_TO_LE, |
| 84 | 58 | R_RELAX_TLS_LD_TO_LE, |
| 85 | 59 | R_RELAX_TLS_LD_TO_LE_ABS, |
| 86 | R_RISCV_PC_INDIRECT, | |
| 87 | 60 | R_SIZE, |
| 88 | 61 | R_TLS, |
| 89 | 62 | R_TLSDESC, |
| 90 | 63 | R_TLSDESC_CALL, |
| 64 | R_TLSDESC_PC, | |
| 91 | 65 | R_TLSGD_GOT, |
| 92 | R_TLSGD_GOT_FROM_END, | |
| 66 | R_TLSGD_GOTPLT, | |
| 93 | 67 | R_TLSGD_PC, |
| 94 | 68 | R_TLSIE_HINT, |
| 95 | 69 | R_TLSLD_GOT, |
| 96 | R_TLSLD_GOT_FROM_END, | |
| 70 | R_TLSLD_GOTPLT, | |
| 97 | 71 | R_TLSLD_GOT_OFF, |
| 98 | 72 | R_TLSLD_HINT, |
| 99 | 73 | R_TLSLD_PC, |
| 100 | }; | |
| 101 | 74 | |
| 102 | // Build a bitmask with one bit set for each RelExpr. | |
| 103 | // | |
| 104 | // Constexpr function arguments can't be used in static asserts, so we | |
| 105 | // use template arguments to build the mask. | |
| 106 | // But function template partial specializations don't exist (needed | |
| 107 | // for base case of the recursion), so we need a dummy struct. | |
| 108 | template <RelExpr... Exprs> struct RelExprMaskBuilder { | |
| 109 | static inline uint64_t build() { return 0; } | |
| 110 | }; | |
| 111 | ||
| 112 | // Specialization for recursive case. | |
| 113 | template <RelExpr Head, RelExpr... Tail> | |
| 114 | struct RelExprMaskBuilder<Head, Tail...> { | |
| 115 | static inline uint64_t build() { | |
| 116 | static_assert(0 <= Head && Head < 64, | |
| 117 | "RelExpr is too large for 64-bit mask!"); | |
| 118 | return (uint64_t(1) << Head) | RelExprMaskBuilder<Tail...>::build(); | |
| 119 | } | |
| 75 | // The following is abstract relocation types used for only one target. | |
| 76 | // | |
| 77 | // Even though RelExpr is intended to be a target-neutral representation | |
| 78 | // of a relocation type, there are some relocations whose semantics are | |
| 79 | // unique to a target. Such relocation are marked with R_<TARGET_NAME>. | |
| 80 | R_AARCH64_GOT_PAGE_PC, | |
| 81 | R_AARCH64_PAGE_PC, | |
| 82 | R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC, | |
| 83 | R_AARCH64_TLSDESC_PAGE, | |
| 84 | R_ARM_SBREL, | |
| 85 | R_HEXAGON_GOT, | |
| 86 | R_MIPS_GOTREL, | |
| 87 | R_MIPS_GOT_GP, | |
| 88 | R_MIPS_GOT_GP_PC, | |
| 89 | R_MIPS_GOT_LOCAL_PAGE, | |
| 90 | R_MIPS_GOT_OFF, | |
| 91 | R_MIPS_GOT_OFF32, | |
| 92 | R_MIPS_TLSGD, | |
| 93 | R_MIPS_TLSLD, | |
| 94 | R_PPC32_PLTREL, | |
| 95 | R_PPC64_CALL, | |
| 96 | R_PPC64_CALL_PLT, | |
| 97 | R_PPC64_RELAX_TOC, | |
| 98 | R_PPC64_TOCBASE, | |
| 99 | R_RISCV_ADD, | |
| 100 | R_RISCV_PC_INDIRECT, | |
| 120 | 101 | }; |
| 121 | 102 | |
| 122 | // Return true if `Expr` is one of `Exprs`. | |
| 123 | // There are fewer than 64 RelExpr's, so we can represent any set of | |
| 124 | // RelExpr's as a constant bit mask and test for membership with a | |
| 125 | // couple cheap bitwise operations. | |
| 126 | template <RelExpr... Exprs> bool isRelExprOneOf(RelExpr Expr) { | |
| 127 | assert(0 <= Expr && (int)Expr < 64 && | |
| 128 | "RelExpr is too large for 64-bit mask!"); | |
| 129 | return (uint64_t(1) << Expr) & RelExprMaskBuilder<Exprs...>::build(); | |
| 130 | } | |
| 131 | ||
| 132 | 103 | // Architecture-neutral representation of relocation. |
| 133 | 104 | struct Relocation { |
| 134 | RelExpr Expr; | |
| 135 | RelType Type; | |
| 136 | uint64_t Offset; | |
| 137 | int64_t Addend; | |
| 138 | Symbol *Sym; | |
| 105 | RelExpr expr; | |
| 106 | RelType type; | |
| 107 | uint64_t offset; | |
| 108 | int64_t addend; | |
| 109 | Symbol *sym; | |
| 139 | 110 | }; |
| 140 | 111 | |
| 141 | struct RelocationOffsetComparator { | |
| 142 | bool operator()(const Relocation &Lhs, const Relocation &Rhs) { | |
| 143 | return Lhs.Offset < Rhs.Offset; | |
| 144 | } | |
| 112 | // This function writes undefined symbol diagnostics to an internal buffer. | |
| 113 | // Call reportUndefinedSymbols() after calling scanRelocations() to emit | |
| 114 | // the diagnostics. | |
| 115 | template <class ELFT> void scanRelocations(InputSectionBase &); | |
| 145 | 116 | |
| 146 | // For std::lower_bound, std::upper_bound, std::equal_range. | |
| 147 | bool operator()(const Relocation &Rel, uint64_t Val) { | |
| 148 | return Rel.Offset < Val; | |
| 149 | } | |
| 117 | template <class ELFT> void reportUndefinedSymbols(); | |
| 150 | 118 | |
| 151 | bool operator()(uint64_t Val, const Relocation &Rel) { | |
| 152 | return Val < Rel.Offset; | |
| 153 | } | |
| 154 | }; | |
| 155 | ||
| 156 | template <class ELFT> void scanRelocations(InputSectionBase &); | |
| 119 | void addIRelativeRelocs(); | |
| 157 | 120 | |
| 158 | 121 | class ThunkSection; |
| 159 | 122 | class Thunk; |
| ... | ... | @@ -162,56 +125,57 @@ struct InputSectionDescription; |
| 162 | 125 | class ThunkCreator { |
| 163 | 126 | public: |
| 164 | 127 | // Return true if Thunks have been added to OutputSections |
| 165 | bool createThunks(ArrayRef<OutputSection *> OutputSections); | |
| 128 | bool createThunks(ArrayRef<OutputSection *> outputSections); | |
| 166 | 129 | |
| 167 | 130 | // The number of completed passes of createThunks this permits us |
| 168 | 131 | // to do one time initialization on Pass 0 and put a limit on the |
| 169 | 132 | // number of times it can be called to prevent infinite loops. |
| 170 | uint32_t Pass = 0; | |
| 133 | uint32_t pass = 0; | |
| 171 | 134 | |
| 172 | 135 | private: |
| 173 | void mergeThunks(ArrayRef<OutputSection *> OutputSections); | |
| 136 | void mergeThunks(ArrayRef<OutputSection *> outputSections); | |
| 174 | 137 | |
| 175 | ThunkSection *getISDThunkSec(OutputSection *OS, InputSection *IS, | |
| 176 | InputSectionDescription *ISD, uint32_t Type, | |
| 177 | uint64_t Src); | |
| 138 | ThunkSection *getISDThunkSec(OutputSection *os, InputSection *isec, | |
| 139 | InputSectionDescription *isd, uint32_t type, | |
| 140 | uint64_t src); | |
| 178 | 141 | |
| 179 | ThunkSection *getISThunkSec(InputSection *IS); | |
| 142 | ThunkSection *getISThunkSec(InputSection *isec); | |
| 180 | 143 | |
| 181 | void createInitialThunkSections(ArrayRef<OutputSection *> OutputSections); | |
| 144 | void createInitialThunkSections(ArrayRef<OutputSection *> outputSections); | |
| 182 | 145 | |
| 183 | std::pair<Thunk *, bool> getThunk(Symbol &Sym, RelType Type, uint64_t Src); | |
| 146 | std::pair<Thunk *, bool> getThunk(InputSection *isec, Relocation &rel, | |
| 147 | uint64_t src); | |
| 184 | 148 | |
| 185 | ThunkSection *addThunkSection(OutputSection *OS, InputSectionDescription *, | |
| 186 | uint64_t Off); | |
| 149 | ThunkSection *addThunkSection(OutputSection *os, InputSectionDescription *, | |
| 150 | uint64_t off); | |
| 187 | 151 | |
| 188 | bool normalizeExistingThunk(Relocation &Rel, uint64_t Src); | |
| 152 | bool normalizeExistingThunk(Relocation &rel, uint64_t src); | |
| 189 | 153 | |
| 190 | 154 | // Record all the available Thunks for a Symbol |
| 191 | 155 | llvm::DenseMap<std::pair<SectionBase *, uint64_t>, std::vector<Thunk *>> |
| 192 | ThunkedSymbolsBySection; | |
| 193 | llvm::DenseMap<Symbol *, std::vector<Thunk *>> ThunkedSymbols; | |
| 156 | thunkedSymbolsBySection; | |
| 157 | llvm::DenseMap<Symbol *, std::vector<Thunk *>> thunkedSymbols; | |
| 194 | 158 | |
| 195 | 159 | // Find a Thunk from the Thunks symbol definition, we can use this to find |
| 196 | 160 | // the Thunk from a relocation to the Thunks symbol definition. |
| 197 | llvm::DenseMap<Symbol *, Thunk *> Thunks; | |
| 161 | llvm::DenseMap<Symbol *, Thunk *> thunks; | |
| 198 | 162 | |
| 199 | 163 | // Track InputSections that have an inline ThunkSection placed in front |
| 200 | 164 | // an inline ThunkSection may have control fall through to the section below |
| 201 | 165 | // so we need to make sure that there is only one of them. |
| 202 | 166 | // The Mips LA25 Thunk is an example of an inline ThunkSection. |
| 203 | llvm::DenseMap<InputSection *, ThunkSection *> ThunkedSections; | |
| 167 | llvm::DenseMap<InputSection *, ThunkSection *> thunkedSections; | |
| 204 | 168 | }; |
| 205 | 169 | |
| 206 | 170 | // Return a int64_t to make sure we get the sign extension out of the way as |
| 207 | 171 | // early as possible. |
| 208 | 172 | template <class ELFT> |
| 209 | static inline int64_t getAddend(const typename ELFT::Rel &Rel) { | |
| 173 | static inline int64_t getAddend(const typename ELFT::Rel &rel) { | |
| 210 | 174 | return 0; |
| 211 | 175 | } |
| 212 | 176 | template <class ELFT> |
| 213 | static inline int64_t getAddend(const typename ELFT::Rela &Rel) { | |
| 214 | return Rel.r_addend; | |
| 177 | static inline int64_t getAddend(const typename ELFT::Rela &rel) { | |
| 178 | return rel.r_addend; | |
| 215 | 179 | } |
| 216 | 180 | } // namespace elf |
| 217 | 181 | } // namespace lld |
deps/lld/ELF/ScriptLexer.cpp+113-111| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- ScriptLexer.cpp ----------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -42,166 +41,169 @@ using namespace lld::elf; |
| 42 | 41 | |
| 43 | 42 | // Returns a whole line containing the current token. |
| 44 | 43 | StringRef ScriptLexer::getLine() { |
| 45 | StringRef S = getCurrentMB().getBuffer(); | |
| 46 | StringRef Tok = Tokens[Pos - 1]; | |
| 44 | StringRef s = getCurrentMB().getBuffer(); | |
| 45 | StringRef tok = tokens[pos - 1]; | |
| 47 | 46 | |
| 48 | size_t Pos = S.rfind('\n', Tok.data() - S.data()); | |
| 49 | if (Pos != StringRef::npos) | |
| 50 | S = S.substr(Pos + 1); | |
| 51 | return S.substr(0, S.find_first_of("\r\n")); | |
| 47 | size_t pos = s.rfind('\n', tok.data() - s.data()); | |
| 48 | if (pos != StringRef::npos) | |
| 49 | s = s.substr(pos + 1); | |
| 50 | return s.substr(0, s.find_first_of("\r\n")); | |
| 52 | 51 | } |
| 53 | 52 | |
| 54 | 53 | // Returns 1-based line number of the current token. |
| 55 | 54 | size_t ScriptLexer::getLineNumber() { |
| 56 | StringRef S = getCurrentMB().getBuffer(); | |
| 57 | StringRef Tok = Tokens[Pos - 1]; | |
| 58 | return S.substr(0, Tok.data() - S.data()).count('\n') + 1; | |
| 55 | StringRef s = getCurrentMB().getBuffer(); | |
| 56 | StringRef tok = tokens[pos - 1]; | |
| 57 | return s.substr(0, tok.data() - s.data()).count('\n') + 1; | |
| 59 | 58 | } |
| 60 | 59 | |
| 61 | 60 | // Returns 0-based column number of the current token. |
| 62 | 61 | size_t ScriptLexer::getColumnNumber() { |
| 63 | StringRef Tok = Tokens[Pos - 1]; | |
| 64 | return Tok.data() - getLine().data(); | |
| 62 | StringRef tok = tokens[pos - 1]; | |
| 63 | return tok.data() - getLine().data(); | |
| 65 | 64 | } |
| 66 | 65 | |
| 67 | 66 | std::string ScriptLexer::getCurrentLocation() { |
| 68 | std::string Filename = getCurrentMB().getBufferIdentifier(); | |
| 69 | return (Filename + ":" + Twine(getLineNumber())).str(); | |
| 67 | std::string filename = getCurrentMB().getBufferIdentifier(); | |
| 68 | return (filename + ":" + Twine(getLineNumber())).str(); | |
| 70 | 69 | } |
| 71 | 70 | |
| 72 | ScriptLexer::ScriptLexer(MemoryBufferRef MB) { tokenize(MB); } | |
| 71 | ScriptLexer::ScriptLexer(MemoryBufferRef mb) { tokenize(mb); } | |
| 73 | 72 | |
| 74 | 73 | // We don't want to record cascading errors. Keep only the first one. |
| 75 | void ScriptLexer::setError(const Twine &Msg) { | |
| 74 | void ScriptLexer::setError(const Twine &msg) { | |
| 76 | 75 | if (errorCount()) |
| 77 | 76 | return; |
| 78 | 77 | |
| 79 | std::string S = (getCurrentLocation() + ": " + Msg).str(); | |
| 80 | if (Pos) | |
| 81 | S += "\n>>> " + getLine().str() + "\n>>> " + | |
| 78 | std::string s = (getCurrentLocation() + ": " + msg).str(); | |
| 79 | if (pos) | |
| 80 | s += "\n>>> " + getLine().str() + "\n>>> " + | |
| 82 | 81 | std::string(getColumnNumber(), ' ') + "^"; |
| 83 | error(S); | |
| 82 | error(s); | |
| 84 | 83 | } |
| 85 | 84 | |
| 86 | 85 | // Split S into linker script tokens. |
| 87 | void ScriptLexer::tokenize(MemoryBufferRef MB) { | |
| 88 | std::vector<StringRef> Vec; | |
| 89 | MBs.push_back(MB); | |
| 90 | StringRef S = MB.getBuffer(); | |
| 91 | StringRef Begin = S; | |
| 86 | void ScriptLexer::tokenize(MemoryBufferRef mb) { | |
| 87 | std::vector<StringRef> vec; | |
| 88 | mbs.push_back(mb); | |
| 89 | StringRef s = mb.getBuffer(); | |
| 90 | StringRef begin = s; | |
| 92 | 91 | |
| 93 | 92 | for (;;) { |
| 94 | S = skipSpace(S); | |
| 95 | if (S.empty()) | |
| 93 | s = skipSpace(s); | |
| 94 | if (s.empty()) | |
| 96 | 95 | break; |
| 97 | 96 | |
| 98 | 97 | // Quoted token. Note that double-quote characters are parts of a token |
| 99 | 98 | // because, in a glob match context, only unquoted tokens are interpreted |
| 100 | 99 | // as glob patterns. Double-quoted tokens are literal patterns in that |
| 101 | 100 | // context. |
| 102 | if (S.startswith("\"")) { | |
| 103 | size_t E = S.find("\"", 1); | |
| 104 | if (E == StringRef::npos) { | |
| 105 | StringRef Filename = MB.getBufferIdentifier(); | |
| 106 | size_t Lineno = Begin.substr(0, S.data() - Begin.data()).count('\n'); | |
| 107 | error(Filename + ":" + Twine(Lineno + 1) + ": unclosed quote"); | |
| 101 | if (s.startswith("\"")) { | |
| 102 | size_t e = s.find("\"", 1); | |
| 103 | if (e == StringRef::npos) { | |
| 104 | StringRef filename = mb.getBufferIdentifier(); | |
| 105 | size_t lineno = begin.substr(0, s.data() - begin.data()).count('\n'); | |
| 106 | error(filename + ":" + Twine(lineno + 1) + ": unclosed quote"); | |
| 108 | 107 | return; |
| 109 | 108 | } |
| 110 | 109 | |
| 111 | Vec.push_back(S.take_front(E + 1)); | |
| 112 | S = S.substr(E + 1); | |
| 110 | vec.push_back(s.take_front(e + 1)); | |
| 111 | s = s.substr(e + 1); | |
| 113 | 112 | continue; |
| 114 | 113 | } |
| 115 | 114 | |
| 116 | 115 | // ">foo" is parsed to ">" and "foo", but ">>" is parsed to ">>". |
| 117 | 116 | // "|", "||", "&" and "&&" are different operators. |
| 118 | if (S.startswith("<<") || S.startswith("<=") || S.startswith(">>") || | |
| 119 | S.startswith(">=") || S.startswith("||") || S.startswith("&&")) { | |
| 120 | Vec.push_back(S.substr(0, 2)); | |
| 121 | S = S.substr(2); | |
| 117 | if (s.startswith("<<") || s.startswith("<=") || s.startswith(">>") || | |
| 118 | s.startswith(">=") || s.startswith("||") || s.startswith("&&")) { | |
| 119 | vec.push_back(s.substr(0, 2)); | |
| 120 | s = s.substr(2); | |
| 122 | 121 | continue; |
| 123 | 122 | } |
| 124 | 123 | |
| 125 | 124 | // Unquoted token. This is more relaxed than tokens in C-like language, |
| 126 | 125 | // so that you can write "file-name.cpp" as one bare token, for example. |
| 127 | size_t Pos = S.find_first_not_of( | |
| 126 | size_t pos = s.find_first_not_of( | |
| 128 | 127 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" |
| 129 | 128 | "0123456789_.$/\\~=+[]*?-!^:"); |
| 130 | 129 | |
| 131 | 130 | // A character that cannot start a word (which is usually a |
| 132 | 131 | // punctuation) forms a single character token. |
| 133 | if (Pos == 0) | |
| 134 | Pos = 1; | |
| 135 | Vec.push_back(S.substr(0, Pos)); | |
| 136 | S = S.substr(Pos); | |
| 132 | if (pos == 0) | |
| 133 | pos = 1; | |
| 134 | vec.push_back(s.substr(0, pos)); | |
| 135 | s = s.substr(pos); | |
| 137 | 136 | } |
| 138 | 137 | |
| 139 | Tokens.insert(Tokens.begin() + Pos, Vec.begin(), Vec.end()); | |
| 138 | tokens.insert(tokens.begin() + pos, vec.begin(), vec.end()); | |
| 140 | 139 | } |
| 141 | 140 | |
| 142 | 141 | // Skip leading whitespace characters or comments. |
| 143 | StringRef ScriptLexer::skipSpace(StringRef S) { | |
| 142 | StringRef ScriptLexer::skipSpace(StringRef s) { | |
| 144 | 143 | for (;;) { |
| 145 | if (S.startswith("/*")) { | |
| 146 | size_t E = S.find("*/", 2); | |
| 147 | if (E == StringRef::npos) { | |
| 144 | if (s.startswith("/*")) { | |
| 145 | size_t e = s.find("*/", 2); | |
| 146 | if (e == StringRef::npos) { | |
| 148 | 147 | error("unclosed comment in a linker script"); |
| 149 | 148 | return ""; |
| 150 | 149 | } |
| 151 | S = S.substr(E + 2); | |
| 150 | s = s.substr(e + 2); | |
| 152 | 151 | continue; |
| 153 | 152 | } |
| 154 | if (S.startswith("#")) { | |
| 155 | size_t E = S.find('\n', 1); | |
| 156 | if (E == StringRef::npos) | |
| 157 | E = S.size() - 1; | |
| 158 | S = S.substr(E + 1); | |
| 153 | if (s.startswith("#")) { | |
| 154 | size_t e = s.find('\n', 1); | |
| 155 | if (e == StringRef::npos) | |
| 156 | e = s.size() - 1; | |
| 157 | s = s.substr(e + 1); | |
| 159 | 158 | continue; |
| 160 | 159 | } |
| 161 | size_t Size = S.size(); | |
| 162 | S = S.ltrim(); | |
| 163 | if (S.size() == Size) | |
| 164 | return S; | |
| 160 | size_t size = s.size(); | |
| 161 | s = s.ltrim(); | |
| 162 | if (s.size() == size) | |
| 163 | return s; | |
| 165 | 164 | } |
| 166 | 165 | } |
| 167 | 166 | |
| 168 | 167 | // An erroneous token is handled as if it were the last token before EOF. |
| 169 | bool ScriptLexer::atEOF() { return errorCount() || Tokens.size() == Pos; } | |
| 168 | bool ScriptLexer::atEOF() { return errorCount() || tokens.size() == pos; } | |
| 170 | 169 | |
| 171 | 170 | // Split a given string as an expression. |
| 172 | 171 | // This function returns "3", "*" and "5" for "3*5" for example. |
| 173 | static std::vector<StringRef> tokenizeExpr(StringRef S) { | |
| 174 | StringRef Ops = "+-*/:!~"; // List of operators | |
| 172 | static std::vector<StringRef> tokenizeExpr(StringRef s) { | |
| 173 | StringRef ops = "+-*/:!~=<>"; // List of operators | |
| 175 | 174 | |
| 176 | 175 | // Quoted strings are literal strings, so we don't want to split it. |
| 177 | if (S.startswith("\"")) | |
| 178 | return {S}; | |
| 176 | if (s.startswith("\"")) | |
| 177 | return {s}; | |
| 179 | 178 | |
| 180 | 179 | // Split S with operators as separators. |
| 181 | std::vector<StringRef> Ret; | |
| 182 | while (!S.empty()) { | |
| 183 | size_t E = S.find_first_of(Ops); | |
| 180 | std::vector<StringRef> ret; | |
| 181 | while (!s.empty()) { | |
| 182 | size_t e = s.find_first_of(ops); | |
| 184 | 183 | |
| 185 | 184 | // No need to split if there is no operator. |
| 186 | if (E == StringRef::npos) { | |
| 187 | Ret.push_back(S); | |
| 185 | if (e == StringRef::npos) { | |
| 186 | ret.push_back(s); | |
| 188 | 187 | break; |
| 189 | 188 | } |
| 190 | 189 | |
| 191 | 190 | // Get a token before the opreator. |
| 192 | if (E != 0) | |
| 193 | Ret.push_back(S.substr(0, E)); | |
| 194 | ||
| 195 | // Get the operator as a token. Keep != as one token. | |
| 196 | if (S.substr(E).startswith("!=")) { | |
| 197 | Ret.push_back(S.substr(E, 2)); | |
| 198 | S = S.substr(E + 2); | |
| 191 | if (e != 0) | |
| 192 | ret.push_back(s.substr(0, e)); | |
| 193 | ||
| 194 | // Get the operator as a token. | |
| 195 | // Keep !=, ==, >=, <=, << and >> operators as a single tokens. | |
| 196 | if (s.substr(e).startswith("!=") || s.substr(e).startswith("==") || | |
| 197 | s.substr(e).startswith(">=") || s.substr(e).startswith("<=") || | |
| 198 | s.substr(e).startswith("<<") || s.substr(e).startswith(">>")) { | |
| 199 | ret.push_back(s.substr(e, 2)); | |
| 200 | s = s.substr(e + 2); | |
| 199 | 201 | } else { |
| 200 | Ret.push_back(S.substr(E, 1)); | |
| 201 | S = S.substr(E + 1); | |
| 202 | ret.push_back(s.substr(e, 1)); | |
| 203 | s = s.substr(e + 1); | |
| 202 | 204 | } |
| 203 | 205 | } |
| 204 | return Ret; | |
| 206 | return ret; | |
| 205 | 207 | } |
| 206 | 208 | |
| 207 | 209 | // In contexts where expressions are expected, the lexer should apply |
| ... | ... | @@ -214,14 +216,14 @@ static std::vector<StringRef> tokenizeExpr(StringRef S) { |
| 214 | 216 | // |
| 215 | 217 | // This function may split the current token into multiple tokens. |
| 216 | 218 | void ScriptLexer::maybeSplitExpr() { |
| 217 | if (!InExpr || errorCount() || atEOF()) | |
| 219 | if (!inExpr || errorCount() || atEOF()) | |
| 218 | 220 | return; |
| 219 | 221 | |
| 220 | std::vector<StringRef> V = tokenizeExpr(Tokens[Pos]); | |
| 221 | if (V.size() == 1) | |
| 222 | std::vector<StringRef> v = tokenizeExpr(tokens[pos]); | |
| 223 | if (v.size() == 1) | |
| 222 | 224 | return; |
| 223 | Tokens.erase(Tokens.begin() + Pos); | |
| 224 | Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end()); | |
| 225 | tokens.erase(tokens.begin() + pos); | |
| 226 | tokens.insert(tokens.begin() + pos, v.begin(), v.end()); | |
| 225 | 227 | } |
| 226 | 228 | |
| 227 | 229 | StringRef ScriptLexer::next() { |
| ... | ... | @@ -233,28 +235,28 @@ StringRef ScriptLexer::next() { |
| 233 | 235 | setError("unexpected EOF"); |
| 234 | 236 | return ""; |
| 235 | 237 | } |
| 236 | return Tokens[Pos++]; | |
| 238 | return tokens[pos++]; | |
| 237 | 239 | } |
| 238 | 240 | |
| 239 | 241 | StringRef ScriptLexer::peek() { |
| 240 | StringRef Tok = next(); | |
| 242 | StringRef tok = next(); | |
| 241 | 243 | if (errorCount()) |
| 242 | 244 | return ""; |
| 243 | Pos = Pos - 1; | |
| 244 | return Tok; | |
| 245 | pos = pos - 1; | |
| 246 | return tok; | |
| 245 | 247 | } |
| 246 | 248 | |
| 247 | 249 | StringRef ScriptLexer::peek2() { |
| 248 | 250 | skip(); |
| 249 | StringRef Tok = next(); | |
| 251 | StringRef tok = next(); | |
| 250 | 252 | if (errorCount()) |
| 251 | 253 | return ""; |
| 252 | Pos = Pos - 2; | |
| 253 | return Tok; | |
| 254 | pos = pos - 2; | |
| 255 | return tok; | |
| 254 | 256 | } |
| 255 | 257 | |
| 256 | bool ScriptLexer::consume(StringRef Tok) { | |
| 257 | if (peek() == Tok) { | |
| 258 | bool ScriptLexer::consume(StringRef tok) { | |
| 259 | if (peek() == tok) { | |
| 258 | 260 | skip(); |
| 259 | 261 | return true; |
| 260 | 262 | } |
| ... | ... | @@ -262,12 +264,12 @@ bool ScriptLexer::consume(StringRef Tok) { |
| 262 | 264 | } |
| 263 | 265 | |
| 264 | 266 | // Consumes Tok followed by ":". Space is allowed between Tok and ":". |
| 265 | bool ScriptLexer::consumeLabel(StringRef Tok) { | |
| 266 | if (consume((Tok + ":").str())) | |
| 267 | bool ScriptLexer::consumeLabel(StringRef tok) { | |
| 268 | if (consume((tok + ":").str())) | |
| 267 | 269 | return true; |
| 268 | if (Tokens.size() >= Pos + 2 && Tokens[Pos] == Tok && | |
| 269 | Tokens[Pos + 1] == ":") { | |
| 270 | Pos += 2; | |
| 270 | if (tokens.size() >= pos + 2 && tokens[pos] == tok && | |
| 271 | tokens[pos + 1] == ":") { | |
| 272 | pos += 2; | |
| 271 | 273 | return true; |
| 272 | 274 | } |
| 273 | 275 | return false; |
| ... | ... | @@ -275,24 +277,24 @@ bool ScriptLexer::consumeLabel(StringRef Tok) { |
| 275 | 277 | |
| 276 | 278 | void ScriptLexer::skip() { (void)next(); } |
| 277 | 279 | |
| 278 | void ScriptLexer::expect(StringRef Expect) { | |
| 280 | void ScriptLexer::expect(StringRef expect) { | |
| 279 | 281 | if (errorCount()) |
| 280 | 282 | return; |
| 281 | StringRef Tok = next(); | |
| 282 | if (Tok != Expect) | |
| 283 | setError(Expect + " expected, but got " + Tok); | |
| 283 | StringRef tok = next(); | |
| 284 | if (tok != expect) | |
| 285 | setError(expect + " expected, but got " + tok); | |
| 284 | 286 | } |
| 285 | 287 | |
| 286 | 288 | // Returns true if S encloses T. |
| 287 | static bool encloses(StringRef S, StringRef T) { | |
| 288 | return S.bytes_begin() <= T.bytes_begin() && T.bytes_end() <= S.bytes_end(); | |
| 289 | static bool encloses(StringRef s, StringRef t) { | |
| 290 | return s.bytes_begin() <= t.bytes_begin() && t.bytes_end() <= s.bytes_end(); | |
| 289 | 291 | } |
| 290 | 292 | |
| 291 | 293 | MemoryBufferRef ScriptLexer::getCurrentMB() { |
| 292 | 294 | // Find input buffer containing the current token. |
| 293 | assert(!MBs.empty() && Pos > 0); | |
| 294 | for (MemoryBufferRef MB : MBs) | |
| 295 | if (encloses(MB.getBuffer(), Tokens[Pos - 1])) | |
| 296 | return MB; | |
| 295 | assert(!mbs.empty() && pos > 0); | |
| 296 | for (MemoryBufferRef mb : mbs) | |
| 297 | if (encloses(mb.getBuffer(), tokens[pos - 1])) | |
| 298 | return mb; | |
| 297 | 299 | llvm_unreachable("getCurrentMB: failed to find a token"); |
| 298 | 300 | } |
deps/lld/ELF/ScriptLexer.h+14-15| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- ScriptLexer.h --------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -21,25 +20,25 @@ namespace elf { |
| 21 | 20 | |
| 22 | 21 | class ScriptLexer { |
| 23 | 22 | public: |
| 24 | explicit ScriptLexer(MemoryBufferRef MB); | |
| 23 | explicit ScriptLexer(MemoryBufferRef mb); | |
| 25 | 24 | |
| 26 | void setError(const Twine &Msg); | |
| 27 | void tokenize(MemoryBufferRef MB); | |
| 28 | static StringRef skipSpace(StringRef S); | |
| 25 | void setError(const Twine &msg); | |
| 26 | void tokenize(MemoryBufferRef mb); | |
| 27 | static StringRef skipSpace(StringRef s); | |
| 29 | 28 | bool atEOF(); |
| 30 | 29 | StringRef next(); |
| 31 | 30 | StringRef peek(); |
| 32 | 31 | StringRef peek2(); |
| 33 | 32 | void skip(); |
| 34 | bool consume(StringRef Tok); | |
| 35 | void expect(StringRef Expect); | |
| 36 | bool consumeLabel(StringRef Tok); | |
| 33 | bool consume(StringRef tok); | |
| 34 | void expect(StringRef expect); | |
| 35 | bool consumeLabel(StringRef tok); | |
| 37 | 36 | std::string getCurrentLocation(); |
| 38 | 37 | |
| 39 | std::vector<MemoryBufferRef> MBs; | |
| 40 | std::vector<StringRef> Tokens; | |
| 41 | bool InExpr = false; | |
| 42 | size_t Pos = 0; | |
| 38 | std::vector<MemoryBufferRef> mbs; | |
| 39 | std::vector<StringRef> tokens; | |
| 40 | bool inExpr = false; | |
| 41 | size_t pos = 0; | |
| 43 | 42 | |
| 44 | 43 | private: |
| 45 | 44 | void maybeSplitExpr(); |
deps/lld/ELF/ScriptParser.cpp+633-636| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- ScriptParser.cpp ---------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -41,22 +40,29 @@ using namespace llvm::support::endian; |
| 41 | 40 | using namespace lld; |
| 42 | 41 | using namespace lld::elf; |
| 43 | 42 | |
| 44 | static bool isUnderSysroot(StringRef Path); | |
| 45 | ||
| 46 | 43 | namespace { |
| 47 | 44 | class ScriptParser final : ScriptLexer { |
| 48 | 45 | public: |
| 49 | ScriptParser(MemoryBufferRef MB) | |
| 50 | : ScriptLexer(MB), | |
| 51 | IsUnderSysroot(isUnderSysroot(MB.getBufferIdentifier())) {} | |
| 46 | ScriptParser(MemoryBufferRef mb) : ScriptLexer(mb) { | |
| 47 | // Initialize IsUnderSysroot | |
| 48 | if (config->sysroot == "") | |
| 49 | return; | |
| 50 | StringRef path = mb.getBufferIdentifier(); | |
| 51 | for (; !path.empty(); path = sys::path::parent_path(path)) { | |
| 52 | if (!sys::fs::equivalent(config->sysroot, path)) | |
| 53 | continue; | |
| 54 | isUnderSysroot = true; | |
| 55 | return; | |
| 56 | } | |
| 57 | } | |
| 52 | 58 | |
| 53 | 59 | void readLinkerScript(); |
| 54 | 60 | void readVersionScript(); |
| 55 | 61 | void readDynamicList(); |
| 56 | void readDefsym(StringRef Name); | |
| 62 | void readDefsym(StringRef name); | |
| 57 | 63 | |
| 58 | 64 | private: |
| 59 | void addFile(StringRef Path); | |
| 65 | void addFile(StringRef path); | |
| 60 | 66 | |
| 61 | 67 | void readAsNeeded(); |
| 62 | 68 | void readEntry(); |
| ... | ... | @@ -76,24 +82,23 @@ private: |
| 76 | 82 | void readVersion(); |
| 77 | 83 | void readVersionScriptCommand(); |
| 78 | 84 | |
| 79 | SymbolAssignment *readSymbolAssignment(StringRef Name); | |
| 80 | ByteCommand *readByteCommand(StringRef Tok); | |
| 85 | SymbolAssignment *readSymbolAssignment(StringRef name); | |
| 86 | ByteCommand *readByteCommand(StringRef tok); | |
| 81 | 87 | std::array<uint8_t, 4> readFill(); |
| 82 | std::array<uint8_t, 4> parseFill(StringRef Tok); | |
| 83 | bool readSectionDirective(OutputSection *Cmd, StringRef Tok1, StringRef Tok2); | |
| 84 | void readSectionAddressType(OutputSection *Cmd); | |
| 88 | bool readSectionDirective(OutputSection *cmd, StringRef tok1, StringRef tok2); | |
| 89 | void readSectionAddressType(OutputSection *cmd); | |
| 85 | 90 | OutputSection *readOverlaySectionDescription(); |
| 86 | OutputSection *readOutputSectionDescription(StringRef OutSec); | |
| 91 | OutputSection *readOutputSectionDescription(StringRef outSec); | |
| 87 | 92 | std::vector<BaseCommand *> readOverlay(); |
| 88 | 93 | std::vector<StringRef> readOutputSectionPhdrs(); |
| 89 | InputSectionDescription *readInputSectionDescription(StringRef Tok); | |
| 94 | InputSectionDescription *readInputSectionDescription(StringRef tok); | |
| 90 | 95 | StringMatcher readFilePatterns(); |
| 91 | 96 | std::vector<SectionPattern> readInputSectionsList(); |
| 92 | InputSectionDescription *readInputSectionRules(StringRef FilePattern); | |
| 97 | InputSectionDescription *readInputSectionRules(StringRef filePattern); | |
| 93 | 98 | unsigned readPhdrType(); |
| 94 | 99 | SortSectionPolicy readSortKind(); |
| 95 | SymbolAssignment *readProvideHidden(bool Provide, bool Hidden); | |
| 96 | SymbolAssignment *readAssignment(StringRef Tok); | |
| 100 | SymbolAssignment *readProvideHidden(bool provide, bool hidden); | |
| 101 | SymbolAssignment *readAssignment(StringRef tok); | |
| 97 | 102 | void readSort(); |
| 98 | 103 | Expr readAssert(); |
| 99 | 104 | Expr readConstant(); |
| ... | ... | @@ -102,97 +107,88 @@ private: |
| 102 | 107 | uint64_t readMemoryAssignment(StringRef, StringRef, StringRef); |
| 103 | 108 | std::pair<uint32_t, uint32_t> readMemoryAttributes(); |
| 104 | 109 | |
| 105 | Expr combine(StringRef Op, Expr L, Expr R); | |
| 110 | Expr combine(StringRef op, Expr l, Expr r); | |
| 106 | 111 | Expr readExpr(); |
| 107 | Expr readExpr1(Expr Lhs, int MinPrec); | |
| 112 | Expr readExpr1(Expr lhs, int minPrec); | |
| 108 | 113 | StringRef readParenLiteral(); |
| 109 | 114 | Expr readPrimary(); |
| 110 | Expr readTernary(Expr Cond); | |
| 115 | Expr readTernary(Expr cond); | |
| 111 | 116 | Expr readParenExpr(); |
| 112 | 117 | |
| 113 | 118 | // For parsing version script. |
| 114 | 119 | std::vector<SymbolVersion> readVersionExtern(); |
| 115 | 120 | void readAnonymousDeclaration(); |
| 116 | void readVersionDeclaration(StringRef VerStr); | |
| 121 | void readVersionDeclaration(StringRef verStr); | |
| 117 | 122 | |
| 118 | 123 | std::pair<std::vector<SymbolVersion>, std::vector<SymbolVersion>> |
| 119 | 124 | readSymbols(); |
| 120 | 125 | |
| 121 | 126 | // True if a script being read is in a subdirectory specified by -sysroot. |
| 122 | bool IsUnderSysroot; | |
| 127 | bool isUnderSysroot = false; | |
| 123 | 128 | |
| 124 | 129 | // A set to detect an INCLUDE() cycle. |
| 125 | StringSet<> Seen; | |
| 130 | StringSet<> seen; | |
| 126 | 131 | }; |
| 127 | 132 | } // namespace |
| 128 | 133 | |
| 129 | static StringRef unquote(StringRef S) { | |
| 130 | if (S.startswith("\"")) | |
| 131 | return S.substr(1, S.size() - 2); | |
| 132 | return S; | |
| 133 | } | |
| 134 | ||
| 135 | static bool isUnderSysroot(StringRef Path) { | |
| 136 | if (Config->Sysroot == "") | |
| 137 | return false; | |
| 138 | for (; !Path.empty(); Path = sys::path::parent_path(Path)) | |
| 139 | if (sys::fs::equivalent(Config->Sysroot, Path)) | |
| 140 | return true; | |
| 141 | return false; | |
| 134 | static StringRef unquote(StringRef s) { | |
| 135 | if (s.startswith("\"")) | |
| 136 | return s.substr(1, s.size() - 2); | |
| 137 | return s; | |
| 142 | 138 | } |
| 143 | 139 | |
| 144 | 140 | // Some operations only support one non absolute value. Move the |
| 145 | 141 | // absolute one to the right hand side for convenience. |
| 146 | static void moveAbsRight(ExprValue &A, ExprValue &B) { | |
| 147 | if (A.Sec == nullptr || (A.ForceAbsolute && !B.isAbsolute())) | |
| 148 | std::swap(A, B); | |
| 149 | if (!B.isAbsolute()) | |
| 150 | error(A.Loc + ": at least one side of the expression must be absolute"); | |
| 142 | static void moveAbsRight(ExprValue &a, ExprValue &b) { | |
| 143 | if (a.sec == nullptr || (a.forceAbsolute && !b.isAbsolute())) | |
| 144 | std::swap(a, b); | |
| 145 | if (!b.isAbsolute()) | |
| 146 | error(a.loc + ": at least one side of the expression must be absolute"); | |
| 151 | 147 | } |
| 152 | 148 | |
| 153 | static ExprValue add(ExprValue A, ExprValue B) { | |
| 154 | moveAbsRight(A, B); | |
| 155 | return {A.Sec, A.ForceAbsolute, A.getSectionOffset() + B.getValue(), A.Loc}; | |
| 149 | static ExprValue add(ExprValue a, ExprValue b) { | |
| 150 | moveAbsRight(a, b); | |
| 151 | return {a.sec, a.forceAbsolute, a.getSectionOffset() + b.getValue(), a.loc}; | |
| 156 | 152 | } |
| 157 | 153 | |
| 158 | static ExprValue sub(ExprValue A, ExprValue B) { | |
| 154 | static ExprValue sub(ExprValue a, ExprValue b) { | |
| 159 | 155 | // The distance between two symbols in sections is absolute. |
| 160 | if (!A.isAbsolute() && !B.isAbsolute()) | |
| 161 | return A.getValue() - B.getValue(); | |
| 162 | return {A.Sec, false, A.getSectionOffset() - B.getValue(), A.Loc}; | |
| 156 | if (!a.isAbsolute() && !b.isAbsolute()) | |
| 157 | return a.getValue() - b.getValue(); | |
| 158 | return {a.sec, false, a.getSectionOffset() - b.getValue(), a.loc}; | |
| 163 | 159 | } |
| 164 | 160 | |
| 165 | static ExprValue bitAnd(ExprValue A, ExprValue B) { | |
| 166 | moveAbsRight(A, B); | |
| 167 | return {A.Sec, A.ForceAbsolute, | |
| 168 | (A.getValue() & B.getValue()) - A.getSecAddr(), A.Loc}; | |
| 161 | static ExprValue bitAnd(ExprValue a, ExprValue b) { | |
| 162 | moveAbsRight(a, b); | |
| 163 | return {a.sec, a.forceAbsolute, | |
| 164 | (a.getValue() & b.getValue()) - a.getSecAddr(), a.loc}; | |
| 169 | 165 | } |
| 170 | 166 | |
| 171 | static ExprValue bitOr(ExprValue A, ExprValue B) { | |
| 172 | moveAbsRight(A, B); | |
| 173 | return {A.Sec, A.ForceAbsolute, | |
| 174 | (A.getValue() | B.getValue()) - A.getSecAddr(), A.Loc}; | |
| 167 | static ExprValue bitOr(ExprValue a, ExprValue b) { | |
| 168 | moveAbsRight(a, b); | |
| 169 | return {a.sec, a.forceAbsolute, | |
| 170 | (a.getValue() | b.getValue()) - a.getSecAddr(), a.loc}; | |
| 175 | 171 | } |
| 176 | 172 | |
| 177 | 173 | void ScriptParser::readDynamicList() { |
| 178 | Config->HasDynamicList = true; | |
| 174 | config->hasDynamicList = true; | |
| 179 | 175 | expect("{"); |
| 180 | std::vector<SymbolVersion> Locals; | |
| 181 | std::vector<SymbolVersion> Globals; | |
| 182 | std::tie(Locals, Globals) = readSymbols(); | |
| 176 | std::vector<SymbolVersion> locals; | |
| 177 | std::vector<SymbolVersion> globals; | |
| 178 | std::tie(locals, globals) = readSymbols(); | |
| 183 | 179 | expect(";"); |
| 184 | 180 | |
| 185 | 181 | if (!atEOF()) { |
| 186 | 182 | setError("EOF expected, but got " + next()); |
| 187 | 183 | return; |
| 188 | 184 | } |
| 189 | if (!Locals.empty()) { | |
| 185 | if (!locals.empty()) { | |
| 190 | 186 | setError("\"local:\" scope not supported in --dynamic-list"); |
| 191 | 187 | return; |
| 192 | 188 | } |
| 193 | 189 | |
| 194 | for (SymbolVersion V : Globals) | |
| 195 | Config->DynamicList.push_back(V); | |
| 190 | for (SymbolVersion v : globals) | |
| 191 | config->dynamicList.push_back(v); | |
| 196 | 192 | } |
| 197 | 193 | |
| 198 | 194 | void ScriptParser::readVersionScript() { |
| ... | ... | @@ -208,14 +204,14 @@ void ScriptParser::readVersionScriptCommand() { |
| 208 | 204 | } |
| 209 | 205 | |
| 210 | 206 | while (!atEOF() && !errorCount() && peek() != "}") { |
| 211 | StringRef VerStr = next(); | |
| 212 | if (VerStr == "{") { | |
| 207 | StringRef verStr = next(); | |
| 208 | if (verStr == "{") { | |
| 213 | 209 | setError("anonymous version definition is used in " |
| 214 | 210 | "combination with other version definitions"); |
| 215 | 211 | return; |
| 216 | 212 | } |
| 217 | 213 | expect("{"); |
| 218 | readVersionDeclaration(VerStr); | |
| 214 | readVersionDeclaration(verStr); | |
| 219 | 215 | } |
| 220 | 216 | } |
| 221 | 217 | |
| ... | ... | @@ -227,135 +223,135 @@ void ScriptParser::readVersion() { |
| 227 | 223 | |
| 228 | 224 | void ScriptParser::readLinkerScript() { |
| 229 | 225 | while (!atEOF()) { |
| 230 | StringRef Tok = next(); | |
| 231 | if (Tok == ";") | |
| 226 | StringRef tok = next(); | |
| 227 | if (tok == ";") | |
| 232 | 228 | continue; |
| 233 | 229 | |
| 234 | if (Tok == "ENTRY") { | |
| 230 | if (tok == "ENTRY") { | |
| 235 | 231 | readEntry(); |
| 236 | } else if (Tok == "EXTERN") { | |
| 232 | } else if (tok == "EXTERN") { | |
| 237 | 233 | readExtern(); |
| 238 | } else if (Tok == "GROUP") { | |
| 234 | } else if (tok == "GROUP") { | |
| 239 | 235 | readGroup(); |
| 240 | } else if (Tok == "INCLUDE") { | |
| 236 | } else if (tok == "INCLUDE") { | |
| 241 | 237 | readInclude(); |
| 242 | } else if (Tok == "INPUT") { | |
| 238 | } else if (tok == "INPUT") { | |
| 243 | 239 | readInput(); |
| 244 | } else if (Tok == "MEMORY") { | |
| 240 | } else if (tok == "MEMORY") { | |
| 245 | 241 | readMemory(); |
| 246 | } else if (Tok == "OUTPUT") { | |
| 242 | } else if (tok == "OUTPUT") { | |
| 247 | 243 | readOutput(); |
| 248 | } else if (Tok == "OUTPUT_ARCH") { | |
| 244 | } else if (tok == "OUTPUT_ARCH") { | |
| 249 | 245 | readOutputArch(); |
| 250 | } else if (Tok == "OUTPUT_FORMAT") { | |
| 246 | } else if (tok == "OUTPUT_FORMAT") { | |
| 251 | 247 | readOutputFormat(); |
| 252 | } else if (Tok == "PHDRS") { | |
| 248 | } else if (tok == "PHDRS") { | |
| 253 | 249 | readPhdrs(); |
| 254 | } else if (Tok == "REGION_ALIAS") { | |
| 250 | } else if (tok == "REGION_ALIAS") { | |
| 255 | 251 | readRegionAlias(); |
| 256 | } else if (Tok == "SEARCH_DIR") { | |
| 252 | } else if (tok == "SEARCH_DIR") { | |
| 257 | 253 | readSearchDir(); |
| 258 | } else if (Tok == "SECTIONS") { | |
| 254 | } else if (tok == "SECTIONS") { | |
| 259 | 255 | readSections(); |
| 260 | } else if (Tok == "TARGET") { | |
| 256 | } else if (tok == "TARGET") { | |
| 261 | 257 | readTarget(); |
| 262 | } else if (Tok == "VERSION") { | |
| 258 | } else if (tok == "VERSION") { | |
| 263 | 259 | readVersion(); |
| 264 | } else if (SymbolAssignment *Cmd = readAssignment(Tok)) { | |
| 265 | Script->SectionCommands.push_back(Cmd); | |
| 260 | } else if (SymbolAssignment *cmd = readAssignment(tok)) { | |
| 261 | script->sectionCommands.push_back(cmd); | |
| 266 | 262 | } else { |
| 267 | setError("unknown directive: " + Tok); | |
| 263 | setError("unknown directive: " + tok); | |
| 268 | 264 | } |
| 269 | 265 | } |
| 270 | 266 | } |
| 271 | 267 | |
| 272 | void ScriptParser::readDefsym(StringRef Name) { | |
| 268 | void ScriptParser::readDefsym(StringRef name) { | |
| 273 | 269 | if (errorCount()) |
| 274 | 270 | return; |
| 275 | Expr E = readExpr(); | |
| 271 | Expr e = readExpr(); | |
| 276 | 272 | if (!atEOF()) |
| 277 | 273 | setError("EOF expected, but got " + next()); |
| 278 | SymbolAssignment *Cmd = make<SymbolAssignment>(Name, E, getCurrentLocation()); | |
| 279 | Script->SectionCommands.push_back(Cmd); | |
| 274 | SymbolAssignment *cmd = make<SymbolAssignment>(name, e, getCurrentLocation()); | |
| 275 | script->sectionCommands.push_back(cmd); | |
| 280 | 276 | } |
| 281 | 277 | |
| 282 | void ScriptParser::addFile(StringRef S) { | |
| 283 | if (IsUnderSysroot && S.startswith("/")) { | |
| 284 | SmallString<128> PathData; | |
| 285 | StringRef Path = (Config->Sysroot + S).toStringRef(PathData); | |
| 286 | if (sys::fs::exists(Path)) { | |
| 287 | Driver->addFile(Saver.save(Path), /*WithLOption=*/false); | |
| 278 | void ScriptParser::addFile(StringRef s) { | |
| 279 | if (isUnderSysroot && s.startswith("/")) { | |
| 280 | SmallString<128> pathData; | |
| 281 | StringRef path = (config->sysroot + s).toStringRef(pathData); | |
| 282 | if (sys::fs::exists(path)) { | |
| 283 | driver->addFile(saver.save(path), /*withLOption=*/false); | |
| 288 | 284 | return; |
| 289 | 285 | } |
| 290 | 286 | } |
| 291 | 287 | |
| 292 | if (S.startswith("/")) { | |
| 293 | Driver->addFile(S, /*WithLOption=*/false); | |
| 294 | } else if (S.startswith("=")) { | |
| 295 | if (Config->Sysroot.empty()) | |
| 296 | Driver->addFile(S.substr(1), /*WithLOption=*/false); | |
| 288 | if (s.startswith("/")) { | |
| 289 | driver->addFile(s, /*withLOption=*/false); | |
| 290 | } else if (s.startswith("=")) { | |
| 291 | if (config->sysroot.empty()) | |
| 292 | driver->addFile(s.substr(1), /*withLOption=*/false); | |
| 297 | 293 | else |
| 298 | Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)), | |
| 299 | /*WithLOption=*/false); | |
| 300 | } else if (S.startswith("-l")) { | |
| 301 | Driver->addLibrary(S.substr(2)); | |
| 302 | } else if (sys::fs::exists(S)) { | |
| 303 | Driver->addFile(S, /*WithLOption=*/false); | |
| 294 | driver->addFile(saver.save(config->sysroot + "/" + s.substr(1)), | |
| 295 | /*withLOption=*/false); | |
| 296 | } else if (s.startswith("-l")) { | |
| 297 | driver->addLibrary(s.substr(2)); | |
| 298 | } else if (sys::fs::exists(s)) { | |
| 299 | driver->addFile(s, /*withLOption=*/false); | |
| 304 | 300 | } else { |
| 305 | if (Optional<std::string> Path = findFromSearchPaths(S)) | |
| 306 | Driver->addFile(Saver.save(*Path), /*WithLOption=*/true); | |
| 301 | if (Optional<std::string> path = findFromSearchPaths(s)) | |
| 302 | driver->addFile(saver.save(*path), /*withLOption=*/true); | |
| 307 | 303 | else |
| 308 | setError("unable to find " + S); | |
| 304 | setError("unable to find " + s); | |
| 309 | 305 | } |
| 310 | 306 | } |
| 311 | 307 | |
| 312 | 308 | void ScriptParser::readAsNeeded() { |
| 313 | 309 | expect("("); |
| 314 | bool Orig = Config->AsNeeded; | |
| 315 | Config->AsNeeded = true; | |
| 310 | bool orig = config->asNeeded; | |
| 311 | config->asNeeded = true; | |
| 316 | 312 | while (!errorCount() && !consume(")")) |
| 317 | 313 | addFile(unquote(next())); |
| 318 | Config->AsNeeded = Orig; | |
| 314 | config->asNeeded = orig; | |
| 319 | 315 | } |
| 320 | 316 | |
| 321 | 317 | void ScriptParser::readEntry() { |
| 322 | 318 | // -e <symbol> takes predecence over ENTRY(<symbol>). |
| 323 | 319 | expect("("); |
| 324 | StringRef Tok = next(); | |
| 325 | if (Config->Entry.empty()) | |
| 326 | Config->Entry = Tok; | |
| 320 | StringRef tok = next(); | |
| 321 | if (config->entry.empty()) | |
| 322 | config->entry = tok; | |
| 327 | 323 | expect(")"); |
| 328 | 324 | } |
| 329 | 325 | |
| 330 | 326 | void ScriptParser::readExtern() { |
| 331 | 327 | expect("("); |
| 332 | 328 | while (!errorCount() && !consume(")")) |
| 333 | Config->Undefined.push_back(next()); | |
| 329 | config->undefined.push_back(unquote(next())); | |
| 334 | 330 | } |
| 335 | 331 | |
| 336 | 332 | void ScriptParser::readGroup() { |
| 337 | bool Orig = InputFile::IsInGroup; | |
| 338 | InputFile::IsInGroup = true; | |
| 333 | bool orig = InputFile::isInGroup; | |
| 334 | InputFile::isInGroup = true; | |
| 339 | 335 | readInput(); |
| 340 | InputFile::IsInGroup = Orig; | |
| 341 | if (!Orig) | |
| 342 | ++InputFile::NextGroupId; | |
| 336 | InputFile::isInGroup = orig; | |
| 337 | if (!orig) | |
| 338 | ++InputFile::nextGroupId; | |
| 343 | 339 | } |
| 344 | 340 | |
| 345 | 341 | void ScriptParser::readInclude() { |
| 346 | StringRef Tok = unquote(next()); | |
| 342 | StringRef tok = unquote(next()); | |
| 347 | 343 | |
| 348 | if (!Seen.insert(Tok).second) { | |
| 344 | if (!seen.insert(tok).second) { | |
| 349 | 345 | setError("there is a cycle in linker script INCLUDEs"); |
| 350 | 346 | return; |
| 351 | 347 | } |
| 352 | 348 | |
| 353 | if (Optional<std::string> Path = searchScript(Tok)) { | |
| 354 | if (Optional<MemoryBufferRef> MB = readFile(*Path)) | |
| 355 | tokenize(*MB); | |
| 349 | if (Optional<std::string> path = searchScript(tok)) { | |
| 350 | if (Optional<MemoryBufferRef> mb = readFile(*path)) | |
| 351 | tokenize(*mb); | |
| 356 | 352 | return; |
| 357 | 353 | } |
| 358 | setError("cannot find linker script " + Tok); | |
| 354 | setError("cannot find linker script " + tok); | |
| 359 | 355 | } |
| 360 | 356 | |
| 361 | 357 | void ScriptParser::readInput() { |
| ... | ... | @@ -371,9 +367,9 @@ void ScriptParser::readInput() { |
| 371 | 367 | void ScriptParser::readOutput() { |
| 372 | 368 | // -o <file> takes predecence over OUTPUT(<file>). |
| 373 | 369 | expect("("); |
| 374 | StringRef Tok = next(); | |
| 375 | if (Config->OutputFile.empty()) | |
| 376 | Config->OutputFile = unquote(Tok); | |
| 370 | StringRef tok = next(); | |
| 371 | if (config->outputFile.empty()) | |
| 372 | config->outputFile = unquote(tok); | |
| 377 | 373 | expect(")"); |
| 378 | 374 | } |
| 379 | 375 | |
| ... | ... | @@ -384,8 +380,8 @@ void ScriptParser::readOutputArch() { |
| 384 | 380 | skip(); |
| 385 | 381 | } |
| 386 | 382 | |
| 387 | static std::pair<ELFKind, uint16_t> parseBfdName(StringRef S) { | |
| 388 | return StringSwitch<std::pair<ELFKind, uint16_t>>(S) | |
| 383 | static std::pair<ELFKind, uint16_t> parseBfdName(StringRef s) { | |
| 384 | return StringSwitch<std::pair<ELFKind, uint16_t>>(s) | |
| 389 | 385 | .Case("elf32-i386", {ELF32LEKind, EM_386}) |
| 390 | 386 | .Case("elf32-iamcu", {ELF32LEKind, EM_IAMCU}) |
| 391 | 387 | .Case("elf32-littlearm", {ELF32LEKind, EM_ARM}) |
| ... | ... | @@ -402,6 +398,8 @@ static std::pair<ELFKind, uint16_t> parseBfdName(StringRef S) { |
| 402 | 398 | .Case("elf32-ntradlittlemips", {ELF32LEKind, EM_MIPS}) |
| 403 | 399 | .Case("elf64-tradbigmips", {ELF64BEKind, EM_MIPS}) |
| 404 | 400 | .Case("elf64-tradlittlemips", {ELF64LEKind, EM_MIPS}) |
| 401 | .Case("elf32-littleriscv", {ELF32LEKind, EM_RISCV}) | |
| 402 | .Case("elf64-littleriscv", {ELF64LEKind, EM_RISCV}) | |
| 405 | 403 | .Default({ELFNoneKind, EM_NONE}); |
| 406 | 404 | } |
| 407 | 405 | |
| ... | ... | @@ -410,16 +408,16 @@ static std::pair<ELFKind, uint16_t> parseBfdName(StringRef S) { |
| 410 | 408 | void ScriptParser::readOutputFormat() { |
| 411 | 409 | expect("("); |
| 412 | 410 | |
| 413 | StringRef Name = unquote(next()); | |
| 414 | StringRef S = Name; | |
| 415 | if (S.consume_back("-freebsd")) | |
| 416 | Config->OSABI = ELFOSABI_FREEBSD; | |
| 411 | StringRef name = unquote(next()); | |
| 412 | StringRef s = name; | |
| 413 | if (s.consume_back("-freebsd")) | |
| 414 | config->osabi = ELFOSABI_FREEBSD; | |
| 417 | 415 | |
| 418 | std::tie(Config->EKind, Config->EMachine) = parseBfdName(S); | |
| 419 | if (Config->EMachine == EM_NONE) | |
| 420 | setError("unknown output format name: " + Name); | |
| 421 | if (S == "elf32-ntradlittlemips" || S == "elf32-ntradbigmips") | |
| 422 | Config->MipsN32Abi = true; | |
| 416 | std::tie(config->ekind, config->emachine) = parseBfdName(s); | |
| 417 | if (config->emachine == EM_NONE) | |
| 418 | setError("unknown output format name: " + name); | |
| 419 | if (s == "elf32-ntradlittlemips" || s == "elf32-ntradbigmips") | |
| 420 | config->mipsN32Abi = true; | |
| 423 | 421 | |
| 424 | 422 | if (consume(")")) |
| 425 | 423 | return; |
| ... | ... | @@ -434,46 +432,46 @@ void ScriptParser::readPhdrs() { |
| 434 | 432 | expect("{"); |
| 435 | 433 | |
| 436 | 434 | while (!errorCount() && !consume("}")) { |
| 437 | PhdrsCommand Cmd; | |
| 438 | Cmd.Name = next(); | |
| 439 | Cmd.Type = readPhdrType(); | |
| 435 | PhdrsCommand cmd; | |
| 436 | cmd.name = next(); | |
| 437 | cmd.type = readPhdrType(); | |
| 440 | 438 | |
| 441 | 439 | while (!errorCount() && !consume(";")) { |
| 442 | 440 | if (consume("FILEHDR")) |
| 443 | Cmd.HasFilehdr = true; | |
| 441 | cmd.hasFilehdr = true; | |
| 444 | 442 | else if (consume("PHDRS")) |
| 445 | Cmd.HasPhdrs = true; | |
| 443 | cmd.hasPhdrs = true; | |
| 446 | 444 | else if (consume("AT")) |
| 447 | Cmd.LMAExpr = readParenExpr(); | |
| 445 | cmd.lmaExpr = readParenExpr(); | |
| 448 | 446 | else if (consume("FLAGS")) |
| 449 | Cmd.Flags = readParenExpr()().getValue(); | |
| 447 | cmd.flags = readParenExpr()().getValue(); | |
| 450 | 448 | else |
| 451 | 449 | setError("unexpected header attribute: " + next()); |
| 452 | 450 | } |
| 453 | 451 | |
| 454 | Script->PhdrsCommands.push_back(Cmd); | |
| 452 | script->phdrsCommands.push_back(cmd); | |
| 455 | 453 | } |
| 456 | 454 | } |
| 457 | 455 | |
| 458 | 456 | void ScriptParser::readRegionAlias() { |
| 459 | 457 | expect("("); |
| 460 | StringRef Alias = unquote(next()); | |
| 458 | StringRef alias = unquote(next()); | |
| 461 | 459 | expect(","); |
| 462 | StringRef Name = next(); | |
| 460 | StringRef name = next(); | |
| 463 | 461 | expect(")"); |
| 464 | 462 | |
| 465 | if (Script->MemoryRegions.count(Alias)) | |
| 466 | setError("redefinition of memory region '" + Alias + "'"); | |
| 467 | if (!Script->MemoryRegions.count(Name)) | |
| 468 | setError("memory region '" + Name + "' is not defined"); | |
| 469 | Script->MemoryRegions.insert({Alias, Script->MemoryRegions[Name]}); | |
| 463 | if (script->memoryRegions.count(alias)) | |
| 464 | setError("redefinition of memory region '" + alias + "'"); | |
| 465 | if (!script->memoryRegions.count(name)) | |
| 466 | setError("memory region '" + name + "' is not defined"); | |
| 467 | script->memoryRegions.insert({alias, script->memoryRegions[name]}); | |
| 470 | 468 | } |
| 471 | 469 | |
| 472 | 470 | void ScriptParser::readSearchDir() { |
| 473 | 471 | expect("("); |
| 474 | StringRef Tok = next(); | |
| 475 | if (!Config->Nostdlib) | |
| 476 | Config->SearchPaths.push_back(unquote(Tok)); | |
| 472 | StringRef tok = next(); | |
| 473 | if (!config->nostdlib) | |
| 474 | config->searchPaths.push_back(unquote(tok)); | |
| 477 | 475 | expect(")"); |
| 478 | 476 | } |
| 479 | 477 | |
| ... | ... | @@ -485,83 +483,83 @@ std::vector<BaseCommand *> ScriptParser::readOverlay() { |
| 485 | 483 | // VA and LMA expressions are optional, though for simplicity of |
| 486 | 484 | // implementation we assume they are not. That is what OVERLAY was designed |
| 487 | 485 | // for first of all: to allow sections with overlapping VAs at different LMAs. |
| 488 | Expr AddrExpr = readExpr(); | |
| 486 | Expr addrExpr = readExpr(); | |
| 489 | 487 | expect(":"); |
| 490 | 488 | expect("AT"); |
| 491 | Expr LMAExpr = readParenExpr(); | |
| 489 | Expr lmaExpr = readParenExpr(); | |
| 492 | 490 | expect("{"); |
| 493 | 491 | |
| 494 | std::vector<BaseCommand *> V; | |
| 495 | OutputSection *Prev = nullptr; | |
| 492 | std::vector<BaseCommand *> v; | |
| 493 | OutputSection *prev = nullptr; | |
| 496 | 494 | while (!errorCount() && !consume("}")) { |
| 497 | 495 | // VA is the same for all sections. The LMAs are consecutive in memory |
| 498 | 496 | // starting from the base load address specified. |
| 499 | OutputSection *OS = readOverlaySectionDescription(); | |
| 500 | OS->AddrExpr = AddrExpr; | |
| 501 | if (Prev) | |
| 502 | OS->LMAExpr = [=] { return Prev->getLMA() + Prev->Size; }; | |
| 497 | OutputSection *os = readOverlaySectionDescription(); | |
| 498 | os->addrExpr = addrExpr; | |
| 499 | if (prev) | |
| 500 | os->lmaExpr = [=] { return prev->getLMA() + prev->size; }; | |
| 503 | 501 | else |
| 504 | OS->LMAExpr = LMAExpr; | |
| 505 | V.push_back(OS); | |
| 506 | Prev = OS; | |
| 502 | os->lmaExpr = lmaExpr; | |
| 503 | v.push_back(os); | |
| 504 | prev = os; | |
| 507 | 505 | } |
| 508 | 506 | |
| 509 | 507 | // According to the specification, at the end of the overlay, the location |
| 510 | 508 | // counter should be equal to the overlay base address plus size of the |
| 511 | 509 | // largest section seen in the overlay. |
| 512 | 510 | // Here we want to create the Dot assignment command to achieve that. |
| 513 | Expr MoveDot = [=] { | |
| 514 | uint64_t Max = 0; | |
| 515 | for (BaseCommand *Cmd : V) | |
| 516 | Max = std::max(Max, cast<OutputSection>(Cmd)->Size); | |
| 517 | return AddrExpr().getValue() + Max; | |
| 511 | Expr moveDot = [=] { | |
| 512 | uint64_t max = 0; | |
| 513 | for (BaseCommand *cmd : v) | |
| 514 | max = std::max(max, cast<OutputSection>(cmd)->size); | |
| 515 | return addrExpr().getValue() + max; | |
| 518 | 516 | }; |
| 519 | V.push_back(make<SymbolAssignment>(".", MoveDot, getCurrentLocation())); | |
| 520 | return V; | |
| 517 | v.push_back(make<SymbolAssignment>(".", moveDot, getCurrentLocation())); | |
| 518 | return v; | |
| 521 | 519 | } |
| 522 | 520 | |
| 523 | 521 | void ScriptParser::readSections() { |
| 524 | Script->HasSectionsCommand = true; | |
| 522 | script->hasSectionsCommand = true; | |
| 525 | 523 | |
| 526 | 524 | // -no-rosegment is used to avoid placing read only non-executable sections in |
| 527 | 525 | // their own segment. We do the same if SECTIONS command is present in linker |
| 528 | 526 | // script. See comment for computeFlags(). |
| 529 | Config->SingleRoRx = true; | |
| 527 | config->singleRoRx = true; | |
| 530 | 528 | |
| 531 | 529 | expect("{"); |
| 532 | std::vector<BaseCommand *> V; | |
| 530 | std::vector<BaseCommand *> v; | |
| 533 | 531 | while (!errorCount() && !consume("}")) { |
| 534 | StringRef Tok = next(); | |
| 535 | if (Tok == "OVERLAY") { | |
| 536 | for (BaseCommand *Cmd : readOverlay()) | |
| 537 | V.push_back(Cmd); | |
| 532 | StringRef tok = next(); | |
| 533 | if (tok == "OVERLAY") { | |
| 534 | for (BaseCommand *cmd : readOverlay()) | |
| 535 | v.push_back(cmd); | |
| 538 | 536 | continue; |
| 539 | } else if (Tok == "INCLUDE") { | |
| 537 | } else if (tok == "INCLUDE") { | |
| 540 | 538 | readInclude(); |
| 541 | 539 | continue; |
| 542 | 540 | } |
| 543 | 541 | |
| 544 | if (BaseCommand *Cmd = readAssignment(Tok)) | |
| 545 | V.push_back(Cmd); | |
| 542 | if (BaseCommand *cmd = readAssignment(tok)) | |
| 543 | v.push_back(cmd); | |
| 546 | 544 | else |
| 547 | V.push_back(readOutputSectionDescription(Tok)); | |
| 545 | v.push_back(readOutputSectionDescription(tok)); | |
| 548 | 546 | } |
| 549 | 547 | |
| 550 | 548 | if (!atEOF() && consume("INSERT")) { |
| 551 | std::vector<BaseCommand *> *Dest = nullptr; | |
| 549 | std::vector<BaseCommand *> *dest = nullptr; | |
| 552 | 550 | if (consume("AFTER")) |
| 553 | Dest = &Script->InsertAfterCommands[next()]; | |
| 551 | dest = &script->insertAfterCommands[next()]; | |
| 554 | 552 | else if (consume("BEFORE")) |
| 555 | Dest = &Script->InsertBeforeCommands[next()]; | |
| 553 | dest = &script->insertBeforeCommands[next()]; | |
| 556 | 554 | else |
| 557 | 555 | setError("expected AFTER/BEFORE, but got '" + next() + "'"); |
| 558 | if (Dest) | |
| 559 | Dest->insert(Dest->end(), V.begin(), V.end()); | |
| 556 | if (dest) | |
| 557 | dest->insert(dest->end(), v.begin(), v.end()); | |
| 560 | 558 | return; |
| 561 | 559 | } |
| 562 | 560 | |
| 563 | Script->SectionCommands.insert(Script->SectionCommands.end(), V.begin(), | |
| 564 | V.end()); | |
| 561 | script->sectionCommands.insert(script->sectionCommands.end(), v.begin(), | |
| 562 | v.end()); | |
| 565 | 563 | } |
| 566 | 564 | |
| 567 | 565 | void ScriptParser::readTarget() { |
| ... | ... | @@ -570,19 +568,19 @@ void ScriptParser::readTarget() { |
| 570 | 568 | // for --format. We recognize only /^elf/ and "binary" in the linker |
| 571 | 569 | // script as well. |
| 572 | 570 | expect("("); |
| 573 | StringRef Tok = next(); | |
| 571 | StringRef tok = next(); | |
| 574 | 572 | expect(")"); |
| 575 | 573 | |
| 576 | if (Tok.startswith("elf")) | |
| 577 | Config->FormatBinary = false; | |
| 578 | else if (Tok == "binary") | |
| 579 | Config->FormatBinary = true; | |
| 574 | if (tok.startswith("elf")) | |
| 575 | config->formatBinary = false; | |
| 576 | else if (tok == "binary") | |
| 577 | config->formatBinary = true; | |
| 580 | 578 | else |
| 581 | setError("unknown target: " + Tok); | |
| 579 | setError("unknown target: " + tok); | |
| 582 | 580 | } |
| 583 | 581 | |
| 584 | static int precedence(StringRef Op) { | |
| 585 | return StringSwitch<int>(Op) | |
| 582 | static int precedence(StringRef op) { | |
| 583 | return StringSwitch<int>(op) | |
| 586 | 584 | .Cases("*", "/", "%", 8) |
| 587 | 585 | .Cases("+", "-", 7) |
| 588 | 586 | .Cases("<<", ">>", 6) |
| ... | ... | @@ -595,10 +593,10 @@ static int precedence(StringRef Op) { |
| 595 | 593 | } |
| 596 | 594 | |
| 597 | 595 | StringMatcher ScriptParser::readFilePatterns() { |
| 598 | std::vector<StringRef> V; | |
| 596 | std::vector<StringRef> v; | |
| 599 | 597 | while (!errorCount() && !consume(")")) |
| 600 | V.push_back(next()); | |
| 601 | return StringMatcher(V); | |
| 598 | v.push_back(next()); | |
| 599 | return StringMatcher(v); | |
| 602 | 600 | } |
| 603 | 601 | |
| 604 | 602 | SortSectionPolicy ScriptParser::readSortKind() { |
| ... | ... | @@ -627,24 +625,24 @@ SortSectionPolicy ScriptParser::readSortKind() { |
| 627 | 625 | // The semantics of that is section .foo in any file, section .bar in |
| 628 | 626 | // any file but a.o, and section .baz in any file but b.o. |
| 629 | 627 | std::vector<SectionPattern> ScriptParser::readInputSectionsList() { |
| 630 | std::vector<SectionPattern> Ret; | |
| 628 | std::vector<SectionPattern> ret; | |
| 631 | 629 | while (!errorCount() && peek() != ")") { |
| 632 | StringMatcher ExcludeFilePat; | |
| 630 | StringMatcher excludeFilePat; | |
| 633 | 631 | if (consume("EXCLUDE_FILE")) { |
| 634 | 632 | expect("("); |
| 635 | ExcludeFilePat = readFilePatterns(); | |
| 633 | excludeFilePat = readFilePatterns(); | |
| 636 | 634 | } |
| 637 | 635 | |
| 638 | std::vector<StringRef> V; | |
| 636 | std::vector<StringRef> v; | |
| 639 | 637 | while (!errorCount() && peek() != ")" && peek() != "EXCLUDE_FILE") |
| 640 | V.push_back(next()); | |
| 638 | v.push_back(unquote(next())); | |
| 641 | 639 | |
| 642 | if (!V.empty()) | |
| 643 | Ret.push_back({std::move(ExcludeFilePat), StringMatcher(V)}); | |
| 640 | if (!v.empty()) | |
| 641 | ret.push_back({std::move(excludeFilePat), StringMatcher(v)}); | |
| 644 | 642 | else |
| 645 | 643 | setError("section pattern is expected"); |
| 646 | 644 | } |
| 647 | return Ret; | |
| 645 | return ret; | |
| 648 | 646 | } |
| 649 | 647 | |
| 650 | 648 | // Reads contents of "SECTIONS" directive. That directive contains a |
| ... | ... | @@ -659,52 +657,52 @@ std::vector<SectionPattern> ScriptParser::readInputSectionsList() { |
| 659 | 657 | // |
| 660 | 658 | // <section-list> is parsed by readInputSectionsList(). |
| 661 | 659 | InputSectionDescription * |
| 662 | ScriptParser::readInputSectionRules(StringRef FilePattern) { | |
| 663 | auto *Cmd = make<InputSectionDescription>(FilePattern); | |
| 660 | ScriptParser::readInputSectionRules(StringRef filePattern) { | |
| 661 | auto *cmd = make<InputSectionDescription>(filePattern); | |
| 664 | 662 | expect("("); |
| 665 | 663 | |
| 666 | 664 | while (!errorCount() && !consume(")")) { |
| 667 | SortSectionPolicy Outer = readSortKind(); | |
| 668 | SortSectionPolicy Inner = SortSectionPolicy::Default; | |
| 669 | std::vector<SectionPattern> V; | |
| 670 | if (Outer != SortSectionPolicy::Default) { | |
| 665 | SortSectionPolicy outer = readSortKind(); | |
| 666 | SortSectionPolicy inner = SortSectionPolicy::Default; | |
| 667 | std::vector<SectionPattern> v; | |
| 668 | if (outer != SortSectionPolicy::Default) { | |
| 671 | 669 | expect("("); |
| 672 | Inner = readSortKind(); | |
| 673 | if (Inner != SortSectionPolicy::Default) { | |
| 670 | inner = readSortKind(); | |
| 671 | if (inner != SortSectionPolicy::Default) { | |
| 674 | 672 | expect("("); |
| 675 | V = readInputSectionsList(); | |
| 673 | v = readInputSectionsList(); | |
| 676 | 674 | expect(")"); |
| 677 | 675 | } else { |
| 678 | V = readInputSectionsList(); | |
| 676 | v = readInputSectionsList(); | |
| 679 | 677 | } |
| 680 | 678 | expect(")"); |
| 681 | 679 | } else { |
| 682 | V = readInputSectionsList(); | |
| 680 | v = readInputSectionsList(); | |
| 683 | 681 | } |
| 684 | 682 | |
| 685 | for (SectionPattern &Pat : V) { | |
| 686 | Pat.SortInner = Inner; | |
| 687 | Pat.SortOuter = Outer; | |
| 683 | for (SectionPattern &pat : v) { | |
| 684 | pat.sortInner = inner; | |
| 685 | pat.sortOuter = outer; | |
| 688 | 686 | } |
| 689 | 687 | |
| 690 | std::move(V.begin(), V.end(), std::back_inserter(Cmd->SectionPatterns)); | |
| 688 | std::move(v.begin(), v.end(), std::back_inserter(cmd->sectionPatterns)); | |
| 691 | 689 | } |
| 692 | return Cmd; | |
| 690 | return cmd; | |
| 693 | 691 | } |
| 694 | 692 | |
| 695 | 693 | InputSectionDescription * |
| 696 | ScriptParser::readInputSectionDescription(StringRef Tok) { | |
| 694 | ScriptParser::readInputSectionDescription(StringRef tok) { | |
| 697 | 695 | // Input section wildcard can be surrounded by KEEP. |
| 698 | 696 | // https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep |
| 699 | if (Tok == "KEEP") { | |
| 697 | if (tok == "KEEP") { | |
| 700 | 698 | expect("("); |
| 701 | StringRef FilePattern = next(); | |
| 702 | InputSectionDescription *Cmd = readInputSectionRules(FilePattern); | |
| 699 | StringRef filePattern = next(); | |
| 700 | InputSectionDescription *cmd = readInputSectionRules(filePattern); | |
| 703 | 701 | expect(")"); |
| 704 | Script->KeptSections.push_back(Cmd); | |
| 705 | return Cmd; | |
| 702 | script->keptSections.push_back(cmd); | |
| 703 | return cmd; | |
| 706 | 704 | } |
| 707 | return readInputSectionRules(Tok); | |
| 705 | return readInputSectionRules(tok); | |
| 708 | 706 | } |
| 709 | 707 | |
| 710 | 708 | void ScriptParser::readSort() { |
| ... | ... | @@ -715,44 +713,33 @@ void ScriptParser::readSort() { |
| 715 | 713 | |
| 716 | 714 | Expr ScriptParser::readAssert() { |
| 717 | 715 | expect("("); |
| 718 | Expr E = readExpr(); | |
| 716 | Expr e = readExpr(); | |
| 719 | 717 | expect(","); |
| 720 | StringRef Msg = unquote(next()); | |
| 718 | StringRef msg = unquote(next()); | |
| 721 | 719 | expect(")"); |
| 722 | 720 | |
| 723 | 721 | return [=] { |
| 724 | if (!E().getValue()) | |
| 725 | error(Msg); | |
| 726 | return Script->getDot(); | |
| 722 | if (!e().getValue()) | |
| 723 | error(msg); | |
| 724 | return script->getDot(); | |
| 727 | 725 | }; |
| 728 | 726 | } |
| 729 | 727 | |
| 730 | // Reads a FILL(expr) command. We handle the FILL command as an | |
| 731 | // alias for =fillexp section attribute, which is different from | |
| 732 | // what GNU linkers do. | |
| 733 | // https://sourceware.org/binutils/docs/ld/Output-Section-Data.html | |
| 734 | std::array<uint8_t, 4> ScriptParser::readFill() { | |
| 735 | expect("("); | |
| 736 | std::array<uint8_t, 4> V = parseFill(next()); | |
| 737 | expect(")"); | |
| 738 | return V; | |
| 739 | } | |
| 740 | ||
| 741 | 728 | // Tries to read the special directive for an output section definition which |
| 742 | 729 | // can be one of following: "(NOLOAD)", "(COPY)", "(INFO)" or "(OVERLAY)". |
| 743 | 730 | // Tok1 and Tok2 are next 2 tokens peeked. See comment for readSectionAddressType below. |
| 744 | bool ScriptParser::readSectionDirective(OutputSection *Cmd, StringRef Tok1, StringRef Tok2) { | |
| 745 | if (Tok1 != "(") | |
| 731 | bool ScriptParser::readSectionDirective(OutputSection *cmd, StringRef tok1, StringRef tok2) { | |
| 732 | if (tok1 != "(") | |
| 746 | 733 | return false; |
| 747 | if (Tok2 != "NOLOAD" && Tok2 != "COPY" && Tok2 != "INFO" && Tok2 != "OVERLAY") | |
| 734 | if (tok2 != "NOLOAD" && tok2 != "COPY" && tok2 != "INFO" && tok2 != "OVERLAY") | |
| 748 | 735 | return false; |
| 749 | 736 | |
| 750 | 737 | expect("("); |
| 751 | 738 | if (consume("NOLOAD")) { |
| 752 | Cmd->Noload = true; | |
| 739 | cmd->noload = true; | |
| 753 | 740 | } else { |
| 754 | 741 | skip(); // This is "COPY", "INFO" or "OVERLAY". |
| 755 | Cmd->NonAlloc = true; | |
| 742 | cmd->nonAlloc = true; | |
| 756 | 743 | } |
| 757 | 744 | expect(")"); |
| 758 | 745 | return true; |
| ... | ... | @@ -769,178 +756,186 @@ bool ScriptParser::readSectionDirective(OutputSection *Cmd, StringRef Tok1, Stri |
| 769 | 756 | // |
| 770 | 757 | // https://sourceware.org/binutils/docs/ld/Output-Section-Address.html |
| 771 | 758 | // https://sourceware.org/binutils/docs/ld/Output-Section-Type.html |
| 772 | void ScriptParser::readSectionAddressType(OutputSection *Cmd) { | |
| 773 | if (readSectionDirective(Cmd, peek(), peek2())) | |
| 759 | void ScriptParser::readSectionAddressType(OutputSection *cmd) { | |
| 760 | if (readSectionDirective(cmd, peek(), peek2())) | |
| 774 | 761 | return; |
| 775 | 762 | |
| 776 | Cmd->AddrExpr = readExpr(); | |
| 777 | if (peek() == "(" && !readSectionDirective(Cmd, "(", peek2())) | |
| 763 | cmd->addrExpr = readExpr(); | |
| 764 | if (peek() == "(" && !readSectionDirective(cmd, "(", peek2())) | |
| 778 | 765 | setError("unknown section directive: " + peek2()); |
| 779 | 766 | } |
| 780 | 767 | |
| 781 | static Expr checkAlignment(Expr E, std::string &Loc) { | |
| 768 | static Expr checkAlignment(Expr e, std::string &loc) { | |
| 782 | 769 | return [=] { |
| 783 | uint64_t Alignment = std::max((uint64_t)1, E().getValue()); | |
| 784 | if (!isPowerOf2_64(Alignment)) { | |
| 785 | error(Loc + ": alignment must be power of 2"); | |
| 770 | uint64_t alignment = std::max((uint64_t)1, e().getValue()); | |
| 771 | if (!isPowerOf2_64(alignment)) { | |
| 772 | error(loc + ": alignment must be power of 2"); | |
| 786 | 773 | return (uint64_t)1; // Return a dummy value. |
| 787 | 774 | } |
| 788 | return Alignment; | |
| 775 | return alignment; | |
| 789 | 776 | }; |
| 790 | 777 | } |
| 791 | 778 | |
| 792 | 779 | OutputSection *ScriptParser::readOverlaySectionDescription() { |
| 793 | OutputSection *Cmd = | |
| 794 | Script->createOutputSection(next(), getCurrentLocation()); | |
| 795 | Cmd->InOverlay = true; | |
| 780 | OutputSection *cmd = | |
| 781 | script->createOutputSection(next(), getCurrentLocation()); | |
| 782 | cmd->inOverlay = true; | |
| 796 | 783 | expect("{"); |
| 797 | 784 | while (!errorCount() && !consume("}")) |
| 798 | Cmd->SectionCommands.push_back(readInputSectionRules(next())); | |
| 799 | Cmd->Phdrs = readOutputSectionPhdrs(); | |
| 800 | return Cmd; | |
| 785 | cmd->sectionCommands.push_back(readInputSectionRules(next())); | |
| 786 | cmd->phdrs = readOutputSectionPhdrs(); | |
| 787 | return cmd; | |
| 801 | 788 | } |
| 802 | 789 | |
| 803 | OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) { | |
| 804 | OutputSection *Cmd = | |
| 805 | Script->createOutputSection(OutSec, getCurrentLocation()); | |
| 790 | OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) { | |
| 791 | OutputSection *cmd = | |
| 792 | script->createOutputSection(outSec, getCurrentLocation()); | |
| 806 | 793 | |
| 807 | size_t SymbolsReferenced = Script->ReferencedSymbols.size(); | |
| 794 | size_t symbolsReferenced = script->referencedSymbols.size(); | |
| 808 | 795 | |
| 809 | 796 | if (peek() != ":") |
| 810 | readSectionAddressType(Cmd); | |
| 797 | readSectionAddressType(cmd); | |
| 811 | 798 | expect(":"); |
| 812 | 799 | |
| 813 | std::string Location = getCurrentLocation(); | |
| 800 | std::string location = getCurrentLocation(); | |
| 814 | 801 | if (consume("AT")) |
| 815 | Cmd->LMAExpr = readParenExpr(); | |
| 802 | cmd->lmaExpr = readParenExpr(); | |
| 816 | 803 | if (consume("ALIGN")) |
| 817 | Cmd->AlignExpr = checkAlignment(readParenExpr(), Location); | |
| 804 | cmd->alignExpr = checkAlignment(readParenExpr(), location); | |
| 818 | 805 | if (consume("SUBALIGN")) |
| 819 | Cmd->SubalignExpr = checkAlignment(readParenExpr(), Location); | |
| 806 | cmd->subalignExpr = checkAlignment(readParenExpr(), location); | |
| 820 | 807 | |
| 821 | 808 | // Parse constraints. |
| 822 | 809 | if (consume("ONLY_IF_RO")) |
| 823 | Cmd->Constraint = ConstraintKind::ReadOnly; | |
| 810 | cmd->constraint = ConstraintKind::ReadOnly; | |
| 824 | 811 | if (consume("ONLY_IF_RW")) |
| 825 | Cmd->Constraint = ConstraintKind::ReadWrite; | |
| 812 | cmd->constraint = ConstraintKind::ReadWrite; | |
| 826 | 813 | expect("{"); |
| 827 | 814 | |
| 828 | 815 | while (!errorCount() && !consume("}")) { |
| 829 | StringRef Tok = next(); | |
| 830 | if (Tok == ";") { | |
| 816 | StringRef tok = next(); | |
| 817 | if (tok == ";") { | |
| 831 | 818 | // Empty commands are allowed. Do nothing here. |
| 832 | } else if (SymbolAssignment *Assign = readAssignment(Tok)) { | |
| 833 | Cmd->SectionCommands.push_back(Assign); | |
| 834 | } else if (ByteCommand *Data = readByteCommand(Tok)) { | |
| 835 | Cmd->SectionCommands.push_back(Data); | |
| 836 | } else if (Tok == "CONSTRUCTORS") { | |
| 819 | } else if (SymbolAssignment *assign = readAssignment(tok)) { | |
| 820 | cmd->sectionCommands.push_back(assign); | |
| 821 | } else if (ByteCommand *data = readByteCommand(tok)) { | |
| 822 | cmd->sectionCommands.push_back(data); | |
| 823 | } else if (tok == "CONSTRUCTORS") { | |
| 837 | 824 | // CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors |
| 838 | 825 | // by name. This is for very old file formats such as ECOFF/XCOFF. |
| 839 | 826 | // For ELF, we should ignore. |
| 840 | } else if (Tok == "FILL") { | |
| 841 | Cmd->Filler = readFill(); | |
| 842 | } else if (Tok == "SORT") { | |
| 827 | } else if (tok == "FILL") { | |
| 828 | // We handle the FILL command as an alias for =fillexp section attribute, | |
| 829 | // which is different from what GNU linkers do. | |
| 830 | // https://sourceware.org/binutils/docs/ld/Output-Section-Data.html | |
| 831 | expect("("); | |
| 832 | cmd->filler = readFill(); | |
| 833 | expect(")"); | |
| 834 | } else if (tok == "SORT") { | |
| 843 | 835 | readSort(); |
| 844 | } else if (Tok == "INCLUDE") { | |
| 836 | } else if (tok == "INCLUDE") { | |
| 845 | 837 | readInclude(); |
| 846 | 838 | } else if (peek() == "(") { |
| 847 | Cmd->SectionCommands.push_back(readInputSectionDescription(Tok)); | |
| 839 | cmd->sectionCommands.push_back(readInputSectionDescription(tok)); | |
| 848 | 840 | } else { |
| 849 | 841 | // We have a file name and no input sections description. It is not a |
| 850 | 842 | // commonly used syntax, but still acceptable. In that case, all sections |
| 851 | 843 | // from the file will be included. |
| 852 | auto *ISD = make<InputSectionDescription>(Tok); | |
| 853 | ISD->SectionPatterns.push_back({{}, StringMatcher({"*"})}); | |
| 854 | Cmd->SectionCommands.push_back(ISD); | |
| 844 | auto *isd = make<InputSectionDescription>(tok); | |
| 845 | isd->sectionPatterns.push_back({{}, StringMatcher({"*"})}); | |
| 846 | cmd->sectionCommands.push_back(isd); | |
| 855 | 847 | } |
| 856 | 848 | } |
| 857 | 849 | |
| 858 | 850 | if (consume(">")) |
| 859 | Cmd->MemoryRegionName = next(); | |
| 851 | cmd->memoryRegionName = next(); | |
| 860 | 852 | |
| 861 | 853 | if (consume("AT")) { |
| 862 | 854 | expect(">"); |
| 863 | Cmd->LMARegionName = next(); | |
| 855 | cmd->lmaRegionName = next(); | |
| 864 | 856 | } |
| 865 | 857 | |
| 866 | if (Cmd->LMAExpr && !Cmd->LMARegionName.empty()) | |
| 858 | if (cmd->lmaExpr && !cmd->lmaRegionName.empty()) | |
| 867 | 859 | error("section can't have both LMA and a load region"); |
| 868 | 860 | |
| 869 | Cmd->Phdrs = readOutputSectionPhdrs(); | |
| 861 | cmd->phdrs = readOutputSectionPhdrs(); | |
| 870 | 862 | |
| 871 | if (consume("=")) | |
| 872 | Cmd->Filler = parseFill(next()); | |
| 873 | else if (peek().startswith("=")) | |
| 874 | Cmd->Filler = parseFill(next().drop_front()); | |
| 863 | if (peek() == "=" || peek().startswith("=")) { | |
| 864 | inExpr = true; | |
| 865 | consume("="); | |
| 866 | cmd->filler = readFill(); | |
| 867 | inExpr = false; | |
| 868 | } | |
| 875 | 869 | |
| 876 | 870 | // Consume optional comma following output section command. |
| 877 | 871 | consume(","); |
| 878 | 872 | |
| 879 | if (Script->ReferencedSymbols.size() > SymbolsReferenced) | |
| 880 | Cmd->ExpressionsUseSymbols = true; | |
| 881 | return Cmd; | |
| 873 | if (script->referencedSymbols.size() > symbolsReferenced) | |
| 874 | cmd->expressionsUseSymbols = true; | |
| 875 | return cmd; | |
| 882 | 876 | } |
| 883 | 877 | |
| 884 | // Parses a given string as a octal/decimal/hexadecimal number and | |
| 885 | // returns it as a big-endian number. Used for `=<fillexp>`. | |
| 878 | // Reads a `=<fillexp>` expression and returns its value as a big-endian number. | |
| 886 | 879 | // https://sourceware.org/binutils/docs/ld/Output-Section-Fill.html |
| 880 | // We do not support using symbols in such expressions. | |
| 887 | 881 | // |
| 888 | 882 | // When reading a hexstring, ld.bfd handles it as a blob of arbitrary |
| 889 | 883 | // size, while ld.gold always handles it as a 32-bit big-endian number. |
| 890 | 884 | // We are compatible with ld.gold because it's easier to implement. |
| 891 | std::array<uint8_t, 4> ScriptParser::parseFill(StringRef Tok) { | |
| 892 | uint32_t V = 0; | |
| 893 | if (!to_integer(Tok, V)) | |
| 894 | setError("invalid filler expression: " + Tok); | |
| 885 | std::array<uint8_t, 4> ScriptParser::readFill() { | |
| 886 | uint64_t value = readExpr()().val; | |
| 887 | if (value > UINT32_MAX) | |
| 888 | setError("filler expression result does not fit 32-bit: 0x" + | |
| 889 | Twine::utohexstr(value)); | |
| 895 | 890 | |
| 896 | std::array<uint8_t, 4> Buf; | |
| 897 | write32be(Buf.data(), V); | |
| 898 | return Buf; | |
| 891 | std::array<uint8_t, 4> buf; | |
| 892 | write32be(buf.data(), (uint32_t)value); | |
| 893 | return buf; | |
| 899 | 894 | } |
| 900 | 895 | |
| 901 | SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) { | |
| 896 | SymbolAssignment *ScriptParser::readProvideHidden(bool provide, bool hidden) { | |
| 902 | 897 | expect("("); |
| 903 | SymbolAssignment *Cmd = readSymbolAssignment(next()); | |
| 904 | Cmd->Provide = Provide; | |
| 905 | Cmd->Hidden = Hidden; | |
| 898 | SymbolAssignment *cmd = readSymbolAssignment(next()); | |
| 899 | cmd->provide = provide; | |
| 900 | cmd->hidden = hidden; | |
| 906 | 901 | expect(")"); |
| 907 | return Cmd; | |
| 902 | return cmd; | |
| 908 | 903 | } |
| 909 | 904 | |
| 910 | SymbolAssignment *ScriptParser::readAssignment(StringRef Tok) { | |
| 905 | SymbolAssignment *ScriptParser::readAssignment(StringRef tok) { | |
| 911 | 906 | // Assert expression returns Dot, so this is equal to ".=." |
| 912 | if (Tok == "ASSERT") | |
| 907 | if (tok == "ASSERT") | |
| 913 | 908 | return make<SymbolAssignment>(".", readAssert(), getCurrentLocation()); |
| 914 | 909 | |
| 915 | size_t OldPos = Pos; | |
| 916 | SymbolAssignment *Cmd = nullptr; | |
| 910 | size_t oldPos = pos; | |
| 911 | SymbolAssignment *cmd = nullptr; | |
| 917 | 912 | if (peek() == "=" || peek() == "+=") |
| 918 | Cmd = readSymbolAssignment(Tok); | |
| 919 | else if (Tok == "PROVIDE") | |
| 920 | Cmd = readProvideHidden(true, false); | |
| 921 | else if (Tok == "HIDDEN") | |
| 922 | Cmd = readProvideHidden(false, true); | |
| 923 | else if (Tok == "PROVIDE_HIDDEN") | |
| 924 | Cmd = readProvideHidden(true, true); | |
| 925 | ||
| 926 | if (Cmd) { | |
| 927 | Cmd->CommandString = | |
| 928 | Tok.str() + " " + | |
| 929 | llvm::join(Tokens.begin() + OldPos, Tokens.begin() + Pos, " "); | |
| 913 | cmd = readSymbolAssignment(tok); | |
| 914 | else if (tok == "PROVIDE") | |
| 915 | cmd = readProvideHidden(true, false); | |
| 916 | else if (tok == "HIDDEN") | |
| 917 | cmd = readProvideHidden(false, true); | |
| 918 | else if (tok == "PROVIDE_HIDDEN") | |
| 919 | cmd = readProvideHidden(true, true); | |
| 920 | ||
| 921 | if (cmd) { | |
| 922 | cmd->commandString = | |
| 923 | tok.str() + " " + | |
| 924 | llvm::join(tokens.begin() + oldPos, tokens.begin() + pos, " "); | |
| 930 | 925 | expect(";"); |
| 931 | 926 | } |
| 932 | return Cmd; | |
| 927 | return cmd; | |
| 933 | 928 | } |
| 934 | 929 | |
| 935 | SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef Name) { | |
| 936 | StringRef Op = next(); | |
| 937 | assert(Op == "=" || Op == "+="); | |
| 938 | Expr E = readExpr(); | |
| 939 | if (Op == "+=") { | |
| 940 | std::string Loc = getCurrentLocation(); | |
| 941 | E = [=] { return add(Script->getSymbolValue(Name, Loc), E()); }; | |
| 930 | SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef name) { | |
| 931 | StringRef op = next(); | |
| 932 | assert(op == "=" || op == "+="); | |
| 933 | Expr e = readExpr(); | |
| 934 | if (op == "+=") { | |
| 935 | std::string loc = getCurrentLocation(); | |
| 936 | e = [=] { return add(script->getSymbolValue(name, loc), e()); }; | |
| 942 | 937 | } |
| 943 | return make<SymbolAssignment>(Name, E, getCurrentLocation()); | |
| 938 | return make<SymbolAssignment>(name, e, getCurrentLocation()); | |
| 944 | 939 | } |
| 945 | 940 | |
| 946 | 941 | // This is an operator-precedence parser to parse a linker |
| ... | ... | @@ -948,178 +943,178 @@ SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef Name) { |
| 948 | 943 | Expr ScriptParser::readExpr() { |
| 949 | 944 | // Our lexer is context-aware. Set the in-expression bit so that |
| 950 | 945 | // they apply different tokenization rules. |
| 951 | bool Orig = InExpr; | |
| 952 | InExpr = true; | |
| 953 | Expr E = readExpr1(readPrimary(), 0); | |
| 954 | InExpr = Orig; | |
| 955 | return E; | |
| 956 | } | |
| 957 | ||
| 958 | Expr ScriptParser::combine(StringRef Op, Expr L, Expr R) { | |
| 959 | if (Op == "+") | |
| 960 | return [=] { return add(L(), R()); }; | |
| 961 | if (Op == "-") | |
| 962 | return [=] { return sub(L(), R()); }; | |
| 963 | if (Op == "*") | |
| 964 | return [=] { return L().getValue() * R().getValue(); }; | |
| 965 | if (Op == "/") { | |
| 966 | std::string Loc = getCurrentLocation(); | |
| 946 | bool orig = inExpr; | |
| 947 | inExpr = true; | |
| 948 | Expr e = readExpr1(readPrimary(), 0); | |
| 949 | inExpr = orig; | |
| 950 | return e; | |
| 951 | } | |
| 952 | ||
| 953 | Expr ScriptParser::combine(StringRef op, Expr l, Expr r) { | |
| 954 | if (op == "+") | |
| 955 | return [=] { return add(l(), r()); }; | |
| 956 | if (op == "-") | |
| 957 | return [=] { return sub(l(), r()); }; | |
| 958 | if (op == "*") | |
| 959 | return [=] { return l().getValue() * r().getValue(); }; | |
| 960 | if (op == "/") { | |
| 961 | std::string loc = getCurrentLocation(); | |
| 967 | 962 | return [=]() -> uint64_t { |
| 968 | if (uint64_t RV = R().getValue()) | |
| 969 | return L().getValue() / RV; | |
| 970 | error(Loc + ": division by zero"); | |
| 963 | if (uint64_t rv = r().getValue()) | |
| 964 | return l().getValue() / rv; | |
| 965 | error(loc + ": division by zero"); | |
| 971 | 966 | return 0; |
| 972 | 967 | }; |
| 973 | 968 | } |
| 974 | if (Op == "%") { | |
| 975 | std::string Loc = getCurrentLocation(); | |
| 969 | if (op == "%") { | |
| 970 | std::string loc = getCurrentLocation(); | |
| 976 | 971 | return [=]() -> uint64_t { |
| 977 | if (uint64_t RV = R().getValue()) | |
| 978 | return L().getValue() % RV; | |
| 979 | error(Loc + ": modulo by zero"); | |
| 972 | if (uint64_t rv = r().getValue()) | |
| 973 | return l().getValue() % rv; | |
| 974 | error(loc + ": modulo by zero"); | |
| 980 | 975 | return 0; |
| 981 | 976 | }; |
| 982 | 977 | } |
| 983 | if (Op == "<<") | |
| 984 | return [=] { return L().getValue() << R().getValue(); }; | |
| 985 | if (Op == ">>") | |
| 986 | return [=] { return L().getValue() >> R().getValue(); }; | |
| 987 | if (Op == "<") | |
| 988 | return [=] { return L().getValue() < R().getValue(); }; | |
| 989 | if (Op == ">") | |
| 990 | return [=] { return L().getValue() > R().getValue(); }; | |
| 991 | if (Op == ">=") | |
| 992 | return [=] { return L().getValue() >= R().getValue(); }; | |
| 993 | if (Op == "<=") | |
| 994 | return [=] { return L().getValue() <= R().getValue(); }; | |
| 995 | if (Op == "==") | |
| 996 | return [=] { return L().getValue() == R().getValue(); }; | |
| 997 | if (Op == "!=") | |
| 998 | return [=] { return L().getValue() != R().getValue(); }; | |
| 999 | if (Op == "||") | |
| 1000 | return [=] { return L().getValue() || R().getValue(); }; | |
| 1001 | if (Op == "&&") | |
| 1002 | return [=] { return L().getValue() && R().getValue(); }; | |
| 1003 | if (Op == "&") | |
| 1004 | return [=] { return bitAnd(L(), R()); }; | |
| 1005 | if (Op == "|") | |
| 1006 | return [=] { return bitOr(L(), R()); }; | |
| 978 | if (op == "<<") | |
| 979 | return [=] { return l().getValue() << r().getValue(); }; | |
| 980 | if (op == ">>") | |
| 981 | return [=] { return l().getValue() >> r().getValue(); }; | |
| 982 | if (op == "<") | |
| 983 | return [=] { return l().getValue() < r().getValue(); }; | |
| 984 | if (op == ">") | |
| 985 | return [=] { return l().getValue() > r().getValue(); }; | |
| 986 | if (op == ">=") | |
| 987 | return [=] { return l().getValue() >= r().getValue(); }; | |
| 988 | if (op == "<=") | |
| 989 | return [=] { return l().getValue() <= r().getValue(); }; | |
| 990 | if (op == "==") | |
| 991 | return [=] { return l().getValue() == r().getValue(); }; | |
| 992 | if (op == "!=") | |
| 993 | return [=] { return l().getValue() != r().getValue(); }; | |
| 994 | if (op == "||") | |
| 995 | return [=] { return l().getValue() || r().getValue(); }; | |
| 996 | if (op == "&&") | |
| 997 | return [=] { return l().getValue() && r().getValue(); }; | |
| 998 | if (op == "&") | |
| 999 | return [=] { return bitAnd(l(), r()); }; | |
| 1000 | if (op == "|") | |
| 1001 | return [=] { return bitOr(l(), r()); }; | |
| 1007 | 1002 | llvm_unreachable("invalid operator"); |
| 1008 | 1003 | } |
| 1009 | 1004 | |
| 1010 | 1005 | // This is a part of the operator-precedence parser. This function |
| 1011 | 1006 | // assumes that the remaining token stream starts with an operator. |
| 1012 | Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec) { | |
| 1007 | Expr ScriptParser::readExpr1(Expr lhs, int minPrec) { | |
| 1013 | 1008 | while (!atEOF() && !errorCount()) { |
| 1014 | 1009 | // Read an operator and an expression. |
| 1015 | 1010 | if (consume("?")) |
| 1016 | return readTernary(Lhs); | |
| 1017 | StringRef Op1 = peek(); | |
| 1018 | if (precedence(Op1) < MinPrec) | |
| 1011 | return readTernary(lhs); | |
| 1012 | StringRef op1 = peek(); | |
| 1013 | if (precedence(op1) < minPrec) | |
| 1019 | 1014 | break; |
| 1020 | 1015 | skip(); |
| 1021 | Expr Rhs = readPrimary(); | |
| 1016 | Expr rhs = readPrimary(); | |
| 1022 | 1017 | |
| 1023 | 1018 | // Evaluate the remaining part of the expression first if the |
| 1024 | 1019 | // next operator has greater precedence than the previous one. |
| 1025 | 1020 | // For example, if we have read "+" and "3", and if the next |
| 1026 | 1021 | // operator is "*", then we'll evaluate 3 * ... part first. |
| 1027 | 1022 | while (!atEOF()) { |
| 1028 | StringRef Op2 = peek(); | |
| 1029 | if (precedence(Op2) <= precedence(Op1)) | |
| 1023 | StringRef op2 = peek(); | |
| 1024 | if (precedence(op2) <= precedence(op1)) | |
| 1030 | 1025 | break; |
| 1031 | Rhs = readExpr1(Rhs, precedence(Op2)); | |
| 1026 | rhs = readExpr1(rhs, precedence(op2)); | |
| 1032 | 1027 | } |
| 1033 | 1028 | |
| 1034 | Lhs = combine(Op1, Lhs, Rhs); | |
| 1029 | lhs = combine(op1, lhs, rhs); | |
| 1035 | 1030 | } |
| 1036 | return Lhs; | |
| 1031 | return lhs; | |
| 1037 | 1032 | } |
| 1038 | 1033 | |
| 1039 | 1034 | Expr ScriptParser::getPageSize() { |
| 1040 | std::string Location = getCurrentLocation(); | |
| 1035 | std::string location = getCurrentLocation(); | |
| 1041 | 1036 | return [=]() -> uint64_t { |
| 1042 | if (Target) | |
| 1043 | return Target->PageSize; | |
| 1044 | error(Location + ": unable to calculate page size"); | |
| 1037 | if (target) | |
| 1038 | return config->commonPageSize; | |
| 1039 | error(location + ": unable to calculate page size"); | |
| 1045 | 1040 | return 4096; // Return a dummy value. |
| 1046 | 1041 | }; |
| 1047 | 1042 | } |
| 1048 | 1043 | |
| 1049 | 1044 | Expr ScriptParser::readConstant() { |
| 1050 | StringRef S = readParenLiteral(); | |
| 1051 | if (S == "COMMONPAGESIZE") | |
| 1045 | StringRef s = readParenLiteral(); | |
| 1046 | if (s == "COMMONPAGESIZE") | |
| 1052 | 1047 | return getPageSize(); |
| 1053 | if (S == "MAXPAGESIZE") | |
| 1054 | return [] { return Config->MaxPageSize; }; | |
| 1055 | setError("unknown constant: " + S); | |
| 1048 | if (s == "MAXPAGESIZE") | |
| 1049 | return [] { return config->maxPageSize; }; | |
| 1050 | setError("unknown constant: " + s); | |
| 1056 | 1051 | return [] { return 0; }; |
| 1057 | 1052 | } |
| 1058 | 1053 | |
| 1059 | 1054 | // Parses Tok as an integer. It recognizes hexadecimal (prefixed with |
| 1060 | 1055 | // "0x" or suffixed with "H") and decimal numbers. Decimal numbers may |
| 1061 | 1056 | // have "K" (Ki) or "M" (Mi) suffixes. |
| 1062 | static Optional<uint64_t> parseInt(StringRef Tok) { | |
| 1057 | static Optional<uint64_t> parseInt(StringRef tok) { | |
| 1063 | 1058 | // Hexadecimal |
| 1064 | uint64_t Val; | |
| 1065 | if (Tok.startswith_lower("0x")) { | |
| 1066 | if (!to_integer(Tok.substr(2), Val, 16)) | |
| 1059 | uint64_t val; | |
| 1060 | if (tok.startswith_lower("0x")) { | |
| 1061 | if (!to_integer(tok.substr(2), val, 16)) | |
| 1067 | 1062 | return None; |
| 1068 | return Val; | |
| 1063 | return val; | |
| 1069 | 1064 | } |
| 1070 | if (Tok.endswith_lower("H")) { | |
| 1071 | if (!to_integer(Tok.drop_back(), Val, 16)) | |
| 1065 | if (tok.endswith_lower("H")) { | |
| 1066 | if (!to_integer(tok.drop_back(), val, 16)) | |
| 1072 | 1067 | return None; |
| 1073 | return Val; | |
| 1068 | return val; | |
| 1074 | 1069 | } |
| 1075 | 1070 | |
| 1076 | 1071 | // Decimal |
| 1077 | if (Tok.endswith_lower("K")) { | |
| 1078 | if (!to_integer(Tok.drop_back(), Val, 10)) | |
| 1072 | if (tok.endswith_lower("K")) { | |
| 1073 | if (!to_integer(tok.drop_back(), val, 10)) | |
| 1079 | 1074 | return None; |
| 1080 | return Val * 1024; | |
| 1075 | return val * 1024; | |
| 1081 | 1076 | } |
| 1082 | if (Tok.endswith_lower("M")) { | |
| 1083 | if (!to_integer(Tok.drop_back(), Val, 10)) | |
| 1077 | if (tok.endswith_lower("M")) { | |
| 1078 | if (!to_integer(tok.drop_back(), val, 10)) | |
| 1084 | 1079 | return None; |
| 1085 | return Val * 1024 * 1024; | |
| 1080 | return val * 1024 * 1024; | |
| 1086 | 1081 | } |
| 1087 | if (!to_integer(Tok, Val, 10)) | |
| 1082 | if (!to_integer(tok, val, 10)) | |
| 1088 | 1083 | return None; |
| 1089 | return Val; | |
| 1084 | return val; | |
| 1090 | 1085 | } |
| 1091 | 1086 | |
| 1092 | ByteCommand *ScriptParser::readByteCommand(StringRef Tok) { | |
| 1093 | int Size = StringSwitch<int>(Tok) | |
| 1087 | ByteCommand *ScriptParser::readByteCommand(StringRef tok) { | |
| 1088 | int size = StringSwitch<int>(tok) | |
| 1094 | 1089 | .Case("BYTE", 1) |
| 1095 | 1090 | .Case("SHORT", 2) |
| 1096 | 1091 | .Case("LONG", 4) |
| 1097 | 1092 | .Case("QUAD", 8) |
| 1098 | 1093 | .Default(-1); |
| 1099 | if (Size == -1) | |
| 1094 | if (size == -1) | |
| 1100 | 1095 | return nullptr; |
| 1101 | 1096 | |
| 1102 | size_t OldPos = Pos; | |
| 1103 | Expr E = readParenExpr(); | |
| 1104 | std::string CommandString = | |
| 1105 | Tok.str() + " " + | |
| 1106 | llvm::join(Tokens.begin() + OldPos, Tokens.begin() + Pos, " "); | |
| 1107 | return make<ByteCommand>(E, Size, CommandString); | |
| 1097 | size_t oldPos = pos; | |
| 1098 | Expr e = readParenExpr(); | |
| 1099 | std::string commandString = | |
| 1100 | tok.str() + " " + | |
| 1101 | llvm::join(tokens.begin() + oldPos, tokens.begin() + pos, " "); | |
| 1102 | return make<ByteCommand>(e, size, commandString); | |
| 1108 | 1103 | } |
| 1109 | 1104 | |
| 1110 | 1105 | StringRef ScriptParser::readParenLiteral() { |
| 1111 | 1106 | expect("("); |
| 1112 | bool Orig = InExpr; | |
| 1113 | InExpr = false; | |
| 1114 | StringRef Tok = next(); | |
| 1115 | InExpr = Orig; | |
| 1107 | bool orig = inExpr; | |
| 1108 | inExpr = false; | |
| 1109 | StringRef tok = next(); | |
| 1110 | inExpr = orig; | |
| 1116 | 1111 | expect(")"); |
| 1117 | return Tok; | |
| 1112 | return tok; | |
| 1118 | 1113 | } |
| 1119 | 1114 | |
| 1120 | static void checkIfExists(OutputSection *Cmd, StringRef Location) { | |
| 1121 | if (Cmd->Location.empty() && Script->ErrorOnMissingSection) | |
| 1122 | error(Location + ": undefined section " + Cmd->Name); | |
| 1115 | static void checkIfExists(OutputSection *cmd, StringRef location) { | |
| 1116 | if (cmd->location.empty() && script->errorOnMissingSection) | |
| 1117 | error(location + ": undefined section " + cmd->name); | |
| 1123 | 1118 | } |
| 1124 | 1119 | |
| 1125 | 1120 | Expr ScriptParser::readPrimary() { |
| ... | ... | @@ -1127,84 +1122,85 @@ Expr ScriptParser::readPrimary() { |
| 1127 | 1122 | return readParenExpr(); |
| 1128 | 1123 | |
| 1129 | 1124 | if (consume("~")) { |
| 1130 | Expr E = readPrimary(); | |
| 1131 | return [=] { return ~E().getValue(); }; | |
| 1125 | Expr e = readPrimary(); | |
| 1126 | return [=] { return ~e().getValue(); }; | |
| 1132 | 1127 | } |
| 1133 | 1128 | if (consume("!")) { |
| 1134 | Expr E = readPrimary(); | |
| 1135 | return [=] { return !E().getValue(); }; | |
| 1129 | Expr e = readPrimary(); | |
| 1130 | return [=] { return !e().getValue(); }; | |
| 1136 | 1131 | } |
| 1137 | 1132 | if (consume("-")) { |
| 1138 | Expr E = readPrimary(); | |
| 1139 | return [=] { return -E().getValue(); }; | |
| 1133 | Expr e = readPrimary(); | |
| 1134 | return [=] { return -e().getValue(); }; | |
| 1140 | 1135 | } |
| 1141 | 1136 | |
| 1142 | StringRef Tok = next(); | |
| 1143 | std::string Location = getCurrentLocation(); | |
| 1137 | StringRef tok = next(); | |
| 1138 | std::string location = getCurrentLocation(); | |
| 1144 | 1139 | |
| 1145 | 1140 | // Built-in functions are parsed here. |
| 1146 | 1141 | // https://sourceware.org/binutils/docs/ld/Builtin-Functions.html. |
| 1147 | if (Tok == "ABSOLUTE") { | |
| 1148 | Expr Inner = readParenExpr(); | |
| 1142 | if (tok == "ABSOLUTE") { | |
| 1143 | Expr inner = readParenExpr(); | |
| 1149 | 1144 | return [=] { |
| 1150 | ExprValue I = Inner(); | |
| 1151 | I.ForceAbsolute = true; | |
| 1152 | return I; | |
| 1145 | ExprValue i = inner(); | |
| 1146 | i.forceAbsolute = true; | |
| 1147 | return i; | |
| 1153 | 1148 | }; |
| 1154 | 1149 | } |
| 1155 | if (Tok == "ADDR") { | |
| 1156 | StringRef Name = readParenLiteral(); | |
| 1157 | OutputSection *Sec = Script->getOrCreateOutputSection(Name); | |
| 1150 | if (tok == "ADDR") { | |
| 1151 | StringRef name = readParenLiteral(); | |
| 1152 | OutputSection *sec = script->getOrCreateOutputSection(name); | |
| 1153 | sec->usedInExpression = true; | |
| 1158 | 1154 | return [=]() -> ExprValue { |
| 1159 | checkIfExists(Sec, Location); | |
| 1160 | return {Sec, false, 0, Location}; | |
| 1155 | checkIfExists(sec, location); | |
| 1156 | return {sec, false, 0, location}; | |
| 1161 | 1157 | }; |
| 1162 | 1158 | } |
| 1163 | if (Tok == "ALIGN") { | |
| 1159 | if (tok == "ALIGN") { | |
| 1164 | 1160 | expect("("); |
| 1165 | Expr E = readExpr(); | |
| 1161 | Expr e = readExpr(); | |
| 1166 | 1162 | if (consume(")")) { |
| 1167 | E = checkAlignment(E, Location); | |
| 1168 | return [=] { return alignTo(Script->getDot(), E().getValue()); }; | |
| 1163 | e = checkAlignment(e, location); | |
| 1164 | return [=] { return alignTo(script->getDot(), e().getValue()); }; | |
| 1169 | 1165 | } |
| 1170 | 1166 | expect(","); |
| 1171 | Expr E2 = checkAlignment(readExpr(), Location); | |
| 1167 | Expr e2 = checkAlignment(readExpr(), location); | |
| 1172 | 1168 | expect(")"); |
| 1173 | 1169 | return [=] { |
| 1174 | ExprValue V = E(); | |
| 1175 | V.Alignment = E2().getValue(); | |
| 1176 | return V; | |
| 1170 | ExprValue v = e(); | |
| 1171 | v.alignment = e2().getValue(); | |
| 1172 | return v; | |
| 1177 | 1173 | }; |
| 1178 | 1174 | } |
| 1179 | if (Tok == "ALIGNOF") { | |
| 1180 | StringRef Name = readParenLiteral(); | |
| 1181 | OutputSection *Cmd = Script->getOrCreateOutputSection(Name); | |
| 1175 | if (tok == "ALIGNOF") { | |
| 1176 | StringRef name = readParenLiteral(); | |
| 1177 | OutputSection *cmd = script->getOrCreateOutputSection(name); | |
| 1182 | 1178 | return [=] { |
| 1183 | checkIfExists(Cmd, Location); | |
| 1184 | return Cmd->Alignment; | |
| 1179 | checkIfExists(cmd, location); | |
| 1180 | return cmd->alignment; | |
| 1185 | 1181 | }; |
| 1186 | 1182 | } |
| 1187 | if (Tok == "ASSERT") | |
| 1183 | if (tok == "ASSERT") | |
| 1188 | 1184 | return readAssert(); |
| 1189 | if (Tok == "CONSTANT") | |
| 1185 | if (tok == "CONSTANT") | |
| 1190 | 1186 | return readConstant(); |
| 1191 | if (Tok == "DATA_SEGMENT_ALIGN") { | |
| 1187 | if (tok == "DATA_SEGMENT_ALIGN") { | |
| 1192 | 1188 | expect("("); |
| 1193 | Expr E = readExpr(); | |
| 1189 | Expr e = readExpr(); | |
| 1194 | 1190 | expect(","); |
| 1195 | 1191 | readExpr(); |
| 1196 | 1192 | expect(")"); |
| 1197 | 1193 | return [=] { |
| 1198 | return alignTo(Script->getDot(), std::max((uint64_t)1, E().getValue())); | |
| 1194 | return alignTo(script->getDot(), std::max((uint64_t)1, e().getValue())); | |
| 1199 | 1195 | }; |
| 1200 | 1196 | } |
| 1201 | if (Tok == "DATA_SEGMENT_END") { | |
| 1197 | if (tok == "DATA_SEGMENT_END") { | |
| 1202 | 1198 | expect("("); |
| 1203 | 1199 | expect("."); |
| 1204 | 1200 | expect(")"); |
| 1205 | return [] { return Script->getDot(); }; | |
| 1201 | return [] { return script->getDot(); }; | |
| 1206 | 1202 | } |
| 1207 | if (Tok == "DATA_SEGMENT_RELRO_END") { | |
| 1203 | if (tok == "DATA_SEGMENT_RELRO_END") { | |
| 1208 | 1204 | // GNU linkers implements more complicated logic to handle |
| 1209 | 1205 | // DATA_SEGMENT_RELRO_END. We instead ignore the arguments and |
| 1210 | 1206 | // just align to the next page boundary for simplicity. |
| ... | ... | @@ -1213,112 +1209,113 @@ Expr ScriptParser::readPrimary() { |
| 1213 | 1209 | expect(","); |
| 1214 | 1210 | readExpr(); |
| 1215 | 1211 | expect(")"); |
| 1216 | Expr E = getPageSize(); | |
| 1217 | return [=] { return alignTo(Script->getDot(), E().getValue()); }; | |
| 1212 | Expr e = getPageSize(); | |
| 1213 | return [=] { return alignTo(script->getDot(), e().getValue()); }; | |
| 1218 | 1214 | } |
| 1219 | if (Tok == "DEFINED") { | |
| 1220 | StringRef Name = readParenLiteral(); | |
| 1221 | return [=] { return Symtab->find(Name) ? 1 : 0; }; | |
| 1215 | if (tok == "DEFINED") { | |
| 1216 | StringRef name = readParenLiteral(); | |
| 1217 | return [=] { return symtab->find(name) ? 1 : 0; }; | |
| 1222 | 1218 | } |
| 1223 | if (Tok == "LENGTH") { | |
| 1224 | StringRef Name = readParenLiteral(); | |
| 1225 | if (Script->MemoryRegions.count(Name) == 0) { | |
| 1226 | setError("memory region not defined: " + Name); | |
| 1219 | if (tok == "LENGTH") { | |
| 1220 | StringRef name = readParenLiteral(); | |
| 1221 | if (script->memoryRegions.count(name) == 0) { | |
| 1222 | setError("memory region not defined: " + name); | |
| 1227 | 1223 | return [] { return 0; }; |
| 1228 | 1224 | } |
| 1229 | return [=] { return Script->MemoryRegions[Name]->Length; }; | |
| 1225 | return [=] { return script->memoryRegions[name]->length; }; | |
| 1230 | 1226 | } |
| 1231 | if (Tok == "LOADADDR") { | |
| 1232 | StringRef Name = readParenLiteral(); | |
| 1233 | OutputSection *Cmd = Script->getOrCreateOutputSection(Name); | |
| 1227 | if (tok == "LOADADDR") { | |
| 1228 | StringRef name = readParenLiteral(); | |
| 1229 | OutputSection *cmd = script->getOrCreateOutputSection(name); | |
| 1230 | cmd->usedInExpression = true; | |
| 1234 | 1231 | return [=] { |
| 1235 | checkIfExists(Cmd, Location); | |
| 1236 | return Cmd->getLMA(); | |
| 1232 | checkIfExists(cmd, location); | |
| 1233 | return cmd->getLMA(); | |
| 1237 | 1234 | }; |
| 1238 | 1235 | } |
| 1239 | if (Tok == "MAX" || Tok == "MIN") { | |
| 1236 | if (tok == "MAX" || tok == "MIN") { | |
| 1240 | 1237 | expect("("); |
| 1241 | Expr A = readExpr(); | |
| 1238 | Expr a = readExpr(); | |
| 1242 | 1239 | expect(","); |
| 1243 | Expr B = readExpr(); | |
| 1240 | Expr b = readExpr(); | |
| 1244 | 1241 | expect(")"); |
| 1245 | if (Tok == "MIN") | |
| 1246 | return [=] { return std::min(A().getValue(), B().getValue()); }; | |
| 1247 | return [=] { return std::max(A().getValue(), B().getValue()); }; | |
| 1242 | if (tok == "MIN") | |
| 1243 | return [=] { return std::min(a().getValue(), b().getValue()); }; | |
| 1244 | return [=] { return std::max(a().getValue(), b().getValue()); }; | |
| 1248 | 1245 | } |
| 1249 | if (Tok == "ORIGIN") { | |
| 1250 | StringRef Name = readParenLiteral(); | |
| 1251 | if (Script->MemoryRegions.count(Name) == 0) { | |
| 1252 | setError("memory region not defined: " + Name); | |
| 1246 | if (tok == "ORIGIN") { | |
| 1247 | StringRef name = readParenLiteral(); | |
| 1248 | if (script->memoryRegions.count(name) == 0) { | |
| 1249 | setError("memory region not defined: " + name); | |
| 1253 | 1250 | return [] { return 0; }; |
| 1254 | 1251 | } |
| 1255 | return [=] { return Script->MemoryRegions[Name]->Origin; }; | |
| 1252 | return [=] { return script->memoryRegions[name]->origin; }; | |
| 1256 | 1253 | } |
| 1257 | if (Tok == "SEGMENT_START") { | |
| 1254 | if (tok == "SEGMENT_START") { | |
| 1258 | 1255 | expect("("); |
| 1259 | 1256 | skip(); |
| 1260 | 1257 | expect(","); |
| 1261 | Expr E = readExpr(); | |
| 1258 | Expr e = readExpr(); | |
| 1262 | 1259 | expect(")"); |
| 1263 | return [=] { return E(); }; | |
| 1260 | return [=] { return e(); }; | |
| 1264 | 1261 | } |
| 1265 | if (Tok == "SIZEOF") { | |
| 1266 | StringRef Name = readParenLiteral(); | |
| 1267 | OutputSection *Cmd = Script->getOrCreateOutputSection(Name); | |
| 1262 | if (tok == "SIZEOF") { | |
| 1263 | StringRef name = readParenLiteral(); | |
| 1264 | OutputSection *cmd = script->getOrCreateOutputSection(name); | |
| 1268 | 1265 | // Linker script does not create an output section if its content is empty. |
| 1269 | 1266 | // We want to allow SIZEOF(.foo) where .foo is a section which happened to |
| 1270 | 1267 | // be empty. |
| 1271 | return [=] { return Cmd->Size; }; | |
| 1268 | return [=] { return cmd->size; }; | |
| 1272 | 1269 | } |
| 1273 | if (Tok == "SIZEOF_HEADERS") | |
| 1270 | if (tok == "SIZEOF_HEADERS") | |
| 1274 | 1271 | return [=] { return elf::getHeaderSize(); }; |
| 1275 | 1272 | |
| 1276 | 1273 | // Tok is the dot. |
| 1277 | if (Tok == ".") | |
| 1278 | return [=] { return Script->getSymbolValue(Tok, Location); }; | |
| 1274 | if (tok == ".") | |
| 1275 | return [=] { return script->getSymbolValue(tok, location); }; | |
| 1279 | 1276 | |
| 1280 | 1277 | // Tok is a literal number. |
| 1281 | if (Optional<uint64_t> Val = parseInt(Tok)) | |
| 1282 | return [=] { return *Val; }; | |
| 1278 | if (Optional<uint64_t> val = parseInt(tok)) | |
| 1279 | return [=] { return *val; }; | |
| 1283 | 1280 | |
| 1284 | 1281 | // Tok is a symbol name. |
| 1285 | if (!isValidCIdentifier(Tok)) | |
| 1286 | setError("malformed number: " + Tok); | |
| 1287 | Script->ReferencedSymbols.push_back(Tok); | |
| 1288 | return [=] { return Script->getSymbolValue(Tok, Location); }; | |
| 1282 | if (!isValidCIdentifier(tok)) | |
| 1283 | setError("malformed number: " + tok); | |
| 1284 | script->referencedSymbols.push_back(tok); | |
| 1285 | return [=] { return script->getSymbolValue(tok, location); }; | |
| 1289 | 1286 | } |
| 1290 | 1287 | |
| 1291 | Expr ScriptParser::readTernary(Expr Cond) { | |
| 1292 | Expr L = readExpr(); | |
| 1288 | Expr ScriptParser::readTernary(Expr cond) { | |
| 1289 | Expr l = readExpr(); | |
| 1293 | 1290 | expect(":"); |
| 1294 | Expr R = readExpr(); | |
| 1295 | return [=] { return Cond().getValue() ? L() : R(); }; | |
| 1291 | Expr r = readExpr(); | |
| 1292 | return [=] { return cond().getValue() ? l() : r(); }; | |
| 1296 | 1293 | } |
| 1297 | 1294 | |
| 1298 | 1295 | Expr ScriptParser::readParenExpr() { |
| 1299 | 1296 | expect("("); |
| 1300 | Expr E = readExpr(); | |
| 1297 | Expr e = readExpr(); | |
| 1301 | 1298 | expect(")"); |
| 1302 | return E; | |
| 1299 | return e; | |
| 1303 | 1300 | } |
| 1304 | 1301 | |
| 1305 | 1302 | std::vector<StringRef> ScriptParser::readOutputSectionPhdrs() { |
| 1306 | std::vector<StringRef> Phdrs; | |
| 1303 | std::vector<StringRef> phdrs; | |
| 1307 | 1304 | while (!errorCount() && peek().startswith(":")) { |
| 1308 | StringRef Tok = next(); | |
| 1309 | Phdrs.push_back((Tok.size() == 1) ? next() : Tok.substr(1)); | |
| 1305 | StringRef tok = next(); | |
| 1306 | phdrs.push_back((tok.size() == 1) ? next() : tok.substr(1)); | |
| 1310 | 1307 | } |
| 1311 | return Phdrs; | |
| 1308 | return phdrs; | |
| 1312 | 1309 | } |
| 1313 | 1310 | |
| 1314 | 1311 | // Read a program header type name. The next token must be a |
| 1315 | 1312 | // name of a program header type or a constant (e.g. "0x3"). |
| 1316 | 1313 | unsigned ScriptParser::readPhdrType() { |
| 1317 | StringRef Tok = next(); | |
| 1318 | if (Optional<uint64_t> Val = parseInt(Tok)) | |
| 1319 | return *Val; | |
| 1314 | StringRef tok = next(); | |
| 1315 | if (Optional<uint64_t> val = parseInt(tok)) | |
| 1316 | return *val; | |
| 1320 | 1317 | |
| 1321 | unsigned Ret = StringSwitch<unsigned>(Tok) | |
| 1318 | unsigned ret = StringSwitch<unsigned>(tok) | |
| 1322 | 1319 | .Case("PT_NULL", PT_NULL) |
| 1323 | 1320 | .Case("PT_LOAD", PT_LOAD) |
| 1324 | 1321 | .Case("PT_DYNAMIC", PT_DYNAMIC) |
| ... | ... | @@ -1335,56 +1332,56 @@ unsigned ScriptParser::readPhdrType() { |
| 1335 | 1332 | .Case("PT_OPENBSD_BOOTDATA", PT_OPENBSD_BOOTDATA) |
| 1336 | 1333 | .Default(-1); |
| 1337 | 1334 | |
| 1338 | if (Ret == (unsigned)-1) { | |
| 1339 | setError("invalid program header type: " + Tok); | |
| 1335 | if (ret == (unsigned)-1) { | |
| 1336 | setError("invalid program header type: " + tok); | |
| 1340 | 1337 | return PT_NULL; |
| 1341 | 1338 | } |
| 1342 | return Ret; | |
| 1339 | return ret; | |
| 1343 | 1340 | } |
| 1344 | 1341 | |
| 1345 | 1342 | // Reads an anonymous version declaration. |
| 1346 | 1343 | void ScriptParser::readAnonymousDeclaration() { |
| 1347 | std::vector<SymbolVersion> Locals; | |
| 1348 | std::vector<SymbolVersion> Globals; | |
| 1349 | std::tie(Locals, Globals) = readSymbols(); | |
| 1344 | std::vector<SymbolVersion> locals; | |
| 1345 | std::vector<SymbolVersion> globals; | |
| 1346 | std::tie(locals, globals) = readSymbols(); | |
| 1350 | 1347 | |
| 1351 | for (SymbolVersion V : Locals) { | |
| 1352 | if (V.Name == "*") | |
| 1353 | Config->DefaultSymbolVersion = VER_NDX_LOCAL; | |
| 1348 | for (SymbolVersion v : locals) { | |
| 1349 | if (v.name == "*") | |
| 1350 | config->defaultSymbolVersion = VER_NDX_LOCAL; | |
| 1354 | 1351 | else |
| 1355 | Config->VersionScriptLocals.push_back(V); | |
| 1352 | config->versionScriptLocals.push_back(v); | |
| 1356 | 1353 | } |
| 1357 | 1354 | |
| 1358 | for (SymbolVersion V : Globals) | |
| 1359 | Config->VersionScriptGlobals.push_back(V); | |
| 1355 | for (SymbolVersion v : globals) | |
| 1356 | config->versionScriptGlobals.push_back(v); | |
| 1360 | 1357 | |
| 1361 | 1358 | expect(";"); |
| 1362 | 1359 | } |
| 1363 | 1360 | |
| 1364 | 1361 | // Reads a non-anonymous version definition, |
| 1365 | 1362 | // e.g. "VerStr { global: foo; bar; local: *; };". |
| 1366 | void ScriptParser::readVersionDeclaration(StringRef VerStr) { | |
| 1363 | void ScriptParser::readVersionDeclaration(StringRef verStr) { | |
| 1367 | 1364 | // Read a symbol list. |
| 1368 | std::vector<SymbolVersion> Locals; | |
| 1369 | std::vector<SymbolVersion> Globals; | |
| 1370 | std::tie(Locals, Globals) = readSymbols(); | |
| 1365 | std::vector<SymbolVersion> locals; | |
| 1366 | std::vector<SymbolVersion> globals; | |
| 1367 | std::tie(locals, globals) = readSymbols(); | |
| 1371 | 1368 | |
| 1372 | for (SymbolVersion V : Locals) { | |
| 1373 | if (V.Name == "*") | |
| 1374 | Config->DefaultSymbolVersion = VER_NDX_LOCAL; | |
| 1369 | for (SymbolVersion v : locals) { | |
| 1370 | if (v.name == "*") | |
| 1371 | config->defaultSymbolVersion = VER_NDX_LOCAL; | |
| 1375 | 1372 | else |
| 1376 | Config->VersionScriptLocals.push_back(V); | |
| 1373 | config->versionScriptLocals.push_back(v); | |
| 1377 | 1374 | } |
| 1378 | 1375 | |
| 1379 | 1376 | // Create a new version definition and add that to the global symbols. |
| 1380 | VersionDefinition Ver; | |
| 1381 | Ver.Name = VerStr; | |
| 1382 | Ver.Globals = Globals; | |
| 1377 | VersionDefinition ver; | |
| 1378 | ver.name = verStr; | |
| 1379 | ver.globals = globals; | |
| 1383 | 1380 | |
| 1384 | 1381 | // User-defined version number starts from 2 because 0 and 1 are |
| 1385 | 1382 | // reserved for VER_NDX_LOCAL and VER_NDX_GLOBAL, respectively. |
| 1386 | Ver.Id = Config->VersionDefinitions.size() + 2; | |
| 1387 | Config->VersionDefinitions.push_back(Ver); | |
| 1383 | ver.id = config->versionDefinitions.size() + 2; | |
| 1384 | config->versionDefinitions.push_back(ver); | |
| 1388 | 1385 | |
| 1389 | 1386 | // Each version may have a parent version. For example, "Ver2" |
| 1390 | 1387 | // defined as "Ver2 { global: foo; local: *; } Ver1;" has "Ver1" |
| ... | ... | @@ -1396,39 +1393,39 @@ void ScriptParser::readVersionDeclaration(StringRef VerStr) { |
| 1396 | 1393 | expect(";"); |
| 1397 | 1394 | } |
| 1398 | 1395 | |
| 1399 | static bool hasWildcard(StringRef S) { | |
| 1400 | return S.find_first_of("?*[") != StringRef::npos; | |
| 1396 | static bool hasWildcard(StringRef s) { | |
| 1397 | return s.find_first_of("?*[") != StringRef::npos; | |
| 1401 | 1398 | } |
| 1402 | 1399 | |
| 1403 | 1400 | // Reads a list of symbols, e.g. "{ global: foo; bar; local: *; };". |
| 1404 | 1401 | std::pair<std::vector<SymbolVersion>, std::vector<SymbolVersion>> |
| 1405 | 1402 | ScriptParser::readSymbols() { |
| 1406 | std::vector<SymbolVersion> Locals; | |
| 1407 | std::vector<SymbolVersion> Globals; | |
| 1408 | std::vector<SymbolVersion> *V = &Globals; | |
| 1403 | std::vector<SymbolVersion> locals; | |
| 1404 | std::vector<SymbolVersion> globals; | |
| 1405 | std::vector<SymbolVersion> *v = &globals; | |
| 1409 | 1406 | |
| 1410 | 1407 | while (!errorCount()) { |
| 1411 | 1408 | if (consume("}")) |
| 1412 | 1409 | break; |
| 1413 | 1410 | if (consumeLabel("local")) { |
| 1414 | V = &Locals; | |
| 1411 | v = &locals; | |
| 1415 | 1412 | continue; |
| 1416 | 1413 | } |
| 1417 | 1414 | if (consumeLabel("global")) { |
| 1418 | V = &Globals; | |
| 1415 | v = &globals; | |
| 1419 | 1416 | continue; |
| 1420 | 1417 | } |
| 1421 | 1418 | |
| 1422 | 1419 | if (consume("extern")) { |
| 1423 | std::vector<SymbolVersion> Ext = readVersionExtern(); | |
| 1424 | V->insert(V->end(), Ext.begin(), Ext.end()); | |
| 1420 | std::vector<SymbolVersion> ext = readVersionExtern(); | |
| 1421 | v->insert(v->end(), ext.begin(), ext.end()); | |
| 1425 | 1422 | } else { |
| 1426 | StringRef Tok = next(); | |
| 1427 | V->push_back({unquote(Tok), false, hasWildcard(Tok)}); | |
| 1423 | StringRef tok = next(); | |
| 1424 | v->push_back({unquote(tok), false, hasWildcard(tok)}); | |
| 1428 | 1425 | } |
| 1429 | 1426 | expect(";"); |
| 1430 | 1427 | } |
| 1431 | return {Locals, Globals}; | |
| 1428 | return {locals, globals}; | |
| 1432 | 1429 | } |
| 1433 | 1430 | |
| 1434 | 1431 | // Reads an "extern C++" directive, e.g., |
| ... | ... | @@ -1437,30 +1434,30 @@ ScriptParser::readSymbols() { |
| 1437 | 1434 | // The last semicolon is optional. E.g. this is OK: |
| 1438 | 1435 | // "extern "C++" { ns::*; "f(int, double)" };" |
| 1439 | 1436 | std::vector<SymbolVersion> ScriptParser::readVersionExtern() { |
| 1440 | StringRef Tok = next(); | |
| 1441 | bool IsCXX = Tok == "\"C++\""; | |
| 1442 | if (!IsCXX && Tok != "\"C\"") | |
| 1437 | StringRef tok = next(); | |
| 1438 | bool isCXX = tok == "\"C++\""; | |
| 1439 | if (!isCXX && tok != "\"C\"") | |
| 1443 | 1440 | setError("Unknown language"); |
| 1444 | 1441 | expect("{"); |
| 1445 | 1442 | |
| 1446 | std::vector<SymbolVersion> Ret; | |
| 1443 | std::vector<SymbolVersion> ret; | |
| 1447 | 1444 | while (!errorCount() && peek() != "}") { |
| 1448 | StringRef Tok = next(); | |
| 1449 | bool HasWildcard = !Tok.startswith("\"") && hasWildcard(Tok); | |
| 1450 | Ret.push_back({unquote(Tok), IsCXX, HasWildcard}); | |
| 1445 | StringRef tok = next(); | |
| 1446 | ret.push_back( | |
| 1447 | {unquote(tok), isCXX, !tok.startswith("\"") && hasWildcard(tok)}); | |
| 1451 | 1448 | if (consume("}")) |
| 1452 | return Ret; | |
| 1449 | return ret; | |
| 1453 | 1450 | expect(";"); |
| 1454 | 1451 | } |
| 1455 | 1452 | |
| 1456 | 1453 | expect("}"); |
| 1457 | return Ret; | |
| 1454 | return ret; | |
| 1458 | 1455 | } |
| 1459 | 1456 | |
| 1460 | uint64_t ScriptParser::readMemoryAssignment(StringRef S1, StringRef S2, | |
| 1461 | StringRef S3) { | |
| 1462 | if (!consume(S1) && !consume(S2) && !consume(S3)) { | |
| 1463 | setError("expected one of: " + S1 + ", " + S2 + ", or " + S3); | |
| 1457 | uint64_t ScriptParser::readMemoryAssignment(StringRef s1, StringRef s2, | |
| 1458 | StringRef s3) { | |
| 1459 | if (!consume(s1) && !consume(s2) && !consume(s3)) { | |
| 1460 | setError("expected one of: " + s1 + ", " + s2 + ", or " + s3); | |
| 1464 | 1461 | return 0; |
| 1465 | 1462 | } |
| 1466 | 1463 | expect("="); |
| ... | ... | @@ -1474,28 +1471,28 @@ uint64_t ScriptParser::readMemoryAssignment(StringRef S1, StringRef S2, |
| 1474 | 1471 | void ScriptParser::readMemory() { |
| 1475 | 1472 | expect("{"); |
| 1476 | 1473 | while (!errorCount() && !consume("}")) { |
| 1477 | StringRef Tok = next(); | |
| 1478 | if (Tok == "INCLUDE") { | |
| 1474 | StringRef tok = next(); | |
| 1475 | if (tok == "INCLUDE") { | |
| 1479 | 1476 | readInclude(); |
| 1480 | 1477 | continue; |
| 1481 | 1478 | } |
| 1482 | 1479 | |
| 1483 | uint32_t Flags = 0; | |
| 1484 | uint32_t NegFlags = 0; | |
| 1480 | uint32_t flags = 0; | |
| 1481 | uint32_t negFlags = 0; | |
| 1485 | 1482 | if (consume("(")) { |
| 1486 | std::tie(Flags, NegFlags) = readMemoryAttributes(); | |
| 1483 | std::tie(flags, negFlags) = readMemoryAttributes(); | |
| 1487 | 1484 | expect(")"); |
| 1488 | 1485 | } |
| 1489 | 1486 | expect(":"); |
| 1490 | 1487 | |
| 1491 | uint64_t Origin = readMemoryAssignment("ORIGIN", "org", "o"); | |
| 1488 | uint64_t origin = readMemoryAssignment("ORIGIN", "org", "o"); | |
| 1492 | 1489 | expect(","); |
| 1493 | uint64_t Length = readMemoryAssignment("LENGTH", "len", "l"); | |
| 1490 | uint64_t length = readMemoryAssignment("LENGTH", "len", "l"); | |
| 1494 | 1491 | |
| 1495 | 1492 | // Add the memory region to the region map. |
| 1496 | MemoryRegion *MR = make<MemoryRegion>(Tok, Origin, Length, Flags, NegFlags); | |
| 1497 | if (!Script->MemoryRegions.insert({Tok, MR}).second) | |
| 1498 | setError("region '" + Tok + "' already defined"); | |
| 1493 | MemoryRegion *mr = make<MemoryRegion>(tok, origin, length, flags, negFlags); | |
| 1494 | if (!script->memoryRegions.insert({tok, mr}).second) | |
| 1495 | setError("region '" + tok + "' already defined"); | |
| 1499 | 1496 | } |
| 1500 | 1497 | } |
| 1501 | 1498 | |
| ... | ... | @@ -1503,43 +1500,43 @@ void ScriptParser::readMemory() { |
| 1503 | 1500 | // flags when placing output sections in a memory region. These flags |
| 1504 | 1501 | // are only used when an explicit memory region name is not used. |
| 1505 | 1502 | std::pair<uint32_t, uint32_t> ScriptParser::readMemoryAttributes() { |
| 1506 | uint32_t Flags = 0; | |
| 1507 | uint32_t NegFlags = 0; | |
| 1508 | bool Invert = false; | |
| 1509 | ||
| 1510 | for (char C : next().lower()) { | |
| 1511 | uint32_t Flag = 0; | |
| 1512 | if (C == '!') | |
| 1513 | Invert = !Invert; | |
| 1514 | else if (C == 'w') | |
| 1515 | Flag = SHF_WRITE; | |
| 1516 | else if (C == 'x') | |
| 1517 | Flag = SHF_EXECINSTR; | |
| 1518 | else if (C == 'a') | |
| 1519 | Flag = SHF_ALLOC; | |
| 1520 | else if (C != 'r') | |
| 1503 | uint32_t flags = 0; | |
| 1504 | uint32_t negFlags = 0; | |
| 1505 | bool invert = false; | |
| 1506 | ||
| 1507 | for (char c : next().lower()) { | |
| 1508 | uint32_t flag = 0; | |
| 1509 | if (c == '!') | |
| 1510 | invert = !invert; | |
| 1511 | else if (c == 'w') | |
| 1512 | flag = SHF_WRITE; | |
| 1513 | else if (c == 'x') | |
| 1514 | flag = SHF_EXECINSTR; | |
| 1515 | else if (c == 'a') | |
| 1516 | flag = SHF_ALLOC; | |
| 1517 | else if (c != 'r') | |
| 1521 | 1518 | setError("invalid memory region attribute"); |
| 1522 | 1519 | |
| 1523 | if (Invert) | |
| 1524 | NegFlags |= Flag; | |
| 1520 | if (invert) | |
| 1521 | negFlags |= flag; | |
| 1525 | 1522 | else |
| 1526 | Flags |= Flag; | |
| 1523 | flags |= flag; | |
| 1527 | 1524 | } |
| 1528 | return {Flags, NegFlags}; | |
| 1525 | return {flags, negFlags}; | |
| 1529 | 1526 | } |
| 1530 | 1527 | |
| 1531 | void elf::readLinkerScript(MemoryBufferRef MB) { | |
| 1532 | ScriptParser(MB).readLinkerScript(); | |
| 1528 | void elf::readLinkerScript(MemoryBufferRef mb) { | |
| 1529 | ScriptParser(mb).readLinkerScript(); | |
| 1533 | 1530 | } |
| 1534 | 1531 | |
| 1535 | void elf::readVersionScript(MemoryBufferRef MB) { | |
| 1536 | ScriptParser(MB).readVersionScript(); | |
| 1532 | void elf::readVersionScript(MemoryBufferRef mb) { | |
| 1533 | ScriptParser(mb).readVersionScript(); | |
| 1537 | 1534 | } |
| 1538 | 1535 | |
| 1539 | void elf::readDynamicList(MemoryBufferRef MB) { | |
| 1540 | ScriptParser(MB).readDynamicList(); | |
| 1536 | void elf::readDynamicList(MemoryBufferRef mb) { | |
| 1537 | ScriptParser(mb).readDynamicList(); | |
| 1541 | 1538 | } |
| 1542 | 1539 | |
| 1543 | void elf::readDefsym(StringRef Name, MemoryBufferRef MB) { | |
| 1544 | ScriptParser(MB).readDefsym(Name); | |
| 1540 | void elf::readDefsym(StringRef name, MemoryBufferRef mb) { | |
| 1541 | ScriptParser(mb).readDefsym(name); | |
| 1545 | 1542 | } |
deps/lld/ELF/ScriptParser.h+8-9| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- ScriptParser.h -------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -17,16 +16,16 @@ namespace lld { |
| 17 | 16 | namespace elf { |
| 18 | 17 | |
| 19 | 18 | // Parses a linker script. Calling this function updates |
| 20 | // Config and ScriptConfig. | |
| 21 | void readLinkerScript(MemoryBufferRef MB); | |
| 19 | // lld::elf::config and lld::elf::script. | |
| 20 | void readLinkerScript(MemoryBufferRef mb); | |
| 22 | 21 | |
| 23 | 22 | // Parses a version script. |
| 24 | void readVersionScript(MemoryBufferRef MB); | |
| 23 | void readVersionScript(MemoryBufferRef mb); | |
| 25 | 24 | |
| 26 | void readDynamicList(MemoryBufferRef MB); | |
| 25 | void readDynamicList(MemoryBufferRef mb); | |
| 27 | 26 | |
| 28 | 27 | // Parses the defsym expression. |
| 29 | void readDefsym(StringRef Name, MemoryBufferRef MB); | |
| 28 | void readDefsym(StringRef name, MemoryBufferRef mb); | |
| 30 | 29 | |
| 31 | 30 | } // namespace elf |
| 32 | 31 | } // namespace lld |
deps/lld/ELF/SymbolTable.cpp+143-692| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- SymbolTable.cpp ----------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -31,576 +30,76 @@ using namespace llvm::ELF; |
| 31 | 30 | using namespace lld; |
| 32 | 31 | using namespace lld::elf; |
| 33 | 32 | |
| 34 | SymbolTable *elf::Symtab; | |
| 35 | ||
| 36 | static InputFile *getFirstElf() { | |
| 37 | if (!ObjectFiles.empty()) | |
| 38 | return ObjectFiles[0]; | |
| 39 | if (!SharedFiles.empty()) | |
| 40 | return SharedFiles[0]; | |
| 41 | return BitcodeFiles[0]; | |
| 42 | } | |
| 43 | ||
| 44 | // All input object files must be for the same architecture | |
| 45 | // (e.g. it does not make sense to link x86 object files with | |
| 46 | // MIPS object files.) This function checks for that error. | |
| 47 | static bool isCompatible(InputFile *F) { | |
| 48 | if (!F->isElf() && !isa<BitcodeFile>(F)) | |
| 49 | return true; | |
| 50 | ||
| 51 | if (F->EKind == Config->EKind && F->EMachine == Config->EMachine) { | |
| 52 | if (Config->EMachine != EM_MIPS) | |
| 53 | return true; | |
| 54 | if (isMipsN32Abi(F) == Config->MipsN32Abi) | |
| 55 | return true; | |
| 56 | } | |
| 57 | ||
| 58 | if (!Config->Emulation.empty()) | |
| 59 | error(toString(F) + " is incompatible with " + Config->Emulation); | |
| 60 | else | |
| 61 | error(toString(F) + " is incompatible with " + toString(getFirstElf())); | |
| 62 | return false; | |
| 63 | } | |
| 64 | ||
| 65 | // Add symbols in File to the symbol table. | |
| 66 | template <class ELFT> void SymbolTable::addFile(InputFile *File) { | |
| 67 | if (!isCompatible(File)) | |
| 68 | return; | |
| 69 | ||
| 70 | // Binary file | |
| 71 | if (auto *F = dyn_cast<BinaryFile>(File)) { | |
| 72 | BinaryFiles.push_back(F); | |
| 73 | F->parse(); | |
| 74 | return; | |
| 75 | } | |
| 76 | ||
| 77 | // .a file | |
| 78 | if (auto *F = dyn_cast<ArchiveFile>(File)) { | |
| 79 | F->parse<ELFT>(); | |
| 80 | return; | |
| 81 | } | |
| 82 | ||
| 83 | // Lazy object file | |
| 84 | if (auto *F = dyn_cast<LazyObjFile>(File)) { | |
| 85 | LazyObjFiles.push_back(F); | |
| 86 | F->parse<ELFT>(); | |
| 87 | return; | |
| 88 | } | |
| 89 | ||
| 90 | if (Config->Trace) | |
| 91 | message(toString(File)); | |
| 92 | ||
| 93 | // .so file | |
| 94 | if (auto *F = dyn_cast<SharedFile<ELFT>>(File)) { | |
| 95 | // DSOs are uniquified not by filename but by soname. | |
| 96 | F->parseSoName(); | |
| 97 | if (errorCount()) | |
| 98 | return; | |
| 99 | ||
| 100 | // If a DSO appears more than once on the command line with and without | |
| 101 | // --as-needed, --no-as-needed takes precedence over --as-needed because a | |
| 102 | // user can add an extra DSO with --no-as-needed to force it to be added to | |
| 103 | // the dependency list. | |
| 104 | DenseMap<StringRef, InputFile *>::iterator It; | |
| 105 | bool WasInserted; | |
| 106 | std::tie(It, WasInserted) = SoNames.try_emplace(F->SoName, F); | |
| 107 | cast<SharedFile<ELFT>>(It->second)->IsNeeded |= F->IsNeeded; | |
| 108 | if (!WasInserted) | |
| 109 | return; | |
| 110 | ||
| 111 | SharedFiles.push_back(F); | |
| 112 | F->parseRest(); | |
| 113 | return; | |
| 114 | } | |
| 115 | ||
| 116 | // LLVM bitcode file | |
| 117 | if (auto *F = dyn_cast<BitcodeFile>(File)) { | |
| 118 | BitcodeFiles.push_back(F); | |
| 119 | F->parse<ELFT>(ComdatGroups); | |
| 120 | return; | |
| 121 | } | |
| 122 | ||
| 123 | // Regular object file | |
| 124 | ObjectFiles.push_back(File); | |
| 125 | cast<ObjFile<ELFT>>(File)->parse(ComdatGroups); | |
| 126 | } | |
| 127 | ||
| 128 | // This function is where all the optimizations of link-time | |
| 129 | // optimization happens. When LTO is in use, some input files are | |
| 130 | // not in native object file format but in the LLVM bitcode format. | |
| 131 | // This function compiles bitcode files into a few big native files | |
| 132 | // using LLVM functions and replaces bitcode symbols with the results. | |
| 133 | // Because all bitcode files that the program consists of are passed | |
| 134 | // to the compiler at once, it can do whole-program optimization. | |
| 135 | template <class ELFT> void SymbolTable::addCombinedLTOObject() { | |
| 136 | if (BitcodeFiles.empty()) | |
| 137 | return; | |
| 138 | ||
| 139 | // Compile bitcode files and replace bitcode symbols. | |
| 140 | LTO.reset(new BitcodeCompiler); | |
| 141 | for (BitcodeFile *F : BitcodeFiles) | |
| 142 | LTO->add(*F); | |
| 143 | ||
| 144 | for (InputFile *File : LTO->compile()) { | |
| 145 | DenseSet<CachedHashStringRef> DummyGroups; | |
| 146 | auto *Obj = cast<ObjFile<ELFT>>(File); | |
| 147 | Obj->parse(DummyGroups); | |
| 148 | for (Symbol *Sym : Obj->getGlobalSymbols()) | |
| 149 | Sym->parseSymbolVersion(); | |
| 150 | ObjectFiles.push_back(File); | |
| 151 | } | |
| 152 | } | |
| 153 | ||
| 154 | // Set a flag for --trace-symbol so that we can print out a log message | |
| 155 | // if a new symbol with the same name is inserted into the symbol table. | |
| 156 | void SymbolTable::trace(StringRef Name) { | |
| 157 | SymMap.insert({CachedHashStringRef(Name), -1}); | |
| 158 | } | |
| 33 | SymbolTable *elf::symtab; | |
| 159 | 34 | |
| 160 | void SymbolTable::wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap) { | |
| 35 | void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) { | |
| 161 | 36 | // Swap symbols as instructed by -wrap. |
| 162 | int &Idx1 = SymMap[CachedHashStringRef(Sym->getName())]; | |
| 163 | int &Idx2 = SymMap[CachedHashStringRef(Real->getName())]; | |
| 164 | int &Idx3 = SymMap[CachedHashStringRef(Wrap->getName())]; | |
| 37 | int &idx1 = symMap[CachedHashStringRef(sym->getName())]; | |
| 38 | int &idx2 = symMap[CachedHashStringRef(real->getName())]; | |
| 39 | int &idx3 = symMap[CachedHashStringRef(wrap->getName())]; | |
| 165 | 40 | |
| 166 | Idx2 = Idx1; | |
| 167 | Idx1 = Idx3; | |
| 41 | idx2 = idx1; | |
| 42 | idx1 = idx3; | |
| 168 | 43 | |
| 169 | 44 | // Now renaming is complete. No one refers Real symbol. We could leave |
| 170 | 45 | // Real as-is, but if Real is written to the symbol table, that may |
| 171 | 46 | // contain irrelevant values. So, we copy all values from Sym to Real. |
| 172 | StringRef S = Real->getName(); | |
| 173 | memcpy(Real, Sym, sizeof(SymbolUnion)); | |
| 174 | Real->setName(S); | |
| 175 | } | |
| 176 | ||
| 177 | static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { | |
| 178 | if (VA == STV_DEFAULT) | |
| 179 | return VB; | |
| 180 | if (VB == STV_DEFAULT) | |
| 181 | return VA; | |
| 182 | return std::min(VA, VB); | |
| 47 | StringRef s = real->getName(); | |
| 48 | memcpy(real, sym, sizeof(SymbolUnion)); | |
| 49 | real->setName(s); | |
| 183 | 50 | } |
| 184 | 51 | |
| 185 | // Find an existing symbol or create and insert a new one. | |
| 186 | std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) { | |
| 52 | // Find an existing symbol or create a new one. | |
| 53 | Symbol *SymbolTable::insert(StringRef name) { | |
| 187 | 54 | // <name>@@<version> means the symbol is the default version. In that |
| 188 | 55 | // case <name>@@<version> will be used to resolve references to <name>. |
| 189 | 56 | // |
| 190 | 57 | // Since this is a hot path, the following string search code is |
| 191 | 58 | // optimized for speed. StringRef::find(char) is much faster than |
| 192 | 59 | // StringRef::find(StringRef). |
| 193 | size_t Pos = Name.find('@'); | |
| 194 | if (Pos != StringRef::npos && Pos + 1 < Name.size() && Name[Pos + 1] == '@') | |
| 195 | Name = Name.take_front(Pos); | |
| 196 | ||
| 197 | auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()}); | |
| 198 | int &SymIndex = P.first->second; | |
| 199 | bool IsNew = P.second; | |
| 200 | bool Traced = false; | |
| 201 | ||
| 202 | if (SymIndex == -1) { | |
| 203 | SymIndex = SymVector.size(); | |
| 204 | IsNew = true; | |
| 205 | Traced = true; | |
| 206 | } | |
| 207 | ||
| 208 | if (!IsNew) | |
| 209 | return {SymVector[SymIndex], false}; | |
| 210 | ||
| 211 | auto *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); | |
| 212 | Sym->SymbolKind = Symbol::PlaceholderKind; | |
| 213 | Sym->Visibility = STV_DEFAULT; | |
| 214 | Sym->IsUsedInRegularObj = false; | |
| 215 | Sym->ExportDynamic = false; | |
| 216 | Sym->CanInline = true; | |
| 217 | Sym->Traced = Traced; | |
| 218 | Sym->VersionId = Config->DefaultSymbolVersion; | |
| 219 | SymVector.push_back(Sym); | |
| 220 | return {Sym, true}; | |
| 60 | size_t pos = name.find('@'); | |
| 61 | if (pos != StringRef::npos && pos + 1 < name.size() && name[pos + 1] == '@') | |
| 62 | name = name.take_front(pos); | |
| 63 | ||
| 64 | auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()}); | |
| 65 | int &symIndex = p.first->second; | |
| 66 | bool isNew = p.second; | |
| 67 | ||
| 68 | if (!isNew) | |
| 69 | return symVector[symIndex]; | |
| 70 | ||
| 71 | Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); | |
| 72 | symVector.push_back(sym); | |
| 73 | ||
| 74 | sym->setName(name); | |
| 75 | sym->symbolKind = Symbol::PlaceholderKind; | |
| 76 | sym->versionId = config->defaultSymbolVersion; | |
| 77 | sym->visibility = STV_DEFAULT; | |
| 78 | sym->isUsedInRegularObj = false; | |
| 79 | sym->exportDynamic = false; | |
| 80 | sym->canInline = true; | |
| 81 | sym->scriptDefined = false; | |
| 82 | sym->partition = 1; | |
| 83 | return sym; | |
| 221 | 84 | } |
| 222 | 85 | |
| 223 | // Find an existing symbol or create and insert a new one, then apply the given | |
| 224 | // attributes. | |
| 225 | std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, | |
| 226 | uint8_t Visibility, | |
| 227 | bool CanOmitFromDynSym, | |
| 228 | InputFile *File) { | |
| 229 | Symbol *S; | |
| 230 | bool WasInserted; | |
| 231 | std::tie(S, WasInserted) = insertName(Name); | |
| 232 | ||
| 233 | // Merge in the new symbol's visibility. | |
| 234 | S->Visibility = getMinVisibility(S->Visibility, Visibility); | |
| 235 | ||
| 236 | if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic)) | |
| 237 | S->ExportDynamic = true; | |
| 238 | ||
| 239 | if (!File || File->kind() == InputFile::ObjKind) | |
| 240 | S->IsUsedInRegularObj = true; | |
| 241 | ||
| 242 | return {S, WasInserted}; | |
| 86 | Symbol *SymbolTable::addSymbol(const Symbol &New) { | |
| 87 | Symbol *sym = symtab->insert(New.getName()); | |
| 88 | sym->resolve(New); | |
| 89 | return sym; | |
| 243 | 90 | } |
| 244 | 91 | |
| 245 | static uint8_t getVisibility(uint8_t StOther) { return StOther & 3; } | |
| 246 | ||
| 247 | template <class ELFT> | |
| 248 | Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding, | |
| 249 | uint8_t StOther, uint8_t Type, | |
| 250 | bool CanOmitFromDynSym, InputFile *File) { | |
| 251 | Symbol *S; | |
| 252 | bool WasInserted; | |
| 253 | uint8_t Visibility = getVisibility(StOther); | |
| 254 | std::tie(S, WasInserted) = insert(Name, Visibility, CanOmitFromDynSym, File); | |
| 255 | ||
| 256 | // An undefined symbol with non default visibility must be satisfied | |
| 257 | // in the same DSO. | |
| 258 | if (WasInserted || (isa<SharedSymbol>(S) && Visibility != STV_DEFAULT)) { | |
| 259 | replaceSymbol<Undefined>(S, File, Name, Binding, StOther, Type); | |
| 260 | return S; | |
| 261 | } | |
| 262 | ||
| 263 | if (S->isShared() || S->isLazy() || (S->isUndefined() && Binding != STB_WEAK)) | |
| 264 | S->Binding = Binding; | |
| 265 | ||
| 266 | if (S->isLazy()) { | |
| 267 | // An undefined weak will not fetch archive members. See comment on Lazy in | |
| 268 | // Symbols.h for the details. | |
| 269 | if (Binding == STB_WEAK) { | |
| 270 | S->Type = Type; | |
| 271 | return S; | |
| 272 | } | |
| 273 | ||
| 274 | // Do extra check for --warn-backrefs. | |
| 275 | // | |
| 276 | // --warn-backrefs is an option to prevent an undefined reference from | |
| 277 | // fetching an archive member written earlier in the command line. It can be | |
| 278 | // used to keep compatibility with GNU linkers to some degree. | |
| 279 | // I'll explain the feature and why you may find it useful in this comment. | |
| 280 | // | |
| 281 | // lld's symbol resolution semantics is more relaxed than traditional Unix | |
| 282 | // linkers. For example, | |
| 283 | // | |
| 284 | // ld.lld foo.a bar.o | |
| 285 | // | |
| 286 | // succeeds even if bar.o contains an undefined symbol that has to be | |
| 287 | // resolved by some object file in foo.a. Traditional Unix linkers don't | |
| 288 | // allow this kind of backward reference, as they visit each file only once | |
| 289 | // from left to right in the command line while resolving all undefined | |
| 290 | // symbols at the moment of visiting. | |
| 291 | // | |
| 292 | // In the above case, since there's no undefined symbol when a linker visits | |
| 293 | // foo.a, no files are pulled out from foo.a, and because the linker forgets | |
| 294 | // about foo.a after visiting, it can't resolve undefined symbols in bar.o | |
| 295 | // that could have been resolved otherwise. | |
| 296 | // | |
| 297 | // That lld accepts more relaxed form means that (besides it'd make more | |
| 298 | // sense) you can accidentally write a command line or a build file that | |
| 299 | // works only with lld, even if you have a plan to distribute it to wider | |
| 300 | // users who may be using GNU linkers. With --warn-backrefs, you can detect | |
| 301 | // a library order that doesn't work with other Unix linkers. | |
| 302 | // | |
| 303 | // The option is also useful to detect cyclic dependencies between static | |
| 304 | // archives. Again, lld accepts | |
| 305 | // | |
| 306 | // ld.lld foo.a bar.a | |
| 307 | // | |
| 308 | // even if foo.a and bar.a depend on each other. With --warn-backrefs, it is | |
| 309 | // handled as an error. | |
| 310 | // | |
| 311 | // Here is how the option works. We assign a group ID to each file. A file | |
| 312 | // with a smaller group ID can pull out object files from an archive file | |
| 313 | // with an equal or greater group ID. Otherwise, it is a reverse dependency | |
| 314 | // and an error. | |
| 315 | // | |
| 316 | // A file outside --{start,end}-group gets a fresh ID when instantiated. All | |
| 317 | // files within the same --{start,end}-group get the same group ID. E.g. | |
| 318 | // | |
| 319 | // ld.lld A B --start-group C D --end-group E | |
| 320 | // | |
| 321 | // A forms group 0. B form group 1. C and D (including their member object | |
| 322 | // files) form group 2. E forms group 3. I think that you can see how this | |
| 323 | // group assignment rule simulates the traditional linker's semantics. | |
| 324 | bool Backref = | |
| 325 | Config->WarnBackrefs && File && S->File->GroupId < File->GroupId; | |
| 326 | fetchLazy<ELFT>(S); | |
| 327 | ||
| 328 | // We don't report backward references to weak symbols as they can be | |
| 329 | // overridden later. | |
| 330 | if (Backref && S->Binding != STB_WEAK) | |
| 331 | warn("backward reference detected: " + Name + " in " + toString(File) + | |
| 332 | " refers to " + toString(S->File)); | |
| 333 | } | |
| 334 | return S; | |
| 335 | } | |
| 336 | ||
| 337 | // Using .symver foo,foo@@VER unfortunately creates two symbols: foo and | |
| 338 | // foo@@VER. We want to effectively ignore foo, so give precedence to | |
| 339 | // foo@@VER. | |
| 340 | // FIXME: If users can transition to using | |
| 341 | // .symver foo,foo@@@VER | |
| 342 | // we can delete this hack. | |
| 343 | static int compareVersion(Symbol *S, StringRef Name) { | |
| 344 | bool A = Name.contains("@@"); | |
| 345 | bool B = S->getName().contains("@@"); | |
| 346 | if (A && !B) | |
| 347 | return 1; | |
| 348 | if (!A && B) | |
| 349 | return -1; | |
| 350 | return 0; | |
| 351 | } | |
| 352 | ||
| 353 | // We have a new defined symbol with the specified binding. Return 1 if the new | |
| 354 | // symbol should win, -1 if the new symbol should lose, or 0 if both symbols are | |
| 355 | // strong defined symbols. | |
| 356 | static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding, | |
| 357 | StringRef Name) { | |
| 358 | if (WasInserted) | |
| 359 | return 1; | |
| 360 | if (!S->isDefined()) | |
| 361 | return 1; | |
| 362 | if (int R = compareVersion(S, Name)) | |
| 363 | return R; | |
| 364 | if (Binding == STB_WEAK) | |
| 365 | return -1; | |
| 366 | if (S->isWeak()) | |
| 367 | return 1; | |
| 368 | return 0; | |
| 369 | } | |
| 370 | ||
| 371 | // We have a new non-common defined symbol with the specified binding. Return 1 | |
| 372 | // if the new symbol should win, -1 if the new symbol should lose, or 0 if there | |
| 373 | // is a conflict. If the new symbol wins, also update the binding. | |
| 374 | static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding, | |
| 375 | bool IsAbsolute, uint64_t Value, | |
| 376 | StringRef Name) { | |
| 377 | if (int Cmp = compareDefined(S, WasInserted, Binding, Name)) | |
| 378 | return Cmp; | |
| 379 | if (auto *R = dyn_cast<Defined>(S)) { | |
| 380 | if (R->Section && isa<BssSection>(R->Section)) { | |
| 381 | // Non-common symbols take precedence over common symbols. | |
| 382 | if (Config->WarnCommon) | |
| 383 | warn("common " + S->getName() + " is overridden"); | |
| 384 | return 1; | |
| 385 | } | |
| 386 | if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute && | |
| 387 | R->Value == Value) | |
| 388 | return -1; | |
| 389 | } | |
| 390 | return 0; | |
| 391 | } | |
| 392 | ||
| 393 | Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment, | |
| 394 | uint8_t Binding, uint8_t StOther, uint8_t Type, | |
| 395 | InputFile &File) { | |
| 396 | Symbol *S; | |
| 397 | bool WasInserted; | |
| 398 | std::tie(S, WasInserted) = insert(N, getVisibility(StOther), | |
| 399 | /*CanOmitFromDynSym*/ false, &File); | |
| 400 | ||
| 401 | int Cmp = compareDefined(S, WasInserted, Binding, N); | |
| 402 | if (Cmp < 0) | |
| 403 | return S; | |
| 404 | ||
| 405 | if (Cmp > 0) { | |
| 406 | auto *Bss = make<BssSection>("COMMON", Size, Alignment); | |
| 407 | Bss->File = &File; | |
| 408 | Bss->Live = !Config->GcSections; | |
| 409 | InputSections.push_back(Bss); | |
| 410 | ||
| 411 | replaceSymbol<Defined>(S, &File, N, Binding, StOther, Type, 0, Size, Bss); | |
| 412 | return S; | |
| 413 | } | |
| 414 | ||
| 415 | auto *D = cast<Defined>(S); | |
| 416 | auto *Bss = dyn_cast_or_null<BssSection>(D->Section); | |
| 417 | if (!Bss) { | |
| 418 | // Non-common symbols take precedence over common symbols. | |
| 419 | if (Config->WarnCommon) | |
| 420 | warn("common " + S->getName() + " is overridden"); | |
| 421 | return S; | |
| 422 | } | |
| 423 | ||
| 424 | if (Config->WarnCommon) | |
| 425 | warn("multiple common of " + D->getName()); | |
| 426 | ||
| 427 | Bss->Alignment = std::max(Bss->Alignment, Alignment); | |
| 428 | if (Size > Bss->Size) { | |
| 429 | D->File = Bss->File = &File; | |
| 430 | D->Size = Bss->Size = Size; | |
| 431 | } | |
| 432 | return S; | |
| 433 | } | |
| 434 | ||
| 435 | static void reportDuplicate(Symbol *Sym, InputFile *NewFile, | |
| 436 | InputSectionBase *ErrSec, uint64_t ErrOffset) { | |
| 437 | if (Config->AllowMultipleDefinition) | |
| 438 | return; | |
| 439 | ||
| 440 | Defined *D = cast<Defined>(Sym); | |
| 441 | if (!D->Section || !ErrSec) { | |
| 442 | error("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " + | |
| 443 | toString(Sym->File) + "\n>>> defined in " + toString(NewFile)); | |
| 444 | return; | |
| 445 | } | |
| 446 | ||
| 447 | // Construct and print an error message in the form of: | |
| 448 | // | |
| 449 | // ld.lld: error: duplicate symbol: foo | |
| 450 | // >>> defined at bar.c:30 | |
| 451 | // >>> bar.o (/home/alice/src/bar.o) | |
| 452 | // >>> defined at baz.c:563 | |
| 453 | // >>> baz.o in archive libbaz.a | |
| 454 | auto *Sec1 = cast<InputSectionBase>(D->Section); | |
| 455 | std::string Src1 = Sec1->getSrcMsg(*Sym, D->Value); | |
| 456 | std::string Obj1 = Sec1->getObjMsg(D->Value); | |
| 457 | std::string Src2 = ErrSec->getSrcMsg(*Sym, ErrOffset); | |
| 458 | std::string Obj2 = ErrSec->getObjMsg(ErrOffset); | |
| 459 | ||
| 460 | std::string Msg = "duplicate symbol: " + toString(*Sym) + "\n>>> defined at "; | |
| 461 | if (!Src1.empty()) | |
| 462 | Msg += Src1 + "\n>>> "; | |
| 463 | Msg += Obj1 + "\n>>> defined at "; | |
| 464 | if (!Src2.empty()) | |
| 465 | Msg += Src2 + "\n>>> "; | |
| 466 | Msg += Obj2; | |
| 467 | error(Msg); | |
| 468 | } | |
| 469 | ||
| 470 | Defined *SymbolTable::addDefined(StringRef Name, uint8_t StOther, uint8_t Type, | |
| 471 | uint64_t Value, uint64_t Size, uint8_t Binding, | |
| 472 | SectionBase *Section, InputFile *File) { | |
| 473 | Symbol *S; | |
| 474 | bool WasInserted; | |
| 475 | std::tie(S, WasInserted) = insert(Name, getVisibility(StOther), | |
| 476 | /*CanOmitFromDynSym*/ false, File); | |
| 477 | int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, Section == nullptr, | |
| 478 | Value, Name); | |
| 479 | if (Cmp > 0) | |
| 480 | replaceSymbol<Defined>(S, File, Name, Binding, StOther, Type, Value, Size, | |
| 481 | Section); | |
| 482 | else if (Cmp == 0) | |
| 483 | reportDuplicate(S, File, dyn_cast_or_null<InputSectionBase>(Section), | |
| 484 | Value); | |
| 485 | return cast<Defined>(S); | |
| 486 | } | |
| 487 | ||
| 488 | template <typename ELFT> | |
| 489 | void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> &File, | |
| 490 | const typename ELFT::Sym &Sym, uint32_t Alignment, | |
| 491 | uint32_t VerdefIndex) { | |
| 492 | // DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT | |
| 493 | // as the visibility, which will leave the visibility in the symbol table | |
| 494 | // unchanged. | |
| 495 | Symbol *S; | |
| 496 | bool WasInserted; | |
| 497 | std::tie(S, WasInserted) = insert(Name, STV_DEFAULT, | |
| 498 | /*CanOmitFromDynSym*/ true, &File); | |
| 499 | // Make sure we preempt DSO symbols with default visibility. | |
| 500 | if (Sym.getVisibility() == STV_DEFAULT) | |
| 501 | S->ExportDynamic = true; | |
| 502 | ||
| 503 | // An undefined symbol with non default visibility must be satisfied | |
| 504 | // in the same DSO. | |
| 505 | auto Replace = [&](uint8_t Binding) { | |
| 506 | replaceSymbol<SharedSymbol>(S, File, Name, Binding, Sym.st_other, | |
| 507 | Sym.getType(), Sym.st_value, Sym.st_size, | |
| 508 | Alignment, VerdefIndex); | |
| 509 | }; | |
| 510 | ||
| 511 | if (WasInserted) | |
| 512 | Replace(Sym.getBinding()); | |
| 513 | else if (S->Visibility == STV_DEFAULT && (S->isUndefined() || S->isLazy())) | |
| 514 | Replace(S->Binding); | |
| 515 | } | |
| 516 | ||
| 517 | Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding, | |
| 518 | uint8_t StOther, uint8_t Type, | |
| 519 | bool CanOmitFromDynSym, BitcodeFile &F) { | |
| 520 | Symbol *S; | |
| 521 | bool WasInserted; | |
| 522 | std::tie(S, WasInserted) = | |
| 523 | insert(Name, getVisibility(StOther), CanOmitFromDynSym, &F); | |
| 524 | int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, | |
| 525 | /*IsAbs*/ false, /*Value*/ 0, Name); | |
| 526 | if (Cmp > 0) | |
| 527 | replaceSymbol<Defined>(S, &F, Name, Binding, StOther, Type, 0, 0, nullptr); | |
| 528 | else if (Cmp == 0) | |
| 529 | reportDuplicate(S, &F, nullptr, 0); | |
| 530 | return S; | |
| 531 | } | |
| 532 | ||
| 533 | Symbol *SymbolTable::find(StringRef Name) { | |
| 534 | auto It = SymMap.find(CachedHashStringRef(Name)); | |
| 535 | if (It == SymMap.end()) | |
| 92 | Symbol *SymbolTable::find(StringRef name) { | |
| 93 | auto it = symMap.find(CachedHashStringRef(name)); | |
| 94 | if (it == symMap.end()) | |
| 536 | 95 | return nullptr; |
| 537 | if (It->second == -1) | |
| 96 | Symbol *sym = symVector[it->second]; | |
| 97 | if (sym->isPlaceholder()) | |
| 538 | 98 | return nullptr; |
| 539 | return SymVector[It->second]; | |
| 99 | return sym; | |
| 540 | 100 | } |
| 541 | 101 | |
| 542 | template <class ELFT> | |
| 543 | void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &File, | |
| 544 | const object::Archive::Symbol Sym) { | |
| 545 | Symbol *S; | |
| 546 | bool WasInserted; | |
| 547 | std::tie(S, WasInserted) = insertName(Name); | |
| 548 | if (WasInserted) { | |
| 549 | replaceSymbol<LazyArchive>(S, File, STT_NOTYPE, Sym); | |
| 550 | return; | |
| 551 | } | |
| 552 | if (!S->isUndefined()) | |
| 553 | return; | |
| 554 | ||
| 555 | // An undefined weak will not fetch archive members. See comment on Lazy in | |
| 556 | // Symbols.h for the details. | |
| 557 | if (S->isWeak()) { | |
| 558 | replaceSymbol<LazyArchive>(S, File, S->Type, Sym); | |
| 559 | S->Binding = STB_WEAK; | |
| 560 | return; | |
| 561 | } | |
| 562 | ||
| 563 | if (InputFile *F = File.fetch(Sym)) | |
| 564 | addFile<ELFT>(F); | |
| 565 | } | |
| 566 | ||
| 567 | template <class ELFT> | |
| 568 | void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &File) { | |
| 569 | Symbol *S; | |
| 570 | bool WasInserted; | |
| 571 | std::tie(S, WasInserted) = insertName(Name); | |
| 572 | if (WasInserted) { | |
| 573 | replaceSymbol<LazyObject>(S, File, STT_NOTYPE, Name); | |
| 574 | return; | |
| 575 | } | |
| 576 | if (!S->isUndefined()) | |
| 577 | return; | |
| 578 | ||
| 579 | // An undefined weak will not fetch archive members. See comment on Lazy in | |
| 580 | // Symbols.h for the details. | |
| 581 | if (S->isWeak()) { | |
| 582 | replaceSymbol<LazyObject>(S, File, S->Type, Name); | |
| 583 | S->Binding = STB_WEAK; | |
| 584 | return; | |
| 585 | } | |
| 586 | ||
| 587 | if (InputFile *F = File.fetch()) | |
| 588 | addFile<ELFT>(F); | |
| 589 | } | |
| 590 | ||
| 591 | template <class ELFT> void SymbolTable::fetchLazy(Symbol *Sym) { | |
| 592 | if (auto *S = dyn_cast<LazyArchive>(Sym)) { | |
| 593 | if (InputFile *File = S->fetch()) | |
| 594 | addFile<ELFT>(File); | |
| 595 | return; | |
| 596 | } | |
| 597 | ||
| 598 | auto *S = cast<LazyObject>(Sym); | |
| 599 | if (InputFile *File = cast<LazyObjFile>(S->File)->fetch()) | |
| 600 | addFile<ELFT>(File); | |
| 601 | } | |
| 602 | ||
| 603 | // Initialize DemangledSyms with a map from demangled symbols to symbol | |
| 102 | // Initialize demangledSyms with a map from demangled symbols to symbol | |
| 604 | 103 | // objects. Used to handle "extern C++" directive in version scripts. |
| 605 | 104 | // |
| 606 | 105 | // The map will contain all demangled symbols. That can be very large, |
| ... | ... | @@ -614,204 +113,156 @@ template <class ELFT> void SymbolTable::fetchLazy(Symbol *Sym) { |
| 614 | 113 | // So, if "extern C++" feature is used, we need to demangle all known |
| 615 | 114 | // symbols. |
| 616 | 115 | StringMap<std::vector<Symbol *>> &SymbolTable::getDemangledSyms() { |
| 617 | if (!DemangledSyms) { | |
| 618 | DemangledSyms.emplace(); | |
| 619 | for (Symbol *Sym : SymVector) { | |
| 620 | if (!Sym->isDefined()) | |
| 116 | if (!demangledSyms) { | |
| 117 | demangledSyms.emplace(); | |
| 118 | for (Symbol *sym : symVector) { | |
| 119 | if (!sym->isDefined() && !sym->isCommon()) | |
| 621 | 120 | continue; |
| 622 | if (Optional<std::string> S = demangleItanium(Sym->getName())) | |
| 623 | (*DemangledSyms)[*S].push_back(Sym); | |
| 121 | if (Optional<std::string> s = demangleItanium(sym->getName())) | |
| 122 | (*demangledSyms)[*s].push_back(sym); | |
| 624 | 123 | else |
| 625 | (*DemangledSyms)[Sym->getName()].push_back(Sym); | |
| 124 | (*demangledSyms)[sym->getName()].push_back(sym); | |
| 626 | 125 | } |
| 627 | 126 | } |
| 628 | return *DemangledSyms; | |
| 127 | return *demangledSyms; | |
| 629 | 128 | } |
| 630 | 129 | |
| 631 | std::vector<Symbol *> SymbolTable::findByVersion(SymbolVersion Ver) { | |
| 632 | if (Ver.IsExternCpp) | |
| 633 | return getDemangledSyms().lookup(Ver.Name); | |
| 634 | if (Symbol *B = find(Ver.Name)) | |
| 635 | if (B->isDefined()) | |
| 636 | return {B}; | |
| 130 | std::vector<Symbol *> SymbolTable::findByVersion(SymbolVersion ver) { | |
| 131 | if (ver.isExternCpp) | |
| 132 | return getDemangledSyms().lookup(ver.name); | |
| 133 | if (Symbol *b = find(ver.name)) | |
| 134 | if (b->isDefined() || b->isCommon()) | |
| 135 | return {b}; | |
| 637 | 136 | return {}; |
| 638 | 137 | } |
| 639 | 138 | |
| 640 | std::vector<Symbol *> SymbolTable::findAllByVersion(SymbolVersion Ver) { | |
| 641 | std::vector<Symbol *> Res; | |
| 642 | StringMatcher M(Ver.Name); | |
| 139 | std::vector<Symbol *> SymbolTable::findAllByVersion(SymbolVersion ver) { | |
| 140 | std::vector<Symbol *> res; | |
| 141 | StringMatcher m(ver.name); | |
| 643 | 142 | |
| 644 | if (Ver.IsExternCpp) { | |
| 645 | for (auto &P : getDemangledSyms()) | |
| 646 | if (M.match(P.first())) | |
| 647 | Res.insert(Res.end(), P.second.begin(), P.second.end()); | |
| 648 | return Res; | |
| 143 | if (ver.isExternCpp) { | |
| 144 | for (auto &p : getDemangledSyms()) | |
| 145 | if (m.match(p.first())) | |
| 146 | res.insert(res.end(), p.second.begin(), p.second.end()); | |
| 147 | return res; | |
| 649 | 148 | } |
| 650 | 149 | |
| 651 | for (Symbol *Sym : SymVector) | |
| 652 | if (Sym->isDefined() && M.match(Sym->getName())) | |
| 653 | Res.push_back(Sym); | |
| 654 | return Res; | |
| 655 | } | |
| 656 | ||
| 657 | // If there's only one anonymous version definition in a version | |
| 658 | // script file, the script does not actually define any symbol version, | |
| 659 | // but just specifies symbols visibilities. | |
| 660 | void SymbolTable::handleAnonymousVersion() { | |
| 661 | for (SymbolVersion &Ver : Config->VersionScriptGlobals) | |
| 662 | assignExactVersion(Ver, VER_NDX_GLOBAL, "global"); | |
| 663 | for (SymbolVersion &Ver : Config->VersionScriptGlobals) | |
| 664 | assignWildcardVersion(Ver, VER_NDX_GLOBAL); | |
| 665 | for (SymbolVersion &Ver : Config->VersionScriptLocals) | |
| 666 | assignExactVersion(Ver, VER_NDX_LOCAL, "local"); | |
| 667 | for (SymbolVersion &Ver : Config->VersionScriptLocals) | |
| 668 | assignWildcardVersion(Ver, VER_NDX_LOCAL); | |
| 150 | for (Symbol *sym : symVector) | |
| 151 | if ((sym->isDefined() || sym->isCommon()) && m.match(sym->getName())) | |
| 152 | res.push_back(sym); | |
| 153 | return res; | |
| 669 | 154 | } |
| 670 | 155 | |
| 671 | 156 | // Handles -dynamic-list. |
| 672 | 157 | void SymbolTable::handleDynamicList() { |
| 673 | for (SymbolVersion &Ver : Config->DynamicList) { | |
| 674 | std::vector<Symbol *> Syms; | |
| 675 | if (Ver.HasWildcard) | |
| 676 | Syms = findAllByVersion(Ver); | |
| 158 | for (SymbolVersion &ver : config->dynamicList) { | |
| 159 | std::vector<Symbol *> syms; | |
| 160 | if (ver.hasWildcard) | |
| 161 | syms = findAllByVersion(ver); | |
| 677 | 162 | else |
| 678 | Syms = findByVersion(Ver); | |
| 163 | syms = findByVersion(ver); | |
| 679 | 164 | |
| 680 | for (Symbol *B : Syms) { | |
| 681 | if (!Config->Shared) | |
| 682 | B->ExportDynamic = true; | |
| 683 | else if (B->includeInDynsym()) | |
| 684 | B->IsPreemptible = true; | |
| 165 | for (Symbol *b : syms) { | |
| 166 | if (!config->shared) | |
| 167 | b->exportDynamic = true; | |
| 168 | else if (b->includeInDynsym()) | |
| 169 | b->isPreemptible = true; | |
| 685 | 170 | } |
| 686 | 171 | } |
| 687 | 172 | } |
| 688 | 173 | |
| 689 | 174 | // Set symbol versions to symbols. This function handles patterns |
| 690 | 175 | // containing no wildcard characters. |
| 691 | void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId, | |
| 692 | StringRef VersionName) { | |
| 693 | if (Ver.HasWildcard) | |
| 176 | void SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId, | |
| 177 | StringRef versionName) { | |
| 178 | if (ver.hasWildcard) | |
| 694 | 179 | return; |
| 695 | 180 | |
| 696 | 181 | // Get a list of symbols which we need to assign the version to. |
| 697 | std::vector<Symbol *> Syms = findByVersion(Ver); | |
| 698 | if (Syms.empty()) { | |
| 699 | if (!Config->UndefinedVersion) | |
| 700 | error("version script assignment of '" + VersionName + "' to symbol '" + | |
| 701 | Ver.Name + "' failed: symbol not defined"); | |
| 182 | std::vector<Symbol *> syms = findByVersion(ver); | |
| 183 | if (syms.empty()) { | |
| 184 | if (!config->undefinedVersion) | |
| 185 | error("version script assignment of '" + versionName + "' to symbol '" + | |
| 186 | ver.name + "' failed: symbol not defined"); | |
| 702 | 187 | return; |
| 703 | 188 | } |
| 704 | 189 | |
| 190 | auto getName = [](uint16_t ver) -> std::string { | |
| 191 | if (ver == VER_NDX_LOCAL) | |
| 192 | return "VER_NDX_LOCAL"; | |
| 193 | if (ver == VER_NDX_GLOBAL) | |
| 194 | return "VER_NDX_GLOBAL"; | |
| 195 | return ("version '" + config->versionDefinitions[ver - 2].name + "'").str(); | |
| 196 | }; | |
| 197 | ||
| 705 | 198 | // Assign the version. |
| 706 | for (Symbol *Sym : Syms) { | |
| 199 | for (Symbol *sym : syms) { | |
| 707 | 200 | // Skip symbols containing version info because symbol versions |
| 708 | 201 | // specified by symbol names take precedence over version scripts. |
| 709 | 202 | // See parseSymbolVersion(). |
| 710 | if (Sym->getName().contains('@')) | |
| 203 | if (sym->getName().contains('@')) | |
| 204 | continue; | |
| 205 | ||
| 206 | if (sym->versionId == config->defaultSymbolVersion) | |
| 207 | sym->versionId = versionId; | |
| 208 | if (sym->versionId == versionId) | |
| 711 | 209 | continue; |
| 712 | 210 | |
| 713 | if (Sym->VersionId != Config->DefaultSymbolVersion && | |
| 714 | Sym->VersionId != VersionId) | |
| 715 | error("duplicate symbol '" + Ver.Name + "' in version script"); | |
| 716 | Sym->VersionId = VersionId; | |
| 211 | warn("attempt to reassign symbol '" + ver.name + "' of " + | |
| 212 | getName(sym->versionId) + " to " + getName(versionId)); | |
| 717 | 213 | } |
| 718 | 214 | } |
| 719 | 215 | |
| 720 | void SymbolTable::assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId) { | |
| 721 | if (!Ver.HasWildcard) | |
| 216 | void SymbolTable::assignWildcardVersion(SymbolVersion ver, uint16_t versionId) { | |
| 217 | if (!ver.hasWildcard) | |
| 722 | 218 | return; |
| 723 | 219 | |
| 724 | 220 | // Exact matching takes precendence over fuzzy matching, |
| 725 | 221 | // so we set a version to a symbol only if no version has been assigned |
| 726 | 222 | // to the symbol. This behavior is compatible with GNU. |
| 727 | for (Symbol *B : findAllByVersion(Ver)) | |
| 728 | if (B->VersionId == Config->DefaultSymbolVersion) | |
| 729 | B->VersionId = VersionId; | |
| 223 | for (Symbol *b : findAllByVersion(ver)) | |
| 224 | if (b->versionId == config->defaultSymbolVersion) | |
| 225 | b->versionId = versionId; | |
| 730 | 226 | } |
| 731 | 227 | |
| 732 | // This function processes version scripts by updating VersionId | |
| 228 | // This function processes version scripts by updating the versionId | |
| 733 | 229 | // member of symbols. |
| 230 | // If there's only one anonymous version definition in a version | |
| 231 | // script file, the script does not actually define any symbol version, | |
| 232 | // but just specifies symbols visibilities. | |
| 734 | 233 | void SymbolTable::scanVersionScript() { |
| 735 | // Handle edge cases first. | |
| 736 | handleAnonymousVersion(); | |
| 737 | handleDynamicList(); | |
| 738 | ||
| 739 | // Now we have version definitions, so we need to set version ids to symbols. | |
| 740 | // Each version definition has a glob pattern, and all symbols that match | |
| 741 | // with the pattern get that version. | |
| 742 | ||
| 743 | 234 | // First, we assign versions to exact matching symbols, |
| 744 | 235 | // i.e. version definitions not containing any glob meta-characters. |
| 745 | for (VersionDefinition &V : Config->VersionDefinitions) | |
| 746 | for (SymbolVersion &Ver : V.Globals) | |
| 747 | assignExactVersion(Ver, V.Id, V.Name); | |
| 236 | for (SymbolVersion &ver : config->versionScriptGlobals) | |
| 237 | assignExactVersion(ver, VER_NDX_GLOBAL, "global"); | |
| 238 | for (SymbolVersion &ver : config->versionScriptLocals) | |
| 239 | assignExactVersion(ver, VER_NDX_LOCAL, "local"); | |
| 240 | for (VersionDefinition &v : config->versionDefinitions) | |
| 241 | for (SymbolVersion &ver : v.globals) | |
| 242 | assignExactVersion(ver, v.id, v.name); | |
| 748 | 243 | |
| 749 | 244 | // Next, we assign versions to fuzzy matching symbols, |
| 750 | 245 | // i.e. version definitions containing glob meta-characters. |
| 246 | for (SymbolVersion &ver : config->versionScriptGlobals) | |
| 247 | assignWildcardVersion(ver, VER_NDX_GLOBAL); | |
| 248 | for (SymbolVersion &ver : config->versionScriptLocals) | |
| 249 | assignWildcardVersion(ver, VER_NDX_LOCAL); | |
| 250 | ||
| 751 | 251 | // Note that because the last match takes precedence over previous matches, |
| 752 | 252 | // we iterate over the definitions in the reverse order. |
| 753 | for (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions)) | |
| 754 | for (SymbolVersion &Ver : V.Globals) | |
| 755 | assignWildcardVersion(Ver, V.Id); | |
| 253 | for (VersionDefinition &v : llvm::reverse(config->versionDefinitions)) | |
| 254 | for (SymbolVersion &ver : v.globals) | |
| 255 | assignWildcardVersion(ver, v.id); | |
| 756 | 256 | |
| 757 | 257 | // Symbol themselves might know their versions because symbols |
| 758 | 258 | // can contain versions in the form of <name>@<version>. |
| 759 | 259 | // Let them parse and update their names to exclude version suffix. |
| 760 | for (Symbol *Sym : SymVector) | |
| 761 | Sym->parseSymbolVersion(); | |
| 762 | } | |
| 260 | for (Symbol *sym : symVector) | |
| 261 | sym->parseSymbolVersion(); | |
| 763 | 262 | |
| 764 | template void SymbolTable::addFile<ELF32LE>(InputFile *); | |
| 765 | template void SymbolTable::addFile<ELF32BE>(InputFile *); | |
| 766 | template void SymbolTable::addFile<ELF64LE>(InputFile *); | |
| 767 | template void SymbolTable::addFile<ELF64BE>(InputFile *); | |
| 768 | ||
| 769 | template Symbol *SymbolTable::addUndefined<ELF32LE>(StringRef, uint8_t, uint8_t, | |
| 770 | uint8_t, bool, InputFile *); | |
| 771 | template Symbol *SymbolTable::addUndefined<ELF32BE>(StringRef, uint8_t, uint8_t, | |
| 772 | uint8_t, bool, InputFile *); | |
| 773 | template Symbol *SymbolTable::addUndefined<ELF64LE>(StringRef, uint8_t, uint8_t, | |
| 774 | uint8_t, bool, InputFile *); | |
| 775 | template Symbol *SymbolTable::addUndefined<ELF64BE>(StringRef, uint8_t, uint8_t, | |
| 776 | uint8_t, bool, InputFile *); | |
| 777 | ||
| 778 | template void SymbolTable::addCombinedLTOObject<ELF32LE>(); | |
| 779 | template void SymbolTable::addCombinedLTOObject<ELF32BE>(); | |
| 780 | template void SymbolTable::addCombinedLTOObject<ELF64LE>(); | |
| 781 | template void SymbolTable::addCombinedLTOObject<ELF64BE>(); | |
| 782 | ||
| 783 | template void | |
| 784 | SymbolTable::addLazyArchive<ELF32LE>(StringRef, ArchiveFile &, | |
| 785 | const object::Archive::Symbol); | |
| 786 | template void | |
| 787 | SymbolTable::addLazyArchive<ELF32BE>(StringRef, ArchiveFile &, | |
| 788 | const object::Archive::Symbol); | |
| 789 | template void | |
| 790 | SymbolTable::addLazyArchive<ELF64LE>(StringRef, ArchiveFile &, | |
| 791 | const object::Archive::Symbol); | |
| 792 | template void | |
| 793 | SymbolTable::addLazyArchive<ELF64BE>(StringRef, ArchiveFile &, | |
| 794 | const object::Archive::Symbol); | |
| 795 | ||
| 796 | template void SymbolTable::addLazyObject<ELF32LE>(StringRef, LazyObjFile &); | |
| 797 | template void SymbolTable::addLazyObject<ELF32BE>(StringRef, LazyObjFile &); | |
| 798 | template void SymbolTable::addLazyObject<ELF64LE>(StringRef, LazyObjFile &); | |
| 799 | template void SymbolTable::addLazyObject<ELF64BE>(StringRef, LazyObjFile &); | |
| 800 | ||
| 801 | template void SymbolTable::fetchLazy<ELF32LE>(Symbol *); | |
| 802 | template void SymbolTable::fetchLazy<ELF32BE>(Symbol *); | |
| 803 | template void SymbolTable::fetchLazy<ELF64LE>(Symbol *); | |
| 804 | template void SymbolTable::fetchLazy<ELF64BE>(Symbol *); | |
| 805 | ||
| 806 | template void SymbolTable::addShared<ELF32LE>(StringRef, SharedFile<ELF32LE> &, | |
| 807 | const typename ELF32LE::Sym &, | |
| 808 | uint32_t Alignment, uint32_t); | |
| 809 | template void SymbolTable::addShared<ELF32BE>(StringRef, SharedFile<ELF32BE> &, | |
| 810 | const typename ELF32BE::Sym &, | |
| 811 | uint32_t Alignment, uint32_t); | |
| 812 | template void SymbolTable::addShared<ELF64LE>(StringRef, SharedFile<ELF64LE> &, | |
| 813 | const typename ELF64LE::Sym &, | |
| 814 | uint32_t Alignment, uint32_t); | |
| 815 | template void SymbolTable::addShared<ELF64BE>(StringRef, SharedFile<ELF64BE> &, | |
| 816 | const typename ELF64BE::Sym &, | |
| 817 | uint32_t Alignment, uint32_t); | |
| 263 | // isPreemptible is false at this point. To correctly compute the binding of a | |
| 264 | // Defined (which is used by includeInDynsym()), we need to know if it is | |
| 265 | // VER_NDX_LOCAL or not. If defaultSymbolVersion is VER_NDX_LOCAL, we should | |
| 266 | // compute symbol versions before handling --dynamic-list. | |
| 267 | handleDynamicList(); | |
| 268 | } |
deps/lld/ELF/SymbolTable.h+32-66| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- SymbolTable.h --------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -11,15 +10,14 @@ |
| 11 | 10 | #define LLD_ELF_SYMBOL_TABLE_H |
| 12 | 11 | |
| 13 | 12 | #include "InputFiles.h" |
| 14 | #include "LTO.h" | |
| 13 | #include "Symbols.h" | |
| 15 | 14 | #include "lld/Common/Strings.h" |
| 16 | 15 | #include "llvm/ADT/CachedHashString.h" |
| 17 | 16 | #include "llvm/ADT/DenseMap.h" |
| 17 | #include "llvm/ADT/STLExtras.h" | |
| 18 | 18 | |
| 19 | 19 | namespace lld { |
| 20 | 20 | namespace elf { |
| 21 | class Defined; | |
| 22 | class SectionBase; | |
| 23 | 21 | |
| 24 | 22 | // SymbolTable is a bucket of all known symbols, including defined, |
| 25 | 23 | // undefined, or lazy symbols (the last one is symbols in archive |
| ... | ... | @@ -35,62 +33,40 @@ class SectionBase; |
| 35 | 33 | // is one add* function per symbol type. |
| 36 | 34 | class SymbolTable { |
| 37 | 35 | public: |
| 38 | template <class ELFT> void addFile(InputFile *File); | |
| 39 | template <class ELFT> void addCombinedLTOObject(); | |
| 40 | void wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap); | |
| 41 | ||
| 42 | ArrayRef<Symbol *> getSymbols() const { return SymVector; } | |
| 43 | ||
| 44 | template <class ELFT> | |
| 45 | Symbol *addUndefined(StringRef Name, uint8_t Binding, uint8_t StOther, | |
| 46 | uint8_t Type, bool CanOmitFromDynSym, InputFile *File); | |
| 47 | ||
| 48 | Defined *addDefined(StringRef Name, uint8_t StOther, uint8_t Type, | |
| 49 | uint64_t Value, uint64_t Size, uint8_t Binding, | |
| 50 | SectionBase *Section, InputFile *File); | |
| 51 | ||
| 52 | template <class ELFT> | |
| 53 | void addShared(StringRef Name, SharedFile<ELFT> &F, | |
| 54 | const typename ELFT::Sym &Sym, uint32_t Alignment, | |
| 55 | uint32_t VerdefIndex); | |
| 56 | ||
| 57 | template <class ELFT> | |
| 58 | void addLazyArchive(StringRef Name, ArchiveFile &F, | |
| 59 | const llvm::object::Archive::Symbol S); | |
| 36 | void wrap(Symbol *sym, Symbol *real, Symbol *wrap); | |
| 60 | 37 | |
| 61 | template <class ELFT> void addLazyObject(StringRef Name, LazyObjFile &Obj); | |
| 38 | void forEachSymbol(llvm::function_ref<void(Symbol *)> fn) { | |
| 39 | for (Symbol *sym : symVector) | |
| 40 | if (!sym->isPlaceholder()) | |
| 41 | fn(sym); | |
| 42 | } | |
| 62 | 43 | |
| 63 | Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther, | |
| 64 | uint8_t Type, bool CanOmitFromDynSym, BitcodeFile &File); | |
| 44 | Symbol *insert(StringRef name); | |
| 65 | 45 | |
| 66 | Symbol *addCommon(StringRef Name, uint64_t Size, uint32_t Alignment, | |
| 67 | uint8_t Binding, uint8_t StOther, uint8_t Type, | |
| 68 | InputFile &File); | |
| 69 | ||
| 70 | std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Visibility, | |
| 71 | bool CanOmitFromDynSym, InputFile *File); | |
| 72 | ||
| 73 | template <class ELFT> void fetchLazy(Symbol *Sym); | |
| 46 | Symbol *addSymbol(const Symbol &New); | |
| 74 | 47 | |
| 75 | 48 | void scanVersionScript(); |
| 76 | 49 | |
| 77 | Symbol *find(StringRef Name); | |
| 78 | ||
| 79 | void trace(StringRef Name); | |
| 50 | Symbol *find(StringRef name); | |
| 80 | 51 | |
| 81 | 52 | void handleDynamicList(); |
| 82 | 53 | |
| 83 | private: | |
| 84 | std::pair<Symbol *, bool> insertName(StringRef Name); | |
| 54 | // Set of .so files to not link the same shared object file more than once. | |
| 55 | llvm::DenseMap<StringRef, SharedFile *> soNames; | |
| 85 | 56 | |
| 86 | std::vector<Symbol *> findByVersion(SymbolVersion Ver); | |
| 87 | std::vector<Symbol *> findAllByVersion(SymbolVersion Ver); | |
| 57 | // Comdat groups define "link once" sections. If two comdat groups have the | |
| 58 | // same name, only one of them is linked, and the other is ignored. This map | |
| 59 | // is used to uniquify them. | |
| 60 | llvm::DenseMap<llvm::CachedHashStringRef, const InputFile *> comdatGroups; | |
| 61 | ||
| 62 | private: | |
| 63 | std::vector<Symbol *> findByVersion(SymbolVersion ver); | |
| 64 | std::vector<Symbol *> findAllByVersion(SymbolVersion ver); | |
| 88 | 65 | |
| 89 | 66 | llvm::StringMap<std::vector<Symbol *>> &getDemangledSyms(); |
| 90 | void handleAnonymousVersion(); | |
| 91 | void assignExactVersion(SymbolVersion Ver, uint16_t VersionId, | |
| 92 | StringRef VersionName); | |
| 93 | void assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId); | |
| 67 | void assignExactVersion(SymbolVersion ver, uint16_t versionId, | |
| 68 | StringRef versionName); | |
| 69 | void assignWildcardVersion(SymbolVersion ver, uint16_t versionId); | |
| 94 | 70 | |
| 95 | 71 | // The order the global symbols are in is not defined. We can use an arbitrary |
| 96 | 72 | // order, but it has to be reproducible. That is true even when cross linking. |
| ... | ... | @@ -99,28 +75,18 @@ private: |
| 99 | 75 | // but a bit inefficient. |
| 100 | 76 | // FIXME: Experiment with passing in a custom hashing or sorting the symbols |
| 101 | 77 | // once symbol resolution is finished. |
| 102 | llvm::DenseMap<llvm::CachedHashStringRef, int> SymMap; | |
| 103 | std::vector<Symbol *> SymVector; | |
| 104 | ||
| 105 | // Comdat groups define "link once" sections. If two comdat groups have the | |
| 106 | // same name, only one of them is linked, and the other is ignored. This set | |
| 107 | // is used to uniquify them. | |
| 108 | llvm::DenseSet<llvm::CachedHashStringRef> ComdatGroups; | |
| 109 | ||
| 110 | // Set of .so files to not link the same shared object file more than once. | |
| 111 | llvm::DenseMap<StringRef, InputFile *> SoNames; | |
| 78 | llvm::DenseMap<llvm::CachedHashStringRef, int> symMap; | |
| 79 | std::vector<Symbol *> symVector; | |
| 112 | 80 | |
| 113 | 81 | // A map from demangled symbol names to their symbol objects. |
| 114 | 82 | // This mapping is 1:N because two symbols with different versions |
| 115 | 83 | // can have the same name. We use this map to handle "extern C++ {}" |
| 116 | 84 | // directive in version scripts. |
| 117 | llvm::Optional<llvm::StringMap<std::vector<Symbol *>>> DemangledSyms; | |
| 118 | ||
| 119 | // For LTO. | |
| 120 | std::unique_ptr<BitcodeCompiler> LTO; | |
| 85 | llvm::Optional<llvm::StringMap<std::vector<Symbol *>>> demangledSyms; | |
| 121 | 86 | }; |
| 122 | 87 | |
| 123 | extern SymbolTable *Symtab; | |
| 88 | extern SymbolTable *symtab; | |
| 89 | ||
| 124 | 90 | } // namespace elf |
| 125 | 91 | } // namespace lld |
| 126 | 92 |
deps/lld/ELF/Symbols.cpp+489-138| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Symbols.cpp --------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -27,40 +26,36 @@ using namespace llvm::ELF; |
| 27 | 26 | using namespace lld; |
| 28 | 27 | using namespace lld::elf; |
| 29 | 28 | |
| 30 | Defined *ElfSym::Bss; | |
| 31 | Defined *ElfSym::Etext1; | |
| 32 | Defined *ElfSym::Etext2; | |
| 33 | Defined *ElfSym::Edata1; | |
| 34 | Defined *ElfSym::Edata2; | |
| 35 | Defined *ElfSym::End1; | |
| 36 | Defined *ElfSym::End2; | |
| 37 | Defined *ElfSym::GlobalOffsetTable; | |
| 38 | Defined *ElfSym::MipsGp; | |
| 39 | Defined *ElfSym::MipsGpDisp; | |
| 40 | Defined *ElfSym::MipsLocalGp; | |
| 41 | Defined *ElfSym::RelaIpltStart; | |
| 42 | Defined *ElfSym::RelaIpltEnd; | |
| 43 | ||
| 44 | static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { | |
| 45 | switch (Sym.kind()) { | |
| 29 | Defined *ElfSym::bss; | |
| 30 | Defined *ElfSym::etext1; | |
| 31 | Defined *ElfSym::etext2; | |
| 32 | Defined *ElfSym::edata1; | |
| 33 | Defined *ElfSym::edata2; | |
| 34 | Defined *ElfSym::end1; | |
| 35 | Defined *ElfSym::end2; | |
| 36 | Defined *ElfSym::globalOffsetTable; | |
| 37 | Defined *ElfSym::mipsGp; | |
| 38 | Defined *ElfSym::mipsGpDisp; | |
| 39 | Defined *ElfSym::mipsLocalGp; | |
| 40 | Defined *ElfSym::relaIpltStart; | |
| 41 | Defined *ElfSym::relaIpltEnd; | |
| 42 | Defined *ElfSym::riscvGlobalPointer; | |
| 43 | Defined *ElfSym::tlsModuleBase; | |
| 44 | ||
| 45 | static uint64_t getSymVA(const Symbol &sym, int64_t &addend) { | |
| 46 | switch (sym.kind()) { | |
| 46 | 47 | case Symbol::DefinedKind: { |
| 47 | auto &D = cast<Defined>(Sym); | |
| 48 | SectionBase *IS = D.Section; | |
| 49 | ||
| 50 | // According to the ELF spec reference to a local symbol from outside | |
| 51 | // the group are not allowed. Unfortunately .eh_frame breaks that rule | |
| 52 | // and must be treated specially. For now we just replace the symbol with | |
| 53 | // 0. | |
| 54 | if (IS == &InputSection::Discarded) | |
| 55 | return 0; | |
| 48 | auto &d = cast<Defined>(sym); | |
| 49 | SectionBase *isec = d.section; | |
| 56 | 50 | |
| 57 | 51 | // This is an absolute symbol. |
| 58 | if (!IS) | |
| 59 | return D.Value; | |
| 52 | if (!isec) | |
| 53 | return d.value; | |
| 60 | 54 | |
| 61 | IS = IS->Repl; | |
| 55 | assert(isec != &InputSection::discarded); | |
| 56 | isec = isec->repl; | |
| 62 | 57 | |
| 63 | uint64_t Offset = D.Value; | |
| 58 | uint64_t offset = d.value; | |
| 64 | 59 | |
| 65 | 60 | // An object in an SHF_MERGE section might be referenced via a |
| 66 | 61 | // section symbol (as a hack for reducing the number of local |
| ... | ... | @@ -73,9 +68,9 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { |
| 73 | 68 | // To make this work, we incorporate the addend into the section |
| 74 | 69 | // offset (and zero out the addend for later processing) so that |
| 75 | 70 | // we find the right object in the section. |
| 76 | if (D.isSection()) { | |
| 77 | Offset += Addend; | |
| 78 | Addend = 0; | |
| 71 | if (d.isSection()) { | |
| 72 | offset += addend; | |
| 73 | addend = 0; | |
| 79 | 74 | } |
| 80 | 75 | |
| 81 | 76 | // In the typical case, this is actually very simple and boils |
| ... | ... | @@ -88,83 +83,107 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { |
| 88 | 83 | // If you understand the data structures involved with this next |
| 89 | 84 | // line (and how they get built), then you have a pretty good |
| 90 | 85 | // understanding of the linker. |
| 91 | uint64_t VA = IS->getVA(Offset); | |
| 92 | ||
| 93 | if (D.isTls() && !Config->Relocatable) { | |
| 86 | uint64_t va = isec->getVA(offset); | |
| 87 | ||
| 88 | // MIPS relocatable files can mix regular and microMIPS code. | |
| 89 | // Linker needs to distinguish such code. To do so microMIPS | |
| 90 | // symbols has the `STO_MIPS_MICROMIPS` flag in the `st_other` | |
| 91 | // field. Unfortunately, the `MIPS::relocateOne()` method has | |
| 92 | // a symbol value only. To pass type of the symbol (regular/microMIPS) | |
| 93 | // to that routine as well as other places where we write | |
| 94 | // a symbol value as-is (.dynamic section, `Elf_Ehdr::e_entry` | |
| 95 | // field etc) do the same trick as compiler uses to mark microMIPS | |
| 96 | // for CPU - set the less-significant bit. | |
| 97 | if (config->emachine == EM_MIPS && isMicroMips() && | |
| 98 | ((sym.stOther & STO_MIPS_MICROMIPS) || sym.needsPltAddr)) | |
| 99 | va |= 1; | |
| 100 | ||
| 101 | if (d.isTls() && !config->relocatable) { | |
| 94 | 102 | // Use the address of the TLS segment's first section rather than the |
| 95 | 103 | // segment's address, because segment addresses aren't initialized until |
| 96 | 104 | // after sections are finalized. (e.g. Measuring the size of .rela.dyn |
| 97 | 105 | // for Android relocation packing requires knowing TLS symbol addresses |
| 98 | 106 | // during section finalization.) |
| 99 | if (!Out::TlsPhdr || !Out::TlsPhdr->FirstSec) | |
| 100 | fatal(toString(D.File) + | |
| 107 | if (!Out::tlsPhdr || !Out::tlsPhdr->firstSec) | |
| 108 | fatal(toString(d.file) + | |
| 101 | 109 | " has an STT_TLS symbol but doesn't have an SHF_TLS section"); |
| 102 | return VA - Out::TlsPhdr->FirstSec->Addr; | |
| 110 | return va - Out::tlsPhdr->firstSec->addr; | |
| 103 | 111 | } |
| 104 | return VA; | |
| 112 | return va; | |
| 105 | 113 | } |
| 106 | 114 | case Symbol::SharedKind: |
| 107 | 115 | case Symbol::UndefinedKind: |
| 108 | 116 | return 0; |
| 109 | 117 | case Symbol::LazyArchiveKind: |
| 110 | 118 | case Symbol::LazyObjectKind: |
| 111 | assert(Sym.IsUsedInRegularObj && "lazy symbol reached writer"); | |
| 119 | assert(sym.isUsedInRegularObj && "lazy symbol reached writer"); | |
| 112 | 120 | return 0; |
| 121 | case Symbol::CommonKind: | |
| 122 | llvm_unreachable("common symbol reached writer"); | |
| 113 | 123 | case Symbol::PlaceholderKind: |
| 114 | 124 | llvm_unreachable("placeholder symbol reached writer"); |
| 115 | 125 | } |
| 116 | 126 | llvm_unreachable("invalid symbol kind"); |
| 117 | 127 | } |
| 118 | 128 | |
| 119 | uint64_t Symbol::getVA(int64_t Addend) const { | |
| 120 | uint64_t OutVA = getSymVA(*this, Addend); | |
| 121 | return OutVA + Addend; | |
| 129 | uint64_t Symbol::getVA(int64_t addend) const { | |
| 130 | uint64_t outVA = getSymVA(*this, addend); | |
| 131 | return outVA + addend; | |
| 122 | 132 | } |
| 123 | 133 | |
| 124 | uint64_t Symbol::getGotVA() const { return In.Got->getVA() + getGotOffset(); } | |
| 125 | ||
| 126 | uint64_t Symbol::getGotOffset() const { | |
| 127 | return GotIndex * Target->GotEntrySize; | |
| 134 | uint64_t Symbol::getGotVA() const { | |
| 135 | if (gotInIgot) | |
| 136 | return in.igotPlt->getVA() + getGotPltOffset(); | |
| 137 | return in.got->getVA() + getGotOffset(); | |
| 128 | 138 | } |
| 129 | 139 | |
| 140 | uint64_t Symbol::getGotOffset() const { return gotIndex * config->wordsize; } | |
| 141 | ||
| 130 | 142 | uint64_t Symbol::getGotPltVA() const { |
| 131 | if (this->IsInIgot) | |
| 132 | return In.IgotPlt->getVA() + getGotPltOffset(); | |
| 133 | return In.GotPlt->getVA() + getGotPltOffset(); | |
| 143 | if (isInIplt) | |
| 144 | return in.igotPlt->getVA() + getGotPltOffset(); | |
| 145 | return in.gotPlt->getVA() + getGotPltOffset(); | |
| 134 | 146 | } |
| 135 | 147 | |
| 136 | 148 | uint64_t Symbol::getGotPltOffset() const { |
| 137 | if (IsInIgot) | |
| 138 | return PltIndex * Target->GotPltEntrySize; | |
| 139 | return (PltIndex + Target->GotPltHeaderEntriesNum) * Target->GotPltEntrySize; | |
| 149 | if (isInIplt) | |
| 150 | return pltIndex * config->wordsize; | |
| 151 | return (pltIndex + target->gotPltHeaderEntriesNum) * config->wordsize; | |
| 140 | 152 | } |
| 141 | 153 | |
| 142 | 154 | uint64_t Symbol::getPPC64LongBranchOffset() const { |
| 143 | assert(PPC64BranchltIndex != 0xffff); | |
| 144 | return PPC64BranchltIndex * Target->GotPltEntrySize; | |
| 155 | assert(ppc64BranchltIndex != 0xffff); | |
| 156 | return ppc64BranchltIndex * config->wordsize; | |
| 145 | 157 | } |
| 146 | 158 | |
| 147 | 159 | uint64_t Symbol::getPltVA() const { |
| 148 | PltSection *Plt = IsInIplt ? In.Iplt : In.Plt; | |
| 149 | return Plt->getVA() + Plt->HeaderSize + PltIndex * Target->PltEntrySize; | |
| 160 | PltSection *plt = isInIplt ? in.iplt : in.plt; | |
| 161 | uint64_t outVA = | |
| 162 | plt->getVA() + plt->headerSize + pltIndex * target->pltEntrySize; | |
| 163 | // While linking microMIPS code PLT code are always microMIPS | |
| 164 | // code. Set the less-significant bit to track that fact. | |
| 165 | // See detailed comment in the `getSymVA` function. | |
| 166 | if (config->emachine == EM_MIPS && isMicroMips()) | |
| 167 | outVA |= 1; | |
| 168 | return outVA; | |
| 150 | 169 | } |
| 151 | 170 | |
| 152 | 171 | uint64_t Symbol::getPPC64LongBranchTableVA() const { |
| 153 | assert(PPC64BranchltIndex != 0xffff); | |
| 154 | return In.PPC64LongBranchTarget->getVA() + | |
| 155 | PPC64BranchltIndex * Target->GotPltEntrySize; | |
| 172 | assert(ppc64BranchltIndex != 0xffff); | |
| 173 | return in.ppc64LongBranchTarget->getVA() + | |
| 174 | ppc64BranchltIndex * config->wordsize; | |
| 156 | 175 | } |
| 157 | 176 | |
| 158 | 177 | uint64_t Symbol::getSize() const { |
| 159 | if (const auto *DR = dyn_cast<Defined>(this)) | |
| 160 | return DR->Size; | |
| 161 | return cast<SharedSymbol>(this)->Size; | |
| 178 | if (const auto *dr = dyn_cast<Defined>(this)) | |
| 179 | return dr->size; | |
| 180 | return cast<SharedSymbol>(this)->size; | |
| 162 | 181 | } |
| 163 | 182 | |
| 164 | 183 | OutputSection *Symbol::getOutputSection() const { |
| 165 | if (auto *S = dyn_cast<Defined>(this)) { | |
| 166 | if (auto *Sec = S->Section) | |
| 167 | return Sec->Repl->getOutputSection(); | |
| 184 | if (auto *s = dyn_cast<Defined>(this)) { | |
| 185 | if (auto *sec = s->section) | |
| 186 | return sec->repl->getOutputSection(); | |
| 168 | 187 | return nullptr; |
| 169 | 188 | } |
| 170 | 189 | return nullptr; |
| ... | ... | @@ -173,16 +192,16 @@ OutputSection *Symbol::getOutputSection() const { |
| 173 | 192 | // If a symbol name contains '@', the characters after that is |
| 174 | 193 | // a symbol version name. This function parses that. |
| 175 | 194 | void Symbol::parseSymbolVersion() { |
| 176 | StringRef S = getName(); | |
| 177 | size_t Pos = S.find('@'); | |
| 178 | if (Pos == 0 || Pos == StringRef::npos) | |
| 195 | StringRef s = getName(); | |
| 196 | size_t pos = s.find('@'); | |
| 197 | if (pos == 0 || pos == StringRef::npos) | |
| 179 | 198 | return; |
| 180 | StringRef Verstr = S.substr(Pos + 1); | |
| 181 | if (Verstr.empty()) | |
| 199 | StringRef verstr = s.substr(pos + 1); | |
| 200 | if (verstr.empty()) | |
| 182 | 201 | return; |
| 183 | 202 | |
| 184 | 203 | // Truncate the symbol name so that it doesn't include the version string. |
| 185 | NameSize = Pos; | |
| 204 | nameSize = pos; | |
| 186 | 205 | |
| 187 | 206 | // If this is not in this DSO, it is not a definition. |
| 188 | 207 | if (!isDefined()) |
| ... | ... | @@ -190,18 +209,18 @@ void Symbol::parseSymbolVersion() { |
| 190 | 209 | |
| 191 | 210 | // '@@' in a symbol name means the default version. |
| 192 | 211 | // It is usually the most recent one. |
| 193 | bool IsDefault = (Verstr[0] == '@'); | |
| 194 | if (IsDefault) | |
| 195 | Verstr = Verstr.substr(1); | |
| 212 | bool isDefault = (verstr[0] == '@'); | |
| 213 | if (isDefault) | |
| 214 | verstr = verstr.substr(1); | |
| 196 | 215 | |
| 197 | for (VersionDefinition &Ver : Config->VersionDefinitions) { | |
| 198 | if (Ver.Name != Verstr) | |
| 216 | for (VersionDefinition &ver : config->versionDefinitions) { | |
| 217 | if (ver.name != verstr) | |
| 199 | 218 | continue; |
| 200 | 219 | |
| 201 | if (IsDefault) | |
| 202 | VersionId = Ver.Id; | |
| 220 | if (isDefault) | |
| 221 | versionId = ver.id; | |
| 203 | 222 | else |
| 204 | VersionId = Ver.Id | VERSYM_HIDDEN; | |
| 223 | versionId = ver.id | VERSYM_HIDDEN; | |
| 205 | 224 | return; |
| 206 | 225 | } |
| 207 | 226 | |
| ... | ... | @@ -211,63 +230,79 @@ void Symbol::parseSymbolVersion() { |
| 211 | 230 | // so we do not report error in this case. We also do not error |
| 212 | 231 | // if the symbol has a local version as it won't be in the dynamic |
| 213 | 232 | // symbol table. |
| 214 | if (Config->Shared && VersionId != VER_NDX_LOCAL) | |
| 215 | error(toString(File) + ": symbol " + S + " has undefined version " + | |
| 216 | Verstr); | |
| 233 | if (config->shared && versionId != VER_NDX_LOCAL) | |
| 234 | error(toString(file) + ": symbol " + s + " has undefined version " + | |
| 235 | verstr); | |
| 217 | 236 | } |
| 218 | 237 | |
| 219 | InputFile *LazyArchive::fetch() { return cast<ArchiveFile>(File)->fetch(Sym); } | |
| 238 | void Symbol::fetch() const { | |
| 239 | if (auto *sym = dyn_cast<LazyArchive>(this)) { | |
| 240 | cast<ArchiveFile>(sym->file)->fetch(sym->sym); | |
| 241 | return; | |
| 242 | } | |
| 243 | ||
| 244 | if (auto *sym = dyn_cast<LazyObject>(this)) { | |
| 245 | dyn_cast<LazyObjFile>(sym->file)->fetch(); | |
| 246 | return; | |
| 247 | } | |
| 248 | ||
| 249 | llvm_unreachable("Symbol::fetch() is called on a non-lazy symbol"); | |
| 250 | } | |
| 220 | 251 | |
| 221 | 252 | MemoryBufferRef LazyArchive::getMemberBuffer() { |
| 222 | Archive::Child C = CHECK( | |
| 223 | Sym.getMember(), "could not get the member for symbol " + Sym.getName()); | |
| 253 | Archive::Child c = CHECK( | |
| 254 | sym.getMember(), "could not get the member for symbol " + sym.getName()); | |
| 224 | 255 | |
| 225 | return CHECK(C.getMemoryBufferRef(), | |
| 256 | return CHECK(c.getMemoryBufferRef(), | |
| 226 | 257 | "could not get the buffer for the member defining symbol " + |
| 227 | Sym.getName()); | |
| 258 | sym.getName()); | |
| 228 | 259 | } |
| 229 | 260 | |
| 230 | 261 | uint8_t Symbol::computeBinding() const { |
| 231 | if (Config->Relocatable) | |
| 232 | return Binding; | |
| 233 | if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) | |
| 262 | if (config->relocatable) | |
| 263 | return binding; | |
| 264 | if (visibility != STV_DEFAULT && visibility != STV_PROTECTED) | |
| 234 | 265 | return STB_LOCAL; |
| 235 | if (VersionId == VER_NDX_LOCAL && isDefined() && !IsPreemptible) | |
| 266 | if (versionId == VER_NDX_LOCAL && isDefined() && !isPreemptible) | |
| 236 | 267 | return STB_LOCAL; |
| 237 | if (!Config->GnuUnique && Binding == STB_GNU_UNIQUE) | |
| 268 | if (!config->gnuUnique && binding == STB_GNU_UNIQUE) | |
| 238 | 269 | return STB_GLOBAL; |
| 239 | return Binding; | |
| 270 | return binding; | |
| 240 | 271 | } |
| 241 | 272 | |
| 242 | 273 | bool Symbol::includeInDynsym() const { |
| 243 | if (!Config->HasDynSymTab) | |
| 274 | if (!config->hasDynSymTab) | |
| 244 | 275 | return false; |
| 245 | 276 | if (computeBinding() == STB_LOCAL) |
| 246 | 277 | return false; |
| 247 | if (!isDefined()) | |
| 248 | return true; | |
| 249 | return ExportDynamic; | |
| 278 | ||
| 279 | // If a PIE binary was not linked against any shared libraries, then we can | |
| 280 | // safely drop weak undef symbols from .dynsym. | |
| 281 | if (isUndefWeak() && config->pie && sharedFiles.empty()) | |
| 282 | return false; | |
| 283 | ||
| 284 | return isUndefined() || isShared() || exportDynamic; | |
| 250 | 285 | } |
| 251 | 286 | |
| 252 | 287 | // Print out a log message for --trace-symbol. |
| 253 | void elf::printTraceSymbol(Symbol *Sym) { | |
| 254 | std::string S; | |
| 255 | if (Sym->isUndefined()) | |
| 256 | S = ": reference to "; | |
| 257 | else if (Sym->isLazy()) | |
| 258 | S = ": lazy definition of "; | |
| 259 | else if (Sym->isShared()) | |
| 260 | S = ": shared definition of "; | |
| 261 | else if (dyn_cast_or_null<BssSection>(cast<Defined>(Sym)->Section)) | |
| 262 | S = ": common definition of "; | |
| 288 | void elf::printTraceSymbol(const Symbol *sym) { | |
| 289 | std::string s; | |
| 290 | if (sym->isUndefined()) | |
| 291 | s = ": reference to "; | |
| 292 | else if (sym->isLazy()) | |
| 293 | s = ": lazy definition of "; | |
| 294 | else if (sym->isShared()) | |
| 295 | s = ": shared definition of "; | |
| 296 | else if (sym->isCommon()) | |
| 297 | s = ": common definition of "; | |
| 263 | 298 | else |
| 264 | S = ": definition of "; | |
| 299 | s = ": definition of "; | |
| 265 | 300 | |
| 266 | message(toString(Sym->File) + S + Sym->getName()); | |
| 301 | message(toString(sym->file) + s + sym->getName()); | |
| 267 | 302 | } |
| 268 | 303 | |
| 269 | void elf::maybeWarnUnorderableSymbol(const Symbol *Sym) { | |
| 270 | if (!Config->WarnSymbolOrdering) | |
| 304 | void elf::maybeWarnUnorderableSymbol(const Symbol *sym) { | |
| 305 | if (!config->warnSymbolOrdering) | |
| 271 | 306 | return; |
| 272 | 307 | |
| 273 | 308 | // If UnresolvedPolicy::Ignore is used, no "undefined symbol" error/warning |
| ... | ... | @@ -275,31 +310,347 @@ void elf::maybeWarnUnorderableSymbol(const Symbol *Sym) { |
| 275 | 310 | // |
| 276 | 311 | // Note, ld.bfd --symbol-ordering-file= does not warn on undefined symbols, |
| 277 | 312 | // but we don't have to be compatible here. |
| 278 | if (Sym->isUndefined() && | |
| 279 | Config->UnresolvedSymbols == UnresolvedPolicy::Ignore) | |
| 313 | if (sym->isUndefined() && | |
| 314 | config->unresolvedSymbols == UnresolvedPolicy::Ignore) | |
| 280 | 315 | return; |
| 281 | 316 | |
| 282 | const InputFile *File = Sym->File; | |
| 283 | auto *D = dyn_cast<Defined>(Sym); | |
| 284 | ||
| 285 | auto Warn = [&](StringRef S) { warn(toString(File) + S + Sym->getName()); }; | |
| 286 | ||
| 287 | if (Sym->isUndefined()) | |
| 288 | Warn(": unable to order undefined symbol: "); | |
| 289 | else if (Sym->isShared()) | |
| 290 | Warn(": unable to order shared symbol: "); | |
| 291 | else if (D && !D->Section) | |
| 292 | Warn(": unable to order absolute symbol: "); | |
| 293 | else if (D && isa<OutputSection>(D->Section)) | |
| 294 | Warn(": unable to order synthetic symbol: "); | |
| 295 | else if (D && !D->Section->Repl->Live) | |
| 296 | Warn(": unable to order discarded symbol: "); | |
| 317 | const InputFile *file = sym->file; | |
| 318 | auto *d = dyn_cast<Defined>(sym); | |
| 319 | ||
| 320 | auto report = [&](StringRef s) { warn(toString(file) + s + sym->getName()); }; | |
| 321 | ||
| 322 | if (sym->isUndefined()) | |
| 323 | report(": unable to order undefined symbol: "); | |
| 324 | else if (sym->isShared()) | |
| 325 | report(": unable to order shared symbol: "); | |
| 326 | else if (d && !d->section) | |
| 327 | report(": unable to order absolute symbol: "); | |
| 328 | else if (d && isa<OutputSection>(d->section)) | |
| 329 | report(": unable to order synthetic symbol: "); | |
| 330 | else if (d && !d->section->repl->isLive()) | |
| 331 | report(": unable to order discarded symbol: "); | |
| 297 | 332 | } |
| 298 | 333 | |
| 299 | 334 | // Returns a symbol for an error message. |
| 300 | std::string lld::toString(const Symbol &B) { | |
| 301 | if (Config->Demangle) | |
| 302 | if (Optional<std::string> S = demangleItanium(B.getName())) | |
| 303 | return *S; | |
| 304 | return B.getName(); | |
| 335 | std::string lld::toString(const Symbol &b) { | |
| 336 | if (config->demangle) | |
| 337 | if (Optional<std::string> s = demangleItanium(b.getName())) | |
| 338 | return *s; | |
| 339 | return b.getName(); | |
| 340 | } | |
| 341 | ||
| 342 | static uint8_t getMinVisibility(uint8_t va, uint8_t vb) { | |
| 343 | if (va == STV_DEFAULT) | |
| 344 | return vb; | |
| 345 | if (vb == STV_DEFAULT) | |
| 346 | return va; | |
| 347 | return std::min(va, vb); | |
| 348 | } | |
| 349 | ||
| 350 | // Merge symbol properties. | |
| 351 | // | |
| 352 | // When we have many symbols of the same name, we choose one of them, | |
| 353 | // and that's the result of symbol resolution. However, symbols that | |
| 354 | // were not chosen still affect some symbol properties. | |
| 355 | void Symbol::mergeProperties(const Symbol &other) { | |
| 356 | if (other.exportDynamic) | |
| 357 | exportDynamic = true; | |
| 358 | if (other.isUsedInRegularObj) | |
| 359 | isUsedInRegularObj = true; | |
| 360 | ||
| 361 | // DSO symbols do not affect visibility in the output. | |
| 362 | if (!other.isShared()) | |
| 363 | visibility = getMinVisibility(visibility, other.visibility); | |
| 364 | } | |
| 365 | ||
| 366 | void Symbol::resolve(const Symbol &other) { | |
| 367 | mergeProperties(other); | |
| 368 | ||
| 369 | if (isPlaceholder()) { | |
| 370 | replace(other); | |
| 371 | return; | |
| 372 | } | |
| 373 | ||
| 374 | switch (other.kind()) { | |
| 375 | case Symbol::UndefinedKind: | |
| 376 | resolveUndefined(cast<Undefined>(other)); | |
| 377 | break; | |
| 378 | case Symbol::CommonKind: | |
| 379 | resolveCommon(cast<CommonSymbol>(other)); | |
| 380 | break; | |
| 381 | case Symbol::DefinedKind: | |
| 382 | resolveDefined(cast<Defined>(other)); | |
| 383 | break; | |
| 384 | case Symbol::LazyArchiveKind: | |
| 385 | resolveLazy(cast<LazyArchive>(other)); | |
| 386 | break; | |
| 387 | case Symbol::LazyObjectKind: | |
| 388 | resolveLazy(cast<LazyObject>(other)); | |
| 389 | break; | |
| 390 | case Symbol::SharedKind: | |
| 391 | resolveShared(cast<SharedSymbol>(other)); | |
| 392 | break; | |
| 393 | case Symbol::PlaceholderKind: | |
| 394 | llvm_unreachable("bad symbol kind"); | |
| 395 | } | |
| 396 | } | |
| 397 | ||
| 398 | void Symbol::resolveUndefined(const Undefined &other) { | |
| 399 | // An undefined symbol with non default visibility must be satisfied | |
| 400 | // in the same DSO. | |
| 401 | // | |
| 402 | // If this is a non-weak defined symbol in a discarded section, override the | |
| 403 | // existing undefined symbol for better error message later. | |
| 404 | if ((isShared() && other.visibility != STV_DEFAULT) || | |
| 405 | (isUndefined() && other.binding != STB_WEAK && other.discardedSecIdx)) { | |
| 406 | replace(other); | |
| 407 | return; | |
| 408 | } | |
| 409 | ||
| 410 | if (traced) | |
| 411 | printTraceSymbol(&other); | |
| 412 | ||
| 413 | if (isLazy()) { | |
| 414 | // An undefined weak will not fetch archive members. See comment on Lazy in | |
| 415 | // Symbols.h for the details. | |
| 416 | if (other.binding == STB_WEAK) { | |
| 417 | binding = STB_WEAK; | |
| 418 | type = other.type; | |
| 419 | return; | |
| 420 | } | |
| 421 | ||
| 422 | // Do extra check for --warn-backrefs. | |
| 423 | // | |
| 424 | // --warn-backrefs is an option to prevent an undefined reference from | |
| 425 | // fetching an archive member written earlier in the command line. It can be | |
| 426 | // used to keep compatibility with GNU linkers to some degree. | |
| 427 | // I'll explain the feature and why you may find it useful in this comment. | |
| 428 | // | |
| 429 | // lld's symbol resolution semantics is more relaxed than traditional Unix | |
| 430 | // linkers. For example, | |
| 431 | // | |
| 432 | // ld.lld foo.a bar.o | |
| 433 | // | |
| 434 | // succeeds even if bar.o contains an undefined symbol that has to be | |
| 435 | // resolved by some object file in foo.a. Traditional Unix linkers don't | |
| 436 | // allow this kind of backward reference, as they visit each file only once | |
| 437 | // from left to right in the command line while resolving all undefined | |
| 438 | // symbols at the moment of visiting. | |
| 439 | // | |
| 440 | // In the above case, since there's no undefined symbol when a linker visits | |
| 441 | // foo.a, no files are pulled out from foo.a, and because the linker forgets | |
| 442 | // about foo.a after visiting, it can't resolve undefined symbols in bar.o | |
| 443 | // that could have been resolved otherwise. | |
| 444 | // | |
| 445 | // That lld accepts more relaxed form means that (besides it'd make more | |
| 446 | // sense) you can accidentally write a command line or a build file that | |
| 447 | // works only with lld, even if you have a plan to distribute it to wider | |
| 448 | // users who may be using GNU linkers. With --warn-backrefs, you can detect | |
| 449 | // a library order that doesn't work with other Unix linkers. | |
| 450 | // | |
| 451 | // The option is also useful to detect cyclic dependencies between static | |
| 452 | // archives. Again, lld accepts | |
| 453 | // | |
| 454 | // ld.lld foo.a bar.a | |
| 455 | // | |
| 456 | // even if foo.a and bar.a depend on each other. With --warn-backrefs, it is | |
| 457 | // handled as an error. | |
| 458 | // | |
| 459 | // Here is how the option works. We assign a group ID to each file. A file | |
| 460 | // with a smaller group ID can pull out object files from an archive file | |
| 461 | // with an equal or greater group ID. Otherwise, it is a reverse dependency | |
| 462 | // and an error. | |
| 463 | // | |
| 464 | // A file outside --{start,end}-group gets a fresh ID when instantiated. All | |
| 465 | // files within the same --{start,end}-group get the same group ID. E.g. | |
| 466 | // | |
| 467 | // ld.lld A B --start-group C D --end-group E | |
| 468 | // | |
| 469 | // A forms group 0. B form group 1. C and D (including their member object | |
| 470 | // files) form group 2. E forms group 3. I think that you can see how this | |
| 471 | // group assignment rule simulates the traditional linker's semantics. | |
| 472 | bool backref = config->warnBackrefs && other.file && | |
| 473 | file->groupId < other.file->groupId; | |
| 474 | fetch(); | |
| 475 | ||
| 476 | // We don't report backward references to weak symbols as they can be | |
| 477 | // overridden later. | |
| 478 | if (backref && !isWeak()) | |
| 479 | warn("backward reference detected: " + other.getName() + " in " + | |
| 480 | toString(other.file) + " refers to " + toString(file)); | |
| 481 | return; | |
| 482 | } | |
| 483 | ||
| 484 | // Undefined symbols in a SharedFile do not change the binding. | |
| 485 | if (dyn_cast_or_null<SharedFile>(other.file)) | |
| 486 | return; | |
| 487 | ||
| 488 | if (isUndefined()) { | |
| 489 | // The binding may "upgrade" from weak to non-weak. | |
| 490 | if (other.binding != STB_WEAK) | |
| 491 | binding = other.binding; | |
| 492 | } else if (auto *s = dyn_cast<SharedSymbol>(this)) { | |
| 493 | // The binding of a SharedSymbol will be weak if there is at least one | |
| 494 | // reference and all are weak. The binding has one opportunity to change to | |
| 495 | // weak: if the first reference is weak. | |
| 496 | if (other.binding != STB_WEAK || !s->referenced) | |
| 497 | binding = other.binding; | |
| 498 | s->referenced = true; | |
| 499 | } | |
| 500 | } | |
| 501 | ||
| 502 | // Using .symver foo,foo@@VER unfortunately creates two symbols: foo and | |
| 503 | // foo@@VER. We want to effectively ignore foo, so give precedence to | |
| 504 | // foo@@VER. | |
| 505 | // FIXME: If users can transition to using | |
| 506 | // .symver foo,foo@@@VER | |
| 507 | // we can delete this hack. | |
| 508 | static int compareVersion(StringRef a, StringRef b) { | |
| 509 | bool x = a.contains("@@"); | |
| 510 | bool y = b.contains("@@"); | |
| 511 | if (!x && y) | |
| 512 | return 1; | |
| 513 | if (x && !y) | |
| 514 | return -1; | |
| 515 | return 0; | |
| 516 | } | |
| 517 | ||
| 518 | // Compare two symbols. Return 1 if the new symbol should win, -1 if | |
| 519 | // the new symbol should lose, or 0 if there is a conflict. | |
| 520 | int Symbol::compare(const Symbol *other) const { | |
| 521 | assert(other->isDefined() || other->isCommon()); | |
| 522 | ||
| 523 | if (!isDefined() && !isCommon()) | |
| 524 | return 1; | |
| 525 | ||
| 526 | if (int cmp = compareVersion(getName(), other->getName())) | |
| 527 | return cmp; | |
| 528 | ||
| 529 | if (other->isWeak()) | |
| 530 | return -1; | |
| 531 | ||
| 532 | if (isWeak()) | |
| 533 | return 1; | |
| 534 | ||
| 535 | if (isCommon() && other->isCommon()) { | |
| 536 | if (config->warnCommon) | |
| 537 | warn("multiple common of " + getName()); | |
| 538 | return 0; | |
| 539 | } | |
| 540 | ||
| 541 | if (isCommon()) { | |
| 542 | if (config->warnCommon) | |
| 543 | warn("common " + getName() + " is overridden"); | |
| 544 | return 1; | |
| 545 | } | |
| 546 | ||
| 547 | if (other->isCommon()) { | |
| 548 | if (config->warnCommon) | |
| 549 | warn("common " + getName() + " is overridden"); | |
| 550 | return -1; | |
| 551 | } | |
| 552 | ||
| 553 | auto *oldSym = cast<Defined>(this); | |
| 554 | auto *newSym = cast<Defined>(other); | |
| 555 | ||
| 556 | if (other->file && isa<BitcodeFile>(other->file)) | |
| 557 | return 0; | |
| 558 | ||
| 559 | if (!oldSym->section && !newSym->section && oldSym->value == newSym->value && | |
| 560 | newSym->binding == STB_GLOBAL) | |
| 561 | return -1; | |
| 562 | ||
| 563 | return 0; | |
| 564 | } | |
| 565 | ||
| 566 | static void reportDuplicate(Symbol *sym, InputFile *newFile, | |
| 567 | InputSectionBase *errSec, uint64_t errOffset) { | |
| 568 | if (config->allowMultipleDefinition) | |
| 569 | return; | |
| 570 | ||
| 571 | Defined *d = cast<Defined>(sym); | |
| 572 | if (!d->section || !errSec) { | |
| 573 | error("duplicate symbol: " + toString(*sym) + "\n>>> defined in " + | |
| 574 | toString(sym->file) + "\n>>> defined in " + toString(newFile)); | |
| 575 | return; | |
| 576 | } | |
| 577 | ||
| 578 | // Construct and print an error message in the form of: | |
| 579 | // | |
| 580 | // ld.lld: error: duplicate symbol: foo | |
| 581 | // >>> defined at bar.c:30 | |
| 582 | // >>> bar.o (/home/alice/src/bar.o) | |
| 583 | // >>> defined at baz.c:563 | |
| 584 | // >>> baz.o in archive libbaz.a | |
| 585 | auto *sec1 = cast<InputSectionBase>(d->section); | |
| 586 | std::string src1 = sec1->getSrcMsg(*sym, d->value); | |
| 587 | std::string obj1 = sec1->getObjMsg(d->value); | |
| 588 | std::string src2 = errSec->getSrcMsg(*sym, errOffset); | |
| 589 | std::string obj2 = errSec->getObjMsg(errOffset); | |
| 590 | ||
| 591 | std::string msg = "duplicate symbol: " + toString(*sym) + "\n>>> defined at "; | |
| 592 | if (!src1.empty()) | |
| 593 | msg += src1 + "\n>>> "; | |
| 594 | msg += obj1 + "\n>>> defined at "; | |
| 595 | if (!src2.empty()) | |
| 596 | msg += src2 + "\n>>> "; | |
| 597 | msg += obj2; | |
| 598 | error(msg); | |
| 599 | } | |
| 600 | ||
| 601 | void Symbol::resolveCommon(const CommonSymbol &other) { | |
| 602 | int cmp = compare(&other); | |
| 603 | if (cmp < 0) | |
| 604 | return; | |
| 605 | ||
| 606 | if (cmp > 0) { | |
| 607 | replace(other); | |
| 608 | return; | |
| 609 | } | |
| 610 | ||
| 611 | CommonSymbol *oldSym = cast<CommonSymbol>(this); | |
| 612 | ||
| 613 | oldSym->alignment = std::max(oldSym->alignment, other.alignment); | |
| 614 | if (oldSym->size < other.size) { | |
| 615 | oldSym->file = other.file; | |
| 616 | oldSym->size = other.size; | |
| 617 | } | |
| 618 | } | |
| 619 | ||
| 620 | void Symbol::resolveDefined(const Defined &other) { | |
| 621 | int cmp = compare(&other); | |
| 622 | if (cmp > 0) | |
| 623 | replace(other); | |
| 624 | else if (cmp == 0) | |
| 625 | reportDuplicate(this, other.file, | |
| 626 | dyn_cast_or_null<InputSectionBase>(other.section), | |
| 627 | other.value); | |
| 628 | } | |
| 629 | ||
| 630 | template <class LazyT> void Symbol::resolveLazy(const LazyT &other) { | |
| 631 | if (!isUndefined()) | |
| 632 | return; | |
| 633 | ||
| 634 | // An undefined weak will not fetch archive members. See comment on Lazy in | |
| 635 | // Symbols.h for the details. | |
| 636 | if (isWeak()) { | |
| 637 | uint8_t ty = type; | |
| 638 | replace(other); | |
| 639 | type = ty; | |
| 640 | binding = STB_WEAK; | |
| 641 | return; | |
| 642 | } | |
| 643 | ||
| 644 | other.fetch(); | |
| 645 | } | |
| 646 | ||
| 647 | void Symbol::resolveShared(const SharedSymbol &other) { | |
| 648 | if (visibility == STV_DEFAULT && (isUndefined() || isLazy())) { | |
| 649 | // An undefined symbol with non default visibility must be satisfied | |
| 650 | // in the same DSO. | |
| 651 | uint8_t bind = binding; | |
| 652 | replace(other); | |
| 653 | binding = bind; | |
| 654 | cast<SharedSymbol>(this)->referenced = true; | |
| 655 | } | |
| 305 | 656 | } |
deps/lld/ELF/Symbols.h+298-163| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Symbols.h ------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -14,6 +13,7 @@ |
| 14 | 13 | #ifndef LLD_ELF_SYMBOLS_H |
| 15 | 14 | #define LLD_ELF_SYMBOLS_H |
| 16 | 15 | |
| 16 | #include "InputFiles.h" | |
| 17 | 17 | #include "InputSection.h" |
| 18 | 18 | #include "lld/Common/LLVM.h" |
| 19 | 19 | #include "lld/Common/Strings.h" |
| ... | ... | @@ -22,8 +22,14 @@ |
| 22 | 22 | |
| 23 | 23 | namespace lld { |
| 24 | 24 | namespace elf { |
| 25 | class Symbol; | |
| 25 | class CommonSymbol; | |
| 26 | class Defined; | |
| 26 | 27 | class InputFile; |
| 28 | class LazyArchive; | |
| 29 | class LazyObject; | |
| 30 | class SharedSymbol; | |
| 31 | class Symbol; | |
| 32 | class Undefined; | |
| 27 | 33 | } // namespace elf |
| 28 | 34 | |
| 29 | 35 | std::string toString(const elf::Symbol &); |
| ... | ... | @@ -31,15 +37,6 @@ std::string toString(const elf::InputFile *); |
| 31 | 37 | |
| 32 | 38 | namespace elf { |
| 33 | 39 | |
| 34 | class ArchiveFile; | |
| 35 | class BitcodeFile; | |
| 36 | class BssSection; | |
| 37 | class InputFile; | |
| 38 | class LazyObjFile; | |
| 39 | template <class ELFT> class ObjFile; | |
| 40 | class OutputSection; | |
| 41 | template <class ELFT> class SharedFile; | |
| 42 | ||
| 43 | 40 | // This is a StringRef-like container that doesn't run strlen(). |
| 44 | 41 | // |
| 45 | 42 | // ELF string tables contain a lot of null-terminated strings. Most of them |
| ... | ... | @@ -47,11 +44,11 @@ template <class ELFT> class SharedFile; |
| 47 | 44 | // and the linker doesn't use local symbol names for name resolution. So, we |
| 48 | 45 | // use this class to represents strings read from string tables. |
| 49 | 46 | struct StringRefZ { |
| 50 | StringRefZ(const char *S) : Data(S), Size(-1) {} | |
| 51 | StringRefZ(StringRef S) : Data(S.data()), Size(S.size()) {} | |
| 47 | StringRefZ(const char *s) : data(s), size(-1) {} | |
| 48 | StringRefZ(StringRef s) : data(s.data()), size(s.size()) {} | |
| 52 | 49 | |
| 53 | const char *Data; | |
| 54 | const uint32_t Size; | |
| 50 | const char *data; | |
| 51 | const uint32_t size; | |
| 55 | 52 | }; |
| 56 | 53 | |
| 57 | 54 | // The base class for real symbol classes. |
| ... | ... | @@ -60,85 +57,91 @@ public: |
| 60 | 57 | enum Kind { |
| 61 | 58 | PlaceholderKind, |
| 62 | 59 | DefinedKind, |
| 60 | CommonKind, | |
| 63 | 61 | SharedKind, |
| 64 | 62 | UndefinedKind, |
| 65 | 63 | LazyArchiveKind, |
| 66 | 64 | LazyObjectKind, |
| 67 | 65 | }; |
| 68 | 66 | |
| 69 | Kind kind() const { return static_cast<Kind>(SymbolKind); } | |
| 67 | Kind kind() const { return static_cast<Kind>(symbolKind); } | |
| 70 | 68 | |
| 71 | 69 | // The file from which this symbol was created. |
| 72 | InputFile *File; | |
| 70 | InputFile *file; | |
| 73 | 71 | |
| 74 | 72 | protected: |
| 75 | const char *NameData; | |
| 76 | mutable uint32_t NameSize; | |
| 73 | const char *nameData; | |
| 74 | mutable uint32_t nameSize; | |
| 77 | 75 | |
| 78 | 76 | public: |
| 79 | uint32_t DynsymIndex = 0; | |
| 80 | uint32_t GotIndex = -1; | |
| 81 | uint32_t PltIndex = -1; | |
| 77 | uint32_t dynsymIndex = 0; | |
| 78 | uint32_t gotIndex = -1; | |
| 79 | uint32_t pltIndex = -1; | |
| 82 | 80 | |
| 83 | uint32_t GlobalDynIndex = -1; | |
| 81 | uint32_t globalDynIndex = -1; | |
| 84 | 82 | |
| 85 | 83 | // This field is a index to the symbol's version definition. |
| 86 | uint32_t VerdefIndex = -1; | |
| 84 | uint32_t verdefIndex = -1; | |
| 87 | 85 | |
| 88 | 86 | // Version definition index. |
| 89 | uint16_t VersionId; | |
| 87 | uint16_t versionId; | |
| 90 | 88 | |
| 91 | 89 | // An index into the .branch_lt section on PPC64. |
| 92 | uint16_t PPC64BranchltIndex = -1; | |
| 90 | uint16_t ppc64BranchltIndex = -1; | |
| 93 | 91 | |
| 94 | // Symbol binding. This is not overwritten by replaceSymbol to track | |
| 92 | // Symbol binding. This is not overwritten by replace() to track | |
| 95 | 93 | // changes during resolution. In particular: |
| 96 | 94 | // - An undefined weak is still weak when it resolves to a shared library. |
| 97 | 95 | // - An undefined weak will not fetch archive members, but we have to |
| 98 | 96 | // remember it is weak. |
| 99 | uint8_t Binding; | |
| 97 | uint8_t binding; | |
| 100 | 98 | |
| 101 | 99 | // The following fields have the same meaning as the ELF symbol attributes. |
| 102 | uint8_t Type; // symbol type | |
| 103 | uint8_t StOther; // st_other field value | |
| 100 | uint8_t type; // symbol type | |
| 101 | uint8_t stOther; // st_other field value | |
| 104 | 102 | |
| 105 | uint8_t SymbolKind; | |
| 103 | uint8_t symbolKind; | |
| 106 | 104 | |
| 107 | 105 | // Symbol visibility. This is the computed minimum visibility of all |
| 108 | 106 | // observed non-DSO symbols. |
| 109 | unsigned Visibility : 2; | |
| 107 | unsigned visibility : 2; | |
| 110 | 108 | |
| 111 | 109 | // True if the symbol was used for linking and thus need to be added to the |
| 112 | 110 | // output file's symbol table. This is true for all symbols except for |
| 113 | // unreferenced DSO symbols and bitcode symbols that are unreferenced except | |
| 114 | // by other bitcode objects. | |
| 115 | unsigned IsUsedInRegularObj : 1; | |
| 111 | // unreferenced DSO symbols, lazy (archive) symbols, and bitcode symbols that | |
| 112 | // are unreferenced except by other bitcode objects. | |
| 113 | unsigned isUsedInRegularObj : 1; | |
| 116 | 114 | |
| 117 | 115 | // If this flag is true and the symbol has protected or default visibility, it |
| 118 | 116 | // will appear in .dynsym. This flag is set by interposable DSO symbols in |
| 119 | 117 | // executables, by most symbols in DSOs and executables built with |
| 120 | 118 | // --export-dynamic, and by dynamic lists. |
| 121 | unsigned ExportDynamic : 1; | |
| 119 | unsigned exportDynamic : 1; | |
| 122 | 120 | |
| 123 | 121 | // False if LTO shouldn't inline whatever this symbol points to. If a symbol |
| 124 | 122 | // is overwritten after LTO, LTO shouldn't inline the symbol because it |
| 125 | 123 | // doesn't know the final contents of the symbol. |
| 126 | unsigned CanInline : 1; | |
| 124 | unsigned canInline : 1; | |
| 127 | 125 | |
| 128 | 126 | // True if this symbol is specified by --trace-symbol option. |
| 129 | unsigned Traced : 1; | |
| 127 | unsigned traced : 1; | |
| 128 | ||
| 129 | inline void replace(const Symbol &New); | |
| 130 | 130 | |
| 131 | 131 | bool includeInDynsym() const; |
| 132 | 132 | uint8_t computeBinding() const; |
| 133 | bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; } | |
| 133 | bool isWeak() const { return binding == llvm::ELF::STB_WEAK; } | |
| 134 | ||
| 135 | bool isUndefined() const { return symbolKind == UndefinedKind; } | |
| 136 | bool isCommon() const { return symbolKind == CommonKind; } | |
| 137 | bool isDefined() const { return symbolKind == DefinedKind; } | |
| 138 | bool isShared() const { return symbolKind == SharedKind; } | |
| 139 | bool isPlaceholder() const { return symbolKind == PlaceholderKind; } | |
| 134 | 140 | |
| 135 | bool isUndefined() const { return SymbolKind == UndefinedKind; } | |
| 136 | bool isDefined() const { return SymbolKind == DefinedKind; } | |
| 137 | bool isShared() const { return SymbolKind == SharedKind; } | |
| 138 | bool isLocal() const { return Binding == llvm::ELF::STB_LOCAL; } | |
| 141 | bool isLocal() const { return binding == llvm::ELF::STB_LOCAL; } | |
| 139 | 142 | |
| 140 | 143 | bool isLazy() const { |
| 141 | return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind; | |
| 144 | return symbolKind == LazyArchiveKind || symbolKind == LazyObjectKind; | |
| 142 | 145 | } |
| 143 | 146 | |
| 144 | 147 | // True if this is an undefined weak symbol. This only works once |
| ... | ... | @@ -149,23 +152,23 @@ public: |
| 149 | 152 | } |
| 150 | 153 | |
| 151 | 154 | StringRef getName() const { |
| 152 | if (NameSize == (uint32_t)-1) | |
| 153 | NameSize = strlen(NameData); | |
| 154 | return {NameData, NameSize}; | |
| 155 | if (nameSize == (uint32_t)-1) | |
| 156 | nameSize = strlen(nameData); | |
| 157 | return {nameData, nameSize}; | |
| 155 | 158 | } |
| 156 | 159 | |
| 157 | void setName(StringRef S) { | |
| 158 | NameData = S.data(); | |
| 159 | NameSize = S.size(); | |
| 160 | void setName(StringRef s) { | |
| 161 | nameData = s.data(); | |
| 162 | nameSize = s.size(); | |
| 160 | 163 | } |
| 161 | 164 | |
| 162 | 165 | void parseSymbolVersion(); |
| 163 | 166 | |
| 164 | bool isInGot() const { return GotIndex != -1U; } | |
| 165 | bool isInPlt() const { return PltIndex != -1U; } | |
| 166 | bool isInPPC64Branchlt() const { return PPC64BranchltIndex != 0xffff; } | |
| 167 | bool isInGot() const { return gotIndex != -1U; } | |
| 168 | bool isInPlt() const { return pltIndex != -1U; } | |
| 169 | bool isInPPC64Branchlt() const { return ppc64BranchltIndex != 0xffff; } | |
| 167 | 170 | |
| 168 | uint64_t getVA(int64_t Addend = 0) const; | |
| 171 | uint64_t getVA(int64_t addend = 0) const; | |
| 169 | 172 | |
| 170 | 173 | uint64_t getGotOffset() const; |
| 171 | 174 | uint64_t getGotVA() const; |
| ... | ... | @@ -177,81 +180,164 @@ public: |
| 177 | 180 | uint64_t getSize() const; |
| 178 | 181 | OutputSection *getOutputSection() const; |
| 179 | 182 | |
| 183 | // The following two functions are used for symbol resolution. | |
| 184 | // | |
| 185 | // You are expected to call mergeProperties for all symbols in input | |
| 186 | // files so that attributes that are attached to names rather than | |
| 187 | // indivisual symbol (such as visibility) are merged together. | |
| 188 | // | |
| 189 | // Every time you read a new symbol from an input, you are supposed | |
| 190 | // to call resolve() with the new symbol. That function replaces | |
| 191 | // "this" object as a result of name resolution if the new symbol is | |
| 192 | // more appropriate to be included in the output. | |
| 193 | // | |
| 194 | // For example, if "this" is an undefined symbol and a new symbol is | |
| 195 | // a defined symbol, "this" is replaced with the new symbol. | |
| 196 | void mergeProperties(const Symbol &other); | |
| 197 | void resolve(const Symbol &other); | |
| 198 | ||
| 199 | // If this is a lazy symbol, fetch an input file and add the symbol | |
| 200 | // in the file to the symbol table. Calling this function on | |
| 201 | // non-lazy object causes a runtime error. | |
| 202 | void fetch() const; | |
| 203 | ||
| 204 | private: | |
| 205 | static bool isExportDynamic(Kind k, uint8_t visibility) { | |
| 206 | if (k == SharedKind) | |
| 207 | return visibility == llvm::ELF::STV_DEFAULT; | |
| 208 | return config->shared || config->exportDynamic; | |
| 209 | } | |
| 210 | ||
| 211 | void resolveUndefined(const Undefined &other); | |
| 212 | void resolveCommon(const CommonSymbol &other); | |
| 213 | void resolveDefined(const Defined &other); | |
| 214 | template <class LazyT> void resolveLazy(const LazyT &other); | |
| 215 | void resolveShared(const SharedSymbol &other); | |
| 216 | ||
| 217 | int compare(const Symbol *other) const; | |
| 218 | ||
| 219 | inline size_t getSymbolSize() const; | |
| 220 | ||
| 180 | 221 | protected: |
| 181 | Symbol(Kind K, InputFile *File, StringRefZ Name, uint8_t Binding, | |
| 182 | uint8_t StOther, uint8_t Type) | |
| 183 | : File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding), | |
| 184 | Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false), | |
| 185 | IsInIplt(false), IsInIgot(false), IsPreemptible(false), | |
| 186 | Used(!Config->GcSections), NeedsTocRestore(false), | |
| 187 | ScriptDefined(false) {} | |
| 222 | Symbol(Kind k, InputFile *file, StringRefZ name, uint8_t binding, | |
| 223 | uint8_t stOther, uint8_t type) | |
| 224 | : file(file), nameData(name.data), nameSize(name.size), binding(binding), | |
| 225 | type(type), stOther(stOther), symbolKind(k), visibility(stOther & 3), | |
| 226 | isUsedInRegularObj(!file || file->kind() == InputFile::ObjKind), | |
| 227 | exportDynamic(isExportDynamic(k, visibility)), canInline(false), | |
| 228 | traced(false), needsPltAddr(false), isInIplt(false), gotInIgot(false), | |
| 229 | isPreemptible(false), used(!config->gcSections), needsTocRestore(false), | |
| 230 | scriptDefined(false) {} | |
| 188 | 231 | |
| 189 | 232 | public: |
| 190 | 233 | // True the symbol should point to its PLT entry. |
| 191 | 234 | // For SharedSymbol only. |
| 192 | unsigned NeedsPltAddr : 1; | |
| 235 | unsigned needsPltAddr : 1; | |
| 193 | 236 | |
| 194 | // True if this symbol is in the Iplt sub-section of the Plt. | |
| 195 | unsigned IsInIplt : 1; | |
| 237 | // True if this symbol is in the Iplt sub-section of the Plt and the Igot | |
| 238 | // sub-section of the .got.plt or .got. | |
| 239 | unsigned isInIplt : 1; | |
| 196 | 240 | |
| 197 | // True if this symbol is in the Igot sub-section of the .got.plt or .got. | |
| 198 | unsigned IsInIgot : 1; | |
| 241 | // True if this symbol needs a GOT entry and its GOT entry is actually in | |
| 242 | // Igot. This will be true only for certain non-preemptible ifuncs. | |
| 243 | unsigned gotInIgot : 1; | |
| 199 | 244 | |
| 200 | 245 | // True if this symbol is preemptible at load time. |
| 201 | unsigned IsPreemptible : 1; | |
| 246 | unsigned isPreemptible : 1; | |
| 202 | 247 | |
| 203 | 248 | // True if an undefined or shared symbol is used from a live section. |
| 204 | unsigned Used : 1; | |
| 249 | unsigned used : 1; | |
| 205 | 250 | |
| 206 | 251 | // True if a call to this symbol needs to be followed by a restore of the |
| 207 | 252 | // PPC64 toc pointer. |
| 208 | unsigned NeedsTocRestore : 1; | |
| 253 | unsigned needsTocRestore : 1; | |
| 209 | 254 | |
| 210 | 255 | // True if this symbol is defined by a linker script. |
| 211 | unsigned ScriptDefined : 1; | |
| 212 | ||
| 213 | bool isSection() const { return Type == llvm::ELF::STT_SECTION; } | |
| 214 | bool isTls() const { return Type == llvm::ELF::STT_TLS; } | |
| 215 | bool isFunc() const { return Type == llvm::ELF::STT_FUNC; } | |
| 216 | bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; } | |
| 217 | bool isObject() const { return Type == llvm::ELF::STT_OBJECT; } | |
| 218 | bool isFile() const { return Type == llvm::ELF::STT_FILE; } | |
| 256 | unsigned scriptDefined : 1; | |
| 257 | ||
| 258 | // The partition whose dynamic symbol table contains this symbol's definition. | |
| 259 | uint8_t partition = 1; | |
| 260 | ||
| 261 | bool isSection() const { return type == llvm::ELF::STT_SECTION; } | |
| 262 | bool isTls() const { return type == llvm::ELF::STT_TLS; } | |
| 263 | bool isFunc() const { return type == llvm::ELF::STT_FUNC; } | |
| 264 | bool isGnuIFunc() const { return type == llvm::ELF::STT_GNU_IFUNC; } | |
| 265 | bool isObject() const { return type == llvm::ELF::STT_OBJECT; } | |
| 266 | bool isFile() const { return type == llvm::ELF::STT_FILE; } | |
| 219 | 267 | }; |
| 220 | 268 | |
| 221 | 269 | // Represents a symbol that is defined in the current output file. |
| 222 | 270 | class Defined : public Symbol { |
| 223 | 271 | public: |
| 224 | Defined(InputFile *File, StringRefZ Name, uint8_t Binding, uint8_t StOther, | |
| 225 | uint8_t Type, uint64_t Value, uint64_t Size, SectionBase *Section) | |
| 226 | : Symbol(DefinedKind, File, Name, Binding, StOther, Type), Value(Value), | |
| 227 | Size(Size), Section(Section) {} | |
| 272 | Defined(InputFile *file, StringRefZ name, uint8_t binding, uint8_t stOther, | |
| 273 | uint8_t type, uint64_t value, uint64_t size, SectionBase *section) | |
| 274 | : Symbol(DefinedKind, file, name, binding, stOther, type), value(value), | |
| 275 | size(size), section(section) {} | |
| 276 | ||
| 277 | static bool classof(const Symbol *s) { return s->isDefined(); } | |
| 278 | ||
| 279 | uint64_t value; | |
| 280 | uint64_t size; | |
| 281 | SectionBase *section; | |
| 282 | }; | |
| 283 | ||
| 284 | // Represents a common symbol. | |
| 285 | // | |
| 286 | // On Unix, it is traditionally allowed to write variable definitions | |
| 287 | // without initialization expressions (such as "int foo;") to header | |
| 288 | // files. Such definition is called "tentative definition". | |
| 289 | // | |
| 290 | // Using tentative definition is usually considered a bad practice | |
| 291 | // because you should write only declarations (such as "extern int | |
| 292 | // foo;") to header files. Nevertheless, the linker and the compiler | |
| 293 | // have to do something to support bad code by allowing duplicate | |
| 294 | // definitions for this particular case. | |
| 295 | // | |
| 296 | // Common symbols represent variable definitions without initializations. | |
| 297 | // The compiler creates common symbols when it sees varaible definitions | |
| 298 | // without initialization (you can suppress this behavior and let the | |
| 299 | // compiler create a regular defined symbol by -fno-common). | |
| 300 | // | |
| 301 | // The linker allows common symbols to be replaced by regular defined | |
| 302 | // symbols. If there are remaining common symbols after name resolution is | |
| 303 | // complete, they are converted to regular defined symbols in a .bss | |
| 304 | // section. (Therefore, the later passes don't see any CommonSymbols.) | |
| 305 | class CommonSymbol : public Symbol { | |
| 306 | public: | |
| 307 | CommonSymbol(InputFile *file, StringRefZ name, uint8_t binding, | |
| 308 | uint8_t stOther, uint8_t type, uint64_t alignment, uint64_t size) | |
| 309 | : Symbol(CommonKind, file, name, binding, stOther, type), | |
| 310 | alignment(alignment), size(size) {} | |
| 228 | 311 | |
| 229 | static bool classof(const Symbol *S) { return S->isDefined(); } | |
| 312 | static bool classof(const Symbol *s) { return s->isCommon(); } | |
| 230 | 313 | |
| 231 | uint64_t Value; | |
| 232 | uint64_t Size; | |
| 233 | SectionBase *Section; | |
| 314 | uint32_t alignment; | |
| 315 | uint64_t size; | |
| 234 | 316 | }; |
| 235 | 317 | |
| 236 | 318 | class Undefined : public Symbol { |
| 237 | 319 | public: |
| 238 | Undefined(InputFile *File, StringRefZ Name, uint8_t Binding, uint8_t StOther, | |
| 239 | uint8_t Type) | |
| 240 | : Symbol(UndefinedKind, File, Name, Binding, StOther, Type) {} | |
| 320 | Undefined(InputFile *file, StringRefZ name, uint8_t binding, uint8_t stOther, | |
| 321 | uint8_t type, uint32_t discardedSecIdx = 0) | |
| 322 | : Symbol(UndefinedKind, file, name, binding, stOther, type), | |
| 323 | discardedSecIdx(discardedSecIdx) {} | |
| 241 | 324 | |
| 242 | static bool classof(const Symbol *S) { return S->kind() == UndefinedKind; } | |
| 325 | static bool classof(const Symbol *s) { return s->kind() == UndefinedKind; } | |
| 326 | ||
| 327 | // The section index if in a discarded section, 0 otherwise. | |
| 328 | uint32_t discardedSecIdx; | |
| 243 | 329 | }; |
| 244 | 330 | |
| 245 | 331 | class SharedSymbol : public Symbol { |
| 246 | 332 | public: |
| 247 | static bool classof(const Symbol *S) { return S->kind() == SharedKind; } | |
| 248 | ||
| 249 | SharedSymbol(InputFile &File, StringRef Name, uint8_t Binding, | |
| 250 | uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size, | |
| 251 | uint32_t Alignment, uint32_t VerdefIndex) | |
| 252 | : Symbol(SharedKind, &File, Name, Binding, StOther, Type), | |
| 253 | Alignment(Alignment), Value(Value), Size(Size) { | |
| 254 | this->VerdefIndex = VerdefIndex; | |
| 333 | static bool classof(const Symbol *s) { return s->kind() == SharedKind; } | |
| 334 | ||
| 335 | SharedSymbol(InputFile &file, StringRef name, uint8_t binding, | |
| 336 | uint8_t stOther, uint8_t type, uint64_t value, uint64_t size, | |
| 337 | uint32_t alignment, uint32_t verdefIndex) | |
| 338 | : Symbol(SharedKind, &file, name, binding, stOther, type), value(value), | |
| 339 | size(size), alignment(alignment) { | |
| 340 | this->verdefIndex = verdefIndex; | |
| 255 | 341 | // GNU ifunc is a mechanism to allow user-supplied functions to |
| 256 | 342 | // resolve PLT slot values at load-time. This is contrary to the |
| 257 | 343 | // regular symbol resolution scheme in which symbols are resolved just |
| ... | ... | @@ -268,18 +354,20 @@ public: |
| 268 | 354 | // For DSO symbols, we always call them through PLT slots anyway. |
| 269 | 355 | // So there's no difference between GNU ifunc and regular function |
| 270 | 356 | // symbols if they are in DSOs. So we can handle GNU_IFUNC as FUNC. |
| 271 | if (this->Type == llvm::ELF::STT_GNU_IFUNC) | |
| 272 | this->Type = llvm::ELF::STT_FUNC; | |
| 357 | if (this->type == llvm::ELF::STT_GNU_IFUNC) | |
| 358 | this->type = llvm::ELF::STT_FUNC; | |
| 273 | 359 | } |
| 274 | 360 | |
| 275 | template <class ELFT> SharedFile<ELFT> &getFile() const { | |
| 276 | return *cast<SharedFile<ELFT>>(File); | |
| 277 | } | |
| 361 | SharedFile &getFile() const { return *cast<SharedFile>(file); } | |
| 278 | 362 | |
| 279 | uint32_t Alignment; | |
| 363 | uint64_t value; // st_value | |
| 364 | uint64_t size; // st_size | |
| 365 | uint32_t alignment; | |
| 280 | 366 | |
| 281 | uint64_t Value; // st_value | |
| 282 | uint64_t Size; // st_size | |
| 367 | // This is true if there has been at least one undefined reference to the | |
| 368 | // symbol. The binding may change to STB_WEAK if the first undefined reference | |
| 369 | // is weak. | |
| 370 | bool referenced = false; | |
| 283 | 371 | }; |
| 284 | 372 | |
| 285 | 373 | // LazyArchive and LazyObject represent a symbols that is not yet in the link, |
| ... | ... | @@ -298,121 +386,168 @@ public: |
| 298 | 386 | // symbol. |
| 299 | 387 | class LazyArchive : public Symbol { |
| 300 | 388 | public: |
| 301 | LazyArchive(InputFile &File, uint8_t Type, | |
| 302 | const llvm::object::Archive::Symbol S) | |
| 303 | : Symbol(LazyArchiveKind, &File, S.getName(), llvm::ELF::STB_GLOBAL, | |
| 304 | llvm::ELF::STV_DEFAULT, Type), | |
| 305 | Sym(S) {} | |
| 389 | LazyArchive(InputFile &file, const llvm::object::Archive::Symbol s) | |
| 390 | : Symbol(LazyArchiveKind, &file, s.getName(), llvm::ELF::STB_GLOBAL, | |
| 391 | llvm::ELF::STV_DEFAULT, llvm::ELF::STT_NOTYPE), | |
| 392 | sym(s) {} | |
| 306 | 393 | |
| 307 | static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; } | |
| 394 | static bool classof(const Symbol *s) { return s->kind() == LazyArchiveKind; } | |
| 308 | 395 | |
| 309 | InputFile *fetch(); | |
| 310 | 396 | MemoryBufferRef getMemberBuffer(); |
| 311 | 397 | |
| 312 | private: | |
| 313 | const llvm::object::Archive::Symbol Sym; | |
| 398 | const llvm::object::Archive::Symbol sym; | |
| 314 | 399 | }; |
| 315 | 400 | |
| 316 | 401 | // LazyObject symbols represents symbols in object files between |
| 317 | 402 | // --start-lib and --end-lib options. |
| 318 | 403 | class LazyObject : public Symbol { |
| 319 | 404 | public: |
| 320 | LazyObject(InputFile &File, uint8_t Type, StringRef Name) | |
| 321 | : Symbol(LazyObjectKind, &File, Name, llvm::ELF::STB_GLOBAL, | |
| 322 | llvm::ELF::STV_DEFAULT, Type) {} | |
| 405 | LazyObject(InputFile &file, StringRef name) | |
| 406 | : Symbol(LazyObjectKind, &file, name, llvm::ELF::STB_GLOBAL, | |
| 407 | llvm::ELF::STV_DEFAULT, llvm::ELF::STT_NOTYPE) {} | |
| 323 | 408 | |
| 324 | static bool classof(const Symbol *S) { return S->kind() == LazyObjectKind; } | |
| 409 | static bool classof(const Symbol *s) { return s->kind() == LazyObjectKind; } | |
| 325 | 410 | }; |
| 326 | 411 | |
| 327 | 412 | // Some linker-generated symbols need to be created as |
| 328 | 413 | // Defined symbols. |
| 329 | 414 | struct ElfSym { |
| 330 | 415 | // __bss_start |
| 331 | static Defined *Bss; | |
| 416 | static Defined *bss; | |
| 332 | 417 | |
| 333 | 418 | // etext and _etext |
| 334 | static Defined *Etext1; | |
| 335 | static Defined *Etext2; | |
| 419 | static Defined *etext1; | |
| 420 | static Defined *etext2; | |
| 336 | 421 | |
| 337 | 422 | // edata and _edata |
| 338 | static Defined *Edata1; | |
| 339 | static Defined *Edata2; | |
| 423 | static Defined *edata1; | |
| 424 | static Defined *edata2; | |
| 340 | 425 | |
| 341 | 426 | // end and _end |
| 342 | static Defined *End1; | |
| 343 | static Defined *End2; | |
| 427 | static Defined *end1; | |
| 428 | static Defined *end2; | |
| 344 | 429 | |
| 345 | 430 | // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to |
| 346 | 431 | // be at some offset from the base of the .got section, usually 0 or |
| 347 | 432 | // the end of the .got. |
| 348 | static Defined *GlobalOffsetTable; | |
| 433 | static Defined *globalOffsetTable; | |
| 349 | 434 | |
| 350 | 435 | // _gp, _gp_disp and __gnu_local_gp symbols. Only for MIPS. |
| 351 | static Defined *MipsGp; | |
| 352 | static Defined *MipsGpDisp; | |
| 353 | static Defined *MipsLocalGp; | |
| 436 | static Defined *mipsGp; | |
| 437 | static Defined *mipsGpDisp; | |
| 438 | static Defined *mipsLocalGp; | |
| 354 | 439 | |
| 355 | 440 | // __rel{,a}_iplt_{start,end} symbols. |
| 356 | static Defined *RelaIpltStart; | |
| 357 | static Defined *RelaIpltEnd; | |
| 441 | static Defined *relaIpltStart; | |
| 442 | static Defined *relaIpltEnd; | |
| 443 | ||
| 444 | // __global_pointer$ for RISC-V. | |
| 445 | static Defined *riscvGlobalPointer; | |
| 446 | ||
| 447 | // _TLS_MODULE_BASE_ on targets that support TLSDESC. | |
| 448 | static Defined *tlsModuleBase; | |
| 358 | 449 | }; |
| 359 | 450 | |
| 360 | 451 | // A buffer class that is large enough to hold any Symbol-derived |
| 361 | 452 | // object. We allocate memory using this class and instantiate a symbol |
| 362 | 453 | // using the placement new. |
| 363 | 454 | union SymbolUnion { |
| 364 | alignas(Defined) char A[sizeof(Defined)]; | |
| 365 | alignas(Undefined) char C[sizeof(Undefined)]; | |
| 366 | alignas(SharedSymbol) char D[sizeof(SharedSymbol)]; | |
| 367 | alignas(LazyArchive) char E[sizeof(LazyArchive)]; | |
| 368 | alignas(LazyObject) char F[sizeof(LazyObject)]; | |
| 455 | alignas(Defined) char a[sizeof(Defined)]; | |
| 456 | alignas(CommonSymbol) char b[sizeof(CommonSymbol)]; | |
| 457 | alignas(Undefined) char c[sizeof(Undefined)]; | |
| 458 | alignas(SharedSymbol) char d[sizeof(SharedSymbol)]; | |
| 459 | alignas(LazyArchive) char e[sizeof(LazyArchive)]; | |
| 460 | alignas(LazyObject) char f[sizeof(LazyObject)]; | |
| 369 | 461 | }; |
| 370 | 462 | |
| 371 | void printTraceSymbol(Symbol *Sym); | |
| 372 | ||
| 373 | template <typename T, typename... ArgT> | |
| 374 | void replaceSymbol(Symbol *S, ArgT &&... Arg) { | |
| 375 | using llvm::ELF::STT_TLS; | |
| 463 | // It is important to keep the size of SymbolUnion small for performance and | |
| 464 | // memory usage reasons. 80 bytes is a soft limit based on the size of Defined | |
| 465 | // on a 64-bit system. | |
| 466 | static_assert(sizeof(SymbolUnion) <= 80, "SymbolUnion too large"); | |
| 376 | 467 | |
| 468 | template <typename T> struct AssertSymbol { | |
| 377 | 469 | static_assert(std::is_trivially_destructible<T>(), |
| 378 | 470 | "Symbol types must be trivially destructible"); |
| 379 | 471 | static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small"); |
| 380 | 472 | static_assert(alignof(T) <= alignof(SymbolUnion), |
| 381 | 473 | "SymbolUnion not aligned enough"); |
| 382 | assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr && | |
| 383 | "Not a Symbol"); | |
| 474 | }; | |
| 384 | 475 | |
| 385 | Symbol Sym = *S; | |
| 476 | static inline void assertSymbols() { | |
| 477 | AssertSymbol<Defined>(); | |
| 478 | AssertSymbol<CommonSymbol>(); | |
| 479 | AssertSymbol<Undefined>(); | |
| 480 | AssertSymbol<SharedSymbol>(); | |
| 481 | AssertSymbol<LazyArchive>(); | |
| 482 | AssertSymbol<LazyObject>(); | |
| 483 | } | |
| 386 | 484 | |
| 387 | new (S) T(std::forward<ArgT>(Arg)...); | |
| 485 | void printTraceSymbol(const Symbol *sym); | |
| 486 | ||
| 487 | size_t Symbol::getSymbolSize() const { | |
| 488 | switch (kind()) { | |
| 489 | case CommonKind: | |
| 490 | return sizeof(CommonSymbol); | |
| 491 | case DefinedKind: | |
| 492 | return sizeof(Defined); | |
| 493 | case LazyArchiveKind: | |
| 494 | return sizeof(LazyArchive); | |
| 495 | case LazyObjectKind: | |
| 496 | return sizeof(LazyObject); | |
| 497 | case SharedKind: | |
| 498 | return sizeof(SharedSymbol); | |
| 499 | case UndefinedKind: | |
| 500 | return sizeof(Undefined); | |
| 501 | case PlaceholderKind: | |
| 502 | return sizeof(Symbol); | |
| 503 | } | |
| 504 | llvm_unreachable("unknown symbol kind"); | |
| 505 | } | |
| 388 | 506 | |
| 389 | S->VersionId = Sym.VersionId; | |
| 390 | S->Visibility = Sym.Visibility; | |
| 391 | S->IsUsedInRegularObj = Sym.IsUsedInRegularObj; | |
| 392 | S->ExportDynamic = Sym.ExportDynamic; | |
| 393 | S->CanInline = Sym.CanInline; | |
| 394 | S->Traced = Sym.Traced; | |
| 395 | S->ScriptDefined = Sym.ScriptDefined; | |
| 507 | // replace() replaces "this" object with a given symbol by memcpy'ing | |
| 508 | // it over to "this". This function is called as a result of name | |
| 509 | // resolution, e.g. to replace an undefind symbol with a defined symbol. | |
| 510 | void Symbol::replace(const Symbol &New) { | |
| 511 | using llvm::ELF::STT_TLS; | |
| 396 | 512 | |
| 397 | 513 | // Symbols representing thread-local variables must be referenced by |
| 398 | 514 | // TLS-aware relocations, and non-TLS symbols must be reference by |
| 399 | 515 | // non-TLS relocations, so there's a clear distinction between TLS |
| 400 | 516 | // and non-TLS symbols. It is an error if the same symbol is defined |
| 401 | 517 | // as a TLS symbol in one file and as a non-TLS symbol in other file. |
| 402 | bool TlsMismatch = (Sym.Type == STT_TLS && S->Type != STT_TLS) || | |
| 403 | (Sym.Type != STT_TLS && S->Type == STT_TLS); | |
| 518 | if (symbolKind != PlaceholderKind && !isLazy() && !New.isLazy()) { | |
| 519 | bool tlsMismatch = (type == STT_TLS && New.type != STT_TLS) || | |
| 520 | (type != STT_TLS && New.type == STT_TLS); | |
| 521 | if (tlsMismatch) | |
| 522 | error("TLS attribute mismatch: " + toString(*this) + "\n>>> defined in " + | |
| 523 | toString(New.file) + "\n>>> defined in " + toString(file)); | |
| 524 | } | |
| 525 | ||
| 526 | Symbol old = *this; | |
| 527 | memcpy(this, &New, New.getSymbolSize()); | |
| 528 | ||
| 529 | versionId = old.versionId; | |
| 530 | visibility = old.visibility; | |
| 531 | isUsedInRegularObj = old.isUsedInRegularObj; | |
| 532 | exportDynamic = old.exportDynamic; | |
| 533 | canInline = old.canInline; | |
| 534 | traced = old.traced; | |
| 535 | isPreemptible = old.isPreemptible; | |
| 536 | scriptDefined = old.scriptDefined; | |
| 537 | partition = old.partition; | |
| 404 | 538 | |
| 405 | if (Sym.SymbolKind != Symbol::PlaceholderKind && TlsMismatch && !Sym.isLazy()) | |
| 406 | error("TLS attribute mismatch: " + toString(Sym) + "\n>>> defined in " + | |
| 407 | toString(Sym.File) + "\n>>> defined in " + toString(S->File)); | |
| 539 | // Symbol length is computed lazily. If we already know a symbol length, | |
| 540 | // propagate it. | |
| 541 | if (nameData == old.nameData && nameSize == 0 && old.nameSize != 0) | |
| 542 | nameSize = old.nameSize; | |
| 408 | 543 | |
| 409 | 544 | // Print out a log message if --trace-symbol was specified. |
| 410 | 545 | // This is for debugging. |
| 411 | if (S->Traced) | |
| 412 | printTraceSymbol(S); | |
| 546 | if (traced) | |
| 547 | printTraceSymbol(this); | |
| 413 | 548 | } |
| 414 | 549 | |
| 415 | void maybeWarnUnorderableSymbol(const Symbol *Sym); | |
| 550 | void maybeWarnUnorderableSymbol(const Symbol *sym); | |
| 416 | 551 | } // namespace elf |
| 417 | 552 | } // namespace lld |
| 418 | 553 |
deps/lld/ELF/SyntheticSections.cpp+2046-1654| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- SyntheticSections.cpp ----------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -15,7 +14,6 @@ |
| 15 | 14 | //===----------------------------------------------------------------------===// |
| 16 | 15 | |
| 17 | 16 | #include "SyntheticSections.h" |
| 18 | #include "Bits.h" | |
| 19 | 17 | #include "Config.h" |
| 20 | 18 | #include "InputFiles.h" |
| 21 | 19 | #include "LinkerScript.h" |
| ... | ... | @@ -38,9 +36,6 @@ |
| 38 | 36 | #include "llvm/Support/Endian.h" |
| 39 | 37 | #include "llvm/Support/LEB128.h" |
| 40 | 38 | #include "llvm/Support/MD5.h" |
| 41 | #include "llvm/Support/RandomNumberGenerator.h" | |
| 42 | #include "llvm/Support/SHA1.h" | |
| 43 | #include "llvm/Support/xxhash.h" | |
| 44 | 39 | #include <cstdlib> |
| 45 | 40 | #include <thread> |
| 46 | 41 | |
| ... | ... | @@ -57,19 +52,30 @@ using llvm::support::endian::read32le; |
| 57 | 52 | using llvm::support::endian::write32le; |
| 58 | 53 | using llvm::support::endian::write64le; |
| 59 | 54 | |
| 60 | constexpr size_t MergeNoTailSection::NumShards; | |
| 55 | constexpr size_t MergeNoTailSection::numShards; | |
| 56 | ||
| 57 | static uint64_t readUint(uint8_t *buf) { | |
| 58 | return config->is64 ? read64(buf) : read32(buf); | |
| 59 | } | |
| 60 | ||
| 61 | static void writeUint(uint8_t *buf, uint64_t val) { | |
| 62 | if (config->is64) | |
| 63 | write64(buf, val); | |
| 64 | else | |
| 65 | write32(buf, val); | |
| 66 | } | |
| 61 | 67 | |
| 62 | 68 | // Returns an LLD version string. |
| 63 | 69 | static ArrayRef<uint8_t> getVersion() { |
| 64 | 70 | // Check LLD_VERSION first for ease of testing. |
| 65 | 71 | // You can get consistent output by using the environment variable. |
| 66 | 72 | // This is only for testing. |
| 67 | StringRef S = getenv("LLD_VERSION"); | |
| 68 | if (S.empty()) | |
| 69 | S = Saver.save(Twine("Linker: ") + getLLDVersion()); | |
| 73 | StringRef s = getenv("LLD_VERSION"); | |
| 74 | if (s.empty()) | |
| 75 | s = saver.save(Twine("Linker: ") + getLLDVersion()); | |
| 70 | 76 | |
| 71 | 77 | // +1 to include the terminating '\0'. |
| 72 | return {(const uint8_t *)S.data(), S.size() + 1}; | |
| 78 | return {(const uint8_t *)s.data(), s.size() + 1}; | |
| 73 | 79 | } |
| 74 | 80 | |
| 75 | 81 | // Creates a .comment section containing LLD version info. |
| ... | ... | @@ -83,79 +89,79 @@ MergeInputSection *elf::createCommentSection() { |
| 83 | 89 | |
| 84 | 90 | // .MIPS.abiflags section. |
| 85 | 91 | template <class ELFT> |
| 86 | MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags) | |
| 92 | MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection(Elf_Mips_ABIFlags flags) | |
| 87 | 93 | : SyntheticSection(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ".MIPS.abiflags"), |
| 88 | Flags(Flags) { | |
| 89 | this->Entsize = sizeof(Elf_Mips_ABIFlags); | |
| 94 | flags(flags) { | |
| 95 | this->entsize = sizeof(Elf_Mips_ABIFlags); | |
| 90 | 96 | } |
| 91 | 97 | |
| 92 | template <class ELFT> void MipsAbiFlagsSection<ELFT>::writeTo(uint8_t *Buf) { | |
| 93 | memcpy(Buf, &Flags, sizeof(Flags)); | |
| 98 | template <class ELFT> void MipsAbiFlagsSection<ELFT>::writeTo(uint8_t *buf) { | |
| 99 | memcpy(buf, &flags, sizeof(flags)); | |
| 94 | 100 | } |
| 95 | 101 | |
| 96 | 102 | template <class ELFT> |
| 97 | 103 | MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() { |
| 98 | Elf_Mips_ABIFlags Flags = {}; | |
| 99 | bool Create = false; | |
| 104 | Elf_Mips_ABIFlags flags = {}; | |
| 105 | bool create = false; | |
| 100 | 106 | |
| 101 | for (InputSectionBase *Sec : InputSections) { | |
| 102 | if (Sec->Type != SHT_MIPS_ABIFLAGS) | |
| 107 | for (InputSectionBase *sec : inputSections) { | |
| 108 | if (sec->type != SHT_MIPS_ABIFLAGS) | |
| 103 | 109 | continue; |
| 104 | Sec->Live = false; | |
| 105 | Create = true; | |
| 110 | sec->markDead(); | |
| 111 | create = true; | |
| 106 | 112 | |
| 107 | std::string Filename = toString(Sec->File); | |
| 108 | const size_t Size = Sec->data().size(); | |
| 113 | std::string filename = toString(sec->file); | |
| 114 | const size_t size = sec->data().size(); | |
| 109 | 115 | // Older version of BFD (such as the default FreeBSD linker) concatenate |
| 110 | 116 | // .MIPS.abiflags instead of merging. To allow for this case (or potential |
| 111 | 117 | // zero padding) we ignore everything after the first Elf_Mips_ABIFlags |
| 112 | if (Size < sizeof(Elf_Mips_ABIFlags)) { | |
| 113 | error(Filename + ": invalid size of .MIPS.abiflags section: got " + | |
| 114 | Twine(Size) + " instead of " + Twine(sizeof(Elf_Mips_ABIFlags))); | |
| 118 | if (size < sizeof(Elf_Mips_ABIFlags)) { | |
| 119 | error(filename + ": invalid size of .MIPS.abiflags section: got " + | |
| 120 | Twine(size) + " instead of " + Twine(sizeof(Elf_Mips_ABIFlags))); | |
| 115 | 121 | return nullptr; |
| 116 | 122 | } |
| 117 | auto *S = reinterpret_cast<const Elf_Mips_ABIFlags *>(Sec->data().data()); | |
| 118 | if (S->version != 0) { | |
| 119 | error(Filename + ": unexpected .MIPS.abiflags version " + | |
| 120 | Twine(S->version)); | |
| 123 | auto *s = reinterpret_cast<const Elf_Mips_ABIFlags *>(sec->data().data()); | |
| 124 | if (s->version != 0) { | |
| 125 | error(filename + ": unexpected .MIPS.abiflags version " + | |
| 126 | Twine(s->version)); | |
| 121 | 127 | return nullptr; |
| 122 | 128 | } |
| 123 | 129 | |
| 124 | 130 | // LLD checks ISA compatibility in calcMipsEFlags(). Here we just |
| 125 | 131 | // select the highest number of ISA/Rev/Ext. |
| 126 | Flags.isa_level = std::max(Flags.isa_level, S->isa_level); | |
| 127 | Flags.isa_rev = std::max(Flags.isa_rev, S->isa_rev); | |
| 128 | Flags.isa_ext = std::max(Flags.isa_ext, S->isa_ext); | |
| 129 | Flags.gpr_size = std::max(Flags.gpr_size, S->gpr_size); | |
| 130 | Flags.cpr1_size = std::max(Flags.cpr1_size, S->cpr1_size); | |
| 131 | Flags.cpr2_size = std::max(Flags.cpr2_size, S->cpr2_size); | |
| 132 | Flags.ases |= S->ases; | |
| 133 | Flags.flags1 |= S->flags1; | |
| 134 | Flags.flags2 |= S->flags2; | |
| 135 | Flags.fp_abi = elf::getMipsFpAbiFlag(Flags.fp_abi, S->fp_abi, Filename); | |
| 132 | flags.isa_level = std::max(flags.isa_level, s->isa_level); | |
| 133 | flags.isa_rev = std::max(flags.isa_rev, s->isa_rev); | |
| 134 | flags.isa_ext = std::max(flags.isa_ext, s->isa_ext); | |
| 135 | flags.gpr_size = std::max(flags.gpr_size, s->gpr_size); | |
| 136 | flags.cpr1_size = std::max(flags.cpr1_size, s->cpr1_size); | |
| 137 | flags.cpr2_size = std::max(flags.cpr2_size, s->cpr2_size); | |
| 138 | flags.ases |= s->ases; | |
| 139 | flags.flags1 |= s->flags1; | |
| 140 | flags.flags2 |= s->flags2; | |
| 141 | flags.fp_abi = elf::getMipsFpAbiFlag(flags.fp_abi, s->fp_abi, filename); | |
| 136 | 142 | }; |
| 137 | 143 | |
| 138 | if (Create) | |
| 139 | return make<MipsAbiFlagsSection<ELFT>>(Flags); | |
| 144 | if (create) | |
| 145 | return make<MipsAbiFlagsSection<ELFT>>(flags); | |
| 140 | 146 | return nullptr; |
| 141 | 147 | } |
| 142 | 148 | |
| 143 | 149 | // .MIPS.options section. |
| 144 | 150 | template <class ELFT> |
| 145 | MipsOptionsSection<ELFT>::MipsOptionsSection(Elf_Mips_RegInfo Reginfo) | |
| 151 | MipsOptionsSection<ELFT>::MipsOptionsSection(Elf_Mips_RegInfo reginfo) | |
| 146 | 152 | : SyntheticSection(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ".MIPS.options"), |
| 147 | Reginfo(Reginfo) { | |
| 148 | this->Entsize = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo); | |
| 153 | reginfo(reginfo) { | |
| 154 | this->entsize = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo); | |
| 149 | 155 | } |
| 150 | 156 | |
| 151 | template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *Buf) { | |
| 152 | auto *Options = reinterpret_cast<Elf_Mips_Options *>(Buf); | |
| 153 | Options->kind = ODK_REGINFO; | |
| 154 | Options->size = getSize(); | |
| 157 | template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *buf) { | |
| 158 | auto *options = reinterpret_cast<Elf_Mips_Options *>(buf); | |
| 159 | options->kind = ODK_REGINFO; | |
| 160 | options->size = getSize(); | |
| 155 | 161 | |
| 156 | if (!Config->Relocatable) | |
| 157 | Reginfo.ri_gp_value = In.MipsGot->getGp(); | |
| 158 | memcpy(Buf + sizeof(Elf_Mips_Options), &Reginfo, sizeof(Reginfo)); | |
| 162 | if (!config->relocatable) | |
| 163 | reginfo.ri_gp_value = in.mipsGot->getGp(); | |
| 164 | memcpy(buf + sizeof(Elf_Mips_Options), &reginfo, sizeof(reginfo)); | |
| 159 | 165 | } |
| 160 | 166 | |
| 161 | 167 | template <class ELFT> |
| ... | ... | @@ -164,55 +170,55 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() { |
| 164 | 170 | if (!ELFT::Is64Bits) |
| 165 | 171 | return nullptr; |
| 166 | 172 | |
| 167 | std::vector<InputSectionBase *> Sections; | |
| 168 | for (InputSectionBase *Sec : InputSections) | |
| 169 | if (Sec->Type == SHT_MIPS_OPTIONS) | |
| 170 | Sections.push_back(Sec); | |
| 173 | std::vector<InputSectionBase *> sections; | |
| 174 | for (InputSectionBase *sec : inputSections) | |
| 175 | if (sec->type == SHT_MIPS_OPTIONS) | |
| 176 | sections.push_back(sec); | |
| 171 | 177 | |
| 172 | if (Sections.empty()) | |
| 178 | if (sections.empty()) | |
| 173 | 179 | return nullptr; |
| 174 | 180 | |
| 175 | Elf_Mips_RegInfo Reginfo = {}; | |
| 176 | for (InputSectionBase *Sec : Sections) { | |
| 177 | Sec->Live = false; | |
| 181 | Elf_Mips_RegInfo reginfo = {}; | |
| 182 | for (InputSectionBase *sec : sections) { | |
| 183 | sec->markDead(); | |
| 178 | 184 | |
| 179 | std::string Filename = toString(Sec->File); | |
| 180 | ArrayRef<uint8_t> D = Sec->data(); | |
| 185 | std::string filename = toString(sec->file); | |
| 186 | ArrayRef<uint8_t> d = sec->data(); | |
| 181 | 187 | |
| 182 | while (!D.empty()) { | |
| 183 | if (D.size() < sizeof(Elf_Mips_Options)) { | |
| 184 | error(Filename + ": invalid size of .MIPS.options section"); | |
| 188 | while (!d.empty()) { | |
| 189 | if (d.size() < sizeof(Elf_Mips_Options)) { | |
| 190 | error(filename + ": invalid size of .MIPS.options section"); | |
| 185 | 191 | break; |
| 186 | 192 | } |
| 187 | 193 | |
| 188 | auto *Opt = reinterpret_cast<const Elf_Mips_Options *>(D.data()); | |
| 189 | if (Opt->kind == ODK_REGINFO) { | |
| 190 | Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask; | |
| 191 | Sec->getFile<ELFT>()->MipsGp0 = Opt->getRegInfo().ri_gp_value; | |
| 194 | auto *opt = reinterpret_cast<const Elf_Mips_Options *>(d.data()); | |
| 195 | if (opt->kind == ODK_REGINFO) { | |
| 196 | reginfo.ri_gprmask |= opt->getRegInfo().ri_gprmask; | |
| 197 | sec->getFile<ELFT>()->mipsGp0 = opt->getRegInfo().ri_gp_value; | |
| 192 | 198 | break; |
| 193 | 199 | } |
| 194 | 200 | |
| 195 | if (!Opt->size) | |
| 196 | fatal(Filename + ": zero option descriptor size"); | |
| 197 | D = D.slice(Opt->size); | |
| 201 | if (!opt->size) | |
| 202 | fatal(filename + ": zero option descriptor size"); | |
| 203 | d = d.slice(opt->size); | |
| 198 | 204 | } |
| 199 | 205 | }; |
| 200 | 206 | |
| 201 | return make<MipsOptionsSection<ELFT>>(Reginfo); | |
| 207 | return make<MipsOptionsSection<ELFT>>(reginfo); | |
| 202 | 208 | } |
| 203 | 209 | |
| 204 | 210 | // MIPS .reginfo section. |
| 205 | 211 | template <class ELFT> |
| 206 | MipsReginfoSection<ELFT>::MipsReginfoSection(Elf_Mips_RegInfo Reginfo) | |
| 212 | MipsReginfoSection<ELFT>::MipsReginfoSection(Elf_Mips_RegInfo reginfo) | |
| 207 | 213 | : SyntheticSection(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ".reginfo"), |
| 208 | Reginfo(Reginfo) { | |
| 209 | this->Entsize = sizeof(Elf_Mips_RegInfo); | |
| 214 | reginfo(reginfo) { | |
| 215 | this->entsize = sizeof(Elf_Mips_RegInfo); | |
| 210 | 216 | } |
| 211 | 217 | |
| 212 | template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *Buf) { | |
| 213 | if (!Config->Relocatable) | |
| 214 | Reginfo.ri_gp_value = In.MipsGot->getGp(); | |
| 215 | memcpy(Buf, &Reginfo, sizeof(Reginfo)); | |
| 218 | template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *buf) { | |
| 219 | if (!config->relocatable) | |
| 220 | reginfo.ri_gp_value = in.mipsGot->getGp(); | |
| 221 | memcpy(buf, &reginfo, sizeof(reginfo)); | |
| 216 | 222 | } |
| 217 | 223 | |
| 218 | 224 | template <class ELFT> |
| ... | ... | @@ -221,53 +227,53 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() { |
| 221 | 227 | if (ELFT::Is64Bits) |
| 222 | 228 | return nullptr; |
| 223 | 229 | |
| 224 | std::vector<InputSectionBase *> Sections; | |
| 225 | for (InputSectionBase *Sec : InputSections) | |
| 226 | if (Sec->Type == SHT_MIPS_REGINFO) | |
| 227 | Sections.push_back(Sec); | |
| 230 | std::vector<InputSectionBase *> sections; | |
| 231 | for (InputSectionBase *sec : inputSections) | |
| 232 | if (sec->type == SHT_MIPS_REGINFO) | |
| 233 | sections.push_back(sec); | |
| 228 | 234 | |
| 229 | if (Sections.empty()) | |
| 235 | if (sections.empty()) | |
| 230 | 236 | return nullptr; |
| 231 | 237 | |
| 232 | Elf_Mips_RegInfo Reginfo = {}; | |
| 233 | for (InputSectionBase *Sec : Sections) { | |
| 234 | Sec->Live = false; | |
| 238 | Elf_Mips_RegInfo reginfo = {}; | |
| 239 | for (InputSectionBase *sec : sections) { | |
| 240 | sec->markDead(); | |
| 235 | 241 | |
| 236 | if (Sec->data().size() != sizeof(Elf_Mips_RegInfo)) { | |
| 237 | error(toString(Sec->File) + ": invalid size of .reginfo section"); | |
| 242 | if (sec->data().size() != sizeof(Elf_Mips_RegInfo)) { | |
| 243 | error(toString(sec->file) + ": invalid size of .reginfo section"); | |
| 238 | 244 | return nullptr; |
| 239 | 245 | } |
| 240 | 246 | |
| 241 | auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->data().data()); | |
| 242 | Reginfo.ri_gprmask |= R->ri_gprmask; | |
| 243 | Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value; | |
| 247 | auto *r = reinterpret_cast<const Elf_Mips_RegInfo *>(sec->data().data()); | |
| 248 | reginfo.ri_gprmask |= r->ri_gprmask; | |
| 249 | sec->getFile<ELFT>()->mipsGp0 = r->ri_gp_value; | |
| 244 | 250 | }; |
| 245 | 251 | |
| 246 | return make<MipsReginfoSection<ELFT>>(Reginfo); | |
| 252 | return make<MipsReginfoSection<ELFT>>(reginfo); | |
| 247 | 253 | } |
| 248 | 254 | |
| 249 | 255 | InputSection *elf::createInterpSection() { |
| 250 | 256 | // StringSaver guarantees that the returned string ends with '\0'. |
| 251 | StringRef S = Saver.save(Config->DynamicLinker); | |
| 252 | ArrayRef<uint8_t> Contents = {(const uint8_t *)S.data(), S.size() + 1}; | |
| 257 | StringRef s = saver.save(config->dynamicLinker); | |
| 258 | ArrayRef<uint8_t> contents = {(const uint8_t *)s.data(), s.size() + 1}; | |
| 253 | 259 | |
| 254 | auto *Sec = make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, Contents, | |
| 260 | auto *sec = make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, contents, | |
| 255 | 261 | ".interp"); |
| 256 | Sec->Live = true; | |
| 257 | return Sec; | |
| 262 | sec->markLive(); | |
| 263 | return sec; | |
| 258 | 264 | } |
| 259 | 265 | |
| 260 | Defined *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, | |
| 261 | uint64_t Size, InputSectionBase &Section) { | |
| 262 | auto *S = make<Defined>(Section.File, Name, STB_LOCAL, STV_DEFAULT, Type, | |
| 263 | Value, Size, &Section); | |
| 264 | if (In.SymTab) | |
| 265 | In.SymTab->addSymbol(S); | |
| 266 | return S; | |
| 266 | Defined *elf::addSyntheticLocal(StringRef name, uint8_t type, uint64_t value, | |
| 267 | uint64_t size, InputSectionBase &section) { | |
| 268 | auto *s = make<Defined>(section.file, name, STB_LOCAL, STV_DEFAULT, type, | |
| 269 | value, size, &section); | |
| 270 | if (in.symTab) | |
| 271 | in.symTab->addSymbol(s); | |
| 272 | return s; | |
| 267 | 273 | } |
| 268 | 274 | |
| 269 | 275 | static size_t getHashSize() { |
| 270 | switch (Config->BuildId) { | |
| 276 | switch (config->buildId) { | |
| 271 | 277 | case BuildIdKind::Fast: |
| 272 | 278 | return 8; |
| 273 | 279 | case BuildIdKind::Md5: |
| ... | ... | @@ -276,89 +282,67 @@ static size_t getHashSize() { |
| 276 | 282 | case BuildIdKind::Sha1: |
| 277 | 283 | return 20; |
| 278 | 284 | case BuildIdKind::Hexstring: |
| 279 | return Config->BuildIdVector.size(); | |
| 285 | return config->buildIdVector.size(); | |
| 280 | 286 | default: |
| 281 | 287 | llvm_unreachable("unknown BuildIdKind"); |
| 282 | 288 | } |
| 283 | 289 | } |
| 284 | 290 | |
| 291 | // This class represents a linker-synthesized .note.gnu.property section. | |
| 292 | // | |
| 293 | // In x86 and AArch64, object files may contain feature flags indicating the | |
| 294 | // features that they have used. The flags are stored in a .note.gnu.property | |
| 295 | // section. | |
| 296 | // | |
| 297 | // lld reads the sections from input files and merges them by computing AND of | |
| 298 | // the flags. The result is written as a new .note.gnu.property section. | |
| 299 | // | |
| 300 | // If the flag is zero (which indicates that the intersection of the feature | |
| 301 | // sets is empty, or some input files didn't have .note.gnu.property sections), | |
| 302 | // we don't create this section. | |
| 303 | GnuPropertySection::GnuPropertySection() | |
| 304 | : SyntheticSection(llvm::ELF::SHF_ALLOC, llvm::ELF::SHT_NOTE, 4, | |
| 305 | ".note.gnu.property") {} | |
| 306 | ||
| 307 | void GnuPropertySection::writeTo(uint8_t *buf) { | |
| 308 | uint32_t featureAndType = config->emachine == EM_AARCH64 | |
| 309 | ? GNU_PROPERTY_AARCH64_FEATURE_1_AND | |
| 310 | : GNU_PROPERTY_X86_FEATURE_1_AND; | |
| 311 | ||
| 312 | write32(buf, 4); // Name size | |
| 313 | write32(buf + 4, config->is64 ? 16 : 12); // Content size | |
| 314 | write32(buf + 8, NT_GNU_PROPERTY_TYPE_0); // Type | |
| 315 | memcpy(buf + 12, "GNU", 4); // Name string | |
| 316 | write32(buf + 16, featureAndType); // Feature type | |
| 317 | write32(buf + 20, 4); // Feature size | |
| 318 | write32(buf + 24, config->andFeatures); // Feature flags | |
| 319 | if (config->is64) | |
| 320 | write32(buf + 28, 0); // Padding | |
| 321 | } | |
| 322 | ||
| 323 | size_t GnuPropertySection::getSize() const { return config->is64 ? 32 : 28; } | |
| 324 | ||
| 285 | 325 | BuildIdSection::BuildIdSection() |
| 286 | 326 | : SyntheticSection(SHF_ALLOC, SHT_NOTE, 4, ".note.gnu.build-id"), |
| 287 | HashSize(getHashSize()) {} | |
| 288 | ||
| 289 | void BuildIdSection::writeTo(uint8_t *Buf) { | |
| 290 | write32(Buf, 4); // Name size | |
| 291 | write32(Buf + 4, HashSize); // Content size | |
| 292 | write32(Buf + 8, NT_GNU_BUILD_ID); // Type | |
| 293 | memcpy(Buf + 12, "GNU", 4); // Name string | |
| 294 | HashBuf = Buf + 16; | |
| 295 | } | |
| 296 | ||
| 297 | // Split one uint8 array into small pieces of uint8 arrays. | |
| 298 | static std::vector<ArrayRef<uint8_t>> split(ArrayRef<uint8_t> Arr, | |
| 299 | size_t ChunkSize) { | |
| 300 | std::vector<ArrayRef<uint8_t>> Ret; | |
| 301 | while (Arr.size() > ChunkSize) { | |
| 302 | Ret.push_back(Arr.take_front(ChunkSize)); | |
| 303 | Arr = Arr.drop_front(ChunkSize); | |
| 304 | } | |
| 305 | if (!Arr.empty()) | |
| 306 | Ret.push_back(Arr); | |
| 307 | return Ret; | |
| 308 | } | |
| 309 | ||
| 310 | // Computes a hash value of Data using a given hash function. | |
| 311 | // In order to utilize multiple cores, we first split data into 1MB | |
| 312 | // chunks, compute a hash for each chunk, and then compute a hash value | |
| 313 | // of the hash values. | |
| 314 | void BuildIdSection::computeHash( | |
| 315 | llvm::ArrayRef<uint8_t> Data, | |
| 316 | std::function<void(uint8_t *Dest, ArrayRef<uint8_t> Arr)> HashFn) { | |
| 317 | std::vector<ArrayRef<uint8_t>> Chunks = split(Data, 1024 * 1024); | |
| 318 | std::vector<uint8_t> Hashes(Chunks.size() * HashSize); | |
| 319 | ||
| 320 | // Compute hash values. | |
| 321 | parallelForEachN(0, Chunks.size(), [&](size_t I) { | |
| 322 | HashFn(Hashes.data() + I * HashSize, Chunks[I]); | |
| 323 | }); | |
| 327 | hashSize(getHashSize()) {} | |
| 324 | 328 | |
| 325 | // Write to the final output buffer. | |
| 326 | HashFn(HashBuf, Hashes); | |
| 329 | void BuildIdSection::writeTo(uint8_t *buf) { | |
| 330 | write32(buf, 4); // Name size | |
| 331 | write32(buf + 4, hashSize); // Content size | |
| 332 | write32(buf + 8, NT_GNU_BUILD_ID); // Type | |
| 333 | memcpy(buf + 12, "GNU", 4); // Name string | |
| 334 | hashBuf = buf + 16; | |
| 327 | 335 | } |
| 328 | 336 | |
| 329 | BssSection::BssSection(StringRef Name, uint64_t Size, uint32_t Alignment) | |
| 330 | : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, Alignment, Name) { | |
| 331 | this->Bss = true; | |
| 332 | this->Size = Size; | |
| 337 | void BuildIdSection::writeBuildId(ArrayRef<uint8_t> buf) { | |
| 338 | assert(buf.size() == hashSize); | |
| 339 | memcpy(hashBuf, buf.data(), hashSize); | |
| 333 | 340 | } |
| 334 | 341 | |
| 335 | void BuildIdSection::writeBuildId(ArrayRef<uint8_t> Buf) { | |
| 336 | switch (Config->BuildId) { | |
| 337 | case BuildIdKind::Fast: | |
| 338 | computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) { | |
| 339 | write64le(Dest, xxHash64(Arr)); | |
| 340 | }); | |
| 341 | break; | |
| 342 | case BuildIdKind::Md5: | |
| 343 | computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) { | |
| 344 | memcpy(Dest, MD5::hash(Arr).data(), 16); | |
| 345 | }); | |
| 346 | break; | |
| 347 | case BuildIdKind::Sha1: | |
| 348 | computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) { | |
| 349 | memcpy(Dest, SHA1::hash(Arr).data(), 20); | |
| 350 | }); | |
| 351 | break; | |
| 352 | case BuildIdKind::Uuid: | |
| 353 | if (auto EC = getRandomBytes(HashBuf, HashSize)) | |
| 354 | error("entropy source failure: " + EC.message()); | |
| 355 | break; | |
| 356 | case BuildIdKind::Hexstring: | |
| 357 | memcpy(HashBuf, Config->BuildIdVector.data(), Config->BuildIdVector.size()); | |
| 358 | break; | |
| 359 | default: | |
| 360 | llvm_unreachable("unknown BuildIdKind"); | |
| 361 | } | |
| 342 | BssSection::BssSection(StringRef name, uint64_t size, uint32_t alignment) | |
| 343 | : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, alignment, name) { | |
| 344 | this->bss = true; | |
| 345 | this->size = size; | |
| 362 | 346 | } |
| 363 | 347 | |
| 364 | 348 | EhFrameSection::EhFrameSection() |
| ... | ... | @@ -368,47 +352,48 @@ EhFrameSection::EhFrameSection() |
| 368 | 352 | // CIE records from input object files are uniquified by their contents |
| 369 | 353 | // and where their relocations point to. |
| 370 | 354 | template <class ELFT, class RelTy> |
| 371 | CieRecord *EhFrameSection::addCie(EhSectionPiece &Cie, ArrayRef<RelTy> Rels) { | |
| 372 | Symbol *Personality = nullptr; | |
| 373 | unsigned FirstRelI = Cie.FirstRelocation; | |
| 374 | if (FirstRelI != (unsigned)-1) | |
| 375 | Personality = | |
| 376 | &Cie.Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]); | |
| 355 | CieRecord *EhFrameSection::addCie(EhSectionPiece &cie, ArrayRef<RelTy> rels) { | |
| 356 | Symbol *personality = nullptr; | |
| 357 | unsigned firstRelI = cie.firstRelocation; | |
| 358 | if (firstRelI != (unsigned)-1) | |
| 359 | personality = | |
| 360 | &cie.sec->template getFile<ELFT>()->getRelocTargetSym(rels[firstRelI]); | |
| 377 | 361 | |
| 378 | 362 | // Search for an existing CIE by CIE contents/relocation target pair. |
| 379 | CieRecord *&Rec = CieMap[{Cie.data(), Personality}]; | |
| 363 | CieRecord *&rec = cieMap[{cie.data(), personality}]; | |
| 380 | 364 | |
| 381 | 365 | // If not found, create a new one. |
| 382 | if (!Rec) { | |
| 383 | Rec = make<CieRecord>(); | |
| 384 | Rec->Cie = &Cie; | |
| 385 | CieRecords.push_back(Rec); | |
| 366 | if (!rec) { | |
| 367 | rec = make<CieRecord>(); | |
| 368 | rec->cie = &cie; | |
| 369 | cieRecords.push_back(rec); | |
| 386 | 370 | } |
| 387 | return Rec; | |
| 371 | return rec; | |
| 388 | 372 | } |
| 389 | 373 | |
| 390 | 374 | // There is one FDE per function. Returns true if a given FDE |
| 391 | 375 | // points to a live function. |
| 392 | 376 | template <class ELFT, class RelTy> |
| 393 | bool EhFrameSection::isFdeLive(EhSectionPiece &Fde, ArrayRef<RelTy> Rels) { | |
| 394 | auto *Sec = cast<EhInputSection>(Fde.Sec); | |
| 395 | unsigned FirstRelI = Fde.FirstRelocation; | |
| 377 | bool EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef<RelTy> rels) { | |
| 378 | auto *sec = cast<EhInputSection>(fde.sec); | |
| 379 | unsigned firstRelI = fde.firstRelocation; | |
| 396 | 380 | |
| 397 | 381 | // An FDE should point to some function because FDEs are to describe |
| 398 | 382 | // functions. That's however not always the case due to an issue of |
| 399 | 383 | // ld.gold with -r. ld.gold may discard only functions and leave their |
| 400 | 384 | // corresponding FDEs, which results in creating bad .eh_frame sections. |
| 401 | 385 | // To deal with that, we ignore such FDEs. |
| 402 | if (FirstRelI == (unsigned)-1) | |
| 386 | if (firstRelI == (unsigned)-1) | |
| 403 | 387 | return false; |
| 404 | 388 | |
| 405 | const RelTy &Rel = Rels[FirstRelI]; | |
| 406 | Symbol &B = Sec->template getFile<ELFT>()->getRelocTargetSym(Rel); | |
| 389 | const RelTy &rel = rels[firstRelI]; | |
| 390 | Symbol &b = sec->template getFile<ELFT>()->getRelocTargetSym(rel); | |
| 407 | 391 | |
| 408 | // FDEs for garbage-collected or merged-by-ICF sections are dead. | |
| 409 | if (auto *D = dyn_cast<Defined>(&B)) | |
| 410 | if (SectionBase *Sec = D->Section) | |
| 411 | return Sec->Live; | |
| 392 | // FDEs for garbage-collected or merged-by-ICF sections, or sections in | |
| 393 | // another partition, are dead. | |
| 394 | if (auto *d = dyn_cast<Defined>(&b)) | |
| 395 | if (SectionBase *sec = d->section) | |
| 396 | return sec->partition == partition; | |
| 412 | 397 | return false; |
| 413 | 398 | } |
| 414 | 399 | |
| ... | ... | @@ -417,73 +402,73 @@ bool EhFrameSection::isFdeLive(EhSectionPiece &Fde, ArrayRef<RelTy> Rels) { |
| 417 | 402 | // a list of FDEs. This function searches an existing CIE or create a new |
| 418 | 403 | // one and associates FDEs to the CIE. |
| 419 | 404 | template <class ELFT, class RelTy> |
| 420 | void EhFrameSection::addSectionAux(EhInputSection *Sec, ArrayRef<RelTy> Rels) { | |
| 421 | OffsetToCie.clear(); | |
| 422 | for (EhSectionPiece &Piece : Sec->Pieces) { | |
| 405 | void EhFrameSection::addSectionAux(EhInputSection *sec, ArrayRef<RelTy> rels) { | |
| 406 | offsetToCie.clear(); | |
| 407 | for (EhSectionPiece &piece : sec->pieces) { | |
| 423 | 408 | // The empty record is the end marker. |
| 424 | if (Piece.Size == 4) | |
| 409 | if (piece.size == 4) | |
| 425 | 410 | return; |
| 426 | 411 | |
| 427 | size_t Offset = Piece.InputOff; | |
| 428 | uint32_t ID = read32(Piece.data().data() + 4); | |
| 429 | if (ID == 0) { | |
| 430 | OffsetToCie[Offset] = addCie<ELFT>(Piece, Rels); | |
| 412 | size_t offset = piece.inputOff; | |
| 413 | uint32_t id = read32(piece.data().data() + 4); | |
| 414 | if (id == 0) { | |
| 415 | offsetToCie[offset] = addCie<ELFT>(piece, rels); | |
| 431 | 416 | continue; |
| 432 | 417 | } |
| 433 | 418 | |
| 434 | uint32_t CieOffset = Offset + 4 - ID; | |
| 435 | CieRecord *Rec = OffsetToCie[CieOffset]; | |
| 436 | if (!Rec) | |
| 437 | fatal(toString(Sec) + ": invalid CIE reference"); | |
| 419 | uint32_t cieOffset = offset + 4 - id; | |
| 420 | CieRecord *rec = offsetToCie[cieOffset]; | |
| 421 | if (!rec) | |
| 422 | fatal(toString(sec) + ": invalid CIE reference"); | |
| 438 | 423 | |
| 439 | if (!isFdeLive<ELFT>(Piece, Rels)) | |
| 424 | if (!isFdeLive<ELFT>(piece, rels)) | |
| 440 | 425 | continue; |
| 441 | Rec->Fdes.push_back(&Piece); | |
| 442 | NumFdes++; | |
| 426 | rec->fdes.push_back(&piece); | |
| 427 | numFdes++; | |
| 443 | 428 | } |
| 444 | 429 | } |
| 445 | 430 | |
| 446 | template <class ELFT> void EhFrameSection::addSection(InputSectionBase *C) { | |
| 447 | auto *Sec = cast<EhInputSection>(C); | |
| 448 | Sec->Parent = this; | |
| 431 | template <class ELFT> void EhFrameSection::addSection(InputSectionBase *c) { | |
| 432 | auto *sec = cast<EhInputSection>(c); | |
| 433 | sec->parent = this; | |
| 449 | 434 | |
| 450 | Alignment = std::max(Alignment, Sec->Alignment); | |
| 451 | Sections.push_back(Sec); | |
| 435 | alignment = std::max(alignment, sec->alignment); | |
| 436 | sections.push_back(sec); | |
| 452 | 437 | |
| 453 | for (auto *DS : Sec->DependentSections) | |
| 454 | DependentSections.push_back(DS); | |
| 438 | for (auto *ds : sec->dependentSections) | |
| 439 | dependentSections.push_back(ds); | |
| 455 | 440 | |
| 456 | if (Sec->Pieces.empty()) | |
| 441 | if (sec->pieces.empty()) | |
| 457 | 442 | return; |
| 458 | 443 | |
| 459 | if (Sec->AreRelocsRela) | |
| 460 | addSectionAux<ELFT>(Sec, Sec->template relas<ELFT>()); | |
| 444 | if (sec->areRelocsRela) | |
| 445 | addSectionAux<ELFT>(sec, sec->template relas<ELFT>()); | |
| 461 | 446 | else |
| 462 | addSectionAux<ELFT>(Sec, Sec->template rels<ELFT>()); | |
| 447 | addSectionAux<ELFT>(sec, sec->template rels<ELFT>()); | |
| 463 | 448 | } |
| 464 | 449 | |
| 465 | static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) { | |
| 466 | memcpy(Buf, D.data(), D.size()); | |
| 450 | static void writeCieFde(uint8_t *buf, ArrayRef<uint8_t> d) { | |
| 451 | memcpy(buf, d.data(), d.size()); | |
| 467 | 452 | |
| 468 | size_t Aligned = alignTo(D.size(), Config->Wordsize); | |
| 453 | size_t aligned = alignTo(d.size(), config->wordsize); | |
| 469 | 454 | |
| 470 | 455 | // Zero-clear trailing padding if it exists. |
| 471 | memset(Buf + D.size(), 0, Aligned - D.size()); | |
| 456 | memset(buf + d.size(), 0, aligned - d.size()); | |
| 472 | 457 | |
| 473 | 458 | // Fix the size field. -4 since size does not include the size field itself. |
| 474 | write32(Buf, Aligned - 4); | |
| 459 | write32(buf, aligned - 4); | |
| 475 | 460 | } |
| 476 | 461 | |
| 477 | 462 | void EhFrameSection::finalizeContents() { |
| 478 | assert(!this->Size); // Not finalized. | |
| 479 | size_t Off = 0; | |
| 480 | for (CieRecord *Rec : CieRecords) { | |
| 481 | Rec->Cie->OutputOff = Off; | |
| 482 | Off += alignTo(Rec->Cie->Size, Config->Wordsize); | |
| 483 | ||
| 484 | for (EhSectionPiece *Fde : Rec->Fdes) { | |
| 485 | Fde->OutputOff = Off; | |
| 486 | Off += alignTo(Fde->Size, Config->Wordsize); | |
| 463 | assert(!this->size); // Not finalized. | |
| 464 | size_t off = 0; | |
| 465 | for (CieRecord *rec : cieRecords) { | |
| 466 | rec->cie->outputOff = off; | |
| 467 | off += alignTo(rec->cie->size, config->wordsize); | |
| 468 | ||
| 469 | for (EhSectionPiece *fde : rec->fdes) { | |
| 470 | fde->outputOff = off; | |
| 471 | off += alignTo(fde->size, config->wordsize); | |
| 487 | 472 | } |
| 488 | 473 | } |
| 489 | 474 | |
| ... | ... | @@ -491,375 +476,374 @@ void EhFrameSection::finalizeContents() { |
| 491 | 476 | // Call Frame Information records. glibc unwind-dw2-fde.c |
| 492 | 477 | // classify_object_over_fdes expects there is a CIE record length 0 as a |
| 493 | 478 | // terminator. Thus we add one unconditionally. |
| 494 | Off += 4; | |
| 479 | off += 4; | |
| 495 | 480 | |
| 496 | this->Size = Off; | |
| 481 | this->size = off; | |
| 497 | 482 | } |
| 498 | 483 | |
| 499 | 484 | // Returns data for .eh_frame_hdr. .eh_frame_hdr is a binary search table |
| 500 | 485 | // to get an FDE from an address to which FDE is applied. This function |
| 501 | 486 | // returns a list of such pairs. |
| 502 | 487 | std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const { |
| 503 | uint8_t *Buf = getParent()->Loc + OutSecOff; | |
| 504 | std::vector<FdeData> Ret; | |
| 505 | ||
| 506 | uint64_t VA = In.EhFrameHdr->getVA(); | |
| 507 | for (CieRecord *Rec : CieRecords) { | |
| 508 | uint8_t Enc = getFdeEncoding(Rec->Cie); | |
| 509 | for (EhSectionPiece *Fde : Rec->Fdes) { | |
| 510 | uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc); | |
| 511 | uint64_t FdeVA = getParent()->Addr + Fde->OutputOff; | |
| 512 | if (!isInt<32>(Pc - VA)) | |
| 513 | fatal(toString(Fde->Sec) + ": PC offset is too large: 0x" + | |
| 514 | Twine::utohexstr(Pc - VA)); | |
| 515 | Ret.push_back({uint32_t(Pc - VA), uint32_t(FdeVA - VA)}); | |
| 488 | uint8_t *buf = Out::bufferStart + getParent()->offset + outSecOff; | |
| 489 | std::vector<FdeData> ret; | |
| 490 | ||
| 491 | uint64_t va = getPartition().ehFrameHdr->getVA(); | |
| 492 | for (CieRecord *rec : cieRecords) { | |
| 493 | uint8_t enc = getFdeEncoding(rec->cie); | |
| 494 | for (EhSectionPiece *fde : rec->fdes) { | |
| 495 | uint64_t pc = getFdePc(buf, fde->outputOff, enc); | |
| 496 | uint64_t fdeVA = getParent()->addr + fde->outputOff; | |
| 497 | if (!isInt<32>(pc - va)) | |
| 498 | fatal(toString(fde->sec) + ": PC offset is too large: 0x" + | |
| 499 | Twine::utohexstr(pc - va)); | |
| 500 | ret.push_back({uint32_t(pc - va), uint32_t(fdeVA - va)}); | |
| 516 | 501 | } |
| 517 | 502 | } |
| 518 | 503 | |
| 519 | 504 | // Sort the FDE list by their PC and uniqueify. Usually there is only |
| 520 | 505 | // one FDE for a PC (i.e. function), but if ICF merges two functions |
| 521 | 506 | // into one, there can be more than one FDEs pointing to the address. |
| 522 | auto Less = [](const FdeData &A, const FdeData &B) { | |
| 523 | return A.PcRel < B.PcRel; | |
| 507 | auto less = [](const FdeData &a, const FdeData &b) { | |
| 508 | return a.pcRel < b.pcRel; | |
| 524 | 509 | }; |
| 525 | std::stable_sort(Ret.begin(), Ret.end(), Less); | |
| 526 | auto Eq = [](const FdeData &A, const FdeData &B) { | |
| 527 | return A.PcRel == B.PcRel; | |
| 510 | llvm::stable_sort(ret, less); | |
| 511 | auto eq = [](const FdeData &a, const FdeData &b) { | |
| 512 | return a.pcRel == b.pcRel; | |
| 528 | 513 | }; |
| 529 | Ret.erase(std::unique(Ret.begin(), Ret.end(), Eq), Ret.end()); | |
| 514 | ret.erase(std::unique(ret.begin(), ret.end(), eq), ret.end()); | |
| 530 | 515 | |
| 531 | return Ret; | |
| 516 | return ret; | |
| 532 | 517 | } |
| 533 | 518 | |
| 534 | static uint64_t readFdeAddr(uint8_t *Buf, int Size) { | |
| 535 | switch (Size) { | |
| 519 | static uint64_t readFdeAddr(uint8_t *buf, int size) { | |
| 520 | switch (size) { | |
| 536 | 521 | case DW_EH_PE_udata2: |
| 537 | return read16(Buf); | |
| 522 | return read16(buf); | |
| 538 | 523 | case DW_EH_PE_sdata2: |
| 539 | return (int16_t)read16(Buf); | |
| 524 | return (int16_t)read16(buf); | |
| 540 | 525 | case DW_EH_PE_udata4: |
| 541 | return read32(Buf); | |
| 526 | return read32(buf); | |
| 542 | 527 | case DW_EH_PE_sdata4: |
| 543 | return (int32_t)read32(Buf); | |
| 528 | return (int32_t)read32(buf); | |
| 544 | 529 | case DW_EH_PE_udata8: |
| 545 | 530 | case DW_EH_PE_sdata8: |
| 546 | return read64(Buf); | |
| 531 | return read64(buf); | |
| 547 | 532 | case DW_EH_PE_absptr: |
| 548 | return readUint(Buf); | |
| 533 | return readUint(buf); | |
| 549 | 534 | } |
| 550 | 535 | fatal("unknown FDE size encoding"); |
| 551 | 536 | } |
| 552 | 537 | |
| 553 | 538 | // Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to. |
| 554 | 539 | // We need it to create .eh_frame_hdr section. |
| 555 | uint64_t EhFrameSection::getFdePc(uint8_t *Buf, size_t FdeOff, | |
| 556 | uint8_t Enc) const { | |
| 540 | uint64_t EhFrameSection::getFdePc(uint8_t *buf, size_t fdeOff, | |
| 541 | uint8_t enc) const { | |
| 557 | 542 | // The starting address to which this FDE applies is |
| 558 | 543 | // stored at FDE + 8 byte. |
| 559 | size_t Off = FdeOff + 8; | |
| 560 | uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0xf); | |
| 561 | if ((Enc & 0x70) == DW_EH_PE_absptr) | |
| 562 | return Addr; | |
| 563 | if ((Enc & 0x70) == DW_EH_PE_pcrel) | |
| 564 | return Addr + getParent()->Addr + Off; | |
| 544 | size_t off = fdeOff + 8; | |
| 545 | uint64_t addr = readFdeAddr(buf + off, enc & 0xf); | |
| 546 | if ((enc & 0x70) == DW_EH_PE_absptr) | |
| 547 | return addr; | |
| 548 | if ((enc & 0x70) == DW_EH_PE_pcrel) | |
| 549 | return addr + getParent()->addr + off; | |
| 565 | 550 | fatal("unknown FDE size relative encoding"); |
| 566 | 551 | } |
| 567 | 552 | |
| 568 | void EhFrameSection::writeTo(uint8_t *Buf) { | |
| 553 | void EhFrameSection::writeTo(uint8_t *buf) { | |
| 569 | 554 | // Write CIE and FDE records. |
| 570 | for (CieRecord *Rec : CieRecords) { | |
| 571 | size_t CieOffset = Rec->Cie->OutputOff; | |
| 572 | writeCieFde(Buf + CieOffset, Rec->Cie->data()); | |
| 555 | for (CieRecord *rec : cieRecords) { | |
| 556 | size_t cieOffset = rec->cie->outputOff; | |
| 557 | writeCieFde(buf + cieOffset, rec->cie->data()); | |
| 573 | 558 | |
| 574 | for (EhSectionPiece *Fde : Rec->Fdes) { | |
| 575 | size_t Off = Fde->OutputOff; | |
| 576 | writeCieFde(Buf + Off, Fde->data()); | |
| 559 | for (EhSectionPiece *fde : rec->fdes) { | |
| 560 | size_t off = fde->outputOff; | |
| 561 | writeCieFde(buf + off, fde->data()); | |
| 577 | 562 | |
| 578 | 563 | // FDE's second word should have the offset to an associated CIE. |
| 579 | 564 | // Write it. |
| 580 | write32(Buf + Off + 4, Off + 4 - CieOffset); | |
| 565 | write32(buf + off + 4, off + 4 - cieOffset); | |
| 581 | 566 | } |
| 582 | 567 | } |
| 583 | 568 | |
| 584 | 569 | // Apply relocations. .eh_frame section contents are not contiguous |
| 585 | 570 | // in the output buffer, but relocateAlloc() still works because |
| 586 | 571 | // getOffset() takes care of discontiguous section pieces. |
| 587 | for (EhInputSection *S : Sections) | |
| 588 | S->relocateAlloc(Buf, nullptr); | |
| 572 | for (EhInputSection *s : sections) | |
| 573 | s->relocateAlloc(buf, nullptr); | |
| 574 | ||
| 575 | if (getPartition().ehFrameHdr && getPartition().ehFrameHdr->getParent()) | |
| 576 | getPartition().ehFrameHdr->write(); | |
| 589 | 577 | } |
| 590 | 578 | |
| 591 | 579 | GotSection::GotSection() |
| 592 | : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, | |
| 593 | Target->GotEntrySize, ".got") { | |
| 594 | // PPC64 saves the ElfSym::GlobalOffsetTable .TOC. as the first entry in the | |
| 595 | // .got. If there are no references to .TOC. in the symbol table, | |
| 596 | // ElfSym::GlobalOffsetTable will not be defined and we won't need to save | |
| 597 | // .TOC. in the .got. When it is defined, we increase NumEntries by the number | |
| 598 | // of entries used to emit ElfSym::GlobalOffsetTable. | |
| 599 | if (ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt) | |
| 600 | NumEntries += Target->GotHeaderEntriesNum; | |
| 580 | : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize, | |
| 581 | ".got") { | |
| 582 | // If ElfSym::globalOffsetTable is relative to .got and is referenced, | |
| 583 | // increase numEntries by the number of entries used to emit | |
| 584 | // ElfSym::globalOffsetTable. | |
| 585 | if (ElfSym::globalOffsetTable && !target->gotBaseSymInGotPlt) | |
| 586 | numEntries += target->gotHeaderEntriesNum; | |
| 601 | 587 | } |
| 602 | 588 | |
| 603 | void GotSection::addEntry(Symbol &Sym) { | |
| 604 | Sym.GotIndex = NumEntries; | |
| 605 | ++NumEntries; | |
| 589 | void GotSection::addEntry(Symbol &sym) { | |
| 590 | sym.gotIndex = numEntries; | |
| 591 | ++numEntries; | |
| 606 | 592 | } |
| 607 | 593 | |
| 608 | bool GotSection::addDynTlsEntry(Symbol &Sym) { | |
| 609 | if (Sym.GlobalDynIndex != -1U) | |
| 594 | bool GotSection::addDynTlsEntry(Symbol &sym) { | |
| 595 | if (sym.globalDynIndex != -1U) | |
| 610 | 596 | return false; |
| 611 | Sym.GlobalDynIndex = NumEntries; | |
| 597 | sym.globalDynIndex = numEntries; | |
| 612 | 598 | // Global Dynamic TLS entries take two GOT slots. |
| 613 | NumEntries += 2; | |
| 599 | numEntries += 2; | |
| 614 | 600 | return true; |
| 615 | 601 | } |
| 616 | 602 | |
| 617 | 603 | // Reserves TLS entries for a TLS module ID and a TLS block offset. |
| 618 | 604 | // In total it takes two GOT slots. |
| 619 | 605 | bool GotSection::addTlsIndex() { |
| 620 | if (TlsIndexOff != uint32_t(-1)) | |
| 606 | if (tlsIndexOff != uint32_t(-1)) | |
| 621 | 607 | return false; |
| 622 | TlsIndexOff = NumEntries * Config->Wordsize; | |
| 623 | NumEntries += 2; | |
| 608 | tlsIndexOff = numEntries * config->wordsize; | |
| 609 | numEntries += 2; | |
| 624 | 610 | return true; |
| 625 | 611 | } |
| 626 | 612 | |
| 627 | uint64_t GotSection::getGlobalDynAddr(const Symbol &B) const { | |
| 628 | return this->getVA() + B.GlobalDynIndex * Config->Wordsize; | |
| 613 | uint64_t GotSection::getGlobalDynAddr(const Symbol &b) const { | |
| 614 | return this->getVA() + b.globalDynIndex * config->wordsize; | |
| 629 | 615 | } |
| 630 | 616 | |
| 631 | uint64_t GotSection::getGlobalDynOffset(const Symbol &B) const { | |
| 632 | return B.GlobalDynIndex * Config->Wordsize; | |
| 617 | uint64_t GotSection::getGlobalDynOffset(const Symbol &b) const { | |
| 618 | return b.globalDynIndex * config->wordsize; | |
| 633 | 619 | } |
| 634 | 620 | |
| 635 | 621 | void GotSection::finalizeContents() { |
| 636 | Size = NumEntries * Config->Wordsize; | |
| 622 | size = numEntries * config->wordsize; | |
| 637 | 623 | } |
| 638 | 624 | |
| 639 | bool GotSection::empty() const { | |
| 625 | bool GotSection::isNeeded() const { | |
| 640 | 626 | // We need to emit a GOT even if it's empty if there's a relocation that is |
| 641 | // relative to GOT(such as GOTOFFREL) or there's a symbol that points to a GOT | |
| 642 | // (i.e. _GLOBAL_OFFSET_TABLE_) that the target defines relative to the .got. | |
| 643 | return NumEntries == 0 && !HasGotOffRel && | |
| 644 | !(ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt); | |
| 627 | // relative to GOT(such as GOTOFFREL). | |
| 628 | return numEntries || hasGotOffRel; | |
| 645 | 629 | } |
| 646 | 630 | |
| 647 | void GotSection::writeTo(uint8_t *Buf) { | |
| 631 | void GotSection::writeTo(uint8_t *buf) { | |
| 648 | 632 | // Buf points to the start of this section's buffer, |
| 649 | 633 | // whereas InputSectionBase::relocateAlloc() expects its argument |
| 650 | 634 | // to point to the start of the output section. |
| 651 | Target->writeGotHeader(Buf); | |
| 652 | relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size); | |
| 635 | target->writeGotHeader(buf); | |
| 636 | relocateAlloc(buf - outSecOff, buf - outSecOff + size); | |
| 653 | 637 | } |
| 654 | 638 | |
| 655 | static uint64_t getMipsPageAddr(uint64_t Addr) { | |
| 656 | return (Addr + 0x8000) & ~0xffff; | |
| 639 | static uint64_t getMipsPageAddr(uint64_t addr) { | |
| 640 | return (addr + 0x8000) & ~0xffff; | |
| 657 | 641 | } |
| 658 | 642 | |
| 659 | static uint64_t getMipsPageCount(uint64_t Size) { | |
| 660 | return (Size + 0xfffe) / 0xffff + 1; | |
| 643 | static uint64_t getMipsPageCount(uint64_t size) { | |
| 644 | return (size + 0xfffe) / 0xffff + 1; | |
| 661 | 645 | } |
| 662 | 646 | |
| 663 | 647 | MipsGotSection::MipsGotSection() |
| 664 | 648 | : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16, |
| 665 | 649 | ".got") {} |
| 666 | 650 | |
| 667 | void MipsGotSection::addEntry(InputFile &File, Symbol &Sym, int64_t Addend, | |
| 668 | RelExpr Expr) { | |
| 669 | FileGot &G = getGot(File); | |
| 670 | if (Expr == R_MIPS_GOT_LOCAL_PAGE) { | |
| 671 | if (const OutputSection *OS = Sym.getOutputSection()) | |
| 672 | G.PagesMap.insert({OS, {}}); | |
| 651 | void MipsGotSection::addEntry(InputFile &file, Symbol &sym, int64_t addend, | |
| 652 | RelExpr expr) { | |
| 653 | FileGot &g = getGot(file); | |
| 654 | if (expr == R_MIPS_GOT_LOCAL_PAGE) { | |
| 655 | if (const OutputSection *os = sym.getOutputSection()) | |
| 656 | g.pagesMap.insert({os, {}}); | |
| 673 | 657 | else |
| 674 | G.Local16.insert({{nullptr, getMipsPageAddr(Sym.getVA(Addend))}, 0}); | |
| 675 | } else if (Sym.isTls()) | |
| 676 | G.Tls.insert({&Sym, 0}); | |
| 677 | else if (Sym.IsPreemptible && Expr == R_ABS) | |
| 678 | G.Relocs.insert({&Sym, 0}); | |
| 679 | else if (Sym.IsPreemptible) | |
| 680 | G.Global.insert({&Sym, 0}); | |
| 681 | else if (Expr == R_MIPS_GOT_OFF32) | |
| 682 | G.Local32.insert({{&Sym, Addend}, 0}); | |
| 658 | g.local16.insert({{nullptr, getMipsPageAddr(sym.getVA(addend))}, 0}); | |
| 659 | } else if (sym.isTls()) | |
| 660 | g.tls.insert({&sym, 0}); | |
| 661 | else if (sym.isPreemptible && expr == R_ABS) | |
| 662 | g.relocs.insert({&sym, 0}); | |
| 663 | else if (sym.isPreemptible) | |
| 664 | g.global.insert({&sym, 0}); | |
| 665 | else if (expr == R_MIPS_GOT_OFF32) | |
| 666 | g.local32.insert({{&sym, addend}, 0}); | |
| 683 | 667 | else |
| 684 | G.Local16.insert({{&Sym, Addend}, 0}); | |
| 668 | g.local16.insert({{&sym, addend}, 0}); | |
| 685 | 669 | } |
| 686 | 670 | |
| 687 | void MipsGotSection::addDynTlsEntry(InputFile &File, Symbol &Sym) { | |
| 688 | getGot(File).DynTlsSymbols.insert({&Sym, 0}); | |
| 671 | void MipsGotSection::addDynTlsEntry(InputFile &file, Symbol &sym) { | |
| 672 | getGot(file).dynTlsSymbols.insert({&sym, 0}); | |
| 689 | 673 | } |
| 690 | 674 | |
| 691 | void MipsGotSection::addTlsIndex(InputFile &File) { | |
| 692 | getGot(File).DynTlsSymbols.insert({nullptr, 0}); | |
| 675 | void MipsGotSection::addTlsIndex(InputFile &file) { | |
| 676 | getGot(file).dynTlsSymbols.insert({nullptr, 0}); | |
| 693 | 677 | } |
| 694 | 678 | |
| 695 | 679 | size_t MipsGotSection::FileGot::getEntriesNum() const { |
| 696 | return getPageEntriesNum() + Local16.size() + Global.size() + Relocs.size() + | |
| 697 | Tls.size() + DynTlsSymbols.size() * 2; | |
| 680 | return getPageEntriesNum() + local16.size() + global.size() + relocs.size() + | |
| 681 | tls.size() + dynTlsSymbols.size() * 2; | |
| 698 | 682 | } |
| 699 | 683 | |
| 700 | 684 | size_t MipsGotSection::FileGot::getPageEntriesNum() const { |
| 701 | size_t Num = 0; | |
| 702 | for (const std::pair<const OutputSection *, FileGot::PageBlock> &P : PagesMap) | |
| 703 | Num += P.second.Count; | |
| 704 | return Num; | |
| 685 | size_t num = 0; | |
| 686 | for (const std::pair<const OutputSection *, FileGot::PageBlock> &p : pagesMap) | |
| 687 | num += p.second.count; | |
| 688 | return num; | |
| 705 | 689 | } |
| 706 | 690 | |
| 707 | 691 | size_t MipsGotSection::FileGot::getIndexedEntriesNum() const { |
| 708 | size_t Count = getPageEntriesNum() + Local16.size() + Global.size(); | |
| 692 | size_t count = getPageEntriesNum() + local16.size() + global.size(); | |
| 709 | 693 | // If there are relocation-only entries in the GOT, TLS entries |
| 710 | 694 | // are allocated after them. TLS entries should be addressable |
| 711 | 695 | // by 16-bit index so count both reloc-only and TLS entries. |
| 712 | if (!Tls.empty() || !DynTlsSymbols.empty()) | |
| 713 | Count += Relocs.size() + Tls.size() + DynTlsSymbols.size() * 2; | |
| 714 | return Count; | |
| 696 | if (!tls.empty() || !dynTlsSymbols.empty()) | |
| 697 | count += relocs.size() + tls.size() + dynTlsSymbols.size() * 2; | |
| 698 | return count; | |
| 715 | 699 | } |
| 716 | 700 | |
| 717 | MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &F) { | |
| 718 | if (!F.MipsGotIndex.hasValue()) { | |
| 719 | Gots.emplace_back(); | |
| 720 | Gots.back().File = &F; | |
| 721 | F.MipsGotIndex = Gots.size() - 1; | |
| 701 | MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &f) { | |
| 702 | if (!f.mipsGotIndex.hasValue()) { | |
| 703 | gots.emplace_back(); | |
| 704 | gots.back().file = &f; | |
| 705 | f.mipsGotIndex = gots.size() - 1; | |
| 722 | 706 | } |
| 723 | return Gots[*F.MipsGotIndex]; | |
| 707 | return gots[*f.mipsGotIndex]; | |
| 724 | 708 | } |
| 725 | 709 | |
| 726 | uint64_t MipsGotSection::getPageEntryOffset(const InputFile *F, | |
| 727 | const Symbol &Sym, | |
| 728 | int64_t Addend) const { | |
| 729 | const FileGot &G = Gots[*F->MipsGotIndex]; | |
| 730 | uint64_t Index = 0; | |
| 731 | if (const OutputSection *OutSec = Sym.getOutputSection()) { | |
| 732 | uint64_t SecAddr = getMipsPageAddr(OutSec->Addr); | |
| 733 | uint64_t SymAddr = getMipsPageAddr(Sym.getVA(Addend)); | |
| 734 | Index = G.PagesMap.lookup(OutSec).FirstIndex + (SymAddr - SecAddr) / 0xffff; | |
| 710 | uint64_t MipsGotSection::getPageEntryOffset(const InputFile *f, | |
| 711 | const Symbol &sym, | |
| 712 | int64_t addend) const { | |
| 713 | const FileGot &g = gots[*f->mipsGotIndex]; | |
| 714 | uint64_t index = 0; | |
| 715 | if (const OutputSection *outSec = sym.getOutputSection()) { | |
| 716 | uint64_t secAddr = getMipsPageAddr(outSec->addr); | |
| 717 | uint64_t symAddr = getMipsPageAddr(sym.getVA(addend)); | |
| 718 | index = g.pagesMap.lookup(outSec).firstIndex + (symAddr - secAddr) / 0xffff; | |
| 735 | 719 | } else { |
| 736 | Index = G.Local16.lookup({nullptr, getMipsPageAddr(Sym.getVA(Addend))}); | |
| 720 | index = g.local16.lookup({nullptr, getMipsPageAddr(sym.getVA(addend))}); | |
| 737 | 721 | } |
| 738 | return Index * Config->Wordsize; | |
| 722 | return index * config->wordsize; | |
| 739 | 723 | } |
| 740 | 724 | |
| 741 | uint64_t MipsGotSection::getSymEntryOffset(const InputFile *F, const Symbol &S, | |
| 742 | int64_t Addend) const { | |
| 743 | const FileGot &G = Gots[*F->MipsGotIndex]; | |
| 744 | Symbol *Sym = const_cast<Symbol *>(&S); | |
| 745 | if (Sym->isTls()) | |
| 746 | return G.Tls.lookup(Sym) * Config->Wordsize; | |
| 747 | if (Sym->IsPreemptible) | |
| 748 | return G.Global.lookup(Sym) * Config->Wordsize; | |
| 749 | return G.Local16.lookup({Sym, Addend}) * Config->Wordsize; | |
| 725 | uint64_t MipsGotSection::getSymEntryOffset(const InputFile *f, const Symbol &s, | |
| 726 | int64_t addend) const { | |
| 727 | const FileGot &g = gots[*f->mipsGotIndex]; | |
| 728 | Symbol *sym = const_cast<Symbol *>(&s); | |
| 729 | if (sym->isTls()) | |
| 730 | return g.tls.lookup(sym) * config->wordsize; | |
| 731 | if (sym->isPreemptible) | |
| 732 | return g.global.lookup(sym) * config->wordsize; | |
| 733 | return g.local16.lookup({sym, addend}) * config->wordsize; | |
| 750 | 734 | } |
| 751 | 735 | |
| 752 | uint64_t MipsGotSection::getTlsIndexOffset(const InputFile *F) const { | |
| 753 | const FileGot &G = Gots[*F->MipsGotIndex]; | |
| 754 | return G.DynTlsSymbols.lookup(nullptr) * Config->Wordsize; | |
| 736 | uint64_t MipsGotSection::getTlsIndexOffset(const InputFile *f) const { | |
| 737 | const FileGot &g = gots[*f->mipsGotIndex]; | |
| 738 | return g.dynTlsSymbols.lookup(nullptr) * config->wordsize; | |
| 755 | 739 | } |
| 756 | 740 | |
| 757 | uint64_t MipsGotSection::getGlobalDynOffset(const InputFile *F, | |
| 758 | const Symbol &S) const { | |
| 759 | const FileGot &G = Gots[*F->MipsGotIndex]; | |
| 760 | Symbol *Sym = const_cast<Symbol *>(&S); | |
| 761 | return G.DynTlsSymbols.lookup(Sym) * Config->Wordsize; | |
| 741 | uint64_t MipsGotSection::getGlobalDynOffset(const InputFile *f, | |
| 742 | const Symbol &s) const { | |
| 743 | const FileGot &g = gots[*f->mipsGotIndex]; | |
| 744 | Symbol *sym = const_cast<Symbol *>(&s); | |
| 745 | return g.dynTlsSymbols.lookup(sym) * config->wordsize; | |
| 762 | 746 | } |
| 763 | 747 | |
| 764 | 748 | const Symbol *MipsGotSection::getFirstGlobalEntry() const { |
| 765 | if (Gots.empty()) | |
| 749 | if (gots.empty()) | |
| 766 | 750 | return nullptr; |
| 767 | const FileGot &PrimGot = Gots.front(); | |
| 768 | if (!PrimGot.Global.empty()) | |
| 769 | return PrimGot.Global.front().first; | |
| 770 | if (!PrimGot.Relocs.empty()) | |
| 771 | return PrimGot.Relocs.front().first; | |
| 751 | const FileGot &primGot = gots.front(); | |
| 752 | if (!primGot.global.empty()) | |
| 753 | return primGot.global.front().first; | |
| 754 | if (!primGot.relocs.empty()) | |
| 755 | return primGot.relocs.front().first; | |
| 772 | 756 | return nullptr; |
| 773 | 757 | } |
| 774 | 758 | |
| 775 | 759 | unsigned MipsGotSection::getLocalEntriesNum() const { |
| 776 | if (Gots.empty()) | |
| 777 | return HeaderEntriesNum; | |
| 778 | return HeaderEntriesNum + Gots.front().getPageEntriesNum() + | |
| 779 | Gots.front().Local16.size(); | |
| 760 | if (gots.empty()) | |
| 761 | return headerEntriesNum; | |
| 762 | return headerEntriesNum + gots.front().getPageEntriesNum() + | |
| 763 | gots.front().local16.size(); | |
| 780 | 764 | } |
| 781 | 765 | |
| 782 | bool MipsGotSection::tryMergeGots(FileGot &Dst, FileGot &Src, bool IsPrimary) { | |
| 783 | FileGot Tmp = Dst; | |
| 784 | set_union(Tmp.PagesMap, Src.PagesMap); | |
| 785 | set_union(Tmp.Local16, Src.Local16); | |
| 786 | set_union(Tmp.Global, Src.Global); | |
| 787 | set_union(Tmp.Relocs, Src.Relocs); | |
| 788 | set_union(Tmp.Tls, Src.Tls); | |
| 789 | set_union(Tmp.DynTlsSymbols, Src.DynTlsSymbols); | |
| 766 | bool MipsGotSection::tryMergeGots(FileGot &dst, FileGot &src, bool isPrimary) { | |
| 767 | FileGot tmp = dst; | |
| 768 | set_union(tmp.pagesMap, src.pagesMap); | |
| 769 | set_union(tmp.local16, src.local16); | |
| 770 | set_union(tmp.global, src.global); | |
| 771 | set_union(tmp.relocs, src.relocs); | |
| 772 | set_union(tmp.tls, src.tls); | |
| 773 | set_union(tmp.dynTlsSymbols, src.dynTlsSymbols); | |
| 790 | 774 | |
| 791 | size_t Count = IsPrimary ? HeaderEntriesNum : 0; | |
| 792 | Count += Tmp.getIndexedEntriesNum(); | |
| 775 | size_t count = isPrimary ? headerEntriesNum : 0; | |
| 776 | count += tmp.getIndexedEntriesNum(); | |
| 793 | 777 | |
| 794 | if (Count * Config->Wordsize > Config->MipsGotSize) | |
| 778 | if (count * config->wordsize > config->mipsGotSize) | |
| 795 | 779 | return false; |
| 796 | 780 | |
| 797 | std::swap(Tmp, Dst); | |
| 781 | std::swap(tmp, dst); | |
| 798 | 782 | return true; |
| 799 | 783 | } |
| 800 | 784 | |
| 801 | 785 | void MipsGotSection::finalizeContents() { updateAllocSize(); } |
| 802 | 786 | |
| 803 | 787 | bool MipsGotSection::updateAllocSize() { |
| 804 | Size = HeaderEntriesNum * Config->Wordsize; | |
| 805 | for (const FileGot &G : Gots) | |
| 806 | Size += G.getEntriesNum() * Config->Wordsize; | |
| 788 | size = headerEntriesNum * config->wordsize; | |
| 789 | for (const FileGot &g : gots) | |
| 790 | size += g.getEntriesNum() * config->wordsize; | |
| 807 | 791 | return false; |
| 808 | 792 | } |
| 809 | 793 | |
| 810 | template <class ELFT> void MipsGotSection::build() { | |
| 811 | if (Gots.empty()) | |
| 794 | void MipsGotSection::build() { | |
| 795 | if (gots.empty()) | |
| 812 | 796 | return; |
| 813 | 797 | |
| 814 | std::vector<FileGot> MergedGots(1); | |
| 798 | std::vector<FileGot> mergedGots(1); | |
| 815 | 799 | |
| 816 | 800 | // For each GOT move non-preemptible symbols from the `Global` |
| 817 | 801 | // to `Local16` list. Preemptible symbol might become non-preemptible |
| 818 | 802 | // one if, for example, it gets a related copy relocation. |
| 819 | for (FileGot &Got : Gots) { | |
| 820 | for (auto &P: Got.Global) | |
| 821 | if (!P.first->IsPreemptible) | |
| 822 | Got.Local16.insert({{P.first, 0}, 0}); | |
| 823 | Got.Global.remove_if([&](const std::pair<Symbol *, size_t> &P) { | |
| 824 | return !P.first->IsPreemptible; | |
| 803 | for (FileGot &got : gots) { | |
| 804 | for (auto &p: got.global) | |
| 805 | if (!p.first->isPreemptible) | |
| 806 | got.local16.insert({{p.first, 0}, 0}); | |
| 807 | got.global.remove_if([&](const std::pair<Symbol *, size_t> &p) { | |
| 808 | return !p.first->isPreemptible; | |
| 825 | 809 | }); |
| 826 | 810 | } |
| 827 | 811 | |
| 828 | 812 | // For each GOT remove "reloc-only" entry if there is "global" |
| 829 | 813 | // entry for the same symbol. And add local entries which indexed |
| 830 | 814 | // using 32-bit value at the end of 16-bit entries. |
| 831 | for (FileGot &Got : Gots) { | |
| 832 | Got.Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) { | |
| 833 | return Got.Global.count(P.first); | |
| 815 | for (FileGot &got : gots) { | |
| 816 | got.relocs.remove_if([&](const std::pair<Symbol *, size_t> &p) { | |
| 817 | return got.global.count(p.first); | |
| 834 | 818 | }); |
| 835 | set_union(Got.Local16, Got.Local32); | |
| 836 | Got.Local32.clear(); | |
| 819 | set_union(got.local16, got.local32); | |
| 820 | got.local32.clear(); | |
| 837 | 821 | } |
| 838 | 822 | |
| 839 | 823 | // Evaluate number of "reloc-only" entries in the resulting GOT. |
| 840 | 824 | // To do that put all unique "reloc-only" and "global" entries |
| 841 | 825 | // from all GOTs to the future primary GOT. |
| 842 | FileGot *PrimGot = &MergedGots.front(); | |
| 843 | for (FileGot &Got : Gots) { | |
| 844 | set_union(PrimGot->Relocs, Got.Global); | |
| 845 | set_union(PrimGot->Relocs, Got.Relocs); | |
| 846 | Got.Relocs.clear(); | |
| 826 | FileGot *primGot = &mergedGots.front(); | |
| 827 | for (FileGot &got : gots) { | |
| 828 | set_union(primGot->relocs, got.global); | |
| 829 | set_union(primGot->relocs, got.relocs); | |
| 830 | got.relocs.clear(); | |
| 847 | 831 | } |
| 848 | 832 | |
| 849 | 833 | // Evaluate number of "page" entries in each GOT. |
| 850 | for (FileGot &Got : Gots) { | |
| 851 | for (std::pair<const OutputSection *, FileGot::PageBlock> &P : | |
| 852 | Got.PagesMap) { | |
| 853 | const OutputSection *OS = P.first; | |
| 854 | uint64_t SecSize = 0; | |
| 855 | for (BaseCommand *Cmd : OS->SectionCommands) { | |
| 856 | if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd)) | |
| 857 | for (InputSection *IS : ISD->Sections) { | |
| 858 | uint64_t Off = alignTo(SecSize, IS->Alignment); | |
| 859 | SecSize = Off + IS->getSize(); | |
| 834 | for (FileGot &got : gots) { | |
| 835 | for (std::pair<const OutputSection *, FileGot::PageBlock> &p : | |
| 836 | got.pagesMap) { | |
| 837 | const OutputSection *os = p.first; | |
| 838 | uint64_t secSize = 0; | |
| 839 | for (BaseCommand *cmd : os->sectionCommands) { | |
| 840 | if (auto *isd = dyn_cast<InputSectionDescription>(cmd)) | |
| 841 | for (InputSection *isec : isd->sections) { | |
| 842 | uint64_t off = alignTo(secSize, isec->alignment); | |
| 843 | secSize = off + isec->getSize(); | |
| 860 | 844 | } |
| 861 | 845 | } |
| 862 | P.second.Count = getMipsPageCount(SecSize); | |
| 846 | p.second.count = getMipsPageCount(secSize); | |
| 863 | 847 | } |
| 864 | 848 | } |
| 865 | 849 | |
| ... | ... | @@ -868,149 +852,149 @@ template <class ELFT> void MipsGotSection::build() { |
| 868 | 852 | // the primary GOT can be accessed in the most effective way. If it |
| 869 | 853 | // is not possible, try to fill the last GOT in the list, and finally |
| 870 | 854 | // create a new GOT if both attempts failed. |
| 871 | for (FileGot &SrcGot : Gots) { | |
| 872 | InputFile *File = SrcGot.File; | |
| 873 | if (tryMergeGots(MergedGots.front(), SrcGot, true)) { | |
| 874 | File->MipsGotIndex = 0; | |
| 855 | for (FileGot &srcGot : gots) { | |
| 856 | InputFile *file = srcGot.file; | |
| 857 | if (tryMergeGots(mergedGots.front(), srcGot, true)) { | |
| 858 | file->mipsGotIndex = 0; | |
| 875 | 859 | } else { |
| 876 | 860 | // If this is the first time we failed to merge with the primary GOT, |
| 877 | 861 | // MergedGots.back() will also be the primary GOT. We must make sure not |
| 878 | // to try to merge again with IsPrimary=false, as otherwise, if the | |
| 862 | // to try to merge again with isPrimary=false, as otherwise, if the | |
| 879 | 863 | // inputs are just right, we could allow the primary GOT to become 1 or 2 |
| 880 | // words too big due to ignoring the header size. | |
| 881 | if (MergedGots.size() == 1 || | |
| 882 | !tryMergeGots(MergedGots.back(), SrcGot, false)) { | |
| 883 | MergedGots.emplace_back(); | |
| 884 | std::swap(MergedGots.back(), SrcGot); | |
| 864 | // words bigger due to ignoring the header size. | |
| 865 | if (mergedGots.size() == 1 || | |
| 866 | !tryMergeGots(mergedGots.back(), srcGot, false)) { | |
| 867 | mergedGots.emplace_back(); | |
| 868 | std::swap(mergedGots.back(), srcGot); | |
| 885 | 869 | } |
| 886 | File->MipsGotIndex = MergedGots.size() - 1; | |
| 870 | file->mipsGotIndex = mergedGots.size() - 1; | |
| 887 | 871 | } |
| 888 | 872 | } |
| 889 | std::swap(Gots, MergedGots); | |
| 873 | std::swap(gots, mergedGots); | |
| 890 | 874 | |
| 891 | 875 | // Reduce number of "reloc-only" entries in the primary GOT |
| 892 | 876 | // by substracting "global" entries exist in the primary GOT. |
| 893 | PrimGot = &Gots.front(); | |
| 894 | PrimGot->Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) { | |
| 895 | return PrimGot->Global.count(P.first); | |
| 877 | primGot = &gots.front(); | |
| 878 | primGot->relocs.remove_if([&](const std::pair<Symbol *, size_t> &p) { | |
| 879 | return primGot->global.count(p.first); | |
| 896 | 880 | }); |
| 897 | 881 | |
| 898 | 882 | // Calculate indexes for each GOT entry. |
| 899 | size_t Index = HeaderEntriesNum; | |
| 900 | for (FileGot &Got : Gots) { | |
| 901 | Got.StartIndex = &Got == PrimGot ? 0 : Index; | |
| 902 | for (std::pair<const OutputSection *, FileGot::PageBlock> &P : | |
| 903 | Got.PagesMap) { | |
| 883 | size_t index = headerEntriesNum; | |
| 884 | for (FileGot &got : gots) { | |
| 885 | got.startIndex = &got == primGot ? 0 : index; | |
| 886 | for (std::pair<const OutputSection *, FileGot::PageBlock> &p : | |
| 887 | got.pagesMap) { | |
| 904 | 888 | // For each output section referenced by GOT page relocations calculate |
| 905 | // and save into PagesMap an upper bound of MIPS GOT entries required | |
| 889 | // and save into pagesMap an upper bound of MIPS GOT entries required | |
| 906 | 890 | // to store page addresses of local symbols. We assume the worst case - |
| 907 | 891 | // each 64kb page of the output section has at least one GOT relocation |
| 908 | 892 | // against it. And take in account the case when the section intersects |
| 909 | 893 | // page boundaries. |
| 910 | P.second.FirstIndex = Index; | |
| 911 | Index += P.second.Count; | |
| 894 | p.second.firstIndex = index; | |
| 895 | index += p.second.count; | |
| 912 | 896 | } |
| 913 | for (auto &P: Got.Local16) | |
| 914 | P.second = Index++; | |
| 915 | for (auto &P: Got.Global) | |
| 916 | P.second = Index++; | |
| 917 | for (auto &P: Got.Relocs) | |
| 918 | P.second = Index++; | |
| 919 | for (auto &P: Got.Tls) | |
| 920 | P.second = Index++; | |
| 921 | for (auto &P: Got.DynTlsSymbols) { | |
| 922 | P.second = Index; | |
| 923 | Index += 2; | |
| 897 | for (auto &p: got.local16) | |
| 898 | p.second = index++; | |
| 899 | for (auto &p: got.global) | |
| 900 | p.second = index++; | |
| 901 | for (auto &p: got.relocs) | |
| 902 | p.second = index++; | |
| 903 | for (auto &p: got.tls) | |
| 904 | p.second = index++; | |
| 905 | for (auto &p: got.dynTlsSymbols) { | |
| 906 | p.second = index; | |
| 907 | index += 2; | |
| 924 | 908 | } |
| 925 | 909 | } |
| 926 | 910 | |
| 927 | // Update Symbol::GotIndex field to use this | |
| 911 | // Update Symbol::gotIndex field to use this | |
| 928 | 912 | // value later in the `sortMipsSymbols` function. |
| 929 | for (auto &P : PrimGot->Global) | |
| 930 | P.first->GotIndex = P.second; | |
| 931 | for (auto &P : PrimGot->Relocs) | |
| 932 | P.first->GotIndex = P.second; | |
| 913 | for (auto &p : primGot->global) | |
| 914 | p.first->gotIndex = p.second; | |
| 915 | for (auto &p : primGot->relocs) | |
| 916 | p.first->gotIndex = p.second; | |
| 933 | 917 | |
| 934 | 918 | // Create dynamic relocations. |
| 935 | for (FileGot &Got : Gots) { | |
| 919 | for (FileGot &got : gots) { | |
| 936 | 920 | // Create dynamic relocations for TLS entries. |
| 937 | for (std::pair<Symbol *, size_t> &P : Got.Tls) { | |
| 938 | Symbol *S = P.first; | |
| 939 | uint64_t Offset = P.second * Config->Wordsize; | |
| 940 | if (S->IsPreemptible) | |
| 941 | In.RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S); | |
| 921 | for (std::pair<Symbol *, size_t> &p : got.tls) { | |
| 922 | Symbol *s = p.first; | |
| 923 | uint64_t offset = p.second * config->wordsize; | |
| 924 | if (s->isPreemptible) | |
| 925 | mainPart->relaDyn->addReloc(target->tlsGotRel, this, offset, s); | |
| 942 | 926 | } |
| 943 | for (std::pair<Symbol *, size_t> &P : Got.DynTlsSymbols) { | |
| 944 | Symbol *S = P.first; | |
| 945 | uint64_t Offset = P.second * Config->Wordsize; | |
| 946 | if (S == nullptr) { | |
| 947 | if (!Config->Pic) | |
| 927 | for (std::pair<Symbol *, size_t> &p : got.dynTlsSymbols) { | |
| 928 | Symbol *s = p.first; | |
| 929 | uint64_t offset = p.second * config->wordsize; | |
| 930 | if (s == nullptr) { | |
| 931 | if (!config->isPic) | |
| 948 | 932 | continue; |
| 949 | In.RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S); | |
| 933 | mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, this, offset, s); | |
| 950 | 934 | } else { |
| 951 | 935 | // When building a shared library we still need a dynamic relocation |
| 952 | 936 | // for the module index. Therefore only checking for |
| 953 | // S->IsPreemptible is not sufficient (this happens e.g. for | |
| 937 | // S->isPreemptible is not sufficient (this happens e.g. for | |
| 954 | 938 | // thread-locals that have been marked as local through a linker script) |
| 955 | if (!S->IsPreemptible && !Config->Pic) | |
| 939 | if (!s->isPreemptible && !config->isPic) | |
| 956 | 940 | continue; |
| 957 | In.RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S); | |
| 941 | mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, this, offset, s); | |
| 958 | 942 | // However, we can skip writing the TLS offset reloc for non-preemptible |
| 959 | 943 | // symbols since it is known even in shared libraries |
| 960 | if (!S->IsPreemptible) | |
| 944 | if (!s->isPreemptible) | |
| 961 | 945 | continue; |
| 962 | Offset += Config->Wordsize; | |
| 963 | In.RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S); | |
| 946 | offset += config->wordsize; | |
| 947 | mainPart->relaDyn->addReloc(target->tlsOffsetRel, this, offset, s); | |
| 964 | 948 | } |
| 965 | 949 | } |
| 966 | 950 | |
| 967 | 951 | // Do not create dynamic relocations for non-TLS |
| 968 | 952 | // entries in the primary GOT. |
| 969 | if (&Got == PrimGot) | |
| 953 | if (&got == primGot) | |
| 970 | 954 | continue; |
| 971 | 955 | |
| 972 | 956 | // Dynamic relocations for "global" entries. |
| 973 | for (const std::pair<Symbol *, size_t> &P : Got.Global) { | |
| 974 | uint64_t Offset = P.second * Config->Wordsize; | |
| 975 | In.RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first); | |
| 957 | for (const std::pair<Symbol *, size_t> &p : got.global) { | |
| 958 | uint64_t offset = p.second * config->wordsize; | |
| 959 | mainPart->relaDyn->addReloc(target->relativeRel, this, offset, p.first); | |
| 976 | 960 | } |
| 977 | if (!Config->Pic) | |
| 961 | if (!config->isPic) | |
| 978 | 962 | continue; |
| 979 | 963 | // Dynamic relocations for "local" entries in case of PIC. |
| 980 | for (const std::pair<const OutputSection *, FileGot::PageBlock> &L : | |
| 981 | Got.PagesMap) { | |
| 982 | size_t PageCount = L.second.Count; | |
| 983 | for (size_t PI = 0; PI < PageCount; ++PI) { | |
| 984 | uint64_t Offset = (L.second.FirstIndex + PI) * Config->Wordsize; | |
| 985 | In.RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first, | |
| 986 | int64_t(PI * 0x10000)}); | |
| 964 | for (const std::pair<const OutputSection *, FileGot::PageBlock> &l : | |
| 965 | got.pagesMap) { | |
| 966 | size_t pageCount = l.second.count; | |
| 967 | for (size_t pi = 0; pi < pageCount; ++pi) { | |
| 968 | uint64_t offset = (l.second.firstIndex + pi) * config->wordsize; | |
| 969 | mainPart->relaDyn->addReloc({target->relativeRel, this, offset, l.first, | |
| 970 | int64_t(pi * 0x10000)}); | |
| 987 | 971 | } |
| 988 | 972 | } |
| 989 | for (const std::pair<GotEntry, size_t> &P : Got.Local16) { | |
| 990 | uint64_t Offset = P.second * Config->Wordsize; | |
| 991 | In.RelaDyn->addReloc({Target->RelativeRel, this, Offset, true, | |
| 992 | P.first.first, P.first.second}); | |
| 973 | for (const std::pair<GotEntry, size_t> &p : got.local16) { | |
| 974 | uint64_t offset = p.second * config->wordsize; | |
| 975 | mainPart->relaDyn->addReloc({target->relativeRel, this, offset, true, | |
| 976 | p.first.first, p.first.second}); | |
| 993 | 977 | } |
| 994 | 978 | } |
| 995 | 979 | } |
| 996 | 980 | |
| 997 | bool MipsGotSection::empty() const { | |
| 981 | bool MipsGotSection::isNeeded() const { | |
| 998 | 982 | // We add the .got section to the result for dynamic MIPS target because |
| 999 | 983 | // its address and properties are mentioned in the .dynamic section. |
| 1000 | return Config->Relocatable; | |
| 984 | return !config->relocatable; | |
| 1001 | 985 | } |
| 1002 | 986 | |
| 1003 | uint64_t MipsGotSection::getGp(const InputFile *F) const { | |
| 987 | uint64_t MipsGotSection::getGp(const InputFile *f) const { | |
| 1004 | 988 | // For files without related GOT or files refer a primary GOT |
| 1005 | 989 | // returns "common" _gp value. For secondary GOTs calculate |
| 1006 | 990 | // individual _gp values. |
| 1007 | if (!F || !F->MipsGotIndex.hasValue() || *F->MipsGotIndex == 0) | |
| 1008 | return ElfSym::MipsGp->getVA(0); | |
| 1009 | return getVA() + Gots[*F->MipsGotIndex].StartIndex * Config->Wordsize + | |
| 991 | if (!f || !f->mipsGotIndex.hasValue() || *f->mipsGotIndex == 0) | |
| 992 | return ElfSym::mipsGp->getVA(0); | |
| 993 | return getVA() + gots[*f->mipsGotIndex].startIndex * config->wordsize + | |
| 1010 | 994 | 0x7ff0; |
| 1011 | 995 | } |
| 1012 | 996 | |
| 1013 | void MipsGotSection::writeTo(uint8_t *Buf) { | |
| 997 | void MipsGotSection::writeTo(uint8_t *buf) { | |
| 1014 | 998 | // Set the MSB of the second GOT slot. This is not required by any |
| 1015 | 999 | // MIPS ABI documentation, though. |
| 1016 | 1000 | // |
| ... | ... | @@ -1025,51 +1009,48 @@ void MipsGotSection::writeTo(uint8_t *Buf) { |
| 1025 | 1009 | // we've been doing this for years, it is probably a safe bet to |
| 1026 | 1010 | // keep doing this for now. We really need to revisit this to see |
| 1027 | 1011 | // if we had to do this. |
| 1028 | writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1)); | |
| 1029 | for (const FileGot &G : Gots) { | |
| 1030 | auto Write = [&](size_t I, const Symbol *S, int64_t A) { | |
| 1031 | uint64_t VA = A; | |
| 1032 | if (S) { | |
| 1033 | VA = S->getVA(A); | |
| 1034 | if (S->StOther & STO_MIPS_MICROMIPS) | |
| 1035 | VA |= 1; | |
| 1036 | } | |
| 1037 | writeUint(Buf + I * Config->Wordsize, VA); | |
| 1012 | writeUint(buf + config->wordsize, (uint64_t)1 << (config->wordsize * 8 - 1)); | |
| 1013 | for (const FileGot &g : gots) { | |
| 1014 | auto write = [&](size_t i, const Symbol *s, int64_t a) { | |
| 1015 | uint64_t va = a; | |
| 1016 | if (s) | |
| 1017 | va = s->getVA(a); | |
| 1018 | writeUint(buf + i * config->wordsize, va); | |
| 1038 | 1019 | }; |
| 1039 | 1020 | // Write 'page address' entries to the local part of the GOT. |
| 1040 | for (const std::pair<const OutputSection *, FileGot::PageBlock> &L : | |
| 1041 | G.PagesMap) { | |
| 1042 | size_t PageCount = L.second.Count; | |
| 1043 | uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr); | |
| 1044 | for (size_t PI = 0; PI < PageCount; ++PI) | |
| 1045 | Write(L.second.FirstIndex + PI, nullptr, FirstPageAddr + PI * 0x10000); | |
| 1021 | for (const std::pair<const OutputSection *, FileGot::PageBlock> &l : | |
| 1022 | g.pagesMap) { | |
| 1023 | size_t pageCount = l.second.count; | |
| 1024 | uint64_t firstPageAddr = getMipsPageAddr(l.first->addr); | |
| 1025 | for (size_t pi = 0; pi < pageCount; ++pi) | |
| 1026 | write(l.second.firstIndex + pi, nullptr, firstPageAddr + pi * 0x10000); | |
| 1046 | 1027 | } |
| 1047 | 1028 | // Local, global, TLS, reloc-only entries. |
| 1048 | 1029 | // If TLS entry has a corresponding dynamic relocations, leave it |
| 1049 | 1030 | // initialized by zero. Write down adjusted TLS symbol's values otherwise. |
| 1050 | 1031 | // To calculate the adjustments use offsets for thread-local storage. |
| 1051 | 1032 | // https://www.linux-mips.org/wiki/NPTL |
| 1052 | for (const std::pair<GotEntry, size_t> &P : G.Local16) | |
| 1053 | Write(P.second, P.first.first, P.first.second); | |
| 1033 | for (const std::pair<GotEntry, size_t> &p : g.local16) | |
| 1034 | write(p.second, p.first.first, p.first.second); | |
| 1054 | 1035 | // Write VA to the primary GOT only. For secondary GOTs that |
| 1055 | 1036 | // will be done by REL32 dynamic relocations. |
| 1056 | if (&G == &Gots.front()) | |
| 1057 | for (const std::pair<const Symbol *, size_t> &P : G.Global) | |
| 1058 | Write(P.second, P.first, 0); | |
| 1059 | for (const std::pair<Symbol *, size_t> &P : G.Relocs) | |
| 1060 | Write(P.second, P.first, 0); | |
| 1061 | for (const std::pair<Symbol *, size_t> &P : G.Tls) | |
| 1062 | Write(P.second, P.first, P.first->IsPreemptible ? 0 : -0x7000); | |
| 1063 | for (const std::pair<Symbol *, size_t> &P : G.DynTlsSymbols) { | |
| 1064 | if (P.first == nullptr && !Config->Pic) | |
| 1065 | Write(P.second, nullptr, 1); | |
| 1066 | else if (P.first && !P.first->IsPreemptible) { | |
| 1037 | if (&g == &gots.front()) | |
| 1038 | for (const std::pair<const Symbol *, size_t> &p : g.global) | |
| 1039 | write(p.second, p.first, 0); | |
| 1040 | for (const std::pair<Symbol *, size_t> &p : g.relocs) | |
| 1041 | write(p.second, p.first, 0); | |
| 1042 | for (const std::pair<Symbol *, size_t> &p : g.tls) | |
| 1043 | write(p.second, p.first, p.first->isPreemptible ? 0 : -0x7000); | |
| 1044 | for (const std::pair<Symbol *, size_t> &p : g.dynTlsSymbols) { | |
| 1045 | if (p.first == nullptr && !config->isPic) | |
| 1046 | write(p.second, nullptr, 1); | |
| 1047 | else if (p.first && !p.first->isPreemptible) { | |
| 1067 | 1048 | // If we are emitting PIC code with relocations we mustn't write |
| 1068 | 1049 | // anything to the GOT here. When using Elf_Rel relocations the value |
| 1069 | 1050 | // one will be treated as an addend and will cause crashes at runtime |
| 1070 | if (!Config->Pic) | |
| 1071 | Write(P.second, nullptr, 1); | |
| 1072 | Write(P.second + 1, P.first, -0x8000); | |
| 1051 | if (!config->isPic) | |
| 1052 | write(p.second, nullptr, 1); | |
| 1053 | write(p.second + 1, p.first, -0x8000); | |
| 1073 | 1054 | } |
| 1074 | 1055 | } |
| 1075 | 1056 | } |
| ... | ... | @@ -1080,46 +1061,48 @@ void MipsGotSection::writeTo(uint8_t *Buf) { |
| 1080 | 1061 | // section. I don't know why we have a BSS style type for the section but it is |
| 1081 | 1062 | // consitent across both 64-bit PowerPC ABIs as well as the 32-bit PowerPC ABI. |
| 1082 | 1063 | GotPltSection::GotPltSection() |
| 1083 | : SyntheticSection(SHF_ALLOC | SHF_WRITE, | |
| 1084 | Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS, | |
| 1085 | Target->GotPltEntrySize, | |
| 1086 | Config->EMachine == EM_PPC64 ? ".plt" : ".got.plt") {} | |
| 1064 | : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize, | |
| 1065 | ".got.plt") { | |
| 1066 | if (config->emachine == EM_PPC) { | |
| 1067 | name = ".plt"; | |
| 1068 | } else if (config->emachine == EM_PPC64) { | |
| 1069 | type = SHT_NOBITS; | |
| 1070 | name = ".plt"; | |
| 1071 | } | |
| 1072 | } | |
| 1087 | 1073 | |
| 1088 | void GotPltSection::addEntry(Symbol &Sym) { | |
| 1089 | assert(Sym.PltIndex == Entries.size()); | |
| 1090 | Entries.push_back(&Sym); | |
| 1074 | void GotPltSection::addEntry(Symbol &sym) { | |
| 1075 | assert(sym.pltIndex == entries.size()); | |
| 1076 | entries.push_back(&sym); | |
| 1091 | 1077 | } |
| 1092 | 1078 | |
| 1093 | 1079 | size_t GotPltSection::getSize() const { |
| 1094 | return (Target->GotPltHeaderEntriesNum + Entries.size()) * | |
| 1095 | Target->GotPltEntrySize; | |
| 1080 | return (target->gotPltHeaderEntriesNum + entries.size()) * config->wordsize; | |
| 1096 | 1081 | } |
| 1097 | 1082 | |
| 1098 | void GotPltSection::writeTo(uint8_t *Buf) { | |
| 1099 | Target->writeGotPltHeader(Buf); | |
| 1100 | Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize; | |
| 1101 | for (const Symbol *B : Entries) { | |
| 1102 | Target->writeGotPlt(Buf, *B); | |
| 1103 | Buf += Config->Wordsize; | |
| 1083 | void GotPltSection::writeTo(uint8_t *buf) { | |
| 1084 | target->writeGotPltHeader(buf); | |
| 1085 | buf += target->gotPltHeaderEntriesNum * config->wordsize; | |
| 1086 | for (const Symbol *b : entries) { | |
| 1087 | target->writeGotPlt(buf, *b); | |
| 1088 | buf += config->wordsize; | |
| 1104 | 1089 | } |
| 1105 | 1090 | } |
| 1106 | 1091 | |
| 1107 | bool GotPltSection::empty() const { | |
| 1108 | // We need to emit a GOT.PLT even if it's empty if there's a symbol that | |
| 1109 | // references the _GLOBAL_OFFSET_TABLE_ and the Target defines the symbol | |
| 1110 | // relative to the .got.plt section. | |
| 1111 | return Entries.empty() && | |
| 1112 | !(ElfSym::GlobalOffsetTable && Target->GotBaseSymInGotPlt); | |
| 1092 | bool GotPltSection::isNeeded() const { | |
| 1093 | // We need to emit GOTPLT even if it's empty if there's a relocation relative | |
| 1094 | // to it. | |
| 1095 | return !entries.empty() || hasGotPltOffRel; | |
| 1113 | 1096 | } |
| 1114 | 1097 | |
| 1115 | 1098 | static StringRef getIgotPltName() { |
| 1116 | 1099 | // On ARM the IgotPltSection is part of the GotSection. |
| 1117 | if (Config->EMachine == EM_ARM) | |
| 1100 | if (config->emachine == EM_ARM) | |
| 1118 | 1101 | return ".got"; |
| 1119 | 1102 | |
| 1120 | 1103 | // On PowerPC64 the GotPltSection is renamed to '.plt' so the IgotPltSection |
| 1121 | 1104 | // needs to be named the same. |
| 1122 | if (Config->EMachine == EM_PPC64) | |
| 1105 | if (config->emachine == EM_PPC64) | |
| 1123 | 1106 | return ".plt"; |
| 1124 | 1107 | |
| 1125 | 1108 | return ".got.plt"; |
| ... | ... | @@ -1129,130 +1112,110 @@ static StringRef getIgotPltName() { |
| 1129 | 1112 | // with the IgotPltSection. |
| 1130 | 1113 | IgotPltSection::IgotPltSection() |
| 1131 | 1114 | : SyntheticSection(SHF_ALLOC | SHF_WRITE, |
| 1132 | Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS, | |
| 1133 | Target->GotPltEntrySize, getIgotPltName()) {} | |
| 1115 | config->emachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS, | |
| 1116 | config->wordsize, getIgotPltName()) {} | |
| 1134 | 1117 | |
| 1135 | void IgotPltSection::addEntry(Symbol &Sym) { | |
| 1136 | Sym.IsInIgot = true; | |
| 1137 | assert(Sym.PltIndex == Entries.size()); | |
| 1138 | Entries.push_back(&Sym); | |
| 1118 | void IgotPltSection::addEntry(Symbol &sym) { | |
| 1119 | assert(sym.pltIndex == entries.size()); | |
| 1120 | entries.push_back(&sym); | |
| 1139 | 1121 | } |
| 1140 | 1122 | |
| 1141 | 1123 | size_t IgotPltSection::getSize() const { |
| 1142 | return Entries.size() * Target->GotPltEntrySize; | |
| 1124 | return entries.size() * config->wordsize; | |
| 1143 | 1125 | } |
| 1144 | 1126 | |
| 1145 | void IgotPltSection::writeTo(uint8_t *Buf) { | |
| 1146 | for (const Symbol *B : Entries) { | |
| 1147 | Target->writeIgotPlt(Buf, *B); | |
| 1148 | Buf += Config->Wordsize; | |
| 1127 | void IgotPltSection::writeTo(uint8_t *buf) { | |
| 1128 | for (const Symbol *b : entries) { | |
| 1129 | target->writeIgotPlt(buf, *b); | |
| 1130 | buf += config->wordsize; | |
| 1149 | 1131 | } |
| 1150 | 1132 | } |
| 1151 | 1133 | |
| 1152 | StringTableSection::StringTableSection(StringRef Name, bool Dynamic) | |
| 1153 | : SyntheticSection(Dynamic ? (uint64_t)SHF_ALLOC : 0, SHT_STRTAB, 1, Name), | |
| 1154 | Dynamic(Dynamic) { | |
| 1134 | StringTableSection::StringTableSection(StringRef name, bool dynamic) | |
| 1135 | : SyntheticSection(dynamic ? (uint64_t)SHF_ALLOC : 0, SHT_STRTAB, 1, name), | |
| 1136 | dynamic(dynamic) { | |
| 1155 | 1137 | // ELF string tables start with a NUL byte. |
| 1156 | 1138 | addString(""); |
| 1157 | 1139 | } |
| 1158 | 1140 | |
| 1159 | // Adds a string to the string table. If HashIt is true we hash and check for | |
| 1141 | // Adds a string to the string table. If `hashIt` is true we hash and check for | |
| 1160 | 1142 | // duplicates. It is optional because the name of global symbols are already |
| 1161 | 1143 | // uniqued and hashing them again has a big cost for a small value: uniquing |
| 1162 | 1144 | // them with some other string that happens to be the same. |
| 1163 | unsigned StringTableSection::addString(StringRef S, bool HashIt) { | |
| 1164 | if (HashIt) { | |
| 1165 | auto R = StringMap.insert(std::make_pair(S, this->Size)); | |
| 1166 | if (!R.second) | |
| 1167 | return R.first->second; | |
| 1145 | unsigned StringTableSection::addString(StringRef s, bool hashIt) { | |
| 1146 | if (hashIt) { | |
| 1147 | auto r = stringMap.insert(std::make_pair(s, this->size)); | |
| 1148 | if (!r.second) | |
| 1149 | return r.first->second; | |
| 1168 | 1150 | } |
| 1169 | unsigned Ret = this->Size; | |
| 1170 | this->Size = this->Size + S.size() + 1; | |
| 1171 | Strings.push_back(S); | |
| 1172 | return Ret; | |
| 1151 | unsigned ret = this->size; | |
| 1152 | this->size = this->size + s.size() + 1; | |
| 1153 | strings.push_back(s); | |
| 1154 | return ret; | |
| 1173 | 1155 | } |
| 1174 | 1156 | |
| 1175 | void StringTableSection::writeTo(uint8_t *Buf) { | |
| 1176 | for (StringRef S : Strings) { | |
| 1177 | memcpy(Buf, S.data(), S.size()); | |
| 1178 | Buf[S.size()] = '\0'; | |
| 1179 | Buf += S.size() + 1; | |
| 1157 | void StringTableSection::writeTo(uint8_t *buf) { | |
| 1158 | for (StringRef s : strings) { | |
| 1159 | memcpy(buf, s.data(), s.size()); | |
| 1160 | buf[s.size()] = '\0'; | |
| 1161 | buf += s.size() + 1; | |
| 1180 | 1162 | } |
| 1181 | 1163 | } |
| 1182 | 1164 | |
| 1183 | 1165 | // Returns the number of version definition entries. Because the first entry |
| 1184 | 1166 | // is for the version definition itself, it is the number of versioned symbols |
| 1185 | 1167 | // plus one. Note that we don't support multiple versions yet. |
| 1186 | static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; } | |
| 1168 | static unsigned getVerDefNum() { return config->versionDefinitions.size() + 1; } | |
| 1187 | 1169 | |
| 1188 | 1170 | template <class ELFT> |
| 1189 | 1171 | DynamicSection<ELFT>::DynamicSection() |
| 1190 | : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC, Config->Wordsize, | |
| 1172 | : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC, config->wordsize, | |
| 1191 | 1173 | ".dynamic") { |
| 1192 | this->Entsize = ELFT::Is64Bits ? 16 : 8; | |
| 1174 | this->entsize = ELFT::Is64Bits ? 16 : 8; | |
| 1193 | 1175 | |
| 1194 | 1176 | // .dynamic section is not writable on MIPS and on Fuchsia OS |
| 1195 | 1177 | // which passes -z rodynamic. |
| 1196 | 1178 | // See "Special Section" in Chapter 4 in the following document: |
| 1197 | 1179 | // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf |
| 1198 | if (Config->EMachine == EM_MIPS || Config->ZRodynamic) | |
| 1199 | this->Flags = SHF_ALLOC; | |
| 1200 | ||
| 1201 | // Add strings to .dynstr early so that .dynstr's size will be | |
| 1202 | // fixed early. | |
| 1203 | for (StringRef S : Config->FilterList) | |
| 1204 | addInt(DT_FILTER, In.DynStrTab->addString(S)); | |
| 1205 | for (StringRef S : Config->AuxiliaryList) | |
| 1206 | addInt(DT_AUXILIARY, In.DynStrTab->addString(S)); | |
| 1207 | ||
| 1208 | if (!Config->Rpath.empty()) | |
| 1209 | addInt(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, | |
| 1210 | In.DynStrTab->addString(Config->Rpath)); | |
| 1211 | ||
| 1212 | for (InputFile *File : SharedFiles) { | |
| 1213 | SharedFile<ELFT> *F = cast<SharedFile<ELFT>>(File); | |
| 1214 | if (F->IsNeeded) | |
| 1215 | addInt(DT_NEEDED, In.DynStrTab->addString(F->SoName)); | |
| 1216 | } | |
| 1217 | if (!Config->SoName.empty()) | |
| 1218 | addInt(DT_SONAME, In.DynStrTab->addString(Config->SoName)); | |
| 1180 | if (config->emachine == EM_MIPS || config->zRodynamic) | |
| 1181 | this->flags = SHF_ALLOC; | |
| 1219 | 1182 | } |
| 1220 | 1183 | |
| 1221 | 1184 | template <class ELFT> |
| 1222 | void DynamicSection<ELFT>::add(int32_t Tag, std::function<uint64_t()> Fn) { | |
| 1223 | Entries.push_back({Tag, Fn}); | |
| 1185 | void DynamicSection<ELFT>::add(int32_t tag, std::function<uint64_t()> fn) { | |
| 1186 | entries.push_back({tag, fn}); | |
| 1224 | 1187 | } |
| 1225 | 1188 | |
| 1226 | 1189 | template <class ELFT> |
| 1227 | void DynamicSection<ELFT>::addInt(int32_t Tag, uint64_t Val) { | |
| 1228 | Entries.push_back({Tag, [=] { return Val; }}); | |
| 1190 | void DynamicSection<ELFT>::addInt(int32_t tag, uint64_t val) { | |
| 1191 | entries.push_back({tag, [=] { return val; }}); | |
| 1229 | 1192 | } |
| 1230 | 1193 | |
| 1231 | 1194 | template <class ELFT> |
| 1232 | void DynamicSection<ELFT>::addInSec(int32_t Tag, InputSection *Sec) { | |
| 1233 | Entries.push_back({Tag, [=] { return Sec->getVA(0); }}); | |
| 1195 | void DynamicSection<ELFT>::addInSec(int32_t tag, InputSection *sec) { | |
| 1196 | entries.push_back({tag, [=] { return sec->getVA(0); }}); | |
| 1234 | 1197 | } |
| 1235 | 1198 | |
| 1236 | 1199 | template <class ELFT> |
| 1237 | void DynamicSection<ELFT>::addInSecRelative(int32_t Tag, InputSection *Sec) { | |
| 1238 | size_t TagOffset = Entries.size() * Entsize; | |
| 1239 | Entries.push_back( | |
| 1240 | {Tag, [=] { return Sec->getVA(0) - (getVA() + TagOffset); }}); | |
| 1200 | void DynamicSection<ELFT>::addInSecRelative(int32_t tag, InputSection *sec) { | |
| 1201 | size_t tagOffset = entries.size() * entsize; | |
| 1202 | entries.push_back( | |
| 1203 | {tag, [=] { return sec->getVA(0) - (getVA() + tagOffset); }}); | |
| 1241 | 1204 | } |
| 1242 | 1205 | |
| 1243 | 1206 | template <class ELFT> |
| 1244 | void DynamicSection<ELFT>::addOutSec(int32_t Tag, OutputSection *Sec) { | |
| 1245 | Entries.push_back({Tag, [=] { return Sec->Addr; }}); | |
| 1207 | void DynamicSection<ELFT>::addOutSec(int32_t tag, OutputSection *sec) { | |
| 1208 | entries.push_back({tag, [=] { return sec->addr; }}); | |
| 1246 | 1209 | } |
| 1247 | 1210 | |
| 1248 | 1211 | template <class ELFT> |
| 1249 | void DynamicSection<ELFT>::addSize(int32_t Tag, OutputSection *Sec) { | |
| 1250 | Entries.push_back({Tag, [=] { return Sec->Size; }}); | |
| 1212 | void DynamicSection<ELFT>::addSize(int32_t tag, OutputSection *sec) { | |
| 1213 | entries.push_back({tag, [=] { return sec->size; }}); | |
| 1251 | 1214 | } |
| 1252 | 1215 | |
| 1253 | 1216 | template <class ELFT> |
| 1254 | void DynamicSection<ELFT>::addSym(int32_t Tag, Symbol *Sym) { | |
| 1255 | Entries.push_back({Tag, [=] { return Sym->getVA(); }}); | |
| 1217 | void DynamicSection<ELFT>::addSym(int32_t tag, Symbol *sym) { | |
| 1218 | entries.push_back({tag, [=] { return sym->getVA(); }}); | |
| 1256 | 1219 | } |
| 1257 | 1220 | |
| 1258 | 1221 | // A Linker script may assign the RELA relocation sections to the same |
| ... | ... | @@ -1260,47 +1223,74 @@ void DynamicSection<ELFT>::addSym(int32_t Tag, Symbol *Sym) { |
| 1260 | 1223 | // Size. Moreover the [DT_JMPREL, DT_JMPREL + DT_PLTRELSZ) is permitted to |
| 1261 | 1224 | // overlap with the [DT_RELA, DT_RELA + DT_RELASZ). |
| 1262 | 1225 | static uint64_t addPltRelSz() { |
| 1263 | size_t Size = In.RelaPlt->getSize(); | |
| 1264 | if (In.RelaIplt->getParent() == In.RelaPlt->getParent() && | |
| 1265 | In.RelaIplt->Name == In.RelaPlt->Name) | |
| 1266 | Size += In.RelaIplt->getSize(); | |
| 1267 | return Size; | |
| 1226 | size_t size = in.relaPlt->getSize(); | |
| 1227 | if (in.relaIplt->getParent() == in.relaPlt->getParent() && | |
| 1228 | in.relaIplt->name == in.relaPlt->name) | |
| 1229 | size += in.relaIplt->getSize(); | |
| 1230 | return size; | |
| 1268 | 1231 | } |
| 1269 | 1232 | |
| 1270 | 1233 | // Add remaining entries to complete .dynamic contents. |
| 1271 | 1234 | template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { |
| 1235 | elf::Partition &part = getPartition(); | |
| 1236 | bool isMain = part.name.empty(); | |
| 1237 | ||
| 1238 | for (StringRef s : config->filterList) | |
| 1239 | addInt(DT_FILTER, part.dynStrTab->addString(s)); | |
| 1240 | for (StringRef s : config->auxiliaryList) | |
| 1241 | addInt(DT_AUXILIARY, part.dynStrTab->addString(s)); | |
| 1242 | ||
| 1243 | if (!config->rpath.empty()) | |
| 1244 | addInt(config->enableNewDtags ? DT_RUNPATH : DT_RPATH, | |
| 1245 | part.dynStrTab->addString(config->rpath)); | |
| 1246 | ||
| 1247 | for (SharedFile *file : sharedFiles) | |
| 1248 | if (file->isNeeded) | |
| 1249 | addInt(DT_NEEDED, part.dynStrTab->addString(file->soName)); | |
| 1250 | ||
| 1251 | if (isMain) { | |
| 1252 | if (!config->soName.empty()) | |
| 1253 | addInt(DT_SONAME, part.dynStrTab->addString(config->soName)); | |
| 1254 | } else { | |
| 1255 | if (!config->soName.empty()) | |
| 1256 | addInt(DT_NEEDED, part.dynStrTab->addString(config->soName)); | |
| 1257 | addInt(DT_SONAME, part.dynStrTab->addString(part.name)); | |
| 1258 | } | |
| 1259 | ||
| 1272 | 1260 | // Set DT_FLAGS and DT_FLAGS_1. |
| 1273 | uint32_t DtFlags = 0; | |
| 1274 | uint32_t DtFlags1 = 0; | |
| 1275 | if (Config->Bsymbolic) | |
| 1276 | DtFlags |= DF_SYMBOLIC; | |
| 1277 | if (Config->ZGlobal) | |
| 1278 | DtFlags1 |= DF_1_GLOBAL; | |
| 1279 | if (Config->ZInitfirst) | |
| 1280 | DtFlags1 |= DF_1_INITFIRST; | |
| 1281 | if (Config->ZInterpose) | |
| 1282 | DtFlags1 |= DF_1_INTERPOSE; | |
| 1283 | if (Config->ZNodefaultlib) | |
| 1284 | DtFlags1 |= DF_1_NODEFLIB; | |
| 1285 | if (Config->ZNodelete) | |
| 1286 | DtFlags1 |= DF_1_NODELETE; | |
| 1287 | if (Config->ZNodlopen) | |
| 1288 | DtFlags1 |= DF_1_NOOPEN; | |
| 1289 | if (Config->ZNow) { | |
| 1290 | DtFlags |= DF_BIND_NOW; | |
| 1291 | DtFlags1 |= DF_1_NOW; | |
| 1292 | } | |
| 1293 | if (Config->ZOrigin) { | |
| 1294 | DtFlags |= DF_ORIGIN; | |
| 1295 | DtFlags1 |= DF_1_ORIGIN; | |
| 1296 | } | |
| 1297 | if (!Config->ZText) | |
| 1298 | DtFlags |= DF_TEXTREL; | |
| 1299 | ||
| 1300 | if (DtFlags) | |
| 1301 | addInt(DT_FLAGS, DtFlags); | |
| 1302 | if (DtFlags1) | |
| 1303 | addInt(DT_FLAGS_1, DtFlags1); | |
| 1261 | uint32_t dtFlags = 0; | |
| 1262 | uint32_t dtFlags1 = 0; | |
| 1263 | if (config->bsymbolic) | |
| 1264 | dtFlags |= DF_SYMBOLIC; | |
| 1265 | if (config->zGlobal) | |
| 1266 | dtFlags1 |= DF_1_GLOBAL; | |
| 1267 | if (config->zInitfirst) | |
| 1268 | dtFlags1 |= DF_1_INITFIRST; | |
| 1269 | if (config->zInterpose) | |
| 1270 | dtFlags1 |= DF_1_INTERPOSE; | |
| 1271 | if (config->zNodefaultlib) | |
| 1272 | dtFlags1 |= DF_1_NODEFLIB; | |
| 1273 | if (config->zNodelete) | |
| 1274 | dtFlags1 |= DF_1_NODELETE; | |
| 1275 | if (config->zNodlopen) | |
| 1276 | dtFlags1 |= DF_1_NOOPEN; | |
| 1277 | if (config->zNow) { | |
| 1278 | dtFlags |= DF_BIND_NOW; | |
| 1279 | dtFlags1 |= DF_1_NOW; | |
| 1280 | } | |
| 1281 | if (config->zOrigin) { | |
| 1282 | dtFlags |= DF_ORIGIN; | |
| 1283 | dtFlags1 |= DF_1_ORIGIN; | |
| 1284 | } | |
| 1285 | if (!config->zText) | |
| 1286 | dtFlags |= DF_TEXTREL; | |
| 1287 | if (config->hasStaticTlsModel) | |
| 1288 | dtFlags |= DF_STATIC_TLS; | |
| 1289 | ||
| 1290 | if (dtFlags) | |
| 1291 | addInt(DT_FLAGS, dtFlags); | |
| 1292 | if (dtFlags1) | |
| 1293 | addInt(DT_FLAGS_1, dtFlags1); | |
| 1304 | 1294 | |
| 1305 | 1295 | // DT_DEBUG is a pointer to debug informaion used by debuggers at runtime. We |
| 1306 | 1296 | // need it for each process, so we don't write it for DSOs. The loader writes |
| ... | ... | @@ -1310,268 +1300,287 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { |
| 1310 | 1300 | // systems (currently only Fuchsia OS) provide other means to give the |
| 1311 | 1301 | // debugger this information. Such systems may choose make .dynamic read-only. |
| 1312 | 1302 | // If the target is such a system (used -z rodynamic) don't write DT_DEBUG. |
| 1313 | if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic) | |
| 1303 | if (!config->shared && !config->relocatable && !config->zRodynamic) | |
| 1314 | 1304 | addInt(DT_DEBUG, 0); |
| 1315 | 1305 | |
| 1316 | if (OutputSection *Sec = In.DynStrTab->getParent()) | |
| 1317 | this->Link = Sec->SectionIndex; | |
| 1306 | if (OutputSection *sec = part.dynStrTab->getParent()) | |
| 1307 | this->link = sec->sectionIndex; | |
| 1318 | 1308 | |
| 1319 | if (!In.RelaDyn->empty()) { | |
| 1320 | addInSec(In.RelaDyn->DynamicTag, In.RelaDyn); | |
| 1321 | addSize(In.RelaDyn->SizeDynamicTag, In.RelaDyn->getParent()); | |
| 1309 | if (part.relaDyn->isNeeded()) { | |
| 1310 | addInSec(part.relaDyn->dynamicTag, part.relaDyn); | |
| 1311 | addSize(part.relaDyn->sizeDynamicTag, part.relaDyn->getParent()); | |
| 1322 | 1312 | |
| 1323 | bool IsRela = Config->IsRela; | |
| 1324 | addInt(IsRela ? DT_RELAENT : DT_RELENT, | |
| 1325 | IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel)); | |
| 1313 | bool isRela = config->isRela; | |
| 1314 | addInt(isRela ? DT_RELAENT : DT_RELENT, | |
| 1315 | isRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel)); | |
| 1326 | 1316 | |
| 1327 | 1317 | // MIPS dynamic loader does not support RELCOUNT tag. |
| 1328 | 1318 | // The problem is in the tight relation between dynamic |
| 1329 | 1319 | // relocations and GOT. So do not emit this tag on MIPS. |
| 1330 | if (Config->EMachine != EM_MIPS) { | |
| 1331 | size_t NumRelativeRels = In.RelaDyn->getRelativeRelocCount(); | |
| 1332 | if (Config->ZCombreloc && NumRelativeRels) | |
| 1333 | addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels); | |
| 1320 | if (config->emachine != EM_MIPS) { | |
| 1321 | size_t numRelativeRels = part.relaDyn->getRelativeRelocCount(); | |
| 1322 | if (config->zCombreloc && numRelativeRels) | |
| 1323 | addInt(isRela ? DT_RELACOUNT : DT_RELCOUNT, numRelativeRels); | |
| 1334 | 1324 | } |
| 1335 | 1325 | } |
| 1336 | if (In.RelrDyn && !In.RelrDyn->Relocs.empty()) { | |
| 1337 | addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR, | |
| 1338 | In.RelrDyn); | |
| 1339 | addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ, | |
| 1340 | In.RelrDyn->getParent()); | |
| 1341 | addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT, | |
| 1326 | if (part.relrDyn && !part.relrDyn->relocs.empty()) { | |
| 1327 | addInSec(config->useAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR, | |
| 1328 | part.relrDyn); | |
| 1329 | addSize(config->useAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ, | |
| 1330 | part.relrDyn->getParent()); | |
| 1331 | addInt(config->useAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT, | |
| 1342 | 1332 | sizeof(Elf_Relr)); |
| 1343 | 1333 | } |
| 1344 | 1334 | // .rel[a].plt section usually consists of two parts, containing plt and |
| 1345 | 1335 | // iplt relocations. It is possible to have only iplt relocations in the |
| 1346 | // output. In that case RelaPlt is empty and have zero offset, the same offset | |
| 1347 | // as RelaIplt have. And we still want to emit proper dynamic tags for that | |
| 1348 | // case, so here we always use RelaPlt as marker for the begining of | |
| 1336 | // output. In that case relaPlt is empty and have zero offset, the same offset | |
| 1337 | // as relaIplt has. And we still want to emit proper dynamic tags for that | |
| 1338 | // case, so here we always use relaPlt as marker for the begining of | |
| 1349 | 1339 | // .rel[a].plt section. |
| 1350 | if (In.RelaPlt->getParent()->Live) { | |
| 1351 | addInSec(DT_JMPREL, In.RelaPlt); | |
| 1352 | Entries.push_back({DT_PLTRELSZ, addPltRelSz}); | |
| 1353 | switch (Config->EMachine) { | |
| 1340 | if (isMain && (in.relaPlt->isNeeded() || in.relaIplt->isNeeded())) { | |
| 1341 | addInSec(DT_JMPREL, in.relaPlt); | |
| 1342 | entries.push_back({DT_PLTRELSZ, addPltRelSz}); | |
| 1343 | switch (config->emachine) { | |
| 1354 | 1344 | case EM_MIPS: |
| 1355 | addInSec(DT_MIPS_PLTGOT, In.GotPlt); | |
| 1345 | addInSec(DT_MIPS_PLTGOT, in.gotPlt); | |
| 1356 | 1346 | break; |
| 1357 | 1347 | case EM_SPARCV9: |
| 1358 | addInSec(DT_PLTGOT, In.Plt); | |
| 1348 | addInSec(DT_PLTGOT, in.plt); | |
| 1359 | 1349 | break; |
| 1360 | 1350 | default: |
| 1361 | addInSec(DT_PLTGOT, In.GotPlt); | |
| 1351 | addInSec(DT_PLTGOT, in.gotPlt); | |
| 1362 | 1352 | break; |
| 1363 | 1353 | } |
| 1364 | addInt(DT_PLTREL, Config->IsRela ? DT_RELA : DT_REL); | |
| 1354 | addInt(DT_PLTREL, config->isRela ? DT_RELA : DT_REL); | |
| 1355 | } | |
| 1356 | ||
| 1357 | if (config->emachine == EM_AARCH64) { | |
| 1358 | if (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) | |
| 1359 | addInt(DT_AARCH64_BTI_PLT, 0); | |
| 1360 | if (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_PAC) | |
| 1361 | addInt(DT_AARCH64_PAC_PLT, 0); | |
| 1365 | 1362 | } |
| 1366 | 1363 | |
| 1367 | addInSec(DT_SYMTAB, In.DynSymTab); | |
| 1364 | addInSec(DT_SYMTAB, part.dynSymTab); | |
| 1368 | 1365 | addInt(DT_SYMENT, sizeof(Elf_Sym)); |
| 1369 | addInSec(DT_STRTAB, In.DynStrTab); | |
| 1370 | addInt(DT_STRSZ, In.DynStrTab->getSize()); | |
| 1371 | if (!Config->ZText) | |
| 1366 | addInSec(DT_STRTAB, part.dynStrTab); | |
| 1367 | addInt(DT_STRSZ, part.dynStrTab->getSize()); | |
| 1368 | if (!config->zText) | |
| 1372 | 1369 | addInt(DT_TEXTREL, 0); |
| 1373 | if (In.GnuHashTab) | |
| 1374 | addInSec(DT_GNU_HASH, In.GnuHashTab); | |
| 1375 | if (In.HashTab) | |
| 1376 | addInSec(DT_HASH, In.HashTab); | |
| 1377 | ||
| 1378 | if (Out::PreinitArray) { | |
| 1379 | addOutSec(DT_PREINIT_ARRAY, Out::PreinitArray); | |
| 1380 | addSize(DT_PREINIT_ARRAYSZ, Out::PreinitArray); | |
| 1381 | } | |
| 1382 | if (Out::InitArray) { | |
| 1383 | addOutSec(DT_INIT_ARRAY, Out::InitArray); | |
| 1384 | addSize(DT_INIT_ARRAYSZ, Out::InitArray); | |
| 1385 | } | |
| 1386 | if (Out::FiniArray) { | |
| 1387 | addOutSec(DT_FINI_ARRAY, Out::FiniArray); | |
| 1388 | addSize(DT_FINI_ARRAYSZ, Out::FiniArray); | |
| 1389 | } | |
| 1390 | ||
| 1391 | if (Symbol *B = Symtab->find(Config->Init)) | |
| 1392 | if (B->isDefined()) | |
| 1393 | addSym(DT_INIT, B); | |
| 1394 | if (Symbol *B = Symtab->find(Config->Fini)) | |
| 1395 | if (B->isDefined()) | |
| 1396 | addSym(DT_FINI, B); | |
| 1397 | ||
| 1398 | bool HasVerNeed = InX<ELFT>::VerNeed->getNeedNum() != 0; | |
| 1399 | if (HasVerNeed || In.VerDef) | |
| 1400 | addInSec(DT_VERSYM, InX<ELFT>::VerSym); | |
| 1401 | if (In.VerDef) { | |
| 1402 | addInSec(DT_VERDEF, In.VerDef); | |
| 1370 | if (part.gnuHashTab) | |
| 1371 | addInSec(DT_GNU_HASH, part.gnuHashTab); | |
| 1372 | if (part.hashTab) | |
| 1373 | addInSec(DT_HASH, part.hashTab); | |
| 1374 | ||
| 1375 | if (isMain) { | |
| 1376 | if (Out::preinitArray) { | |
| 1377 | addOutSec(DT_PREINIT_ARRAY, Out::preinitArray); | |
| 1378 | addSize(DT_PREINIT_ARRAYSZ, Out::preinitArray); | |
| 1379 | } | |
| 1380 | if (Out::initArray) { | |
| 1381 | addOutSec(DT_INIT_ARRAY, Out::initArray); | |
| 1382 | addSize(DT_INIT_ARRAYSZ, Out::initArray); | |
| 1383 | } | |
| 1384 | if (Out::finiArray) { | |
| 1385 | addOutSec(DT_FINI_ARRAY, Out::finiArray); | |
| 1386 | addSize(DT_FINI_ARRAYSZ, Out::finiArray); | |
| 1387 | } | |
| 1388 | ||
| 1389 | if (Symbol *b = symtab->find(config->init)) | |
| 1390 | if (b->isDefined()) | |
| 1391 | addSym(DT_INIT, b); | |
| 1392 | if (Symbol *b = symtab->find(config->fini)) | |
| 1393 | if (b->isDefined()) | |
| 1394 | addSym(DT_FINI, b); | |
| 1395 | } | |
| 1396 | ||
| 1397 | bool hasVerNeed = SharedFile::vernauxNum != 0; | |
| 1398 | if (hasVerNeed || part.verDef) | |
| 1399 | addInSec(DT_VERSYM, part.verSym); | |
| 1400 | if (part.verDef) { | |
| 1401 | addInSec(DT_VERDEF, part.verDef); | |
| 1403 | 1402 | addInt(DT_VERDEFNUM, getVerDefNum()); |
| 1404 | 1403 | } |
| 1405 | if (HasVerNeed) { | |
| 1406 | addInSec(DT_VERNEED, InX<ELFT>::VerNeed); | |
| 1407 | addInt(DT_VERNEEDNUM, InX<ELFT>::VerNeed->getNeedNum()); | |
| 1404 | if (hasVerNeed) { | |
| 1405 | addInSec(DT_VERNEED, part.verNeed); | |
| 1406 | unsigned needNum = 0; | |
| 1407 | for (SharedFile *f : sharedFiles) | |
| 1408 | if (!f->vernauxs.empty()) | |
| 1409 | ++needNum; | |
| 1410 | addInt(DT_VERNEEDNUM, needNum); | |
| 1408 | 1411 | } |
| 1409 | 1412 | |
| 1410 | if (Config->EMachine == EM_MIPS) { | |
| 1413 | if (config->emachine == EM_MIPS) { | |
| 1411 | 1414 | addInt(DT_MIPS_RLD_VERSION, 1); |
| 1412 | 1415 | addInt(DT_MIPS_FLAGS, RHF_NOTPOT); |
| 1413 | addInt(DT_MIPS_BASE_ADDRESS, Target->getImageBase()); | |
| 1414 | addInt(DT_MIPS_SYMTABNO, In.DynSymTab->getNumSymbols()); | |
| 1416 | addInt(DT_MIPS_BASE_ADDRESS, target->getImageBase()); | |
| 1417 | addInt(DT_MIPS_SYMTABNO, part.dynSymTab->getNumSymbols()); | |
| 1415 | 1418 | |
| 1416 | add(DT_MIPS_LOCAL_GOTNO, [] { return In.MipsGot->getLocalEntriesNum(); }); | |
| 1419 | add(DT_MIPS_LOCAL_GOTNO, [] { return in.mipsGot->getLocalEntriesNum(); }); | |
| 1417 | 1420 | |
| 1418 | if (const Symbol *B = In.MipsGot->getFirstGlobalEntry()) | |
| 1419 | addInt(DT_MIPS_GOTSYM, B->DynsymIndex); | |
| 1421 | if (const Symbol *b = in.mipsGot->getFirstGlobalEntry()) | |
| 1422 | addInt(DT_MIPS_GOTSYM, b->dynsymIndex); | |
| 1420 | 1423 | else |
| 1421 | addInt(DT_MIPS_GOTSYM, In.DynSymTab->getNumSymbols()); | |
| 1422 | addInSec(DT_PLTGOT, In.MipsGot); | |
| 1423 | if (In.MipsRldMap) { | |
| 1424 | if (!Config->Pie) | |
| 1425 | addInSec(DT_MIPS_RLD_MAP, In.MipsRldMap); | |
| 1424 | addInt(DT_MIPS_GOTSYM, part.dynSymTab->getNumSymbols()); | |
| 1425 | addInSec(DT_PLTGOT, in.mipsGot); | |
| 1426 | if (in.mipsRldMap) { | |
| 1427 | if (!config->pie) | |
| 1428 | addInSec(DT_MIPS_RLD_MAP, in.mipsRldMap); | |
| 1426 | 1429 | // Store the offset to the .rld_map section |
| 1427 | 1430 | // relative to the address of the tag. |
| 1428 | addInSecRelative(DT_MIPS_RLD_MAP_REL, In.MipsRldMap); | |
| 1431 | addInSecRelative(DT_MIPS_RLD_MAP_REL, in.mipsRldMap); | |
| 1429 | 1432 | } |
| 1430 | 1433 | } |
| 1431 | 1434 | |
| 1435 | // DT_PPC_GOT indicates to glibc Secure PLT is used. If DT_PPC_GOT is absent, | |
| 1436 | // glibc assumes the old-style BSS PLT layout which we don't support. | |
| 1437 | if (config->emachine == EM_PPC) | |
| 1438 | add(DT_PPC_GOT, [] { return in.got->getVA(); }); | |
| 1439 | ||
| 1432 | 1440 | // Glink dynamic tag is required by the V2 abi if the plt section isn't empty. |
| 1433 | if (Config->EMachine == EM_PPC64 && !In.Plt->empty()) { | |
| 1441 | if (config->emachine == EM_PPC64 && in.plt->isNeeded()) { | |
| 1434 | 1442 | // The Glink tag points to 32 bytes before the first lazy symbol resolution |
| 1435 | 1443 | // stub, which starts directly after the header. |
| 1436 | Entries.push_back({DT_PPC64_GLINK, [=] { | |
| 1437 | unsigned Offset = Target->PltHeaderSize - 32; | |
| 1438 | return In.Plt->getVA(0) + Offset; | |
| 1444 | entries.push_back({DT_PPC64_GLINK, [=] { | |
| 1445 | unsigned offset = target->pltHeaderSize - 32; | |
| 1446 | return in.plt->getVA(0) + offset; | |
| 1439 | 1447 | }}); |
| 1440 | 1448 | } |
| 1441 | 1449 | |
| 1442 | 1450 | addInt(DT_NULL, 0); |
| 1443 | 1451 | |
| 1444 | getParent()->Link = this->Link; | |
| 1445 | this->Size = Entries.size() * this->Entsize; | |
| 1452 | getParent()->link = this->link; | |
| 1453 | this->size = entries.size() * this->entsize; | |
| 1446 | 1454 | } |
| 1447 | 1455 | |
| 1448 | template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) { | |
| 1449 | auto *P = reinterpret_cast<Elf_Dyn *>(Buf); | |
| 1456 | template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *buf) { | |
| 1457 | auto *p = reinterpret_cast<Elf_Dyn *>(buf); | |
| 1450 | 1458 | |
| 1451 | for (std::pair<int32_t, std::function<uint64_t()>> &KV : Entries) { | |
| 1452 | P->d_tag = KV.first; | |
| 1453 | P->d_un.d_val = KV.second(); | |
| 1454 | ++P; | |
| 1459 | for (std::pair<int32_t, std::function<uint64_t()>> &kv : entries) { | |
| 1460 | p->d_tag = kv.first; | |
| 1461 | p->d_un.d_val = kv.second(); | |
| 1462 | ++p; | |
| 1455 | 1463 | } |
| 1456 | 1464 | } |
| 1457 | 1465 | |
| 1458 | 1466 | uint64_t DynamicReloc::getOffset() const { |
| 1459 | return InputSec->getVA(OffsetInSec); | |
| 1467 | return inputSec->getVA(offsetInSec); | |
| 1460 | 1468 | } |
| 1461 | 1469 | |
| 1462 | 1470 | int64_t DynamicReloc::computeAddend() const { |
| 1463 | if (UseSymVA) | |
| 1464 | return Sym->getVA(Addend); | |
| 1465 | if (!OutputSec) | |
| 1466 | return Addend; | |
| 1471 | if (useSymVA) | |
| 1472 | return sym->getVA(addend); | |
| 1473 | if (!outputSec) | |
| 1474 | return addend; | |
| 1467 | 1475 | // See the comment in the DynamicReloc ctor. |
| 1468 | return getMipsPageAddr(OutputSec->Addr) + Addend; | |
| 1476 | return getMipsPageAddr(outputSec->addr) + addend; | |
| 1469 | 1477 | } |
| 1470 | 1478 | |
| 1471 | uint32_t DynamicReloc::getSymIndex() const { | |
| 1472 | if (Sym && !UseSymVA) | |
| 1473 | return Sym->DynsymIndex; | |
| 1479 | uint32_t DynamicReloc::getSymIndex(SymbolTableBaseSection *symTab) const { | |
| 1480 | if (sym && !useSymVA) | |
| 1481 | return symTab->getSymbolIndex(sym); | |
| 1474 | 1482 | return 0; |
| 1475 | 1483 | } |
| 1476 | 1484 | |
| 1477 | RelocationBaseSection::RelocationBaseSection(StringRef Name, uint32_t Type, | |
| 1478 | int32_t DynamicTag, | |
| 1479 | int32_t SizeDynamicTag) | |
| 1480 | : SyntheticSection(SHF_ALLOC, Type, Config->Wordsize, Name), | |
| 1481 | DynamicTag(DynamicTag), SizeDynamicTag(SizeDynamicTag) {} | |
| 1485 | RelocationBaseSection::RelocationBaseSection(StringRef name, uint32_t type, | |
| 1486 | int32_t dynamicTag, | |
| 1487 | int32_t sizeDynamicTag) | |
| 1488 | : SyntheticSection(SHF_ALLOC, type, config->wordsize, name), | |
| 1489 | dynamicTag(dynamicTag), sizeDynamicTag(sizeDynamicTag) {} | |
| 1482 | 1490 | |
| 1483 | void RelocationBaseSection::addReloc(RelType DynType, InputSectionBase *IS, | |
| 1484 | uint64_t OffsetInSec, Symbol *Sym) { | |
| 1485 | addReloc({DynType, IS, OffsetInSec, false, Sym, 0}); | |
| 1491 | void RelocationBaseSection::addReloc(RelType dynType, InputSectionBase *isec, | |
| 1492 | uint64_t offsetInSec, Symbol *sym) { | |
| 1493 | addReloc({dynType, isec, offsetInSec, false, sym, 0}); | |
| 1486 | 1494 | } |
| 1487 | 1495 | |
| 1488 | void RelocationBaseSection::addReloc(RelType DynType, | |
| 1489 | InputSectionBase *InputSec, | |
| 1490 | uint64_t OffsetInSec, Symbol *Sym, | |
| 1491 | int64_t Addend, RelExpr Expr, | |
| 1492 | RelType Type) { | |
| 1496 | void RelocationBaseSection::addReloc(RelType dynType, | |
| 1497 | InputSectionBase *inputSec, | |
| 1498 | uint64_t offsetInSec, Symbol *sym, | |
| 1499 | int64_t addend, RelExpr expr, | |
| 1500 | RelType type) { | |
| 1493 | 1501 | // Write the addends to the relocated address if required. We skip |
| 1494 | 1502 | // it if the written value would be zero. |
| 1495 | if (Config->WriteAddends && (Expr != R_ADDEND || Addend != 0)) | |
| 1496 | InputSec->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym}); | |
| 1497 | addReloc({DynType, InputSec, OffsetInSec, Expr != R_ADDEND, Sym, Addend}); | |
| 1503 | if (config->writeAddends && (expr != R_ADDEND || addend != 0)) | |
| 1504 | inputSec->relocations.push_back({expr, type, offsetInSec, addend, sym}); | |
| 1505 | addReloc({dynType, inputSec, offsetInSec, expr != R_ADDEND, sym, addend}); | |
| 1498 | 1506 | } |
| 1499 | 1507 | |
| 1500 | void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) { | |
| 1501 | if (Reloc.Type == Target->RelativeRel) | |
| 1502 | ++NumRelativeRelocs; | |
| 1503 | Relocs.push_back(Reloc); | |
| 1508 | void RelocationBaseSection::addReloc(const DynamicReloc &reloc) { | |
| 1509 | if (reloc.type == target->relativeRel) | |
| 1510 | ++numRelativeRelocs; | |
| 1511 | relocs.push_back(reloc); | |
| 1504 | 1512 | } |
| 1505 | 1513 | |
| 1506 | 1514 | void RelocationBaseSection::finalizeContents() { |
| 1515 | SymbolTableBaseSection *symTab = getPartition().dynSymTab; | |
| 1516 | ||
| 1507 | 1517 | // When linking glibc statically, .rel{,a}.plt contains R_*_IRELATIVE |
| 1508 | 1518 | // relocations due to IFUNC (e.g. strcpy). sh_link will be set to 0 in that |
| 1509 | 1519 | // case. |
| 1510 | InputSection *SymTab = Config->Relocatable ? In.SymTab : In.DynSymTab; | |
| 1511 | if (SymTab && SymTab->getParent()) | |
| 1512 | getParent()->Link = SymTab->getParent()->SectionIndex; | |
| 1520 | if (symTab && symTab->getParent()) | |
| 1521 | getParent()->link = symTab->getParent()->sectionIndex; | |
| 1513 | 1522 | else |
| 1514 | getParent()->Link = 0; | |
| 1523 | getParent()->link = 0; | |
| 1515 | 1524 | |
| 1516 | if (In.RelaPlt == this) | |
| 1517 | getParent()->Info = In.GotPlt->getParent()->SectionIndex; | |
| 1518 | if (In.RelaIplt == this) | |
| 1519 | getParent()->Info = In.IgotPlt->getParent()->SectionIndex; | |
| 1525 | if (in.relaPlt == this) | |
| 1526 | getParent()->info = in.gotPlt->getParent()->sectionIndex; | |
| 1527 | if (in.relaIplt == this) | |
| 1528 | getParent()->info = in.igotPlt->getParent()->sectionIndex; | |
| 1520 | 1529 | } |
| 1521 | 1530 | |
| 1522 | 1531 | RelrBaseSection::RelrBaseSection() |
| 1523 | 1532 | : SyntheticSection(SHF_ALLOC, |
| 1524 | Config->UseAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR, | |
| 1525 | Config->Wordsize, ".relr.dyn") {} | |
| 1533 | config->useAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR, | |
| 1534 | config->wordsize, ".relr.dyn") {} | |
| 1526 | 1535 | |
| 1527 | 1536 | template <class ELFT> |
| 1528 | static void encodeDynamicReloc(typename ELFT::Rela *P, | |
| 1529 | const DynamicReloc &Rel) { | |
| 1530 | if (Config->IsRela) | |
| 1531 | P->r_addend = Rel.computeAddend(); | |
| 1532 | P->r_offset = Rel.getOffset(); | |
| 1533 | P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL); | |
| 1537 | static void encodeDynamicReloc(SymbolTableBaseSection *symTab, | |
| 1538 | typename ELFT::Rela *p, | |
| 1539 | const DynamicReloc &rel) { | |
| 1540 | if (config->isRela) | |
| 1541 | p->r_addend = rel.computeAddend(); | |
| 1542 | p->r_offset = rel.getOffset(); | |
| 1543 | p->setSymbolAndType(rel.getSymIndex(symTab), rel.type, config->isMips64EL); | |
| 1534 | 1544 | } |
| 1535 | 1545 | |
| 1536 | 1546 | template <class ELFT> |
| 1537 | RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort) | |
| 1538 | : RelocationBaseSection(Name, Config->IsRela ? SHT_RELA : SHT_REL, | |
| 1539 | Config->IsRela ? DT_RELA : DT_REL, | |
| 1540 | Config->IsRela ? DT_RELASZ : DT_RELSZ), | |
| 1541 | Sort(Sort) { | |
| 1542 | this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); | |
| 1547 | RelocationSection<ELFT>::RelocationSection(StringRef name, bool sort) | |
| 1548 | : RelocationBaseSection(name, config->isRela ? SHT_RELA : SHT_REL, | |
| 1549 | config->isRela ? DT_RELA : DT_REL, | |
| 1550 | config->isRela ? DT_RELASZ : DT_RELSZ), | |
| 1551 | sort(sort) { | |
| 1552 | this->entsize = config->isRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); | |
| 1543 | 1553 | } |
| 1544 | 1554 | |
| 1545 | static bool compRelocations(const DynamicReloc &A, const DynamicReloc &B) { | |
| 1546 | bool AIsRel = A.Type == Target->RelativeRel; | |
| 1547 | bool BIsRel = B.Type == Target->RelativeRel; | |
| 1548 | if (AIsRel != BIsRel) | |
| 1549 | return AIsRel; | |
| 1550 | return A.getSymIndex() < B.getSymIndex(); | |
| 1551 | } | |
| 1555 | template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *buf) { | |
| 1556 | SymbolTableBaseSection *symTab = getPartition().dynSymTab; | |
| 1552 | 1557 | |
| 1553 | template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) { | |
| 1554 | if (Sort) | |
| 1555 | std::stable_sort(Relocs.begin(), Relocs.end(), compRelocations); | |
| 1558 | // Sort by (!IsRelative,SymIndex,r_offset). DT_REL[A]COUNT requires us to | |
| 1559 | // place R_*_RELATIVE first. SymIndex is to improve locality, while r_offset | |
| 1560 | // is to make results easier to read. | |
| 1561 | if (sort) | |
| 1562 | llvm::stable_sort( | |
| 1563 | relocs, [&](const DynamicReloc &a, const DynamicReloc &b) { | |
| 1564 | return std::make_tuple(a.type != target->relativeRel, | |
| 1565 | a.getSymIndex(symTab), a.getOffset()) < | |
| 1566 | std::make_tuple(b.type != target->relativeRel, | |
| 1567 | b.getSymIndex(symTab), b.getOffset()); | |
| 1568 | }); | |
| 1556 | 1569 | |
| 1557 | for (const DynamicReloc &Rel : Relocs) { | |
| 1558 | encodeDynamicReloc<ELFT>(reinterpret_cast<Elf_Rela *>(Buf), Rel); | |
| 1559 | Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); | |
| 1570 | for (const DynamicReloc &rel : relocs) { | |
| 1571 | encodeDynamicReloc<ELFT>(symTab, reinterpret_cast<Elf_Rela *>(buf), rel); | |
| 1572 | buf += config->isRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); | |
| 1560 | 1573 | } |
| 1561 | 1574 | } |
| 1562 | 1575 | |
| 1563 | template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() { | |
| 1564 | return this->Entsize * Relocs.size(); | |
| 1565 | } | |
| 1566 | ||
| 1567 | 1576 | template <class ELFT> |
| 1568 | 1577 | AndroidPackedRelocationSection<ELFT>::AndroidPackedRelocationSection( |
| 1569 | StringRef Name) | |
| 1578 | StringRef name) | |
| 1570 | 1579 | : RelocationBaseSection( |
| 1571 | Name, Config->IsRela ? SHT_ANDROID_RELA : SHT_ANDROID_REL, | |
| 1572 | Config->IsRela ? DT_ANDROID_RELA : DT_ANDROID_REL, | |
| 1573 | Config->IsRela ? DT_ANDROID_RELASZ : DT_ANDROID_RELSZ) { | |
| 1574 | this->Entsize = 1; | |
| 1580 | name, config->isRela ? SHT_ANDROID_RELA : SHT_ANDROID_REL, | |
| 1581 | config->isRela ? DT_ANDROID_RELA : DT_ANDROID_REL, | |
| 1582 | config->isRela ? DT_ANDROID_RELASZ : DT_ANDROID_RELSZ) { | |
| 1583 | this->entsize = 1; | |
| 1575 | 1584 | } |
| 1576 | 1585 | |
| 1577 | 1586 | template <class ELFT> |
| ... | ... | @@ -1621,32 +1630,32 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() { |
| 1621 | 1630 | // RELOCATION_GROUPED_BY_ADDEND_FLAG is not set) the r_addend delta for |
| 1622 | 1631 | // this relocation. |
| 1623 | 1632 | |
| 1624 | size_t OldSize = RelocData.size(); | |
| 1633 | size_t oldSize = relocData.size(); | |
| 1625 | 1634 | |
| 1626 | RelocData = {'A', 'P', 'S', '2'}; | |
| 1627 | raw_svector_ostream OS(RelocData); | |
| 1628 | auto Add = [&](int64_t V) { encodeSLEB128(V, OS); }; | |
| 1635 | relocData = {'A', 'P', 'S', '2'}; | |
| 1636 | raw_svector_ostream os(relocData); | |
| 1637 | auto add = [&](int64_t v) { encodeSLEB128(v, os); }; | |
| 1629 | 1638 | |
| 1630 | 1639 | // The format header includes the number of relocations and the initial |
| 1631 | 1640 | // offset (we set this to zero because the first relocation group will |
| 1632 | 1641 | // perform the initial adjustment). |
| 1633 | Add(Relocs.size()); | |
| 1634 | Add(0); | |
| 1642 | add(relocs.size()); | |
| 1643 | add(0); | |
| 1635 | 1644 | |
| 1636 | std::vector<Elf_Rela> Relatives, NonRelatives; | |
| 1645 | std::vector<Elf_Rela> relatives, nonRelatives; | |
| 1637 | 1646 | |
| 1638 | for (const DynamicReloc &Rel : Relocs) { | |
| 1639 | Elf_Rela R; | |
| 1640 | encodeDynamicReloc<ELFT>(&R, Rel); | |
| 1647 | for (const DynamicReloc &rel : relocs) { | |
| 1648 | Elf_Rela r; | |
| 1649 | encodeDynamicReloc<ELFT>(getPartition().dynSymTab, &r, rel); | |
| 1641 | 1650 | |
| 1642 | if (R.getType(Config->IsMips64EL) == Target->RelativeRel) | |
| 1643 | Relatives.push_back(R); | |
| 1651 | if (r.getType(config->isMips64EL) == target->relativeRel) | |
| 1652 | relatives.push_back(r); | |
| 1644 | 1653 | else |
| 1645 | NonRelatives.push_back(R); | |
| 1654 | nonRelatives.push_back(r); | |
| 1646 | 1655 | } |
| 1647 | 1656 | |
| 1648 | llvm::sort(Relatives, [](const Elf_Rel &A, const Elf_Rel &B) { | |
| 1649 | return A.r_offset < B.r_offset; | |
| 1657 | llvm::sort(relatives, [](const Elf_Rel &a, const Elf_Rel &b) { | |
| 1658 | return a.r_offset < b.r_offset; | |
| 1650 | 1659 | }); |
| 1651 | 1660 | |
| 1652 | 1661 | // Try to find groups of relative relocations which are spaced one word |
| ... | ... | @@ -1655,108 +1664,108 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() { |
| 1655 | 1664 | // encoding, but each group will cost 7 bytes in addition to the offset from |
| 1656 | 1665 | // the previous group, so it is only profitable to do this for groups of |
| 1657 | 1666 | // size 8 or larger. |
| 1658 | std::vector<Elf_Rela> UngroupedRelatives; | |
| 1659 | std::vector<std::vector<Elf_Rela>> RelativeGroups; | |
| 1660 | for (auto I = Relatives.begin(), E = Relatives.end(); I != E;) { | |
| 1661 | std::vector<Elf_Rela> Group; | |
| 1667 | std::vector<Elf_Rela> ungroupedRelatives; | |
| 1668 | std::vector<std::vector<Elf_Rela>> relativeGroups; | |
| 1669 | for (auto i = relatives.begin(), e = relatives.end(); i != e;) { | |
| 1670 | std::vector<Elf_Rela> group; | |
| 1662 | 1671 | do { |
| 1663 | Group.push_back(*I++); | |
| 1664 | } while (I != E && (I - 1)->r_offset + Config->Wordsize == I->r_offset); | |
| 1672 | group.push_back(*i++); | |
| 1673 | } while (i != e && (i - 1)->r_offset + config->wordsize == i->r_offset); | |
| 1665 | 1674 | |
| 1666 | if (Group.size() < 8) | |
| 1667 | UngroupedRelatives.insert(UngroupedRelatives.end(), Group.begin(), | |
| 1668 | Group.end()); | |
| 1675 | if (group.size() < 8) | |
| 1676 | ungroupedRelatives.insert(ungroupedRelatives.end(), group.begin(), | |
| 1677 | group.end()); | |
| 1669 | 1678 | else |
| 1670 | RelativeGroups.emplace_back(std::move(Group)); | |
| 1679 | relativeGroups.emplace_back(std::move(group)); | |
| 1671 | 1680 | } |
| 1672 | 1681 | |
| 1673 | unsigned HasAddendIfRela = | |
| 1674 | Config->IsRela ? RELOCATION_GROUP_HAS_ADDEND_FLAG : 0; | |
| 1682 | unsigned hasAddendIfRela = | |
| 1683 | config->isRela ? RELOCATION_GROUP_HAS_ADDEND_FLAG : 0; | |
| 1675 | 1684 | |
| 1676 | uint64_t Offset = 0; | |
| 1677 | uint64_t Addend = 0; | |
| 1685 | uint64_t offset = 0; | |
| 1686 | uint64_t addend = 0; | |
| 1678 | 1687 | |
| 1679 | 1688 | // Emit the run-length encoding for the groups of adjacent relative |
| 1680 | 1689 | // relocations. Each group is represented using two groups in the packed |
| 1681 | 1690 | // format. The first is used to set the current offset to the start of the |
| 1682 | 1691 | // group (and also encodes the first relocation), and the second encodes the |
| 1683 | 1692 | // remaining relocations. |
| 1684 | for (std::vector<Elf_Rela> &G : RelativeGroups) { | |
| 1693 | for (std::vector<Elf_Rela> &g : relativeGroups) { | |
| 1685 | 1694 | // The first relocation in the group. |
| 1686 | Add(1); | |
| 1687 | Add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG | | |
| 1688 | RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela); | |
| 1689 | Add(G[0].r_offset - Offset); | |
| 1690 | Add(Target->RelativeRel); | |
| 1691 | if (Config->IsRela) { | |
| 1692 | Add(G[0].r_addend - Addend); | |
| 1693 | Addend = G[0].r_addend; | |
| 1695 | add(1); | |
| 1696 | add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG | | |
| 1697 | RELOCATION_GROUPED_BY_INFO_FLAG | hasAddendIfRela); | |
| 1698 | add(g[0].r_offset - offset); | |
| 1699 | add(target->relativeRel); | |
| 1700 | if (config->isRela) { | |
| 1701 | add(g[0].r_addend - addend); | |
| 1702 | addend = g[0].r_addend; | |
| 1694 | 1703 | } |
| 1695 | 1704 | |
| 1696 | 1705 | // The remaining relocations. |
| 1697 | Add(G.size() - 1); | |
| 1698 | Add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG | | |
| 1699 | RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela); | |
| 1700 | Add(Config->Wordsize); | |
| 1701 | Add(Target->RelativeRel); | |
| 1702 | if (Config->IsRela) { | |
| 1703 | for (auto I = G.begin() + 1, E = G.end(); I != E; ++I) { | |
| 1704 | Add(I->r_addend - Addend); | |
| 1705 | Addend = I->r_addend; | |
| 1706 | add(g.size() - 1); | |
| 1707 | add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG | | |
| 1708 | RELOCATION_GROUPED_BY_INFO_FLAG | hasAddendIfRela); | |
| 1709 | add(config->wordsize); | |
| 1710 | add(target->relativeRel); | |
| 1711 | if (config->isRela) { | |
| 1712 | for (auto i = g.begin() + 1, e = g.end(); i != e; ++i) { | |
| 1713 | add(i->r_addend - addend); | |
| 1714 | addend = i->r_addend; | |
| 1706 | 1715 | } |
| 1707 | 1716 | } |
| 1708 | 1717 | |
| 1709 | Offset = G.back().r_offset; | |
| 1718 | offset = g.back().r_offset; | |
| 1710 | 1719 | } |
| 1711 | 1720 | |
| 1712 | 1721 | // Now the ungrouped relatives. |
| 1713 | if (!UngroupedRelatives.empty()) { | |
| 1714 | Add(UngroupedRelatives.size()); | |
| 1715 | Add(RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela); | |
| 1716 | Add(Target->RelativeRel); | |
| 1717 | for (Elf_Rela &R : UngroupedRelatives) { | |
| 1718 | Add(R.r_offset - Offset); | |
| 1719 | Offset = R.r_offset; | |
| 1720 | if (Config->IsRela) { | |
| 1721 | Add(R.r_addend - Addend); | |
| 1722 | Addend = R.r_addend; | |
| 1722 | if (!ungroupedRelatives.empty()) { | |
| 1723 | add(ungroupedRelatives.size()); | |
| 1724 | add(RELOCATION_GROUPED_BY_INFO_FLAG | hasAddendIfRela); | |
| 1725 | add(target->relativeRel); | |
| 1726 | for (Elf_Rela &r : ungroupedRelatives) { | |
| 1727 | add(r.r_offset - offset); | |
| 1728 | offset = r.r_offset; | |
| 1729 | if (config->isRela) { | |
| 1730 | add(r.r_addend - addend); | |
| 1731 | addend = r.r_addend; | |
| 1723 | 1732 | } |
| 1724 | 1733 | } |
| 1725 | 1734 | } |
| 1726 | 1735 | |
| 1727 | 1736 | // Finally the non-relative relocations. |
| 1728 | llvm::sort(NonRelatives, [](const Elf_Rela &A, const Elf_Rela &B) { | |
| 1729 | return A.r_offset < B.r_offset; | |
| 1737 | llvm::sort(nonRelatives, [](const Elf_Rela &a, const Elf_Rela &b) { | |
| 1738 | return a.r_offset < b.r_offset; | |
| 1730 | 1739 | }); |
| 1731 | if (!NonRelatives.empty()) { | |
| 1732 | Add(NonRelatives.size()); | |
| 1733 | Add(HasAddendIfRela); | |
| 1734 | for (Elf_Rela &R : NonRelatives) { | |
| 1735 | Add(R.r_offset - Offset); | |
| 1736 | Offset = R.r_offset; | |
| 1737 | Add(R.r_info); | |
| 1738 | if (Config->IsRela) { | |
| 1739 | Add(R.r_addend - Addend); | |
| 1740 | Addend = R.r_addend; | |
| 1740 | if (!nonRelatives.empty()) { | |
| 1741 | add(nonRelatives.size()); | |
| 1742 | add(hasAddendIfRela); | |
| 1743 | for (Elf_Rela &r : nonRelatives) { | |
| 1744 | add(r.r_offset - offset); | |
| 1745 | offset = r.r_offset; | |
| 1746 | add(r.r_info); | |
| 1747 | if (config->isRela) { | |
| 1748 | add(r.r_addend - addend); | |
| 1749 | addend = r.r_addend; | |
| 1741 | 1750 | } |
| 1742 | 1751 | } |
| 1743 | 1752 | } |
| 1744 | 1753 | |
| 1745 | 1754 | // Don't allow the section to shrink; otherwise the size of the section can |
| 1746 | 1755 | // oscillate infinitely. |
| 1747 | if (RelocData.size() < OldSize) | |
| 1748 | RelocData.append(OldSize - RelocData.size(), 0); | |
| 1756 | if (relocData.size() < oldSize) | |
| 1757 | relocData.append(oldSize - relocData.size(), 0); | |
| 1749 | 1758 | |
| 1750 | 1759 | // Returns whether the section size changed. We need to keep recomputing both |
| 1751 | 1760 | // section layout and the contents of this section until the size converges |
| 1752 | 1761 | // because changing this section's size can affect section layout, which in |
| 1753 | 1762 | // turn can affect the sizes of the LEB-encoded integers stored in this |
| 1754 | 1763 | // section. |
| 1755 | return RelocData.size() != OldSize; | |
| 1764 | return relocData.size() != oldSize; | |
| 1756 | 1765 | } |
| 1757 | 1766 | |
| 1758 | 1767 | template <class ELFT> RelrSection<ELFT>::RelrSection() { |
| 1759 | this->Entsize = Config->Wordsize; | |
| 1768 | this->entsize = config->wordsize; | |
| 1760 | 1769 | } |
| 1761 | 1770 | |
| 1762 | 1771 | template <class ELFT> bool RelrSection<ELFT>::updateAllocSize() { |
| ... | ... | @@ -1790,90 +1799,90 @@ template <class ELFT> bool RelrSection<ELFT>::updateAllocSize() { |
| 1790 | 1799 | // even means address, odd means bitmap. |
| 1791 | 1800 | // 2. Just a simple list of addresses is a valid encoding. |
| 1792 | 1801 | |
| 1793 | size_t OldSize = RelrRelocs.size(); | |
| 1794 | RelrRelocs.clear(); | |
| 1802 | size_t oldSize = relrRelocs.size(); | |
| 1803 | relrRelocs.clear(); | |
| 1795 | 1804 | |
| 1796 | 1805 | // Same as Config->Wordsize but faster because this is a compile-time |
| 1797 | 1806 | // constant. |
| 1798 | const size_t Wordsize = sizeof(typename ELFT::uint); | |
| 1807 | const size_t wordsize = sizeof(typename ELFT::uint); | |
| 1799 | 1808 | |
| 1800 | 1809 | // Number of bits to use for the relocation offsets bitmap. |
| 1801 | 1810 | // Must be either 63 or 31. |
| 1802 | const size_t NBits = Wordsize * 8 - 1; | |
| 1811 | const size_t nBits = wordsize * 8 - 1; | |
| 1803 | 1812 | |
| 1804 | 1813 | // Get offsets for all relative relocations and sort them. |
| 1805 | std::vector<uint64_t> Offsets; | |
| 1806 | for (const RelativeReloc &Rel : Relocs) | |
| 1807 | Offsets.push_back(Rel.getOffset()); | |
| 1808 | llvm::sort(Offsets.begin(), Offsets.end()); | |
| 1814 | std::vector<uint64_t> offsets; | |
| 1815 | for (const RelativeReloc &rel : relocs) | |
| 1816 | offsets.push_back(rel.getOffset()); | |
| 1817 | llvm::sort(offsets); | |
| 1809 | 1818 | |
| 1810 | 1819 | // For each leading relocation, find following ones that can be folded |
| 1811 | 1820 | // as a bitmap and fold them. |
| 1812 | for (size_t I = 0, E = Offsets.size(); I < E;) { | |
| 1821 | for (size_t i = 0, e = offsets.size(); i < e;) { | |
| 1813 | 1822 | // Add a leading relocation. |
| 1814 | RelrRelocs.push_back(Elf_Relr(Offsets[I])); | |
| 1815 | uint64_t Base = Offsets[I] + Wordsize; | |
| 1816 | ++I; | |
| 1823 | relrRelocs.push_back(Elf_Relr(offsets[i])); | |
| 1824 | uint64_t base = offsets[i] + wordsize; | |
| 1825 | ++i; | |
| 1817 | 1826 | |
| 1818 | 1827 | // Find foldable relocations to construct bitmaps. |
| 1819 | while (I < E) { | |
| 1820 | uint64_t Bitmap = 0; | |
| 1828 | while (i < e) { | |
| 1829 | uint64_t bitmap = 0; | |
| 1821 | 1830 | |
| 1822 | while (I < E) { | |
| 1823 | uint64_t Delta = Offsets[I] - Base; | |
| 1831 | while (i < e) { | |
| 1832 | uint64_t delta = offsets[i] - base; | |
| 1824 | 1833 | |
| 1825 | 1834 | // If it is too far, it cannot be folded. |
| 1826 | if (Delta >= NBits * Wordsize) | |
| 1835 | if (delta >= nBits * wordsize) | |
| 1827 | 1836 | break; |
| 1828 | 1837 | |
| 1829 | 1838 | // If it is not a multiple of wordsize away, it cannot be folded. |
| 1830 | if (Delta % Wordsize) | |
| 1839 | if (delta % wordsize) | |
| 1831 | 1840 | break; |
| 1832 | 1841 | |
| 1833 | 1842 | // Fold it. |
| 1834 | Bitmap |= 1ULL << (Delta / Wordsize); | |
| 1835 | ++I; | |
| 1843 | bitmap |= 1ULL << (delta / wordsize); | |
| 1844 | ++i; | |
| 1836 | 1845 | } |
| 1837 | 1846 | |
| 1838 | if (!Bitmap) | |
| 1847 | if (!bitmap) | |
| 1839 | 1848 | break; |
| 1840 | 1849 | |
| 1841 | RelrRelocs.push_back(Elf_Relr((Bitmap << 1) | 1)); | |
| 1842 | Base += NBits * Wordsize; | |
| 1850 | relrRelocs.push_back(Elf_Relr((bitmap << 1) | 1)); | |
| 1851 | base += nBits * wordsize; | |
| 1843 | 1852 | } |
| 1844 | 1853 | } |
| 1845 | 1854 | |
| 1846 | return RelrRelocs.size() != OldSize; | |
| 1855 | return relrRelocs.size() != oldSize; | |
| 1847 | 1856 | } |
| 1848 | 1857 | |
| 1849 | SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec) | |
| 1850 | : SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0, | |
| 1851 | StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB, | |
| 1852 | Config->Wordsize, | |
| 1853 | StrTabSec.isDynamic() ? ".dynsym" : ".symtab"), | |
| 1854 | StrTabSec(StrTabSec) {} | |
| 1858 | SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &strTabSec) | |
| 1859 | : SyntheticSection(strTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0, | |
| 1860 | strTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB, | |
| 1861 | config->wordsize, | |
| 1862 | strTabSec.isDynamic() ? ".dynsym" : ".symtab"), | |
| 1863 | strTabSec(strTabSec) {} | |
| 1855 | 1864 | |
| 1856 | 1865 | // Orders symbols according to their positions in the GOT, |
| 1857 | 1866 | // in compliance with MIPS ABI rules. |
| 1858 | 1867 | // See "Global Offset Table" in Chapter 5 in the following document |
| 1859 | 1868 | // for detailed description: |
| 1860 | 1869 | // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf |
| 1861 | static bool sortMipsSymbols(const SymbolTableEntry &L, | |
| 1862 | const SymbolTableEntry &R) { | |
| 1870 | static bool sortMipsSymbols(const SymbolTableEntry &l, | |
| 1871 | const SymbolTableEntry &r) { | |
| 1863 | 1872 | // Sort entries related to non-local preemptible symbols by GOT indexes. |
| 1864 | 1873 | // All other entries go to the beginning of a dynsym in arbitrary order. |
| 1865 | if (L.Sym->isInGot() && R.Sym->isInGot()) | |
| 1866 | return L.Sym->GotIndex < R.Sym->GotIndex; | |
| 1867 | if (!L.Sym->isInGot() && !R.Sym->isInGot()) | |
| 1874 | if (l.sym->isInGot() && r.sym->isInGot()) | |
| 1875 | return l.sym->gotIndex < r.sym->gotIndex; | |
| 1876 | if (!l.sym->isInGot() && !r.sym->isInGot()) | |
| 1868 | 1877 | return false; |
| 1869 | return !L.Sym->isInGot(); | |
| 1878 | return !l.sym->isInGot(); | |
| 1870 | 1879 | } |
| 1871 | 1880 | |
| 1872 | 1881 | void SymbolTableBaseSection::finalizeContents() { |
| 1873 | if (OutputSection *Sec = StrTabSec.getParent()) | |
| 1874 | getParent()->Link = Sec->SectionIndex; | |
| 1882 | if (OutputSection *sec = strTabSec.getParent()) | |
| 1883 | getParent()->link = sec->sectionIndex; | |
| 1875 | 1884 | |
| 1876 | if (this->Type != SHT_DYNSYM) { | |
| 1885 | if (this->type != SHT_DYNSYM) { | |
| 1877 | 1886 | sortSymTabSymbols(); |
| 1878 | 1887 | return; |
| 1879 | 1888 | } |
| ... | ... | @@ -1883,18 +1892,22 @@ void SymbolTableBaseSection::finalizeContents() { |
| 1883 | 1892 | |
| 1884 | 1893 | // Section's Info field has the index of the first non-local symbol. |
| 1885 | 1894 | // Because the first symbol entry is a null entry, 1 is the first. |
| 1886 | getParent()->Info = 1; | |
| 1895 | getParent()->info = 1; | |
| 1887 | 1896 | |
| 1888 | if (In.GnuHashTab) { | |
| 1897 | if (getPartition().gnuHashTab) { | |
| 1889 | 1898 | // NB: It also sorts Symbols to meet the GNU hash table requirements. |
| 1890 | In.GnuHashTab->addSymbols(Symbols); | |
| 1891 | } else if (Config->EMachine == EM_MIPS) { | |
| 1892 | std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols); | |
| 1899 | getPartition().gnuHashTab->addSymbols(symbols); | |
| 1900 | } else if (config->emachine == EM_MIPS) { | |
| 1901 | llvm::stable_sort(symbols, sortMipsSymbols); | |
| 1893 | 1902 | } |
| 1894 | 1903 | |
| 1895 | size_t I = 0; | |
| 1896 | for (const SymbolTableEntry &S : Symbols) | |
| 1897 | S.Sym->DynsymIndex = ++I; | |
| 1904 | // Only the main partition's dynsym indexes are stored in the symbols | |
| 1905 | // themselves. All other partitions use a lookup table. | |
| 1906 | if (this == mainPart->dynSymTab) { | |
| 1907 | size_t i = 0; | |
| 1908 | for (const SymbolTableEntry &s : symbols) | |
| 1909 | s.sym->dynsymIndex = ++i; | |
| 1910 | } | |
| 1898 | 1911 | } |
| 1899 | 1912 | |
| 1900 | 1913 | // The ELF spec requires that all local symbols precede global symbols, so we |
| ... | ... | @@ -1906,193 +1919,210 @@ void SymbolTableBaseSection::finalizeContents() { |
| 1906 | 1919 | // coming from. |
| 1907 | 1920 | void SymbolTableBaseSection::sortSymTabSymbols() { |
| 1908 | 1921 | // Move all local symbols before global symbols. |
| 1909 | auto E = std::stable_partition( | |
| 1910 | Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) { | |
| 1911 | return S.Sym->isLocal() || S.Sym->computeBinding() == STB_LOCAL; | |
| 1922 | auto e = std::stable_partition( | |
| 1923 | symbols.begin(), symbols.end(), [](const SymbolTableEntry &s) { | |
| 1924 | return s.sym->isLocal() || s.sym->computeBinding() == STB_LOCAL; | |
| 1912 | 1925 | }); |
| 1913 | size_t NumLocals = E - Symbols.begin(); | |
| 1914 | getParent()->Info = NumLocals + 1; | |
| 1926 | size_t numLocals = e - symbols.begin(); | |
| 1927 | getParent()->info = numLocals + 1; | |
| 1915 | 1928 | |
| 1916 | 1929 | // We want to group the local symbols by file. For that we rebuild the local |
| 1917 | 1930 | // part of the symbols vector. We do not need to care about the STT_FILE |
| 1918 | 1931 | // symbols, they are already naturally placed first in each group. That |
| 1919 | 1932 | // happens because STT_FILE is always the first symbol in the object and hence |
| 1920 | 1933 | // precede all other local symbols we add for a file. |
| 1921 | MapVector<InputFile *, std::vector<SymbolTableEntry>> Arr; | |
| 1922 | for (const SymbolTableEntry &S : llvm::make_range(Symbols.begin(), E)) | |
| 1923 | Arr[S.Sym->File].push_back(S); | |
| 1934 | MapVector<InputFile *, std::vector<SymbolTableEntry>> arr; | |
| 1935 | for (const SymbolTableEntry &s : llvm::make_range(symbols.begin(), e)) | |
| 1936 | arr[s.sym->file].push_back(s); | |
| 1924 | 1937 | |
| 1925 | auto I = Symbols.begin(); | |
| 1926 | for (std::pair<InputFile *, std::vector<SymbolTableEntry>> &P : Arr) | |
| 1927 | for (SymbolTableEntry &Entry : P.second) | |
| 1928 | *I++ = Entry; | |
| 1938 | auto i = symbols.begin(); | |
| 1939 | for (std::pair<InputFile *, std::vector<SymbolTableEntry>> &p : arr) | |
| 1940 | for (SymbolTableEntry &entry : p.second) | |
| 1941 | *i++ = entry; | |
| 1929 | 1942 | } |
| 1930 | 1943 | |
| 1931 | void SymbolTableBaseSection::addSymbol(Symbol *B) { | |
| 1944 | void SymbolTableBaseSection::addSymbol(Symbol *b) { | |
| 1932 | 1945 | // Adding a local symbol to a .dynsym is a bug. |
| 1933 | assert(this->Type != SHT_DYNSYM || !B->isLocal()); | |
| 1946 | assert(this->type != SHT_DYNSYM || !b->isLocal()); | |
| 1934 | 1947 | |
| 1935 | bool HashIt = B->isLocal(); | |
| 1936 | Symbols.push_back({B, StrTabSec.addString(B->getName(), HashIt)}); | |
| 1948 | bool hashIt = b->isLocal(); | |
| 1949 | symbols.push_back({b, strTabSec.addString(b->getName(), hashIt)}); | |
| 1937 | 1950 | } |
| 1938 | 1951 | |
| 1939 | size_t SymbolTableBaseSection::getSymbolIndex(Symbol *Sym) { | |
| 1940 | // Initializes symbol lookup tables lazily. This is used only | |
| 1941 | // for -r or -emit-relocs. | |
| 1942 | llvm::call_once(OnceFlag, [&] { | |
| 1943 | SymbolIndexMap.reserve(Symbols.size()); | |
| 1944 | size_t I = 0; | |
| 1945 | for (const SymbolTableEntry &E : Symbols) { | |
| 1946 | if (E.Sym->Type == STT_SECTION) | |
| 1947 | SectionIndexMap[E.Sym->getOutputSection()] = ++I; | |
| 1952 | size_t SymbolTableBaseSection::getSymbolIndex(Symbol *sym) { | |
| 1953 | if (this == mainPart->dynSymTab) | |
| 1954 | return sym->dynsymIndex; | |
| 1955 | ||
| 1956 | // Initializes symbol lookup tables lazily. This is used only for -r, | |
| 1957 | // -emit-relocs and dynsyms in partitions other than the main one. | |
| 1958 | llvm::call_once(onceFlag, [&] { | |
| 1959 | symbolIndexMap.reserve(symbols.size()); | |
| 1960 | size_t i = 0; | |
| 1961 | for (const SymbolTableEntry &e : symbols) { | |
| 1962 | if (e.sym->type == STT_SECTION) | |
| 1963 | sectionIndexMap[e.sym->getOutputSection()] = ++i; | |
| 1948 | 1964 | else |
| 1949 | SymbolIndexMap[E.Sym] = ++I; | |
| 1965 | symbolIndexMap[e.sym] = ++i; | |
| 1950 | 1966 | } |
| 1951 | 1967 | }); |
| 1952 | 1968 | |
| 1953 | 1969 | // Section symbols are mapped based on their output sections |
| 1954 | 1970 | // to maintain their semantics. |
| 1955 | if (Sym->Type == STT_SECTION) | |
| 1956 | return SectionIndexMap.lookup(Sym->getOutputSection()); | |
| 1957 | return SymbolIndexMap.lookup(Sym); | |
| 1971 | if (sym->type == STT_SECTION) | |
| 1972 | return sectionIndexMap.lookup(sym->getOutputSection()); | |
| 1973 | return symbolIndexMap.lookup(sym); | |
| 1958 | 1974 | } |
| 1959 | 1975 | |
| 1960 | 1976 | template <class ELFT> |
| 1961 | SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &StrTabSec) | |
| 1962 | : SymbolTableBaseSection(StrTabSec) { | |
| 1963 | this->Entsize = sizeof(Elf_Sym); | |
| 1977 | SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &strTabSec) | |
| 1978 | : SymbolTableBaseSection(strTabSec) { | |
| 1979 | this->entsize = sizeof(Elf_Sym); | |
| 1964 | 1980 | } |
| 1965 | 1981 | |
| 1966 | static BssSection *getCommonSec(Symbol *Sym) { | |
| 1967 | if (!Config->DefineCommon) | |
| 1968 | if (auto *D = dyn_cast<Defined>(Sym)) | |
| 1969 | return dyn_cast_or_null<BssSection>(D->Section); | |
| 1982 | static BssSection *getCommonSec(Symbol *sym) { | |
| 1983 | if (!config->defineCommon) | |
| 1984 | if (auto *d = dyn_cast<Defined>(sym)) | |
| 1985 | return dyn_cast_or_null<BssSection>(d->section); | |
| 1970 | 1986 | return nullptr; |
| 1971 | 1987 | } |
| 1972 | 1988 | |
| 1973 | static uint32_t getSymSectionIndex(Symbol *Sym) { | |
| 1974 | if (getCommonSec(Sym)) | |
| 1989 | static uint32_t getSymSectionIndex(Symbol *sym) { | |
| 1990 | if (getCommonSec(sym)) | |
| 1975 | 1991 | return SHN_COMMON; |
| 1976 | if (!isa<Defined>(Sym) || Sym->NeedsPltAddr) | |
| 1992 | if (!isa<Defined>(sym) || sym->needsPltAddr) | |
| 1977 | 1993 | return SHN_UNDEF; |
| 1978 | if (const OutputSection *OS = Sym->getOutputSection()) | |
| 1979 | return OS->SectionIndex >= SHN_LORESERVE ? (uint32_t)SHN_XINDEX | |
| 1980 | : OS->SectionIndex; | |
| 1994 | if (const OutputSection *os = sym->getOutputSection()) | |
| 1995 | return os->sectionIndex >= SHN_LORESERVE ? (uint32_t)SHN_XINDEX | |
| 1996 | : os->sectionIndex; | |
| 1981 | 1997 | return SHN_ABS; |
| 1982 | 1998 | } |
| 1983 | 1999 | |
| 1984 | 2000 | // Write the internal symbol table contents to the output symbol table. |
| 1985 | template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) { | |
| 2001 | template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *buf) { | |
| 1986 | 2002 | // The first entry is a null entry as per the ELF spec. |
| 1987 | memset(Buf, 0, sizeof(Elf_Sym)); | |
| 1988 | Buf += sizeof(Elf_Sym); | |
| 2003 | memset(buf, 0, sizeof(Elf_Sym)); | |
| 2004 | buf += sizeof(Elf_Sym); | |
| 1989 | 2005 | |
| 1990 | auto *ESym = reinterpret_cast<Elf_Sym *>(Buf); | |
| 2006 | auto *eSym = reinterpret_cast<Elf_Sym *>(buf); | |
| 1991 | 2007 | |
| 1992 | for (SymbolTableEntry &Ent : Symbols) { | |
| 1993 | Symbol *Sym = Ent.Sym; | |
| 2008 | for (SymbolTableEntry &ent : symbols) { | |
| 2009 | Symbol *sym = ent.sym; | |
| 2010 | bool isDefinedHere = type == SHT_SYMTAB || sym->partition == partition; | |
| 1994 | 2011 | |
| 1995 | 2012 | // Set st_info and st_other. |
| 1996 | ESym->st_other = 0; | |
| 1997 | if (Sym->isLocal()) { | |
| 1998 | ESym->setBindingAndType(STB_LOCAL, Sym->Type); | |
| 2013 | eSym->st_other = 0; | |
| 2014 | if (sym->isLocal()) { | |
| 2015 | eSym->setBindingAndType(STB_LOCAL, sym->type); | |
| 1999 | 2016 | } else { |
| 2000 | ESym->setBindingAndType(Sym->computeBinding(), Sym->Type); | |
| 2001 | ESym->setVisibility(Sym->Visibility); | |
| 2017 | eSym->setBindingAndType(sym->computeBinding(), sym->type); | |
| 2018 | eSym->setVisibility(sym->visibility); | |
| 2002 | 2019 | } |
| 2003 | 2020 | |
| 2004 | ESym->st_name = Ent.StrTabOffset; | |
| 2005 | ESym->st_shndx = getSymSectionIndex(Ent.Sym); | |
| 2021 | // The 3 most significant bits of st_other are used by OpenPOWER ABI. | |
| 2022 | // See getPPC64GlobalEntryToLocalEntryOffset() for more details. | |
| 2023 | if (config->emachine == EM_PPC64) | |
| 2024 | eSym->st_other |= sym->stOther & 0xe0; | |
| 2025 | ||
| 2026 | eSym->st_name = ent.strTabOffset; | |
| 2027 | if (isDefinedHere) | |
| 2028 | eSym->st_shndx = getSymSectionIndex(ent.sym); | |
| 2029 | else | |
| 2030 | eSym->st_shndx = 0; | |
| 2006 | 2031 | |
| 2007 | 2032 | // Copy symbol size if it is a defined symbol. st_size is not significant |
| 2008 | 2033 | // for undefined symbols, so whether copying it or not is up to us if that's |
| 2009 | 2034 | // the case. We'll leave it as zero because by not setting a value, we can |
| 2010 | 2035 | // get the exact same outputs for two sets of input files that differ only |
| 2011 | 2036 | // in undefined symbol size in DSOs. |
| 2012 | if (ESym->st_shndx == SHN_UNDEF) | |
| 2013 | ESym->st_size = 0; | |
| 2037 | if (eSym->st_shndx == SHN_UNDEF || !isDefinedHere) | |
| 2038 | eSym->st_size = 0; | |
| 2014 | 2039 | else |
| 2015 | ESym->st_size = Sym->getSize(); | |
| 2040 | eSym->st_size = sym->getSize(); | |
| 2016 | 2041 | |
| 2017 | 2042 | // st_value is usually an address of a symbol, but that has a |
| 2018 | 2043 | // special meaining for uninstantiated common symbols (this can |
| 2019 | 2044 | // occur if -r is given). |
| 2020 | if (BssSection *CommonSec = getCommonSec(Ent.Sym)) | |
| 2021 | ESym->st_value = CommonSec->Alignment; | |
| 2045 | if (BssSection *commonSec = getCommonSec(ent.sym)) | |
| 2046 | eSym->st_value = commonSec->alignment; | |
| 2047 | else if (isDefinedHere) | |
| 2048 | eSym->st_value = sym->getVA(); | |
| 2022 | 2049 | else |
| 2023 | ESym->st_value = Sym->getVA(); | |
| 2050 | eSym->st_value = 0; | |
| 2024 | 2051 | |
| 2025 | ++ESym; | |
| 2052 | ++eSym; | |
| 2026 | 2053 | } |
| 2027 | 2054 | |
| 2028 | 2055 | // On MIPS we need to mark symbol which has a PLT entry and requires |
| 2029 | 2056 | // pointer equality by STO_MIPS_PLT flag. That is necessary to help |
| 2030 | 2057 | // dynamic linker distinguish such symbols and MIPS lazy-binding stubs. |
| 2031 | 2058 | // https://sourceware.org/ml/binutils/2008-07/txt00000.txt |
| 2032 | if (Config->EMachine == EM_MIPS) { | |
| 2033 | auto *ESym = reinterpret_cast<Elf_Sym *>(Buf); | |
| 2059 | if (config->emachine == EM_MIPS) { | |
| 2060 | auto *eSym = reinterpret_cast<Elf_Sym *>(buf); | |
| 2034 | 2061 | |
| 2035 | for (SymbolTableEntry &Ent : Symbols) { | |
| 2036 | Symbol *Sym = Ent.Sym; | |
| 2037 | if (Sym->isInPlt() && Sym->NeedsPltAddr) | |
| 2038 | ESym->st_other |= STO_MIPS_PLT; | |
| 2062 | for (SymbolTableEntry &ent : symbols) { | |
| 2063 | Symbol *sym = ent.sym; | |
| 2064 | if (sym->isInPlt() && sym->needsPltAddr) | |
| 2065 | eSym->st_other |= STO_MIPS_PLT; | |
| 2039 | 2066 | if (isMicroMips()) { |
| 2040 | // Set STO_MIPS_MICROMIPS flag and less-significant bit for | |
| 2041 | // a defined microMIPS symbol and symbol should point to its | |
| 2042 | // PLT entry (in case of microMIPS, PLT entries always contain | |
| 2043 | // microMIPS code). | |
| 2044 | if (Sym->isDefined() && | |
| 2045 | ((Sym->StOther & STO_MIPS_MICROMIPS) || Sym->NeedsPltAddr)) { | |
| 2046 | if (StrTabSec.isDynamic()) | |
| 2047 | ESym->st_value |= 1; | |
| 2048 | ESym->st_other |= STO_MIPS_MICROMIPS; | |
| 2067 | // We already set the less-significant bit for symbols | |
| 2068 | // marked by the `STO_MIPS_MICROMIPS` flag and for microMIPS PLT | |
| 2069 | // records. That allows us to distinguish such symbols in | |
| 2070 | // the `MIPS<ELFT>::relocateOne()` routine. Now we should | |
| 2071 | // clear that bit for non-dynamic symbol table, so tools | |
| 2072 | // like `objdump` will be able to deal with a correct | |
| 2073 | // symbol position. | |
| 2074 | if (sym->isDefined() && | |
| 2075 | ((sym->stOther & STO_MIPS_MICROMIPS) || sym->needsPltAddr)) { | |
| 2076 | if (!strTabSec.isDynamic()) | |
| 2077 | eSym->st_value &= ~1; | |
| 2078 | eSym->st_other |= STO_MIPS_MICROMIPS; | |
| 2049 | 2079 | } |
| 2050 | 2080 | } |
| 2051 | if (Config->Relocatable) | |
| 2052 | if (auto *D = dyn_cast<Defined>(Sym)) | |
| 2053 | if (isMipsPIC<ELFT>(D)) | |
| 2054 | ESym->st_other |= STO_MIPS_PIC; | |
| 2055 | ++ESym; | |
| 2081 | if (config->relocatable) | |
| 2082 | if (auto *d = dyn_cast<Defined>(sym)) | |
| 2083 | if (isMipsPIC<ELFT>(d)) | |
| 2084 | eSym->st_other |= STO_MIPS_PIC; | |
| 2085 | ++eSym; | |
| 2056 | 2086 | } |
| 2057 | 2087 | } |
| 2058 | 2088 | } |
| 2059 | 2089 | |
| 2060 | 2090 | SymtabShndxSection::SymtabShndxSection() |
| 2061 | : SyntheticSection(0, SHT_SYMTAB_SHNDX, 4, ".symtab_shndxr") { | |
| 2062 | this->Entsize = 4; | |
| 2091 | : SyntheticSection(0, SHT_SYMTAB_SHNDX, 4, ".symtab_shndx") { | |
| 2092 | this->entsize = 4; | |
| 2063 | 2093 | } |
| 2064 | 2094 | |
| 2065 | void SymtabShndxSection::writeTo(uint8_t *Buf) { | |
| 2095 | void SymtabShndxSection::writeTo(uint8_t *buf) { | |
| 2066 | 2096 | // We write an array of 32 bit values, where each value has 1:1 association |
| 2067 | 2097 | // with an entry in .symtab. If the corresponding entry contains SHN_XINDEX, |
| 2068 | 2098 | // we need to write actual index, otherwise, we must write SHN_UNDEF(0). |
| 2069 | Buf += 4; // Ignore .symtab[0] entry. | |
| 2070 | for (const SymbolTableEntry &Entry : In.SymTab->getSymbols()) { | |
| 2071 | if (getSymSectionIndex(Entry.Sym) == SHN_XINDEX) | |
| 2072 | write32(Buf, Entry.Sym->getOutputSection()->SectionIndex); | |
| 2073 | Buf += 4; | |
| 2099 | buf += 4; // Ignore .symtab[0] entry. | |
| 2100 | for (const SymbolTableEntry &entry : in.symTab->getSymbols()) { | |
| 2101 | if (getSymSectionIndex(entry.sym) == SHN_XINDEX) | |
| 2102 | write32(buf, entry.sym->getOutputSection()->sectionIndex); | |
| 2103 | buf += 4; | |
| 2074 | 2104 | } |
| 2075 | 2105 | } |
| 2076 | 2106 | |
| 2077 | bool SymtabShndxSection::empty() const { | |
| 2107 | bool SymtabShndxSection::isNeeded() const { | |
| 2078 | 2108 | // SHT_SYMTAB can hold symbols with section indices values up to |
| 2079 | 2109 | // SHN_LORESERVE. If we need more, we want to use extension SHT_SYMTAB_SHNDX |
| 2080 | 2110 | // section. Problem is that we reveal the final section indices a bit too |
| 2081 | 2111 | // late, and we do not know them here. For simplicity, we just always create |
| 2082 | // a .symtab_shndxr section when the amount of output sections is huge. | |
| 2083 | size_t Size = 0; | |
| 2084 | for (BaseCommand *Base : Script->SectionCommands) | |
| 2085 | if (isa<OutputSection>(Base)) | |
| 2086 | ++Size; | |
| 2087 | return Size < SHN_LORESERVE; | |
| 2112 | // a .symtab_shndx section when the amount of output sections is huge. | |
| 2113 | size_t size = 0; | |
| 2114 | for (BaseCommand *base : script->sectionCommands) | |
| 2115 | if (isa<OutputSection>(base)) | |
| 2116 | ++size; | |
| 2117 | return size >= SHN_LORESERVE; | |
| 2088 | 2118 | } |
| 2089 | 2119 | |
| 2090 | 2120 | void SymtabShndxSection::finalizeContents() { |
| 2091 | getParent()->Link = In.SymTab->getParent()->SectionIndex; | |
| 2121 | getParent()->link = in.symTab->getParent()->sectionIndex; | |
| 2092 | 2122 | } |
| 2093 | 2123 | |
| 2094 | 2124 | size_t SymtabShndxSection::getSize() const { |
| 2095 | return In.SymTab->getNumSymbols() * 4; | |
| 2125 | return in.symTab->getNumSymbols() * 4; | |
| 2096 | 2126 | } |
| 2097 | 2127 | |
| 2098 | 2128 | // .hash and .gnu.hash sections contain on-disk hash tables that map |
| ... | ... | @@ -2127,45 +2157,45 @@ size_t SymtabShndxSection::getSize() const { |
| 2127 | 2157 | // about .gnu.hash, you want to specify -hash-style=gnu. Otherwise, a |
| 2128 | 2158 | // safe bet is to specify -hash-style=both for backward compatibilty. |
| 2129 | 2159 | GnuHashTableSection::GnuHashTableSection() |
| 2130 | : SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, Config->Wordsize, ".gnu.hash") { | |
| 2160 | : SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, config->wordsize, ".gnu.hash") { | |
| 2131 | 2161 | } |
| 2132 | 2162 | |
| 2133 | 2163 | void GnuHashTableSection::finalizeContents() { |
| 2134 | if (OutputSection *Sec = In.DynSymTab->getParent()) | |
| 2135 | getParent()->Link = Sec->SectionIndex; | |
| 2164 | if (OutputSection *sec = getPartition().dynSymTab->getParent()) | |
| 2165 | getParent()->link = sec->sectionIndex; | |
| 2136 | 2166 | |
| 2137 | 2167 | // Computes bloom filter size in word size. We want to allocate 12 |
| 2138 | 2168 | // bits for each symbol. It must be a power of two. |
| 2139 | if (Symbols.empty()) { | |
| 2140 | MaskWords = 1; | |
| 2169 | if (symbols.empty()) { | |
| 2170 | maskWords = 1; | |
| 2141 | 2171 | } else { |
| 2142 | uint64_t NumBits = Symbols.size() * 12; | |
| 2143 | MaskWords = NextPowerOf2(NumBits / (Config->Wordsize * 8)); | |
| 2172 | uint64_t numBits = symbols.size() * 12; | |
| 2173 | maskWords = NextPowerOf2(numBits / (config->wordsize * 8)); | |
| 2144 | 2174 | } |
| 2145 | 2175 | |
| 2146 | Size = 16; // Header | |
| 2147 | Size += Config->Wordsize * MaskWords; // Bloom filter | |
| 2148 | Size += NBuckets * 4; // Hash buckets | |
| 2149 | Size += Symbols.size() * 4; // Hash values | |
| 2176 | size = 16; // Header | |
| 2177 | size += config->wordsize * maskWords; // Bloom filter | |
| 2178 | size += nBuckets * 4; // Hash buckets | |
| 2179 | size += symbols.size() * 4; // Hash values | |
| 2150 | 2180 | } |
| 2151 | 2181 | |
| 2152 | void GnuHashTableSection::writeTo(uint8_t *Buf) { | |
| 2182 | void GnuHashTableSection::writeTo(uint8_t *buf) { | |
| 2153 | 2183 | // The output buffer is not guaranteed to be zero-cleared because we pre- |
| 2154 | 2184 | // fill executable sections with trap instructions. This is a precaution |
| 2155 | 2185 | // for that case, which happens only when -no-rosegment is given. |
| 2156 | memset(Buf, 0, Size); | |
| 2186 | memset(buf, 0, size); | |
| 2157 | 2187 | |
| 2158 | 2188 | // Write a header. |
| 2159 | write32(Buf, NBuckets); | |
| 2160 | write32(Buf + 4, In.DynSymTab->getNumSymbols() - Symbols.size()); | |
| 2161 | write32(Buf + 8, MaskWords); | |
| 2162 | write32(Buf + 12, Shift2); | |
| 2163 | Buf += 16; | |
| 2189 | write32(buf, nBuckets); | |
| 2190 | write32(buf + 4, getPartition().dynSymTab->getNumSymbols() - symbols.size()); | |
| 2191 | write32(buf + 8, maskWords); | |
| 2192 | write32(buf + 12, Shift2); | |
| 2193 | buf += 16; | |
| 2164 | 2194 | |
| 2165 | 2195 | // Write a bloom filter and a hash table. |
| 2166 | writeBloomFilter(Buf); | |
| 2167 | Buf += Config->Wordsize * MaskWords; | |
| 2168 | writeHashTable(Buf); | |
| 2196 | writeBloomFilter(buf); | |
| 2197 | buf += config->wordsize * maskWords; | |
| 2198 | writeHashTable(buf); | |
| 2169 | 2199 | } |
| 2170 | 2200 | |
| 2171 | 2201 | // This function writes a 2-bit bloom filter. This bloom filter alone |
| ... | ... | @@ -2175,57 +2205,58 @@ void GnuHashTableSection::writeTo(uint8_t *Buf) { |
| 2175 | 2205 | // |
| 2176 | 2206 | // [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2), |
| 2177 | 2207 | // p.9, https://www.akkadia.org/drepper/dsohowto.pdf |
| 2178 | void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) { | |
| 2179 | unsigned C = Config->Is64 ? 64 : 32; | |
| 2180 | for (const Entry &Sym : Symbols) { | |
| 2208 | void GnuHashTableSection::writeBloomFilter(uint8_t *buf) { | |
| 2209 | unsigned c = config->is64 ? 64 : 32; | |
| 2210 | for (const Entry &sym : symbols) { | |
| 2181 | 2211 | // When C = 64, we choose a word with bits [6:...] and set 1 to two bits in |
| 2182 | 2212 | // the word using bits [0:5] and [26:31]. |
| 2183 | size_t I = (Sym.Hash / C) & (MaskWords - 1); | |
| 2184 | uint64_t Val = readUint(Buf + I * Config->Wordsize); | |
| 2185 | Val |= uint64_t(1) << (Sym.Hash % C); | |
| 2186 | Val |= uint64_t(1) << ((Sym.Hash >> Shift2) % C); | |
| 2187 | writeUint(Buf + I * Config->Wordsize, Val); | |
| 2213 | size_t i = (sym.hash / c) & (maskWords - 1); | |
| 2214 | uint64_t val = readUint(buf + i * config->wordsize); | |
| 2215 | val |= uint64_t(1) << (sym.hash % c); | |
| 2216 | val |= uint64_t(1) << ((sym.hash >> Shift2) % c); | |
| 2217 | writeUint(buf + i * config->wordsize, val); | |
| 2188 | 2218 | } |
| 2189 | 2219 | } |
| 2190 | 2220 | |
| 2191 | void GnuHashTableSection::writeHashTable(uint8_t *Buf) { | |
| 2192 | uint32_t *Buckets = reinterpret_cast<uint32_t *>(Buf); | |
| 2193 | uint32_t OldBucket = -1; | |
| 2194 | uint32_t *Values = Buckets + NBuckets; | |
| 2195 | for (auto I = Symbols.begin(), E = Symbols.end(); I != E; ++I) { | |
| 2221 | void GnuHashTableSection::writeHashTable(uint8_t *buf) { | |
| 2222 | uint32_t *buckets = reinterpret_cast<uint32_t *>(buf); | |
| 2223 | uint32_t oldBucket = -1; | |
| 2224 | uint32_t *values = buckets + nBuckets; | |
| 2225 | for (auto i = symbols.begin(), e = symbols.end(); i != e; ++i) { | |
| 2196 | 2226 | // Write a hash value. It represents a sequence of chains that share the |
| 2197 | 2227 | // same hash modulo value. The last element of each chain is terminated by |
| 2198 | 2228 | // LSB 1. |
| 2199 | uint32_t Hash = I->Hash; | |
| 2200 | bool IsLastInChain = (I + 1) == E || I->BucketIdx != (I + 1)->BucketIdx; | |
| 2201 | Hash = IsLastInChain ? Hash | 1 : Hash & ~1; | |
| 2202 | write32(Values++, Hash); | |
| 2229 | uint32_t hash = i->hash; | |
| 2230 | bool isLastInChain = (i + 1) == e || i->bucketIdx != (i + 1)->bucketIdx; | |
| 2231 | hash = isLastInChain ? hash | 1 : hash & ~1; | |
| 2232 | write32(values++, hash); | |
| 2203 | 2233 | |
| 2204 | if (I->BucketIdx == OldBucket) | |
| 2234 | if (i->bucketIdx == oldBucket) | |
| 2205 | 2235 | continue; |
| 2206 | 2236 | // Write a hash bucket. Hash buckets contain indices in the following hash |
| 2207 | 2237 | // value table. |
| 2208 | write32(Buckets + I->BucketIdx, I->Sym->DynsymIndex); | |
| 2209 | OldBucket = I->BucketIdx; | |
| 2238 | write32(buckets + i->bucketIdx, | |
| 2239 | getPartition().dynSymTab->getSymbolIndex(i->sym)); | |
| 2240 | oldBucket = i->bucketIdx; | |
| 2210 | 2241 | } |
| 2211 | 2242 | } |
| 2212 | 2243 | |
| 2213 | static uint32_t hashGnu(StringRef Name) { | |
| 2214 | uint32_t H = 5381; | |
| 2215 | for (uint8_t C : Name) | |
| 2216 | H = (H << 5) + H + C; | |
| 2217 | return H; | |
| 2244 | static uint32_t hashGnu(StringRef name) { | |
| 2245 | uint32_t h = 5381; | |
| 2246 | for (uint8_t c : name) | |
| 2247 | h = (h << 5) + h + c; | |
| 2248 | return h; | |
| 2218 | 2249 | } |
| 2219 | 2250 | |
| 2220 | 2251 | // Add symbols to this symbol hash table. Note that this function |
| 2221 | 2252 | // destructively sort a given vector -- which is needed because |
| 2222 | 2253 | // GNU-style hash table places some sorting requirements. |
| 2223 | void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) { | |
| 2254 | void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &v) { | |
| 2224 | 2255 | // We cannot use 'auto' for Mid because GCC 6.1 cannot deduce |
| 2225 | 2256 | // its type correctly. |
| 2226 | std::vector<SymbolTableEntry>::iterator Mid = | |
| 2227 | std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) { | |
| 2228 | return !S.Sym->isDefined(); | |
| 2257 | std::vector<SymbolTableEntry>::iterator mid = | |
| 2258 | std::stable_partition(v.begin(), v.end(), [&](const SymbolTableEntry &s) { | |
| 2259 | return !s.sym->isDefined() || s.sym->partition != partition; | |
| 2229 | 2260 | }); |
| 2230 | 2261 | |
| 2231 | 2262 | // We chose load factor 4 for the on-disk hash table. For each hash |
| ... | ... | @@ -2237,138 +2268,143 @@ void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) { |
| 2237 | 2268 | // Android loader as of 2018 doesn't like a .gnu.hash containing such |
| 2238 | 2269 | // table. If that's the case, we create a hash table with one unused |
| 2239 | 2270 | // dummy slot. |
| 2240 | NBuckets = std::max<size_t>((V.end() - Mid) / 4, 1); | |
| 2271 | nBuckets = std::max<size_t>((v.end() - mid) / 4, 1); | |
| 2241 | 2272 | |
| 2242 | if (Mid == V.end()) | |
| 2273 | if (mid == v.end()) | |
| 2243 | 2274 | return; |
| 2244 | 2275 | |
| 2245 | for (SymbolTableEntry &Ent : llvm::make_range(Mid, V.end())) { | |
| 2246 | Symbol *B = Ent.Sym; | |
| 2247 | uint32_t Hash = hashGnu(B->getName()); | |
| 2248 | uint32_t BucketIdx = Hash % NBuckets; | |
| 2249 | Symbols.push_back({B, Ent.StrTabOffset, Hash, BucketIdx}); | |
| 2276 | for (SymbolTableEntry &ent : llvm::make_range(mid, v.end())) { | |
| 2277 | Symbol *b = ent.sym; | |
| 2278 | uint32_t hash = hashGnu(b->getName()); | |
| 2279 | uint32_t bucketIdx = hash % nBuckets; | |
| 2280 | symbols.push_back({b, ent.strTabOffset, hash, bucketIdx}); | |
| 2250 | 2281 | } |
| 2251 | 2282 | |
| 2252 | std::stable_sort( | |
| 2253 | Symbols.begin(), Symbols.end(), | |
| 2254 | [](const Entry &L, const Entry &R) { return L.BucketIdx < R.BucketIdx; }); | |
| 2283 | llvm::stable_sort(symbols, [](const Entry &l, const Entry &r) { | |
| 2284 | return l.bucketIdx < r.bucketIdx; | |
| 2285 | }); | |
| 2255 | 2286 | |
| 2256 | V.erase(Mid, V.end()); | |
| 2257 | for (const Entry &Ent : Symbols) | |
| 2258 | V.push_back({Ent.Sym, Ent.StrTabOffset}); | |
| 2287 | v.erase(mid, v.end()); | |
| 2288 | for (const Entry &ent : symbols) | |
| 2289 | v.push_back({ent.sym, ent.strTabOffset}); | |
| 2259 | 2290 | } |
| 2260 | 2291 | |
| 2261 | 2292 | HashTableSection::HashTableSection() |
| 2262 | 2293 | : SyntheticSection(SHF_ALLOC, SHT_HASH, 4, ".hash") { |
| 2263 | this->Entsize = 4; | |
| 2294 | this->entsize = 4; | |
| 2264 | 2295 | } |
| 2265 | 2296 | |
| 2266 | 2297 | void HashTableSection::finalizeContents() { |
| 2267 | if (OutputSection *Sec = In.DynSymTab->getParent()) | |
| 2268 | getParent()->Link = Sec->SectionIndex; | |
| 2298 | SymbolTableBaseSection *symTab = getPartition().dynSymTab; | |
| 2269 | 2299 | |
| 2270 | unsigned NumEntries = 2; // nbucket and nchain. | |
| 2271 | NumEntries += In.DynSymTab->getNumSymbols(); // The chain entries. | |
| 2300 | if (OutputSection *sec = symTab->getParent()) | |
| 2301 | getParent()->link = sec->sectionIndex; | |
| 2302 | ||
| 2303 | unsigned numEntries = 2; // nbucket and nchain. | |
| 2304 | numEntries += symTab->getNumSymbols(); // The chain entries. | |
| 2272 | 2305 | |
| 2273 | 2306 | // Create as many buckets as there are symbols. |
| 2274 | NumEntries += In.DynSymTab->getNumSymbols(); | |
| 2275 | this->Size = NumEntries * 4; | |
| 2307 | numEntries += symTab->getNumSymbols(); | |
| 2308 | this->size = numEntries * 4; | |
| 2276 | 2309 | } |
| 2277 | 2310 | |
| 2278 | void HashTableSection::writeTo(uint8_t *Buf) { | |
| 2311 | void HashTableSection::writeTo(uint8_t *buf) { | |
| 2312 | SymbolTableBaseSection *symTab = getPartition().dynSymTab; | |
| 2313 | ||
| 2279 | 2314 | // See comment in GnuHashTableSection::writeTo. |
| 2280 | memset(Buf, 0, Size); | |
| 2315 | memset(buf, 0, size); | |
| 2281 | 2316 | |
| 2282 | unsigned NumSymbols = In.DynSymTab->getNumSymbols(); | |
| 2317 | unsigned numSymbols = symTab->getNumSymbols(); | |
| 2283 | 2318 | |
| 2284 | uint32_t *P = reinterpret_cast<uint32_t *>(Buf); | |
| 2285 | write32(P++, NumSymbols); // nbucket | |
| 2286 | write32(P++, NumSymbols); // nchain | |
| 2319 | uint32_t *p = reinterpret_cast<uint32_t *>(buf); | |
| 2320 | write32(p++, numSymbols); // nbucket | |
| 2321 | write32(p++, numSymbols); // nchain | |
| 2287 | 2322 | |
| 2288 | uint32_t *Buckets = P; | |
| 2289 | uint32_t *Chains = P + NumSymbols; | |
| 2323 | uint32_t *buckets = p; | |
| 2324 | uint32_t *chains = p + numSymbols; | |
| 2290 | 2325 | |
| 2291 | for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) { | |
| 2292 | Symbol *Sym = S.Sym; | |
| 2293 | StringRef Name = Sym->getName(); | |
| 2294 | unsigned I = Sym->DynsymIndex; | |
| 2295 | uint32_t Hash = hashSysV(Name) % NumSymbols; | |
| 2296 | Chains[I] = Buckets[Hash]; | |
| 2297 | write32(Buckets + Hash, I); | |
| 2326 | for (const SymbolTableEntry &s : symTab->getSymbols()) { | |
| 2327 | Symbol *sym = s.sym; | |
| 2328 | StringRef name = sym->getName(); | |
| 2329 | unsigned i = sym->dynsymIndex; | |
| 2330 | uint32_t hash = hashSysV(name) % numSymbols; | |
| 2331 | chains[i] = buckets[hash]; | |
| 2332 | write32(buckets + hash, i); | |
| 2298 | 2333 | } |
| 2299 | 2334 | } |
| 2300 | 2335 | |
| 2301 | 2336 | // On PowerPC64 the lazy symbol resolvers go into the `global linkage table` |
| 2302 | 2337 | // in the .glink section, rather then the typical .plt section. |
| 2303 | PltSection::PltSection(bool IsIplt) | |
| 2304 | : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, | |
| 2305 | Config->EMachine == EM_PPC64 ? ".glink" : ".plt"), | |
| 2306 | HeaderSize(!IsIplt || Config->ZRetpolineplt ? Target->PltHeaderSize : 0), | |
| 2307 | IsIplt(IsIplt) { | |
| 2338 | PltSection::PltSection(bool isIplt) | |
| 2339 | : SyntheticSection( | |
| 2340 | SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, | |
| 2341 | (config->emachine == EM_PPC || config->emachine == EM_PPC64) | |
| 2342 | ? ".glink" | |
| 2343 | : ".plt"), | |
| 2344 | headerSize(!isIplt || config->zRetpolineplt ? target->pltHeaderSize : 0), | |
| 2345 | isIplt(isIplt) { | |
| 2308 | 2346 | // The PLT needs to be writable on SPARC as the dynamic linker will |
| 2309 | 2347 | // modify the instructions in the PLT entries. |
| 2310 | if (Config->EMachine == EM_SPARCV9) | |
| 2311 | this->Flags |= SHF_WRITE; | |
| 2348 | if (config->emachine == EM_SPARCV9) | |
| 2349 | this->flags |= SHF_WRITE; | |
| 2312 | 2350 | } |
| 2313 | 2351 | |
| 2314 | void PltSection::writeTo(uint8_t *Buf) { | |
| 2352 | void PltSection::writeTo(uint8_t *buf) { | |
| 2353 | if (config->emachine == EM_PPC) { | |
| 2354 | writePPC32GlinkSection(buf, entries.size()); | |
| 2355 | return; | |
| 2356 | } | |
| 2357 | ||
| 2315 | 2358 | // At beginning of PLT or retpoline IPLT, we have code to call the dynamic |
| 2316 | 2359 | // linker to resolve dynsyms at runtime. Write such code. |
| 2317 | if (HeaderSize > 0) | |
| 2318 | Target->writePltHeader(Buf); | |
| 2319 | size_t Off = HeaderSize; | |
| 2320 | // The IPlt is immediately after the Plt, account for this in RelOff | |
| 2321 | unsigned PltOff = getPltRelocOff(); | |
| 2360 | if (headerSize) | |
| 2361 | target->writePltHeader(buf); | |
| 2362 | size_t off = headerSize; | |
| 2363 | ||
| 2364 | RelocationBaseSection *relSec = isIplt ? in.relaIplt : in.relaPlt; | |
| 2322 | 2365 | |
| 2323 | for (auto &I : Entries) { | |
| 2324 | const Symbol *B = I.first; | |
| 2325 | unsigned RelOff = I.second + PltOff; | |
| 2326 | uint64_t Got = B->getGotPltVA(); | |
| 2327 | uint64_t Plt = this->getVA() + Off; | |
| 2328 | Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff); | |
| 2329 | Off += Target->PltEntrySize; | |
| 2366 | // The IPlt is immediately after the Plt, account for this in relOff | |
| 2367 | size_t pltOff = isIplt ? in.plt->getSize() : 0; | |
| 2368 | ||
| 2369 | for (size_t i = 0, e = entries.size(); i != e; ++i) { | |
| 2370 | const Symbol *b = entries[i]; | |
| 2371 | unsigned relOff = relSec->entsize * i + pltOff; | |
| 2372 | uint64_t got = b->getGotPltVA(); | |
| 2373 | uint64_t plt = this->getVA() + off; | |
| 2374 | target->writePlt(buf + off, got, plt, b->pltIndex, relOff); | |
| 2375 | off += target->pltEntrySize; | |
| 2330 | 2376 | } |
| 2331 | 2377 | } |
| 2332 | 2378 | |
| 2333 | template <class ELFT> void PltSection::addEntry(Symbol &Sym) { | |
| 2334 | Sym.PltIndex = Entries.size(); | |
| 2335 | RelocationBaseSection *PltRelocSection = In.RelaPlt; | |
| 2336 | if (IsIplt) { | |
| 2337 | PltRelocSection = In.RelaIplt; | |
| 2338 | Sym.IsInIplt = true; | |
| 2339 | } | |
| 2340 | unsigned RelOff = | |
| 2341 | static_cast<RelocationSection<ELFT> *>(PltRelocSection)->getRelocOffset(); | |
| 2342 | Entries.push_back(std::make_pair(&Sym, RelOff)); | |
| 2379 | template <class ELFT> void PltSection::addEntry(Symbol &sym) { | |
| 2380 | sym.pltIndex = entries.size(); | |
| 2381 | entries.push_back(&sym); | |
| 2343 | 2382 | } |
| 2344 | 2383 | |
| 2345 | 2384 | size_t PltSection::getSize() const { |
| 2346 | return HeaderSize + Entries.size() * Target->PltEntrySize; | |
| 2385 | return headerSize + entries.size() * target->pltEntrySize; | |
| 2347 | 2386 | } |
| 2348 | 2387 | |
| 2349 | 2388 | // Some architectures such as additional symbols in the PLT section. For |
| 2350 | 2389 | // example ARM uses mapping symbols to aid disassembly |
| 2351 | 2390 | void PltSection::addSymbols() { |
| 2352 | 2391 | // The PLT may have symbols defined for the Header, the IPLT has no header |
| 2353 | if (!IsIplt) | |
| 2354 | Target->addPltHeaderSymbols(*this); | |
| 2355 | size_t Off = HeaderSize; | |
| 2356 | for (size_t I = 0; I < Entries.size(); ++I) { | |
| 2357 | Target->addPltSymbols(*this, Off); | |
| 2358 | Off += Target->PltEntrySize; | |
| 2359 | } | |
| 2360 | } | |
| 2392 | if (!isIplt) | |
| 2393 | target->addPltHeaderSymbols(*this); | |
| 2361 | 2394 | |
| 2362 | unsigned PltSection::getPltRelocOff() const { | |
| 2363 | return IsIplt ? In.Plt->getSize() : 0; | |
| 2395 | size_t off = headerSize; | |
| 2396 | for (size_t i = 0; i < entries.size(); ++i) { | |
| 2397 | target->addPltSymbols(*this, off); | |
| 2398 | off += target->pltEntrySize; | |
| 2399 | } | |
| 2364 | 2400 | } |
| 2365 | 2401 | |
| 2366 | 2402 | // The string hash function for .gdb_index. |
| 2367 | static uint32_t computeGdbHash(StringRef S) { | |
| 2368 | uint32_t H = 0; | |
| 2369 | for (uint8_t C : S) | |
| 2370 | H = H * 67 + toLower(C) - 113; | |
| 2371 | return H; | |
| 2403 | static uint32_t computeGdbHash(StringRef s) { | |
| 2404 | uint32_t h = 0; | |
| 2405 | for (uint8_t c : s) | |
| 2406 | h = h * 67 + toLower(c) - 113; | |
| 2407 | return h; | |
| 2372 | 2408 | } |
| 2373 | 2409 | |
| 2374 | 2410 | GdbIndexSection::GdbIndexSection() |
| ... | ... | @@ -2377,367 +2413,384 @@ GdbIndexSection::GdbIndexSection() |
| 2377 | 2413 | // Returns the desired size of an on-disk hash table for a .gdb_index section. |
| 2378 | 2414 | // There's a tradeoff between size and collision rate. We aim 75% utilization. |
| 2379 | 2415 | size_t GdbIndexSection::computeSymtabSize() const { |
| 2380 | return std::max<size_t>(NextPowerOf2(Symbols.size() * 4 / 3), 1024); | |
| 2416 | return std::max<size_t>(NextPowerOf2(symbols.size() * 4 / 3), 1024); | |
| 2381 | 2417 | } |
| 2382 | 2418 | |
| 2383 | 2419 | // Compute the output section size. |
| 2384 | 2420 | void GdbIndexSection::initOutputSize() { |
| 2385 | Size = sizeof(GdbIndexHeader) + computeSymtabSize() * 8; | |
| 2421 | size = sizeof(GdbIndexHeader) + computeSymtabSize() * 8; | |
| 2386 | 2422 | |
| 2387 | for (GdbChunk &Chunk : Chunks) | |
| 2388 | Size += Chunk.CompilationUnits.size() * 16 + Chunk.AddressAreas.size() * 20; | |
| 2423 | for (GdbChunk &chunk : chunks) | |
| 2424 | size += chunk.compilationUnits.size() * 16 + chunk.addressAreas.size() * 20; | |
| 2389 | 2425 | |
| 2390 | 2426 | // Add the constant pool size if exists. |
| 2391 | if (!Symbols.empty()) { | |
| 2392 | GdbSymbol &Sym = Symbols.back(); | |
| 2393 | Size += Sym.NameOff + Sym.Name.size() + 1; | |
| 2427 | if (!symbols.empty()) { | |
| 2428 | GdbSymbol &sym = symbols.back(); | |
| 2429 | size += sym.nameOff + sym.name.size() + 1; | |
| 2394 | 2430 | } |
| 2395 | 2431 | } |
| 2396 | 2432 | |
| 2397 | 2433 | static std::vector<InputSection *> getDebugInfoSections() { |
| 2398 | std::vector<InputSection *> Ret; | |
| 2399 | for (InputSectionBase *S : InputSections) | |
| 2400 | if (InputSection *IS = dyn_cast<InputSection>(S)) | |
| 2401 | if (IS->Name == ".debug_info") | |
| 2402 | Ret.push_back(IS); | |
| 2403 | return Ret; | |
| 2434 | std::vector<InputSection *> ret; | |
| 2435 | for (InputSectionBase *s : inputSections) | |
| 2436 | if (InputSection *isec = dyn_cast<InputSection>(s)) | |
| 2437 | if (isec->name == ".debug_info") | |
| 2438 | ret.push_back(isec); | |
| 2439 | return ret; | |
| 2404 | 2440 | } |
| 2405 | 2441 | |
| 2406 | static std::vector<GdbIndexSection::CuEntry> readCuList(DWARFContext &Dwarf) { | |
| 2407 | std::vector<GdbIndexSection::CuEntry> Ret; | |
| 2408 | for (std::unique_ptr<DWARFUnit> &Cu : Dwarf.compile_units()) | |
| 2409 | Ret.push_back({Cu->getOffset(), Cu->getLength() + 4}); | |
| 2410 | return Ret; | |
| 2442 | static std::vector<GdbIndexSection::CuEntry> readCuList(DWARFContext &dwarf) { | |
| 2443 | std::vector<GdbIndexSection::CuEntry> ret; | |
| 2444 | for (std::unique_ptr<DWARFUnit> &cu : dwarf.compile_units()) | |
| 2445 | ret.push_back({cu->getOffset(), cu->getLength() + 4}); | |
| 2446 | return ret; | |
| 2411 | 2447 | } |
| 2412 | 2448 | |
| 2413 | 2449 | static std::vector<GdbIndexSection::AddressEntry> |
| 2414 | readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) { | |
| 2415 | std::vector<GdbIndexSection::AddressEntry> Ret; | |
| 2416 | ||
| 2417 | uint32_t CuIdx = 0; | |
| 2418 | for (std::unique_ptr<DWARFUnit> &Cu : Dwarf.compile_units()) { | |
| 2419 | Expected<DWARFAddressRangesVector> Ranges = Cu->collectAddressRanges(); | |
| 2420 | if (!Ranges) { | |
| 2421 | error(toString(Sec) + ": " + toString(Ranges.takeError())); | |
| 2450 | readAddressAreas(DWARFContext &dwarf, InputSection *sec) { | |
| 2451 | std::vector<GdbIndexSection::AddressEntry> ret; | |
| 2452 | ||
| 2453 | uint32_t cuIdx = 0; | |
| 2454 | for (std::unique_ptr<DWARFUnit> &cu : dwarf.compile_units()) { | |
| 2455 | Expected<DWARFAddressRangesVector> ranges = cu->collectAddressRanges(); | |
| 2456 | if (!ranges) { | |
| 2457 | error(toString(sec) + ": " + toString(ranges.takeError())); | |
| 2422 | 2458 | return {}; |
| 2423 | 2459 | } |
| 2424 | 2460 | |
| 2425 | ArrayRef<InputSectionBase *> Sections = Sec->File->getSections(); | |
| 2426 | for (DWARFAddressRange &R : *Ranges) { | |
| 2427 | InputSectionBase *S = Sections[R.SectionIndex]; | |
| 2428 | if (!S || S == &InputSection::Discarded || !S->Live) | |
| 2461 | ArrayRef<InputSectionBase *> sections = sec->file->getSections(); | |
| 2462 | for (DWARFAddressRange &r : *ranges) { | |
| 2463 | if (r.SectionIndex == -1ULL) | |
| 2464 | continue; | |
| 2465 | InputSectionBase *s = sections[r.SectionIndex]; | |
| 2466 | if (!s || s == &InputSection::discarded || !s->isLive()) | |
| 2429 | 2467 | continue; |
| 2430 | 2468 | // Range list with zero size has no effect. |
| 2431 | if (R.LowPC == R.HighPC) | |
| 2469 | if (r.LowPC == r.HighPC) | |
| 2432 | 2470 | continue; |
| 2433 | auto *IS = cast<InputSection>(S); | |
| 2434 | uint64_t Offset = IS->getOffsetInFile(); | |
| 2435 | Ret.push_back({IS, R.LowPC - Offset, R.HighPC - Offset, CuIdx}); | |
| 2471 | auto *isec = cast<InputSection>(s); | |
| 2472 | uint64_t offset = isec->getOffsetInFile(); | |
| 2473 | ret.push_back({isec, r.LowPC - offset, r.HighPC - offset, cuIdx}); | |
| 2436 | 2474 | } |
| 2437 | ++CuIdx; | |
| 2475 | ++cuIdx; | |
| 2438 | 2476 | } |
| 2439 | 2477 | |
| 2440 | return Ret; | |
| 2478 | return ret; | |
| 2441 | 2479 | } |
| 2442 | 2480 | |
| 2443 | 2481 | template <class ELFT> |
| 2444 | 2482 | static std::vector<GdbIndexSection::NameAttrEntry> |
| 2445 | readPubNamesAndTypes(const LLDDwarfObj<ELFT> &Obj, | |
| 2446 | const std::vector<GdbIndexSection::CuEntry> &CUs) { | |
| 2447 | const DWARFSection &PubNames = Obj.getGnuPubNamesSection(); | |
| 2448 | const DWARFSection &PubTypes = Obj.getGnuPubTypesSection(); | |
| 2449 | ||
| 2450 | std::vector<GdbIndexSection::NameAttrEntry> Ret; | |
| 2451 | for (const DWARFSection *Pub : {&PubNames, &PubTypes}) { | |
| 2452 | DWARFDebugPubTable Table(Obj, *Pub, Config->IsLE, true); | |
| 2453 | for (const DWARFDebugPubTable::Set &Set : Table.getData()) { | |
| 2454 | // The value written into the constant pool is Kind << 24 | CuIndex. As we | |
| 2483 | readPubNamesAndTypes(const LLDDwarfObj<ELFT> &obj, | |
| 2484 | const std::vector<GdbIndexSection::CuEntry> &cUs) { | |
| 2485 | const DWARFSection &pubNames = obj.getGnuPubNamesSection(); | |
| 2486 | const DWARFSection &pubTypes = obj.getGnuPubTypesSection(); | |
| 2487 | ||
| 2488 | std::vector<GdbIndexSection::NameAttrEntry> ret; | |
| 2489 | for (const DWARFSection *pub : {&pubNames, &pubTypes}) { | |
| 2490 | DWARFDebugPubTable table(obj, *pub, config->isLE, true); | |
| 2491 | for (const DWARFDebugPubTable::Set &set : table.getData()) { | |
| 2492 | // The value written into the constant pool is kind << 24 | cuIndex. As we | |
| 2455 | 2493 | // don't know how many compilation units precede this object to compute |
| 2456 | // CuIndex, we compute (Kind << 24 | CuIndexInThisObject) instead, and add | |
| 2494 | // cuIndex, we compute (kind << 24 | cuIndexInThisObject) instead, and add | |
| 2457 | 2495 | // the number of preceding compilation units later. |
| 2458 | uint32_t I = | |
| 2459 | lower_bound(CUs, Set.Offset, | |
| 2460 | [](GdbIndexSection::CuEntry CU, uint32_t Offset) { | |
| 2461 | return CU.CuOffset < Offset; | |
| 2496 | uint32_t i = | |
| 2497 | lower_bound(cUs, set.Offset, | |
| 2498 | [](GdbIndexSection::CuEntry cu, uint32_t offset) { | |
| 2499 | return cu.cuOffset < offset; | |
| 2462 | 2500 | }) - |
| 2463 | CUs.begin(); | |
| 2464 | for (const DWARFDebugPubTable::Entry &Ent : Set.Entries) | |
| 2465 | Ret.push_back({{Ent.Name, computeGdbHash(Ent.Name)}, | |
| 2466 | (Ent.Descriptor.toBits() << 24) | I}); | |
| 2501 | cUs.begin(); | |
| 2502 | for (const DWARFDebugPubTable::Entry &ent : set.Entries) | |
| 2503 | ret.push_back({{ent.Name, computeGdbHash(ent.Name)}, | |
| 2504 | (ent.Descriptor.toBits() << 24) | i}); | |
| 2467 | 2505 | } |
| 2468 | 2506 | } |
| 2469 | return Ret; | |
| 2507 | return ret; | |
| 2470 | 2508 | } |
| 2471 | 2509 | |
| 2472 | 2510 | // Create a list of symbols from a given list of symbol names and types |
| 2473 | 2511 | // by uniquifying them by name. |
| 2474 | 2512 | static std::vector<GdbIndexSection::GdbSymbol> |
| 2475 | createSymbols(ArrayRef<std::vector<GdbIndexSection::NameAttrEntry>> NameAttrs, | |
| 2476 | const std::vector<GdbIndexSection::GdbChunk> &Chunks) { | |
| 2477 | typedef GdbIndexSection::GdbSymbol GdbSymbol; | |
| 2478 | typedef GdbIndexSection::NameAttrEntry NameAttrEntry; | |
| 2513 | createSymbols(ArrayRef<std::vector<GdbIndexSection::NameAttrEntry>> nameAttrs, | |
| 2514 | const std::vector<GdbIndexSection::GdbChunk> &chunks) { | |
| 2515 | using GdbSymbol = GdbIndexSection::GdbSymbol; | |
| 2516 | using NameAttrEntry = GdbIndexSection::NameAttrEntry; | |
| 2479 | 2517 | |
| 2480 | 2518 | // For each chunk, compute the number of compilation units preceding it. |
| 2481 | uint32_t CuIdx = 0; | |
| 2482 | std::vector<uint32_t> CuIdxs(Chunks.size()); | |
| 2483 | for (uint32_t I = 0, E = Chunks.size(); I != E; ++I) { | |
| 2484 | CuIdxs[I] = CuIdx; | |
| 2485 | CuIdx += Chunks[I].CompilationUnits.size(); | |
| 2519 | uint32_t cuIdx = 0; | |
| 2520 | std::vector<uint32_t> cuIdxs(chunks.size()); | |
| 2521 | for (uint32_t i = 0, e = chunks.size(); i != e; ++i) { | |
| 2522 | cuIdxs[i] = cuIdx; | |
| 2523 | cuIdx += chunks[i].compilationUnits.size(); | |
| 2486 | 2524 | } |
| 2487 | 2525 | |
| 2488 | 2526 | // The number of symbols we will handle in this function is of the order |
| 2489 | 2527 | // of millions for very large executables, so we use multi-threading to |
| 2490 | 2528 | // speed it up. |
| 2491 | size_t NumShards = 32; | |
| 2492 | size_t Concurrency = 1; | |
| 2493 | if (ThreadsEnabled) | |
| 2494 | Concurrency = | |
| 2495 | std::min<size_t>(PowerOf2Floor(hardware_concurrency()), NumShards); | |
| 2529 | size_t numShards = 32; | |
| 2530 | size_t concurrency = 1; | |
| 2531 | if (threadsEnabled) | |
| 2532 | concurrency = | |
| 2533 | std::min<size_t>(PowerOf2Floor(hardware_concurrency()), numShards); | |
| 2496 | 2534 | |
| 2497 | 2535 | // A sharded map to uniquify symbols by name. |
| 2498 | std::vector<DenseMap<CachedHashStringRef, size_t>> Map(NumShards); | |
| 2499 | size_t Shift = 32 - countTrailingZeros(NumShards); | |
| 2536 | std::vector<DenseMap<CachedHashStringRef, size_t>> map(numShards); | |
| 2537 | size_t shift = 32 - countTrailingZeros(numShards); | |
| 2500 | 2538 | |
| 2501 | 2539 | // Instantiate GdbSymbols while uniqufying them by name. |
| 2502 | std::vector<std::vector<GdbSymbol>> Symbols(NumShards); | |
| 2503 | parallelForEachN(0, Concurrency, [&](size_t ThreadId) { | |
| 2504 | uint32_t I = 0; | |
| 2505 | for (ArrayRef<NameAttrEntry> Entries : NameAttrs) { | |
| 2506 | for (const NameAttrEntry &Ent : Entries) { | |
| 2507 | size_t ShardId = Ent.Name.hash() >> Shift; | |
| 2508 | if ((ShardId & (Concurrency - 1)) != ThreadId) | |
| 2540 | std::vector<std::vector<GdbSymbol>> symbols(numShards); | |
| 2541 | parallelForEachN(0, concurrency, [&](size_t threadId) { | |
| 2542 | uint32_t i = 0; | |
| 2543 | for (ArrayRef<NameAttrEntry> entries : nameAttrs) { | |
| 2544 | for (const NameAttrEntry &ent : entries) { | |
| 2545 | size_t shardId = ent.name.hash() >> shift; | |
| 2546 | if ((shardId & (concurrency - 1)) != threadId) | |
| 2509 | 2547 | continue; |
| 2510 | 2548 | |
| 2511 | uint32_t V = Ent.CuIndexAndAttrs + CuIdxs[I]; | |
| 2512 | size_t &Idx = Map[ShardId][Ent.Name]; | |
| 2513 | if (Idx) { | |
| 2514 | Symbols[ShardId][Idx - 1].CuVector.push_back(V); | |
| 2549 | uint32_t v = ent.cuIndexAndAttrs + cuIdxs[i]; | |
| 2550 | size_t &idx = map[shardId][ent.name]; | |
| 2551 | if (idx) { | |
| 2552 | symbols[shardId][idx - 1].cuVector.push_back(v); | |
| 2515 | 2553 | continue; |
| 2516 | 2554 | } |
| 2517 | 2555 | |
| 2518 | Idx = Symbols[ShardId].size() + 1; | |
| 2519 | Symbols[ShardId].push_back({Ent.Name, {V}, 0, 0}); | |
| 2556 | idx = symbols[shardId].size() + 1; | |
| 2557 | symbols[shardId].push_back({ent.name, {v}, 0, 0}); | |
| 2520 | 2558 | } |
| 2521 | ++I; | |
| 2559 | ++i; | |
| 2522 | 2560 | } |
| 2523 | 2561 | }); |
| 2524 | 2562 | |
| 2525 | size_t NumSymbols = 0; | |
| 2526 | for (ArrayRef<GdbSymbol> V : Symbols) | |
| 2527 | NumSymbols += V.size(); | |
| 2563 | size_t numSymbols = 0; | |
| 2564 | for (ArrayRef<GdbSymbol> v : symbols) | |
| 2565 | numSymbols += v.size(); | |
| 2528 | 2566 | |
| 2529 | 2567 | // The return type is a flattened vector, so we'll copy each vector |
| 2530 | 2568 | // contents to Ret. |
| 2531 | std::vector<GdbSymbol> Ret; | |
| 2532 | Ret.reserve(NumSymbols); | |
| 2533 | for (std::vector<GdbSymbol> &Vec : Symbols) | |
| 2534 | for (GdbSymbol &Sym : Vec) | |
| 2535 | Ret.push_back(std::move(Sym)); | |
| 2569 | std::vector<GdbSymbol> ret; | |
| 2570 | ret.reserve(numSymbols); | |
| 2571 | for (std::vector<GdbSymbol> &vec : symbols) | |
| 2572 | for (GdbSymbol &sym : vec) | |
| 2573 | ret.push_back(std::move(sym)); | |
| 2536 | 2574 | |
| 2537 | 2575 | // CU vectors and symbol names are adjacent in the output file. |
| 2538 | 2576 | // We can compute their offsets in the output file now. |
| 2539 | size_t Off = 0; | |
| 2540 | for (GdbSymbol &Sym : Ret) { | |
| 2541 | Sym.CuVectorOff = Off; | |
| 2542 | Off += (Sym.CuVector.size() + 1) * 4; | |
| 2577 | size_t off = 0; | |
| 2578 | for (GdbSymbol &sym : ret) { | |
| 2579 | sym.cuVectorOff = off; | |
| 2580 | off += (sym.cuVector.size() + 1) * 4; | |
| 2543 | 2581 | } |
| 2544 | for (GdbSymbol &Sym : Ret) { | |
| 2545 | Sym.NameOff = Off; | |
| 2546 | Off += Sym.Name.size() + 1; | |
| 2582 | for (GdbSymbol &sym : ret) { | |
| 2583 | sym.nameOff = off; | |
| 2584 | off += sym.name.size() + 1; | |
| 2547 | 2585 | } |
| 2548 | 2586 | |
| 2549 | return Ret; | |
| 2587 | return ret; | |
| 2550 | 2588 | } |
| 2551 | 2589 | |
| 2552 | 2590 | // Returns a newly-created .gdb_index section. |
| 2553 | 2591 | template <class ELFT> GdbIndexSection *GdbIndexSection::create() { |
| 2554 | std::vector<InputSection *> Sections = getDebugInfoSections(); | |
| 2592 | std::vector<InputSection *> sections = getDebugInfoSections(); | |
| 2555 | 2593 | |
| 2556 | 2594 | // .debug_gnu_pub{names,types} are useless in executables. |
| 2557 | 2595 | // They are present in input object files solely for creating |
| 2558 | 2596 | // a .gdb_index. So we can remove them from the output. |
| 2559 | for (InputSectionBase *S : InputSections) | |
| 2560 | if (S->Name == ".debug_gnu_pubnames" || S->Name == ".debug_gnu_pubtypes") | |
| 2561 | S->Live = false; | |
| 2562 | ||
| 2563 | std::vector<GdbChunk> Chunks(Sections.size()); | |
| 2564 | std::vector<std::vector<NameAttrEntry>> NameAttrs(Sections.size()); | |
| 2565 | ||
| 2566 | parallelForEachN(0, Sections.size(), [&](size_t I) { | |
| 2567 | ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>(); | |
| 2568 | DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File)); | |
| 2569 | ||
| 2570 | Chunks[I].Sec = Sections[I]; | |
| 2571 | Chunks[I].CompilationUnits = readCuList(Dwarf); | |
| 2572 | Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]); | |
| 2573 | NameAttrs[I] = readPubNamesAndTypes<ELFT>( | |
| 2574 | static_cast<const LLDDwarfObj<ELFT> &>(Dwarf.getDWARFObj()), | |
| 2575 | Chunks[I].CompilationUnits); | |
| 2597 | for (InputSectionBase *s : inputSections) | |
| 2598 | if (s->name == ".debug_gnu_pubnames" || s->name == ".debug_gnu_pubtypes") | |
| 2599 | s->markDead(); | |
| 2600 | ||
| 2601 | std::vector<GdbChunk> chunks(sections.size()); | |
| 2602 | std::vector<std::vector<NameAttrEntry>> nameAttrs(sections.size()); | |
| 2603 | ||
| 2604 | parallelForEachN(0, sections.size(), [&](size_t i) { | |
| 2605 | ObjFile<ELFT> *file = sections[i]->getFile<ELFT>(); | |
| 2606 | DWARFContext dwarf(make_unique<LLDDwarfObj<ELFT>>(file)); | |
| 2607 | ||
| 2608 | chunks[i].sec = sections[i]; | |
| 2609 | chunks[i].compilationUnits = readCuList(dwarf); | |
| 2610 | chunks[i].addressAreas = readAddressAreas(dwarf, sections[i]); | |
| 2611 | nameAttrs[i] = readPubNamesAndTypes<ELFT>( | |
| 2612 | static_cast<const LLDDwarfObj<ELFT> &>(dwarf.getDWARFObj()), | |
| 2613 | chunks[i].compilationUnits); | |
| 2576 | 2614 | }); |
| 2577 | 2615 | |
| 2578 | auto *Ret = make<GdbIndexSection>(); | |
| 2579 | Ret->Chunks = std::move(Chunks); | |
| 2580 | Ret->Symbols = createSymbols(NameAttrs, Ret->Chunks); | |
| 2581 | Ret->initOutputSize(); | |
| 2582 | return Ret; | |
| 2616 | auto *ret = make<GdbIndexSection>(); | |
| 2617 | ret->chunks = std::move(chunks); | |
| 2618 | ret->symbols = createSymbols(nameAttrs, ret->chunks); | |
| 2619 | ret->initOutputSize(); | |
| 2620 | return ret; | |
| 2583 | 2621 | } |
| 2584 | 2622 | |
| 2585 | void GdbIndexSection::writeTo(uint8_t *Buf) { | |
| 2623 | void GdbIndexSection::writeTo(uint8_t *buf) { | |
| 2586 | 2624 | // Write the header. |
| 2587 | auto *Hdr = reinterpret_cast<GdbIndexHeader *>(Buf); | |
| 2588 | uint8_t *Start = Buf; | |
| 2589 | Hdr->Version = 7; | |
| 2590 | Buf += sizeof(*Hdr); | |
| 2625 | auto *hdr = reinterpret_cast<GdbIndexHeader *>(buf); | |
| 2626 | uint8_t *start = buf; | |
| 2627 | hdr->version = 7; | |
| 2628 | buf += sizeof(*hdr); | |
| 2591 | 2629 | |
| 2592 | 2630 | // Write the CU list. |
| 2593 | Hdr->CuListOff = Buf - Start; | |
| 2594 | for (GdbChunk &Chunk : Chunks) { | |
| 2595 | for (CuEntry &Cu : Chunk.CompilationUnits) { | |
| 2596 | write64le(Buf, Chunk.Sec->OutSecOff + Cu.CuOffset); | |
| 2597 | write64le(Buf + 8, Cu.CuLength); | |
| 2598 | Buf += 16; | |
| 2631 | hdr->cuListOff = buf - start; | |
| 2632 | for (GdbChunk &chunk : chunks) { | |
| 2633 | for (CuEntry &cu : chunk.compilationUnits) { | |
| 2634 | write64le(buf, chunk.sec->outSecOff + cu.cuOffset); | |
| 2635 | write64le(buf + 8, cu.cuLength); | |
| 2636 | buf += 16; | |
| 2599 | 2637 | } |
| 2600 | 2638 | } |
| 2601 | 2639 | |
| 2602 | 2640 | // Write the address area. |
| 2603 | Hdr->CuTypesOff = Buf - Start; | |
| 2604 | Hdr->AddressAreaOff = Buf - Start; | |
| 2605 | uint32_t CuOff = 0; | |
| 2606 | for (GdbChunk &Chunk : Chunks) { | |
| 2607 | for (AddressEntry &E : Chunk.AddressAreas) { | |
| 2608 | uint64_t BaseAddr = E.Section->getVA(0); | |
| 2609 | write64le(Buf, BaseAddr + E.LowAddress); | |
| 2610 | write64le(Buf + 8, BaseAddr + E.HighAddress); | |
| 2611 | write32le(Buf + 16, E.CuIndex + CuOff); | |
| 2612 | Buf += 20; | |
| 2641 | hdr->cuTypesOff = buf - start; | |
| 2642 | hdr->addressAreaOff = buf - start; | |
| 2643 | uint32_t cuOff = 0; | |
| 2644 | for (GdbChunk &chunk : chunks) { | |
| 2645 | for (AddressEntry &e : chunk.addressAreas) { | |
| 2646 | uint64_t baseAddr = e.section->getVA(0); | |
| 2647 | write64le(buf, baseAddr + e.lowAddress); | |
| 2648 | write64le(buf + 8, baseAddr + e.highAddress); | |
| 2649 | write32le(buf + 16, e.cuIndex + cuOff); | |
| 2650 | buf += 20; | |
| 2613 | 2651 | } |
| 2614 | CuOff += Chunk.CompilationUnits.size(); | |
| 2652 | cuOff += chunk.compilationUnits.size(); | |
| 2615 | 2653 | } |
| 2616 | 2654 | |
| 2617 | 2655 | // Write the on-disk open-addressing hash table containing symbols. |
| 2618 | Hdr->SymtabOff = Buf - Start; | |
| 2619 | size_t SymtabSize = computeSymtabSize(); | |
| 2620 | uint32_t Mask = SymtabSize - 1; | |
| 2656 | hdr->symtabOff = buf - start; | |
| 2657 | size_t symtabSize = computeSymtabSize(); | |
| 2658 | uint32_t mask = symtabSize - 1; | |
| 2621 | 2659 | |
| 2622 | for (GdbSymbol &Sym : Symbols) { | |
| 2623 | uint32_t H = Sym.Name.hash(); | |
| 2624 | uint32_t I = H & Mask; | |
| 2625 | uint32_t Step = ((H * 17) & Mask) | 1; | |
| 2660 | for (GdbSymbol &sym : symbols) { | |
| 2661 | uint32_t h = sym.name.hash(); | |
| 2662 | uint32_t i = h & mask; | |
| 2663 | uint32_t step = ((h * 17) & mask) | 1; | |
| 2626 | 2664 | |
| 2627 | while (read32le(Buf + I * 8)) | |
| 2628 | I = (I + Step) & Mask; | |
| 2665 | while (read32le(buf + i * 8)) | |
| 2666 | i = (i + step) & mask; | |
| 2629 | 2667 | |
| 2630 | write32le(Buf + I * 8, Sym.NameOff); | |
| 2631 | write32le(Buf + I * 8 + 4, Sym.CuVectorOff); | |
| 2668 | write32le(buf + i * 8, sym.nameOff); | |
| 2669 | write32le(buf + i * 8 + 4, sym.cuVectorOff); | |
| 2632 | 2670 | } |
| 2633 | 2671 | |
| 2634 | Buf += SymtabSize * 8; | |
| 2672 | buf += symtabSize * 8; | |
| 2635 | 2673 | |
| 2636 | 2674 | // Write the string pool. |
| 2637 | Hdr->ConstantPoolOff = Buf - Start; | |
| 2638 | parallelForEach(Symbols, [&](GdbSymbol &Sym) { | |
| 2639 | memcpy(Buf + Sym.NameOff, Sym.Name.data(), Sym.Name.size()); | |
| 2675 | hdr->constantPoolOff = buf - start; | |
| 2676 | parallelForEach(symbols, [&](GdbSymbol &sym) { | |
| 2677 | memcpy(buf + sym.nameOff, sym.name.data(), sym.name.size()); | |
| 2640 | 2678 | }); |
| 2641 | 2679 | |
| 2642 | 2680 | // Write the CU vectors. |
| 2643 | for (GdbSymbol &Sym : Symbols) { | |
| 2644 | write32le(Buf, Sym.CuVector.size()); | |
| 2645 | Buf += 4; | |
| 2646 | for (uint32_t Val : Sym.CuVector) { | |
| 2647 | write32le(Buf, Val); | |
| 2648 | Buf += 4; | |
| 2681 | for (GdbSymbol &sym : symbols) { | |
| 2682 | write32le(buf, sym.cuVector.size()); | |
| 2683 | buf += 4; | |
| 2684 | for (uint32_t val : sym.cuVector) { | |
| 2685 | write32le(buf, val); | |
| 2686 | buf += 4; | |
| 2649 | 2687 | } |
| 2650 | 2688 | } |
| 2651 | 2689 | } |
| 2652 | 2690 | |
| 2653 | bool GdbIndexSection::empty() const { return Chunks.empty(); } | |
| 2691 | bool GdbIndexSection::isNeeded() const { return !chunks.empty(); } | |
| 2654 | 2692 | |
| 2655 | 2693 | EhFrameHeader::EhFrameHeader() |
| 2656 | 2694 | : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".eh_frame_hdr") {} |
| 2657 | 2695 | |
| 2696 | void EhFrameHeader::writeTo(uint8_t *buf) { | |
| 2697 | // Unlike most sections, the EhFrameHeader section is written while writing | |
| 2698 | // another section, namely EhFrameSection, which calls the write() function | |
| 2699 | // below from its writeTo() function. This is necessary because the contents | |
| 2700 | // of EhFrameHeader depend on the relocated contents of EhFrameSection and we | |
| 2701 | // don't know which order the sections will be written in. | |
| 2702 | } | |
| 2703 | ||
| 2658 | 2704 | // .eh_frame_hdr contains a binary search table of pointers to FDEs. |
| 2659 | 2705 | // Each entry of the search table consists of two values, |
| 2660 | 2706 | // the starting PC from where FDEs covers, and the FDE's address. |
| 2661 | 2707 | // It is sorted by PC. |
| 2662 | void EhFrameHeader::writeTo(uint8_t *Buf) { | |
| 2663 | typedef EhFrameSection::FdeData FdeData; | |
| 2708 | void EhFrameHeader::write() { | |
| 2709 | uint8_t *buf = Out::bufferStart + getParent()->offset + outSecOff; | |
| 2710 | using FdeData = EhFrameSection::FdeData; | |
| 2664 | 2711 | |
| 2665 | std::vector<FdeData> Fdes = In.EhFrame->getFdeData(); | |
| 2712 | std::vector<FdeData> fdes = getPartition().ehFrame->getFdeData(); | |
| 2666 | 2713 | |
| 2667 | Buf[0] = 1; | |
| 2668 | Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; | |
| 2669 | Buf[2] = DW_EH_PE_udata4; | |
| 2670 | Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; | |
| 2671 | write32(Buf + 4, In.EhFrame->getParent()->Addr - this->getVA() - 4); | |
| 2672 | write32(Buf + 8, Fdes.size()); | |
| 2673 | Buf += 12; | |
| 2714 | buf[0] = 1; | |
| 2715 | buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; | |
| 2716 | buf[2] = DW_EH_PE_udata4; | |
| 2717 | buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; | |
| 2718 | write32(buf + 4, | |
| 2719 | getPartition().ehFrame->getParent()->addr - this->getVA() - 4); | |
| 2720 | write32(buf + 8, fdes.size()); | |
| 2721 | buf += 12; | |
| 2674 | 2722 | |
| 2675 | for (FdeData &Fde : Fdes) { | |
| 2676 | write32(Buf, Fde.PcRel); | |
| 2677 | write32(Buf + 4, Fde.FdeVARel); | |
| 2678 | Buf += 8; | |
| 2723 | for (FdeData &fde : fdes) { | |
| 2724 | write32(buf, fde.pcRel); | |
| 2725 | write32(buf + 4, fde.fdeVARel); | |
| 2726 | buf += 8; | |
| 2679 | 2727 | } |
| 2680 | 2728 | } |
| 2681 | 2729 | |
| 2682 | 2730 | size_t EhFrameHeader::getSize() const { |
| 2683 | 2731 | // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs. |
| 2684 | return 12 + In.EhFrame->NumFdes * 8; | |
| 2732 | return 12 + getPartition().ehFrame->numFdes * 8; | |
| 2685 | 2733 | } |
| 2686 | 2734 | |
| 2687 | bool EhFrameHeader::empty() const { return In.EhFrame->empty(); } | |
| 2735 | bool EhFrameHeader::isNeeded() const { | |
| 2736 | return isLive() && getPartition().ehFrame->isNeeded(); | |
| 2737 | } | |
| 2688 | 2738 | |
| 2689 | 2739 | VersionDefinitionSection::VersionDefinitionSection() |
| 2690 | 2740 | : SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t), |
| 2691 | 2741 | ".gnu.version_d") {} |
| 2692 | 2742 | |
| 2693 | static StringRef getFileDefName() { | |
| 2694 | if (!Config->SoName.empty()) | |
| 2695 | return Config->SoName; | |
| 2696 | return Config->OutputFile; | |
| 2743 | StringRef VersionDefinitionSection::getFileDefName() { | |
| 2744 | if (!getPartition().name.empty()) | |
| 2745 | return getPartition().name; | |
| 2746 | if (!config->soName.empty()) | |
| 2747 | return config->soName; | |
| 2748 | return config->outputFile; | |
| 2697 | 2749 | } |
| 2698 | 2750 | |
| 2699 | 2751 | void VersionDefinitionSection::finalizeContents() { |
| 2700 | FileDefNameOff = In.DynStrTab->addString(getFileDefName()); | |
| 2701 | for (VersionDefinition &V : Config->VersionDefinitions) | |
| 2702 | V.NameOff = In.DynStrTab->addString(V.Name); | |
| 2752 | fileDefNameOff = getPartition().dynStrTab->addString(getFileDefName()); | |
| 2753 | for (VersionDefinition &v : config->versionDefinitions) | |
| 2754 | verDefNameOffs.push_back(getPartition().dynStrTab->addString(v.name)); | |
| 2703 | 2755 | |
| 2704 | if (OutputSection *Sec = In.DynStrTab->getParent()) | |
| 2705 | getParent()->Link = Sec->SectionIndex; | |
| 2756 | if (OutputSection *sec = getPartition().dynStrTab->getParent()) | |
| 2757 | getParent()->link = sec->sectionIndex; | |
| 2706 | 2758 | |
| 2707 | 2759 | // sh_info should be set to the number of definitions. This fact is missed in |
| 2708 | 2760 | // documentation, but confirmed by binutils community: |
| 2709 | 2761 | // https://sourceware.org/ml/binutils/2014-11/msg00355.html |
| 2710 | getParent()->Info = getVerDefNum(); | |
| 2762 | getParent()->info = getVerDefNum(); | |
| 2711 | 2763 | } |
| 2712 | 2764 | |
| 2713 | void VersionDefinitionSection::writeOne(uint8_t *Buf, uint32_t Index, | |
| 2714 | StringRef Name, size_t NameOff) { | |
| 2715 | uint16_t Flags = Index == 1 ? VER_FLG_BASE : 0; | |
| 2765 | void VersionDefinitionSection::writeOne(uint8_t *buf, uint32_t index, | |
| 2766 | StringRef name, size_t nameOff) { | |
| 2767 | uint16_t flags = index == 1 ? VER_FLG_BASE : 0; | |
| 2716 | 2768 | |
| 2717 | 2769 | // Write a verdef. |
| 2718 | write16(Buf, 1); // vd_version | |
| 2719 | write16(Buf + 2, Flags); // vd_flags | |
| 2720 | write16(Buf + 4, Index); // vd_ndx | |
| 2721 | write16(Buf + 6, 1); // vd_cnt | |
| 2722 | write32(Buf + 8, hashSysV(Name)); // vd_hash | |
| 2723 | write32(Buf + 12, 20); // vd_aux | |
| 2724 | write32(Buf + 16, 28); // vd_next | |
| 2770 | write16(buf, 1); // vd_version | |
| 2771 | write16(buf + 2, flags); // vd_flags | |
| 2772 | write16(buf + 4, index); // vd_ndx | |
| 2773 | write16(buf + 6, 1); // vd_cnt | |
| 2774 | write32(buf + 8, hashSysV(name)); // vd_hash | |
| 2775 | write32(buf + 12, 20); // vd_aux | |
| 2776 | write32(buf + 16, 28); // vd_next | |
| 2725 | 2777 | |
| 2726 | 2778 | // Write a veraux. |
| 2727 | write32(Buf + 20, NameOff); // vda_name | |
| 2728 | write32(Buf + 24, 0); // vda_next | |
| 2779 | write32(buf + 20, nameOff); // vda_name | |
| 2780 | write32(buf + 24, 0); // vda_next | |
| 2729 | 2781 | } |
| 2730 | 2782 | |
| 2731 | void VersionDefinitionSection::writeTo(uint8_t *Buf) { | |
| 2732 | writeOne(Buf, 1, getFileDefName(), FileDefNameOff); | |
| 2783 | void VersionDefinitionSection::writeTo(uint8_t *buf) { | |
| 2784 | writeOne(buf, 1, getFileDefName(), fileDefNameOff); | |
| 2733 | 2785 | |
| 2734 | for (VersionDefinition &V : Config->VersionDefinitions) { | |
| 2735 | Buf += EntrySize; | |
| 2736 | writeOne(Buf, V.Id, V.Name, V.NameOff); | |
| 2786 | auto nameOffIt = verDefNameOffs.begin(); | |
| 2787 | for (VersionDefinition &v : config->versionDefinitions) { | |
| 2788 | buf += EntrySize; | |
| 2789 | writeOne(buf, v.id, v.name, *nameOffIt++); | |
| 2737 | 2790 | } |
| 2738 | 2791 | |
| 2739 | 2792 | // Need to terminate the last version definition. |
| 2740 | write32(Buf + 16, 0); // vd_next | |
| 2793 | write32(buf + 16, 0); // vd_next | |
| 2741 | 2794 | } |
| 2742 | 2795 | |
| 2743 | 2796 | size_t VersionDefinitionSection::getSize() const { |
| ... | ... | @@ -2745,160 +2798,161 @@ size_t VersionDefinitionSection::getSize() const { |
| 2745 | 2798 | } |
| 2746 | 2799 | |
| 2747 | 2800 | // .gnu.version is a table where each entry is 2 byte long. |
| 2748 | template <class ELFT> | |
| 2749 | VersionTableSection<ELFT>::VersionTableSection() | |
| 2801 | VersionTableSection::VersionTableSection() | |
| 2750 | 2802 | : SyntheticSection(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t), |
| 2751 | 2803 | ".gnu.version") { |
| 2752 | this->Entsize = 2; | |
| 2804 | this->entsize = 2; | |
| 2753 | 2805 | } |
| 2754 | 2806 | |
| 2755 | template <class ELFT> void VersionTableSection<ELFT>::finalizeContents() { | |
| 2807 | void VersionTableSection::finalizeContents() { | |
| 2756 | 2808 | // At the moment of june 2016 GNU docs does not mention that sh_link field |
| 2757 | 2809 | // should be set, but Sun docs do. Also readelf relies on this field. |
| 2758 | getParent()->Link = In.DynSymTab->getParent()->SectionIndex; | |
| 2810 | getParent()->link = getPartition().dynSymTab->getParent()->sectionIndex; | |
| 2759 | 2811 | } |
| 2760 | 2812 | |
| 2761 | template <class ELFT> size_t VersionTableSection<ELFT>::getSize() const { | |
| 2762 | return (In.DynSymTab->getSymbols().size() + 1) * 2; | |
| 2813 | size_t VersionTableSection::getSize() const { | |
| 2814 | return (getPartition().dynSymTab->getSymbols().size() + 1) * 2; | |
| 2763 | 2815 | } |
| 2764 | 2816 | |
| 2765 | template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) { | |
| 2766 | Buf += 2; | |
| 2767 | for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) { | |
| 2768 | write16(Buf, S.Sym->VersionId); | |
| 2769 | Buf += 2; | |
| 2817 | void VersionTableSection::writeTo(uint8_t *buf) { | |
| 2818 | buf += 2; | |
| 2819 | for (const SymbolTableEntry &s : getPartition().dynSymTab->getSymbols()) { | |
| 2820 | write16(buf, s.sym->versionId); | |
| 2821 | buf += 2; | |
| 2770 | 2822 | } |
| 2771 | 2823 | } |
| 2772 | 2824 | |
| 2773 | template <class ELFT> bool VersionTableSection<ELFT>::empty() const { | |
| 2774 | return !In.VerDef && InX<ELFT>::VerNeed->empty(); | |
| 2825 | bool VersionTableSection::isNeeded() const { | |
| 2826 | return getPartition().verDef || getPartition().verNeed->isNeeded(); | |
| 2827 | } | |
| 2828 | ||
| 2829 | void elf::addVerneed(Symbol *ss) { | |
| 2830 | auto &file = cast<SharedFile>(*ss->file); | |
| 2831 | if (ss->verdefIndex == VER_NDX_GLOBAL) { | |
| 2832 | ss->versionId = VER_NDX_GLOBAL; | |
| 2833 | return; | |
| 2834 | } | |
| 2835 | ||
| 2836 | if (file.vernauxs.empty()) | |
| 2837 | file.vernauxs.resize(file.verdefs.size()); | |
| 2838 | ||
| 2839 | // Select a version identifier for the vernaux data structure, if we haven't | |
| 2840 | // already allocated one. The verdef identifiers cover the range | |
| 2841 | // [1..getVerDefNum()]; this causes the vernaux identifiers to start from | |
| 2842 | // getVerDefNum()+1. | |
| 2843 | if (file.vernauxs[ss->verdefIndex] == 0) | |
| 2844 | file.vernauxs[ss->verdefIndex] = ++SharedFile::vernauxNum + getVerDefNum(); | |
| 2845 | ||
| 2846 | ss->versionId = file.vernauxs[ss->verdefIndex]; | |
| 2775 | 2847 | } |
| 2776 | 2848 | |
| 2777 | 2849 | template <class ELFT> |
| 2778 | 2850 | VersionNeedSection<ELFT>::VersionNeedSection() |
| 2779 | 2851 | : SyntheticSection(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t), |
| 2780 | ".gnu.version_r") { | |
| 2781 | // Identifiers in verneed section start at 2 because 0 and 1 are reserved | |
| 2782 | // for VER_NDX_LOCAL and VER_NDX_GLOBAL. | |
| 2783 | // First identifiers are reserved by verdef section if it exist. | |
| 2784 | NextIndex = getVerDefNum() + 1; | |
| 2785 | } | |
| 2852 | ".gnu.version_r") {} | |
| 2786 | 2853 | |
| 2787 | template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) { | |
| 2788 | auto &File = cast<SharedFile<ELFT>>(*SS->File); | |
| 2789 | if (SS->VerdefIndex == VER_NDX_GLOBAL) { | |
| 2790 | SS->VersionId = VER_NDX_GLOBAL; | |
| 2791 | return; | |
| 2854 | template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() { | |
| 2855 | for (SharedFile *f : sharedFiles) { | |
| 2856 | if (f->vernauxs.empty()) | |
| 2857 | continue; | |
| 2858 | verneeds.emplace_back(); | |
| 2859 | Verneed &vn = verneeds.back(); | |
| 2860 | vn.nameStrTab = getPartition().dynStrTab->addString(f->soName); | |
| 2861 | for (unsigned i = 0; i != f->vernauxs.size(); ++i) { | |
| 2862 | if (f->vernauxs[i] == 0) | |
| 2863 | continue; | |
| 2864 | auto *verdef = | |
| 2865 | reinterpret_cast<const typename ELFT::Verdef *>(f->verdefs[i]); | |
| 2866 | vn.vernauxs.push_back( | |
| 2867 | {verdef->vd_hash, f->vernauxs[i], | |
| 2868 | getPartition().dynStrTab->addString(f->getStringTable().data() + | |
| 2869 | verdef->getAux()->vda_name)}); | |
| 2870 | } | |
| 2792 | 2871 | } |
| 2793 | 2872 | |
| 2794 | // If we don't already know that we need an Elf_Verneed for this DSO, prepare | |
| 2795 | // to create one by adding it to our needed list and creating a dynstr entry | |
| 2796 | // for the soname. | |
| 2797 | if (File.VerdefMap.empty()) | |
| 2798 | Needed.push_back({&File, In.DynStrTab->addString(File.SoName)}); | |
| 2799 | const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex]; | |
| 2800 | typename SharedFile<ELFT>::NeededVer &NV = File.VerdefMap[Ver]; | |
| 2801 | ||
| 2802 | // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef, | |
| 2803 | // prepare to create one by allocating a version identifier and creating a | |
| 2804 | // dynstr entry for the version name. | |
| 2805 | if (NV.Index == 0) { | |
| 2806 | NV.StrTab = In.DynStrTab->addString(File.getStringTable().data() + | |
| 2807 | Ver->getAux()->vda_name); | |
| 2808 | NV.Index = NextIndex++; | |
| 2809 | } | |
| 2810 | SS->VersionId = NV.Index; | |
| 2873 | if (OutputSection *sec = getPartition().dynStrTab->getParent()) | |
| 2874 | getParent()->link = sec->sectionIndex; | |
| 2875 | getParent()->info = verneeds.size(); | |
| 2811 | 2876 | } |
| 2812 | 2877 | |
| 2813 | template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) { | |
| 2878 | template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *buf) { | |
| 2814 | 2879 | // The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs. |
| 2815 | auto *Verneed = reinterpret_cast<Elf_Verneed *>(Buf); | |
| 2816 | auto *Vernaux = reinterpret_cast<Elf_Vernaux *>(Verneed + Needed.size()); | |
| 2880 | auto *verneed = reinterpret_cast<Elf_Verneed *>(buf); | |
| 2881 | auto *vernaux = reinterpret_cast<Elf_Vernaux *>(verneed + verneeds.size()); | |
| 2817 | 2882 | |
| 2818 | for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed) { | |
| 2883 | for (auto &vn : verneeds) { | |
| 2819 | 2884 | // Create an Elf_Verneed for this DSO. |
| 2820 | Verneed->vn_version = 1; | |
| 2821 | Verneed->vn_cnt = P.first->VerdefMap.size(); | |
| 2822 | Verneed->vn_file = P.second; | |
| 2823 | Verneed->vn_aux = | |
| 2824 | reinterpret_cast<char *>(Vernaux) - reinterpret_cast<char *>(Verneed); | |
| 2825 | Verneed->vn_next = sizeof(Elf_Verneed); | |
| 2826 | ++Verneed; | |
| 2827 | ||
| 2828 | // Create the Elf_Vernauxs for this Elf_Verneed. The loop iterates over | |
| 2829 | // VerdefMap, which will only contain references to needed version | |
| 2830 | // definitions. Each Elf_Vernaux is based on the information contained in | |
| 2831 | // the Elf_Verdef in the source DSO. This loop iterates over a std::map of | |
| 2832 | // pointers, but is deterministic because the pointers refer to Elf_Verdef | |
| 2833 | // data structures within a single input file. | |
| 2834 | for (auto &NV : P.first->VerdefMap) { | |
| 2835 | Vernaux->vna_hash = NV.first->vd_hash; | |
| 2836 | Vernaux->vna_flags = 0; | |
| 2837 | Vernaux->vna_other = NV.second.Index; | |
| 2838 | Vernaux->vna_name = NV.second.StrTab; | |
| 2839 | Vernaux->vna_next = sizeof(Elf_Vernaux); | |
| 2840 | ++Vernaux; | |
| 2885 | verneed->vn_version = 1; | |
| 2886 | verneed->vn_cnt = vn.vernauxs.size(); | |
| 2887 | verneed->vn_file = vn.nameStrTab; | |
| 2888 | verneed->vn_aux = | |
| 2889 | reinterpret_cast<char *>(vernaux) - reinterpret_cast<char *>(verneed); | |
| 2890 | verneed->vn_next = sizeof(Elf_Verneed); | |
| 2891 | ++verneed; | |
| 2892 | ||
| 2893 | // Create the Elf_Vernauxs for this Elf_Verneed. | |
| 2894 | for (auto &vna : vn.vernauxs) { | |
| 2895 | vernaux->vna_hash = vna.hash; | |
| 2896 | vernaux->vna_flags = 0; | |
| 2897 | vernaux->vna_other = vna.verneedIndex; | |
| 2898 | vernaux->vna_name = vna.nameStrTab; | |
| 2899 | vernaux->vna_next = sizeof(Elf_Vernaux); | |
| 2900 | ++vernaux; | |
| 2841 | 2901 | } |
| 2842 | 2902 | |
| 2843 | Vernaux[-1].vna_next = 0; | |
| 2903 | vernaux[-1].vna_next = 0; | |
| 2844 | 2904 | } |
| 2845 | Verneed[-1].vn_next = 0; | |
| 2846 | } | |
| 2847 | ||
| 2848 | template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() { | |
| 2849 | if (OutputSection *Sec = In.DynStrTab->getParent()) | |
| 2850 | getParent()->Link = Sec->SectionIndex; | |
| 2851 | getParent()->Info = Needed.size(); | |
| 2905 | verneed[-1].vn_next = 0; | |
| 2852 | 2906 | } |
| 2853 | 2907 | |
| 2854 | 2908 | template <class ELFT> size_t VersionNeedSection<ELFT>::getSize() const { |
| 2855 | unsigned Size = Needed.size() * sizeof(Elf_Verneed); | |
| 2856 | for (const std::pair<SharedFile<ELFT> *, size_t> &P : Needed) | |
| 2857 | Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux); | |
| 2858 | return Size; | |
| 2909 | return verneeds.size() * sizeof(Elf_Verneed) + | |
| 2910 | SharedFile::vernauxNum * sizeof(Elf_Vernaux); | |
| 2859 | 2911 | } |
| 2860 | 2912 | |
| 2861 | template <class ELFT> bool VersionNeedSection<ELFT>::empty() const { | |
| 2862 | return getNeedNum() == 0; | |
| 2913 | template <class ELFT> bool VersionNeedSection<ELFT>::isNeeded() const { | |
| 2914 | return SharedFile::vernauxNum != 0; | |
| 2863 | 2915 | } |
| 2864 | 2916 | |
| 2865 | void MergeSyntheticSection::addSection(MergeInputSection *MS) { | |
| 2866 | MS->Parent = this; | |
| 2867 | Sections.push_back(MS); | |
| 2917 | void MergeSyntheticSection::addSection(MergeInputSection *ms) { | |
| 2918 | ms->parent = this; | |
| 2919 | sections.push_back(ms); | |
| 2920 | assert(alignment == ms->alignment || !(ms->flags & SHF_STRINGS)); | |
| 2921 | alignment = std::max(alignment, ms->alignment); | |
| 2868 | 2922 | } |
| 2869 | 2923 | |
| 2870 | MergeTailSection::MergeTailSection(StringRef Name, uint32_t Type, | |
| 2871 | uint64_t Flags, uint32_t Alignment) | |
| 2872 | : MergeSyntheticSection(Name, Type, Flags, Alignment), | |
| 2873 | Builder(StringTableBuilder::RAW, Alignment) {} | |
| 2924 | MergeTailSection::MergeTailSection(StringRef name, uint32_t type, | |
| 2925 | uint64_t flags, uint32_t alignment) | |
| 2926 | : MergeSyntheticSection(name, type, flags, alignment), | |
| 2927 | builder(StringTableBuilder::RAW, alignment) {} | |
| 2874 | 2928 | |
| 2875 | size_t MergeTailSection::getSize() const { return Builder.getSize(); } | |
| 2929 | size_t MergeTailSection::getSize() const { return builder.getSize(); } | |
| 2876 | 2930 | |
| 2877 | void MergeTailSection::writeTo(uint8_t *Buf) { Builder.write(Buf); } | |
| 2931 | void MergeTailSection::writeTo(uint8_t *buf) { builder.write(buf); } | |
| 2878 | 2932 | |
| 2879 | 2933 | void MergeTailSection::finalizeContents() { |
| 2880 | 2934 | // Add all string pieces to the string table builder to create section |
| 2881 | 2935 | // contents. |
| 2882 | for (MergeInputSection *Sec : Sections) | |
| 2883 | for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) | |
| 2884 | if (Sec->Pieces[I].Live) | |
| 2885 | Builder.add(Sec->getData(I)); | |
| 2936 | for (MergeInputSection *sec : sections) | |
| 2937 | for (size_t i = 0, e = sec->pieces.size(); i != e; ++i) | |
| 2938 | if (sec->pieces[i].live) | |
| 2939 | builder.add(sec->getData(i)); | |
| 2886 | 2940 | |
| 2887 | 2941 | // Fix the string table content. After this, the contents will never change. |
| 2888 | Builder.finalize(); | |
| 2942 | builder.finalize(); | |
| 2889 | 2943 | |
| 2890 | 2944 | // finalize() fixed tail-optimized strings, so we can now get |
| 2891 | 2945 | // offsets of strings. Get an offset for each string and save it |
| 2892 | // to a corresponding StringPiece for easy access. | |
| 2893 | for (MergeInputSection *Sec : Sections) | |
| 2894 | for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) | |
| 2895 | if (Sec->Pieces[I].Live) | |
| 2896 | Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I)); | |
| 2946 | // to a corresponding SectionPiece for easy access. | |
| 2947 | for (MergeInputSection *sec : sections) | |
| 2948 | for (size_t i = 0, e = sec->pieces.size(); i != e; ++i) | |
| 2949 | if (sec->pieces[i].live) | |
| 2950 | sec->pieces[i].outputOff = builder.getOffset(sec->getData(i)); | |
| 2897 | 2951 | } |
| 2898 | 2952 | |
| 2899 | void MergeNoTailSection::writeTo(uint8_t *Buf) { | |
| 2900 | for (size_t I = 0; I < NumShards; ++I) | |
| 2901 | Shards[I].write(Buf + ShardOffsets[I]); | |
| 2953 | void MergeNoTailSection::writeTo(uint8_t *buf) { | |
| 2954 | for (size_t i = 0; i < numShards; ++i) | |
| 2955 | shards[i].write(buf + shardOffsets[i]); | |
| 2902 | 2956 | } |
| 2903 | 2957 | |
| 2904 | 2958 | // This function is very hot (i.e. it can take several seconds to finish) |
| ... | ... | @@ -2911,66 +2965,68 @@ void MergeNoTailSection::writeTo(uint8_t *Buf) { |
| 2911 | 2965 | // We do it in parallel. |
| 2912 | 2966 | void MergeNoTailSection::finalizeContents() { |
| 2913 | 2967 | // Initializes string table builders. |
| 2914 | for (size_t I = 0; I < NumShards; ++I) | |
| 2915 | Shards.emplace_back(StringTableBuilder::RAW, Alignment); | |
| 2968 | for (size_t i = 0; i < numShards; ++i) | |
| 2969 | shards.emplace_back(StringTableBuilder::RAW, alignment); | |
| 2916 | 2970 | |
| 2917 | 2971 | // Concurrency level. Must be a power of 2 to avoid expensive modulo |
| 2918 | 2972 | // operations in the following tight loop. |
| 2919 | size_t Concurrency = 1; | |
| 2920 | if (ThreadsEnabled) | |
| 2921 | Concurrency = | |
| 2922 | std::min<size_t>(PowerOf2Floor(hardware_concurrency()), NumShards); | |
| 2973 | size_t concurrency = 1; | |
| 2974 | if (threadsEnabled) | |
| 2975 | concurrency = | |
| 2976 | std::min<size_t>(PowerOf2Floor(hardware_concurrency()), numShards); | |
| 2923 | 2977 | |
| 2924 | 2978 | // Add section pieces to the builders. |
| 2925 | parallelForEachN(0, Concurrency, [&](size_t ThreadId) { | |
| 2926 | for (MergeInputSection *Sec : Sections) { | |
| 2927 | for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) { | |
| 2928 | size_t ShardId = getShardId(Sec->Pieces[I].Hash); | |
| 2929 | if ((ShardId & (Concurrency - 1)) == ThreadId && Sec->Pieces[I].Live) | |
| 2930 | Sec->Pieces[I].OutputOff = Shards[ShardId].add(Sec->getData(I)); | |
| 2979 | parallelForEachN(0, concurrency, [&](size_t threadId) { | |
| 2980 | for (MergeInputSection *sec : sections) { | |
| 2981 | for (size_t i = 0, e = sec->pieces.size(); i != e; ++i) { | |
| 2982 | if (!sec->pieces[i].live) | |
| 2983 | continue; | |
| 2984 | size_t shardId = getShardId(sec->pieces[i].hash); | |
| 2985 | if ((shardId & (concurrency - 1)) == threadId) | |
| 2986 | sec->pieces[i].outputOff = shards[shardId].add(sec->getData(i)); | |
| 2931 | 2987 | } |
| 2932 | 2988 | } |
| 2933 | 2989 | }); |
| 2934 | 2990 | |
| 2935 | 2991 | // Compute an in-section offset for each shard. |
| 2936 | size_t Off = 0; | |
| 2937 | for (size_t I = 0; I < NumShards; ++I) { | |
| 2938 | Shards[I].finalizeInOrder(); | |
| 2939 | if (Shards[I].getSize() > 0) | |
| 2940 | Off = alignTo(Off, Alignment); | |
| 2941 | ShardOffsets[I] = Off; | |
| 2942 | Off += Shards[I].getSize(); | |
| 2992 | size_t off = 0; | |
| 2993 | for (size_t i = 0; i < numShards; ++i) { | |
| 2994 | shards[i].finalizeInOrder(); | |
| 2995 | if (shards[i].getSize() > 0) | |
| 2996 | off = alignTo(off, alignment); | |
| 2997 | shardOffsets[i] = off; | |
| 2998 | off += shards[i].getSize(); | |
| 2943 | 2999 | } |
| 2944 | Size = Off; | |
| 3000 | size = off; | |
| 2945 | 3001 | |
| 2946 | 3002 | // So far, section pieces have offsets from beginning of shards, but |
| 2947 | 3003 | // we want offsets from beginning of the whole section. Fix them. |
| 2948 | parallelForEach(Sections, [&](MergeInputSection *Sec) { | |
| 2949 | for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) | |
| 2950 | if (Sec->Pieces[I].Live) | |
| 2951 | Sec->Pieces[I].OutputOff += | |
| 2952 | ShardOffsets[getShardId(Sec->Pieces[I].Hash)]; | |
| 3004 | parallelForEach(sections, [&](MergeInputSection *sec) { | |
| 3005 | for (size_t i = 0, e = sec->pieces.size(); i != e; ++i) | |
| 3006 | if (sec->pieces[i].live) | |
| 3007 | sec->pieces[i].outputOff += | |
| 3008 | shardOffsets[getShardId(sec->pieces[i].hash)]; | |
| 2953 | 3009 | }); |
| 2954 | 3010 | } |
| 2955 | 3011 | |
| 2956 | static MergeSyntheticSection *createMergeSynthetic(StringRef Name, | |
| 2957 | uint32_t Type, | |
| 2958 | uint64_t Flags, | |
| 2959 | uint32_t Alignment) { | |
| 2960 | bool ShouldTailMerge = (Flags & SHF_STRINGS) && Config->Optimize >= 2; | |
| 2961 | if (ShouldTailMerge) | |
| 2962 | return make<MergeTailSection>(Name, Type, Flags, Alignment); | |
| 2963 | return make<MergeNoTailSection>(Name, Type, Flags, Alignment); | |
| 3012 | static MergeSyntheticSection *createMergeSynthetic(StringRef name, | |
| 3013 | uint32_t type, | |
| 3014 | uint64_t flags, | |
| 3015 | uint32_t alignment) { | |
| 3016 | bool shouldTailMerge = (flags & SHF_STRINGS) && config->optimize >= 2; | |
| 3017 | if (shouldTailMerge) | |
| 3018 | return make<MergeTailSection>(name, type, flags, alignment); | |
| 3019 | return make<MergeNoTailSection>(name, type, flags, alignment); | |
| 2964 | 3020 | } |
| 2965 | 3021 | |
| 2966 | 3022 | template <class ELFT> void elf::splitSections() { |
| 2967 | 3023 | // splitIntoPieces needs to be called on each MergeInputSection |
| 2968 | 3024 | // before calling finalizeContents(). |
| 2969 | parallelForEach(InputSections, [](InputSectionBase *Sec) { | |
| 2970 | if (auto *S = dyn_cast<MergeInputSection>(Sec)) | |
| 2971 | S->splitIntoPieces(); | |
| 2972 | else if (auto *Eh = dyn_cast<EhInputSection>(Sec)) | |
| 2973 | Eh->split<ELFT>(); | |
| 3025 | parallelForEach(inputSections, [](InputSectionBase *sec) { | |
| 3026 | if (auto *s = dyn_cast<MergeInputSection>(sec)) | |
| 3027 | s->splitIntoPieces(); | |
| 3028 | else if (auto *eh = dyn_cast<EhInputSection>(sec)) | |
| 3029 | eh->split<ELFT>(); | |
| 2974 | 3030 | }); |
| 2975 | 3031 | } |
| 2976 | 3032 | |
| ... | ... | @@ -2982,23 +3038,22 @@ template <class ELFT> void elf::splitSections() { |
| 2982 | 3038 | // that it replaces. It then finalizes each synthetic section in order |
| 2983 | 3039 | // to compute an output offset for each piece of each input section. |
| 2984 | 3040 | void elf::mergeSections() { |
| 2985 | std::vector<MergeSyntheticSection *> MergeSections; | |
| 2986 | for (InputSectionBase *&S : InputSections) { | |
| 2987 | MergeInputSection *MS = dyn_cast<MergeInputSection>(S); | |
| 2988 | if (!MS) | |
| 3041 | std::vector<MergeSyntheticSection *> mergeSections; | |
| 3042 | for (InputSectionBase *&s : inputSections) { | |
| 3043 | MergeInputSection *ms = dyn_cast<MergeInputSection>(s); | |
| 3044 | if (!ms) | |
| 2989 | 3045 | continue; |
| 2990 | 3046 | |
| 2991 | 3047 | // We do not want to handle sections that are not alive, so just remove |
| 2992 | 3048 | // them instead of trying to merge. |
| 2993 | if (!MS->Live) { | |
| 2994 | S = nullptr; | |
| 3049 | if (!ms->isLive()) { | |
| 3050 | s = nullptr; | |
| 2995 | 3051 | continue; |
| 2996 | 3052 | } |
| 2997 | 3053 | |
| 2998 | StringRef OutsecName = getOutputSectionName(MS); | |
| 2999 | uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize); | |
| 3054 | StringRef outsecName = getOutputSectionName(ms); | |
| 3000 | 3055 | |
| 3001 | auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) { | |
| 3056 | auto i = llvm::find_if(mergeSections, [=](MergeSyntheticSection *sec) { | |
| 3002 | 3057 | // While we could create a single synthetic section for two different |
| 3003 | 3058 | // values of Entsize, it is better to take Entsize into consideration. |
| 3004 | 3059 | // |
| ... | ... | @@ -3007,98 +3062,285 @@ void elf::mergeSections() { |
| 3007 | 3062 | // |
| 3008 | 3063 | // Using Entsize in here also allows us to propagate it to the synthetic |
| 3009 | 3064 | // section. |
| 3010 | return Sec->Name == OutsecName && Sec->Flags == MS->Flags && | |
| 3011 | Sec->Entsize == MS->Entsize && Sec->Alignment == Alignment; | |
| 3065 | // | |
| 3066 | // SHF_STRINGS section with different alignments should not be merged. | |
| 3067 | return sec->name == outsecName && sec->flags == ms->flags && | |
| 3068 | sec->entsize == ms->entsize && | |
| 3069 | (sec->alignment == ms->alignment || !(sec->flags & SHF_STRINGS)); | |
| 3012 | 3070 | }); |
| 3013 | if (I == MergeSections.end()) { | |
| 3014 | MergeSyntheticSection *Syn = | |
| 3015 | createMergeSynthetic(OutsecName, MS->Type, MS->Flags, Alignment); | |
| 3016 | MergeSections.push_back(Syn); | |
| 3017 | I = std::prev(MergeSections.end()); | |
| 3018 | S = Syn; | |
| 3019 | Syn->Entsize = MS->Entsize; | |
| 3071 | if (i == mergeSections.end()) { | |
| 3072 | MergeSyntheticSection *syn = | |
| 3073 | createMergeSynthetic(outsecName, ms->type, ms->flags, ms->alignment); | |
| 3074 | mergeSections.push_back(syn); | |
| 3075 | i = std::prev(mergeSections.end()); | |
| 3076 | s = syn; | |
| 3077 | syn->entsize = ms->entsize; | |
| 3020 | 3078 | } else { |
| 3021 | S = nullptr; | |
| 3079 | s = nullptr; | |
| 3022 | 3080 | } |
| 3023 | (*I)->addSection(MS); | |
| 3081 | (*i)->addSection(ms); | |
| 3024 | 3082 | } |
| 3025 | for (auto *MS : MergeSections) | |
| 3026 | MS->finalizeContents(); | |
| 3083 | for (auto *ms : mergeSections) | |
| 3084 | ms->finalizeContents(); | |
| 3027 | 3085 | |
| 3028 | std::vector<InputSectionBase *> &V = InputSections; | |
| 3029 | V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); | |
| 3086 | std::vector<InputSectionBase *> &v = inputSections; | |
| 3087 | v.erase(std::remove(v.begin(), v.end(), nullptr), v.end()); | |
| 3030 | 3088 | } |
| 3031 | 3089 | |
| 3032 | 3090 | MipsRldMapSection::MipsRldMapSection() |
| 3033 | : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize, | |
| 3091 | : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize, | |
| 3034 | 3092 | ".rld_map") {} |
| 3035 | 3093 | |
| 3036 | ARMExidxSentinelSection::ARMExidxSentinelSection() | |
| 3094 | ARMExidxSyntheticSection::ARMExidxSyntheticSection() | |
| 3037 | 3095 | : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX, |
| 3038 | Config->Wordsize, ".ARM.exidx") {} | |
| 3039 | ||
| 3040 | // Write a terminating sentinel entry to the end of the .ARM.exidx table. | |
| 3041 | // This section will have been sorted last in the .ARM.exidx table. | |
| 3042 | // This table entry will have the form: | |
| 3043 | // | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND | | |
| 3044 | // The sentinel must have the PREL31 value of an address higher than any | |
| 3045 | // address described by any other table entry. | |
| 3046 | void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { | |
| 3047 | assert(Highest); | |
| 3048 | uint64_t S = Highest->getVA(Highest->getSize()); | |
| 3049 | uint64_t P = getVA(); | |
| 3050 | Target->relocateOne(Buf, R_ARM_PREL31, S - P); | |
| 3051 | write32le(Buf + 4, 1); | |
| 3052 | } | |
| 3053 | ||
| 3054 | // The sentinel has to be removed if there are no other .ARM.exidx entries. | |
| 3055 | bool ARMExidxSentinelSection::empty() const { | |
| 3056 | for (InputSection *IS : getInputSections(getParent())) | |
| 3057 | if (!isa<ARMExidxSentinelSection>(IS)) | |
| 3096 | config->wordsize, ".ARM.exidx") {} | |
| 3097 | ||
| 3098 | static InputSection *findExidxSection(InputSection *isec) { | |
| 3099 | for (InputSection *d : isec->dependentSections) | |
| 3100 | if (d->type == SHT_ARM_EXIDX) | |
| 3101 | return d; | |
| 3102 | return nullptr; | |
| 3103 | } | |
| 3104 | ||
| 3105 | bool ARMExidxSyntheticSection::addSection(InputSection *isec) { | |
| 3106 | if (isec->type == SHT_ARM_EXIDX) { | |
| 3107 | exidxSections.push_back(isec); | |
| 3108 | return true; | |
| 3109 | } | |
| 3110 | ||
| 3111 | if ((isec->flags & SHF_ALLOC) && (isec->flags & SHF_EXECINSTR) && | |
| 3112 | isec->getSize() > 0) { | |
| 3113 | executableSections.push_back(isec); | |
| 3114 | if (empty && findExidxSection(isec)) | |
| 3115 | empty = false; | |
| 3116 | return false; | |
| 3117 | } | |
| 3118 | ||
| 3119 | // FIXME: we do not output a relocation section when --emit-relocs is used | |
| 3120 | // as we do not have relocation sections for linker generated table entries | |
| 3121 | // and we would have to erase at a late stage relocations from merged entries. | |
| 3122 | // Given that exception tables are already position independent and a binary | |
| 3123 | // analyzer could derive the relocations we choose to erase the relocations. | |
| 3124 | if (config->emitRelocs && isec->type == SHT_REL) | |
| 3125 | if (InputSectionBase *ex = isec->getRelocatedSection()) | |
| 3126 | if (isa<InputSection>(ex) && ex->type == SHT_ARM_EXIDX) | |
| 3127 | return true; | |
| 3128 | ||
| 3129 | return false; | |
| 3130 | } | |
| 3131 | ||
| 3132 | // References to .ARM.Extab Sections have bit 31 clear and are not the | |
| 3133 | // special EXIDX_CANTUNWIND bit-pattern. | |
| 3134 | static bool isExtabRef(uint32_t unwind) { | |
| 3135 | return (unwind & 0x80000000) == 0 && unwind != 0x1; | |
| 3136 | } | |
| 3137 | ||
| 3138 | // Return true if the .ARM.exidx section Cur can be merged into the .ARM.exidx | |
| 3139 | // section Prev, where Cur follows Prev in the table. This can be done if the | |
| 3140 | // unwinding instructions in Cur are identical to Prev. Linker generated | |
| 3141 | // EXIDX_CANTUNWIND entries are represented by nullptr as they do not have an | |
| 3142 | // InputSection. | |
| 3143 | static bool isDuplicateArmExidxSec(InputSection *prev, InputSection *cur) { | |
| 3144 | ||
| 3145 | struct ExidxEntry { | |
| 3146 | ulittle32_t fn; | |
| 3147 | ulittle32_t unwind; | |
| 3148 | }; | |
| 3149 | // Get the last table Entry from the previous .ARM.exidx section. If Prev is | |
| 3150 | // nullptr then it will be a synthesized EXIDX_CANTUNWIND entry. | |
| 3151 | ExidxEntry prevEntry = {ulittle32_t(0), ulittle32_t(1)}; | |
| 3152 | if (prev) | |
| 3153 | prevEntry = prev->getDataAs<ExidxEntry>().back(); | |
| 3154 | if (isExtabRef(prevEntry.unwind)) | |
| 3155 | return false; | |
| 3156 | ||
| 3157 | // We consider the unwind instructions of an .ARM.exidx table entry | |
| 3158 | // a duplicate if the previous unwind instructions if: | |
| 3159 | // - Both are the special EXIDX_CANTUNWIND. | |
| 3160 | // - Both are the same inline unwind instructions. | |
| 3161 | // We do not attempt to follow and check links into .ARM.extab tables as | |
| 3162 | // consecutive identical entries are rare and the effort to check that they | |
| 3163 | // are identical is high. | |
| 3164 | ||
| 3165 | // If Cur is nullptr then this is synthesized EXIDX_CANTUNWIND entry. | |
| 3166 | if (cur == nullptr) | |
| 3167 | return prevEntry.unwind == 1; | |
| 3168 | ||
| 3169 | for (const ExidxEntry entry : cur->getDataAs<ExidxEntry>()) | |
| 3170 | if (isExtabRef(entry.unwind) || entry.unwind != prevEntry.unwind) | |
| 3058 | 3171 | return false; |
| 3172 | ||
| 3173 | // All table entries in this .ARM.exidx Section can be merged into the | |
| 3174 | // previous Section. | |
| 3059 | 3175 | return true; |
| 3060 | 3176 | } |
| 3061 | 3177 | |
| 3062 | bool ARMExidxSentinelSection::classof(const SectionBase *D) { | |
| 3063 | return D->kind() == InputSectionBase::Synthetic && D->Type == SHT_ARM_EXIDX; | |
| 3178 | // The .ARM.exidx table must be sorted in ascending order of the address of the | |
| 3179 | // functions the table describes. Optionally duplicate adjacent table entries | |
| 3180 | // can be removed. At the end of the function the ExecutableSections must be | |
| 3181 | // sorted in ascending order of address, Sentinel is set to the InputSection | |
| 3182 | // with the highest address and any InputSections that have mergeable | |
| 3183 | // .ARM.exidx table entries are removed from it. | |
| 3184 | void ARMExidxSyntheticSection::finalizeContents() { | |
| 3185 | // Sort the executable sections that may or may not have associated | |
| 3186 | // .ARM.exidx sections by order of ascending address. This requires the | |
| 3187 | // relative positions of InputSections to be known. | |
| 3188 | auto compareByFilePosition = [](const InputSection *a, | |
| 3189 | const InputSection *b) { | |
| 3190 | OutputSection *aOut = a->getParent(); | |
| 3191 | OutputSection *bOut = b->getParent(); | |
| 3192 | ||
| 3193 | if (aOut != bOut) | |
| 3194 | return aOut->sectionIndex < bOut->sectionIndex; | |
| 3195 | return a->outSecOff < b->outSecOff; | |
| 3196 | }; | |
| 3197 | llvm::stable_sort(executableSections, compareByFilePosition); | |
| 3198 | sentinel = executableSections.back(); | |
| 3199 | // Optionally merge adjacent duplicate entries. | |
| 3200 | if (config->mergeArmExidx) { | |
| 3201 | std::vector<InputSection *> selectedSections; | |
| 3202 | selectedSections.reserve(executableSections.size()); | |
| 3203 | selectedSections.push_back(executableSections[0]); | |
| 3204 | size_t prev = 0; | |
| 3205 | for (size_t i = 1; i < executableSections.size(); ++i) { | |
| 3206 | InputSection *ex1 = findExidxSection(executableSections[prev]); | |
| 3207 | InputSection *ex2 = findExidxSection(executableSections[i]); | |
| 3208 | if (!isDuplicateArmExidxSec(ex1, ex2)) { | |
| 3209 | selectedSections.push_back(executableSections[i]); | |
| 3210 | prev = i; | |
| 3211 | } | |
| 3212 | } | |
| 3213 | executableSections = std::move(selectedSections); | |
| 3214 | } | |
| 3215 | ||
| 3216 | size_t offset = 0; | |
| 3217 | size = 0; | |
| 3218 | for (InputSection *isec : executableSections) { | |
| 3219 | if (InputSection *d = findExidxSection(isec)) { | |
| 3220 | d->outSecOff = offset; | |
| 3221 | d->parent = getParent(); | |
| 3222 | offset += d->getSize(); | |
| 3223 | } else { | |
| 3224 | offset += 8; | |
| 3225 | } | |
| 3226 | } | |
| 3227 | // Size includes Sentinel. | |
| 3228 | size = offset + 8; | |
| 3229 | } | |
| 3230 | ||
| 3231 | InputSection *ARMExidxSyntheticSection::getLinkOrderDep() const { | |
| 3232 | return executableSections.front(); | |
| 3064 | 3233 | } |
| 3065 | 3234 | |
| 3066 | ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off) | |
| 3235 | // To write the .ARM.exidx table from the ExecutableSections we have three cases | |
| 3236 | // 1.) The InputSection has a .ARM.exidx InputSection in its dependent sections. | |
| 3237 | // We write the .ARM.exidx section contents and apply its relocations. | |
| 3238 | // 2.) The InputSection does not have a dependent .ARM.exidx InputSection. We | |
| 3239 | // must write the contents of an EXIDX_CANTUNWIND directly. We use the | |
| 3240 | // start of the InputSection as the purpose of the linker generated | |
| 3241 | // section is to terminate the address range of the previous entry. | |
| 3242 | // 3.) A trailing EXIDX_CANTUNWIND sentinel section is required at the end of | |
| 3243 | // the table to terminate the address range of the final entry. | |
| 3244 | void ARMExidxSyntheticSection::writeTo(uint8_t *buf) { | |
| 3245 | ||
| 3246 | const uint8_t cantUnwindData[8] = {0, 0, 0, 0, // PREL31 to target | |
| 3247 | 1, 0, 0, 0}; // EXIDX_CANTUNWIND | |
| 3248 | ||
| 3249 | uint64_t offset = 0; | |
| 3250 | for (InputSection *isec : executableSections) { | |
| 3251 | assert(isec->getParent() != nullptr); | |
| 3252 | if (InputSection *d = findExidxSection(isec)) { | |
| 3253 | memcpy(buf + offset, d->data().data(), d->data().size()); | |
| 3254 | d->relocateAlloc(buf, buf + d->getSize()); | |
| 3255 | offset += d->getSize(); | |
| 3256 | } else { | |
| 3257 | // A Linker generated CANTUNWIND section. | |
| 3258 | memcpy(buf + offset, cantUnwindData, sizeof(cantUnwindData)); | |
| 3259 | uint64_t s = isec->getVA(); | |
| 3260 | uint64_t p = getVA() + offset; | |
| 3261 | target->relocateOne(buf + offset, R_ARM_PREL31, s - p); | |
| 3262 | offset += 8; | |
| 3263 | } | |
| 3264 | } | |
| 3265 | // Write Sentinel. | |
| 3266 | memcpy(buf + offset, cantUnwindData, sizeof(cantUnwindData)); | |
| 3267 | uint64_t s = sentinel->getVA(sentinel->getSize()); | |
| 3268 | uint64_t p = getVA() + offset; | |
| 3269 | target->relocateOne(buf + offset, R_ARM_PREL31, s - p); | |
| 3270 | assert(size == offset + 8); | |
| 3271 | } | |
| 3272 | ||
| 3273 | bool ARMExidxSyntheticSection::classof(const SectionBase *d) { | |
| 3274 | return d->kind() == InputSectionBase::Synthetic && d->type == SHT_ARM_EXIDX; | |
| 3275 | } | |
| 3276 | ||
| 3277 | ThunkSection::ThunkSection(OutputSection *os, uint64_t off) | |
| 3067 | 3278 | : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, |
| 3068 | Config->Wordsize, ".text.thunk") { | |
| 3069 | this->Parent = OS; | |
| 3070 | this->OutSecOff = Off; | |
| 3279 | config->wordsize, ".text.thunk") { | |
| 3280 | this->parent = os; | |
| 3281 | this->outSecOff = off; | |
| 3071 | 3282 | } |
| 3072 | 3283 | |
| 3073 | void ThunkSection::addThunk(Thunk *T) { | |
| 3074 | Thunks.push_back(T); | |
| 3075 | T->addSymbols(*this); | |
| 3284 | void ThunkSection::addThunk(Thunk *t) { | |
| 3285 | thunks.push_back(t); | |
| 3286 | t->addSymbols(*this); | |
| 3076 | 3287 | } |
| 3077 | 3288 | |
| 3078 | void ThunkSection::writeTo(uint8_t *Buf) { | |
| 3079 | for (Thunk *T : Thunks) | |
| 3080 | T->writeTo(Buf + T->Offset); | |
| 3289 | void ThunkSection::writeTo(uint8_t *buf) { | |
| 3290 | for (Thunk *t : thunks) | |
| 3291 | t->writeTo(buf + t->offset); | |
| 3081 | 3292 | } |
| 3082 | 3293 | |
| 3083 | 3294 | InputSection *ThunkSection::getTargetInputSection() const { |
| 3084 | if (Thunks.empty()) | |
| 3295 | if (thunks.empty()) | |
| 3085 | 3296 | return nullptr; |
| 3086 | const Thunk *T = Thunks.front(); | |
| 3087 | return T->getTargetInputSection(); | |
| 3297 | const Thunk *t = thunks.front(); | |
| 3298 | return t->getTargetInputSection(); | |
| 3088 | 3299 | } |
| 3089 | 3300 | |
| 3090 | 3301 | bool ThunkSection::assignOffsets() { |
| 3091 | uint64_t Off = 0; | |
| 3092 | for (Thunk *T : Thunks) { | |
| 3093 | Off = alignTo(Off, T->Alignment); | |
| 3094 | T->setOffset(Off); | |
| 3095 | uint32_t Size = T->size(); | |
| 3096 | T->getThunkTargetSym()->Size = Size; | |
| 3097 | Off += Size; | |
| 3098 | } | |
| 3099 | bool Changed = Off != Size; | |
| 3100 | Size = Off; | |
| 3101 | return Changed; | |
| 3302 | uint64_t off = 0; | |
| 3303 | for (Thunk *t : thunks) { | |
| 3304 | off = alignTo(off, t->alignment); | |
| 3305 | t->setOffset(off); | |
| 3306 | uint32_t size = t->size(); | |
| 3307 | t->getThunkTargetSym()->size = size; | |
| 3308 | off += size; | |
| 3309 | } | |
| 3310 | bool changed = off != size; | |
| 3311 | size = off; | |
| 3312 | return changed; | |
| 3313 | } | |
| 3314 | ||
| 3315 | PPC32Got2Section::PPC32Got2Section() | |
| 3316 | : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 4, ".got2") {} | |
| 3317 | ||
| 3318 | bool PPC32Got2Section::isNeeded() const { | |
| 3319 | // See the comment below. This is not needed if there is no other | |
| 3320 | // InputSection. | |
| 3321 | for (BaseCommand *base : getParent()->sectionCommands) | |
| 3322 | if (auto *isd = dyn_cast<InputSectionDescription>(base)) | |
| 3323 | for (InputSection *isec : isd->sections) | |
| 3324 | if (isec != this) | |
| 3325 | return true; | |
| 3326 | return false; | |
| 3327 | } | |
| 3328 | ||
| 3329 | void PPC32Got2Section::finalizeContents() { | |
| 3330 | // PPC32 may create multiple GOT sections for -fPIC/-fPIE, one per file in | |
| 3331 | // .got2 . This function computes outSecOff of each .got2 to be used in | |
| 3332 | // PPC32PltCallStub::writeTo(). The purpose of this empty synthetic section is | |
| 3333 | // to collect input sections named ".got2". | |
| 3334 | uint32_t offset = 0; | |
| 3335 | for (BaseCommand *base : getParent()->sectionCommands) | |
| 3336 | if (auto *isd = dyn_cast<InputSectionDescription>(base)) { | |
| 3337 | for (InputSection *isec : isd->sections) { | |
| 3338 | if (isec == this) | |
| 3339 | continue; | |
| 3340 | isec->file->ppc32Got2OutSecOff = offset; | |
| 3341 | offset += (uint32_t)isec->getSize(); | |
| 3342 | } | |
| 3343 | } | |
| 3102 | 3344 | } |
| 3103 | 3345 | |
| 3104 | 3346 | // If linking position-dependent code then the table will store the addresses |
| ... | ... | @@ -3107,48 +3349,188 @@ bool ThunkSection::assignOffsets() { |
| 3107 | 3349 | // allocated and filled in by the dynamic linker. |
| 3108 | 3350 | PPC64LongBranchTargetSection::PPC64LongBranchTargetSection() |
| 3109 | 3351 | : SyntheticSection(SHF_ALLOC | SHF_WRITE, |
| 3110 | Config->Pic ? SHT_NOBITS : SHT_PROGBITS, 8, | |
| 3352 | config->isPic ? SHT_NOBITS : SHT_PROGBITS, 8, | |
| 3111 | 3353 | ".branch_lt") {} |
| 3112 | 3354 | |
| 3113 | void PPC64LongBranchTargetSection::addEntry(Symbol &Sym) { | |
| 3114 | assert(Sym.PPC64BranchltIndex == 0xffff); | |
| 3115 | Sym.PPC64BranchltIndex = Entries.size(); | |
| 3116 | Entries.push_back(&Sym); | |
| 3355 | void PPC64LongBranchTargetSection::addEntry(Symbol &sym) { | |
| 3356 | assert(sym.ppc64BranchltIndex == 0xffff); | |
| 3357 | sym.ppc64BranchltIndex = entries.size(); | |
| 3358 | entries.push_back(&sym); | |
| 3117 | 3359 | } |
| 3118 | 3360 | |
| 3119 | 3361 | size_t PPC64LongBranchTargetSection::getSize() const { |
| 3120 | return Entries.size() * 8; | |
| 3362 | return entries.size() * 8; | |
| 3121 | 3363 | } |
| 3122 | 3364 | |
| 3123 | void PPC64LongBranchTargetSection::writeTo(uint8_t *Buf) { | |
| 3124 | assert(Target->GotPltEntrySize == 8); | |
| 3365 | void PPC64LongBranchTargetSection::writeTo(uint8_t *buf) { | |
| 3125 | 3366 | // If linking non-pic we have the final addresses of the targets and they get |
| 3126 | 3367 | // written to the table directly. For pic the dynamic linker will allocate |
| 3127 | 3368 | // the section and fill it it. |
| 3128 | if (Config->Pic) | |
| 3369 | if (config->isPic) | |
| 3129 | 3370 | return; |
| 3130 | 3371 | |
| 3131 | for (const Symbol *Sym : Entries) { | |
| 3132 | assert(Sym->getVA()); | |
| 3372 | for (const Symbol *sym : entries) { | |
| 3373 | assert(sym->getVA()); | |
| 3133 | 3374 | // Need calls to branch to the local entry-point since a long-branch |
| 3134 | 3375 | // must be a local-call. |
| 3135 | write64(Buf, | |
| 3136 | Sym->getVA() + getPPC64GlobalEntryToLocalEntryOffset(Sym->StOther)); | |
| 3137 | Buf += Target->GotPltEntrySize; | |
| 3376 | write64(buf, | |
| 3377 | sym->getVA() + getPPC64GlobalEntryToLocalEntryOffset(sym->stOther)); | |
| 3378 | buf += 8; | |
| 3138 | 3379 | } |
| 3139 | 3380 | } |
| 3140 | 3381 | |
| 3141 | bool PPC64LongBranchTargetSection::empty() const { | |
| 3382 | bool PPC64LongBranchTargetSection::isNeeded() const { | |
| 3142 | 3383 | // `removeUnusedSyntheticSections()` is called before thunk allocation which |
| 3143 | 3384 | // is too early to determine if this section will be empty or not. We need |
| 3144 | 3385 | // Finalized to keep the section alive until after thunk creation. Finalized |
| 3145 | 3386 | // only gets set to true once `finalizeSections()` is called after thunk |
| 3146 | 3387 | // creation. Becuase of this, if we don't create any long-branch thunks we end |
| 3147 | 3388 | // up with an empty .branch_lt section in the binary. |
| 3148 | return Finalized && Entries.empty(); | |
| 3389 | return !finalized || !entries.empty(); | |
| 3149 | 3390 | } |
| 3150 | 3391 | |
| 3151 | InStruct elf::In; | |
| 3392 | RISCVSdataSection::RISCVSdataSection() | |
| 3393 | : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 1, ".sdata") {} | |
| 3394 | ||
| 3395 | bool RISCVSdataSection::isNeeded() const { | |
| 3396 | if (!ElfSym::riscvGlobalPointer) | |
| 3397 | return false; | |
| 3398 | ||
| 3399 | // __global_pointer$ is defined relative to .sdata . If the section does not | |
| 3400 | // exist, create a dummy one. | |
| 3401 | for (BaseCommand *base : getParent()->sectionCommands) | |
| 3402 | if (auto *isd = dyn_cast<InputSectionDescription>(base)) | |
| 3403 | for (InputSection *isec : isd->sections) | |
| 3404 | if (isec != this) | |
| 3405 | return false; | |
| 3406 | return true; | |
| 3407 | } | |
| 3408 | ||
| 3409 | static uint8_t getAbiVersion() { | |
| 3410 | // MIPS non-PIC executable gets ABI version 1. | |
| 3411 | if (config->emachine == EM_MIPS) { | |
| 3412 | if (!config->isPic && !config->relocatable && | |
| 3413 | (config->eflags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC) | |
| 3414 | return 1; | |
| 3415 | return 0; | |
| 3416 | } | |
| 3417 | ||
| 3418 | if (config->emachine == EM_AMDGPU) { | |
| 3419 | uint8_t ver = objectFiles[0]->abiVersion; | |
| 3420 | for (InputFile *file : makeArrayRef(objectFiles).slice(1)) | |
| 3421 | if (file->abiVersion != ver) | |
| 3422 | error("incompatible ABI version: " + toString(file)); | |
| 3423 | return ver; | |
| 3424 | } | |
| 3425 | ||
| 3426 | return 0; | |
| 3427 | } | |
| 3428 | ||
| 3429 | template <typename ELFT> void elf::writeEhdr(uint8_t *buf, Partition &part) { | |
| 3430 | // For executable segments, the trap instructions are written before writing | |
| 3431 | // the header. Setting Elf header bytes to zero ensures that any unused bytes | |
| 3432 | // in header are zero-cleared, instead of having trap instructions. | |
| 3433 | memset(buf, 0, sizeof(typename ELFT::Ehdr)); | |
| 3434 | memcpy(buf, "\177ELF", 4); | |
| 3435 | ||
| 3436 | auto *eHdr = reinterpret_cast<typename ELFT::Ehdr *>(buf); | |
| 3437 | eHdr->e_ident[EI_CLASS] = config->is64 ? ELFCLASS64 : ELFCLASS32; | |
| 3438 | eHdr->e_ident[EI_DATA] = config->isLE ? ELFDATA2LSB : ELFDATA2MSB; | |
| 3439 | eHdr->e_ident[EI_VERSION] = EV_CURRENT; | |
| 3440 | eHdr->e_ident[EI_OSABI] = config->osabi; | |
| 3441 | eHdr->e_ident[EI_ABIVERSION] = getAbiVersion(); | |
| 3442 | eHdr->e_machine = config->emachine; | |
| 3443 | eHdr->e_version = EV_CURRENT; | |
| 3444 | eHdr->e_flags = config->eflags; | |
| 3445 | eHdr->e_ehsize = sizeof(typename ELFT::Ehdr); | |
| 3446 | eHdr->e_phnum = part.phdrs.size(); | |
| 3447 | eHdr->e_shentsize = sizeof(typename ELFT::Shdr); | |
| 3448 | ||
| 3449 | if (!config->relocatable) { | |
| 3450 | eHdr->e_phoff = sizeof(typename ELFT::Ehdr); | |
| 3451 | eHdr->e_phentsize = sizeof(typename ELFT::Phdr); | |
| 3452 | } | |
| 3453 | } | |
| 3454 | ||
| 3455 | template <typename ELFT> void elf::writePhdrs(uint8_t *buf, Partition &part) { | |
| 3456 | // Write the program header table. | |
| 3457 | auto *hBuf = reinterpret_cast<typename ELFT::Phdr *>(buf); | |
| 3458 | for (PhdrEntry *p : part.phdrs) { | |
| 3459 | hBuf->p_type = p->p_type; | |
| 3460 | hBuf->p_flags = p->p_flags; | |
| 3461 | hBuf->p_offset = p->p_offset; | |
| 3462 | hBuf->p_vaddr = p->p_vaddr; | |
| 3463 | hBuf->p_paddr = p->p_paddr; | |
| 3464 | hBuf->p_filesz = p->p_filesz; | |
| 3465 | hBuf->p_memsz = p->p_memsz; | |
| 3466 | hBuf->p_align = p->p_align; | |
| 3467 | ++hBuf; | |
| 3468 | } | |
| 3469 | } | |
| 3470 | ||
| 3471 | template <typename ELFT> | |
| 3472 | PartitionElfHeaderSection<ELFT>::PartitionElfHeaderSection() | |
| 3473 | : SyntheticSection(SHF_ALLOC, SHT_LLVM_PART_EHDR, 1, "") {} | |
| 3474 | ||
| 3475 | template <typename ELFT> | |
| 3476 | size_t PartitionElfHeaderSection<ELFT>::getSize() const { | |
| 3477 | return sizeof(typename ELFT::Ehdr); | |
| 3478 | } | |
| 3479 | ||
| 3480 | template <typename ELFT> | |
| 3481 | void PartitionElfHeaderSection<ELFT>::writeTo(uint8_t *buf) { | |
| 3482 | writeEhdr<ELFT>(buf, getPartition()); | |
| 3483 | ||
| 3484 | // Loadable partitions are always ET_DYN. | |
| 3485 | auto *eHdr = reinterpret_cast<typename ELFT::Ehdr *>(buf); | |
| 3486 | eHdr->e_type = ET_DYN; | |
| 3487 | } | |
| 3488 | ||
| 3489 | template <typename ELFT> | |
| 3490 | PartitionProgramHeadersSection<ELFT>::PartitionProgramHeadersSection() | |
| 3491 | : SyntheticSection(SHF_ALLOC, SHT_LLVM_PART_PHDR, 1, ".phdrs") {} | |
| 3492 | ||
| 3493 | template <typename ELFT> | |
| 3494 | size_t PartitionProgramHeadersSection<ELFT>::getSize() const { | |
| 3495 | return sizeof(typename ELFT::Phdr) * getPartition().phdrs.size(); | |
| 3496 | } | |
| 3497 | ||
| 3498 | template <typename ELFT> | |
| 3499 | void PartitionProgramHeadersSection<ELFT>::writeTo(uint8_t *buf) { | |
| 3500 | writePhdrs<ELFT>(buf, getPartition()); | |
| 3501 | } | |
| 3502 | ||
| 3503 | PartitionIndexSection::PartitionIndexSection() | |
| 3504 | : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".rodata") {} | |
| 3505 | ||
| 3506 | size_t PartitionIndexSection::getSize() const { | |
| 3507 | return 12 * (partitions.size() - 1); | |
| 3508 | } | |
| 3509 | ||
| 3510 | void PartitionIndexSection::finalizeContents() { | |
| 3511 | for (size_t i = 1; i != partitions.size(); ++i) | |
| 3512 | partitions[i].nameStrTab = mainPart->dynStrTab->addString(partitions[i].name); | |
| 3513 | } | |
| 3514 | ||
| 3515 | void PartitionIndexSection::writeTo(uint8_t *buf) { | |
| 3516 | uint64_t va = getVA(); | |
| 3517 | for (size_t i = 1; i != partitions.size(); ++i) { | |
| 3518 | write32(buf, mainPart->dynStrTab->getVA() + partitions[i].nameStrTab - va); | |
| 3519 | write32(buf + 4, partitions[i].elfHeader->getVA() - (va + 4)); | |
| 3520 | ||
| 3521 | SyntheticSection *next = | |
| 3522 | i == partitions.size() - 1 ? in.partEnd : partitions[i + 1].elfHeader; | |
| 3523 | write32(buf + 8, next->getVA() - partitions[i].elfHeader->getVA()); | |
| 3524 | ||
| 3525 | va += 12; | |
| 3526 | buf += 12; | |
| 3527 | } | |
| 3528 | } | |
| 3529 | ||
| 3530 | InStruct elf::in; | |
| 3531 | ||
| 3532 | std::vector<Partition> elf::partitions; | |
| 3533 | Partition *elf::mainPart; | |
| 3152 | 3534 | |
| 3153 | 3535 | template GdbIndexSection *GdbIndexSection::create<ELF32LE>(); |
| 3154 | 3536 | template GdbIndexSection *GdbIndexSection::create<ELF32BE>(); |
| ... | ... | @@ -3170,11 +3552,6 @@ template void PltSection::addEntry<ELF32BE>(Symbol &Sym); |
| 3170 | 3552 | template void PltSection::addEntry<ELF64LE>(Symbol &Sym); |
| 3171 | 3553 | template void PltSection::addEntry<ELF64BE>(Symbol &Sym); |
| 3172 | 3554 | |
| 3173 | template void MipsGotSection::build<ELF32LE>(); | |
| 3174 | template void MipsGotSection::build<ELF32BE>(); | |
| 3175 | template void MipsGotSection::build<ELF64LE>(); | |
| 3176 | template void MipsGotSection::build<ELF64BE>(); | |
| 3177 | ||
| 3178 | 3555 | template class elf::MipsAbiFlagsSection<ELF32LE>; |
| 3179 | 3556 | template class elf::MipsAbiFlagsSection<ELF32BE>; |
| 3180 | 3557 | template class elf::MipsAbiFlagsSection<ELF64LE>; |
| ... | ... | @@ -3215,12 +3592,27 @@ template class elf::SymbolTableSection<ELF32BE>; |
| 3215 | 3592 | template class elf::SymbolTableSection<ELF64LE>; |
| 3216 | 3593 | template class elf::SymbolTableSection<ELF64BE>; |
| 3217 | 3594 | |
| 3218 | template class elf::VersionTableSection<ELF32LE>; | |
| 3219 | template class elf::VersionTableSection<ELF32BE>; | |
| 3220 | template class elf::VersionTableSection<ELF64LE>; | |
| 3221 | template class elf::VersionTableSection<ELF64BE>; | |
| 3222 | ||
| 3223 | 3595 | template class elf::VersionNeedSection<ELF32LE>; |
| 3224 | 3596 | template class elf::VersionNeedSection<ELF32BE>; |
| 3225 | 3597 | template class elf::VersionNeedSection<ELF64LE>; |
| 3226 | 3598 | template class elf::VersionNeedSection<ELF64BE>; |
| 3599 | ||
| 3600 | template void elf::writeEhdr<ELF32LE>(uint8_t *Buf, Partition &Part); | |
| 3601 | template void elf::writeEhdr<ELF32BE>(uint8_t *Buf, Partition &Part); | |
| 3602 | template void elf::writeEhdr<ELF64LE>(uint8_t *Buf, Partition &Part); | |
| 3603 | template void elf::writeEhdr<ELF64BE>(uint8_t *Buf, Partition &Part); | |
| 3604 | ||
| 3605 | template void elf::writePhdrs<ELF32LE>(uint8_t *Buf, Partition &Part); | |
| 3606 | template void elf::writePhdrs<ELF32BE>(uint8_t *Buf, Partition &Part); | |
| 3607 | template void elf::writePhdrs<ELF64LE>(uint8_t *Buf, Partition &Part); | |
| 3608 | template void elf::writePhdrs<ELF64BE>(uint8_t *Buf, Partition &Part); | |
| 3609 | ||
| 3610 | template class elf::PartitionElfHeaderSection<ELF32LE>; | |
| 3611 | template class elf::PartitionElfHeaderSection<ELF32BE>; | |
| 3612 | template class elf::PartitionElfHeaderSection<ELF64LE>; | |
| 3613 | template class elf::PartitionElfHeaderSection<ELF64BE>; | |
| 3614 | ||
| 3615 | template class elf::PartitionProgramHeadersSection<ELF32LE>; | |
| 3616 | template class elf::PartitionProgramHeadersSection<ELF32BE>; | |
| 3617 | template class elf::PartitionProgramHeadersSection<ELF64LE>; | |
| 3618 | template class elf::PartitionProgramHeadersSection<ELF64BE>; |
deps/lld/ELF/SyntheticSections.h+519-374| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- SyntheticSection.h ---------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -18,8 +17,8 @@ |
| 18 | 17 | // |
| 19 | 18 | //===----------------------------------------------------------------------===// |
| 20 | 19 | |
| 21 | #ifndef LLD_ELF_SYNTHETIC_SECTION_H | |
| 22 | #define LLD_ELF_SYNTHETIC_SECTION_H | |
| 20 | #ifndef LLD_ELF_SYNTHETIC_SECTIONS_H | |
| 21 | #define LLD_ELF_SYNTHETIC_SECTIONS_H | |
| 23 | 22 | |
| 24 | 23 | #include "DWARF.h" |
| 25 | 24 | #include "EhFrame.h" |
| ... | ... | @@ -32,107 +31,113 @@ |
| 32 | 31 | namespace lld { |
| 33 | 32 | namespace elf { |
| 34 | 33 | class Defined; |
| 35 | class SharedSymbol; | |
| 34 | struct PhdrEntry; | |
| 35 | class SymbolTableBaseSection; | |
| 36 | class VersionNeedBaseSection; | |
| 36 | 37 | |
| 37 | 38 | class SyntheticSection : public InputSection { |
| 38 | 39 | public: |
| 39 | SyntheticSection(uint64_t Flags, uint32_t Type, uint32_t Alignment, | |
| 40 | StringRef Name) | |
| 41 | : InputSection(nullptr, Flags, Type, Alignment, {}, Name, | |
| 40 | SyntheticSection(uint64_t flags, uint32_t type, uint32_t alignment, | |
| 41 | StringRef name) | |
| 42 | : InputSection(nullptr, flags, type, alignment, {}, name, | |
| 42 | 43 | InputSectionBase::Synthetic) { |
| 43 | this->Live = true; | |
| 44 | markLive(); | |
| 44 | 45 | } |
| 45 | 46 | |
| 46 | 47 | virtual ~SyntheticSection() = default; |
| 47 | virtual void writeTo(uint8_t *Buf) = 0; | |
| 48 | virtual void writeTo(uint8_t *buf) = 0; | |
| 48 | 49 | virtual size_t getSize() const = 0; |
| 49 | 50 | virtual void finalizeContents() {} |
| 50 | 51 | // If the section has the SHF_ALLOC flag and the size may be changed if |
| 51 | 52 | // thunks are added, update the section size. |
| 52 | 53 | virtual bool updateAllocSize() { return false; } |
| 53 | virtual bool empty() const { return false; } | |
| 54 | virtual bool isNeeded() const { return true; } | |
| 54 | 55 | |
| 55 | static bool classof(const SectionBase *D) { | |
| 56 | return D->kind() == InputSectionBase::Synthetic; | |
| 56 | static bool classof(const SectionBase *d) { | |
| 57 | return d->kind() == InputSectionBase::Synthetic; | |
| 57 | 58 | } |
| 58 | 59 | }; |
| 59 | 60 | |
| 60 | 61 | struct CieRecord { |
| 61 | EhSectionPiece *Cie = nullptr; | |
| 62 | std::vector<EhSectionPiece *> Fdes; | |
| 62 | EhSectionPiece *cie = nullptr; | |
| 63 | std::vector<EhSectionPiece *> fdes; | |
| 63 | 64 | }; |
| 64 | 65 | |
| 65 | 66 | // Section for .eh_frame. |
| 66 | 67 | class EhFrameSection final : public SyntheticSection { |
| 67 | 68 | public: |
| 68 | 69 | EhFrameSection(); |
| 69 | void writeTo(uint8_t *Buf) override; | |
| 70 | void writeTo(uint8_t *buf) override; | |
| 70 | 71 | void finalizeContents() override; |
| 71 | bool empty() const override { return Sections.empty(); } | |
| 72 | size_t getSize() const override { return Size; } | |
| 72 | bool isNeeded() const override { return !sections.empty(); } | |
| 73 | size_t getSize() const override { return size; } | |
| 74 | ||
| 75 | static bool classof(const SectionBase *d) { | |
| 76 | return SyntheticSection::classof(d) && d->name == ".eh_frame"; | |
| 77 | } | |
| 73 | 78 | |
| 74 | template <class ELFT> void addSection(InputSectionBase *S); | |
| 79 | template <class ELFT> void addSection(InputSectionBase *s); | |
| 75 | 80 | |
| 76 | std::vector<EhInputSection *> Sections; | |
| 77 | size_t NumFdes = 0; | |
| 81 | std::vector<EhInputSection *> sections; | |
| 82 | size_t numFdes = 0; | |
| 78 | 83 | |
| 79 | 84 | struct FdeData { |
| 80 | uint32_t PcRel; | |
| 81 | uint32_t FdeVARel; | |
| 85 | uint32_t pcRel; | |
| 86 | uint32_t fdeVARel; | |
| 82 | 87 | }; |
| 83 | 88 | |
| 84 | 89 | std::vector<FdeData> getFdeData() const; |
| 85 | ArrayRef<CieRecord *> getCieRecords() const { return CieRecords; } | |
| 90 | ArrayRef<CieRecord *> getCieRecords() const { return cieRecords; } | |
| 86 | 91 | |
| 87 | 92 | private: |
| 88 | 93 | // This is used only when parsing EhInputSection. We keep it here to avoid |
| 89 | 94 | // allocating one for each EhInputSection. |
| 90 | llvm::DenseMap<size_t, CieRecord *> OffsetToCie; | |
| 95 | llvm::DenseMap<size_t, CieRecord *> offsetToCie; | |
| 91 | 96 | |
| 92 | uint64_t Size = 0; | |
| 97 | uint64_t size = 0; | |
| 93 | 98 | |
| 94 | 99 | template <class ELFT, class RelTy> |
| 95 | void addSectionAux(EhInputSection *S, llvm::ArrayRef<RelTy> Rels); | |
| 100 | void addSectionAux(EhInputSection *s, llvm::ArrayRef<RelTy> rels); | |
| 96 | 101 | |
| 97 | 102 | template <class ELFT, class RelTy> |
| 98 | CieRecord *addCie(EhSectionPiece &Piece, ArrayRef<RelTy> Rels); | |
| 103 | CieRecord *addCie(EhSectionPiece &piece, ArrayRef<RelTy> rels); | |
| 99 | 104 | |
| 100 | 105 | template <class ELFT, class RelTy> |
| 101 | bool isFdeLive(EhSectionPiece &Piece, ArrayRef<RelTy> Rels); | |
| 106 | bool isFdeLive(EhSectionPiece &piece, ArrayRef<RelTy> rels); | |
| 102 | 107 | |
| 103 | uint64_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc) const; | |
| 108 | uint64_t getFdePc(uint8_t *buf, size_t off, uint8_t enc) const; | |
| 104 | 109 | |
| 105 | std::vector<CieRecord *> CieRecords; | |
| 110 | std::vector<CieRecord *> cieRecords; | |
| 106 | 111 | |
| 107 | 112 | // CIE records are uniquified by their contents and personality functions. |
| 108 | llvm::DenseMap<std::pair<ArrayRef<uint8_t>, Symbol *>, CieRecord *> CieMap; | |
| 113 | llvm::DenseMap<std::pair<ArrayRef<uint8_t>, Symbol *>, CieRecord *> cieMap; | |
| 109 | 114 | }; |
| 110 | 115 | |
| 111 | 116 | class GotSection : public SyntheticSection { |
| 112 | 117 | public: |
| 113 | 118 | GotSection(); |
| 114 | size_t getSize() const override { return Size; } | |
| 119 | size_t getSize() const override { return size; } | |
| 115 | 120 | void finalizeContents() override; |
| 116 | bool empty() const override; | |
| 117 | void writeTo(uint8_t *Buf) override; | |
| 121 | bool isNeeded() const override; | |
| 122 | void writeTo(uint8_t *buf) override; | |
| 118 | 123 | |
| 119 | void addEntry(Symbol &Sym); | |
| 120 | bool addDynTlsEntry(Symbol &Sym); | |
| 124 | void addEntry(Symbol &sym); | |
| 125 | bool addDynTlsEntry(Symbol &sym); | |
| 121 | 126 | bool addTlsIndex(); |
| 122 | uint64_t getGlobalDynAddr(const Symbol &B) const; | |
| 123 | uint64_t getGlobalDynOffset(const Symbol &B) const; | |
| 127 | uint64_t getGlobalDynAddr(const Symbol &b) const; | |
| 128 | uint64_t getGlobalDynOffset(const Symbol &b) const; | |
| 124 | 129 | |
| 125 | uint64_t getTlsIndexVA() { return this->getVA() + TlsIndexOff; } | |
| 126 | uint32_t getTlsIndexOff() const { return TlsIndexOff; } | |
| 130 | uint64_t getTlsIndexVA() { return this->getVA() + tlsIndexOff; } | |
| 131 | uint32_t getTlsIndexOff() const { return tlsIndexOff; } | |
| 127 | 132 | |
| 128 | 133 | // Flag to force GOT to be in output if we have relocations |
| 129 | 134 | // that relies on its address. |
| 130 | bool HasGotOffRel = false; | |
| 135 | bool hasGotOffRel = false; | |
| 131 | 136 | |
| 132 | 137 | protected: |
| 133 | size_t NumEntries = 0; | |
| 134 | uint32_t TlsIndexOff = -1; | |
| 135 | uint64_t Size = 0; | |
| 138 | size_t numEntries = 0; | |
| 139 | uint32_t tlsIndexOff = -1; | |
| 140 | uint64_t size = 0; | |
| 136 | 141 | }; |
| 137 | 142 | |
| 138 | 143 | // .note.GNU-stack section. |
| ... | ... | @@ -140,27 +145,31 @@ class GnuStackSection : public SyntheticSection { |
| 140 | 145 | public: |
| 141 | 146 | GnuStackSection() |
| 142 | 147 | : SyntheticSection(0, llvm::ELF::SHT_PROGBITS, 1, ".note.GNU-stack") {} |
| 143 | void writeTo(uint8_t *Buf) override {} | |
| 148 | void writeTo(uint8_t *buf) override {} | |
| 144 | 149 | size_t getSize() const override { return 0; } |
| 145 | 150 | }; |
| 146 | 151 | |
| 152 | class GnuPropertySection : public SyntheticSection { | |
| 153 | public: | |
| 154 | GnuPropertySection(); | |
| 155 | void writeTo(uint8_t *buf) override; | |
| 156 | size_t getSize() const override; | |
| 157 | }; | |
| 158 | ||
| 147 | 159 | // .note.gnu.build-id section. |
| 148 | 160 | class BuildIdSection : public SyntheticSection { |
| 149 | 161 | // First 16 bytes are a header. |
| 150 | static const unsigned HeaderSize = 16; | |
| 162 | static const unsigned headerSize = 16; | |
| 151 | 163 | |
| 152 | 164 | public: |
| 165 | const size_t hashSize; | |
| 153 | 166 | BuildIdSection(); |
| 154 | void writeTo(uint8_t *Buf) override; | |
| 155 | size_t getSize() const override { return HeaderSize + HashSize; } | |
| 156 | void writeBuildId(llvm::ArrayRef<uint8_t> Buf); | |
| 167 | void writeTo(uint8_t *buf) override; | |
| 168 | size_t getSize() const override { return headerSize + hashSize; } | |
| 169 | void writeBuildId(llvm::ArrayRef<uint8_t> buf); | |
| 157 | 170 | |
| 158 | 171 | private: |
| 159 | void computeHash(llvm::ArrayRef<uint8_t> Buf, | |
| 160 | std::function<void(uint8_t *, ArrayRef<uint8_t>)> Hash); | |
| 161 | ||
| 162 | size_t HashSize; | |
| 163 | uint8_t *HashBuf; | |
| 172 | uint8_t *hashBuf; | |
| 164 | 173 | }; |
| 165 | 174 | |
| 166 | 175 | // BssSection is used to reserve space for copy relocations and common symbols. |
| ... | ... | @@ -169,40 +178,40 @@ private: |
| 169 | 178 | // respectively. |
| 170 | 179 | class BssSection final : public SyntheticSection { |
| 171 | 180 | public: |
| 172 | BssSection(StringRef Name, uint64_t Size, uint32_t Alignment); | |
| 181 | BssSection(StringRef name, uint64_t size, uint32_t alignment); | |
| 173 | 182 | void writeTo(uint8_t *) override { |
| 174 | 183 | llvm_unreachable("unexpected writeTo() call for SHT_NOBITS section"); |
| 175 | 184 | } |
| 176 | bool empty() const override { return getSize() == 0; } | |
| 177 | size_t getSize() const override { return Size; } | |
| 185 | bool isNeeded() const override { return size != 0; } | |
| 186 | size_t getSize() const override { return size; } | |
| 178 | 187 | |
| 179 | static bool classof(const SectionBase *S) { return S->Bss; } | |
| 180 | uint64_t Size; | |
| 188 | static bool classof(const SectionBase *s) { return s->bss; } | |
| 189 | uint64_t size; | |
| 181 | 190 | }; |
| 182 | 191 | |
| 183 | 192 | class MipsGotSection final : public SyntheticSection { |
| 184 | 193 | public: |
| 185 | 194 | MipsGotSection(); |
| 186 | void writeTo(uint8_t *Buf) override; | |
| 187 | size_t getSize() const override { return Size; } | |
| 195 | void writeTo(uint8_t *buf) override; | |
| 196 | size_t getSize() const override { return size; } | |
| 188 | 197 | bool updateAllocSize() override; |
| 189 | 198 | void finalizeContents() override; |
| 190 | bool empty() const override; | |
| 199 | bool isNeeded() const override; | |
| 191 | 200 | |
| 192 | 201 | // Join separate GOTs built for each input file to generate |
| 193 | 202 | // primary and optional multiple secondary GOTs. |
| 194 | template <class ELFT> void build(); | |
| 203 | void build(); | |
| 195 | 204 | |
| 196 | void addEntry(InputFile &File, Symbol &Sym, int64_t Addend, RelExpr Expr); | |
| 197 | void addDynTlsEntry(InputFile &File, Symbol &Sym); | |
| 198 | void addTlsIndex(InputFile &File); | |
| 205 | void addEntry(InputFile &file, Symbol &sym, int64_t addend, RelExpr expr); | |
| 206 | void addDynTlsEntry(InputFile &file, Symbol &sym); | |
| 207 | void addTlsIndex(InputFile &file); | |
| 199 | 208 | |
| 200 | uint64_t getPageEntryOffset(const InputFile *F, const Symbol &S, | |
| 201 | int64_t Addend) const; | |
| 202 | uint64_t getSymEntryOffset(const InputFile *F, const Symbol &S, | |
| 203 | int64_t Addend) const; | |
| 204 | uint64_t getGlobalDynOffset(const InputFile *F, const Symbol &S) const; | |
| 205 | uint64_t getTlsIndexOffset(const InputFile *F) const; | |
| 209 | uint64_t getPageEntryOffset(const InputFile *f, const Symbol &s, | |
| 210 | int64_t addend) const; | |
| 211 | uint64_t getSymEntryOffset(const InputFile *f, const Symbol &s, | |
| 212 | int64_t addend) const; | |
| 213 | uint64_t getGlobalDynOffset(const InputFile *f, const Symbol &s) const; | |
| 214 | uint64_t getTlsIndexOffset(const InputFile *f) const; | |
| 206 | 215 | |
| 207 | 216 | // Returns the symbol which corresponds to the first entry of the global part |
| 208 | 217 | // of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic |
| ... | ... | @@ -215,7 +224,7 @@ public: |
| 215 | 224 | unsigned getLocalEntriesNum() const; |
| 216 | 225 | |
| 217 | 226 | // Return _gp value for primary GOT (nullptr) or particular input file. |
| 218 | uint64_t getGp(const InputFile *F = nullptr) const; | |
| 227 | uint64_t getGp(const InputFile *f = nullptr) const; | |
| 219 | 228 | |
| 220 | 229 | private: |
| 221 | 230 | // MIPS GOT consists of three parts: local, global and tls. Each part |
| ... | ... | @@ -305,34 +314,35 @@ private: |
| 305 | 314 | // https://dmz-portal.mips.com/wiki/MIPS_Multi_GOT |
| 306 | 315 | |
| 307 | 316 | // Number of "Header" entries. |
| 308 | static const unsigned HeaderEntriesNum = 2; | |
| 317 | static const unsigned headerEntriesNum = 2; | |
| 309 | 318 | |
| 310 | uint64_t Size = 0; | |
| 319 | uint64_t size = 0; | |
| 311 | 320 | |
| 312 | 321 | // Symbol and addend. |
| 313 | typedef std::pair<Symbol *, int64_t> GotEntry; | |
| 322 | using GotEntry = std::pair<Symbol *, int64_t>; | |
| 314 | 323 | |
| 315 | 324 | struct FileGot { |
| 316 | InputFile *File = nullptr; | |
| 317 | size_t StartIndex = 0; | |
| 325 | InputFile *file = nullptr; | |
| 326 | size_t startIndex = 0; | |
| 318 | 327 | |
| 319 | 328 | struct PageBlock { |
| 320 | size_t FirstIndex = 0; | |
| 321 | size_t Count = 0; | |
| 329 | size_t firstIndex; | |
| 330 | size_t count; | |
| 331 | PageBlock() : firstIndex(0), count(0) {} | |
| 322 | 332 | }; |
| 323 | 333 | |
| 324 | 334 | // Map output sections referenced by MIPS GOT relocations |
| 325 | 335 | // to the description (index/count) "page" entries allocated |
| 326 | 336 | // for this section. |
| 327 | llvm::SmallMapVector<const OutputSection *, PageBlock, 16> PagesMap; | |
| 337 | llvm::SmallMapVector<const OutputSection *, PageBlock, 16> pagesMap; | |
| 328 | 338 | // Maps from Symbol+Addend pair or just Symbol to the GOT entry index. |
| 329 | llvm::MapVector<GotEntry, size_t> Local16; | |
| 330 | llvm::MapVector<GotEntry, size_t> Local32; | |
| 331 | llvm::MapVector<Symbol *, size_t> Global; | |
| 332 | llvm::MapVector<Symbol *, size_t> Relocs; | |
| 333 | llvm::MapVector<Symbol *, size_t> Tls; | |
| 339 | llvm::MapVector<GotEntry, size_t> local16; | |
| 340 | llvm::MapVector<GotEntry, size_t> local32; | |
| 341 | llvm::MapVector<Symbol *, size_t> global; | |
| 342 | llvm::MapVector<Symbol *, size_t> relocs; | |
| 343 | llvm::MapVector<Symbol *, size_t> tls; | |
| 334 | 344 | // Set of symbols referenced by dynamic TLS relocations. |
| 335 | llvm::MapVector<Symbol *, size_t> DynTlsSymbols; | |
| 345 | llvm::MapVector<Symbol *, size_t> dynTlsSymbols; | |
| 336 | 346 | |
| 337 | 347 | // Total number of all entries. |
| 338 | 348 | size_t getEntriesNum() const; |
| ... | ... | @@ -345,27 +355,31 @@ private: |
| 345 | 355 | // Container of GOT created for each input file. |
| 346 | 356 | // After building a final series of GOTs this container |
| 347 | 357 | // holds primary and secondary GOT's. |
| 348 | std::vector<FileGot> Gots; | |
| 358 | std::vector<FileGot> gots; | |
| 349 | 359 | |
| 350 | 360 | // Return (and create if necessary) `FileGot`. |
| 351 | FileGot &getGot(InputFile &F); | |
| 361 | FileGot &getGot(InputFile &f); | |
| 352 | 362 | |
| 353 | 363 | // Try to merge two GOTs. In case of success the `Dst` contains |
| 354 | 364 | // result of merging and the function returns true. In case of |
| 355 | 365 | // ovwerflow the `Dst` is unchanged and the function returns false. |
| 356 | bool tryMergeGots(FileGot & Dst, FileGot & Src, bool IsPrimary); | |
| 366 | bool tryMergeGots(FileGot & dst, FileGot & src, bool isPrimary); | |
| 357 | 367 | }; |
| 358 | 368 | |
| 359 | 369 | class GotPltSection final : public SyntheticSection { |
| 360 | 370 | public: |
| 361 | 371 | GotPltSection(); |
| 362 | void addEntry(Symbol &Sym); | |
| 372 | void addEntry(Symbol &sym); | |
| 363 | 373 | size_t getSize() const override; |
| 364 | void writeTo(uint8_t *Buf) override; | |
| 365 | bool empty() const override; | |
| 374 | void writeTo(uint8_t *buf) override; | |
| 375 | bool isNeeded() const override; | |
| 376 | ||
| 377 | // Flag to force GotPlt to be in output if we have relocations | |
| 378 | // that relies on its address. | |
| 379 | bool hasGotPltOffRel = false; | |
| 366 | 380 | |
| 367 | 381 | private: |
| 368 | std::vector<const Symbol *> Entries; | |
| 382 | std::vector<const Symbol *> entries; | |
| 369 | 383 | }; |
| 370 | 384 | |
| 371 | 385 | // The IgotPltSection is a Got associated with the PltSection for GNU Ifunc |
| ... | ... | @@ -375,167 +389,164 @@ private: |
| 375 | 389 | class IgotPltSection final : public SyntheticSection { |
| 376 | 390 | public: |
| 377 | 391 | IgotPltSection(); |
| 378 | void addEntry(Symbol &Sym); | |
| 392 | void addEntry(Symbol &sym); | |
| 379 | 393 | size_t getSize() const override; |
| 380 | void writeTo(uint8_t *Buf) override; | |
| 381 | bool empty() const override { return Entries.empty(); } | |
| 394 | void writeTo(uint8_t *buf) override; | |
| 395 | bool isNeeded() const override { return !entries.empty(); } | |
| 382 | 396 | |
| 383 | 397 | private: |
| 384 | std::vector<const Symbol *> Entries; | |
| 398 | std::vector<const Symbol *> entries; | |
| 385 | 399 | }; |
| 386 | 400 | |
| 387 | 401 | class StringTableSection final : public SyntheticSection { |
| 388 | 402 | public: |
| 389 | StringTableSection(StringRef Name, bool Dynamic); | |
| 390 | unsigned addString(StringRef S, bool HashIt = true); | |
| 391 | void writeTo(uint8_t *Buf) override; | |
| 392 | size_t getSize() const override { return Size; } | |
| 393 | bool isDynamic() const { return Dynamic; } | |
| 403 | StringTableSection(StringRef name, bool dynamic); | |
| 404 | unsigned addString(StringRef s, bool hashIt = true); | |
| 405 | void writeTo(uint8_t *buf) override; | |
| 406 | size_t getSize() const override { return size; } | |
| 407 | bool isDynamic() const { return dynamic; } | |
| 394 | 408 | |
| 395 | 409 | private: |
| 396 | const bool Dynamic; | |
| 410 | const bool dynamic; | |
| 397 | 411 | |
| 398 | uint64_t Size = 0; | |
| 412 | uint64_t size = 0; | |
| 399 | 413 | |
| 400 | llvm::DenseMap<StringRef, unsigned> StringMap; | |
| 401 | std::vector<StringRef> Strings; | |
| 414 | llvm::DenseMap<StringRef, unsigned> stringMap; | |
| 415 | std::vector<StringRef> strings; | |
| 402 | 416 | }; |
| 403 | 417 | |
| 404 | 418 | class DynamicReloc { |
| 405 | 419 | public: |
| 406 | DynamicReloc(RelType Type, const InputSectionBase *InputSec, | |
| 407 | uint64_t OffsetInSec, bool UseSymVA, Symbol *Sym, int64_t Addend) | |
| 408 | : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec), | |
| 409 | UseSymVA(UseSymVA), Addend(Addend), OutputSec(nullptr) {} | |
| 420 | DynamicReloc(RelType type, const InputSectionBase *inputSec, | |
| 421 | uint64_t offsetInSec, bool useSymVA, Symbol *sym, int64_t addend) | |
| 422 | : type(type), sym(sym), inputSec(inputSec), offsetInSec(offsetInSec), | |
| 423 | useSymVA(useSymVA), addend(addend), outputSec(nullptr) {} | |
| 410 | 424 | // This constructor records dynamic relocation settings used by MIPS |
| 411 | 425 | // multi-GOT implementation. It's to relocate addresses of 64kb pages |
| 412 | 426 | // lie inside the output section. |
| 413 | DynamicReloc(RelType Type, const InputSectionBase *InputSec, | |
| 414 | uint64_t OffsetInSec, const OutputSection *OutputSec, | |
| 415 | int64_t Addend) | |
| 416 | : Type(Type), Sym(nullptr), InputSec(InputSec), OffsetInSec(OffsetInSec), | |
| 417 | UseSymVA(false), Addend(Addend), OutputSec(OutputSec) {} | |
| 427 | DynamicReloc(RelType type, const InputSectionBase *inputSec, | |
| 428 | uint64_t offsetInSec, const OutputSection *outputSec, | |
| 429 | int64_t addend) | |
| 430 | : type(type), sym(nullptr), inputSec(inputSec), offsetInSec(offsetInSec), | |
| 431 | useSymVA(false), addend(addend), outputSec(outputSec) {} | |
| 418 | 432 | |
| 419 | 433 | uint64_t getOffset() const; |
| 420 | uint32_t getSymIndex() const; | |
| 421 | const InputSectionBase *getInputSec() const { return InputSec; } | |
| 434 | uint32_t getSymIndex(SymbolTableBaseSection *symTab) const; | |
| 422 | 435 | |
| 423 | 436 | // Computes the addend of the dynamic relocation. Note that this is not the |
| 424 | // same as the Addend member variable as it also includes the symbol address | |
| 425 | // if UseSymVA is true. | |
| 437 | // same as the addend member variable as it also includes the symbol address | |
| 438 | // if useSymVA is true. | |
| 426 | 439 | int64_t computeAddend() const; |
| 427 | 440 | |
| 428 | RelType Type; | |
| 441 | RelType type; | |
| 429 | 442 | |
| 430 | private: | |
| 431 | Symbol *Sym; | |
| 432 | const InputSectionBase *InputSec = nullptr; | |
| 433 | uint64_t OffsetInSec; | |
| 443 | Symbol *sym; | |
| 444 | const InputSectionBase *inputSec = nullptr; | |
| 445 | uint64_t offsetInSec; | |
| 434 | 446 | // If this member is true, the dynamic relocation will not be against the |
| 435 | 447 | // symbol but will instead be a relative relocation that simply adds the |
| 436 | 448 | // load address. This means we need to write the symbol virtual address |
| 437 | 449 | // plus the original addend as the final relocation addend. |
| 438 | bool UseSymVA; | |
| 439 | int64_t Addend; | |
| 440 | const OutputSection *OutputSec; | |
| 450 | bool useSymVA; | |
| 451 | int64_t addend; | |
| 452 | const OutputSection *outputSec; | |
| 441 | 453 | }; |
| 442 | 454 | |
| 443 | 455 | template <class ELFT> class DynamicSection final : public SyntheticSection { |
| 444 | typedef typename ELFT::Dyn Elf_Dyn; | |
| 445 | typedef typename ELFT::Rel Elf_Rel; | |
| 446 | typedef typename ELFT::Rela Elf_Rela; | |
| 447 | typedef typename ELFT::Relr Elf_Relr; | |
| 448 | typedef typename ELFT::Shdr Elf_Shdr; | |
| 449 | typedef typename ELFT::Sym Elf_Sym; | |
| 456 | using Elf_Dyn = typename ELFT::Dyn; | |
| 457 | using Elf_Rel = typename ELFT::Rel; | |
| 458 | using Elf_Rela = typename ELFT::Rela; | |
| 459 | using Elf_Relr = typename ELFT::Relr; | |
| 460 | using Elf_Shdr = typename ELFT::Shdr; | |
| 461 | using Elf_Sym = typename ELFT::Sym; | |
| 450 | 462 | |
| 451 | 463 | // finalizeContents() fills this vector with the section contents. |
| 452 | std::vector<std::pair<int32_t, std::function<uint64_t()>>> Entries; | |
| 464 | std::vector<std::pair<int32_t, std::function<uint64_t()>>> entries; | |
| 453 | 465 | |
| 454 | 466 | public: |
| 455 | 467 | DynamicSection(); |
| 456 | 468 | void finalizeContents() override; |
| 457 | void writeTo(uint8_t *Buf) override; | |
| 458 | size_t getSize() const override { return Size; } | |
| 469 | void writeTo(uint8_t *buf) override; | |
| 470 | size_t getSize() const override { return size; } | |
| 459 | 471 | |
| 460 | 472 | private: |
| 461 | void add(int32_t Tag, std::function<uint64_t()> Fn); | |
| 462 | void addInt(int32_t Tag, uint64_t Val); | |
| 463 | void addInSec(int32_t Tag, InputSection *Sec); | |
| 464 | void addInSecRelative(int32_t Tag, InputSection *Sec); | |
| 465 | void addOutSec(int32_t Tag, OutputSection *Sec); | |
| 466 | void addSize(int32_t Tag, OutputSection *Sec); | |
| 467 | void addSym(int32_t Tag, Symbol *Sym); | |
| 468 | ||
| 469 | uint64_t Size = 0; | |
| 473 | void add(int32_t tag, std::function<uint64_t()> fn); | |
| 474 | void addInt(int32_t tag, uint64_t val); | |
| 475 | void addInSec(int32_t tag, InputSection *sec); | |
| 476 | void addInSecRelative(int32_t tag, InputSection *sec); | |
| 477 | void addOutSec(int32_t tag, OutputSection *sec); | |
| 478 | void addSize(int32_t tag, OutputSection *sec); | |
| 479 | void addSym(int32_t tag, Symbol *sym); | |
| 480 | ||
| 481 | uint64_t size = 0; | |
| 470 | 482 | }; |
| 471 | 483 | |
| 472 | 484 | class RelocationBaseSection : public SyntheticSection { |
| 473 | 485 | public: |
| 474 | RelocationBaseSection(StringRef Name, uint32_t Type, int32_t DynamicTag, | |
| 475 | int32_t SizeDynamicTag); | |
| 476 | void addReloc(RelType DynType, InputSectionBase *IS, uint64_t OffsetInSec, | |
| 477 | Symbol *Sym); | |
| 486 | RelocationBaseSection(StringRef name, uint32_t type, int32_t dynamicTag, | |
| 487 | int32_t sizeDynamicTag); | |
| 488 | void addReloc(RelType dynType, InputSectionBase *isec, uint64_t offsetInSec, | |
| 489 | Symbol *sym); | |
| 478 | 490 | // Add a dynamic relocation that might need an addend. This takes care of |
| 479 | 491 | // writing the addend to the output section if needed. |
| 480 | void addReloc(RelType DynType, InputSectionBase *InputSec, | |
| 481 | uint64_t OffsetInSec, Symbol *Sym, int64_t Addend, RelExpr Expr, | |
| 482 | RelType Type); | |
| 483 | void addReloc(const DynamicReloc &Reloc); | |
| 484 | bool empty() const override { return Relocs.empty(); } | |
| 485 | size_t getSize() const override { return Relocs.size() * this->Entsize; } | |
| 486 | size_t getRelativeRelocCount() const { return NumRelativeRelocs; } | |
| 492 | void addReloc(RelType dynType, InputSectionBase *inputSec, | |
| 493 | uint64_t offsetInSec, Symbol *sym, int64_t addend, RelExpr expr, | |
| 494 | RelType type); | |
| 495 | void addReloc(const DynamicReloc &reloc); | |
| 496 | bool isNeeded() const override { return !relocs.empty(); } | |
| 497 | size_t getSize() const override { return relocs.size() * this->entsize; } | |
| 498 | size_t getRelativeRelocCount() const { return numRelativeRelocs; } | |
| 487 | 499 | void finalizeContents() override; |
| 488 | int32_t DynamicTag, SizeDynamicTag; | |
| 500 | int32_t dynamicTag, sizeDynamicTag; | |
| 501 | std::vector<DynamicReloc> relocs; | |
| 489 | 502 | |
| 490 | 503 | protected: |
| 491 | std::vector<DynamicReloc> Relocs; | |
| 492 | size_t NumRelativeRelocs = 0; | |
| 504 | size_t numRelativeRelocs = 0; | |
| 493 | 505 | }; |
| 494 | 506 | |
| 495 | 507 | template <class ELFT> |
| 496 | 508 | class RelocationSection final : public RelocationBaseSection { |
| 497 | typedef typename ELFT::Rel Elf_Rel; | |
| 498 | typedef typename ELFT::Rela Elf_Rela; | |
| 509 | using Elf_Rel = typename ELFT::Rel; | |
| 510 | using Elf_Rela = typename ELFT::Rela; | |
| 499 | 511 | |
| 500 | 512 | public: |
| 501 | RelocationSection(StringRef Name, bool Sort); | |
| 502 | unsigned getRelocOffset(); | |
| 503 | void writeTo(uint8_t *Buf) override; | |
| 513 | RelocationSection(StringRef name, bool sort); | |
| 514 | void writeTo(uint8_t *buf) override; | |
| 504 | 515 | |
| 505 | 516 | private: |
| 506 | bool Sort; | |
| 517 | bool sort; | |
| 507 | 518 | }; |
| 508 | 519 | |
| 509 | 520 | template <class ELFT> |
| 510 | 521 | class AndroidPackedRelocationSection final : public RelocationBaseSection { |
| 511 | typedef typename ELFT::Rel Elf_Rel; | |
| 512 | typedef typename ELFT::Rela Elf_Rela; | |
| 522 | using Elf_Rel = typename ELFT::Rel; | |
| 523 | using Elf_Rela = typename ELFT::Rela; | |
| 513 | 524 | |
| 514 | 525 | public: |
| 515 | AndroidPackedRelocationSection(StringRef Name); | |
| 526 | AndroidPackedRelocationSection(StringRef name); | |
| 516 | 527 | |
| 517 | 528 | bool updateAllocSize() override; |
| 518 | size_t getSize() const override { return RelocData.size(); } | |
| 519 | void writeTo(uint8_t *Buf) override { | |
| 520 | memcpy(Buf, RelocData.data(), RelocData.size()); | |
| 529 | size_t getSize() const override { return relocData.size(); } | |
| 530 | void writeTo(uint8_t *buf) override { | |
| 531 | memcpy(buf, relocData.data(), relocData.size()); | |
| 521 | 532 | } |
| 522 | 533 | |
| 523 | 534 | private: |
| 524 | SmallVector<char, 0> RelocData; | |
| 535 | SmallVector<char, 0> relocData; | |
| 525 | 536 | }; |
| 526 | 537 | |
| 527 | 538 | struct RelativeReloc { |
| 528 | uint64_t getOffset() const { return InputSec->getVA(OffsetInSec); } | |
| 539 | uint64_t getOffset() const { return inputSec->getVA(offsetInSec); } | |
| 529 | 540 | |
| 530 | const InputSectionBase *InputSec; | |
| 531 | uint64_t OffsetInSec; | |
| 541 | const InputSectionBase *inputSec; | |
| 542 | uint64_t offsetInSec; | |
| 532 | 543 | }; |
| 533 | 544 | |
| 534 | 545 | class RelrBaseSection : public SyntheticSection { |
| 535 | 546 | public: |
| 536 | 547 | RelrBaseSection(); |
| 537 | bool empty() const override { return Relocs.empty(); } | |
| 538 | std::vector<RelativeReloc> Relocs; | |
| 548 | bool isNeeded() const override { return !relocs.empty(); } | |
| 549 | std::vector<RelativeReloc> relocs; | |
| 539 | 550 | }; |
| 540 | 551 | |
| 541 | 552 | // RelrSection is used to encode offsets for relative relocations. |
| ... | ... | @@ -543,65 +554,65 @@ public: |
| 543 | 554 | // https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg |
| 544 | 555 | // For more details, see the comment in RelrSection::updateAllocSize(). |
| 545 | 556 | template <class ELFT> class RelrSection final : public RelrBaseSection { |
| 546 | typedef typename ELFT::Relr Elf_Relr; | |
| 557 | using Elf_Relr = typename ELFT::Relr; | |
| 547 | 558 | |
| 548 | 559 | public: |
| 549 | 560 | RelrSection(); |
| 550 | 561 | |
| 551 | 562 | bool updateAllocSize() override; |
| 552 | size_t getSize() const override { return RelrRelocs.size() * this->Entsize; } | |
| 553 | void writeTo(uint8_t *Buf) override { | |
| 554 | memcpy(Buf, RelrRelocs.data(), getSize()); | |
| 563 | size_t getSize() const override { return relrRelocs.size() * this->entsize; } | |
| 564 | void writeTo(uint8_t *buf) override { | |
| 565 | memcpy(buf, relrRelocs.data(), getSize()); | |
| 555 | 566 | } |
| 556 | 567 | |
| 557 | 568 | private: |
| 558 | std::vector<Elf_Relr> RelrRelocs; | |
| 569 | std::vector<Elf_Relr> relrRelocs; | |
| 559 | 570 | }; |
| 560 | 571 | |
| 561 | 572 | struct SymbolTableEntry { |
| 562 | Symbol *Sym; | |
| 563 | size_t StrTabOffset; | |
| 573 | Symbol *sym; | |
| 574 | size_t strTabOffset; | |
| 564 | 575 | }; |
| 565 | 576 | |
| 566 | 577 | class SymbolTableBaseSection : public SyntheticSection { |
| 567 | 578 | public: |
| 568 | SymbolTableBaseSection(StringTableSection &StrTabSec); | |
| 579 | SymbolTableBaseSection(StringTableSection &strTabSec); | |
| 569 | 580 | void finalizeContents() override; |
| 570 | size_t getSize() const override { return getNumSymbols() * Entsize; } | |
| 571 | void addSymbol(Symbol *Sym); | |
| 572 | unsigned getNumSymbols() const { return Symbols.size() + 1; } | |
| 573 | size_t getSymbolIndex(Symbol *Sym); | |
| 574 | ArrayRef<SymbolTableEntry> getSymbols() const { return Symbols; } | |
| 581 | size_t getSize() const override { return getNumSymbols() * entsize; } | |
| 582 | void addSymbol(Symbol *sym); | |
| 583 | unsigned getNumSymbols() const { return symbols.size() + 1; } | |
| 584 | size_t getSymbolIndex(Symbol *sym); | |
| 585 | ArrayRef<SymbolTableEntry> getSymbols() const { return symbols; } | |
| 575 | 586 | |
| 576 | 587 | protected: |
| 577 | 588 | void sortSymTabSymbols(); |
| 578 | 589 | |
| 579 | 590 | // A vector of symbols and their string table offsets. |
| 580 | std::vector<SymbolTableEntry> Symbols; | |
| 591 | std::vector<SymbolTableEntry> symbols; | |
| 581 | 592 | |
| 582 | StringTableSection &StrTabSec; | |
| 593 | StringTableSection &strTabSec; | |
| 583 | 594 | |
| 584 | llvm::once_flag OnceFlag; | |
| 585 | llvm::DenseMap<Symbol *, size_t> SymbolIndexMap; | |
| 586 | llvm::DenseMap<OutputSection *, size_t> SectionIndexMap; | |
| 595 | llvm::once_flag onceFlag; | |
| 596 | llvm::DenseMap<Symbol *, size_t> symbolIndexMap; | |
| 597 | llvm::DenseMap<OutputSection *, size_t> sectionIndexMap; | |
| 587 | 598 | }; |
| 588 | 599 | |
| 589 | 600 | template <class ELFT> |
| 590 | 601 | class SymbolTableSection final : public SymbolTableBaseSection { |
| 591 | typedef typename ELFT::Sym Elf_Sym; | |
| 602 | using Elf_Sym = typename ELFT::Sym; | |
| 592 | 603 | |
| 593 | 604 | public: |
| 594 | SymbolTableSection(StringTableSection &StrTabSec); | |
| 595 | void writeTo(uint8_t *Buf) override; | |
| 605 | SymbolTableSection(StringTableSection &strTabSec); | |
| 606 | void writeTo(uint8_t *buf) override; | |
| 596 | 607 | }; |
| 597 | 608 | |
| 598 | 609 | class SymtabShndxSection final : public SyntheticSection { |
| 599 | 610 | public: |
| 600 | 611 | SymtabShndxSection(); |
| 601 | 612 | |
| 602 | void writeTo(uint8_t *Buf) override; | |
| 613 | void writeTo(uint8_t *buf) override; | |
| 603 | 614 | size_t getSize() const override; |
| 604 | bool empty() const override; | |
| 615 | bool isNeeded() const override; | |
| 605 | 616 | void finalizeContents() override; |
| 606 | 617 | }; |
| 607 | 618 | |
| ... | ... | @@ -611,42 +622,42 @@ class GnuHashTableSection final : public SyntheticSection { |
| 611 | 622 | public: |
| 612 | 623 | GnuHashTableSection(); |
| 613 | 624 | void finalizeContents() override; |
| 614 | void writeTo(uint8_t *Buf) override; | |
| 615 | size_t getSize() const override { return Size; } | |
| 625 | void writeTo(uint8_t *buf) override; | |
| 626 | size_t getSize() const override { return size; } | |
| 616 | 627 | |
| 617 | 628 | // Adds symbols to the hash table. |
| 618 | 629 | // Sorts the input to satisfy GNU hash section requirements. |
| 619 | void addSymbols(std::vector<SymbolTableEntry> &Symbols); | |
| 630 | void addSymbols(std::vector<SymbolTableEntry> &symbols); | |
| 620 | 631 | |
| 621 | 632 | private: |
| 622 | 633 | // See the comment in writeBloomFilter. |
| 623 | 634 | enum { Shift2 = 26 }; |
| 624 | 635 | |
| 625 | void writeBloomFilter(uint8_t *Buf); | |
| 626 | void writeHashTable(uint8_t *Buf); | |
| 636 | void writeBloomFilter(uint8_t *buf); | |
| 637 | void writeHashTable(uint8_t *buf); | |
| 627 | 638 | |
| 628 | 639 | struct Entry { |
| 629 | Symbol *Sym; | |
| 630 | size_t StrTabOffset; | |
| 631 | uint32_t Hash; | |
| 632 | uint32_t BucketIdx; | |
| 640 | Symbol *sym; | |
| 641 | size_t strTabOffset; | |
| 642 | uint32_t hash; | |
| 643 | uint32_t bucketIdx; | |
| 633 | 644 | }; |
| 634 | 645 | |
| 635 | std::vector<Entry> Symbols; | |
| 636 | size_t MaskWords; | |
| 637 | size_t NBuckets = 0; | |
| 638 | size_t Size = 0; | |
| 646 | std::vector<Entry> symbols; | |
| 647 | size_t maskWords; | |
| 648 | size_t nBuckets = 0; | |
| 649 | size_t size = 0; | |
| 639 | 650 | }; |
| 640 | 651 | |
| 641 | 652 | class HashTableSection final : public SyntheticSection { |
| 642 | 653 | public: |
| 643 | 654 | HashTableSection(); |
| 644 | 655 | void finalizeContents() override; |
| 645 | void writeTo(uint8_t *Buf) override; | |
| 646 | size_t getSize() const override { return Size; } | |
| 656 | void writeTo(uint8_t *buf) override; | |
| 657 | size_t getSize() const override { return size; } | |
| 647 | 658 | |
| 648 | 659 | private: |
| 649 | size_t Size = 0; | |
| 660 | size_t size = 0; | |
| 650 | 661 | }; |
| 651 | 662 | |
| 652 | 663 | // The PltSection is used for both the Plt and Iplt. The former usually has a |
| ... | ... | @@ -655,67 +666,66 @@ private: |
| 655 | 666 | // Target->IRelativeRel. |
| 656 | 667 | class PltSection : public SyntheticSection { |
| 657 | 668 | public: |
| 658 | PltSection(bool IsIplt); | |
| 659 | void writeTo(uint8_t *Buf) override; | |
| 669 | PltSection(bool isIplt); | |
| 670 | void writeTo(uint8_t *buf) override; | |
| 660 | 671 | size_t getSize() const override; |
| 661 | bool empty() const override { return Entries.empty(); } | |
| 672 | bool isNeeded() const override { return !entries.empty(); } | |
| 662 | 673 | void addSymbols(); |
| 663 | template <class ELFT> void addEntry(Symbol &Sym); | |
| 674 | template <class ELFT> void addEntry(Symbol &sym); | |
| 664 | 675 | |
| 665 | size_t HeaderSize; | |
| 676 | size_t headerSize; | |
| 666 | 677 | |
| 667 | 678 | private: |
| 668 | unsigned getPltRelocOff() const; | |
| 669 | std::vector<std::pair<const Symbol *, unsigned>> Entries; | |
| 670 | bool IsIplt; | |
| 679 | std::vector<const Symbol *> entries; | |
| 680 | bool isIplt; | |
| 671 | 681 | }; |
| 672 | 682 | |
| 673 | 683 | class GdbIndexSection final : public SyntheticSection { |
| 674 | 684 | public: |
| 675 | 685 | struct AddressEntry { |
| 676 | InputSection *Section; | |
| 677 | uint64_t LowAddress; | |
| 678 | uint64_t HighAddress; | |
| 679 | uint32_t CuIndex; | |
| 686 | InputSection *section; | |
| 687 | uint64_t lowAddress; | |
| 688 | uint64_t highAddress; | |
| 689 | uint32_t cuIndex; | |
| 680 | 690 | }; |
| 681 | 691 | |
| 682 | 692 | struct CuEntry { |
| 683 | uint64_t CuOffset; | |
| 684 | uint64_t CuLength; | |
| 693 | uint64_t cuOffset; | |
| 694 | uint64_t cuLength; | |
| 685 | 695 | }; |
| 686 | 696 | |
| 687 | 697 | struct NameAttrEntry { |
| 688 | llvm::CachedHashStringRef Name; | |
| 689 | uint32_t CuIndexAndAttrs; | |
| 698 | llvm::CachedHashStringRef name; | |
| 699 | uint32_t cuIndexAndAttrs; | |
| 690 | 700 | }; |
| 691 | 701 | |
| 692 | 702 | struct GdbChunk { |
| 693 | InputSection *Sec; | |
| 694 | std::vector<AddressEntry> AddressAreas; | |
| 695 | std::vector<CuEntry> CompilationUnits; | |
| 703 | InputSection *sec; | |
| 704 | std::vector<AddressEntry> addressAreas; | |
| 705 | std::vector<CuEntry> compilationUnits; | |
| 696 | 706 | }; |
| 697 | 707 | |
| 698 | 708 | struct GdbSymbol { |
| 699 | llvm::CachedHashStringRef Name; | |
| 700 | std::vector<uint32_t> CuVector; | |
| 701 | uint32_t NameOff; | |
| 702 | uint32_t CuVectorOff; | |
| 709 | llvm::CachedHashStringRef name; | |
| 710 | std::vector<uint32_t> cuVector; | |
| 711 | uint32_t nameOff; | |
| 712 | uint32_t cuVectorOff; | |
| 703 | 713 | }; |
| 704 | 714 | |
| 705 | 715 | GdbIndexSection(); |
| 706 | 716 | template <typename ELFT> static GdbIndexSection *create(); |
| 707 | void writeTo(uint8_t *Buf) override; | |
| 708 | size_t getSize() const override { return Size; } | |
| 709 | bool empty() const override; | |
| 717 | void writeTo(uint8_t *buf) override; | |
| 718 | size_t getSize() const override { return size; } | |
| 719 | bool isNeeded() const override; | |
| 710 | 720 | |
| 711 | 721 | private: |
| 712 | 722 | struct GdbIndexHeader { |
| 713 | llvm::support::ulittle32_t Version; | |
| 714 | llvm::support::ulittle32_t CuListOff; | |
| 715 | llvm::support::ulittle32_t CuTypesOff; | |
| 716 | llvm::support::ulittle32_t AddressAreaOff; | |
| 717 | llvm::support::ulittle32_t SymtabOff; | |
| 718 | llvm::support::ulittle32_t ConstantPoolOff; | |
| 723 | llvm::support::ulittle32_t version; | |
| 724 | llvm::support::ulittle32_t cuListOff; | |
| 725 | llvm::support::ulittle32_t cuTypesOff; | |
| 726 | llvm::support::ulittle32_t addressAreaOff; | |
| 727 | llvm::support::ulittle32_t symtabOff; | |
| 728 | llvm::support::ulittle32_t constantPoolOff; | |
| 719 | 729 | }; |
| 720 | 730 | |
| 721 | 731 | void initOutputSize(); |
| ... | ... | @@ -723,12 +733,12 @@ private: |
| 723 | 733 | |
| 724 | 734 | // Each chunk contains information gathered from debug sections of a |
| 725 | 735 | // single object file. |
| 726 | std::vector<GdbChunk> Chunks; | |
| 736 | std::vector<GdbChunk> chunks; | |
| 727 | 737 | |
| 728 | 738 | // A symbol table for this .gdb_index section. |
| 729 | std::vector<GdbSymbol> Symbols; | |
| 739 | std::vector<GdbSymbol> symbols; | |
| 730 | 740 | |
| 731 | size_t Size; | |
| 741 | size_t size; | |
| 732 | 742 | }; |
| 733 | 743 | |
| 734 | 744 | // --eh-frame-hdr option tells linker to construct a header for all the |
| ... | ... | @@ -743,9 +753,10 @@ private: |
| 743 | 753 | class EhFrameHeader final : public SyntheticSection { |
| 744 | 754 | public: |
| 745 | 755 | EhFrameHeader(); |
| 746 | void writeTo(uint8_t *Buf) override; | |
| 756 | void write(); | |
| 757 | void writeTo(uint8_t *buf) override; | |
| 747 | 758 | size_t getSize() const override; |
| 748 | bool empty() const override; | |
| 759 | bool isNeeded() const override; | |
| 749 | 760 | }; |
| 750 | 761 | |
| 751 | 762 | // For more information about .gnu.version and .gnu.version_r see: |
| ... | ... | @@ -761,13 +772,15 @@ public: |
| 761 | 772 | VersionDefinitionSection(); |
| 762 | 773 | void finalizeContents() override; |
| 763 | 774 | size_t getSize() const override; |
| 764 | void writeTo(uint8_t *Buf) override; | |
| 775 | void writeTo(uint8_t *buf) override; | |
| 765 | 776 | |
| 766 | 777 | private: |
| 767 | 778 | enum { EntrySize = 28 }; |
| 768 | void writeOne(uint8_t *Buf, uint32_t Index, StringRef Name, size_t NameOff); | |
| 779 | void writeOne(uint8_t *buf, uint32_t index, StringRef name, size_t nameOff); | |
| 780 | StringRef getFileDefName(); | |
| 769 | 781 | |
| 770 | unsigned FileDefNameOff; | |
| 782 | unsigned fileDefNameOff; | |
| 783 | std::vector<unsigned> verDefNameOffs; | |
| 771 | 784 | }; |
| 772 | 785 | |
| 773 | 786 | // The .gnu.version section specifies the required version of each symbol in the |
| ... | ... | @@ -776,14 +789,13 @@ private: |
| 776 | 789 | // identifier defined in the either .gnu.version_r or .gnu.version_d section. |
| 777 | 790 | // The values 0 and 1 are reserved. All other values are used for versions in |
| 778 | 791 | // the own object or in any of the dependencies. |
| 779 | template <class ELFT> | |
| 780 | 792 | class VersionTableSection final : public SyntheticSection { |
| 781 | 793 | public: |
| 782 | 794 | VersionTableSection(); |
| 783 | 795 | void finalizeContents() override; |
| 784 | 796 | size_t getSize() const override; |
| 785 | void writeTo(uint8_t *Buf) override; | |
| 786 | bool empty() const override; | |
| 797 | void writeTo(uint8_t *buf) override; | |
| 798 | bool isNeeded() const override; | |
| 787 | 799 | }; |
| 788 | 800 | |
| 789 | 801 | // The .gnu.version_r section defines the version identifiers used by |
| ... | ... | @@ -791,25 +803,30 @@ public: |
| 791 | 803 | // Elf_Verneed specifies the version requirements for a single DSO, and contains |
| 792 | 804 | // a reference to a linked list of Elf_Vernaux data structures which define the |
| 793 | 805 | // mapping from version identifiers to version names. |
| 794 | template <class ELFT> class VersionNeedSection final : public SyntheticSection { | |
| 795 | typedef typename ELFT::Verneed Elf_Verneed; | |
| 796 | typedef typename ELFT::Vernaux Elf_Vernaux; | |
| 806 | template <class ELFT> | |
| 807 | class VersionNeedSection final : public SyntheticSection { | |
| 808 | using Elf_Verneed = typename ELFT::Verneed; | |
| 809 | using Elf_Vernaux = typename ELFT::Vernaux; | |
| 810 | ||
| 811 | struct Vernaux { | |
| 812 | uint64_t hash; | |
| 813 | uint32_t verneedIndex; | |
| 814 | uint64_t nameStrTab; | |
| 815 | }; | |
| 797 | 816 | |
| 798 | // A vector of shared files that need Elf_Verneed data structures and the | |
| 799 | // string table offsets of their sonames. | |
| 800 | std::vector<std::pair<SharedFile<ELFT> *, size_t>> Needed; | |
| 817 | struct Verneed { | |
| 818 | uint64_t nameStrTab; | |
| 819 | std::vector<Vernaux> vernauxs; | |
| 820 | }; | |
| 801 | 821 | |
| 802 | // The next available version identifier. | |
| 803 | unsigned NextIndex; | |
| 822 | std::vector<Verneed> verneeds; | |
| 804 | 823 | |
| 805 | 824 | public: |
| 806 | 825 | VersionNeedSection(); |
| 807 | void addSymbol(Symbol *Sym); | |
| 808 | 826 | void finalizeContents() override; |
| 809 | void writeTo(uint8_t *Buf) override; | |
| 827 | void writeTo(uint8_t *buf) override; | |
| 810 | 828 | size_t getSize() const override; |
| 811 | size_t getNeedNum() const { return Needed.size(); } | |
| 812 | bool empty() const override; | |
| 829 | bool isNeeded() const override; | |
| 813 | 830 | }; |
| 814 | 831 | |
| 815 | 832 | // MergeSyntheticSection is a class that allows us to put mergeable sections |
| ... | ... | @@ -818,36 +835,36 @@ public: |
| 818 | 835 | // attached to regular output sections. |
| 819 | 836 | class MergeSyntheticSection : public SyntheticSection { |
| 820 | 837 | public: |
| 821 | void addSection(MergeInputSection *MS); | |
| 822 | std::vector<MergeInputSection *> Sections; | |
| 838 | void addSection(MergeInputSection *ms); | |
| 839 | std::vector<MergeInputSection *> sections; | |
| 823 | 840 | |
| 824 | 841 | protected: |
| 825 | MergeSyntheticSection(StringRef Name, uint32_t Type, uint64_t Flags, | |
| 826 | uint32_t Alignment) | |
| 827 | : SyntheticSection(Flags, Type, Alignment, Name) {} | |
| 842 | MergeSyntheticSection(StringRef name, uint32_t type, uint64_t flags, | |
| 843 | uint32_t alignment) | |
| 844 | : SyntheticSection(flags, type, alignment, name) {} | |
| 828 | 845 | }; |
| 829 | 846 | |
| 830 | 847 | class MergeTailSection final : public MergeSyntheticSection { |
| 831 | 848 | public: |
| 832 | MergeTailSection(StringRef Name, uint32_t Type, uint64_t Flags, | |
| 833 | uint32_t Alignment); | |
| 849 | MergeTailSection(StringRef name, uint32_t type, uint64_t flags, | |
| 850 | uint32_t alignment); | |
| 834 | 851 | |
| 835 | 852 | size_t getSize() const override; |
| 836 | void writeTo(uint8_t *Buf) override; | |
| 853 | void writeTo(uint8_t *buf) override; | |
| 837 | 854 | void finalizeContents() override; |
| 838 | 855 | |
| 839 | 856 | private: |
| 840 | llvm::StringTableBuilder Builder; | |
| 857 | llvm::StringTableBuilder builder; | |
| 841 | 858 | }; |
| 842 | 859 | |
| 843 | 860 | class MergeNoTailSection final : public MergeSyntheticSection { |
| 844 | 861 | public: |
| 845 | MergeNoTailSection(StringRef Name, uint32_t Type, uint64_t Flags, | |
| 846 | uint32_t Alignment) | |
| 847 | : MergeSyntheticSection(Name, Type, Flags, Alignment) {} | |
| 862 | MergeNoTailSection(StringRef name, uint32_t type, uint64_t flags, | |
| 863 | uint32_t alignment) | |
| 864 | : MergeSyntheticSection(name, type, flags, alignment) {} | |
| 848 | 865 | |
| 849 | size_t getSize() const override { return Size; } | |
| 850 | void writeTo(uint8_t *Buf) override; | |
| 866 | size_t getSize() const override { return size; } | |
| 867 | void writeTo(uint8_t *buf) override; | |
| 851 | 868 | void finalizeContents() override; |
| 852 | 869 | |
| 853 | 870 | private: |
| ... | ... | @@ -856,67 +873,68 @@ private: |
| 856 | 873 | // because DenseMap also uses lower bits to determine a bucket ID. |
| 857 | 874 | // If we use lower bits, it significantly increases the probability of |
| 858 | 875 | // hash collisons. |
| 859 | size_t getShardId(uint32_t Hash) { | |
| 860 | return Hash >> (32 - llvm::countTrailingZeros(NumShards)); | |
| 876 | size_t getShardId(uint32_t hash) { | |
| 877 | assert((hash >> 31) == 0); | |
| 878 | return hash >> (31 - llvm::countTrailingZeros(numShards)); | |
| 861 | 879 | } |
| 862 | 880 | |
| 863 | 881 | // Section size |
| 864 | size_t Size; | |
| 882 | size_t size; | |
| 865 | 883 | |
| 866 | 884 | // String table contents |
| 867 | constexpr static size_t NumShards = 32; | |
| 868 | std::vector<llvm::StringTableBuilder> Shards; | |
| 869 | size_t ShardOffsets[NumShards]; | |
| 885 | constexpr static size_t numShards = 32; | |
| 886 | std::vector<llvm::StringTableBuilder> shards; | |
| 887 | size_t shardOffsets[numShards]; | |
| 870 | 888 | }; |
| 871 | 889 | |
| 872 | 890 | // .MIPS.abiflags section. |
| 873 | 891 | template <class ELFT> |
| 874 | 892 | class MipsAbiFlagsSection final : public SyntheticSection { |
| 875 | typedef llvm::object::Elf_Mips_ABIFlags<ELFT> Elf_Mips_ABIFlags; | |
| 893 | using Elf_Mips_ABIFlags = llvm::object::Elf_Mips_ABIFlags<ELFT>; | |
| 876 | 894 | |
| 877 | 895 | public: |
| 878 | 896 | static MipsAbiFlagsSection *create(); |
| 879 | 897 | |
| 880 | MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags); | |
| 898 | MipsAbiFlagsSection(Elf_Mips_ABIFlags flags); | |
| 881 | 899 | size_t getSize() const override { return sizeof(Elf_Mips_ABIFlags); } |
| 882 | void writeTo(uint8_t *Buf) override; | |
| 900 | void writeTo(uint8_t *buf) override; | |
| 883 | 901 | |
| 884 | 902 | private: |
| 885 | Elf_Mips_ABIFlags Flags; | |
| 903 | Elf_Mips_ABIFlags flags; | |
| 886 | 904 | }; |
| 887 | 905 | |
| 888 | 906 | // .MIPS.options section. |
| 889 | 907 | template <class ELFT> class MipsOptionsSection final : public SyntheticSection { |
| 890 | typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options; | |
| 891 | typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo; | |
| 908 | using Elf_Mips_Options = llvm::object::Elf_Mips_Options<ELFT>; | |
| 909 | using Elf_Mips_RegInfo = llvm::object::Elf_Mips_RegInfo<ELFT>; | |
| 892 | 910 | |
| 893 | 911 | public: |
| 894 | 912 | static MipsOptionsSection *create(); |
| 895 | 913 | |
| 896 | MipsOptionsSection(Elf_Mips_RegInfo Reginfo); | |
| 897 | void writeTo(uint8_t *Buf) override; | |
| 914 | MipsOptionsSection(Elf_Mips_RegInfo reginfo); | |
| 915 | void writeTo(uint8_t *buf) override; | |
| 898 | 916 | |
| 899 | 917 | size_t getSize() const override { |
| 900 | 918 | return sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo); |
| 901 | 919 | } |
| 902 | 920 | |
| 903 | 921 | private: |
| 904 | Elf_Mips_RegInfo Reginfo; | |
| 922 | Elf_Mips_RegInfo reginfo; | |
| 905 | 923 | }; |
| 906 | 924 | |
| 907 | 925 | // MIPS .reginfo section. |
| 908 | 926 | template <class ELFT> class MipsReginfoSection final : public SyntheticSection { |
| 909 | typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo; | |
| 927 | using Elf_Mips_RegInfo = llvm::object::Elf_Mips_RegInfo<ELFT>; | |
| 910 | 928 | |
| 911 | 929 | public: |
| 912 | 930 | static MipsReginfoSection *create(); |
| 913 | 931 | |
| 914 | MipsReginfoSection(Elf_Mips_RegInfo Reginfo); | |
| 932 | MipsReginfoSection(Elf_Mips_RegInfo reginfo); | |
| 915 | 933 | size_t getSize() const override { return sizeof(Elf_Mips_RegInfo); } |
| 916 | void writeTo(uint8_t *Buf) override; | |
| 934 | void writeTo(uint8_t *buf) override; | |
| 917 | 935 | |
| 918 | 936 | private: |
| 919 | Elf_Mips_RegInfo Reginfo; | |
| 937 | Elf_Mips_RegInfo reginfo; | |
| 920 | 938 | }; |
| 921 | 939 | |
| 922 | 940 | // This is a MIPS specific section to hold a space within the data segment |
| ... | ... | @@ -926,45 +944,115 @@ private: |
| 926 | 944 | class MipsRldMapSection : public SyntheticSection { |
| 927 | 945 | public: |
| 928 | 946 | MipsRldMapSection(); |
| 929 | size_t getSize() const override { return Config->Wordsize; } | |
| 930 | void writeTo(uint8_t *Buf) override {} | |
| 947 | size_t getSize() const override { return config->wordsize; } | |
| 948 | void writeTo(uint8_t *buf) override {} | |
| 931 | 949 | }; |
| 932 | 950 | |
| 933 | class ARMExidxSentinelSection : public SyntheticSection { | |
| 951 | // Representation of the combined .ARM.Exidx input sections. We process these | |
| 952 | // as a SyntheticSection like .eh_frame as we need to merge duplicate entries | |
| 953 | // and add terminating sentinel entries. | |
| 954 | // | |
| 955 | // The .ARM.exidx input sections after SHF_LINK_ORDER processing is done form | |
| 956 | // a table that the unwinder can derive (Addresses are encoded as offsets from | |
| 957 | // table): | |
| 958 | // | Address of function | Unwind instructions for function | | |
| 959 | // where the unwind instructions are either a small number of unwind or the | |
| 960 | // special EXIDX_CANTUNWIND entry representing no unwinding information. | |
| 961 | // When an exception is thrown from an address A, the unwinder searches the | |
| 962 | // table for the closest table entry with Address of function <= A. This means | |
| 963 | // that for two consecutive table entries: | |
| 964 | // | A1 | U1 | | |
| 965 | // | A2 | U2 | | |
| 966 | // The range of addresses described by U1 is [A1, A2) | |
| 967 | // | |
| 968 | // There are two cases where we need a linker generated table entry to fixup | |
| 969 | // the address ranges in the table | |
| 970 | // Case 1: | |
| 971 | // - A sentinel entry added with an address higher than all | |
| 972 | // executable sections. This was needed to work around libunwind bug pr31091. | |
| 973 | // - After address assignment we need to find the highest addressed executable | |
| 974 | // section and use the limit of that section so that the unwinder never | |
| 975 | // matches it. | |
| 976 | // Case 2: | |
| 977 | // - InputSections without a .ARM.exidx section (usually from Assembly) | |
| 978 | // need a table entry so that they terminate the range of the previously | |
| 979 | // function. This is pr40277. | |
| 980 | // | |
| 981 | // Instead of storing pointers to the .ARM.exidx InputSections from | |
| 982 | // InputObjects, we store pointers to the executable sections that need | |
| 983 | // .ARM.exidx sections. We can then use the dependentSections of these to | |
| 984 | // either find the .ARM.exidx section or know that we need to generate one. | |
| 985 | class ARMExidxSyntheticSection : public SyntheticSection { | |
| 934 | 986 | public: |
| 935 | ARMExidxSentinelSection(); | |
| 936 | size_t getSize() const override { return 8; } | |
| 937 | void writeTo(uint8_t *Buf) override; | |
| 938 | bool empty() const override; | |
| 987 | ARMExidxSyntheticSection(); | |
| 988 | ||
| 989 | // Add an input section to the ARMExidxSyntheticSection. Returns whether the | |
| 990 | // section needs to be removed from the main input section list. | |
| 991 | bool addSection(InputSection *isec); | |
| 939 | 992 | |
| 940 | static bool classof(const SectionBase *D); | |
| 993 | size_t getSize() const override { return size; } | |
| 994 | void writeTo(uint8_t *buf) override; | |
| 995 | bool isNeeded() const override { return !empty; } | |
| 996 | // Sort and remove duplicate entries. | |
| 997 | void finalizeContents() override; | |
| 998 | InputSection *getLinkOrderDep() const; | |
| 999 | ||
| 1000 | static bool classof(const SectionBase *d); | |
| 1001 | ||
| 1002 | // Links to the ARMExidxSections so we can transfer the relocations once the | |
| 1003 | // layout is known. | |
| 1004 | std::vector<InputSection *> exidxSections; | |
| 941 | 1005 | |
| 942 | // The last section referenced by a regular .ARM.exidx section. | |
| 943 | // It is found and filled in Writer<ELFT>::resolveShfLinkOrder(). | |
| 944 | // The sentinel points at the end of that section. | |
| 945 | InputSection *Highest = nullptr; | |
| 1006 | private: | |
| 1007 | size_t size; | |
| 1008 | ||
| 1009 | // Empty if ExecutableSections contains no dependent .ARM.exidx sections. | |
| 1010 | bool empty = true; | |
| 1011 | ||
| 1012 | // Instead of storing pointers to the .ARM.exidx InputSections from | |
| 1013 | // InputObjects, we store pointers to the executable sections that need | |
| 1014 | // .ARM.exidx sections. We can then use the dependentSections of these to | |
| 1015 | // either find the .ARM.exidx section or know that we need to generate one. | |
| 1016 | std::vector<InputSection *> executableSections; | |
| 1017 | ||
| 1018 | // The executable InputSection with the highest address to use for the | |
| 1019 | // sentinel. We store separately from ExecutableSections as merging of | |
| 1020 | // duplicate entries may mean this InputSection is removed from | |
| 1021 | // ExecutableSections. | |
| 1022 | InputSection *sentinel = nullptr; | |
| 946 | 1023 | }; |
| 947 | 1024 | |
| 948 | 1025 | // A container for one or more linker generated thunks. Instances of these |
| 949 | 1026 | // thunks including ARM interworking and Mips LA25 PI to non-PI thunks. |
| 950 | 1027 | class ThunkSection : public SyntheticSection { |
| 951 | 1028 | public: |
| 952 | // ThunkSection in OS, with desired OutSecOff of Off | |
| 953 | ThunkSection(OutputSection *OS, uint64_t Off); | |
| 1029 | // ThunkSection in OS, with desired outSecOff of Off | |
| 1030 | ThunkSection(OutputSection *os, uint64_t off); | |
| 954 | 1031 | |
| 955 | 1032 | // Add a newly created Thunk to this container: |
| 956 | 1033 | // Thunk is given offset from start of this InputSection |
| 957 | 1034 | // Thunk defines a symbol in this InputSection that can be used as target |
| 958 | 1035 | // of a relocation |
| 959 | void addThunk(Thunk *T); | |
| 960 | size_t getSize() const override { return Size; } | |
| 961 | void writeTo(uint8_t *Buf) override; | |
| 1036 | void addThunk(Thunk *t); | |
| 1037 | size_t getSize() const override { return size; } | |
| 1038 | void writeTo(uint8_t *buf) override; | |
| 962 | 1039 | InputSection *getTargetInputSection() const; |
| 963 | 1040 | bool assignOffsets(); |
| 964 | 1041 | |
| 965 | 1042 | private: |
| 966 | std::vector<Thunk *> Thunks; | |
| 967 | size_t Size = 0; | |
| 1043 | std::vector<Thunk *> thunks; | |
| 1044 | size_t size = 0; | |
| 1045 | }; | |
| 1046 | ||
| 1047 | // Used to compute outSecOff of .got2 in each object file. This is needed to | |
| 1048 | // synthesize PLT entries for PPC32 Secure PLT ABI. | |
| 1049 | class PPC32Got2Section final : public SyntheticSection { | |
| 1050 | public: | |
| 1051 | PPC32Got2Section(); | |
| 1052 | size_t getSize() const override { return 0; } | |
| 1053 | bool isNeeded() const override; | |
| 1054 | void finalizeContents() override; | |
| 1055 | void writeTo(uint8_t *buf) override {} | |
| 968 | 1056 | }; |
| 969 | 1057 | |
| 970 | 1058 | // This section is used to store the addresses of functions that are called |
| ... | ... | @@ -975,15 +1063,48 @@ private: |
| 975 | 1063 | class PPC64LongBranchTargetSection final : public SyntheticSection { |
| 976 | 1064 | public: |
| 977 | 1065 | PPC64LongBranchTargetSection(); |
| 978 | void addEntry(Symbol &Sym); | |
| 1066 | void addEntry(Symbol &sym); | |
| 979 | 1067 | size_t getSize() const override; |
| 980 | void writeTo(uint8_t *Buf) override; | |
| 981 | bool empty() const override; | |
| 982 | void finalizeContents() override { Finalized = true; } | |
| 1068 | void writeTo(uint8_t *buf) override; | |
| 1069 | bool isNeeded() const override; | |
| 1070 | void finalizeContents() override { finalized = true; } | |
| 983 | 1071 | |
| 984 | 1072 | private: |
| 985 | std::vector<const Symbol *> Entries; | |
| 986 | bool Finalized = false; | |
| 1073 | std::vector<const Symbol *> entries; | |
| 1074 | bool finalized = false; | |
| 1075 | }; | |
| 1076 | ||
| 1077 | template <typename ELFT> | |
| 1078 | class PartitionElfHeaderSection : public SyntheticSection { | |
| 1079 | public: | |
| 1080 | PartitionElfHeaderSection(); | |
| 1081 | size_t getSize() const override; | |
| 1082 | void writeTo(uint8_t *buf) override; | |
| 1083 | }; | |
| 1084 | ||
| 1085 | template <typename ELFT> | |
| 1086 | class PartitionProgramHeadersSection : public SyntheticSection { | |
| 1087 | public: | |
| 1088 | PartitionProgramHeadersSection(); | |
| 1089 | size_t getSize() const override; | |
| 1090 | void writeTo(uint8_t *buf) override; | |
| 1091 | }; | |
| 1092 | ||
| 1093 | class PartitionIndexSection : public SyntheticSection { | |
| 1094 | public: | |
| 1095 | PartitionIndexSection(); | |
| 1096 | size_t getSize() const override; | |
| 1097 | void finalizeContents() override; | |
| 1098 | void writeTo(uint8_t *buf) override; | |
| 1099 | }; | |
| 1100 | ||
| 1101 | // Create a dummy .sdata for __global_pointer$ if .sdata does not exist. | |
| 1102 | class RISCVSdataSection final : public SyntheticSection { | |
| 1103 | public: | |
| 1104 | RISCVSdataSection(); | |
| 1105 | size_t getSize() const override { return 0; } | |
| 1106 | bool isNeeded() const override; | |
| 1107 | void writeTo(uint8_t *buf) override {} | |
| 987 | 1108 | }; |
| 988 | 1109 | |
| 989 | 1110 | InputSection *createInterpSection(); |
| ... | ... | @@ -991,52 +1112,76 @@ MergeInputSection *createCommentSection(); |
| 991 | 1112 | template <class ELFT> void splitSections(); |
| 992 | 1113 | void mergeSections(); |
| 993 | 1114 | |
| 994 | Defined *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, | |
| 995 | uint64_t Size, InputSectionBase &Section); | |
| 996 | ||
| 997 | // Linker generated sections which can be used as inputs. | |
| 998 | struct InStruct { | |
| 999 | InputSection *ARMAttributes; | |
| 1000 | BssSection *Bss; | |
| 1001 | BssSection *BssRelRo; | |
| 1002 | BuildIdSection *BuildId; | |
| 1003 | EhFrameHeader *EhFrameHdr; | |
| 1004 | EhFrameSection *EhFrame; | |
| 1005 | SyntheticSection *Dynamic; | |
| 1006 | StringTableSection *DynStrTab; | |
| 1007 | SymbolTableBaseSection *DynSymTab; | |
| 1008 | GnuHashTableSection *GnuHashTab; | |
| 1009 | HashTableSection *HashTab; | |
| 1010 | InputSection *Interp; | |
| 1011 | GdbIndexSection *GdbIndex; | |
| 1012 | GotSection *Got; | |
| 1013 | GotPltSection *GotPlt; | |
| 1014 | IgotPltSection *IgotPlt; | |
| 1015 | PPC64LongBranchTargetSection *PPC64LongBranchTarget; | |
| 1016 | MipsGotSection *MipsGot; | |
| 1017 | MipsRldMapSection *MipsRldMap; | |
| 1018 | PltSection *Plt; | |
| 1019 | PltSection *Iplt; | |
| 1020 | RelocationBaseSection *RelaDyn; | |
| 1021 | RelrBaseSection *RelrDyn; | |
| 1022 | RelocationBaseSection *RelaPlt; | |
| 1023 | RelocationBaseSection *RelaIplt; | |
| 1024 | StringTableSection *ShStrTab; | |
| 1025 | StringTableSection *StrTab; | |
| 1026 | SymbolTableBaseSection *SymTab; | |
| 1027 | SymtabShndxSection *SymTabShndx; | |
| 1028 | VersionDefinitionSection *VerDef; | |
| 1115 | template <typename ELFT> void writeEhdr(uint8_t *buf, Partition &part); | |
| 1116 | template <typename ELFT> void writePhdrs(uint8_t *buf, Partition &part); | |
| 1117 | ||
| 1118 | Defined *addSyntheticLocal(StringRef name, uint8_t type, uint64_t value, | |
| 1119 | uint64_t size, InputSectionBase &section); | |
| 1120 | ||
| 1121 | void addVerneed(Symbol *ss); | |
| 1122 | ||
| 1123 | // Linker generated per-partition sections. | |
| 1124 | struct Partition { | |
| 1125 | StringRef name; | |
| 1126 | uint64_t nameStrTab; | |
| 1127 | ||
| 1128 | SyntheticSection *elfHeader; | |
| 1129 | SyntheticSection *programHeaders; | |
| 1130 | std::vector<PhdrEntry *> phdrs; | |
| 1131 | ||
| 1132 | ARMExidxSyntheticSection *armExidx; | |
| 1133 | BuildIdSection *buildId; | |
| 1134 | SyntheticSection *dynamic; | |
| 1135 | StringTableSection *dynStrTab; | |
| 1136 | SymbolTableBaseSection *dynSymTab; | |
| 1137 | EhFrameHeader *ehFrameHdr; | |
| 1138 | EhFrameSection *ehFrame; | |
| 1139 | GnuHashTableSection *gnuHashTab; | |
| 1140 | HashTableSection *hashTab; | |
| 1141 | RelocationBaseSection *relaDyn; | |
| 1142 | RelrBaseSection *relrDyn; | |
| 1143 | VersionDefinitionSection *verDef; | |
| 1144 | SyntheticSection *verNeed; | |
| 1145 | VersionTableSection *verSym; | |
| 1146 | ||
| 1147 | unsigned getNumber() const { return this - &partitions[0] + 1; } | |
| 1029 | 1148 | }; |
| 1030 | 1149 | |
| 1031 | extern InStruct In; | |
| 1150 | extern Partition *mainPart; | |
| 1032 | 1151 | |
| 1033 | template <class ELFT> struct InX { | |
| 1034 | static VersionTableSection<ELFT> *VerSym; | |
| 1035 | static VersionNeedSection<ELFT> *VerNeed; | |
| 1152 | inline Partition &SectionBase::getPartition() const { | |
| 1153 | assert(isLive()); | |
| 1154 | return partitions[partition - 1]; | |
| 1155 | } | |
| 1156 | ||
| 1157 | // Linker generated sections which can be used as inputs and are not specific to | |
| 1158 | // a partition. | |
| 1159 | struct InStruct { | |
| 1160 | InputSection *armAttributes; | |
| 1161 | BssSection *bss; | |
| 1162 | BssSection *bssRelRo; | |
| 1163 | GotSection *got; | |
| 1164 | GotPltSection *gotPlt; | |
| 1165 | IgotPltSection *igotPlt; | |
| 1166 | PPC64LongBranchTargetSection *ppc64LongBranchTarget; | |
| 1167 | MipsGotSection *mipsGot; | |
| 1168 | MipsRldMapSection *mipsRldMap; | |
| 1169 | SyntheticSection *partEnd; | |
| 1170 | SyntheticSection *partIndex; | |
| 1171 | PltSection *plt; | |
| 1172 | PltSection *iplt; | |
| 1173 | PPC32Got2Section *ppc32Got2; | |
| 1174 | RISCVSdataSection *riscvSdata; | |
| 1175 | RelocationBaseSection *relaPlt; | |
| 1176 | RelocationBaseSection *relaIplt; | |
| 1177 | StringTableSection *shStrTab; | |
| 1178 | StringTableSection *strTab; | |
| 1179 | SymbolTableBaseSection *symTab; | |
| 1180 | SymtabShndxSection *symTabShndx; | |
| 1036 | 1181 | }; |
| 1037 | 1182 | |
| 1038 | template <class ELFT> VersionTableSection<ELFT> *InX<ELFT>::VerSym; | |
| 1039 | template <class ELFT> VersionNeedSection<ELFT> *InX<ELFT>::VerNeed; | |
| 1183 | extern InStruct in; | |
| 1184 | ||
| 1040 | 1185 | } // namespace elf |
| 1041 | 1186 | } // namespace lld |
| 1042 | 1187 |
deps/lld/ELF/Target.cpp+49-52| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Target.cpp ---------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -38,17 +37,17 @@ using namespace llvm::ELF; |
| 38 | 37 | using namespace lld; |
| 39 | 38 | using namespace lld::elf; |
| 40 | 39 | |
| 41 | TargetInfo *elf::Target; | |
| 40 | const TargetInfo *elf::target; | |
| 42 | 41 | |
| 43 | std::string lld::toString(RelType Type) { | |
| 44 | StringRef S = getELFRelocationTypeName(elf::Config->EMachine, Type); | |
| 45 | if (S == "Unknown") | |
| 46 | return ("Unknown (" + Twine(Type) + ")").str(); | |
| 47 | return S; | |
| 42 | std::string lld::toString(RelType type) { | |
| 43 | StringRef s = getELFRelocationTypeName(elf::config->emachine, type); | |
| 44 | if (s == "Unknown") | |
| 45 | return ("Unknown (" + Twine(type) + ")").str(); | |
| 46 | return s; | |
| 48 | 47 | } |
| 49 | 48 | |
| 50 | 49 | TargetInfo *elf::getTarget() { |
| 51 | switch (Config->EMachine) { | |
| 50 | switch (config->emachine) { | |
| 52 | 51 | case EM_386: |
| 53 | 52 | case EM_IAMCU: |
| 54 | 53 | return getX86TargetInfo(); |
| ... | ... | @@ -63,7 +62,7 @@ TargetInfo *elf::getTarget() { |
| 63 | 62 | case EM_HEXAGON: |
| 64 | 63 | return getHexagonTargetInfo(); |
| 65 | 64 | case EM_MIPS: |
| 66 | switch (Config->EKind) { | |
| 65 | switch (config->ekind) { | |
| 67 | 66 | case ELF32LEKind: |
| 68 | 67 | return getMipsTargetInfo<ELF32LE>(); |
| 69 | 68 | case ELF32BEKind: |
| ... | ... | @@ -86,36 +85,34 @@ TargetInfo *elf::getTarget() { |
| 86 | 85 | case EM_SPARCV9: |
| 87 | 86 | return getSPARCV9TargetInfo(); |
| 88 | 87 | case EM_X86_64: |
| 89 | if (Config->EKind == ELF32LEKind) | |
| 90 | return getX32TargetInfo(); | |
| 91 | 88 | return getX86_64TargetInfo(); |
| 92 | 89 | } |
| 93 | 90 | llvm_unreachable("unknown target machine"); |
| 94 | 91 | } |
| 95 | 92 | |
| 96 | template <class ELFT> static ErrorPlace getErrPlace(const uint8_t *Loc) { | |
| 97 | for (InputSectionBase *D : InputSections) { | |
| 98 | auto *IS = cast<InputSection>(D); | |
| 99 | if (!IS->getParent()) | |
| 93 | template <class ELFT> static ErrorPlace getErrPlace(const uint8_t *loc) { | |
| 94 | for (InputSectionBase *d : inputSections) { | |
| 95 | auto *isec = cast<InputSection>(d); | |
| 96 | if (!isec->getParent()) | |
| 100 | 97 | continue; |
| 101 | 98 | |
| 102 | uint8_t *ISLoc = IS->getParent()->Loc + IS->OutSecOff; | |
| 103 | if (ISLoc <= Loc && Loc < ISLoc + IS->getSize()) | |
| 104 | return {IS, IS->template getLocation<ELFT>(Loc - ISLoc) + ": "}; | |
| 99 | uint8_t *isecLoc = Out::bufferStart + isec->getParent()->offset + isec->outSecOff; | |
| 100 | if (isecLoc <= loc && loc < isecLoc + isec->getSize()) | |
| 101 | return {isec, isec->template getLocation<ELFT>(loc - isecLoc) + ": "}; | |
| 105 | 102 | } |
| 106 | 103 | return {}; |
| 107 | 104 | } |
| 108 | 105 | |
| 109 | ErrorPlace elf::getErrorPlace(const uint8_t *Loc) { | |
| 110 | switch (Config->EKind) { | |
| 106 | ErrorPlace elf::getErrorPlace(const uint8_t *loc) { | |
| 107 | switch (config->ekind) { | |
| 111 | 108 | case ELF32LEKind: |
| 112 | return getErrPlace<ELF32LE>(Loc); | |
| 109 | return getErrPlace<ELF32LE>(loc); | |
| 113 | 110 | case ELF32BEKind: |
| 114 | return getErrPlace<ELF32BE>(Loc); | |
| 111 | return getErrPlace<ELF32BE>(loc); | |
| 115 | 112 | case ELF64LEKind: |
| 116 | return getErrPlace<ELF64LE>(Loc); | |
| 113 | return getErrPlace<ELF64LE>(loc); | |
| 117 | 114 | case ELF64BEKind: |
| 118 | return getErrPlace<ELF64BE>(Loc); | |
| 115 | return getErrPlace<ELF64BE>(loc); | |
| 119 | 116 | default: |
| 120 | 117 | llvm_unreachable("unknown ELF type"); |
| 121 | 118 | } |
| ... | ... | @@ -123,62 +120,62 @@ ErrorPlace elf::getErrorPlace(const uint8_t *Loc) { |
| 123 | 120 | |
| 124 | 121 | TargetInfo::~TargetInfo() {} |
| 125 | 122 | |
| 126 | int64_t TargetInfo::getImplicitAddend(const uint8_t *Buf, RelType Type) const { | |
| 123 | int64_t TargetInfo::getImplicitAddend(const uint8_t *buf, RelType type) const { | |
| 127 | 124 | return 0; |
| 128 | 125 | } |
| 129 | 126 | |
| 130 | bool TargetInfo::usesOnlyLowPageBits(RelType Type) const { return false; } | |
| 127 | bool TargetInfo::usesOnlyLowPageBits(RelType type) const { return false; } | |
| 131 | 128 | |
| 132 | bool TargetInfo::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, | |
| 133 | uint64_t BranchAddr, const Symbol &S) const { | |
| 129 | bool TargetInfo::needsThunk(RelExpr expr, RelType type, const InputFile *file, | |
| 130 | uint64_t branchAddr, const Symbol &s) const { | |
| 134 | 131 | return false; |
| 135 | 132 | } |
| 136 | 133 | |
| 137 | bool TargetInfo::adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End, | |
| 138 | uint8_t StOther) const { | |
| 134 | bool TargetInfo::adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end, | |
| 135 | uint8_t stOther) const { | |
| 139 | 136 | llvm_unreachable("Target doesn't support split stacks."); |
| 140 | 137 | } |
| 141 | 138 | |
| 142 | bool TargetInfo::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { | |
| 139 | bool TargetInfo::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { | |
| 143 | 140 | return true; |
| 144 | 141 | } |
| 145 | 142 | |
| 146 | void TargetInfo::writeIgotPlt(uint8_t *Buf, const Symbol &S) const { | |
| 147 | writeGotPlt(Buf, S); | |
| 143 | void TargetInfo::writeIgotPlt(uint8_t *buf, const Symbol &s) const { | |
| 144 | writeGotPlt(buf, s); | |
| 148 | 145 | } |
| 149 | 146 | |
| 150 | RelExpr TargetInfo::adjustRelaxExpr(RelType Type, const uint8_t *Data, | |
| 151 | RelExpr Expr) const { | |
| 152 | return Expr; | |
| 147 | RelExpr TargetInfo::adjustRelaxExpr(RelType type, const uint8_t *data, | |
| 148 | RelExpr expr) const { | |
| 149 | return expr; | |
| 153 | 150 | } |
| 154 | 151 | |
| 155 | void TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const { | |
| 152 | void TargetInfo::relaxGot(uint8_t *loc, RelType type, uint64_t val) const { | |
| 156 | 153 | llvm_unreachable("Should not have claimed to be relaxable"); |
| 157 | 154 | } |
| 158 | 155 | |
| 159 | void TargetInfo::relaxTlsGdToLe(uint8_t *Loc, RelType Type, | |
| 160 | uint64_t Val) const { | |
| 156 | void TargetInfo::relaxTlsGdToLe(uint8_t *loc, RelType type, | |
| 157 | uint64_t val) const { | |
| 161 | 158 | llvm_unreachable("Should not have claimed to be relaxable"); |
| 162 | 159 | } |
| 163 | 160 | |
| 164 | void TargetInfo::relaxTlsGdToIe(uint8_t *Loc, RelType Type, | |
| 165 | uint64_t Val) const { | |
| 161 | void TargetInfo::relaxTlsGdToIe(uint8_t *loc, RelType type, | |
| 162 | uint64_t val) const { | |
| 166 | 163 | llvm_unreachable("Should not have claimed to be relaxable"); |
| 167 | 164 | } |
| 168 | 165 | |
| 169 | void TargetInfo::relaxTlsIeToLe(uint8_t *Loc, RelType Type, | |
| 170 | uint64_t Val) const { | |
| 166 | void TargetInfo::relaxTlsIeToLe(uint8_t *loc, RelType type, | |
| 167 | uint64_t val) const { | |
| 171 | 168 | llvm_unreachable("Should not have claimed to be relaxable"); |
| 172 | 169 | } |
| 173 | 170 | |
| 174 | void TargetInfo::relaxTlsLdToLe(uint8_t *Loc, RelType Type, | |
| 175 | uint64_t Val) const { | |
| 171 | void TargetInfo::relaxTlsLdToLe(uint8_t *loc, RelType type, | |
| 172 | uint64_t val) const { | |
| 176 | 173 | llvm_unreachable("Should not have claimed to be relaxable"); |
| 177 | 174 | } |
| 178 | 175 | |
| 179 | uint64_t TargetInfo::getImageBase() { | |
| 176 | uint64_t TargetInfo::getImageBase() const { | |
| 180 | 177 | // Use -image-base if set. Fall back to the target default if not. |
| 181 | if (Config->ImageBase) | |
| 182 | return *Config->ImageBase; | |
| 183 | return Config->Pic ? 0 : DefaultImageBase; | |
| 178 | if (config->imageBase) | |
| 179 | return *config->imageBase; | |
| 180 | return config->isPic ? 0 : defaultImageBase; | |
| 184 | 181 | } |
deps/lld/ELF/Target.h+117-116| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Target.h -------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -17,7 +16,7 @@ |
| 17 | 16 | #include <array> |
| 18 | 17 | |
| 19 | 18 | namespace lld { |
| 20 | std::string toString(elf::RelType Type); | |
| 19 | std::string toString(elf::RelType type); | |
| 21 | 20 | |
| 22 | 21 | namespace elf { |
| 23 | 22 | class Defined; |
| ... | ... | @@ -27,36 +26,39 @@ class Symbol; |
| 27 | 26 | class TargetInfo { |
| 28 | 27 | public: |
| 29 | 28 | virtual uint32_t calcEFlags() const { return 0; } |
| 30 | virtual RelType getDynRel(RelType Type) const { return Type; } | |
| 31 | virtual void writeGotPltHeader(uint8_t *Buf) const {} | |
| 32 | virtual void writeGotHeader(uint8_t *Buf) const {} | |
| 33 | virtual void writeGotPlt(uint8_t *Buf, const Symbol &S) const {}; | |
| 34 | virtual void writeIgotPlt(uint8_t *Buf, const Symbol &S) const; | |
| 35 | virtual int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const; | |
| 29 | virtual RelExpr getRelExpr(RelType type, const Symbol &s, | |
| 30 | const uint8_t *loc) const = 0; | |
| 31 | virtual RelType getDynRel(RelType type) const { return 0; } | |
| 32 | virtual void writeGotPltHeader(uint8_t *buf) const {} | |
| 33 | virtual void writeGotHeader(uint8_t *buf) const {} | |
| 34 | virtual void writeGotPlt(uint8_t *buf, const Symbol &s) const {}; | |
| 35 | virtual void writeIgotPlt(uint8_t *buf, const Symbol &s) const; | |
| 36 | virtual int64_t getImplicitAddend(const uint8_t *buf, RelType type) const; | |
| 37 | virtual int getTlsGdRelaxSkip(RelType type) const { return 1; } | |
| 36 | 38 | |
| 37 | 39 | // If lazy binding is supported, the first entry of the PLT has code |
| 38 | 40 | // to call the dynamic linker to resolve PLT entries the first time |
| 39 | 41 | // they are called. This function writes that code. |
| 40 | virtual void writePltHeader(uint8_t *Buf) const {} | |
| 42 | virtual void writePltHeader(uint8_t *buf) const {} | |
| 41 | 43 | |
| 42 | virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, | |
| 43 | uint64_t PltEntryAddr, int32_t Index, | |
| 44 | unsigned RelOff) const {} | |
| 45 | virtual void addPltHeaderSymbols(InputSection &IS) const {} | |
| 46 | virtual void addPltSymbols(InputSection &IS, uint64_t Off) const {} | |
| 44 | virtual void writePlt(uint8_t *buf, uint64_t gotEntryAddr, | |
| 45 | uint64_t pltEntryAddr, int32_t index, | |
| 46 | unsigned relOff) const {} | |
| 47 | virtual void addPltHeaderSymbols(InputSection &isec) const {} | |
| 48 | virtual void addPltSymbols(InputSection &isec, uint64_t off) const {} | |
| 47 | 49 | |
| 48 | 50 | // Returns true if a relocation only uses the low bits of a value such that |
| 49 | 51 | // all those bits are in the same page. For example, if the relocation |
| 50 | 52 | // only uses the low 12 bits in a system with 4k pages. If this is true, the |
| 51 | 53 | // bits will always have the same value at runtime and we don't have to emit |
| 52 | 54 | // a dynamic relocation. |
| 53 | virtual bool usesOnlyLowPageBits(RelType Type) const; | |
| 55 | virtual bool usesOnlyLowPageBits(RelType type) const; | |
| 54 | 56 | |
| 55 | 57 | // Decide whether a Thunk is needed for the relocation from File |
| 56 | 58 | // targeting S. |
| 57 | virtual bool needsThunk(RelExpr Expr, RelType RelocType, | |
| 58 | const InputFile *File, uint64_t BranchAddr, | |
| 59 | const Symbol &S) const; | |
| 59 | virtual bool needsThunk(RelExpr expr, RelType relocType, | |
| 60 | const InputFile *file, uint64_t branchAddr, | |
| 61 | const Symbol &s) const; | |
| 60 | 62 | |
| 61 | 63 | // On systems with range extensions we place collections of Thunks at |
| 62 | 64 | // regular spacings that enable the majority of branches reach the Thunks. |
| ... | ... | @@ -68,77 +70,71 @@ public: |
| 68 | 70 | // to do the right thing. See https://gcc.gnu.org/wiki/SplitStacks. |
| 69 | 71 | // The symbols st_other flags are needed on PowerPC64 for determining the |
| 70 | 72 | // offset to the split-stack prologue. |
| 71 | virtual bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End, | |
| 72 | uint8_t StOther) const; | |
| 73 | virtual bool adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end, | |
| 74 | uint8_t stOther) const; | |
| 73 | 75 | |
| 74 | // Return true if we can reach Dst from Src with Relocation RelocType | |
| 75 | virtual bool inBranchRange(RelType Type, uint64_t Src, | |
| 76 | uint64_t Dst) const; | |
| 77 | virtual RelExpr getRelExpr(RelType Type, const Symbol &S, | |
| 78 | const uint8_t *Loc) const = 0; | |
| 76 | // Return true if we can reach dst from src with RelType type. | |
| 77 | virtual bool inBranchRange(RelType type, uint64_t src, | |
| 78 | uint64_t dst) const; | |
| 79 | 79 | |
| 80 | virtual void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const = 0; | |
| 80 | virtual void relocateOne(uint8_t *loc, RelType type, uint64_t val) const = 0; | |
| 81 | 81 | |
| 82 | 82 | virtual ~TargetInfo(); |
| 83 | 83 | |
| 84 | unsigned TlsGdRelaxSkip = 1; | |
| 85 | unsigned PageSize = 4096; | |
| 86 | unsigned DefaultMaxPageSize = 4096; | |
| 84 | unsigned defaultCommonPageSize = 4096; | |
| 85 | unsigned defaultMaxPageSize = 4096; | |
| 87 | 86 | |
| 88 | uint64_t getImageBase(); | |
| 87 | uint64_t getImageBase() const; | |
| 89 | 88 | |
| 90 | // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got or .got.plt section. | |
| 91 | uint64_t GotBaseSymOff = 0; | |
| 92 | 89 | // True if _GLOBAL_OFFSET_TABLE_ is relative to .got.plt, false if .got. |
| 93 | bool GotBaseSymInGotPlt = true; | |
| 94 | ||
| 95 | RelType CopyRel; | |
| 96 | RelType GotRel; | |
| 97 | RelType NoneRel; | |
| 98 | RelType PltRel; | |
| 99 | RelType RelativeRel; | |
| 100 | RelType IRelativeRel; | |
| 101 | RelType TlsDescRel; | |
| 102 | RelType TlsGotRel; | |
| 103 | RelType TlsModuleIndexRel; | |
| 104 | RelType TlsOffsetRel; | |
| 105 | unsigned GotEntrySize = 0; | |
| 106 | unsigned GotPltEntrySize = 0; | |
| 107 | unsigned PltEntrySize; | |
| 108 | unsigned PltHeaderSize; | |
| 90 | bool gotBaseSymInGotPlt = true; | |
| 91 | ||
| 92 | RelType copyRel; | |
| 93 | RelType gotRel; | |
| 94 | RelType noneRel; | |
| 95 | RelType pltRel; | |
| 96 | RelType relativeRel; | |
| 97 | RelType iRelativeRel; | |
| 98 | RelType symbolicRel; | |
| 99 | RelType tlsDescRel; | |
| 100 | RelType tlsGotRel; | |
| 101 | RelType tlsModuleIndexRel; | |
| 102 | RelType tlsOffsetRel; | |
| 103 | unsigned pltEntrySize; | |
| 104 | unsigned pltHeaderSize; | |
| 109 | 105 | |
| 110 | 106 | // At least on x86_64 positions 1 and 2 are used by the first plt entry |
| 111 | 107 | // to support lazy loading. |
| 112 | unsigned GotPltHeaderEntriesNum = 3; | |
| 108 | unsigned gotPltHeaderEntriesNum = 3; | |
| 113 | 109 | |
| 114 | 110 | // On PPC ELF V2 abi, the first entry in the .got is the .TOC. |
| 115 | unsigned GotHeaderEntriesNum = 0; | |
| 111 | unsigned gotHeaderEntriesNum = 0; | |
| 116 | 112 | |
| 117 | bool NeedsThunks = false; | |
| 113 | bool needsThunks = false; | |
| 118 | 114 | |
| 119 | 115 | // A 4-byte field corresponding to one or more trap instructions, used to pad |
| 120 | 116 | // executable OutputSections. |
| 121 | std::array<uint8_t, 4> TrapInstr; | |
| 117 | std::array<uint8_t, 4> trapInstr; | |
| 122 | 118 | |
| 123 | 119 | // If a target needs to rewrite calls to __morestack to instead call |
| 124 | 120 | // __morestack_non_split when a split-stack enabled caller calls a |
| 125 | 121 | // non-split-stack callee this will return true. Otherwise returns false. |
| 126 | bool NeedsMoreStackNonSplit = true; | |
| 122 | bool needsMoreStackNonSplit = true; | |
| 127 | 123 | |
| 128 | virtual RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, | |
| 129 | RelExpr Expr) const; | |
| 130 | virtual void relaxGot(uint8_t *Loc, uint64_t Val) const; | |
| 131 | virtual void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const; | |
| 132 | virtual void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const; | |
| 133 | virtual void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const; | |
| 134 | virtual void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const; | |
| 124 | virtual RelExpr adjustRelaxExpr(RelType type, const uint8_t *data, | |
| 125 | RelExpr expr) const; | |
| 126 | virtual void relaxGot(uint8_t *loc, RelType type, uint64_t val) const; | |
| 127 | virtual void relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const; | |
| 128 | virtual void relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const; | |
| 129 | virtual void relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const; | |
| 130 | virtual void relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const; | |
| 135 | 131 | |
| 136 | 132 | protected: |
| 137 | 133 | // On FreeBSD x86_64 the first page cannot be mmaped. |
| 138 | 134 | // On Linux that is controled by vm.mmap_min_addr. At least on some x86_64 |
| 139 | 135 | // installs that is 65536, so the first 15 pages cannot be used. |
| 140 | 136 | // Given that, the smallest value that can be used in here is 0x10000. |
| 141 | uint64_t DefaultImageBase = 0x10000; | |
| 137 | uint64_t defaultImageBase = 0x10000; | |
| 142 | 138 | }; |
| 143 | 139 | |
| 144 | 140 | TargetInfo *getAArch64TargetInfo(); |
| ... | ... | @@ -151,108 +147,113 @@ TargetInfo *getPPC64TargetInfo(); |
| 151 | 147 | TargetInfo *getPPCTargetInfo(); |
| 152 | 148 | TargetInfo *getRISCVTargetInfo(); |
| 153 | 149 | TargetInfo *getSPARCV9TargetInfo(); |
| 154 | TargetInfo *getX32TargetInfo(); | |
| 155 | 150 | TargetInfo *getX86TargetInfo(); |
| 156 | 151 | TargetInfo *getX86_64TargetInfo(); |
| 157 | 152 | template <class ELFT> TargetInfo *getMipsTargetInfo(); |
| 158 | 153 | |
| 159 | 154 | struct ErrorPlace { |
| 160 | InputSectionBase *IS; | |
| 161 | std::string Loc; | |
| 155 | InputSectionBase *isec; | |
| 156 | std::string loc; | |
| 162 | 157 | }; |
| 163 | 158 | |
| 164 | 159 | // Returns input section and corresponding source string for the given location. |
| 165 | ErrorPlace getErrorPlace(const uint8_t *Loc); | |
| 160 | ErrorPlace getErrorPlace(const uint8_t *loc); | |
| 166 | 161 | |
| 167 | static inline std::string getErrorLocation(const uint8_t *Loc) { | |
| 168 | return getErrorPlace(Loc).Loc; | |
| 162 | static inline std::string getErrorLocation(const uint8_t *loc) { | |
| 163 | return getErrorPlace(loc).loc; | |
| 169 | 164 | } |
| 170 | 165 | |
| 171 | // In the PowerPC64 Elf V2 abi a function can have 2 entry points. The first is | |
| 172 | // a global entry point (GEP) which typically is used to intiailzie the TOC | |
| 166 | void writePPC32GlinkSection(uint8_t *buf, size_t numEntries); | |
| 167 | ||
| 168 | bool tryRelaxPPC64TocIndirection(RelType type, const Relocation &rel, | |
| 169 | uint8_t *bufLoc); | |
| 170 | unsigned getPPCDFormOp(unsigned secondaryOp); | |
| 171 | ||
| 172 | // In the PowerPC64 Elf V2 abi a function can have 2 entry points. The first | |
| 173 | // is a global entry point (GEP) which typically is used to initialize the TOC | |
| 173 | 174 | // pointer in general purpose register 2. The second is a local entry |
| 174 | 175 | // point (LEP) which bypasses the TOC pointer initialization code. The |
| 175 | 176 | // offset between GEP and LEP is encoded in a function's st_other flags. |
| 176 | 177 | // This function will return the offset (in bytes) from the global entry-point |
| 177 | 178 | // to the local entry-point. |
| 178 | unsigned getPPC64GlobalEntryToLocalEntryOffset(uint8_t StOther); | |
| 179 | unsigned getPPC64GlobalEntryToLocalEntryOffset(uint8_t stOther); | |
| 180 | ||
| 181 | // Returns true if a relocation is a small code model relocation that accesses | |
| 182 | // the .toc section. | |
| 183 | bool isPPC64SmallCodeModelTocReloc(RelType type); | |
| 179 | 184 | |
| 180 | 185 | uint64_t getPPC64TocBase(); |
| 181 | uint64_t getAArch64Page(uint64_t Expr); | |
| 186 | uint64_t getAArch64Page(uint64_t expr); | |
| 182 | 187 | |
| 183 | extern TargetInfo *Target; | |
| 188 | extern const TargetInfo *target; | |
| 184 | 189 | TargetInfo *getTarget(); |
| 185 | 190 | |
| 186 | template <class ELFT> bool isMipsPIC(const Defined *Sym); | |
| 191 | template <class ELFT> bool isMipsPIC(const Defined *sym); | |
| 187 | 192 | |
| 188 | static inline void reportRangeError(uint8_t *Loc, RelType Type, const Twine &V, | |
| 189 | int64_t Min, uint64_t Max) { | |
| 190 | ErrorPlace ErrPlace = getErrorPlace(Loc); | |
| 191 | StringRef Hint; | |
| 192 | if (ErrPlace.IS && ErrPlace.IS->Name.startswith(".debug")) | |
| 193 | Hint = "; consider recompiling with -fdebug-types-section to reduce size " | |
| 193 | static inline void reportRangeError(uint8_t *loc, RelType type, const Twine &v, | |
| 194 | int64_t min, uint64_t max) { | |
| 195 | ErrorPlace errPlace = getErrorPlace(loc); | |
| 196 | StringRef hint; | |
| 197 | if (errPlace.isec && errPlace.isec->name.startswith(".debug")) | |
| 198 | hint = "; consider recompiling with -fdebug-types-section to reduce size " | |
| 194 | 199 | "of debug sections"; |
| 195 | 200 | |
| 196 | errorOrWarn(ErrPlace.Loc + "relocation " + lld::toString(Type) + | |
| 197 | " out of range: " + V.str() + " is not in [" + Twine(Min).str() + | |
| 198 | ", " + Twine(Max).str() + "]" + Hint); | |
| 199 | } | |
| 200 | ||
| 201 | inline unsigned getPltEntryOffset(unsigned Idx) { | |
| 202 | return Target->PltHeaderSize + Target->PltEntrySize * Idx; | |
| 201 | errorOrWarn(errPlace.loc + "relocation " + lld::toString(type) + | |
| 202 | " out of range: " + v.str() + " is not in [" + Twine(min).str() + | |
| 203 | ", " + Twine(max).str() + "]" + hint); | |
| 203 | 204 | } |
| 204 | 205 | |
| 205 | 206 | // Make sure that V can be represented as an N bit signed integer. |
| 206 | inline void checkInt(uint8_t *Loc, int64_t V, int N, RelType Type) { | |
| 207 | if (V != llvm::SignExtend64(V, N)) | |
| 208 | reportRangeError(Loc, Type, Twine(V), llvm::minIntN(N), llvm::maxIntN(N)); | |
| 207 | inline void checkInt(uint8_t *loc, int64_t v, int n, RelType type) { | |
| 208 | if (v != llvm::SignExtend64(v, n)) | |
| 209 | reportRangeError(loc, type, Twine(v), llvm::minIntN(n), llvm::maxIntN(n)); | |
| 209 | 210 | } |
| 210 | 211 | |
| 211 | 212 | // Make sure that V can be represented as an N bit unsigned integer. |
| 212 | inline void checkUInt(uint8_t *Loc, uint64_t V, int N, RelType Type) { | |
| 213 | if ((V >> N) != 0) | |
| 214 | reportRangeError(Loc, Type, Twine(V), 0, llvm::maxUIntN(N)); | |
| 213 | inline void checkUInt(uint8_t *loc, uint64_t v, int n, RelType type) { | |
| 214 | if ((v >> n) != 0) | |
| 215 | reportRangeError(loc, type, Twine(v), 0, llvm::maxUIntN(n)); | |
| 215 | 216 | } |
| 216 | 217 | |
| 217 | 218 | // Make sure that V can be represented as an N bit signed or unsigned integer. |
| 218 | inline void checkIntUInt(uint8_t *Loc, uint64_t V, int N, RelType Type) { | |
| 219 | inline void checkIntUInt(uint8_t *loc, uint64_t v, int n, RelType type) { | |
| 219 | 220 | // For the error message we should cast V to a signed integer so that error |
| 220 | 221 | // messages show a small negative value rather than an extremely large one |
| 221 | if (V != (uint64_t)llvm::SignExtend64(V, N) && (V >> N) != 0) | |
| 222 | reportRangeError(Loc, Type, Twine((int64_t)V), llvm::minIntN(N), | |
| 223 | llvm::maxIntN(N)); | |
| 222 | if (v != (uint64_t)llvm::SignExtend64(v, n) && (v >> n) != 0) | |
| 223 | reportRangeError(loc, type, Twine((int64_t)v), llvm::minIntN(n), | |
| 224 | llvm::maxUIntN(n)); | |
| 224 | 225 | } |
| 225 | 226 | |
| 226 | inline void checkAlignment(uint8_t *Loc, uint64_t V, int N, RelType Type) { | |
| 227 | if ((V & (N - 1)) != 0) | |
| 228 | error(getErrorLocation(Loc) + "improper alignment for relocation " + | |
| 229 | lld::toString(Type) + ": 0x" + llvm::utohexstr(V) + | |
| 230 | " is not aligned to " + Twine(N) + " bytes"); | |
| 227 | inline void checkAlignment(uint8_t *loc, uint64_t v, int n, RelType type) { | |
| 228 | if ((v & (n - 1)) != 0) | |
| 229 | error(getErrorLocation(loc) + "improper alignment for relocation " + | |
| 230 | lld::toString(type) + ": 0x" + llvm::utohexstr(v) + | |
| 231 | " is not aligned to " + Twine(n) + " bytes"); | |
| 231 | 232 | } |
| 232 | 233 | |
| 233 | 234 | // Endianness-aware read/write. |
| 234 | inline uint16_t read16(const void *P) { | |
| 235 | return llvm::support::endian::read16(P, Config->Endianness); | |
| 235 | inline uint16_t read16(const void *p) { | |
| 236 | return llvm::support::endian::read16(p, config->endianness); | |
| 236 | 237 | } |
| 237 | 238 | |
| 238 | inline uint32_t read32(const void *P) { | |
| 239 | return llvm::support::endian::read32(P, Config->Endianness); | |
| 239 | inline uint32_t read32(const void *p) { | |
| 240 | return llvm::support::endian::read32(p, config->endianness); | |
| 240 | 241 | } |
| 241 | 242 | |
| 242 | inline uint64_t read64(const void *P) { | |
| 243 | return llvm::support::endian::read64(P, Config->Endianness); | |
| 243 | inline uint64_t read64(const void *p) { | |
| 244 | return llvm::support::endian::read64(p, config->endianness); | |
| 244 | 245 | } |
| 245 | 246 | |
| 246 | inline void write16(void *P, uint16_t V) { | |
| 247 | llvm::support::endian::write16(P, V, Config->Endianness); | |
| 247 | inline void write16(void *p, uint16_t v) { | |
| 248 | llvm::support::endian::write16(p, v, config->endianness); | |
| 248 | 249 | } |
| 249 | 250 | |
| 250 | inline void write32(void *P, uint32_t V) { | |
| 251 | llvm::support::endian::write32(P, V, Config->Endianness); | |
| 251 | inline void write32(void *p, uint32_t v) { | |
| 252 | llvm::support::endian::write32(p, v, config->endianness); | |
| 252 | 253 | } |
| 253 | 254 | |
| 254 | inline void write64(void *P, uint64_t V) { | |
| 255 | llvm::support::endian::write64(P, V, Config->Endianness); | |
| 255 | inline void write64(void *p, uint64_t v) { | |
| 256 | llvm::support::endian::write64(p, v, config->endianness); | |
| 256 | 257 | } |
| 257 | 258 | } // namespace elf |
| 258 | 259 | } // namespace lld |
deps/lld/ELF/Thunks.cpp+450-359| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Thunks.cpp --------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===---------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -50,18 +49,18 @@ namespace { |
| 50 | 49 | // AArch64 long range Thunks |
| 51 | 50 | class AArch64ABSLongThunk final : public Thunk { |
| 52 | 51 | public: |
| 53 | AArch64ABSLongThunk(Symbol &Dest) : Thunk(Dest) {} | |
| 52 | AArch64ABSLongThunk(Symbol &dest) : Thunk(dest) {} | |
| 54 | 53 | uint32_t size() override { return 16; } |
| 55 | void writeTo(uint8_t *Buf) override; | |
| 56 | void addSymbols(ThunkSection &IS) override; | |
| 54 | void writeTo(uint8_t *buf) override; | |
| 55 | void addSymbols(ThunkSection &isec) override; | |
| 57 | 56 | }; |
| 58 | 57 | |
| 59 | 58 | class AArch64ADRPThunk final : public Thunk { |
| 60 | 59 | public: |
| 61 | AArch64ADRPThunk(Symbol &Dest) : Thunk(Dest) {} | |
| 60 | AArch64ADRPThunk(Symbol &dest) : Thunk(dest) {} | |
| 62 | 61 | uint32_t size() override { return 12; } |
| 63 | void writeTo(uint8_t *Buf) override; | |
| 64 | void addSymbols(ThunkSection &IS) override; | |
| 62 | void writeTo(uint8_t *buf) override; | |
| 63 | void addSymbols(ThunkSection &isec) override; | |
| 65 | 64 | }; |
| 66 | 65 | |
| 67 | 66 | // Base class for ARM thunks. |
| ... | ... | @@ -74,18 +73,19 @@ public: |
| 74 | 73 | // if the target is in range, otherwise it creates a long thunk. |
| 75 | 74 | class ARMThunk : public Thunk { |
| 76 | 75 | public: |
| 77 | ARMThunk(Symbol &Dest) : Thunk(Dest) {} | |
| 76 | ARMThunk(Symbol &dest) : Thunk(dest) {} | |
| 78 | 77 | |
| 79 | bool mayUseShortThunk(); | |
| 80 | uint32_t size() override { return mayUseShortThunk() ? 4 : sizeLong(); } | |
| 81 | void writeTo(uint8_t *Buf) override; | |
| 82 | bool isCompatibleWith(RelType Type) const override; | |
| 78 | bool getMayUseShortThunk(); | |
| 79 | uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); } | |
| 80 | void writeTo(uint8_t *buf) override; | |
| 81 | bool isCompatibleWith(const InputSection &isec, | |
| 82 | const Relocation &rel) const override; | |
| 83 | 83 | |
| 84 | 84 | // Returns the size of a long thunk. |
| 85 | 85 | virtual uint32_t sizeLong() = 0; |
| 86 | 86 | |
| 87 | 87 | // Writes a long thunk to Buf. |
| 88 | virtual void writeLong(uint8_t *Buf) = 0; | |
| 88 | virtual void writeLong(uint8_t *buf) = 0; | |
| 89 | 89 | |
| 90 | 90 | private: |
| 91 | 91 | // This field tracks whether all previously considered layouts would allow |
| ... | ... | @@ -94,7 +94,7 @@ private: |
| 94 | 94 | // distance to the target. We do this because transitioning from long to short |
| 95 | 95 | // can create layout oscillations in certain corner cases which would prevent |
| 96 | 96 | // the layout from converging. |
| 97 | bool MayUseShortThunk = true; | |
| 97 | bool mayUseShortThunk = true; | |
| 98 | 98 | }; |
| 99 | 99 | |
| 100 | 100 | // Base class for Thumb-2 thunks. |
| ... | ... | @@ -103,60 +103,61 @@ private: |
| 103 | 103 | // which has a range of 16MB. |
| 104 | 104 | class ThumbThunk : public Thunk { |
| 105 | 105 | public: |
| 106 | ThumbThunk(Symbol &Dest) : Thunk(Dest) { Alignment = 2; } | |
| 106 | ThumbThunk(Symbol &dest) : Thunk(dest) { alignment = 2; } | |
| 107 | 107 | |
| 108 | bool mayUseShortThunk(); | |
| 109 | uint32_t size() override { return mayUseShortThunk() ? 4 : sizeLong(); } | |
| 110 | void writeTo(uint8_t *Buf) override; | |
| 111 | bool isCompatibleWith(RelType Type) const override; | |
| 108 | bool getMayUseShortThunk(); | |
| 109 | uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); } | |
| 110 | void writeTo(uint8_t *buf) override; | |
| 111 | bool isCompatibleWith(const InputSection &isec, | |
| 112 | const Relocation &rel) const override; | |
| 112 | 113 | |
| 113 | 114 | // Returns the size of a long thunk. |
| 114 | 115 | virtual uint32_t sizeLong() = 0; |
| 115 | 116 | |
| 116 | 117 | // Writes a long thunk to Buf. |
| 117 | virtual void writeLong(uint8_t *Buf) = 0; | |
| 118 | virtual void writeLong(uint8_t *buf) = 0; | |
| 118 | 119 | |
| 119 | 120 | private: |
| 120 | 121 | // See comment in ARMThunk above. |
| 121 | bool MayUseShortThunk = true; | |
| 122 | bool mayUseShortThunk = true; | |
| 122 | 123 | }; |
| 123 | 124 | |
| 124 | 125 | // Specific ARM Thunk implementations. The naming convention is: |
| 125 | 126 | // Source State, TargetState, Target Requirement, ABS or PI, Range |
| 126 | 127 | class ARMV7ABSLongThunk final : public ARMThunk { |
| 127 | 128 | public: |
| 128 | ARMV7ABSLongThunk(Symbol &Dest) : ARMThunk(Dest) {} | |
| 129 | ARMV7ABSLongThunk(Symbol &dest) : ARMThunk(dest) {} | |
| 129 | 130 | |
| 130 | 131 | uint32_t sizeLong() override { return 12; } |
| 131 | void writeLong(uint8_t *Buf) override; | |
| 132 | void addSymbols(ThunkSection &IS) override; | |
| 132 | void writeLong(uint8_t *buf) override; | |
| 133 | void addSymbols(ThunkSection &isec) override; | |
| 133 | 134 | }; |
| 134 | 135 | |
| 135 | 136 | class ARMV7PILongThunk final : public ARMThunk { |
| 136 | 137 | public: |
| 137 | ARMV7PILongThunk(Symbol &Dest) : ARMThunk(Dest) {} | |
| 138 | ARMV7PILongThunk(Symbol &dest) : ARMThunk(dest) {} | |
| 138 | 139 | |
| 139 | 140 | uint32_t sizeLong() override { return 16; } |
| 140 | void writeLong(uint8_t *Buf) override; | |
| 141 | void addSymbols(ThunkSection &IS) override; | |
| 141 | void writeLong(uint8_t *buf) override; | |
| 142 | void addSymbols(ThunkSection &isec) override; | |
| 142 | 143 | }; |
| 143 | 144 | |
| 144 | 145 | class ThumbV7ABSLongThunk final : public ThumbThunk { |
| 145 | 146 | public: |
| 146 | ThumbV7ABSLongThunk(Symbol &Dest) : ThumbThunk(Dest) {} | |
| 147 | ThumbV7ABSLongThunk(Symbol &dest) : ThumbThunk(dest) {} | |
| 147 | 148 | |
| 148 | 149 | uint32_t sizeLong() override { return 10; } |
| 149 | void writeLong(uint8_t *Buf) override; | |
| 150 | void addSymbols(ThunkSection &IS) override; | |
| 150 | void writeLong(uint8_t *buf) override; | |
| 151 | void addSymbols(ThunkSection &isec) override; | |
| 151 | 152 | }; |
| 152 | 153 | |
| 153 | 154 | class ThumbV7PILongThunk final : public ThumbThunk { |
| 154 | 155 | public: |
| 155 | ThumbV7PILongThunk(Symbol &Dest) : ThumbThunk(Dest) {} | |
| 156 | ThumbV7PILongThunk(Symbol &dest) : ThumbThunk(dest) {} | |
| 156 | 157 | |
| 157 | 158 | uint32_t sizeLong() override { return 12; } |
| 158 | void writeLong(uint8_t *Buf) override; | |
| 159 | void addSymbols(ThunkSection &IS) override; | |
| 159 | void writeLong(uint8_t *buf) override; | |
| 160 | void addSymbols(ThunkSection &isec) override; | |
| 160 | 161 | }; |
| 161 | 162 | |
| 162 | 163 | // Implementations of Thunks for older Arm architectures that do not support |
| ... | ... | @@ -166,76 +167,96 @@ public: |
| 166 | 167 | // can result in a thunk |
| 167 | 168 | class ARMV5ABSLongThunk final : public ARMThunk { |
| 168 | 169 | public: |
| 169 | ARMV5ABSLongThunk(Symbol &Dest) : ARMThunk(Dest) {} | |
| 170 | ARMV5ABSLongThunk(Symbol &dest) : ARMThunk(dest) {} | |
| 170 | 171 | |
| 171 | 172 | uint32_t sizeLong() override { return 8; } |
| 172 | void writeLong(uint8_t *Buf) override; | |
| 173 | void addSymbols(ThunkSection &IS) override; | |
| 174 | bool isCompatibleWith(uint32_t RelocType) const override; | |
| 173 | void writeLong(uint8_t *buf) override; | |
| 174 | void addSymbols(ThunkSection &isec) override; | |
| 175 | bool isCompatibleWith(const InputSection &isec, | |
| 176 | const Relocation &rel) const override; | |
| 175 | 177 | }; |
| 176 | 178 | |
| 177 | 179 | class ARMV5PILongThunk final : public ARMThunk { |
| 178 | 180 | public: |
| 179 | ARMV5PILongThunk(Symbol &Dest) : ARMThunk(Dest) {} | |
| 181 | ARMV5PILongThunk(Symbol &dest) : ARMThunk(dest) {} | |
| 180 | 182 | |
| 181 | 183 | uint32_t sizeLong() override { return 16; } |
| 182 | void writeLong(uint8_t *Buf) override; | |
| 183 | void addSymbols(ThunkSection &IS) override; | |
| 184 | bool isCompatibleWith(uint32_t RelocType) const override; | |
| 184 | void writeLong(uint8_t *buf) override; | |
| 185 | void addSymbols(ThunkSection &isec) override; | |
| 186 | bool isCompatibleWith(const InputSection &isec, | |
| 187 | const Relocation &rel) const override; | |
| 185 | 188 | }; |
| 186 | 189 | |
| 187 | 190 | // Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted |
| 188 | 191 | class ThumbV6MABSLongThunk final : public ThumbThunk { |
| 189 | 192 | public: |
| 190 | ThumbV6MABSLongThunk(Symbol &Dest) : ThumbThunk(Dest) {} | |
| 193 | ThumbV6MABSLongThunk(Symbol &dest) : ThumbThunk(dest) {} | |
| 191 | 194 | |
| 192 | 195 | uint32_t sizeLong() override { return 12; } |
| 193 | void writeLong(uint8_t *Buf) override; | |
| 194 | void addSymbols(ThunkSection &IS) override; | |
| 196 | void writeLong(uint8_t *buf) override; | |
| 197 | void addSymbols(ThunkSection &isec) override; | |
| 195 | 198 | }; |
| 196 | 199 | |
| 197 | 200 | class ThumbV6MPILongThunk final : public ThumbThunk { |
| 198 | 201 | public: |
| 199 | ThumbV6MPILongThunk(Symbol &Dest) : ThumbThunk(Dest) {} | |
| 202 | ThumbV6MPILongThunk(Symbol &dest) : ThumbThunk(dest) {} | |
| 200 | 203 | |
| 201 | 204 | uint32_t sizeLong() override { return 16; } |
| 202 | void writeLong(uint8_t *Buf) override; | |
| 203 | void addSymbols(ThunkSection &IS) override; | |
| 205 | void writeLong(uint8_t *buf) override; | |
| 206 | void addSymbols(ThunkSection &isec) override; | |
| 204 | 207 | }; |
| 205 | 208 | |
| 206 | 209 | // MIPS LA25 thunk |
| 207 | 210 | class MipsThunk final : public Thunk { |
| 208 | 211 | public: |
| 209 | MipsThunk(Symbol &Dest) : Thunk(Dest) {} | |
| 212 | MipsThunk(Symbol &dest) : Thunk(dest) {} | |
| 210 | 213 | |
| 211 | 214 | uint32_t size() override { return 16; } |
| 212 | void writeTo(uint8_t *Buf) override; | |
| 213 | void addSymbols(ThunkSection &IS) override; | |
| 215 | void writeTo(uint8_t *buf) override; | |
| 216 | void addSymbols(ThunkSection &isec) override; | |
| 214 | 217 | InputSection *getTargetInputSection() const override; |
| 215 | 218 | }; |
| 216 | 219 | |
| 217 | 220 | // microMIPS R2-R5 LA25 thunk |
| 218 | 221 | class MicroMipsThunk final : public Thunk { |
| 219 | 222 | public: |
| 220 | MicroMipsThunk(Symbol &Dest) : Thunk(Dest) {} | |
| 223 | MicroMipsThunk(Symbol &dest) : Thunk(dest) {} | |
| 221 | 224 | |
| 222 | 225 | uint32_t size() override { return 14; } |
| 223 | void writeTo(uint8_t *Buf) override; | |
| 224 | void addSymbols(ThunkSection &IS) override; | |
| 226 | void writeTo(uint8_t *buf) override; | |
| 227 | void addSymbols(ThunkSection &isec) override; | |
| 225 | 228 | InputSection *getTargetInputSection() const override; |
| 226 | 229 | }; |
| 227 | 230 | |
| 228 | 231 | // microMIPS R6 LA25 thunk |
| 229 | 232 | class MicroMipsR6Thunk final : public Thunk { |
| 230 | 233 | public: |
| 231 | MicroMipsR6Thunk(Symbol &Dest) : Thunk(Dest) {} | |
| 234 | MicroMipsR6Thunk(Symbol &dest) : Thunk(dest) {} | |
| 232 | 235 | |
| 233 | 236 | uint32_t size() override { return 12; } |
| 234 | void writeTo(uint8_t *Buf) override; | |
| 235 | void addSymbols(ThunkSection &IS) override; | |
| 237 | void writeTo(uint8_t *buf) override; | |
| 238 | void addSymbols(ThunkSection &isec) override; | |
| 236 | 239 | InputSection *getTargetInputSection() const override; |
| 237 | 240 | }; |
| 238 | 241 | |
| 242 | class PPC32PltCallStub final : public Thunk { | |
| 243 | public: | |
| 244 | PPC32PltCallStub(const InputSection &isec, const Relocation &rel, Symbol &dest) | |
| 245 | : Thunk(dest), addend(rel.type == R_PPC_PLTREL24 ? rel.addend : 0), | |
| 246 | file(isec.file) {} | |
| 247 | uint32_t size() override { return 16; } | |
| 248 | void writeTo(uint8_t *buf) override; | |
| 249 | void addSymbols(ThunkSection &isec) override; | |
| 250 | bool isCompatibleWith(const InputSection &isec, const Relocation &rel) const override; | |
| 251 | ||
| 252 | private: | |
| 253 | // For R_PPC_PLTREL24, this records the addend, which will be used to decide | |
| 254 | // the offsets in the call stub. | |
| 255 | uint32_t addend; | |
| 256 | ||
| 257 | // Records the call site of the call stub. | |
| 258 | const InputFile *file; | |
| 259 | }; | |
| 239 | 260 | |
| 240 | 261 | // PPC64 Plt call stubs. |
| 241 | 262 | // Any call site that needs to call through a plt entry needs a call stub in |
| ... | ... | @@ -247,10 +268,10 @@ public: |
| 247 | 268 | // 3) Transfering control to the target function through an indirect branch. |
| 248 | 269 | class PPC64PltCallStub final : public Thunk { |
| 249 | 270 | public: |
| 250 | PPC64PltCallStub(Symbol &Dest) : Thunk(Dest) {} | |
| 271 | PPC64PltCallStub(Symbol &dest) : Thunk(dest) {} | |
| 251 | 272 | uint32_t size() override { return 20; } |
| 252 | void writeTo(uint8_t *Buf) override; | |
| 253 | void addSymbols(ThunkSection &IS) override; | |
| 273 | void writeTo(uint8_t *buf) override; | |
| 274 | void addSymbols(ThunkSection &isec) override; | |
| 254 | 275 | }; |
| 255 | 276 | |
| 256 | 277 | // A bl instruction uses a signed 24 bit offset, with an implicit 4 byte |
| ... | ... | @@ -264,74 +285,75 @@ public: |
| 264 | 285 | class PPC64LongBranchThunk : public Thunk { |
| 265 | 286 | public: |
| 266 | 287 | uint32_t size() override { return 16; } |
| 267 | void writeTo(uint8_t *Buf) override; | |
| 268 | void addSymbols(ThunkSection &IS) override; | |
| 288 | void writeTo(uint8_t *buf) override; | |
| 289 | void addSymbols(ThunkSection &isec) override; | |
| 269 | 290 | |
| 270 | 291 | protected: |
| 271 | PPC64LongBranchThunk(Symbol &Dest) : Thunk(Dest) {} | |
| 292 | PPC64LongBranchThunk(Symbol &dest) : Thunk(dest) {} | |
| 272 | 293 | }; |
| 273 | 294 | |
| 274 | 295 | class PPC64PILongBranchThunk final : public PPC64LongBranchThunk { |
| 275 | 296 | public: |
| 276 | PPC64PILongBranchThunk(Symbol &Dest) : PPC64LongBranchThunk(Dest) { | |
| 277 | assert(!Dest.IsPreemptible); | |
| 278 | if (Dest.isInPPC64Branchlt()) | |
| 297 | PPC64PILongBranchThunk(Symbol &dest) : PPC64LongBranchThunk(dest) { | |
| 298 | assert(!dest.isPreemptible); | |
| 299 | if (dest.isInPPC64Branchlt()) | |
| 279 | 300 | return; |
| 280 | 301 | |
| 281 | In.PPC64LongBranchTarget->addEntry(Dest); | |
| 282 | In.RelaDyn->addReloc({Target->RelativeRel, In.PPC64LongBranchTarget, | |
| 283 | Dest.getPPC64LongBranchOffset(), true, &Dest, | |
| 284 | getPPC64GlobalEntryToLocalEntryOffset(Dest.StOther)}); | |
| 302 | in.ppc64LongBranchTarget->addEntry(dest); | |
| 303 | mainPart->relaDyn->addReloc( | |
| 304 | {target->relativeRel, in.ppc64LongBranchTarget, | |
| 305 | dest.getPPC64LongBranchOffset(), true, &dest, | |
| 306 | getPPC64GlobalEntryToLocalEntryOffset(dest.stOther)}); | |
| 285 | 307 | } |
| 286 | 308 | }; |
| 287 | 309 | |
| 288 | 310 | class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk { |
| 289 | 311 | public: |
| 290 | PPC64PDLongBranchThunk(Symbol &Dest) : PPC64LongBranchThunk(Dest) { | |
| 291 | if (!Dest.isInPPC64Branchlt()) | |
| 292 | In.PPC64LongBranchTarget->addEntry(Dest); | |
| 312 | PPC64PDLongBranchThunk(Symbol &dest) : PPC64LongBranchThunk(dest) { | |
| 313 | if (!dest.isInPPC64Branchlt()) | |
| 314 | in.ppc64LongBranchTarget->addEntry(dest); | |
| 293 | 315 | } |
| 294 | 316 | }; |
| 295 | 317 | |
| 296 | 318 | } // end anonymous namespace |
| 297 | 319 | |
| 298 | Defined *Thunk::addSymbol(StringRef Name, uint8_t Type, uint64_t Value, | |
| 299 | InputSectionBase &Section) { | |
| 300 | Defined *D = addSyntheticLocal(Name, Type, Value, /*Size=*/0, Section); | |
| 301 | Syms.push_back(D); | |
| 302 | return D; | |
| 320 | Defined *Thunk::addSymbol(StringRef name, uint8_t type, uint64_t value, | |
| 321 | InputSectionBase &section) { | |
| 322 | Defined *d = addSyntheticLocal(name, type, value, /*size=*/0, section); | |
| 323 | syms.push_back(d); | |
| 324 | return d; | |
| 303 | 325 | } |
| 304 | 326 | |
| 305 | void Thunk::setOffset(uint64_t NewOffset) { | |
| 306 | for (Defined *D : Syms) | |
| 307 | D->Value = D->Value - Offset + NewOffset; | |
| 308 | Offset = NewOffset; | |
| 327 | void Thunk::setOffset(uint64_t newOffset) { | |
| 328 | for (Defined *d : syms) | |
| 329 | d->value = d->value - offset + newOffset; | |
| 330 | offset = newOffset; | |
| 309 | 331 | } |
| 310 | 332 | |
| 311 | 333 | // AArch64 long range Thunks |
| 312 | 334 | |
| 313 | static uint64_t getAArch64ThunkDestVA(const Symbol &S) { | |
| 314 | uint64_t V = S.isInPlt() ? S.getPltVA() : S.getVA(); | |
| 315 | return V; | |
| 335 | static uint64_t getAArch64ThunkDestVA(const Symbol &s) { | |
| 336 | uint64_t v = s.isInPlt() ? s.getPltVA() : s.getVA(); | |
| 337 | return v; | |
| 316 | 338 | } |
| 317 | 339 | |
| 318 | void AArch64ABSLongThunk::writeTo(uint8_t *Buf) { | |
| 319 | const uint8_t Data[] = { | |
| 340 | void AArch64ABSLongThunk::writeTo(uint8_t *buf) { | |
| 341 | const uint8_t data[] = { | |
| 320 | 342 | 0x50, 0x00, 0x00, 0x58, // ldr x16, L0 |
| 321 | 343 | 0x00, 0x02, 0x1f, 0xd6, // br x16 |
| 322 | 344 | 0x00, 0x00, 0x00, 0x00, // L0: .xword S |
| 323 | 345 | 0x00, 0x00, 0x00, 0x00, |
| 324 | 346 | }; |
| 325 | uint64_t S = getAArch64ThunkDestVA(Destination); | |
| 326 | memcpy(Buf, Data, sizeof(Data)); | |
| 327 | Target->relocateOne(Buf + 8, R_AARCH64_ABS64, S); | |
| 347 | uint64_t s = getAArch64ThunkDestVA(destination); | |
| 348 | memcpy(buf, data, sizeof(data)); | |
| 349 | target->relocateOne(buf + 8, R_AARCH64_ABS64, s); | |
| 328 | 350 | } |
| 329 | 351 | |
| 330 | void AArch64ABSLongThunk::addSymbols(ThunkSection &IS) { | |
| 331 | addSymbol(Saver.save("__AArch64AbsLongThunk_" + Destination.getName()), | |
| 332 | STT_FUNC, 0, IS); | |
| 333 | addSymbol("$x", STT_NOTYPE, 0, IS); | |
| 334 | addSymbol("$d", STT_NOTYPE, 8, IS); | |
| 352 | void AArch64ABSLongThunk::addSymbols(ThunkSection &isec) { | |
| 353 | addSymbol(saver.save("__AArch64AbsLongThunk_" + destination.getName()), | |
| 354 | STT_FUNC, 0, isec); | |
| 355 | addSymbol("$x", STT_NOTYPE, 0, isec); | |
| 356 | addSymbol("$d", STT_NOTYPE, 8, isec); | |
| 335 | 357 | } |
| 336 | 358 | |
| 337 | 359 | // This Thunk has a maximum range of 4Gb, this is sufficient for all programs |
| ... | ... | @@ -339,259 +361,263 @@ void AArch64ABSLongThunk::addSymbols(ThunkSection &IS) { |
| 339 | 361 | // clang and gcc do not support the large code model for position independent |
| 340 | 362 | // code so it is safe to use this for position independent thunks without |
| 341 | 363 | // worrying about the destination being more than 4Gb away. |
| 342 | void AArch64ADRPThunk::writeTo(uint8_t *Buf) { | |
| 343 | const uint8_t Data[] = { | |
| 364 | void AArch64ADRPThunk::writeTo(uint8_t *buf) { | |
| 365 | const uint8_t data[] = { | |
| 344 | 366 | 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest R_AARCH64_ADR_PREL_PG_HI21(Dest) |
| 345 | 367 | 0x10, 0x02, 0x00, 0x91, // add x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest) |
| 346 | 368 | 0x00, 0x02, 0x1f, 0xd6, // br x16 |
| 347 | 369 | }; |
| 348 | uint64_t S = getAArch64ThunkDestVA(Destination); | |
| 349 | uint64_t P = getThunkTargetSym()->getVA(); | |
| 350 | memcpy(Buf, Data, sizeof(Data)); | |
| 351 | Target->relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21, | |
| 352 | getAArch64Page(S) - getAArch64Page(P)); | |
| 353 | Target->relocateOne(Buf + 4, R_AARCH64_ADD_ABS_LO12_NC, S); | |
| 370 | uint64_t s = getAArch64ThunkDestVA(destination); | |
| 371 | uint64_t p = getThunkTargetSym()->getVA(); | |
| 372 | memcpy(buf, data, sizeof(data)); | |
| 373 | target->relocateOne(buf, R_AARCH64_ADR_PREL_PG_HI21, | |
| 374 | getAArch64Page(s) - getAArch64Page(p)); | |
| 375 | target->relocateOne(buf + 4, R_AARCH64_ADD_ABS_LO12_NC, s); | |
| 354 | 376 | } |
| 355 | 377 | |
| 356 | void AArch64ADRPThunk::addSymbols(ThunkSection &IS) { | |
| 357 | addSymbol(Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC, | |
| 358 | 0, IS); | |
| 359 | addSymbol("$x", STT_NOTYPE, 0, IS); | |
| 378 | void AArch64ADRPThunk::addSymbols(ThunkSection &isec) { | |
| 379 | addSymbol(saver.save("__AArch64ADRPThunk_" + destination.getName()), STT_FUNC, | |
| 380 | 0, isec); | |
| 381 | addSymbol("$x", STT_NOTYPE, 0, isec); | |
| 360 | 382 | } |
| 361 | 383 | |
| 362 | 384 | // ARM Target Thunks |
| 363 | static uint64_t getARMThunkDestVA(const Symbol &S) { | |
| 364 | uint64_t V = S.isInPlt() ? S.getPltVA() : S.getVA(); | |
| 365 | return SignExtend64<32>(V); | |
| 385 | static uint64_t getARMThunkDestVA(const Symbol &s) { | |
| 386 | uint64_t v = s.isInPlt() ? s.getPltVA() : s.getVA(); | |
| 387 | return SignExtend64<32>(v); | |
| 366 | 388 | } |
| 367 | 389 | |
| 368 | 390 | // This function returns true if the target is not Thumb and is within 2^26, and |
| 369 | // it has not previously returned false (see comment for MayUseShortThunk). | |
| 370 | bool ARMThunk::mayUseShortThunk() { | |
| 371 | if (!MayUseShortThunk) | |
| 391 | // it has not previously returned false (see comment for mayUseShortThunk). | |
| 392 | bool ARMThunk::getMayUseShortThunk() { | |
| 393 | if (!mayUseShortThunk) | |
| 372 | 394 | return false; |
| 373 | uint64_t S = getARMThunkDestVA(Destination); | |
| 374 | if (S & 1) { | |
| 375 | MayUseShortThunk = false; | |
| 395 | uint64_t s = getARMThunkDestVA(destination); | |
| 396 | if (s & 1) { | |
| 397 | mayUseShortThunk = false; | |
| 376 | 398 | return false; |
| 377 | 399 | } |
| 378 | uint64_t P = getThunkTargetSym()->getVA(); | |
| 379 | int64_t Offset = S - P - 8; | |
| 380 | MayUseShortThunk = llvm::isInt<26>(Offset); | |
| 381 | return MayUseShortThunk; | |
| 400 | uint64_t p = getThunkTargetSym()->getVA(); | |
| 401 | int64_t offset = s - p - 8; | |
| 402 | mayUseShortThunk = llvm::isInt<26>(offset); | |
| 403 | return mayUseShortThunk; | |
| 382 | 404 | } |
| 383 | 405 | |
| 384 | void ARMThunk::writeTo(uint8_t *Buf) { | |
| 385 | if (!mayUseShortThunk()) { | |
| 386 | writeLong(Buf); | |
| 406 | void ARMThunk::writeTo(uint8_t *buf) { | |
| 407 | if (!getMayUseShortThunk()) { | |
| 408 | writeLong(buf); | |
| 387 | 409 | return; |
| 388 | 410 | } |
| 389 | 411 | |
| 390 | uint64_t S = getARMThunkDestVA(Destination); | |
| 391 | uint64_t P = getThunkTargetSym()->getVA(); | |
| 392 | int64_t Offset = S - P - 8; | |
| 393 | const uint8_t Data[] = { | |
| 412 | uint64_t s = getARMThunkDestVA(destination); | |
| 413 | uint64_t p = getThunkTargetSym()->getVA(); | |
| 414 | int64_t offset = s - p - 8; | |
| 415 | const uint8_t data[] = { | |
| 394 | 416 | 0x00, 0x00, 0x00, 0xea, // b S |
| 395 | 417 | }; |
| 396 | memcpy(Buf, Data, sizeof(Data)); | |
| 397 | Target->relocateOne(Buf, R_ARM_JUMP24, Offset); | |
| 418 | memcpy(buf, data, sizeof(data)); | |
| 419 | target->relocateOne(buf, R_ARM_JUMP24, offset); | |
| 398 | 420 | } |
| 399 | 421 | |
| 400 | bool ARMThunk::isCompatibleWith(RelType Type) const { | |
| 422 | bool ARMThunk::isCompatibleWith(const InputSection &isec, | |
| 423 | const Relocation &rel) const { | |
| 401 | 424 | // Thumb branch relocations can't use BLX |
| 402 | return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24; | |
| 425 | return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24; | |
| 403 | 426 | } |
| 404 | 427 | |
| 405 | 428 | // This function returns true if the target is Thumb and is within 2^25, and |
| 406 | // it has not previously returned false (see comment for MayUseShortThunk). | |
| 407 | bool ThumbThunk::mayUseShortThunk() { | |
| 408 | if (!MayUseShortThunk) | |
| 429 | // it has not previously returned false (see comment for mayUseShortThunk). | |
| 430 | bool ThumbThunk::getMayUseShortThunk() { | |
| 431 | if (!mayUseShortThunk) | |
| 409 | 432 | return false; |
| 410 | uint64_t S = getARMThunkDestVA(Destination); | |
| 411 | if ((S & 1) == 0) { | |
| 412 | MayUseShortThunk = false; | |
| 433 | uint64_t s = getARMThunkDestVA(destination); | |
| 434 | if ((s & 1) == 0) { | |
| 435 | mayUseShortThunk = false; | |
| 413 | 436 | return false; |
| 414 | 437 | } |
| 415 | uint64_t P = getThunkTargetSym()->getVA() & ~1; | |
| 416 | int64_t Offset = S - P - 4; | |
| 417 | MayUseShortThunk = llvm::isInt<25>(Offset); | |
| 418 | return MayUseShortThunk; | |
| 438 | uint64_t p = getThunkTargetSym()->getVA() & ~1; | |
| 439 | int64_t offset = s - p - 4; | |
| 440 | mayUseShortThunk = llvm::isInt<25>(offset); | |
| 441 | return mayUseShortThunk; | |
| 419 | 442 | } |
| 420 | 443 | |
| 421 | void ThumbThunk::writeTo(uint8_t *Buf) { | |
| 422 | if (!mayUseShortThunk()) { | |
| 423 | writeLong(Buf); | |
| 444 | void ThumbThunk::writeTo(uint8_t *buf) { | |
| 445 | if (!getMayUseShortThunk()) { | |
| 446 | writeLong(buf); | |
| 424 | 447 | return; |
| 425 | 448 | } |
| 426 | 449 | |
| 427 | uint64_t S = getARMThunkDestVA(Destination); | |
| 428 | uint64_t P = getThunkTargetSym()->getVA(); | |
| 429 | int64_t Offset = S - P - 4; | |
| 430 | const uint8_t Data[] = { | |
| 450 | uint64_t s = getARMThunkDestVA(destination); | |
| 451 | uint64_t p = getThunkTargetSym()->getVA(); | |
| 452 | int64_t offset = s - p - 4; | |
| 453 | const uint8_t data[] = { | |
| 431 | 454 | 0x00, 0xf0, 0x00, 0xb0, // b.w S |
| 432 | 455 | }; |
| 433 | memcpy(Buf, Data, sizeof(Data)); | |
| 434 | Target->relocateOne(Buf, R_ARM_THM_JUMP24, Offset); | |
| 456 | memcpy(buf, data, sizeof(data)); | |
| 457 | target->relocateOne(buf, R_ARM_THM_JUMP24, offset); | |
| 435 | 458 | } |
| 436 | 459 | |
| 437 | bool ThumbThunk::isCompatibleWith(RelType Type) const { | |
| 460 | bool ThumbThunk::isCompatibleWith(const InputSection &isec, | |
| 461 | const Relocation &rel) const { | |
| 438 | 462 | // ARM branch relocations can't use BLX |
| 439 | return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32; | |
| 463 | return rel.type != R_ARM_JUMP24 && rel.type != R_ARM_PC24 && rel.type != R_ARM_PLT32; | |
| 440 | 464 | } |
| 441 | 465 | |
| 442 | void ARMV7ABSLongThunk::writeLong(uint8_t *Buf) { | |
| 443 | const uint8_t Data[] = { | |
| 466 | void ARMV7ABSLongThunk::writeLong(uint8_t *buf) { | |
| 467 | const uint8_t data[] = { | |
| 444 | 468 | 0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S |
| 445 | 469 | 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S |
| 446 | 470 | 0x1c, 0xff, 0x2f, 0xe1, // bx ip |
| 447 | 471 | }; |
| 448 | uint64_t S = getARMThunkDestVA(Destination); | |
| 449 | memcpy(Buf, Data, sizeof(Data)); | |
| 450 | Target->relocateOne(Buf, R_ARM_MOVW_ABS_NC, S); | |
| 451 | Target->relocateOne(Buf + 4, R_ARM_MOVT_ABS, S); | |
| 472 | uint64_t s = getARMThunkDestVA(destination); | |
| 473 | memcpy(buf, data, sizeof(data)); | |
| 474 | target->relocateOne(buf, R_ARM_MOVW_ABS_NC, s); | |
| 475 | target->relocateOne(buf + 4, R_ARM_MOVT_ABS, s); | |
| 452 | 476 | } |
| 453 | 477 | |
| 454 | void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) { | |
| 455 | addSymbol(Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()), | |
| 456 | STT_FUNC, 0, IS); | |
| 457 | addSymbol("$a", STT_NOTYPE, 0, IS); | |
| 478 | void ARMV7ABSLongThunk::addSymbols(ThunkSection &isec) { | |
| 479 | addSymbol(saver.save("__ARMv7ABSLongThunk_" + destination.getName()), | |
| 480 | STT_FUNC, 0, isec); | |
| 481 | addSymbol("$a", STT_NOTYPE, 0, isec); | |
| 458 | 482 | } |
| 459 | 483 | |
| 460 | void ThumbV7ABSLongThunk::writeLong(uint8_t *Buf) { | |
| 461 | const uint8_t Data[] = { | |
| 484 | void ThumbV7ABSLongThunk::writeLong(uint8_t *buf) { | |
| 485 | const uint8_t data[] = { | |
| 462 | 486 | 0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S |
| 463 | 487 | 0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S |
| 464 | 488 | 0x60, 0x47, // bx ip |
| 465 | 489 | }; |
| 466 | uint64_t S = getARMThunkDestVA(Destination); | |
| 467 | memcpy(Buf, Data, sizeof(Data)); | |
| 468 | Target->relocateOne(Buf, R_ARM_THM_MOVW_ABS_NC, S); | |
| 469 | Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_ABS, S); | |
| 490 | uint64_t s = getARMThunkDestVA(destination); | |
| 491 | memcpy(buf, data, sizeof(data)); | |
| 492 | target->relocateOne(buf, R_ARM_THM_MOVW_ABS_NC, s); | |
| 493 | target->relocateOne(buf + 4, R_ARM_THM_MOVT_ABS, s); | |
| 470 | 494 | } |
| 471 | 495 | |
| 472 | void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) { | |
| 473 | addSymbol(Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()), | |
| 474 | STT_FUNC, 1, IS); | |
| 475 | addSymbol("$t", STT_NOTYPE, 0, IS); | |
| 496 | void ThumbV7ABSLongThunk::addSymbols(ThunkSection &isec) { | |
| 497 | addSymbol(saver.save("__Thumbv7ABSLongThunk_" + destination.getName()), | |
| 498 | STT_FUNC, 1, isec); | |
| 499 | addSymbol("$t", STT_NOTYPE, 0, isec); | |
| 476 | 500 | } |
| 477 | 501 | |
| 478 | void ARMV7PILongThunk::writeLong(uint8_t *Buf) { | |
| 479 | const uint8_t Data[] = { | |
| 502 | void ARMV7PILongThunk::writeLong(uint8_t *buf) { | |
| 503 | const uint8_t data[] = { | |
| 480 | 504 | 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) + 8) |
| 481 | 505 | 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P) + 8) |
| 482 | 506 | 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc |
| 483 | 507 | 0x1c, 0xff, 0x2f, 0xe1, // bx ip |
| 484 | 508 | }; |
| 485 | uint64_t S = getARMThunkDestVA(Destination); | |
| 486 | uint64_t P = getThunkTargetSym()->getVA(); | |
| 487 | int64_t Offset = S - P - 16; | |
| 488 | memcpy(Buf, Data, sizeof(Data)); | |
| 489 | Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, Offset); | |
| 490 | Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, Offset); | |
| 509 | uint64_t s = getARMThunkDestVA(destination); | |
| 510 | uint64_t p = getThunkTargetSym()->getVA(); | |
| 511 | int64_t offset = s - p - 16; | |
| 512 | memcpy(buf, data, sizeof(data)); | |
| 513 | target->relocateOne(buf, R_ARM_MOVW_PREL_NC, offset); | |
| 514 | target->relocateOne(buf + 4, R_ARM_MOVT_PREL, offset); | |
| 491 | 515 | } |
| 492 | 516 | |
| 493 | void ARMV7PILongThunk::addSymbols(ThunkSection &IS) { | |
| 494 | addSymbol(Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC, | |
| 495 | 0, IS); | |
| 496 | addSymbol("$a", STT_NOTYPE, 0, IS); | |
| 517 | void ARMV7PILongThunk::addSymbols(ThunkSection &isec) { | |
| 518 | addSymbol(saver.save("__ARMV7PILongThunk_" + destination.getName()), STT_FUNC, | |
| 519 | 0, isec); | |
| 520 | addSymbol("$a", STT_NOTYPE, 0, isec); | |
| 497 | 521 | } |
| 498 | 522 | |
| 499 | void ThumbV7PILongThunk::writeLong(uint8_t *Buf) { | |
| 500 | const uint8_t Data[] = { | |
| 523 | void ThumbV7PILongThunk::writeLong(uint8_t *buf) { | |
| 524 | const uint8_t data[] = { | |
| 501 | 525 | 0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4) |
| 502 | 526 | 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4) |
| 503 | 527 | 0xfc, 0x44, // L1: add ip, pc |
| 504 | 528 | 0x60, 0x47, // bx ip |
| 505 | 529 | }; |
| 506 | uint64_t S = getARMThunkDestVA(Destination); | |
| 507 | uint64_t P = getThunkTargetSym()->getVA() & ~0x1; | |
| 508 | int64_t Offset = S - P - 12; | |
| 509 | memcpy(Buf, Data, sizeof(Data)); | |
| 510 | Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, Offset); | |
| 511 | Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, Offset); | |
| 530 | uint64_t s = getARMThunkDestVA(destination); | |
| 531 | uint64_t p = getThunkTargetSym()->getVA() & ~0x1; | |
| 532 | int64_t offset = s - p - 12; | |
| 533 | memcpy(buf, data, sizeof(data)); | |
| 534 | target->relocateOne(buf, R_ARM_THM_MOVW_PREL_NC, offset); | |
| 535 | target->relocateOne(buf + 4, R_ARM_THM_MOVT_PREL, offset); | |
| 512 | 536 | } |
| 513 | 537 | |
| 514 | void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) { | |
| 515 | addSymbol(Saver.save("__ThumbV7PILongThunk_" + Destination.getName()), | |
| 516 | STT_FUNC, 1, IS); | |
| 517 | addSymbol("$t", STT_NOTYPE, 0, IS); | |
| 538 | void ThumbV7PILongThunk::addSymbols(ThunkSection &isec) { | |
| 539 | addSymbol(saver.save("__ThumbV7PILongThunk_" + destination.getName()), | |
| 540 | STT_FUNC, 1, isec); | |
| 541 | addSymbol("$t", STT_NOTYPE, 0, isec); | |
| 518 | 542 | } |
| 519 | 543 | |
| 520 | void ARMV5ABSLongThunk::writeLong(uint8_t *Buf) { | |
| 521 | const uint8_t Data[] = { | |
| 544 | void ARMV5ABSLongThunk::writeLong(uint8_t *buf) { | |
| 545 | const uint8_t data[] = { | |
| 522 | 546 | 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1 |
| 523 | 547 | 0x00, 0x00, 0x00, 0x00, // L1: .word S |
| 524 | 548 | }; |
| 525 | memcpy(Buf, Data, sizeof(Data)); | |
| 526 | Target->relocateOne(Buf + 4, R_ARM_ABS32, getARMThunkDestVA(Destination)); | |
| 549 | memcpy(buf, data, sizeof(data)); | |
| 550 | target->relocateOne(buf + 4, R_ARM_ABS32, getARMThunkDestVA(destination)); | |
| 527 | 551 | } |
| 528 | 552 | |
| 529 | void ARMV5ABSLongThunk::addSymbols(ThunkSection &IS) { | |
| 530 | addSymbol(Saver.save("__ARMv5ABSLongThunk_" + Destination.getName()), | |
| 531 | STT_FUNC, 0, IS); | |
| 532 | addSymbol("$a", STT_NOTYPE, 0, IS); | |
| 533 | addSymbol("$d", STT_NOTYPE, 4, IS); | |
| 553 | void ARMV5ABSLongThunk::addSymbols(ThunkSection &isec) { | |
| 554 | addSymbol(saver.save("__ARMv5ABSLongThunk_" + destination.getName()), | |
| 555 | STT_FUNC, 0, isec); | |
| 556 | addSymbol("$a", STT_NOTYPE, 0, isec); | |
| 557 | addSymbol("$d", STT_NOTYPE, 4, isec); | |
| 534 | 558 | } |
| 535 | 559 | |
| 536 | bool ARMV5ABSLongThunk::isCompatibleWith(uint32_t RelocType) const { | |
| 560 | bool ARMV5ABSLongThunk::isCompatibleWith(const InputSection &isec, | |
| 561 | const Relocation &rel) const { | |
| 537 | 562 | // Thumb branch relocations can't use BLX |
| 538 | return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; | |
| 563 | return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24; | |
| 539 | 564 | } |
| 540 | 565 | |
| 541 | void ARMV5PILongThunk::writeLong(uint8_t *Buf) { | |
| 542 | const uint8_t Data[] = { | |
| 566 | void ARMV5PILongThunk::writeLong(uint8_t *buf) { | |
| 567 | const uint8_t data[] = { | |
| 543 | 568 | 0x04, 0xc0, 0x9f, 0xe5, // P: ldr ip, [pc,#4] ; L2 |
| 544 | 569 | 0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip |
| 545 | 570 | 0x1c, 0xff, 0x2f, 0xe1, // bx ip |
| 546 | 571 | 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8) |
| 547 | 572 | }; |
| 548 | uint64_t S = getARMThunkDestVA(Destination); | |
| 549 | uint64_t P = getThunkTargetSym()->getVA() & ~0x1; | |
| 550 | memcpy(Buf, Data, sizeof(Data)); | |
| 551 | Target->relocateOne(Buf + 12, R_ARM_REL32, S - P - 12); | |
| 573 | uint64_t s = getARMThunkDestVA(destination); | |
| 574 | uint64_t p = getThunkTargetSym()->getVA() & ~0x1; | |
| 575 | memcpy(buf, data, sizeof(data)); | |
| 576 | target->relocateOne(buf + 12, R_ARM_REL32, s - p - 12); | |
| 552 | 577 | } |
| 553 | 578 | |
| 554 | void ARMV5PILongThunk::addSymbols(ThunkSection &IS) { | |
| 555 | addSymbol(Saver.save("__ARMV5PILongThunk_" + Destination.getName()), STT_FUNC, | |
| 556 | 0, IS); | |
| 557 | addSymbol("$a", STT_NOTYPE, 0, IS); | |
| 558 | addSymbol("$d", STT_NOTYPE, 12, IS); | |
| 579 | void ARMV5PILongThunk::addSymbols(ThunkSection &isec) { | |
| 580 | addSymbol(saver.save("__ARMV5PILongThunk_" + destination.getName()), STT_FUNC, | |
| 581 | 0, isec); | |
| 582 | addSymbol("$a", STT_NOTYPE, 0, isec); | |
| 583 | addSymbol("$d", STT_NOTYPE, 12, isec); | |
| 559 | 584 | } |
| 560 | 585 | |
| 561 | bool ARMV5PILongThunk::isCompatibleWith(uint32_t RelocType) const { | |
| 586 | bool ARMV5PILongThunk::isCompatibleWith(const InputSection &isec, | |
| 587 | const Relocation &rel) const { | |
| 562 | 588 | // Thumb branch relocations can't use BLX |
| 563 | return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; | |
| 589 | return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24; | |
| 564 | 590 | } |
| 565 | 591 | |
| 566 | void ThumbV6MABSLongThunk::writeLong(uint8_t *Buf) { | |
| 592 | void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) { | |
| 567 | 593 | // Most Thumb instructions cannot access the high registers r8 - r15. As the |
| 568 | 594 | // only register we can corrupt is r12 we must instead spill a low register |
| 569 | 595 | // to the stack to use as a scratch register. We push r1 even though we |
| 570 | 596 | // don't need to get some space to use for the return address. |
| 571 | const uint8_t Data[] = { | |
| 597 | const uint8_t data[] = { | |
| 572 | 598 | 0x03, 0xb4, // push {r0, r1} ; Obtain scratch registers |
| 573 | 599 | 0x01, 0x48, // ldr r0, [pc, #4] ; L1 |
| 574 | 600 | 0x01, 0x90, // str r0, [sp, #4] ; SP + 4 = S |
| 575 | 601 | 0x01, 0xbd, // pop {r0, pc} ; restore r0 and branch to dest |
| 576 | 602 | 0x00, 0x00, 0x00, 0x00 // L1: .word S |
| 577 | 603 | }; |
| 578 | uint64_t S = getARMThunkDestVA(Destination); | |
| 579 | memcpy(Buf, Data, sizeof(Data)); | |
| 580 | Target->relocateOne(Buf + 8, R_ARM_ABS32, S); | |
| 604 | uint64_t s = getARMThunkDestVA(destination); | |
| 605 | memcpy(buf, data, sizeof(data)); | |
| 606 | target->relocateOne(buf + 8, R_ARM_ABS32, s); | |
| 581 | 607 | } |
| 582 | 608 | |
| 583 | void ThumbV6MABSLongThunk::addSymbols(ThunkSection &IS) { | |
| 584 | addSymbol(Saver.save("__Thumbv6MABSLongThunk_" + Destination.getName()), | |
| 585 | STT_FUNC, 1, IS); | |
| 586 | addSymbol("$t", STT_NOTYPE, 0, IS); | |
| 587 | addSymbol("$d", STT_NOTYPE, 8, IS); | |
| 609 | void ThumbV6MABSLongThunk::addSymbols(ThunkSection &isec) { | |
| 610 | addSymbol(saver.save("__Thumbv6MABSLongThunk_" + destination.getName()), | |
| 611 | STT_FUNC, 1, isec); | |
| 612 | addSymbol("$t", STT_NOTYPE, 0, isec); | |
| 613 | addSymbol("$d", STT_NOTYPE, 8, isec); | |
| 588 | 614 | } |
| 589 | 615 | |
| 590 | void ThumbV6MPILongThunk::writeLong(uint8_t *Buf) { | |
| 616 | void ThumbV6MPILongThunk::writeLong(uint8_t *buf) { | |
| 591 | 617 | // Most Thumb instructions cannot access the high registers r8 - r15. As the |
| 592 | 618 | // only register we can corrupt is ip (r12) we must instead spill a low |
| 593 | 619 | // register to the stack to use as a scratch register. |
| 594 | const uint8_t Data[] = { | |
| 620 | const uint8_t data[] = { | |
| 595 | 621 | 0x01, 0xb4, // P: push {r0} ; Obtain scratch register |
| 596 | 622 | 0x02, 0x48, // ldr r0, [pc, #8] ; L2 |
| 597 | 623 | 0x84, 0x46, // mov ip, r0 ; high to low register |
| ... | ... | @@ -600,131 +626,185 @@ void ThumbV6MPILongThunk::writeLong(uint8_t *Buf) { |
| 600 | 626 | 0xc0, 0x46, // nop ; pad to 4-byte boundary |
| 601 | 627 | 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 4) |
| 602 | 628 | }; |
| 603 | uint64_t S = getARMThunkDestVA(Destination); | |
| 604 | uint64_t P = getThunkTargetSym()->getVA() & ~0x1; | |
| 605 | memcpy(Buf, Data, sizeof(Data)); | |
| 606 | Target->relocateOne(Buf + 12, R_ARM_REL32, S - P - 12); | |
| 629 | uint64_t s = getARMThunkDestVA(destination); | |
| 630 | uint64_t p = getThunkTargetSym()->getVA() & ~0x1; | |
| 631 | memcpy(buf, data, sizeof(data)); | |
| 632 | target->relocateOne(buf + 12, R_ARM_REL32, s - p - 12); | |
| 607 | 633 | } |
| 608 | 634 | |
| 609 | void ThumbV6MPILongThunk::addSymbols(ThunkSection &IS) { | |
| 610 | addSymbol(Saver.save("__Thumbv6MPILongThunk_" + Destination.getName()), | |
| 611 | STT_FUNC, 1, IS); | |
| 612 | addSymbol("$t", STT_NOTYPE, 0, IS); | |
| 613 | addSymbol("$d", STT_NOTYPE, 12, IS); | |
| 635 | void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) { | |
| 636 | addSymbol(saver.save("__Thumbv6MPILongThunk_" + destination.getName()), | |
| 637 | STT_FUNC, 1, isec); | |
| 638 | addSymbol("$t", STT_NOTYPE, 0, isec); | |
| 639 | addSymbol("$d", STT_NOTYPE, 12, isec); | |
| 614 | 640 | } |
| 615 | 641 | |
| 616 | 642 | // Write MIPS LA25 thunk code to call PIC function from the non-PIC one. |
| 617 | void MipsThunk::writeTo(uint8_t *Buf) { | |
| 618 | uint64_t S = Destination.getVA(); | |
| 619 | write32(Buf, 0x3c190000); // lui $25, %hi(func) | |
| 620 | write32(Buf + 4, 0x08000000 | (S >> 2)); // j func | |
| 621 | write32(Buf + 8, 0x27390000); // addiu $25, $25, %lo(func) | |
| 622 | write32(Buf + 12, 0x00000000); // nop | |
| 623 | Target->relocateOne(Buf, R_MIPS_HI16, S); | |
| 624 | Target->relocateOne(Buf + 8, R_MIPS_LO16, S); | |
| 643 | void MipsThunk::writeTo(uint8_t *buf) { | |
| 644 | uint64_t s = destination.getVA(); | |
| 645 | write32(buf, 0x3c190000); // lui $25, %hi(func) | |
| 646 | write32(buf + 4, 0x08000000 | (s >> 2)); // j func | |
| 647 | write32(buf + 8, 0x27390000); // addiu $25, $25, %lo(func) | |
| 648 | write32(buf + 12, 0x00000000); // nop | |
| 649 | target->relocateOne(buf, R_MIPS_HI16, s); | |
| 650 | target->relocateOne(buf + 8, R_MIPS_LO16, s); | |
| 625 | 651 | } |
| 626 | 652 | |
| 627 | void MipsThunk::addSymbols(ThunkSection &IS) { | |
| 628 | addSymbol(Saver.save("__LA25Thunk_" + Destination.getName()), STT_FUNC, 0, | |
| 629 | IS); | |
| 653 | void MipsThunk::addSymbols(ThunkSection &isec) { | |
| 654 | addSymbol(saver.save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0, | |
| 655 | isec); | |
| 630 | 656 | } |
| 631 | 657 | |
| 632 | 658 | InputSection *MipsThunk::getTargetInputSection() const { |
| 633 | auto &DR = cast<Defined>(Destination); | |
| 634 | return dyn_cast<InputSection>(DR.Section); | |
| 659 | auto &dr = cast<Defined>(destination); | |
| 660 | return dyn_cast<InputSection>(dr.section); | |
| 635 | 661 | } |
| 636 | 662 | |
| 637 | 663 | // Write microMIPS R2-R5 LA25 thunk code |
| 638 | 664 | // to call PIC function from the non-PIC one. |
| 639 | void MicroMipsThunk::writeTo(uint8_t *Buf) { | |
| 640 | uint64_t S = Destination.getVA() | 1; | |
| 641 | write16(Buf, 0x41b9); // lui $25, %hi(func) | |
| 642 | write16(Buf + 4, 0xd400); // j func | |
| 643 | write16(Buf + 8, 0x3339); // addiu $25, $25, %lo(func) | |
| 644 | write16(Buf + 12, 0x0c00); // nop | |
| 645 | Target->relocateOne(Buf, R_MICROMIPS_HI16, S); | |
| 646 | Target->relocateOne(Buf + 4, R_MICROMIPS_26_S1, S); | |
| 647 | Target->relocateOne(Buf + 8, R_MICROMIPS_LO16, S); | |
| 665 | void MicroMipsThunk::writeTo(uint8_t *buf) { | |
| 666 | uint64_t s = destination.getVA(); | |
| 667 | write16(buf, 0x41b9); // lui $25, %hi(func) | |
| 668 | write16(buf + 4, 0xd400); // j func | |
| 669 | write16(buf + 8, 0x3339); // addiu $25, $25, %lo(func) | |
| 670 | write16(buf + 12, 0x0c00); // nop | |
| 671 | target->relocateOne(buf, R_MICROMIPS_HI16, s); | |
| 672 | target->relocateOne(buf + 4, R_MICROMIPS_26_S1, s); | |
| 673 | target->relocateOne(buf + 8, R_MICROMIPS_LO16, s); | |
| 648 | 674 | } |
| 649 | 675 | |
| 650 | void MicroMipsThunk::addSymbols(ThunkSection &IS) { | |
| 651 | Defined *D = addSymbol( | |
| 652 | Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS); | |
| 653 | D->StOther |= STO_MIPS_MICROMIPS; | |
| 676 | void MicroMipsThunk::addSymbols(ThunkSection &isec) { | |
| 677 | Defined *d = addSymbol( | |
| 678 | saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec); | |
| 679 | d->stOther |= STO_MIPS_MICROMIPS; | |
| 654 | 680 | } |
| 655 | 681 | |
| 656 | 682 | InputSection *MicroMipsThunk::getTargetInputSection() const { |
| 657 | auto &DR = cast<Defined>(Destination); | |
| 658 | return dyn_cast<InputSection>(DR.Section); | |
| 683 | auto &dr = cast<Defined>(destination); | |
| 684 | return dyn_cast<InputSection>(dr.section); | |
| 659 | 685 | } |
| 660 | 686 | |
| 661 | 687 | // Write microMIPS R6 LA25 thunk code |
| 662 | 688 | // to call PIC function from the non-PIC one. |
| 663 | void MicroMipsR6Thunk::writeTo(uint8_t *Buf) { | |
| 664 | uint64_t S = Destination.getVA() | 1; | |
| 665 | uint64_t P = getThunkTargetSym()->getVA(); | |
| 666 | write16(Buf, 0x1320); // lui $25, %hi(func) | |
| 667 | write16(Buf + 4, 0x3339); // addiu $25, $25, %lo(func) | |
| 668 | write16(Buf + 8, 0x9400); // bc func | |
| 669 | Target->relocateOne(Buf, R_MICROMIPS_HI16, S); | |
| 670 | Target->relocateOne(Buf + 4, R_MICROMIPS_LO16, S); | |
| 671 | Target->relocateOne(Buf + 8, R_MICROMIPS_PC26_S1, S - P - 12); | |
| 689 | void MicroMipsR6Thunk::writeTo(uint8_t *buf) { | |
| 690 | uint64_t s = destination.getVA(); | |
| 691 | uint64_t p = getThunkTargetSym()->getVA(); | |
| 692 | write16(buf, 0x1320); // lui $25, %hi(func) | |
| 693 | write16(buf + 4, 0x3339); // addiu $25, $25, %lo(func) | |
| 694 | write16(buf + 8, 0x9400); // bc func | |
| 695 | target->relocateOne(buf, R_MICROMIPS_HI16, s); | |
| 696 | target->relocateOne(buf + 4, R_MICROMIPS_LO16, s); | |
| 697 | target->relocateOne(buf + 8, R_MICROMIPS_PC26_S1, s - p - 12); | |
| 672 | 698 | } |
| 673 | 699 | |
| 674 | void MicroMipsR6Thunk::addSymbols(ThunkSection &IS) { | |
| 675 | Defined *D = addSymbol( | |
| 676 | Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS); | |
| 677 | D->StOther |= STO_MIPS_MICROMIPS; | |
| 700 | void MicroMipsR6Thunk::addSymbols(ThunkSection &isec) { | |
| 701 | Defined *d = addSymbol( | |
| 702 | saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec); | |
| 703 | d->stOther |= STO_MIPS_MICROMIPS; | |
| 678 | 704 | } |
| 679 | 705 | |
| 680 | 706 | InputSection *MicroMipsR6Thunk::getTargetInputSection() const { |
| 681 | auto &DR = cast<Defined>(Destination); | |
| 682 | return dyn_cast<InputSection>(DR.Section); | |
| 707 | auto &dr = cast<Defined>(destination); | |
| 708 | return dyn_cast<InputSection>(dr.section); | |
| 683 | 709 | } |
| 684 | 710 | |
| 685 | static void writePPCLoadAndBranch(uint8_t *Buf, int64_t Offset) { | |
| 686 | uint16_t OffHa = (Offset + 0x8000) >> 16; | |
| 687 | uint16_t OffLo = Offset & 0xffff; | |
| 711 | void PPC32PltCallStub::writeTo(uint8_t *buf) { | |
| 712 | if (!config->isPic) { | |
| 713 | uint64_t va = destination.getGotPltVA(); | |
| 714 | write32(buf + 0, 0x3d600000 | (va + 0x8000) >> 16); // lis r11,ha | |
| 715 | write32(buf + 4, 0x816b0000 | (uint16_t)va); // lwz r11,l(r11) | |
| 716 | write32(buf + 8, 0x7d6903a6); // mtctr r11 | |
| 717 | write32(buf + 12, 0x4e800420); // bctr | |
| 718 | return; | |
| 719 | } | |
| 720 | uint32_t offset; | |
| 721 | if (addend >= 0x8000) { | |
| 722 | // The stub loads an address relative to r30 (.got2+Addend). Addend is | |
| 723 | // almost always 0x8000. The address of .got2 is different in another object | |
| 724 | // file, so a stub cannot be shared. | |
| 725 | offset = destination.getGotPltVA() - (in.ppc32Got2->getParent()->getVA() + | |
| 726 | file->ppc32Got2OutSecOff + addend); | |
| 727 | } else { | |
| 728 | // The stub loads an address relative to _GLOBAL_OFFSET_TABLE_ (which is | |
| 729 | // currently the address of .got). | |
| 730 | offset = destination.getGotPltVA() - in.got->getVA(); | |
| 731 | } | |
| 732 | uint16_t ha = (offset + 0x8000) >> 16, l = (uint16_t)offset; | |
| 733 | if (ha == 0) { | |
| 734 | write32(buf + 0, 0x817e0000 | l); // lwz r11,l(r30) | |
| 735 | write32(buf + 4, 0x7d6903a6); // mtctr r11 | |
| 736 | write32(buf + 8, 0x4e800420); // bctr | |
| 737 | write32(buf + 12, 0x60000000); // nop | |
| 738 | } else { | |
| 739 | write32(buf + 0, 0x3d7e0000 | ha); // addis r11,r30,ha | |
| 740 | write32(buf + 4, 0x816b0000 | l); // lwz r11,l(r11) | |
| 741 | write32(buf + 8, 0x7d6903a6); // mtctr r11 | |
| 742 | write32(buf + 12, 0x4e800420); // bctr | |
| 743 | } | |
| 744 | } | |
| 745 | ||
| 746 | void PPC32PltCallStub::addSymbols(ThunkSection &isec) { | |
| 747 | std::string buf; | |
| 748 | raw_string_ostream os(buf); | |
| 749 | os << format_hex_no_prefix(addend, 8); | |
| 750 | if (!config->isPic) | |
| 751 | os << ".plt_call32."; | |
| 752 | else if (addend >= 0x8000) | |
| 753 | os << ".got2.plt_pic32."; | |
| 754 | else | |
| 755 | os << ".plt_pic32."; | |
| 756 | os << destination.getName(); | |
| 757 | addSymbol(saver.save(os.str()), STT_FUNC, 0, isec); | |
| 758 | } | |
| 759 | ||
| 760 | bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec, | |
| 761 | const Relocation &rel) const { | |
| 762 | return !config->isPic || (isec.file == file && rel.addend == addend); | |
| 763 | } | |
| 688 | 764 | |
| 689 | write32(Buf + 0, 0x3d820000 | OffHa); // addis r12, r2, OffHa | |
| 690 | write32(Buf + 4, 0xe98c0000 | OffLo); // ld r12, OffLo(r12) | |
| 691 | write32(Buf + 8, 0x7d8903a6); // mtctr r12 | |
| 692 | write32(Buf + 12, 0x4e800420); // bctr | |
| 765 | static void writePPCLoadAndBranch(uint8_t *buf, int64_t offset) { | |
| 766 | uint16_t offHa = (offset + 0x8000) >> 16; | |
| 767 | uint16_t offLo = offset & 0xffff; | |
| 768 | ||
| 769 | write32(buf + 0, 0x3d820000 | offHa); // addis r12, r2, OffHa | |
| 770 | write32(buf + 4, 0xe98c0000 | offLo); // ld r12, OffLo(r12) | |
| 771 | write32(buf + 8, 0x7d8903a6); // mtctr r12 | |
| 772 | write32(buf + 12, 0x4e800420); // bctr | |
| 693 | 773 | } |
| 694 | 774 | |
| 695 | void PPC64PltCallStub::writeTo(uint8_t *Buf) { | |
| 696 | int64_t Offset = Destination.getGotPltVA() - getPPC64TocBase(); | |
| 775 | void PPC64PltCallStub::writeTo(uint8_t *buf) { | |
| 776 | int64_t offset = destination.getGotPltVA() - getPPC64TocBase(); | |
| 697 | 777 | // Save the TOC pointer to the save-slot reserved in the call frame. |
| 698 | write32(Buf + 0, 0xf8410018); // std r2,24(r1) | |
| 699 | writePPCLoadAndBranch(Buf + 4, Offset); | |
| 778 | write32(buf + 0, 0xf8410018); // std r2,24(r1) | |
| 779 | writePPCLoadAndBranch(buf + 4, offset); | |
| 700 | 780 | } |
| 701 | 781 | |
| 702 | void PPC64PltCallStub::addSymbols(ThunkSection &IS) { | |
| 703 | Defined *S = addSymbol(Saver.save("__plt_" + Destination.getName()), STT_FUNC, | |
| 704 | 0, IS); | |
| 705 | S->NeedsTocRestore = true; | |
| 782 | void PPC64PltCallStub::addSymbols(ThunkSection &isec) { | |
| 783 | Defined *s = addSymbol(saver.save("__plt_" + destination.getName()), STT_FUNC, | |
| 784 | 0, isec); | |
| 785 | s->needsTocRestore = true; | |
| 706 | 786 | } |
| 707 | 787 | |
| 708 | void PPC64LongBranchThunk::writeTo(uint8_t *Buf) { | |
| 709 | int64_t Offset = Destination.getPPC64LongBranchTableVA() - getPPC64TocBase(); | |
| 710 | writePPCLoadAndBranch(Buf, Offset); | |
| 788 | void PPC64LongBranchThunk::writeTo(uint8_t *buf) { | |
| 789 | int64_t offset = destination.getPPC64LongBranchTableVA() - getPPC64TocBase(); | |
| 790 | writePPCLoadAndBranch(buf, offset); | |
| 711 | 791 | } |
| 712 | 792 | |
| 713 | void PPC64LongBranchThunk::addSymbols(ThunkSection &IS) { | |
| 714 | addSymbol(Saver.save("__long_branch_" + Destination.getName()), STT_FUNC, 0, | |
| 715 | IS); | |
| 793 | void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) { | |
| 794 | addSymbol(saver.save("__long_branch_" + destination.getName()), STT_FUNC, 0, | |
| 795 | isec); | |
| 716 | 796 | } |
| 717 | 797 | |
| 718 | Thunk::Thunk(Symbol &D) : Destination(D), Offset(0) {} | |
| 798 | Thunk::Thunk(Symbol &d) : destination(d), offset(0) {} | |
| 719 | 799 | |
| 720 | 800 | Thunk::~Thunk() = default; |
| 721 | 801 | |
| 722 | static Thunk *addThunkAArch64(RelType Type, Symbol &S) { | |
| 723 | if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26) | |
| 802 | static Thunk *addThunkAArch64(RelType type, Symbol &s) { | |
| 803 | if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26) | |
| 724 | 804 | fatal("unrecognized relocation type"); |
| 725 | if (Config->PicThunk) | |
| 726 | return make<AArch64ADRPThunk>(S); | |
| 727 | return make<AArch64ABSLongThunk>(S); | |
| 805 | if (config->picThunk) | |
| 806 | return make<AArch64ADRPThunk>(s); | |
| 807 | return make<AArch64ABSLongThunk>(s); | |
| 728 | 808 | } |
| 729 | 809 | |
| 730 | 810 | // Creates a thunk for Thumb-ARM interworking. |
| ... | ... | @@ -732,18 +812,18 @@ static Thunk *addThunkAArch64(RelType Type, Symbol &S) { |
| 732 | 812 | // - MOVT and MOVW instructions cannot be used |
| 733 | 813 | // - Only Thumb relocation that can generate a Thunk is a BL, this can always |
| 734 | 814 | // be transformed into a BLX |
| 735 | static Thunk *addThunkPreArmv7(RelType Reloc, Symbol &S) { | |
| 736 | switch (Reloc) { | |
| 815 | static Thunk *addThunkPreArmv7(RelType reloc, Symbol &s) { | |
| 816 | switch (reloc) { | |
| 737 | 817 | case R_ARM_PC24: |
| 738 | 818 | case R_ARM_PLT32: |
| 739 | 819 | case R_ARM_JUMP24: |
| 740 | 820 | case R_ARM_CALL: |
| 741 | 821 | case R_ARM_THM_CALL: |
| 742 | if (Config->PicThunk) | |
| 743 | return make<ARMV5PILongThunk>(S); | |
| 744 | return make<ARMV5ABSLongThunk>(S); | |
| 822 | if (config->picThunk) | |
| 823 | return make<ARMV5PILongThunk>(s); | |
| 824 | return make<ARMV5ABSLongThunk>(s); | |
| 745 | 825 | } |
| 746 | fatal("relocation " + toString(Reloc) + " to " + toString(S) + | |
| 826 | fatal("relocation " + toString(reloc) + " to " + toString(s) + | |
| 747 | 827 | " not supported for Armv5 or Armv6 targets"); |
| 748 | 828 | } |
| 749 | 829 | |
| ... | ... | @@ -752,21 +832,21 @@ static Thunk *addThunkPreArmv7(RelType Reloc, Symbol &S) { |
| 752 | 832 | // - MOVT and MOVW instructions cannot be used. |
| 753 | 833 | // - Only a limited number of instructions can access registers r8 and above |
| 754 | 834 | // - No interworking support is needed (all Thumb). |
| 755 | static Thunk *addThunkV6M(RelType Reloc, Symbol &S) { | |
| 756 | switch (Reloc) { | |
| 835 | static Thunk *addThunkV6M(RelType reloc, Symbol &s) { | |
| 836 | switch (reloc) { | |
| 757 | 837 | case R_ARM_THM_JUMP19: |
| 758 | 838 | case R_ARM_THM_JUMP24: |
| 759 | 839 | case R_ARM_THM_CALL: |
| 760 | if (Config->Pic) | |
| 761 | return make<ThumbV6MPILongThunk>(S); | |
| 762 | return make<ThumbV6MABSLongThunk>(S); | |
| 840 | if (config->isPic) | |
| 841 | return make<ThumbV6MPILongThunk>(s); | |
| 842 | return make<ThumbV6MABSLongThunk>(s); | |
| 763 | 843 | } |
| 764 | fatal("relocation " + toString(Reloc) + " to " + toString(S) + | |
| 844 | fatal("relocation " + toString(reloc) + " to " + toString(s) + | |
| 765 | 845 | " not supported for Armv6-M targets"); |
| 766 | 846 | } |
| 767 | 847 | |
| 768 | 848 | // Creates a thunk for Thumb-ARM interworking or branch range extension. |
| 769 | static Thunk *addThunkArm(RelType Reloc, Symbol &S) { | |
| 849 | static Thunk *addThunkArm(RelType reloc, Symbol &s) { | |
| 770 | 850 | // Decide which Thunk is needed based on: |
| 771 | 851 | // Available instruction set |
| 772 | 852 | // - An Arm Thunk can only be used if Arm state is available. |
| ... | ... | @@ -783,61 +863,72 @@ static Thunk *addThunkArm(RelType Reloc, Symbol &S) { |
| 783 | 863 | // can use in Thunks. The flags below are set by reading the BuildAttributes |
| 784 | 864 | // of the input objects. InputFiles.cpp contains the mapping from ARM |
| 785 | 865 | // architecture to flag. |
| 786 | if (!Config->ARMHasMovtMovw) { | |
| 787 | if (!Config->ARMJ1J2BranchEncoding) | |
| 788 | return addThunkPreArmv7(Reloc, S); | |
| 789 | return addThunkV6M(Reloc, S); | |
| 866 | if (!config->armHasMovtMovw) { | |
| 867 | if (!config->armJ1J2BranchEncoding) | |
| 868 | return addThunkPreArmv7(reloc, s); | |
| 869 | return addThunkV6M(reloc, s); | |
| 790 | 870 | } |
| 791 | 871 | |
| 792 | switch (Reloc) { | |
| 872 | switch (reloc) { | |
| 793 | 873 | case R_ARM_PC24: |
| 794 | 874 | case R_ARM_PLT32: |
| 795 | 875 | case R_ARM_JUMP24: |
| 796 | 876 | case R_ARM_CALL: |
| 797 | if (Config->PicThunk) | |
| 798 | return make<ARMV7PILongThunk>(S); | |
| 799 | return make<ARMV7ABSLongThunk>(S); | |
| 877 | if (config->picThunk) | |
| 878 | return make<ARMV7PILongThunk>(s); | |
| 879 | return make<ARMV7ABSLongThunk>(s); | |
| 800 | 880 | case R_ARM_THM_JUMP19: |
| 801 | 881 | case R_ARM_THM_JUMP24: |
| 802 | 882 | case R_ARM_THM_CALL: |
| 803 | if (Config->PicThunk) | |
| 804 | return make<ThumbV7PILongThunk>(S); | |
| 805 | return make<ThumbV7ABSLongThunk>(S); | |
| 883 | if (config->picThunk) | |
| 884 | return make<ThumbV7PILongThunk>(s); | |
| 885 | return make<ThumbV7ABSLongThunk>(s); | |
| 806 | 886 | } |
| 807 | 887 | fatal("unrecognized relocation type"); |
| 808 | 888 | } |
| 809 | 889 | |
| 810 | static Thunk *addThunkMips(RelType Type, Symbol &S) { | |
| 811 | if ((S.StOther & STO_MIPS_MICROMIPS) && isMipsR6()) | |
| 812 | return make<MicroMipsR6Thunk>(S); | |
| 813 | if (S.StOther & STO_MIPS_MICROMIPS) | |
| 814 | return make<MicroMipsThunk>(S); | |
| 815 | return make<MipsThunk>(S); | |
| 890 | static Thunk *addThunkMips(RelType type, Symbol &s) { | |
| 891 | if ((s.stOther & STO_MIPS_MICROMIPS) && isMipsR6()) | |
| 892 | return make<MicroMipsR6Thunk>(s); | |
| 893 | if (s.stOther & STO_MIPS_MICROMIPS) | |
| 894 | return make<MicroMipsThunk>(s); | |
| 895 | return make<MipsThunk>(s); | |
| 896 | } | |
| 897 | ||
| 898 | static Thunk *addThunkPPC32(const InputSection &isec, const Relocation &rel, Symbol &s) { | |
| 899 | assert((rel.type == R_PPC_REL24 || rel.type == R_PPC_PLTREL24) && | |
| 900 | "unexpected relocation type for thunk"); | |
| 901 | return make<PPC32PltCallStub>(isec, rel, s); | |
| 816 | 902 | } |
| 817 | 903 | |
| 818 | static Thunk *addThunkPPC64(RelType Type, Symbol &S) { | |
| 819 | assert(Type == R_PPC64_REL24 && "unexpected relocation type for thunk"); | |
| 820 | if (S.isInPlt()) | |
| 821 | return make<PPC64PltCallStub>(S); | |
| 904 | static Thunk *addThunkPPC64(RelType type, Symbol &s) { | |
| 905 | assert(type == R_PPC64_REL24 && "unexpected relocation type for thunk"); | |
| 906 | if (s.isInPlt()) | |
| 907 | return make<PPC64PltCallStub>(s); | |
| 822 | 908 | |
| 823 | if (Config->PicThunk) | |
| 824 | return make<PPC64PILongBranchThunk>(S); | |
| 909 | if (config->picThunk) | |
| 910 | return make<PPC64PILongBranchThunk>(s); | |
| 825 | 911 | |
| 826 | return make<PPC64PDLongBranchThunk>(S); | |
| 912 | return make<PPC64PDLongBranchThunk>(s); | |
| 827 | 913 | } |
| 828 | 914 | |
| 829 | Thunk *addThunk(RelType Type, Symbol &S) { | |
| 830 | if (Config->EMachine == EM_AARCH64) | |
| 831 | return addThunkAArch64(Type, S); | |
| 915 | Thunk *addThunk(const InputSection &isec, Relocation &rel) { | |
| 916 | Symbol &s = *rel.sym; | |
| 917 | ||
| 918 | if (config->emachine == EM_AARCH64) | |
| 919 | return addThunkAArch64(rel.type, s); | |
| 920 | ||
| 921 | if (config->emachine == EM_ARM) | |
| 922 | return addThunkArm(rel.type, s); | |
| 832 | 923 | |
| 833 | if (Config->EMachine == EM_ARM) | |
| 834 | return addThunkArm(Type, S); | |
| 924 | if (config->emachine == EM_MIPS) | |
| 925 | return addThunkMips(rel.type, s); | |
| 835 | 926 | |
| 836 | if (Config->EMachine == EM_MIPS) | |
| 837 | return addThunkMips(Type, S); | |
| 927 | if (config->emachine == EM_PPC) | |
| 928 | return addThunkPPC32(isec, rel, s); | |
| 838 | 929 | |
| 839 | if (Config->EMachine == EM_PPC64) | |
| 840 | return addThunkPPC64(Type, S); | |
| 930 | if (config->emachine == EM_PPC64) | |
| 931 | return addThunkPPC64(rel.type, s); | |
| 841 | 932 | |
| 842 | 933 | llvm_unreachable("add Thunk only supported for ARM, Mips and PowerPC"); |
| 843 | 934 | } |
deps/lld/ELF/Thunks.h+22-20| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Thunks.h --------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -28,42 +27,45 @@ class ThunkSection; |
| 28 | 27 | // Thunks are assigned to synthetic ThunkSections |
| 29 | 28 | class Thunk { |
| 30 | 29 | public: |
| 31 | Thunk(Symbol &Destination); | |
| 30 | Thunk(Symbol &destination); | |
| 32 | 31 | virtual ~Thunk(); |
| 33 | 32 | |
| 34 | 33 | virtual uint32_t size() = 0; |
| 35 | virtual void writeTo(uint8_t *Buf) = 0; | |
| 34 | virtual void writeTo(uint8_t *buf) = 0; | |
| 36 | 35 | |
| 37 | 36 | // All Thunks must define at least one symbol, known as the thunk target |
| 38 | 37 | // symbol, so that we can redirect relocations to it. The thunk may define |
| 39 | 38 | // additional symbols, but these are never targets for relocations. |
| 40 | virtual void addSymbols(ThunkSection &IS) = 0; | |
| 39 | virtual void addSymbols(ThunkSection &isec) = 0; | |
| 41 | 40 | |
| 42 | void setOffset(uint64_t Offset); | |
| 43 | Defined *addSymbol(StringRef Name, uint8_t Type, uint64_t Value, | |
| 44 | InputSectionBase &Section); | |
| 41 | void setOffset(uint64_t offset); | |
| 42 | Defined *addSymbol(StringRef name, uint8_t type, uint64_t value, | |
| 43 | InputSectionBase &section); | |
| 45 | 44 | |
| 46 | 45 | // Some Thunks must be placed immediately before their Target as they elide |
| 47 | 46 | // a branch and fall through to the first Symbol in the Target. |
| 48 | 47 | virtual InputSection *getTargetInputSection() const { return nullptr; } |
| 49 | 48 | |
| 50 | // To reuse a Thunk the caller as identified by the Type must be | |
| 51 | // compatible with it. | |
| 52 | virtual bool isCompatibleWith(RelType Type) const { return true; } | |
| 49 | // To reuse a Thunk the InputSection and the relocation must be compatible | |
| 50 | // with it. | |
| 51 | virtual bool isCompatibleWith(const InputSection &, | |
| 52 | const Relocation &) const { | |
| 53 | return true; | |
| 54 | } | |
| 53 | 55 | |
| 54 | Defined *getThunkTargetSym() const { return Syms[0]; } | |
| 56 | Defined *getThunkTargetSym() const { return syms[0]; } | |
| 55 | 57 | |
| 56 | 58 | // The alignment requirement for this Thunk, defaults to the size of the |
| 57 | 59 | // typical code section alignment. |
| 58 | Symbol &Destination; | |
| 59 | llvm::SmallVector<Defined *, 3> Syms; | |
| 60 | uint64_t Offset = 0; | |
| 61 | uint32_t Alignment = 4; | |
| 60 | Symbol &destination; | |
| 61 | llvm::SmallVector<Defined *, 3> syms; | |
| 62 | uint64_t offset = 0; | |
| 63 | uint32_t alignment = 4; | |
| 62 | 64 | }; |
| 63 | 65 | |
| 64 | 66 | // For a Relocation to symbol S create a Thunk to be added to a synthetic |
| 65 | // ThunkSection. At present there are implementations for ARM and Mips Thunks. | |
| 66 | Thunk *addThunk(RelType Type, Symbol &S); | |
| 67 | // ThunkSection. | |
| 68 | Thunk *addThunk(const InputSection &isec, Relocation &rel); | |
| 67 | 69 | |
| 68 | 70 | } // namespace elf |
| 69 | 71 | } // namespace lld |
deps/lld/ELF/Writer.cpp+1415-1253| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Writer.cpp ---------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -11,7 +10,6 @@ |
| 11 | 10 | #include "AArch64ErrataFix.h" |
| 12 | 11 | #include "CallGraphSort.h" |
| 13 | 12 | #include "Config.h" |
| 14 | #include "Filesystem.h" | |
| 15 | 13 | #include "LinkerScript.h" |
| 16 | 14 | #include "MapFile.h" |
| 17 | 15 | #include "OutputSections.h" |
| ... | ... | @@ -20,11 +18,15 @@ |
| 20 | 18 | #include "Symbols.h" |
| 21 | 19 | #include "SyntheticSections.h" |
| 22 | 20 | #include "Target.h" |
| 21 | #include "lld/Common/Filesystem.h" | |
| 23 | 22 | #include "lld/Common/Memory.h" |
| 24 | 23 | #include "lld/Common/Strings.h" |
| 25 | 24 | #include "lld/Common/Threads.h" |
| 26 | 25 | #include "llvm/ADT/StringMap.h" |
| 27 | 26 | #include "llvm/ADT/StringSwitch.h" |
| 27 | #include "llvm/Support/RandomNumberGenerator.h" | |
| 28 | #include "llvm/Support/SHA1.h" | |
| 29 | #include "llvm/Support/xxhash.h" | |
| 28 | 30 | #include <climits> |
| 29 | 31 | |
| 30 | 32 | using namespace llvm; |
| ... | ... | @@ -40,31 +42,32 @@ namespace { |
| 40 | 42 | // The writer writes a SymbolTable result to a file. |
| 41 | 43 | template <class ELFT> class Writer { |
| 42 | 44 | public: |
| 43 | Writer() : Buffer(errorHandler().OutputBuffer) {} | |
| 44 | typedef typename ELFT::Shdr Elf_Shdr; | |
| 45 | typedef typename ELFT::Ehdr Elf_Ehdr; | |
| 46 | typedef typename ELFT::Phdr Elf_Phdr; | |
| 45 | Writer() : buffer(errorHandler().outputBuffer) {} | |
| 46 | using Elf_Shdr = typename ELFT::Shdr; | |
| 47 | using Elf_Ehdr = typename ELFT::Ehdr; | |
| 48 | using Elf_Phdr = typename ELFT::Phdr; | |
| 47 | 49 | |
| 48 | 50 | void run(); |
| 49 | 51 | |
| 50 | 52 | private: |
| 51 | 53 | void copyLocalSymbols(); |
| 52 | 54 | void addSectionSymbols(); |
| 53 | void forEachRelSec(llvm::function_ref<void(InputSectionBase &)> Fn); | |
| 55 | void forEachRelSec(llvm::function_ref<void(InputSectionBase &)> fn); | |
| 54 | 56 | void sortSections(); |
| 55 | 57 | void resolveShfLinkOrder(); |
| 56 | void maybeAddThunks(); | |
| 58 | void finalizeAddressDependentContent(); | |
| 57 | 59 | void sortInputSections(); |
| 58 | 60 | void finalizeSections(); |
| 59 | 61 | void checkExecuteOnly(); |
| 60 | 62 | void setReservedSymbolSections(); |
| 61 | 63 | |
| 62 | std::vector<PhdrEntry *> createPhdrs(); | |
| 63 | void removeEmptyPTLoad(); | |
| 64 | void addPtArmExid(std::vector<PhdrEntry *> &Phdrs); | |
| 64 | std::vector<PhdrEntry *> createPhdrs(Partition &part); | |
| 65 | void removeEmptyPTLoad(std::vector<PhdrEntry *> &phdrEntry); | |
| 66 | void addPhdrForSection(Partition &part, unsigned shType, unsigned pType, | |
| 67 | unsigned pFlags); | |
| 65 | 68 | void assignFileOffsets(); |
| 66 | 69 | void assignFileOffsetsBinary(); |
| 67 | void setPhdrs(); | |
| 70 | void setPhdrs(Partition &part); | |
| 68 | 71 | void checkSections(); |
| 69 | 72 | void fixSectionAlignments(); |
| 70 | 73 | void openFile(); |
| ... | ... | @@ -74,36 +77,34 @@ private: |
| 74 | 77 | void writeSectionsBinary(); |
| 75 | 78 | void writeBuildId(); |
| 76 | 79 | |
| 77 | std::unique_ptr<FileOutputBuffer> &Buffer; | |
| 80 | std::unique_ptr<FileOutputBuffer> &buffer; | |
| 78 | 81 | |
| 79 | 82 | void addRelIpltSymbols(); |
| 80 | 83 | void addStartEndSymbols(); |
| 81 | void addStartStopSymbols(OutputSection *Sec); | |
| 82 | ||
| 83 | std::vector<PhdrEntry *> Phdrs; | |
| 84 | void addStartStopSymbols(OutputSection *sec); | |
| 84 | 85 | |
| 85 | uint64_t FileSize; | |
| 86 | uint64_t SectionHeaderOff; | |
| 86 | uint64_t fileSize; | |
| 87 | uint64_t sectionHeaderOff; | |
| 87 | 88 | }; |
| 88 | 89 | } // anonymous namespace |
| 89 | 90 | |
| 90 | static bool isSectionPrefix(StringRef Prefix, StringRef Name) { | |
| 91 | return Name.startswith(Prefix) || Name == Prefix.drop_back(); | |
| 91 | static bool isSectionPrefix(StringRef prefix, StringRef name) { | |
| 92 | return name.startswith(prefix) || name == prefix.drop_back(); | |
| 92 | 93 | } |
| 93 | 94 | |
| 94 | StringRef elf::getOutputSectionName(const InputSectionBase *S) { | |
| 95 | if (Config->Relocatable) | |
| 96 | return S->Name; | |
| 95 | StringRef elf::getOutputSectionName(const InputSectionBase *s) { | |
| 96 | if (config->relocatable) | |
| 97 | return s->name; | |
| 97 | 98 | |
| 98 | 99 | // This is for --emit-relocs. If .text.foo is emitted as .text.bar, we want |
| 99 | 100 | // to emit .rela.text.foo as .rela.text.bar for consistency (this is not |
| 100 | 101 | // technically required, but not doing it is odd). This code guarantees that. |
| 101 | if (auto *IS = dyn_cast<InputSection>(S)) { | |
| 102 | if (InputSectionBase *Rel = IS->getRelocatedSection()) { | |
| 103 | OutputSection *Out = Rel->getOutputSection(); | |
| 104 | if (S->Type == SHT_RELA) | |
| 105 | return Saver.save(".rela" + Out->Name); | |
| 106 | return Saver.save(".rel" + Out->Name); | |
| 102 | if (auto *isec = dyn_cast<InputSection>(s)) { | |
| 103 | if (InputSectionBase *rel = isec->getRelocatedSection()) { | |
| 104 | OutputSection *out = rel->getOutputSection(); | |
| 105 | if (s->type == SHT_RELA) | |
| 106 | return saver.save(".rela" + out->name); | |
| 107 | return saver.save(".rel" + out->name); | |
| 107 | 108 | } |
| 108 | 109 | } |
| 109 | 110 | |
| ... | ... | @@ -113,97 +114,133 @@ StringRef elf::getOutputSectionName(const InputSectionBase *S) { |
| 113 | 114 | // When enabled, this allows identifying the hot code region (.text.hot) in |
| 114 | 115 | // the final binary which can be selectively mapped to huge pages or mlocked, |
| 115 | 116 | // for instance. |
| 116 | if (Config->ZKeepTextSectionPrefix) | |
| 117 | for (StringRef V : | |
| 117 | if (config->zKeepTextSectionPrefix) | |
| 118 | for (StringRef v : | |
| 118 | 119 | {".text.hot.", ".text.unlikely.", ".text.startup.", ".text.exit."}) |
| 119 | if (isSectionPrefix(V, S->Name)) | |
| 120 | return V.drop_back(); | |
| 120 | if (isSectionPrefix(v, s->name)) | |
| 121 | return v.drop_back(); | |
| 121 | 122 | |
| 122 | for (StringRef V : | |
| 123 | for (StringRef v : | |
| 123 | 124 | {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.", |
| 124 | 125 | ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", |
| 125 | 126 | ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."}) |
| 126 | if (isSectionPrefix(V, S->Name)) | |
| 127 | return V.drop_back(); | |
| 127 | if (isSectionPrefix(v, s->name)) | |
| 128 | return v.drop_back(); | |
| 128 | 129 | |
| 129 | 130 | // CommonSection is identified as "COMMON" in linker scripts. |
| 130 | 131 | // By default, it should go to .bss section. |
| 131 | if (S->Name == "COMMON") | |
| 132 | if (s->name == "COMMON") | |
| 132 | 133 | return ".bss"; |
| 133 | 134 | |
| 134 | return S->Name; | |
| 135 | return s->name; | |
| 135 | 136 | } |
| 136 | 137 | |
| 137 | 138 | static bool needsInterpSection() { |
| 138 | return !SharedFiles.empty() && !Config->DynamicLinker.empty() && | |
| 139 | Script->needsInterpSection(); | |
| 139 | return !sharedFiles.empty() && !config->dynamicLinker.empty() && | |
| 140 | script->needsInterpSection(); | |
| 140 | 141 | } |
| 141 | 142 | |
| 142 | 143 | template <class ELFT> void elf::writeResult() { Writer<ELFT>().run(); } |
| 143 | 144 | |
| 144 | template <class ELFT> void Writer<ELFT>::removeEmptyPTLoad() { | |
| 145 | llvm::erase_if(Phdrs, [&](const PhdrEntry *P) { | |
| 146 | if (P->p_type != PT_LOAD) | |
| 145 | template <class ELFT> | |
| 146 | void Writer<ELFT>::removeEmptyPTLoad(std::vector<PhdrEntry *> &phdrs) { | |
| 147 | llvm::erase_if(phdrs, [&](const PhdrEntry *p) { | |
| 148 | if (p->p_type != PT_LOAD) | |
| 147 | 149 | return false; |
| 148 | if (!P->FirstSec) | |
| 150 | if (!p->firstSec) | |
| 149 | 151 | return true; |
| 150 | uint64_t Size = P->LastSec->Addr + P->LastSec->Size - P->FirstSec->Addr; | |
| 151 | return Size == 0; | |
| 152 | uint64_t size = p->lastSec->addr + p->lastSec->size - p->firstSec->addr; | |
| 153 | return size == 0; | |
| 152 | 154 | }); |
| 153 | 155 | } |
| 154 | 156 | |
| 155 | template <class ELFT> static void combineEhFrameSections() { | |
| 156 | for (InputSectionBase *&S : InputSections) { | |
| 157 | EhInputSection *ES = dyn_cast<EhInputSection>(S); | |
| 158 | if (!ES || !ES->Live) | |
| 157 | template <class ELFT> static void copySectionsIntoPartitions() { | |
| 158 | std::vector<InputSectionBase *> newSections; | |
| 159 | for (unsigned part = 2; part != partitions.size() + 1; ++part) { | |
| 160 | for (InputSectionBase *s : inputSections) { | |
| 161 | if (!(s->flags & SHF_ALLOC) || !s->isLive()) | |
| 162 | continue; | |
| 163 | InputSectionBase *copy; | |
| 164 | if (s->type == SHT_NOTE) | |
| 165 | copy = make<InputSection>(cast<InputSection>(*s)); | |
| 166 | else if (auto *es = dyn_cast<EhInputSection>(s)) | |
| 167 | copy = make<EhInputSection>(*es); | |
| 168 | else | |
| 169 | continue; | |
| 170 | copy->partition = part; | |
| 171 | newSections.push_back(copy); | |
| 172 | } | |
| 173 | } | |
| 174 | ||
| 175 | inputSections.insert(inputSections.end(), newSections.begin(), | |
| 176 | newSections.end()); | |
| 177 | } | |
| 178 | ||
| 179 | template <class ELFT> static void combineEhSections() { | |
| 180 | for (InputSectionBase *&s : inputSections) { | |
| 181 | // Ignore dead sections and the partition end marker (.part.end), | |
| 182 | // whose partition number is out of bounds. | |
| 183 | if (!s->isLive() || s->partition == 255) | |
| 159 | 184 | continue; |
| 160 | 185 | |
| 161 | In.EhFrame->addSection<ELFT>(ES); | |
| 162 | S = nullptr; | |
| 186 | Partition &part = s->getPartition(); | |
| 187 | if (auto *es = dyn_cast<EhInputSection>(s)) { | |
| 188 | part.ehFrame->addSection<ELFT>(es); | |
| 189 | s = nullptr; | |
| 190 | } else if (s->kind() == SectionBase::Regular && part.armExidx && | |
| 191 | part.armExidx->addSection(cast<InputSection>(s))) { | |
| 192 | s = nullptr; | |
| 193 | } | |
| 163 | 194 | } |
| 164 | 195 | |
| 165 | std::vector<InputSectionBase *> &V = InputSections; | |
| 166 | V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); | |
| 196 | std::vector<InputSectionBase *> &v = inputSections; | |
| 197 | v.erase(std::remove(v.begin(), v.end(), nullptr), v.end()); | |
| 167 | 198 | } |
| 168 | 199 | |
| 169 | static Defined *addOptionalRegular(StringRef Name, SectionBase *Sec, | |
| 170 | uint64_t Val, uint8_t StOther = STV_HIDDEN, | |
| 171 | uint8_t Binding = STB_GLOBAL) { | |
| 172 | Symbol *S = Symtab->find(Name); | |
| 173 | if (!S || S->isDefined()) | |
| 200 | static Defined *addOptionalRegular(StringRef name, SectionBase *sec, | |
| 201 | uint64_t val, uint8_t stOther = STV_HIDDEN, | |
| 202 | uint8_t binding = STB_GLOBAL) { | |
| 203 | Symbol *s = symtab->find(name); | |
| 204 | if (!s || s->isDefined()) | |
| 174 | 205 | return nullptr; |
| 175 | return Symtab->addDefined(Name, StOther, STT_NOTYPE, Val, | |
| 176 | /*Size=*/0, Binding, Sec, | |
| 177 | /*File=*/nullptr); | |
| 206 | ||
| 207 | s->resolve(Defined{/*file=*/nullptr, name, binding, stOther, STT_NOTYPE, val, | |
| 208 | /*size=*/0, sec}); | |
| 209 | return cast<Defined>(s); | |
| 178 | 210 | } |
| 179 | 211 | |
| 180 | static Defined *addAbsolute(StringRef Name) { | |
| 181 | return Symtab->addDefined(Name, STV_HIDDEN, STT_NOTYPE, 0, 0, STB_GLOBAL, | |
| 182 | nullptr, nullptr); | |
| 212 | static Defined *addAbsolute(StringRef name) { | |
| 213 | Symbol *sym = symtab->addSymbol(Defined{nullptr, name, STB_GLOBAL, STV_HIDDEN, | |
| 214 | STT_NOTYPE, 0, 0, nullptr}); | |
| 215 | return cast<Defined>(sym); | |
| 183 | 216 | } |
| 184 | 217 | |
| 185 | 218 | // The linker is expected to define some symbols depending on |
| 186 | 219 | // the linking result. This function defines such symbols. |
| 187 | 220 | void elf::addReservedSymbols() { |
| 188 | if (Config->EMachine == EM_MIPS) { | |
| 221 | if (config->emachine == EM_MIPS) { | |
| 189 | 222 | // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer |
| 190 | 223 | // so that it points to an absolute address which by default is relative |
| 191 | 224 | // to GOT. Default offset is 0x7ff0. |
| 192 | 225 | // See "Global Data Symbols" in Chapter 6 in the following document: |
| 193 | 226 | // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf |
| 194 | ElfSym::MipsGp = addAbsolute("_gp"); | |
| 227 | ElfSym::mipsGp = addAbsolute("_gp"); | |
| 195 | 228 | |
| 196 | 229 | // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between |
| 197 | 230 | // start of function and 'gp' pointer into GOT. |
| 198 | if (Symtab->find("_gp_disp")) | |
| 199 | ElfSym::MipsGpDisp = addAbsolute("_gp_disp"); | |
| 231 | if (symtab->find("_gp_disp")) | |
| 232 | ElfSym::mipsGpDisp = addAbsolute("_gp_disp"); | |
| 200 | 233 | |
| 201 | 234 | // The __gnu_local_gp is a magic symbol equal to the current value of 'gp' |
| 202 | 235 | // pointer. This symbol is used in the code generated by .cpload pseudo-op |
| 203 | 236 | // in case of using -mno-shared option. |
| 204 | 237 | // https://sourceware.org/ml/binutils/2004-12/msg00094.html |
| 205 | if (Symtab->find("__gnu_local_gp")) | |
| 206 | ElfSym::MipsLocalGp = addAbsolute("__gnu_local_gp"); | |
| 238 | if (symtab->find("__gnu_local_gp")) | |
| 239 | ElfSym::mipsLocalGp = addAbsolute("__gnu_local_gp"); | |
| 240 | } else if (config->emachine == EM_PPC) { | |
| 241 | // glibc *crt1.o has a undefined reference to _SDA_BASE_. Since we don't | |
| 242 | // support Small Data Area, define it arbitrarily as 0. | |
| 243 | addOptionalRegular("_SDA_BASE_", nullptr, 0, STV_HIDDEN); | |
| 207 | 244 | } |
| 208 | 245 | |
| 209 | 246 | // The Power Architecture 64-bit v2 ABI defines a TableOfContents (TOC) which |
| ... | ... | @@ -214,56 +251,62 @@ void elf::addReservedSymbols() { |
| 214 | 251 | // the .got section. |
| 215 | 252 | // We do not allow _GLOBAL_OFFSET_TABLE_ to be defined by input objects as the |
| 216 | 253 | // correctness of some relocations depends on its value. |
| 217 | StringRef GotTableSymName = | |
| 218 | (Config->EMachine == EM_PPC64) ? ".TOC." : "_GLOBAL_OFFSET_TABLE_"; | |
| 219 | if (Symbol *S = Symtab->find(GotTableSymName)) { | |
| 220 | if (S->isDefined()) | |
| 221 | error(toString(S->File) + " cannot redefine linker defined symbol '" + | |
| 222 | GotTableSymName + "'"); | |
| 223 | else | |
| 224 | ElfSym::GlobalOffsetTable = Symtab->addDefined( | |
| 225 | GotTableSymName, STV_HIDDEN, STT_NOTYPE, Target->GotBaseSymOff, | |
| 226 | /*Size=*/0, STB_GLOBAL, Out::ElfHeader, | |
| 227 | /*File=*/nullptr); | |
| 254 | StringRef gotSymName = | |
| 255 | (config->emachine == EM_PPC64) ? ".TOC." : "_GLOBAL_OFFSET_TABLE_"; | |
| 256 | ||
| 257 | if (Symbol *s = symtab->find(gotSymName)) { | |
| 258 | if (s->isDefined()) { | |
| 259 | error(toString(s->file) + " cannot redefine linker defined symbol '" + | |
| 260 | gotSymName + "'"); | |
| 261 | return; | |
| 262 | } | |
| 263 | ||
| 264 | uint64_t gotOff = 0; | |
| 265 | if (config->emachine == EM_PPC64) | |
| 266 | gotOff = 0x8000; | |
| 267 | ||
| 268 | s->resolve(Defined{/*file=*/nullptr, gotSymName, STB_GLOBAL, STV_HIDDEN, | |
| 269 | STT_NOTYPE, gotOff, /*size=*/0, Out::elfHeader}); | |
| 270 | ElfSym::globalOffsetTable = cast<Defined>(s); | |
| 228 | 271 | } |
| 229 | 272 | |
| 230 | 273 | // __ehdr_start is the location of ELF file headers. Note that we define |
| 231 | 274 | // this symbol unconditionally even when using a linker script, which |
| 232 | 275 | // differs from the behavior implemented by GNU linker which only define |
| 233 | 276 | // this symbol if ELF headers are in the memory mapped segment. |
| 234 | addOptionalRegular("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN); | |
| 277 | addOptionalRegular("__ehdr_start", Out::elfHeader, 0, STV_HIDDEN); | |
| 235 | 278 | |
| 236 | 279 | // __executable_start is not documented, but the expectation of at |
| 237 | 280 | // least the Android libc is that it points to the ELF header. |
| 238 | addOptionalRegular("__executable_start", Out::ElfHeader, 0, STV_HIDDEN); | |
| 281 | addOptionalRegular("__executable_start", Out::elfHeader, 0, STV_HIDDEN); | |
| 239 | 282 | |
| 240 | 283 | // __dso_handle symbol is passed to cxa_finalize as a marker to identify |
| 241 | 284 | // each DSO. The address of the symbol doesn't matter as long as they are |
| 242 | 285 | // different in different DSOs, so we chose the start address of the DSO. |
| 243 | addOptionalRegular("__dso_handle", Out::ElfHeader, 0, STV_HIDDEN); | |
| 286 | addOptionalRegular("__dso_handle", Out::elfHeader, 0, STV_HIDDEN); | |
| 244 | 287 | |
| 245 | 288 | // If linker script do layout we do not need to create any standart symbols. |
| 246 | if (Script->HasSectionsCommand) | |
| 289 | if (script->hasSectionsCommand) | |
| 247 | 290 | return; |
| 248 | 291 | |
| 249 | auto Add = [](StringRef S, int64_t Pos) { | |
| 250 | return addOptionalRegular(S, Out::ElfHeader, Pos, STV_DEFAULT); | |
| 292 | auto add = [](StringRef s, int64_t pos) { | |
| 293 | return addOptionalRegular(s, Out::elfHeader, pos, STV_DEFAULT); | |
| 251 | 294 | }; |
| 252 | 295 | |
| 253 | ElfSym::Bss = Add("__bss_start", 0); | |
| 254 | ElfSym::End1 = Add("end", -1); | |
| 255 | ElfSym::End2 = Add("_end", -1); | |
| 256 | ElfSym::Etext1 = Add("etext", -1); | |
| 257 | ElfSym::Etext2 = Add("_etext", -1); | |
| 258 | ElfSym::Edata1 = Add("edata", -1); | |
| 259 | ElfSym::Edata2 = Add("_edata", -1); | |
| 296 | ElfSym::bss = add("__bss_start", 0); | |
| 297 | ElfSym::end1 = add("end", -1); | |
| 298 | ElfSym::end2 = add("_end", -1); | |
| 299 | ElfSym::etext1 = add("etext", -1); | |
| 300 | ElfSym::etext2 = add("_etext", -1); | |
| 301 | ElfSym::edata1 = add("edata", -1); | |
| 302 | ElfSym::edata2 = add("_edata", -1); | |
| 260 | 303 | } |
| 261 | 304 | |
| 262 | static OutputSection *findSection(StringRef Name) { | |
| 263 | for (BaseCommand *Base : Script->SectionCommands) | |
| 264 | if (auto *Sec = dyn_cast<OutputSection>(Base)) | |
| 265 | if (Sec->Name == Name) | |
| 266 | return Sec; | |
| 305 | static OutputSection *findSection(StringRef name, unsigned partition = 1) { | |
| 306 | for (BaseCommand *base : script->sectionCommands) | |
| 307 | if (auto *sec = dyn_cast<OutputSection>(base)) | |
| 308 | if (sec->name == name && sec->partition == partition) | |
| 309 | return sec; | |
| 267 | 310 | return nullptr; |
| 268 | 311 | } |
| 269 | 312 | |
| ... | ... | @@ -271,202 +314,263 @@ static OutputSection *findSection(StringRef Name) { |
| 271 | 314 | template <class ELFT> static void createSyntheticSections() { |
| 272 | 315 | // Initialize all pointers with NULL. This is needed because |
| 273 | 316 | // you can call lld::elf::main more than once as a library. |
| 274 | memset(&Out::First, 0, sizeof(Out)); | |
| 317 | memset(&Out::first, 0, sizeof(Out)); | |
| 275 | 318 | |
| 276 | auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); }; | |
| 319 | auto add = [](InputSectionBase *sec) { inputSections.push_back(sec); }; | |
| 277 | 320 | |
| 278 | In.DynStrTab = make<StringTableSection>(".dynstr", true); | |
| 279 | In.Dynamic = make<DynamicSection<ELFT>>(); | |
| 280 | if (Config->AndroidPackDynRelocs) { | |
| 281 | In.RelaDyn = make<AndroidPackedRelocationSection<ELFT>>( | |
| 282 | Config->IsRela ? ".rela.dyn" : ".rel.dyn"); | |
| 283 | } else { | |
| 284 | In.RelaDyn = make<RelocationSection<ELFT>>( | |
| 285 | Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); | |
| 286 | } | |
| 287 | In.ShStrTab = make<StringTableSection>(".shstrtab", false); | |
| 321 | in.shStrTab = make<StringTableSection>(".shstrtab", false); | |
| 288 | 322 | |
| 289 | Out::ProgramHeaders = make<OutputSection>("", 0, SHF_ALLOC); | |
| 290 | Out::ProgramHeaders->Alignment = Config->Wordsize; | |
| 323 | Out::programHeaders = make<OutputSection>("", 0, SHF_ALLOC); | |
| 324 | Out::programHeaders->alignment = config->wordsize; | |
| 291 | 325 | |
| 292 | if (needsInterpSection()) { | |
| 293 | In.Interp = createInterpSection(); | |
| 294 | Add(In.Interp); | |
| 326 | if (config->strip != StripPolicy::All) { | |
| 327 | in.strTab = make<StringTableSection>(".strtab", false); | |
| 328 | in.symTab = make<SymbolTableSection<ELFT>>(*in.strTab); | |
| 329 | in.symTabShndx = make<SymtabShndxSection>(); | |
| 295 | 330 | } |
| 296 | 331 | |
| 297 | if (Config->Strip != StripPolicy::All) { | |
| 298 | In.StrTab = make<StringTableSection>(".strtab", false); | |
| 299 | In.SymTab = make<SymbolTableSection<ELFT>>(*In.StrTab); | |
| 300 | In.SymTabShndx = make<SymtabShndxSection>(); | |
| 301 | } | |
| 302 | ||
| 303 | if (Config->BuildId != BuildIdKind::None) { | |
| 304 | In.BuildId = make<BuildIdSection>(); | |
| 305 | Add(In.BuildId); | |
| 306 | } | |
| 307 | ||
| 308 | In.Bss = make<BssSection>(".bss", 0, 1); | |
| 309 | Add(In.Bss); | |
| 332 | in.bss = make<BssSection>(".bss", 0, 1); | |
| 333 | add(in.bss); | |
| 310 | 334 | |
| 311 | 335 | // If there is a SECTIONS command and a .data.rel.ro section name use name |
| 312 | 336 | // .data.rel.ro.bss so that we match in the .data.rel.ro output section. |
| 313 | 337 | // This makes sure our relro is contiguous. |
| 314 | bool HasDataRelRo = Script->HasSectionsCommand && findSection(".data.rel.ro"); | |
| 315 | In.BssRelRo = | |
| 316 | make<BssSection>(HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1); | |
| 317 | Add(In.BssRelRo); | |
| 338 | bool hasDataRelRo = | |
| 339 | script->hasSectionsCommand && findSection(".data.rel.ro", 0); | |
| 340 | in.bssRelRo = | |
| 341 | make<BssSection>(hasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1); | |
| 342 | add(in.bssRelRo); | |
| 318 | 343 | |
| 319 | 344 | // Add MIPS-specific sections. |
| 320 | if (Config->EMachine == EM_MIPS) { | |
| 321 | if (!Config->Shared && Config->HasDynSymTab) { | |
| 322 | In.MipsRldMap = make<MipsRldMapSection>(); | |
| 323 | Add(In.MipsRldMap); | |
| 345 | if (config->emachine == EM_MIPS) { | |
| 346 | if (!config->shared && config->hasDynSymTab) { | |
| 347 | in.mipsRldMap = make<MipsRldMapSection>(); | |
| 348 | add(in.mipsRldMap); | |
| 324 | 349 | } |
| 325 | if (auto *Sec = MipsAbiFlagsSection<ELFT>::create()) | |
| 326 | Add(Sec); | |
| 327 | if (auto *Sec = MipsOptionsSection<ELFT>::create()) | |
| 328 | Add(Sec); | |
| 329 | if (auto *Sec = MipsReginfoSection<ELFT>::create()) | |
| 330 | Add(Sec); | |
| 350 | if (auto *sec = MipsAbiFlagsSection<ELFT>::create()) | |
| 351 | add(sec); | |
| 352 | if (auto *sec = MipsOptionsSection<ELFT>::create()) | |
| 353 | add(sec); | |
| 354 | if (auto *sec = MipsReginfoSection<ELFT>::create()) | |
| 355 | add(sec); | |
| 331 | 356 | } |
| 332 | 357 | |
| 333 | if (Config->HasDynSymTab) { | |
| 334 | In.DynSymTab = make<SymbolTableSection<ELFT>>(*In.DynStrTab); | |
| 335 | Add(In.DynSymTab); | |
| 358 | for (Partition &part : partitions) { | |
| 359 | auto add = [&](InputSectionBase *sec) { | |
| 360 | sec->partition = part.getNumber(); | |
| 361 | inputSections.push_back(sec); | |
| 362 | }; | |
| 363 | ||
| 364 | if (!part.name.empty()) { | |
| 365 | part.elfHeader = make<PartitionElfHeaderSection<ELFT>>(); | |
| 366 | part.elfHeader->name = part.name; | |
| 367 | add(part.elfHeader); | |
| 336 | 368 | |
| 337 | InX<ELFT>::VerSym = make<VersionTableSection<ELFT>>(); | |
| 338 | Add(InX<ELFT>::VerSym); | |
| 369 | part.programHeaders = make<PartitionProgramHeadersSection<ELFT>>(); | |
| 370 | add(part.programHeaders); | |
| 371 | } | |
| 339 | 372 | |
| 340 | if (!Config->VersionDefinitions.empty()) { | |
| 341 | In.VerDef = make<VersionDefinitionSection>(); | |
| 342 | Add(In.VerDef); | |
| 373 | if (config->buildId != BuildIdKind::None) { | |
| 374 | part.buildId = make<BuildIdSection>(); | |
| 375 | add(part.buildId); | |
| 343 | 376 | } |
| 344 | 377 | |
| 345 | InX<ELFT>::VerNeed = make<VersionNeedSection<ELFT>>(); | |
| 346 | Add(InX<ELFT>::VerNeed); | |
| 378 | part.dynStrTab = make<StringTableSection>(".dynstr", true); | |
| 379 | part.dynSymTab = make<SymbolTableSection<ELFT>>(*part.dynStrTab); | |
| 380 | part.dynamic = make<DynamicSection<ELFT>>(); | |
| 381 | if (config->androidPackDynRelocs) { | |
| 382 | part.relaDyn = make<AndroidPackedRelocationSection<ELFT>>( | |
| 383 | config->isRela ? ".rela.dyn" : ".rel.dyn"); | |
| 384 | } else { | |
| 385 | part.relaDyn = make<RelocationSection<ELFT>>( | |
| 386 | config->isRela ? ".rela.dyn" : ".rel.dyn", config->zCombreloc); | |
| 387 | } | |
| 388 | ||
| 389 | if (needsInterpSection()) | |
| 390 | add(createInterpSection()); | |
| 391 | ||
| 392 | if (config->hasDynSymTab) { | |
| 393 | part.dynSymTab = make<SymbolTableSection<ELFT>>(*part.dynStrTab); | |
| 394 | add(part.dynSymTab); | |
| 395 | ||
| 396 | part.verSym = make<VersionTableSection>(); | |
| 397 | add(part.verSym); | |
| 398 | ||
| 399 | if (!config->versionDefinitions.empty()) { | |
| 400 | part.verDef = make<VersionDefinitionSection>(); | |
| 401 | add(part.verDef); | |
| 402 | } | |
| 403 | ||
| 404 | part.verNeed = make<VersionNeedSection<ELFT>>(); | |
| 405 | add(part.verNeed); | |
| 406 | ||
| 407 | if (config->gnuHash) { | |
| 408 | part.gnuHashTab = make<GnuHashTableSection>(); | |
| 409 | add(part.gnuHashTab); | |
| 410 | } | |
| 411 | ||
| 412 | if (config->sysvHash) { | |
| 413 | part.hashTab = make<HashTableSection>(); | |
| 414 | add(part.hashTab); | |
| 415 | } | |
| 347 | 416 | |
| 348 | if (Config->GnuHash) { | |
| 349 | In.GnuHashTab = make<GnuHashTableSection>(); | |
| 350 | Add(In.GnuHashTab); | |
| 417 | add(part.dynamic); | |
| 418 | add(part.dynStrTab); | |
| 419 | add(part.relaDyn); | |
| 351 | 420 | } |
| 352 | 421 | |
| 353 | if (Config->SysvHash) { | |
| 354 | In.HashTab = make<HashTableSection>(); | |
| 355 | Add(In.HashTab); | |
| 422 | if (config->relrPackDynRelocs) { | |
| 423 | part.relrDyn = make<RelrSection<ELFT>>(); | |
| 424 | add(part.relrDyn); | |
| 356 | 425 | } |
| 357 | 426 | |
| 358 | Add(In.Dynamic); | |
| 359 | Add(In.DynStrTab); | |
| 360 | Add(In.RelaDyn); | |
| 427 | if (!config->relocatable) { | |
| 428 | if (config->ehFrameHdr) { | |
| 429 | part.ehFrameHdr = make<EhFrameHeader>(); | |
| 430 | add(part.ehFrameHdr); | |
| 431 | } | |
| 432 | part.ehFrame = make<EhFrameSection>(); | |
| 433 | add(part.ehFrame); | |
| 434 | } | |
| 435 | ||
| 436 | if (config->emachine == EM_ARM && !config->relocatable) { | |
| 437 | // The ARMExidxsyntheticsection replaces all the individual .ARM.exidx | |
| 438 | // InputSections. | |
| 439 | part.armExidx = make<ARMExidxSyntheticSection>(); | |
| 440 | add(part.armExidx); | |
| 441 | } | |
| 361 | 442 | } |
| 362 | 443 | |
| 363 | if (Config->RelrPackDynRelocs) { | |
| 364 | In.RelrDyn = make<RelrSection<ELFT>>(); | |
| 365 | Add(In.RelrDyn); | |
| 444 | if (partitions.size() != 1) { | |
| 445 | // Create the partition end marker. This needs to be in partition number 255 | |
| 446 | // so that it is sorted after all other partitions. It also has other | |
| 447 | // special handling (see createPhdrs() and combineEhSections()). | |
| 448 | in.partEnd = make<BssSection>(".part.end", config->maxPageSize, 1); | |
| 449 | in.partEnd->partition = 255; | |
| 450 | add(in.partEnd); | |
| 451 | ||
| 452 | in.partIndex = make<PartitionIndexSection>(); | |
| 453 | addOptionalRegular("__part_index_begin", in.partIndex, 0); | |
| 454 | addOptionalRegular("__part_index_end", in.partIndex, | |
| 455 | in.partIndex->getSize()); | |
| 456 | add(in.partIndex); | |
| 366 | 457 | } |
| 367 | 458 | |
| 368 | 459 | // Add .got. MIPS' .got is so different from the other archs, |
| 369 | 460 | // it has its own class. |
| 370 | if (Config->EMachine == EM_MIPS) { | |
| 371 | In.MipsGot = make<MipsGotSection>(); | |
| 372 | Add(In.MipsGot); | |
| 461 | if (config->emachine == EM_MIPS) { | |
| 462 | in.mipsGot = make<MipsGotSection>(); | |
| 463 | add(in.mipsGot); | |
| 373 | 464 | } else { |
| 374 | In.Got = make<GotSection>(); | |
| 375 | Add(In.Got); | |
| 465 | in.got = make<GotSection>(); | |
| 466 | add(in.got); | |
| 467 | } | |
| 468 | ||
| 469 | if (config->emachine == EM_PPC) { | |
| 470 | in.ppc32Got2 = make<PPC32Got2Section>(); | |
| 471 | add(in.ppc32Got2); | |
| 376 | 472 | } |
| 377 | 473 | |
| 378 | if (Config->EMachine == EM_PPC64) { | |
| 379 | In.PPC64LongBranchTarget = make<PPC64LongBranchTargetSection>(); | |
| 380 | Add(In.PPC64LongBranchTarget); | |
| 474 | if (config->emachine == EM_PPC64) { | |
| 475 | in.ppc64LongBranchTarget = make<PPC64LongBranchTargetSection>(); | |
| 476 | add(in.ppc64LongBranchTarget); | |
| 381 | 477 | } |
| 382 | 478 | |
| 383 | In.GotPlt = make<GotPltSection>(); | |
| 384 | Add(In.GotPlt); | |
| 385 | In.IgotPlt = make<IgotPltSection>(); | |
| 386 | Add(In.IgotPlt); | |
| 479 | if (config->emachine == EM_RISCV) { | |
| 480 | in.riscvSdata = make<RISCVSdataSection>(); | |
| 481 | add(in.riscvSdata); | |
| 482 | } | |
| 483 | ||
| 484 | in.gotPlt = make<GotPltSection>(); | |
| 485 | add(in.gotPlt); | |
| 486 | in.igotPlt = make<IgotPltSection>(); | |
| 487 | add(in.igotPlt); | |
| 387 | 488 | |
| 388 | if (Config->GdbIndex) { | |
| 389 | In.GdbIndex = GdbIndexSection::create<ELFT>(); | |
| 390 | Add(In.GdbIndex); | |
| 489 | // _GLOBAL_OFFSET_TABLE_ is defined relative to either .got.plt or .got. Treat | |
| 490 | // it as a relocation and ensure the referenced section is created. | |
| 491 | if (ElfSym::globalOffsetTable && config->emachine != EM_MIPS) { | |
| 492 | if (target->gotBaseSymInGotPlt) | |
| 493 | in.gotPlt->hasGotPltOffRel = true; | |
| 494 | else | |
| 495 | in.got->hasGotOffRel = true; | |
| 391 | 496 | } |
| 392 | 497 | |
| 498 | if (config->gdbIndex) | |
| 499 | add(GdbIndexSection::create<ELFT>()); | |
| 500 | ||
| 393 | 501 | // We always need to add rel[a].plt to output if it has entries. |
| 394 | 502 | // Even for static linking it can contain R_[*]_IRELATIVE relocations. |
| 395 | In.RelaPlt = make<RelocationSection<ELFT>>( | |
| 396 | Config->IsRela ? ".rela.plt" : ".rel.plt", false /*Sort*/); | |
| 397 | Add(In.RelaPlt); | |
| 503 | in.relaPlt = make<RelocationSection<ELFT>>( | |
| 504 | config->isRela ? ".rela.plt" : ".rel.plt", /*sort=*/false); | |
| 505 | add(in.relaPlt); | |
| 398 | 506 | |
| 399 | // The RelaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure | |
| 507 | // The relaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure | |
| 400 | 508 | // that the IRelative relocations are processed last by the dynamic loader. |
| 401 | 509 | // We cannot place the iplt section in .rel.dyn when Android relocation |
| 402 | 510 | // packing is enabled because that would cause a section type mismatch. |
| 403 | 511 | // However, because the Android dynamic loader reads .rel.plt after .rel.dyn, |
| 404 | 512 | // we can get the desired behaviour by placing the iplt section in .rel.plt. |
| 405 | In.RelaIplt = make<RelocationSection<ELFT>>( | |
| 406 | (Config->EMachine == EM_ARM && !Config->AndroidPackDynRelocs) | |
| 513 | in.relaIplt = make<RelocationSection<ELFT>>( | |
| 514 | (config->emachine == EM_ARM && !config->androidPackDynRelocs) | |
| 407 | 515 | ? ".rel.dyn" |
| 408 | : In.RelaPlt->Name, | |
| 409 | false /*Sort*/); | |
| 410 | Add(In.RelaIplt); | |
| 516 | : in.relaPlt->name, | |
| 517 | /*sort=*/false); | |
| 518 | add(in.relaIplt); | |
| 519 | ||
| 520 | in.plt = make<PltSection>(false); | |
| 521 | add(in.plt); | |
| 522 | in.iplt = make<PltSection>(true); | |
| 523 | add(in.iplt); | |
| 411 | 524 | |
| 412 | In.Plt = make<PltSection>(false); | |
| 413 | Add(In.Plt); | |
| 414 | In.Iplt = make<PltSection>(true); | |
| 415 | Add(In.Iplt); | |
| 525 | if (config->andFeatures) | |
| 526 | add(make<GnuPropertySection>()); | |
| 416 | 527 | |
| 417 | 528 | // .note.GNU-stack is always added when we are creating a re-linkable |
| 418 | 529 | // object file. Other linkers are using the presence of this marker |
| 419 | 530 | // section to control the executable-ness of the stack area, but that |
| 420 | 531 | // is irrelevant these days. Stack area should always be non-executable |
| 421 | 532 | // by default. So we emit this section unconditionally. |
| 422 | if (Config->Relocatable) | |
| 423 | Add(make<GnuStackSection>()); | |
| 424 | ||
| 425 | if (!Config->Relocatable) { | |
| 426 | if (Config->EhFrameHdr) { | |
| 427 | In.EhFrameHdr = make<EhFrameHeader>(); | |
| 428 | Add(In.EhFrameHdr); | |
| 429 | } | |
| 430 | In.EhFrame = make<EhFrameSection>(); | |
| 431 | Add(In.EhFrame); | |
| 432 | } | |
| 433 | ||
| 434 | if (In.SymTab) | |
| 435 | Add(In.SymTab); | |
| 436 | if (In.SymTabShndx) | |
| 437 | Add(In.SymTabShndx); | |
| 438 | Add(In.ShStrTab); | |
| 439 | if (In.StrTab) | |
| 440 | Add(In.StrTab); | |
| 533 | if (config->relocatable) | |
| 534 | add(make<GnuStackSection>()); | |
| 441 | 535 | |
| 442 | if (Config->EMachine == EM_ARM && !Config->Relocatable) | |
| 443 | // Add a sentinel to terminate .ARM.exidx. It helps an unwinder | |
| 444 | // to find the exact address range of the last entry. | |
| 445 | Add(make<ARMExidxSentinelSection>()); | |
| 536 | if (in.symTab) | |
| 537 | add(in.symTab); | |
| 538 | if (in.symTabShndx) | |
| 539 | add(in.symTabShndx); | |
| 540 | add(in.shStrTab); | |
| 541 | if (in.strTab) | |
| 542 | add(in.strTab); | |
| 446 | 543 | } |
| 447 | 544 | |
| 448 | 545 | // The main function of the writer. |
| 449 | 546 | template <class ELFT> void Writer<ELFT>::run() { |
| 547 | // Make copies of any input sections that need to be copied into each | |
| 548 | // partition. | |
| 549 | copySectionsIntoPartitions<ELFT>(); | |
| 550 | ||
| 450 | 551 | // Create linker-synthesized sections such as .got or .plt. |
| 451 | 552 | // Such sections are of type input section. |
| 452 | 553 | createSyntheticSections<ELFT>(); |
| 453 | 554 | |
| 454 | if (!Config->Relocatable) | |
| 455 | combineEhFrameSections<ELFT>(); | |
| 555 | // Some input sections that are used for exception handling need to be moved | |
| 556 | // into synthetic sections. Do that now so that they aren't assigned to | |
| 557 | // output sections in the usual way. | |
| 558 | if (!config->relocatable) | |
| 559 | combineEhSections<ELFT>(); | |
| 456 | 560 | |
| 457 | 561 | // We want to process linker script commands. When SECTIONS command |
| 458 | 562 | // is given we let it create sections. |
| 459 | Script->processSectionCommands(); | |
| 563 | script->processSectionCommands(); | |
| 460 | 564 | |
| 461 | 565 | // Linker scripts controls how input sections are assigned to output sections. |
| 462 | 566 | // Input sections that were not handled by scripts are called "orphans", and |
| 463 | 567 | // they are assigned to output sections by the default rule. Process that. |
| 464 | Script->addOrphanSections(); | |
| 568 | script->addOrphanSections(); | |
| 465 | 569 | |
| 466 | if (Config->Discard != DiscardPolicy::All) | |
| 570 | if (config->discard != DiscardPolicy::All) | |
| 467 | 571 | copyLocalSymbols(); |
| 468 | 572 | |
| 469 | if (Config->CopyRelocs) | |
| 573 | if (config->copyRelocs) | |
| 470 | 574 | addSectionSymbols(); |
| 471 | 575 | |
| 472 | 576 | // Now that we have a complete set of output sections. This function |
| ... | ... | @@ -478,33 +582,35 @@ template <class ELFT> void Writer<ELFT>::run() { |
| 478 | 582 | if (errorCount()) |
| 479 | 583 | return; |
| 480 | 584 | |
| 481 | Script->assignAddresses(); | |
| 585 | script->assignAddresses(); | |
| 482 | 586 | |
| 483 | 587 | // If -compressed-debug-sections is specified, we need to compress |
| 484 | 588 | // .debug_* sections. Do it right now because it changes the size of |
| 485 | 589 | // output sections. |
| 486 | for (OutputSection *Sec : OutputSections) | |
| 487 | Sec->maybeCompress<ELFT>(); | |
| 590 | for (OutputSection *sec : outputSections) | |
| 591 | sec->maybeCompress<ELFT>(); | |
| 488 | 592 | |
| 489 | Script->allocateHeaders(Phdrs); | |
| 593 | script->allocateHeaders(mainPart->phdrs); | |
| 490 | 594 | |
| 491 | 595 | // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a |
| 492 | 596 | // 0 sized region. This has to be done late since only after assignAddresses |
| 493 | 597 | // we know the size of the sections. |
| 494 | removeEmptyPTLoad(); | |
| 598 | for (Partition &part : partitions) | |
| 599 | removeEmptyPTLoad(part.phdrs); | |
| 495 | 600 | |
| 496 | if (!Config->OFormatBinary) | |
| 601 | if (!config->oFormatBinary) | |
| 497 | 602 | assignFileOffsets(); |
| 498 | 603 | else |
| 499 | 604 | assignFileOffsetsBinary(); |
| 500 | 605 | |
| 501 | setPhdrs(); | |
| 606 | for (Partition &part : partitions) | |
| 607 | setPhdrs(part); | |
| 502 | 608 | |
| 503 | if (Config->Relocatable) | |
| 504 | for (OutputSection *Sec : OutputSections) | |
| 505 | Sec->Addr = 0; | |
| 609 | if (config->relocatable) | |
| 610 | for (OutputSection *sec : outputSections) | |
| 611 | sec->addr = 0; | |
| 506 | 612 | |
| 507 | if (Config->CheckSections) | |
| 613 | if (config->checkSections) | |
| 508 | 614 | checkSections(); |
| 509 | 615 | |
| 510 | 616 | // It does not make sense try to open the file if we have error already. |
| ... | ... | @@ -515,7 +621,7 @@ template <class ELFT> void Writer<ELFT>::run() { |
| 515 | 621 | if (errorCount()) |
| 516 | 622 | return; |
| 517 | 623 | |
| 518 | if (!Config->OFormatBinary) { | |
| 624 | if (!config->oFormatBinary) { | |
| 519 | 625 | writeTrapInstr(); |
| 520 | 626 | writeHeader(); |
| 521 | 627 | writeSections(); |
| ... | ... | @@ -535,16 +641,20 @@ template <class ELFT> void Writer<ELFT>::run() { |
| 535 | 641 | if (errorCount()) |
| 536 | 642 | return; |
| 537 | 643 | |
| 538 | if (auto E = Buffer->commit()) | |
| 539 | error("failed to write to the output file: " + toString(std::move(E))); | |
| 644 | if (auto e = buffer->commit()) | |
| 645 | error("failed to write to the output file: " + toString(std::move(e))); | |
| 540 | 646 | } |
| 541 | 647 | |
| 542 | static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName, | |
| 543 | const Symbol &B) { | |
| 544 | if (B.isSection()) | |
| 648 | static bool shouldKeepInSymtab(const Defined &sym) { | |
| 649 | if (sym.isSection()) | |
| 545 | 650 | return false; |
| 546 | 651 | |
| 547 | if (Config->Discard == DiscardPolicy::None) | |
| 652 | if (config->discard == DiscardPolicy::None) | |
| 653 | return true; | |
| 654 | ||
| 655 | // If -emit-reloc is given, all symbols including local ones need to be | |
| 656 | // copied because they may be referenced by relocations. | |
| 657 | if (config->emitRelocs) | |
| 548 | 658 | return true; |
| 549 | 659 | |
| 550 | 660 | // In ELF assembly .L symbols are normally discarded by the assembler. |
| ... | ... | @@ -552,61 +662,62 @@ static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName, |
| 552 | 662 | // * --discard-locals is used. |
| 553 | 663 | // * The symbol is in a SHF_MERGE section, which is normally the reason for |
| 554 | 664 | // the assembler keeping the .L symbol. |
| 555 | if (!SymName.startswith(".L") && !SymName.empty()) | |
| 665 | StringRef name = sym.getName(); | |
| 666 | bool isLocal = name.startswith(".L") || name.empty(); | |
| 667 | if (!isLocal) | |
| 556 | 668 | return true; |
| 557 | 669 | |
| 558 | if (Config->Discard == DiscardPolicy::Locals) | |
| 670 | if (config->discard == DiscardPolicy::Locals) | |
| 559 | 671 | return false; |
| 560 | 672 | |
| 561 | return !Sec || !(Sec->Flags & SHF_MERGE); | |
| 673 | SectionBase *sec = sym.section; | |
| 674 | return !sec || !(sec->flags & SHF_MERGE); | |
| 562 | 675 | } |
| 563 | 676 | |
| 564 | static bool includeInSymtab(const Symbol &B) { | |
| 565 | if (!B.isLocal() && !B.IsUsedInRegularObj) | |
| 677 | static bool includeInSymtab(const Symbol &b) { | |
| 678 | if (!b.isLocal() && !b.isUsedInRegularObj) | |
| 566 | 679 | return false; |
| 567 | 680 | |
| 568 | if (auto *D = dyn_cast<Defined>(&B)) { | |
| 681 | if (auto *d = dyn_cast<Defined>(&b)) { | |
| 569 | 682 | // Always include absolute symbols. |
| 570 | SectionBase *Sec = D->Section; | |
| 571 | if (!Sec) | |
| 683 | SectionBase *sec = d->section; | |
| 684 | if (!sec) | |
| 572 | 685 | return true; |
| 573 | Sec = Sec->Repl; | |
| 686 | sec = sec->repl; | |
| 574 | 687 | |
| 575 | 688 | // Exclude symbols pointing to garbage-collected sections. |
| 576 | if (isa<InputSectionBase>(Sec) && !Sec->Live) | |
| 689 | if (isa<InputSectionBase>(sec) && !sec->isLive()) | |
| 577 | 690 | return false; |
| 578 | 691 | |
| 579 | if (auto *S = dyn_cast<MergeInputSection>(Sec)) | |
| 580 | if (!S->getSectionPiece(D->Value)->Live) | |
| 692 | if (auto *s = dyn_cast<MergeInputSection>(sec)) | |
| 693 | if (!s->getSectionPiece(d->value)->live) | |
| 581 | 694 | return false; |
| 582 | 695 | return true; |
| 583 | 696 | } |
| 584 | return B.Used; | |
| 697 | return b.used; | |
| 585 | 698 | } |
| 586 | 699 | |
| 587 | 700 | // Local symbols are not in the linker's symbol table. This function scans |
| 588 | 701 | // each object file's symbol table to copy local symbols to the output. |
| 589 | 702 | template <class ELFT> void Writer<ELFT>::copyLocalSymbols() { |
| 590 | if (!In.SymTab) | |
| 703 | if (!in.symTab) | |
| 591 | 704 | return; |
| 592 | for (InputFile *File : ObjectFiles) { | |
| 593 | ObjFile<ELFT> *F = cast<ObjFile<ELFT>>(File); | |
| 594 | for (Symbol *B : F->getLocalSymbols()) { | |
| 595 | if (!B->isLocal()) | |
| 596 | fatal(toString(F) + | |
| 705 | for (InputFile *file : objectFiles) { | |
| 706 | ObjFile<ELFT> *f = cast<ObjFile<ELFT>>(file); | |
| 707 | for (Symbol *b : f->getLocalSymbols()) { | |
| 708 | if (!b->isLocal()) | |
| 709 | fatal(toString(f) + | |
| 597 | 710 | ": broken object: getLocalSymbols returns a non-local symbol"); |
| 598 | auto *DR = dyn_cast<Defined>(B); | |
| 711 | auto *dr = dyn_cast<Defined>(b); | |
| 599 | 712 | |
| 600 | 713 | // No reason to keep local undefined symbol in symtab. |
| 601 | if (!DR) | |
| 714 | if (!dr) | |
| 602 | 715 | continue; |
| 603 | if (!includeInSymtab(*B)) | |
| 716 | if (!includeInSymtab(*b)) | |
| 604 | 717 | continue; |
| 605 | ||
| 606 | SectionBase *Sec = DR->Section; | |
| 607 | if (!shouldKeepInSymtab(Sec, B->getName(), *B)) | |
| 718 | if (!shouldKeepInSymtab(*dr)) | |
| 608 | 719 | continue; |
| 609 | In.SymTab->addSymbol(B); | |
| 720 | in.symTab->addSymbol(b); | |
| 610 | 721 | } |
| 611 | 722 | } |
| 612 | 723 | } |
| ... | ... | @@ -616,33 +727,33 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() { |
| 616 | 727 | // referring to a section (that happens if the section is a synthetic one), we |
| 617 | 728 | // don't create a section symbol for that section. |
| 618 | 729 | template <class ELFT> void Writer<ELFT>::addSectionSymbols() { |
| 619 | for (BaseCommand *Base : Script->SectionCommands) { | |
| 620 | auto *Sec = dyn_cast<OutputSection>(Base); | |
| 621 | if (!Sec) | |
| 730 | for (BaseCommand *base : script->sectionCommands) { | |
| 731 | auto *sec = dyn_cast<OutputSection>(base); | |
| 732 | if (!sec) | |
| 622 | 733 | continue; |
| 623 | auto I = llvm::find_if(Sec->SectionCommands, [](BaseCommand *Base) { | |
| 624 | if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) | |
| 625 | return !ISD->Sections.empty(); | |
| 734 | auto i = llvm::find_if(sec->sectionCommands, [](BaseCommand *base) { | |
| 735 | if (auto *isd = dyn_cast<InputSectionDescription>(base)) | |
| 736 | return !isd->sections.empty(); | |
| 626 | 737 | return false; |
| 627 | 738 | }); |
| 628 | if (I == Sec->SectionCommands.end()) | |
| 739 | if (i == sec->sectionCommands.end()) | |
| 629 | 740 | continue; |
| 630 | InputSection *IS = cast<InputSectionDescription>(*I)->Sections[0]; | |
| 741 | InputSection *isec = cast<InputSectionDescription>(*i)->sections[0]; | |
| 631 | 742 | |
| 632 | 743 | // Relocations are not using REL[A] section symbols. |
| 633 | if (IS->Type == SHT_REL || IS->Type == SHT_RELA) | |
| 744 | if (isec->type == SHT_REL || isec->type == SHT_RELA) | |
| 634 | 745 | continue; |
| 635 | 746 | |
| 636 | 747 | // Unlike other synthetic sections, mergeable output sections contain data |
| 637 | 748 | // copied from input sections, and there may be a relocation pointing to its |
| 638 | 749 | // contents if -r or -emit-reloc are given. |
| 639 | if (isa<SyntheticSection>(IS) && !(IS->Flags & SHF_MERGE)) | |
| 750 | if (isa<SyntheticSection>(isec) && !(isec->flags & SHF_MERGE)) | |
| 640 | 751 | continue; |
| 641 | 752 | |
| 642 | auto *Sym = | |
| 643 | make<Defined>(IS->File, "", STB_LOCAL, /*StOther=*/0, STT_SECTION, | |
| 644 | /*Value=*/0, /*Size=*/0, IS); | |
| 645 | In.SymTab->addSymbol(Sym); | |
| 753 | auto *sym = | |
| 754 | make<Defined>(isec->file, "", STB_LOCAL, /*stOther=*/0, STT_SECTION, | |
| 755 | /*value=*/0, /*size=*/0, isec); | |
| 756 | in.symTab->addSymbol(sym); | |
| 646 | 757 | } |
| 647 | 758 | } |
| 648 | 759 | |
| ... | ... | @@ -652,25 +763,25 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() { |
| 652 | 763 | // |
| 653 | 764 | // This function returns true if a section needs to be put into a |
| 654 | 765 | // PT_GNU_RELRO segment. |
| 655 | static bool isRelroSection(const OutputSection *Sec) { | |
| 656 | if (!Config->ZRelro) | |
| 766 | static bool isRelroSection(const OutputSection *sec) { | |
| 767 | if (!config->zRelro) | |
| 657 | 768 | return false; |
| 658 | 769 | |
| 659 | uint64_t Flags = Sec->Flags; | |
| 770 | uint64_t flags = sec->flags; | |
| 660 | 771 | |
| 661 | 772 | // Non-allocatable or non-writable sections don't need RELRO because |
| 662 | 773 | // they are not writable or not even mapped to memory in the first place. |
| 663 | 774 | // RELRO is for sections that are essentially read-only but need to |
| 664 | 775 | // be writable only at process startup to allow dynamic linker to |
| 665 | 776 | // apply relocations. |
| 666 | if (!(Flags & SHF_ALLOC) || !(Flags & SHF_WRITE)) | |
| 777 | if (!(flags & SHF_ALLOC) || !(flags & SHF_WRITE)) | |
| 667 | 778 | return false; |
| 668 | 779 | |
| 669 | 780 | // Once initialized, TLS data segments are used as data templates |
| 670 | 781 | // for a thread-local storage. For each new thread, runtime |
| 671 | 782 | // allocates memory for a TLS and copy templates there. No thread |
| 672 | 783 | // are supposed to use templates directly. Thus, it can be in RELRO. |
| 673 | if (Flags & SHF_TLS) | |
| 784 | if (flags & SHF_TLS) | |
| 674 | 785 | return true; |
| 675 | 786 | |
| 676 | 787 | // .init_array, .preinit_array and .fini_array contain pointers to |
| ... | ... | @@ -679,15 +790,15 @@ static bool isRelroSection(const OutputSection *Sec) { |
| 679 | 790 | // to change at runtime. But if you are an attacker, you could do |
| 680 | 791 | // interesting things by manipulating pointers in .fini_array, for |
| 681 | 792 | // example. So they are put into RELRO. |
| 682 | uint32_t Type = Sec->Type; | |
| 683 | if (Type == SHT_INIT_ARRAY || Type == SHT_FINI_ARRAY || | |
| 684 | Type == SHT_PREINIT_ARRAY) | |
| 793 | uint32_t type = sec->type; | |
| 794 | if (type == SHT_INIT_ARRAY || type == SHT_FINI_ARRAY || | |
| 795 | type == SHT_PREINIT_ARRAY) | |
| 685 | 796 | return true; |
| 686 | 797 | |
| 687 | 798 | // .got contains pointers to external symbols. They are resolved by |
| 688 | 799 | // the dynamic linker when a module is loaded into memory, and after |
| 689 | 800 | // that they are not expected to change. So, it can be in RELRO. |
| 690 | if (In.Got && Sec == In.Got->getParent()) | |
| 801 | if (in.got && sec == in.got->getParent()) | |
| 691 | 802 | return true; |
| 692 | 803 | |
| 693 | 804 | // .toc is a GOT-ish section for PowerPC64. Their contents are accessed |
| ... | ... | @@ -695,30 +806,30 @@ static bool isRelroSection(const OutputSection *Sec) { |
| 695 | 806 | // for accessing .got as well, .got and .toc need to be close enough in the |
| 696 | 807 | // virtual address space. Usually, .toc comes just after .got. Since we place |
| 697 | 808 | // .got into RELRO, .toc needs to be placed into RELRO too. |
| 698 | if (Sec->Name.equals(".toc")) | |
| 809 | if (sec->name.equals(".toc")) | |
| 699 | 810 | return true; |
| 700 | 811 | |
| 701 | 812 | // .got.plt contains pointers to external function symbols. They are |
| 702 | 813 | // by default resolved lazily, so we usually cannot put it into RELRO. |
| 703 | 814 | // However, if "-z now" is given, the lazy symbol resolution is |
| 704 | 815 | // disabled, which enables us to put it into RELRO. |
| 705 | if (Sec == In.GotPlt->getParent()) | |
| 706 | return Config->ZNow; | |
| 816 | if (sec == in.gotPlt->getParent()) | |
| 817 | return config->zNow; | |
| 707 | 818 | |
| 708 | 819 | // .dynamic section contains data for the dynamic linker, and |
| 709 | 820 | // there's no need to write to it at runtime, so it's better to put |
| 710 | 821 | // it into RELRO. |
| 711 | if (Sec == In.Dynamic->getParent()) | |
| 822 | if (sec->name == ".dynamic") | |
| 712 | 823 | return true; |
| 713 | 824 | |
| 714 | 825 | // Sections with some special names are put into RELRO. This is a |
| 715 | 826 | // bit unfortunate because section names shouldn't be significant in |
| 716 | 827 | // ELF in spirit. But in reality many linker features depend on |
| 717 | 828 | // magic section names. |
| 718 | StringRef S = Sec->Name; | |
| 719 | return S == ".data.rel.ro" || S == ".bss.rel.ro" || S == ".ctors" || | |
| 720 | S == ".dtors" || S == ".jcr" || S == ".eh_frame" || | |
| 721 | S == ".openbsd.randomdata"; | |
| 829 | StringRef s = sec->name; | |
| 830 | return s == ".data.rel.ro" || s == ".bss.rel.ro" || s == ".ctors" || | |
| 831 | s == ".dtors" || s == ".jcr" || s == ".eh_frame" || | |
| 832 | s == ".openbsd.randomdata"; | |
| 722 | 833 | } |
| 723 | 834 | |
| 724 | 835 | // We compute a rank for each section. The rank indicates where the |
| ... | ... | @@ -729,16 +840,18 @@ static bool isRelroSection(const OutputSection *Sec) { |
| 729 | 840 | // * It is easy to check if a give branch was taken. |
| 730 | 841 | // * It is easy two see how similar two ranks are (see getRankProximity). |
| 731 | 842 | enum RankFlags { |
| 732 | RF_NOT_ADDR_SET = 1 << 18, | |
| 733 | RF_NOT_ALLOC = 1 << 17, | |
| 734 | RF_NOT_INTERP = 1 << 16, | |
| 735 | RF_NOT_NOTE = 1 << 15, | |
| 736 | RF_WRITE = 1 << 14, | |
| 737 | RF_EXEC_WRITE = 1 << 13, | |
| 738 | RF_EXEC = 1 << 12, | |
| 739 | RF_RODATA = 1 << 11, | |
| 740 | RF_NON_TLS_BSS = 1 << 10, | |
| 741 | RF_NON_TLS_BSS_RO = 1 << 9, | |
| 843 | RF_NOT_ADDR_SET = 1 << 27, | |
| 844 | RF_NOT_ALLOC = 1 << 26, | |
| 845 | RF_PARTITION = 1 << 18, // Partition number (8 bits) | |
| 846 | RF_NOT_PART_EHDR = 1 << 17, | |
| 847 | RF_NOT_PART_PHDR = 1 << 16, | |
| 848 | RF_NOT_INTERP = 1 << 15, | |
| 849 | RF_NOT_NOTE = 1 << 14, | |
| 850 | RF_WRITE = 1 << 13, | |
| 851 | RF_EXEC_WRITE = 1 << 12, | |
| 852 | RF_EXEC = 1 << 11, | |
| 853 | RF_RODATA = 1 << 10, | |
| 854 | RF_NOT_RELRO = 1 << 9, | |
| 742 | 855 | RF_NOT_TLS = 1 << 8, |
| 743 | 856 | RF_BSS = 1 << 7, |
| 744 | 857 | RF_PPC_NOT_TOCBSS = 1 << 6, |
| ... | ... | @@ -750,33 +863,41 @@ enum RankFlags { |
| 750 | 863 | RF_MIPS_NOT_GOT = 1 << 0 |
| 751 | 864 | }; |
| 752 | 865 | |
| 753 | static unsigned getSectionRank(const OutputSection *Sec) { | |
| 754 | unsigned Rank = 0; | |
| 866 | static unsigned getSectionRank(const OutputSection *sec) { | |
| 867 | unsigned rank = sec->partition * RF_PARTITION; | |
| 755 | 868 | |
| 756 | 869 | // We want to put section specified by -T option first, so we |
| 757 | 870 | // can start assigning VA starting from them later. |
| 758 | if (Config->SectionStartMap.count(Sec->Name)) | |
| 759 | return Rank; | |
| 760 | Rank |= RF_NOT_ADDR_SET; | |
| 871 | if (config->sectionStartMap.count(sec->name)) | |
| 872 | return rank; | |
| 873 | rank |= RF_NOT_ADDR_SET; | |
| 761 | 874 | |
| 762 | 875 | // Allocatable sections go first to reduce the total PT_LOAD size and |
| 763 | 876 | // so debug info doesn't change addresses in actual code. |
| 764 | if (!(Sec->Flags & SHF_ALLOC)) | |
| 765 | return Rank | RF_NOT_ALLOC; | |
| 877 | if (!(sec->flags & SHF_ALLOC)) | |
| 878 | return rank | RF_NOT_ALLOC; | |
| 879 | ||
| 880 | if (sec->type == SHT_LLVM_PART_EHDR) | |
| 881 | return rank; | |
| 882 | rank |= RF_NOT_PART_EHDR; | |
| 883 | ||
| 884 | if (sec->type == SHT_LLVM_PART_PHDR) | |
| 885 | return rank; | |
| 886 | rank |= RF_NOT_PART_PHDR; | |
| 766 | 887 | |
| 767 | 888 | // Put .interp first because some loaders want to see that section |
| 768 | 889 | // on the first page of the executable file when loaded into memory. |
| 769 | if (Sec->Name == ".interp") | |
| 770 | return Rank; | |
| 771 | Rank |= RF_NOT_INTERP; | |
| 890 | if (sec->name == ".interp") | |
| 891 | return rank; | |
| 892 | rank |= RF_NOT_INTERP; | |
| 772 | 893 | |
| 773 | 894 | // Put .note sections (which make up one PT_NOTE) at the beginning so that |
| 774 | 895 | // they are likely to be included in a core file even if core file size is |
| 775 | 896 | // limited. In particular, we want a .note.gnu.build-id and a .note.tag to be |
| 776 | 897 | // included in a core to match core files with executables. |
| 777 | if (Sec->Type == SHT_NOTE) | |
| 778 | return Rank; | |
| 779 | Rank |= RF_NOT_NOTE; | |
| 898 | if (sec->type == SHT_NOTE) | |
| 899 | return rank; | |
| 900 | rank |= RF_NOT_NOTE; | |
| 780 | 901 | |
| 781 | 902 | // Sort sections based on their access permission in the following |
| 782 | 903 | // order: R, RX, RWX, RW. This order is based on the following |
| ... | ... | @@ -789,116 +910,105 @@ static unsigned getSectionRank(const OutputSection *Sec) { |
| 789 | 910 | // between .text and .data. |
| 790 | 911 | // * Writable sections come last, such that .bss lands at the very |
| 791 | 912 | // end of the last PT_LOAD. |
| 792 | bool IsExec = Sec->Flags & SHF_EXECINSTR; | |
| 793 | bool IsWrite = Sec->Flags & SHF_WRITE; | |
| 913 | bool isExec = sec->flags & SHF_EXECINSTR; | |
| 914 | bool isWrite = sec->flags & SHF_WRITE; | |
| 794 | 915 | |
| 795 | if (IsExec) { | |
| 796 | if (IsWrite) | |
| 797 | Rank |= RF_EXEC_WRITE; | |
| 916 | if (isExec) { | |
| 917 | if (isWrite) | |
| 918 | rank |= RF_EXEC_WRITE; | |
| 798 | 919 | else |
| 799 | Rank |= RF_EXEC; | |
| 800 | } else if (IsWrite) { | |
| 801 | Rank |= RF_WRITE; | |
| 802 | } else if (Sec->Type == SHT_PROGBITS) { | |
| 920 | rank |= RF_EXEC; | |
| 921 | } else if (isWrite) { | |
| 922 | rank |= RF_WRITE; | |
| 923 | } else if (sec->type == SHT_PROGBITS) { | |
| 803 | 924 | // Make non-executable and non-writable PROGBITS sections (e.g .rodata |
| 804 | 925 | // .eh_frame) closer to .text. They likely contain PC or GOT relative |
| 805 | 926 | // relocations and there could be relocation overflow if other huge sections |
| 806 | 927 | // (.dynstr .dynsym) were placed in between. |
| 807 | Rank |= RF_RODATA; | |
| 928 | rank |= RF_RODATA; | |
| 808 | 929 | } |
| 809 | 930 | |
| 810 | // If we got here we know that both A and B are in the same PT_LOAD. | |
| 931 | // Place RelRo sections first. After considering SHT_NOBITS below, the | |
| 932 | // ordering is PT_LOAD(PT_GNU_RELRO(.data.rel.ro .bss.rel.ro) | .data .bss), | |
| 933 | // where | marks where page alignment happens. An alternative ordering is | |
| 934 | // PT_LOAD(.data | PT_GNU_RELRO( .data.rel.ro .bss.rel.ro) | .bss), but it may | |
| 935 | // waste more bytes due to 2 alignment places. | |
| 936 | if (!isRelroSection(sec)) | |
| 937 | rank |= RF_NOT_RELRO; | |
| 811 | 938 | |
| 812 | bool IsTls = Sec->Flags & SHF_TLS; | |
| 813 | bool IsNoBits = Sec->Type == SHT_NOBITS; | |
| 814 | ||
| 815 | // The first requirement we have is to put (non-TLS) nobits sections last. The | |
| 816 | // reason is that the only thing the dynamic linker will see about them is a | |
| 817 | // p_memsz that is larger than p_filesz. Seeing that it zeros the end of the | |
| 818 | // PT_LOAD, so that has to correspond to the nobits sections. | |
| 819 | bool IsNonTlsNoBits = IsNoBits && !IsTls; | |
| 820 | if (IsNonTlsNoBits) | |
| 821 | Rank |= RF_NON_TLS_BSS; | |
| 822 | ||
| 823 | // We place nobits RelRo sections before plain r/w ones, and non-nobits RelRo | |
| 824 | // sections after r/w ones, so that the RelRo sections are contiguous. | |
| 825 | bool IsRelRo = isRelroSection(Sec); | |
| 826 | if (IsNonTlsNoBits && !IsRelRo) | |
| 827 | Rank |= RF_NON_TLS_BSS_RO; | |
| 828 | if (!IsNonTlsNoBits && IsRelRo) | |
| 829 | Rank |= RF_NON_TLS_BSS_RO; | |
| 939 | // If we got here we know that both A and B are in the same PT_LOAD. | |
| 830 | 940 | |
| 831 | 941 | // The TLS initialization block needs to be a single contiguous block in a R/W |
| 832 | 942 | // PT_LOAD, so stick TLS sections directly before the other RelRo R/W |
| 833 | // sections. The TLS NOBITS sections are placed here as they don't take up | |
| 834 | // virtual address space in the PT_LOAD. | |
| 835 | if (!IsTls) | |
| 836 | Rank |= RF_NOT_TLS; | |
| 943 | // sections. Since p_filesz can be less than p_memsz, place NOBITS sections | |
| 944 | // after PROGBITS. | |
| 945 | if (!(sec->flags & SHF_TLS)) | |
| 946 | rank |= RF_NOT_TLS; | |
| 837 | 947 | |
| 838 | // Within the TLS initialization block, the non-nobits sections need to appear | |
| 839 | // first. | |
| 840 | if (IsNoBits) | |
| 841 | Rank |= RF_BSS; | |
| 948 | // Within TLS sections, or within other RelRo sections, or within non-RelRo | |
| 949 | // sections, place non-NOBITS sections first. | |
| 950 | if (sec->type == SHT_NOBITS) | |
| 951 | rank |= RF_BSS; | |
| 842 | 952 | |
| 843 | 953 | // Some architectures have additional ordering restrictions for sections |
| 844 | 954 | // within the same PT_LOAD. |
| 845 | if (Config->EMachine == EM_PPC64) { | |
| 955 | if (config->emachine == EM_PPC64) { | |
| 846 | 956 | // PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections |
| 847 | 957 | // that we would like to make sure appear is a specific order to maximize |
| 848 | 958 | // their coverage by a single signed 16-bit offset from the TOC base |
| 849 | 959 | // pointer. Conversely, the special .tocbss section should be first among |
| 850 | 960 | // all SHT_NOBITS sections. This will put it next to the loaded special |
| 851 | 961 | // PPC64 sections (and, thus, within reach of the TOC base pointer). |
| 852 | StringRef Name = Sec->Name; | |
| 853 | if (Name != ".tocbss") | |
| 854 | Rank |= RF_PPC_NOT_TOCBSS; | |
| 962 | StringRef name = sec->name; | |
| 963 | if (name != ".tocbss") | |
| 964 | rank |= RF_PPC_NOT_TOCBSS; | |
| 855 | 965 | |
| 856 | if (Name == ".toc1") | |
| 857 | Rank |= RF_PPC_TOCL; | |
| 966 | if (name == ".toc1") | |
| 967 | rank |= RF_PPC_TOCL; | |
| 858 | 968 | |
| 859 | if (Name == ".toc") | |
| 860 | Rank |= RF_PPC_TOC; | |
| 969 | if (name == ".toc") | |
| 970 | rank |= RF_PPC_TOC; | |
| 861 | 971 | |
| 862 | if (Name == ".got") | |
| 863 | Rank |= RF_PPC_GOT; | |
| 972 | if (name == ".got") | |
| 973 | rank |= RF_PPC_GOT; | |
| 864 | 974 | |
| 865 | if (Name == ".branch_lt") | |
| 866 | Rank |= RF_PPC_BRANCH_LT; | |
| 975 | if (name == ".branch_lt") | |
| 976 | rank |= RF_PPC_BRANCH_LT; | |
| 867 | 977 | } |
| 868 | 978 | |
| 869 | if (Config->EMachine == EM_MIPS) { | |
| 979 | if (config->emachine == EM_MIPS) { | |
| 870 | 980 | // All sections with SHF_MIPS_GPREL flag should be grouped together |
| 871 | 981 | // because data in these sections is addressable with a gp relative address. |
| 872 | if (Sec->Flags & SHF_MIPS_GPREL) | |
| 873 | Rank |= RF_MIPS_GPREL; | |
| 982 | if (sec->flags & SHF_MIPS_GPREL) | |
| 983 | rank |= RF_MIPS_GPREL; | |
| 874 | 984 | |
| 875 | if (Sec->Name != ".got") | |
| 876 | Rank |= RF_MIPS_NOT_GOT; | |
| 985 | if (sec->name != ".got") | |
| 986 | rank |= RF_MIPS_NOT_GOT; | |
| 877 | 987 | } |
| 878 | 988 | |
| 879 | return Rank; | |
| 989 | return rank; | |
| 880 | 990 | } |
| 881 | 991 | |
| 882 | static bool compareSections(const BaseCommand *ACmd, const BaseCommand *BCmd) { | |
| 883 | const OutputSection *A = cast<OutputSection>(ACmd); | |
| 884 | const OutputSection *B = cast<OutputSection>(BCmd); | |
| 992 | static bool compareSections(const BaseCommand *aCmd, const BaseCommand *bCmd) { | |
| 993 | const OutputSection *a = cast<OutputSection>(aCmd); | |
| 994 | const OutputSection *b = cast<OutputSection>(bCmd); | |
| 885 | 995 | |
| 886 | if (A->SortRank != B->SortRank) | |
| 887 | return A->SortRank < B->SortRank; | |
| 996 | if (a->sortRank != b->sortRank) | |
| 997 | return a->sortRank < b->sortRank; | |
| 888 | 998 | |
| 889 | if (!(A->SortRank & RF_NOT_ADDR_SET)) | |
| 890 | return Config->SectionStartMap.lookup(A->Name) < | |
| 891 | Config->SectionStartMap.lookup(B->Name); | |
| 999 | if (!(a->sortRank & RF_NOT_ADDR_SET)) | |
| 1000 | return config->sectionStartMap.lookup(a->name) < | |
| 1001 | config->sectionStartMap.lookup(b->name); | |
| 892 | 1002 | return false; |
| 893 | 1003 | } |
| 894 | 1004 | |
| 895 | void PhdrEntry::add(OutputSection *Sec) { | |
| 896 | LastSec = Sec; | |
| 897 | if (!FirstSec) | |
| 898 | FirstSec = Sec; | |
| 899 | p_align = std::max(p_align, Sec->Alignment); | |
| 1005 | void PhdrEntry::add(OutputSection *sec) { | |
| 1006 | lastSec = sec; | |
| 1007 | if (!firstSec) | |
| 1008 | firstSec = sec; | |
| 1009 | p_align = std::max(p_align, sec->alignment); | |
| 900 | 1010 | if (p_type == PT_LOAD) |
| 901 | Sec->PtLoad = this; | |
| 1011 | sec->ptLoad = this; | |
| 902 | 1012 | } |
| 903 | 1013 | |
| 904 | 1014 | // The beginning and the ending of .rel[a].plt section are marked |
| ... | ... | @@ -908,35 +1018,40 @@ void PhdrEntry::add(OutputSection *Sec) { |
| 908 | 1018 | // need these symbols, since IRELATIVE relocs are resolved through GOT |
| 909 | 1019 | // and PLT. For details, see http://www.airs.com/blog/archives/403. |
| 910 | 1020 | template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() { |
| 911 | if (Config->Relocatable || needsInterpSection()) | |
| 1021 | if (config->relocatable || needsInterpSection()) | |
| 912 | 1022 | return; |
| 913 | 1023 | |
| 914 | 1024 | // By default, __rela_iplt_{start,end} belong to a dummy section 0 |
| 915 | 1025 | // because .rela.plt might be empty and thus removed from output. |
| 916 | // We'll override Out::ElfHeader with In.RelaIplt later when we are | |
| 1026 | // We'll override Out::elfHeader with In.relaIplt later when we are | |
| 917 | 1027 | // sure that .rela.plt exists in output. |
| 918 | ElfSym::RelaIpltStart = addOptionalRegular( | |
| 919 | Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start", | |
| 920 | Out::ElfHeader, 0, STV_HIDDEN, STB_WEAK); | |
| 1028 | ElfSym::relaIpltStart = addOptionalRegular( | |
| 1029 | config->isRela ? "__rela_iplt_start" : "__rel_iplt_start", | |
| 1030 | Out::elfHeader, 0, STV_HIDDEN, STB_WEAK); | |
| 921 | 1031 | |
| 922 | ElfSym::RelaIpltEnd = addOptionalRegular( | |
| 923 | Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end", | |
| 924 | Out::ElfHeader, 0, STV_HIDDEN, STB_WEAK); | |
| 1032 | ElfSym::relaIpltEnd = addOptionalRegular( | |
| 1033 | config->isRela ? "__rela_iplt_end" : "__rel_iplt_end", | |
| 1034 | Out::elfHeader, 0, STV_HIDDEN, STB_WEAK); | |
| 925 | 1035 | } |
| 926 | 1036 | |
| 927 | 1037 | template <class ELFT> |
| 928 | 1038 | void Writer<ELFT>::forEachRelSec( |
| 929 | llvm::function_ref<void(InputSectionBase &)> Fn) { | |
| 1039 | llvm::function_ref<void(InputSectionBase &)> fn) { | |
| 930 | 1040 | // Scan all relocations. Each relocation goes through a series |
| 931 | 1041 | // of tests to determine if it needs special treatment, such as |
| 932 | 1042 | // creating GOT, PLT, copy relocations, etc. |
| 933 | 1043 | // Note that relocations for non-alloc sections are directly |
| 934 | 1044 | // processed by InputSection::relocateNonAlloc. |
| 935 | for (InputSectionBase *IS : InputSections) | |
| 936 | if (IS->Live && isa<InputSection>(IS) && (IS->Flags & SHF_ALLOC)) | |
| 937 | Fn(*IS); | |
| 938 | for (EhInputSection *ES : In.EhFrame->Sections) | |
| 939 | Fn(*ES); | |
| 1045 | for (InputSectionBase *isec : inputSections) | |
| 1046 | if (isec->isLive() && isa<InputSection>(isec) && (isec->flags & SHF_ALLOC)) | |
| 1047 | fn(*isec); | |
| 1048 | for (Partition &part : partitions) { | |
| 1049 | for (EhInputSection *es : part.ehFrame->sections) | |
| 1050 | fn(*es); | |
| 1051 | if (part.armExidx && part.armExidx->isLive()) | |
| 1052 | for (InputSection *ex : part.armExidx->exidxSections) | |
| 1053 | fn(*ex); | |
| 1054 | } | |
| 940 | 1055 | } |
| 941 | 1056 | |
| 942 | 1057 | // This function generates assignments for predefined symbols (e.g. _end or |
| ... | ... | @@ -945,76 +1060,78 @@ void Writer<ELFT>::forEachRelSec( |
| 945 | 1060 | // time any references to these symbols are processed and is equivalent to |
| 946 | 1061 | // defining these symbols explicitly in the linker script. |
| 947 | 1062 | template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() { |
| 948 | if (ElfSym::GlobalOffsetTable) { | |
| 1063 | if (ElfSym::globalOffsetTable) { | |
| 949 | 1064 | // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention usually |
| 950 | 1065 | // to the start of the .got or .got.plt section. |
| 951 | InputSection *GotSection = In.GotPlt; | |
| 952 | if (!Target->GotBaseSymInGotPlt) | |
| 953 | GotSection = In.MipsGot ? cast<InputSection>(In.MipsGot) | |
| 954 | : cast<InputSection>(In.Got); | |
| 955 | ElfSym::GlobalOffsetTable->Section = GotSection; | |
| 1066 | InputSection *gotSection = in.gotPlt; | |
| 1067 | if (!target->gotBaseSymInGotPlt) | |
| 1068 | gotSection = in.mipsGot ? cast<InputSection>(in.mipsGot) | |
| 1069 | : cast<InputSection>(in.got); | |
| 1070 | ElfSym::globalOffsetTable->section = gotSection; | |
| 956 | 1071 | } |
| 957 | 1072 | |
| 958 | 1073 | // .rela_iplt_{start,end} mark the start and the end of .rela.plt section. |
| 959 | if (ElfSym::RelaIpltStart && !In.RelaIplt->empty()) { | |
| 960 | ElfSym::RelaIpltStart->Section = In.RelaIplt; | |
| 961 | ElfSym::RelaIpltEnd->Section = In.RelaIplt; | |
| 962 | ElfSym::RelaIpltEnd->Value = In.RelaIplt->getSize(); | |
| 1074 | if (ElfSym::relaIpltStart && in.relaIplt->isNeeded()) { | |
| 1075 | ElfSym::relaIpltStart->section = in.relaIplt; | |
| 1076 | ElfSym::relaIpltEnd->section = in.relaIplt; | |
| 1077 | ElfSym::relaIpltEnd->value = in.relaIplt->getSize(); | |
| 963 | 1078 | } |
| 964 | 1079 | |
| 965 | PhdrEntry *Last = nullptr; | |
| 966 | PhdrEntry *LastRO = nullptr; | |
| 1080 | PhdrEntry *last = nullptr; | |
| 1081 | PhdrEntry *lastRO = nullptr; | |
| 967 | 1082 | |
| 968 | for (PhdrEntry *P : Phdrs) { | |
| 969 | if (P->p_type != PT_LOAD) | |
| 970 | continue; | |
| 971 | Last = P; | |
| 972 | if (!(P->p_flags & PF_W)) | |
| 973 | LastRO = P; | |
| 1083 | for (Partition &part : partitions) { | |
| 1084 | for (PhdrEntry *p : part.phdrs) { | |
| 1085 | if (p->p_type != PT_LOAD) | |
| 1086 | continue; | |
| 1087 | last = p; | |
| 1088 | if (!(p->p_flags & PF_W)) | |
| 1089 | lastRO = p; | |
| 1090 | } | |
| 974 | 1091 | } |
| 975 | 1092 | |
| 976 | if (LastRO) { | |
| 1093 | if (lastRO) { | |
| 977 | 1094 | // _etext is the first location after the last read-only loadable segment. |
| 978 | if (ElfSym::Etext1) | |
| 979 | ElfSym::Etext1->Section = LastRO->LastSec; | |
| 980 | if (ElfSym::Etext2) | |
| 981 | ElfSym::Etext2->Section = LastRO->LastSec; | |
| 1095 | if (ElfSym::etext1) | |
| 1096 | ElfSym::etext1->section = lastRO->lastSec; | |
| 1097 | if (ElfSym::etext2) | |
| 1098 | ElfSym::etext2->section = lastRO->lastSec; | |
| 982 | 1099 | } |
| 983 | 1100 | |
| 984 | if (Last) { | |
| 1101 | if (last) { | |
| 985 | 1102 | // _edata points to the end of the last mapped initialized section. |
| 986 | OutputSection *Edata = nullptr; | |
| 987 | for (OutputSection *OS : OutputSections) { | |
| 988 | if (OS->Type != SHT_NOBITS) | |
| 989 | Edata = OS; | |
| 990 | if (OS == Last->LastSec) | |
| 1103 | OutputSection *edata = nullptr; | |
| 1104 | for (OutputSection *os : outputSections) { | |
| 1105 | if (os->type != SHT_NOBITS) | |
| 1106 | edata = os; | |
| 1107 | if (os == last->lastSec) | |
| 991 | 1108 | break; |
| 992 | 1109 | } |
| 993 | 1110 | |
| 994 | if (ElfSym::Edata1) | |
| 995 | ElfSym::Edata1->Section = Edata; | |
| 996 | if (ElfSym::Edata2) | |
| 997 | ElfSym::Edata2->Section = Edata; | |
| 1111 | if (ElfSym::edata1) | |
| 1112 | ElfSym::edata1->section = edata; | |
| 1113 | if (ElfSym::edata2) | |
| 1114 | ElfSym::edata2->section = edata; | |
| 998 | 1115 | |
| 999 | 1116 | // _end is the first location after the uninitialized data region. |
| 1000 | if (ElfSym::End1) | |
| 1001 | ElfSym::End1->Section = Last->LastSec; | |
| 1002 | if (ElfSym::End2) | |
| 1003 | ElfSym::End2->Section = Last->LastSec; | |
| 1117 | if (ElfSym::end1) | |
| 1118 | ElfSym::end1->section = last->lastSec; | |
| 1119 | if (ElfSym::end2) | |
| 1120 | ElfSym::end2->section = last->lastSec; | |
| 1004 | 1121 | } |
| 1005 | 1122 | |
| 1006 | if (ElfSym::Bss) | |
| 1007 | ElfSym::Bss->Section = findSection(".bss"); | |
| 1123 | if (ElfSym::bss) | |
| 1124 | ElfSym::bss->section = findSection(".bss"); | |
| 1008 | 1125 | |
| 1009 | 1126 | // Setup MIPS _gp_disp/__gnu_local_gp symbols which should |
| 1010 | 1127 | // be equal to the _gp symbol's value. |
| 1011 | if (ElfSym::MipsGp) { | |
| 1128 | if (ElfSym::mipsGp) { | |
| 1012 | 1129 | // Find GP-relative section with the lowest address |
| 1013 | 1130 | // and use this address to calculate default _gp value. |
| 1014 | for (OutputSection *OS : OutputSections) { | |
| 1015 | if (OS->Flags & SHF_MIPS_GPREL) { | |
| 1016 | ElfSym::MipsGp->Section = OS; | |
| 1017 | ElfSym::MipsGp->Value = 0x7ff0; | |
| 1131 | for (OutputSection *os : outputSections) { | |
| 1132 | if (os->flags & SHF_MIPS_GPREL) { | |
| 1133 | ElfSym::mipsGp->section = os; | |
| 1134 | ElfSym::mipsGp->value = 0x7ff0; | |
| 1018 | 1135 | break; |
| 1019 | 1136 | } |
| 1020 | 1137 | } |
| ... | ... | @@ -1025,14 +1142,13 @@ template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() { |
| 1025 | 1142 | // The more branches in getSectionRank that match, the more similar they are. |
| 1026 | 1143 | // Since each branch corresponds to a bit flag, we can just use |
| 1027 | 1144 | // countLeadingZeros. |
| 1028 | static int getRankProximityAux(OutputSection *A, OutputSection *B) { | |
| 1029 | return countLeadingZeros(A->SortRank ^ B->SortRank); | |
| 1145 | static int getRankProximityAux(OutputSection *a, OutputSection *b) { | |
| 1146 | return countLeadingZeros(a->sortRank ^ b->sortRank); | |
| 1030 | 1147 | } |
| 1031 | 1148 | |
| 1032 | static int getRankProximity(OutputSection *A, BaseCommand *B) { | |
| 1033 | if (auto *Sec = dyn_cast<OutputSection>(B)) | |
| 1034 | return getRankProximityAux(A, Sec); | |
| 1035 | return -1; | |
| 1149 | static int getRankProximity(OutputSection *a, BaseCommand *b) { | |
| 1150 | auto *sec = dyn_cast<OutputSection>(b); | |
| 1151 | return (sec && sec->hasInputSections) ? getRankProximityAux(a, sec) : -1; | |
| 1036 | 1152 | } |
| 1037 | 1153 | |
| 1038 | 1154 | // When placing orphan sections, we want to place them after symbol assignments |
| ... | ... | @@ -1049,137 +1165,142 @@ static int getRankProximity(OutputSection *A, BaseCommand *B) { |
| 1049 | 1165 | // /* The RW PT_LOAD starts here*/ |
| 1050 | 1166 | // rw_sec : { *(rw_sec) } |
| 1051 | 1167 | // would mean that the RW PT_LOAD would become unaligned. |
| 1052 | static bool shouldSkip(BaseCommand *Cmd) { | |
| 1053 | if (auto *Assign = dyn_cast<SymbolAssignment>(Cmd)) | |
| 1054 | return Assign->Name != "."; | |
| 1168 | static bool shouldSkip(BaseCommand *cmd) { | |
| 1169 | if (auto *assign = dyn_cast<SymbolAssignment>(cmd)) | |
| 1170 | return assign->name != "."; | |
| 1055 | 1171 | return false; |
| 1056 | 1172 | } |
| 1057 | 1173 | |
| 1058 | 1174 | // We want to place orphan sections so that they share as much |
| 1059 | 1175 | // characteristics with their neighbors as possible. For example, if |
| 1060 | 1176 | // both are rw, or both are tls. |
| 1061 | template <typename ELFT> | |
| 1062 | 1177 | static std::vector<BaseCommand *>::iterator |
| 1063 | findOrphanPos(std::vector<BaseCommand *>::iterator B, | |
| 1064 | std::vector<BaseCommand *>::iterator E) { | |
| 1065 | OutputSection *Sec = cast<OutputSection>(*E); | |
| 1178 | findOrphanPos(std::vector<BaseCommand *>::iterator b, | |
| 1179 | std::vector<BaseCommand *>::iterator e) { | |
| 1180 | OutputSection *sec = cast<OutputSection>(*e); | |
| 1066 | 1181 | |
| 1067 | 1182 | // Find the first element that has as close a rank as possible. |
| 1068 | auto I = std::max_element(B, E, [=](BaseCommand *A, BaseCommand *B) { | |
| 1069 | return getRankProximity(Sec, A) < getRankProximity(Sec, B); | |
| 1183 | auto i = std::max_element(b, e, [=](BaseCommand *a, BaseCommand *b) { | |
| 1184 | return getRankProximity(sec, a) < getRankProximity(sec, b); | |
| 1070 | 1185 | }); |
| 1071 | if (I == E) | |
| 1072 | return E; | |
| 1186 | if (i == e) | |
| 1187 | return e; | |
| 1073 | 1188 | |
| 1074 | 1189 | // Consider all existing sections with the same proximity. |
| 1075 | int Proximity = getRankProximity(Sec, *I); | |
| 1076 | for (; I != E; ++I) { | |
| 1077 | auto *CurSec = dyn_cast<OutputSection>(*I); | |
| 1078 | if (!CurSec) | |
| 1190 | int proximity = getRankProximity(sec, *i); | |
| 1191 | for (; i != e; ++i) { | |
| 1192 | auto *curSec = dyn_cast<OutputSection>(*i); | |
| 1193 | if (!curSec || !curSec->hasInputSections) | |
| 1079 | 1194 | continue; |
| 1080 | if (getRankProximity(Sec, CurSec) != Proximity || | |
| 1081 | Sec->SortRank < CurSec->SortRank) | |
| 1195 | if (getRankProximity(sec, curSec) != proximity || | |
| 1196 | sec->sortRank < curSec->sortRank) | |
| 1082 | 1197 | break; |
| 1083 | 1198 | } |
| 1084 | 1199 | |
| 1085 | auto IsOutputSec = [](BaseCommand *Cmd) { return isa<OutputSection>(Cmd); }; | |
| 1086 | auto J = std::find_if(llvm::make_reverse_iterator(I), | |
| 1087 | llvm::make_reverse_iterator(B), IsOutputSec); | |
| 1088 | I = J.base(); | |
| 1200 | auto isOutputSecWithInputSections = [](BaseCommand *cmd) { | |
| 1201 | auto *os = dyn_cast<OutputSection>(cmd); | |
| 1202 | return os && os->hasInputSections; | |
| 1203 | }; | |
| 1204 | auto j = std::find_if(llvm::make_reverse_iterator(i), | |
| 1205 | llvm::make_reverse_iterator(b), | |
| 1206 | isOutputSecWithInputSections); | |
| 1207 | i = j.base(); | |
| 1089 | 1208 | |
| 1090 | 1209 | // As a special case, if the orphan section is the last section, put |
| 1091 | 1210 | // it at the very end, past any other commands. |
| 1092 | 1211 | // This matches bfd's behavior and is convenient when the linker script fully |
| 1093 | 1212 | // specifies the start of the file, but doesn't care about the end (the non |
| 1094 | 1213 | // alloc sections for example). |
| 1095 | auto NextSec = std::find_if(I, E, IsOutputSec); | |
| 1096 | if (NextSec == E) | |
| 1097 | return E; | |
| 1214 | auto nextSec = std::find_if(i, e, isOutputSecWithInputSections); | |
| 1215 | if (nextSec == e) | |
| 1216 | return e; | |
| 1098 | 1217 | |
| 1099 | while (I != E && shouldSkip(*I)) | |
| 1100 | ++I; | |
| 1101 | return I; | |
| 1218 | while (i != e && shouldSkip(*i)) | |
| 1219 | ++i; | |
| 1220 | return i; | |
| 1102 | 1221 | } |
| 1103 | 1222 | |
| 1104 | 1223 | // Builds section order for handling --symbol-ordering-file. |
| 1105 | 1224 | static DenseMap<const InputSectionBase *, int> buildSectionOrder() { |
| 1106 | DenseMap<const InputSectionBase *, int> SectionOrder; | |
| 1225 | DenseMap<const InputSectionBase *, int> sectionOrder; | |
| 1107 | 1226 | // Use the rarely used option -call-graph-ordering-file to sort sections. |
| 1108 | if (!Config->CallGraphProfile.empty()) | |
| 1227 | if (!config->callGraphProfile.empty()) | |
| 1109 | 1228 | return computeCallGraphProfileOrder(); |
| 1110 | 1229 | |
| 1111 | if (Config->SymbolOrderingFile.empty()) | |
| 1112 | return SectionOrder; | |
| 1230 | if (config->symbolOrderingFile.empty()) | |
| 1231 | return sectionOrder; | |
| 1113 | 1232 | |
| 1114 | 1233 | struct SymbolOrderEntry { |
| 1115 | int Priority; | |
| 1116 | bool Present; | |
| 1234 | int priority; | |
| 1235 | bool present; | |
| 1117 | 1236 | }; |
| 1118 | 1237 | |
| 1119 | 1238 | // Build a map from symbols to their priorities. Symbols that didn't |
| 1120 | 1239 | // appear in the symbol ordering file have the lowest priority 0. |
| 1121 | 1240 | // All explicitly mentioned symbols have negative (higher) priorities. |
| 1122 | DenseMap<StringRef, SymbolOrderEntry> SymbolOrder; | |
| 1123 | int Priority = -Config->SymbolOrderingFile.size(); | |
| 1124 | for (StringRef S : Config->SymbolOrderingFile) | |
| 1125 | SymbolOrder.insert({S, {Priority++, false}}); | |
| 1241 | DenseMap<StringRef, SymbolOrderEntry> symbolOrder; | |
| 1242 | int priority = -config->symbolOrderingFile.size(); | |
| 1243 | for (StringRef s : config->symbolOrderingFile) | |
| 1244 | symbolOrder.insert({s, {priority++, false}}); | |
| 1126 | 1245 | |
| 1127 | 1246 | // Build a map from sections to their priorities. |
| 1128 | auto AddSym = [&](Symbol &Sym) { | |
| 1129 | auto It = SymbolOrder.find(Sym.getName()); | |
| 1130 | if (It == SymbolOrder.end()) | |
| 1247 | auto addSym = [&](Symbol &sym) { | |
| 1248 | auto it = symbolOrder.find(sym.getName()); | |
| 1249 | if (it == symbolOrder.end()) | |
| 1131 | 1250 | return; |
| 1132 | SymbolOrderEntry &Ent = It->second; | |
| 1133 | Ent.Present = true; | |
| 1251 | SymbolOrderEntry &ent = it->second; | |
| 1252 | ent.present = true; | |
| 1134 | 1253 | |
| 1135 | maybeWarnUnorderableSymbol(&Sym); | |
| 1254 | maybeWarnUnorderableSymbol(&sym); | |
| 1136 | 1255 | |
| 1137 | if (auto *D = dyn_cast<Defined>(&Sym)) { | |
| 1138 | if (auto *Sec = dyn_cast_or_null<InputSectionBase>(D->Section)) { | |
| 1139 | int &Priority = SectionOrder[cast<InputSectionBase>(Sec->Repl)]; | |
| 1140 | Priority = std::min(Priority, Ent.Priority); | |
| 1256 | if (auto *d = dyn_cast<Defined>(&sym)) { | |
| 1257 | if (auto *sec = dyn_cast_or_null<InputSectionBase>(d->section)) { | |
| 1258 | int &priority = sectionOrder[cast<InputSectionBase>(sec->repl)]; | |
| 1259 | priority = std::min(priority, ent.priority); | |
| 1141 | 1260 | } |
| 1142 | 1261 | } |
| 1143 | 1262 | }; |
| 1144 | 1263 | |
| 1145 | 1264 | // We want both global and local symbols. We get the global ones from the |
| 1146 | 1265 | // symbol table and iterate the object files for the local ones. |
| 1147 | for (Symbol *Sym : Symtab->getSymbols()) | |
| 1148 | if (!Sym->isLazy()) | |
| 1149 | AddSym(*Sym); | |
| 1150 | for (InputFile *File : ObjectFiles) | |
| 1151 | for (Symbol *Sym : File->getSymbols()) | |
| 1152 | if (Sym->isLocal()) | |
| 1153 | AddSym(*Sym); | |
| 1266 | symtab->forEachSymbol([&](Symbol *sym) { | |
| 1267 | if (!sym->isLazy()) | |
| 1268 | addSym(*sym); | |
| 1269 | }); | |
| 1154 | 1270 | |
| 1155 | if (Config->WarnSymbolOrdering) | |
| 1156 | for (auto OrderEntry : SymbolOrder) | |
| 1157 | if (!OrderEntry.second.Present) | |
| 1158 | warn("symbol ordering file: no such symbol: " + OrderEntry.first); | |
| 1271 | for (InputFile *file : objectFiles) | |
| 1272 | for (Symbol *sym : file->getSymbols()) | |
| 1273 | if (sym->isLocal()) | |
| 1274 | addSym(*sym); | |
| 1159 | 1275 | |
| 1160 | return SectionOrder; | |
| 1276 | if (config->warnSymbolOrdering) | |
| 1277 | for (auto orderEntry : symbolOrder) | |
| 1278 | if (!orderEntry.second.present) | |
| 1279 | warn("symbol ordering file: no such symbol: " + orderEntry.first); | |
| 1280 | ||
| 1281 | return sectionOrder; | |
| 1161 | 1282 | } |
| 1162 | 1283 | |
| 1163 | 1284 | // Sorts the sections in ISD according to the provided section order. |
| 1164 | 1285 | static void |
| 1165 | sortISDBySectionOrder(InputSectionDescription *ISD, | |
| 1166 | const DenseMap<const InputSectionBase *, int> &Order) { | |
| 1167 | std::vector<InputSection *> UnorderedSections; | |
| 1168 | std::vector<std::pair<InputSection *, int>> OrderedSections; | |
| 1169 | uint64_t UnorderedSize = 0; | |
| 1170 | ||
| 1171 | for (InputSection *IS : ISD->Sections) { | |
| 1172 | auto I = Order.find(IS); | |
| 1173 | if (I == Order.end()) { | |
| 1174 | UnorderedSections.push_back(IS); | |
| 1175 | UnorderedSize += IS->getSize(); | |
| 1286 | sortISDBySectionOrder(InputSectionDescription *isd, | |
| 1287 | const DenseMap<const InputSectionBase *, int> &order) { | |
| 1288 | std::vector<InputSection *> unorderedSections; | |
| 1289 | std::vector<std::pair<InputSection *, int>> orderedSections; | |
| 1290 | uint64_t unorderedSize = 0; | |
| 1291 | ||
| 1292 | for (InputSection *isec : isd->sections) { | |
| 1293 | auto i = order.find(isec); | |
| 1294 | if (i == order.end()) { | |
| 1295 | unorderedSections.push_back(isec); | |
| 1296 | unorderedSize += isec->getSize(); | |
| 1176 | 1297 | continue; |
| 1177 | 1298 | } |
| 1178 | OrderedSections.push_back({IS, I->second}); | |
| 1299 | orderedSections.push_back({isec, i->second}); | |
| 1179 | 1300 | } |
| 1180 | llvm::sort(OrderedSections, [&](std::pair<InputSection *, int> A, | |
| 1181 | std::pair<InputSection *, int> B) { | |
| 1182 | return A.second < B.second; | |
| 1301 | llvm::sort(orderedSections, [&](std::pair<InputSection *, int> a, | |
| 1302 | std::pair<InputSection *, int> b) { | |
| 1303 | return a.second < b.second; | |
| 1183 | 1304 | }); |
| 1184 | 1305 | |
| 1185 | 1306 | // Find an insertion point for the ordered section list in the unordered |
| ... | ... | @@ -1209,96 +1330,114 @@ sortISDBySectionOrder(InputSectionDescription *ISD, |
| 1209 | 1330 | // of the second block of cold code can call the hot code without a thunk. So |
| 1210 | 1331 | // we effectively double the amount of code that could potentially call into |
| 1211 | 1332 | // the hot code without a thunk. |
| 1212 | size_t InsPt = 0; | |
| 1213 | if (Target->getThunkSectionSpacing() && !OrderedSections.empty()) { | |
| 1214 | uint64_t UnorderedPos = 0; | |
| 1215 | for (; InsPt != UnorderedSections.size(); ++InsPt) { | |
| 1216 | UnorderedPos += UnorderedSections[InsPt]->getSize(); | |
| 1217 | if (UnorderedPos > UnorderedSize / 2) | |
| 1333 | size_t insPt = 0; | |
| 1334 | if (target->getThunkSectionSpacing() && !orderedSections.empty()) { | |
| 1335 | uint64_t unorderedPos = 0; | |
| 1336 | for (; insPt != unorderedSections.size(); ++insPt) { | |
| 1337 | unorderedPos += unorderedSections[insPt]->getSize(); | |
| 1338 | if (unorderedPos > unorderedSize / 2) | |
| 1218 | 1339 | break; |
| 1219 | 1340 | } |
| 1220 | 1341 | } |
| 1221 | 1342 | |
| 1222 | ISD->Sections.clear(); | |
| 1223 | for (InputSection *IS : makeArrayRef(UnorderedSections).slice(0, InsPt)) | |
| 1224 | ISD->Sections.push_back(IS); | |
| 1225 | for (std::pair<InputSection *, int> P : OrderedSections) | |
| 1226 | ISD->Sections.push_back(P.first); | |
| 1227 | for (InputSection *IS : makeArrayRef(UnorderedSections).slice(InsPt)) | |
| 1228 | ISD->Sections.push_back(IS); | |
| 1343 | isd->sections.clear(); | |
| 1344 | for (InputSection *isec : makeArrayRef(unorderedSections).slice(0, insPt)) | |
| 1345 | isd->sections.push_back(isec); | |
| 1346 | for (std::pair<InputSection *, int> p : orderedSections) | |
| 1347 | isd->sections.push_back(p.first); | |
| 1348 | for (InputSection *isec : makeArrayRef(unorderedSections).slice(insPt)) | |
| 1349 | isd->sections.push_back(isec); | |
| 1229 | 1350 | } |
| 1230 | 1351 | |
| 1231 | static void sortSection(OutputSection *Sec, | |
| 1232 | const DenseMap<const InputSectionBase *, int> &Order) { | |
| 1233 | StringRef Name = Sec->Name; | |
| 1352 | static void sortSection(OutputSection *sec, | |
| 1353 | const DenseMap<const InputSectionBase *, int> &order) { | |
| 1354 | StringRef name = sec->name; | |
| 1234 | 1355 | |
| 1235 | 1356 | // Sort input sections by section name suffixes for |
| 1236 | 1357 | // __attribute__((init_priority(N))). |
| 1237 | if (Name == ".init_array" || Name == ".fini_array") { | |
| 1238 | if (!Script->HasSectionsCommand) | |
| 1239 | Sec->sortInitFini(); | |
| 1358 | if (name == ".init_array" || name == ".fini_array") { | |
| 1359 | if (!script->hasSectionsCommand) | |
| 1360 | sec->sortInitFini(); | |
| 1240 | 1361 | return; |
| 1241 | 1362 | } |
| 1242 | 1363 | |
| 1243 | 1364 | // Sort input sections by the special rule for .ctors and .dtors. |
| 1244 | if (Name == ".ctors" || Name == ".dtors") { | |
| 1245 | if (!Script->HasSectionsCommand) | |
| 1246 | Sec->sortCtorsDtors(); | |
| 1365 | if (name == ".ctors" || name == ".dtors") { | |
| 1366 | if (!script->hasSectionsCommand) | |
| 1367 | sec->sortCtorsDtors(); | |
| 1247 | 1368 | return; |
| 1248 | 1369 | } |
| 1249 | 1370 | |
| 1250 | 1371 | // Never sort these. |
| 1251 | if (Name == ".init" || Name == ".fini") | |
| 1372 | if (name == ".init" || name == ".fini") | |
| 1373 | return; | |
| 1374 | ||
| 1375 | // .toc is allocated just after .got and is accessed using GOT-relative | |
| 1376 | // relocations. Object files compiled with small code model have an | |
| 1377 | // addressable range of [.got, .got + 0xFFFC] for GOT-relative relocations. | |
| 1378 | // To reduce the risk of relocation overflow, .toc contents are sorted so that | |
| 1379 | // sections having smaller relocation offsets are at beginning of .toc | |
| 1380 | if (config->emachine == EM_PPC64 && name == ".toc") { | |
| 1381 | if (script->hasSectionsCommand) | |
| 1382 | return; | |
| 1383 | assert(sec->sectionCommands.size() == 1); | |
| 1384 | auto *isd = cast<InputSectionDescription>(sec->sectionCommands[0]); | |
| 1385 | llvm::stable_sort(isd->sections, | |
| 1386 | [](const InputSection *a, const InputSection *b) -> bool { | |
| 1387 | return a->file->ppc64SmallCodeModelTocRelocs && | |
| 1388 | !b->file->ppc64SmallCodeModelTocRelocs; | |
| 1389 | }); | |
| 1252 | 1390 | return; |
| 1391 | } | |
| 1253 | 1392 | |
| 1254 | 1393 | // Sort input sections by priority using the list provided |
| 1255 | 1394 | // by --symbol-ordering-file. |
| 1256 | if (!Order.empty()) | |
| 1257 | for (BaseCommand *B : Sec->SectionCommands) | |
| 1258 | if (auto *ISD = dyn_cast<InputSectionDescription>(B)) | |
| 1259 | sortISDBySectionOrder(ISD, Order); | |
| 1395 | if (!order.empty()) | |
| 1396 | for (BaseCommand *b : sec->sectionCommands) | |
| 1397 | if (auto *isd = dyn_cast<InputSectionDescription>(b)) | |
| 1398 | sortISDBySectionOrder(isd, order); | |
| 1260 | 1399 | } |
| 1261 | 1400 | |
| 1262 | 1401 | // If no layout was provided by linker script, we want to apply default |
| 1263 | 1402 | // sorting for special input sections. This also handles --symbol-ordering-file. |
| 1264 | 1403 | template <class ELFT> void Writer<ELFT>::sortInputSections() { |
| 1265 | 1404 | // Build the order once since it is expensive. |
| 1266 | DenseMap<const InputSectionBase *, int> Order = buildSectionOrder(); | |
| 1267 | for (BaseCommand *Base : Script->SectionCommands) | |
| 1268 | if (auto *Sec = dyn_cast<OutputSection>(Base)) | |
| 1269 | sortSection(Sec, Order); | |
| 1405 | DenseMap<const InputSectionBase *, int> order = buildSectionOrder(); | |
| 1406 | for (BaseCommand *base : script->sectionCommands) | |
| 1407 | if (auto *sec = dyn_cast<OutputSection>(base)) | |
| 1408 | sortSection(sec, order); | |
| 1270 | 1409 | } |
| 1271 | 1410 | |
| 1272 | 1411 | template <class ELFT> void Writer<ELFT>::sortSections() { |
| 1273 | Script->adjustSectionsBeforeSorting(); | |
| 1412 | script->adjustSectionsBeforeSorting(); | |
| 1274 | 1413 | |
| 1275 | 1414 | // Don't sort if using -r. It is not necessary and we want to preserve the |
| 1276 | 1415 | // relative order for SHF_LINK_ORDER sections. |
| 1277 | if (Config->Relocatable) | |
| 1416 | if (config->relocatable) | |
| 1278 | 1417 | return; |
| 1279 | 1418 | |
| 1280 | 1419 | sortInputSections(); |
| 1281 | 1420 | |
| 1282 | for (BaseCommand *Base : Script->SectionCommands) { | |
| 1283 | auto *OS = dyn_cast<OutputSection>(Base); | |
| 1284 | if (!OS) | |
| 1421 | for (BaseCommand *base : script->sectionCommands) { | |
| 1422 | auto *os = dyn_cast<OutputSection>(base); | |
| 1423 | if (!os) | |
| 1285 | 1424 | continue; |
| 1286 | OS->SortRank = getSectionRank(OS); | |
| 1425 | os->sortRank = getSectionRank(os); | |
| 1287 | 1426 | |
| 1288 | // We want to assign rude approximation values to OutSecOff fields | |
| 1427 | // We want to assign rude approximation values to outSecOff fields | |
| 1289 | 1428 | // to know the relative order of the input sections. We use it for |
| 1290 | 1429 | // sorting SHF_LINK_ORDER sections. See resolveShfLinkOrder(). |
| 1291 | uint64_t I = 0; | |
| 1292 | for (InputSection *Sec : getInputSections(OS)) | |
| 1293 | Sec->OutSecOff = I++; | |
| 1430 | uint64_t i = 0; | |
| 1431 | for (InputSection *sec : getInputSections(os)) | |
| 1432 | sec->outSecOff = i++; | |
| 1294 | 1433 | } |
| 1295 | 1434 | |
| 1296 | if (!Script->HasSectionsCommand) { | |
| 1435 | if (!script->hasSectionsCommand) { | |
| 1297 | 1436 | // We know that all the OutputSections are contiguous in this case. |
| 1298 | auto IsSection = [](BaseCommand *Base) { return isa<OutputSection>(Base); }; | |
| 1437 | auto isSection = [](BaseCommand *base) { return isa<OutputSection>(base); }; | |
| 1299 | 1438 | std::stable_sort( |
| 1300 | llvm::find_if(Script->SectionCommands, IsSection), | |
| 1301 | llvm::find_if(llvm::reverse(Script->SectionCommands), IsSection).base(), | |
| 1439 | llvm::find_if(script->sectionCommands, isSection), | |
| 1440 | llvm::find_if(llvm::reverse(script->sectionCommands), isSection).base(), | |
| 1302 | 1441 | compareSections); |
| 1303 | 1442 | return; |
| 1304 | 1443 | } |
| ... | ... | @@ -1342,211 +1481,127 @@ template <class ELFT> void Writer<ELFT>::sortSections() { |
| 1342 | 1481 | // after another commands. For the details, look at shouldSkip |
| 1343 | 1482 | // function. |
| 1344 | 1483 | |
| 1345 | auto I = Script->SectionCommands.begin(); | |
| 1346 | auto E = Script->SectionCommands.end(); | |
| 1347 | auto NonScriptI = std::find_if(I, E, [](BaseCommand *Base) { | |
| 1348 | if (auto *Sec = dyn_cast<OutputSection>(Base)) | |
| 1349 | return Sec->SectionIndex == UINT32_MAX; | |
| 1484 | auto i = script->sectionCommands.begin(); | |
| 1485 | auto e = script->sectionCommands.end(); | |
| 1486 | auto nonScriptI = std::find_if(i, e, [](BaseCommand *base) { | |
| 1487 | if (auto *sec = dyn_cast<OutputSection>(base)) | |
| 1488 | return sec->sectionIndex == UINT32_MAX; | |
| 1350 | 1489 | return false; |
| 1351 | 1490 | }); |
| 1352 | 1491 | |
| 1353 | 1492 | // Sort the orphan sections. |
| 1354 | std::stable_sort(NonScriptI, E, compareSections); | |
| 1493 | std::stable_sort(nonScriptI, e, compareSections); | |
| 1355 | 1494 | |
| 1356 | 1495 | // As a horrible special case, skip the first . assignment if it is before any |
| 1357 | 1496 | // section. We do this because it is common to set a load address by starting |
| 1358 | 1497 | // the script with ". = 0xabcd" and the expectation is that every section is |
| 1359 | 1498 | // after that. |
| 1360 | auto FirstSectionOrDotAssignment = | |
| 1361 | std::find_if(I, E, [](BaseCommand *Cmd) { return !shouldSkip(Cmd); }); | |
| 1362 | if (FirstSectionOrDotAssignment != E && | |
| 1363 | isa<SymbolAssignment>(**FirstSectionOrDotAssignment)) | |
| 1364 | ++FirstSectionOrDotAssignment; | |
| 1365 | I = FirstSectionOrDotAssignment; | |
| 1499 | auto firstSectionOrDotAssignment = | |
| 1500 | std::find_if(i, e, [](BaseCommand *cmd) { return !shouldSkip(cmd); }); | |
| 1501 | if (firstSectionOrDotAssignment != e && | |
| 1502 | isa<SymbolAssignment>(**firstSectionOrDotAssignment)) | |
| 1503 | ++firstSectionOrDotAssignment; | |
| 1504 | i = firstSectionOrDotAssignment; | |
| 1366 | 1505 | |
| 1367 | while (NonScriptI != E) { | |
| 1368 | auto Pos = findOrphanPos<ELFT>(I, NonScriptI); | |
| 1369 | OutputSection *Orphan = cast<OutputSection>(*NonScriptI); | |
| 1506 | while (nonScriptI != e) { | |
| 1507 | auto pos = findOrphanPos(i, nonScriptI); | |
| 1508 | OutputSection *orphan = cast<OutputSection>(*nonScriptI); | |
| 1370 | 1509 | |
| 1371 | 1510 | // As an optimization, find all sections with the same sort rank |
| 1372 | 1511 | // and insert them with one rotate. |
| 1373 | unsigned Rank = Orphan->SortRank; | |
| 1374 | auto End = std::find_if(NonScriptI + 1, E, [=](BaseCommand *Cmd) { | |
| 1375 | return cast<OutputSection>(Cmd)->SortRank != Rank; | |
| 1512 | unsigned rank = orphan->sortRank; | |
| 1513 | auto end = std::find_if(nonScriptI + 1, e, [=](BaseCommand *cmd) { | |
| 1514 | return cast<OutputSection>(cmd)->sortRank != rank; | |
| 1376 | 1515 | }); |
| 1377 | std::rotate(Pos, NonScriptI, End); | |
| 1378 | NonScriptI = End; | |
| 1516 | std::rotate(pos, nonScriptI, end); | |
| 1517 | nonScriptI = end; | |
| 1379 | 1518 | } |
| 1380 | 1519 | |
| 1381 | Script->adjustSectionsAfterSorting(); | |
| 1520 | script->adjustSectionsAfterSorting(); | |
| 1382 | 1521 | } |
| 1383 | 1522 | |
| 1384 | static bool compareByFilePosition(InputSection *A, InputSection *B) { | |
| 1385 | // Synthetic, i. e. a sentinel section, should go last. | |
| 1386 | if (A->kind() == InputSectionBase::Synthetic || | |
| 1387 | B->kind() == InputSectionBase::Synthetic) | |
| 1388 | return A->kind() != InputSectionBase::Synthetic; | |
| 1389 | ||
| 1390 | InputSection *LA = A->getLinkOrderDep(); | |
| 1391 | InputSection *LB = B->getLinkOrderDep(); | |
| 1392 | OutputSection *AOut = LA->getParent(); | |
| 1393 | OutputSection *BOut = LB->getParent(); | |
| 1394 | ||
| 1395 | if (AOut != BOut) | |
| 1396 | return AOut->SectionIndex < BOut->SectionIndex; | |
| 1397 | return LA->OutSecOff < LB->OutSecOff; | |
| 1398 | } | |
| 1399 | ||
| 1400 | // This function is used by the --merge-exidx-entries to detect duplicate | |
| 1401 | // .ARM.exidx sections. It is Arm only. | |
| 1402 | // | |
| 1403 | // The .ARM.exidx section is of the form: | |
| 1404 | // | PREL31 offset to function | Unwind instructions for function | | |
| 1405 | // where the unwind instructions are either a small number of unwind | |
| 1406 | // instructions inlined into the table entry, the special CANT_UNWIND value of | |
| 1407 | // 0x1 or a PREL31 offset into a .ARM.extab Section that contains unwind | |
| 1408 | // instructions. | |
| 1409 | // | |
| 1410 | // We return true if all the unwind instructions in the .ARM.exidx entries of | |
| 1411 | // Cur can be merged into the last entry of Prev. | |
| 1412 | static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) { | |
| 1413 | ||
| 1414 | // References to .ARM.Extab Sections have bit 31 clear and are not the | |
| 1415 | // special EXIDX_CANTUNWIND bit-pattern. | |
| 1416 | auto IsExtabRef = [](uint32_t Unwind) { | |
| 1417 | return (Unwind & 0x80000000) == 0 && Unwind != 0x1; | |
| 1418 | }; | |
| 1419 | ||
| 1420 | struct ExidxEntry { | |
| 1421 | ulittle32_t Fn; | |
| 1422 | ulittle32_t Unwind; | |
| 1423 | }; | |
| 1424 | ||
| 1425 | // Get the last table Entry from the previous .ARM.exidx section. | |
| 1426 | const ExidxEntry &PrevEntry = Prev->getDataAs<ExidxEntry>().back(); | |
| 1427 | if (IsExtabRef(PrevEntry.Unwind)) | |
| 1428 | return false; | |
| 1429 | ||
| 1430 | // We consider the unwind instructions of an .ARM.exidx table entry | |
| 1431 | // a duplicate if the previous unwind instructions if: | |
| 1432 | // - Both are the special EXIDX_CANTUNWIND. | |
| 1433 | // - Both are the same inline unwind instructions. | |
| 1434 | // We do not attempt to follow and check links into .ARM.extab tables as | |
| 1435 | // consecutive identical entries are rare and the effort to check that they | |
| 1436 | // are identical is high. | |
| 1523 | static bool compareByFilePosition(InputSection *a, InputSection *b) { | |
| 1524 | InputSection *la = a->getLinkOrderDep(); | |
| 1525 | InputSection *lb = b->getLinkOrderDep(); | |
| 1526 | OutputSection *aOut = la->getParent(); | |
| 1527 | OutputSection *bOut = lb->getParent(); | |
| 1437 | 1528 | |
| 1438 | for (const ExidxEntry Entry : Cur->getDataAs<ExidxEntry>()) | |
| 1439 | if (IsExtabRef(Entry.Unwind) || Entry.Unwind != PrevEntry.Unwind) | |
| 1440 | return false; | |
| 1441 | ||
| 1442 | // All table entries in this .ARM.exidx Section can be merged into the | |
| 1443 | // previous Section. | |
| 1444 | return true; | |
| 1529 | if (aOut != bOut) | |
| 1530 | return aOut->sectionIndex < bOut->sectionIndex; | |
| 1531 | return la->outSecOff < lb->outSecOff; | |
| 1445 | 1532 | } |
| 1446 | 1533 | |
| 1447 | 1534 | template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() { |
| 1448 | for (OutputSection *Sec : OutputSections) { | |
| 1449 | if (!(Sec->Flags & SHF_LINK_ORDER)) | |
| 1535 | for (OutputSection *sec : outputSections) { | |
| 1536 | if (!(sec->flags & SHF_LINK_ORDER)) | |
| 1450 | 1537 | continue; |
| 1451 | 1538 | |
| 1452 | 1539 | // Link order may be distributed across several InputSectionDescriptions |
| 1453 | 1540 | // but sort must consider them all at once. |
| 1454 | std::vector<InputSection **> ScriptSections; | |
| 1455 | std::vector<InputSection *> Sections; | |
| 1456 | for (BaseCommand *Base : Sec->SectionCommands) { | |
| 1457 | if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) { | |
| 1458 | for (InputSection *&IS : ISD->Sections) { | |
| 1459 | ScriptSections.push_back(&IS); | |
| 1460 | Sections.push_back(IS); | |
| 1541 | std::vector<InputSection **> scriptSections; | |
| 1542 | std::vector<InputSection *> sections; | |
| 1543 | for (BaseCommand *base : sec->sectionCommands) { | |
| 1544 | if (auto *isd = dyn_cast<InputSectionDescription>(base)) { | |
| 1545 | for (InputSection *&isec : isd->sections) { | |
| 1546 | scriptSections.push_back(&isec); | |
| 1547 | sections.push_back(isec); | |
| 1461 | 1548 | } |
| 1462 | 1549 | } |
| 1463 | 1550 | } |
| 1464 | std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition); | |
| 1465 | ||
| 1466 | if (!Config->Relocatable && Config->EMachine == EM_ARM && | |
| 1467 | Sec->Type == SHT_ARM_EXIDX) { | |
| 1468 | ||
| 1469 | if (auto *Sentinel = dyn_cast<ARMExidxSentinelSection>(Sections.back())) { | |
| 1470 | assert(Sections.size() >= 2 && | |
| 1471 | "We should create a sentinel section only if there are " | |
| 1472 | "alive regular exidx sections."); | |
| 1473 | 1551 | |
| 1474 | // The last executable section is required to fill the sentinel. | |
| 1475 | // Remember it here so that we don't have to find it again. | |
| 1476 | Sentinel->Highest = Sections[Sections.size() - 2]->getLinkOrderDep(); | |
| 1477 | } | |
| 1478 | ||
| 1479 | // The EHABI for the Arm Architecture permits consecutive identical | |
| 1480 | // table entries to be merged. We use a simple implementation that | |
| 1481 | // removes a .ARM.exidx Input Section if it can be merged into the | |
| 1482 | // previous one. This does not require any rewriting of InputSection | |
| 1483 | // contents but misses opportunities for fine grained deduplication | |
| 1484 | // where only a subset of the InputSection contents can be merged. | |
| 1485 | if (Config->MergeArmExidx) { | |
| 1486 | size_t Prev = 0; | |
| 1487 | // The last one is a sentinel entry which should not be removed. | |
| 1488 | for (size_t I = 1; I < Sections.size() - 1; ++I) { | |
| 1489 | if (isDuplicateArmExidxSec(Sections[Prev], Sections[I])) | |
| 1490 | Sections[I] = nullptr; | |
| 1491 | else | |
| 1492 | Prev = I; | |
| 1493 | } | |
| 1494 | } | |
| 1495 | } | |
| 1552 | // The ARM.exidx section use SHF_LINK_ORDER, but we have consolidated | |
| 1553 | // this processing inside the ARMExidxsyntheticsection::finalizeContents(). | |
| 1554 | if (!config->relocatable && config->emachine == EM_ARM && | |
| 1555 | sec->type == SHT_ARM_EXIDX) | |
| 1556 | continue; | |
| 1496 | 1557 | |
| 1497 | for (int I = 0, N = Sections.size(); I < N; ++I) | |
| 1498 | *ScriptSections[I] = Sections[I]; | |
| 1558 | llvm::stable_sort(sections, compareByFilePosition); | |
| 1499 | 1559 | |
| 1500 | // Remove the Sections we marked as duplicate earlier. | |
| 1501 | for (BaseCommand *Base : Sec->SectionCommands) | |
| 1502 | if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) | |
| 1503 | llvm::erase_if(ISD->Sections, [](InputSection *IS) { return !IS; }); | |
| 1560 | for (int i = 0, n = sections.size(); i < n; ++i) | |
| 1561 | *scriptSections[i] = sections[i]; | |
| 1504 | 1562 | } |
| 1505 | 1563 | } |
| 1506 | 1564 | |
| 1507 | // For most RISC ISAs, we need to generate content that depends on the address | |
| 1508 | // of InputSections. For example some architectures such as AArch64 use small | |
| 1509 | // displacements for jump instructions that is the linker's responsibility for | |
| 1510 | // creating range extension thunks for. As the generation of the content may | |
| 1511 | // also alter InputSection addresses we must converge to a fixed point. | |
| 1512 | template <class ELFT> void Writer<ELFT>::maybeAddThunks() { | |
| 1513 | if (!Target->NeedsThunks && !Config->AndroidPackDynRelocs && | |
| 1514 | !Config->RelrPackDynRelocs) | |
| 1515 | return; | |
| 1516 | ||
| 1517 | ThunkCreator TC; | |
| 1518 | AArch64Err843419Patcher A64P; | |
| 1565 | // We need to generate and finalize the content that depends on the address of | |
| 1566 | // InputSections. As the generation of the content may also alter InputSection | |
| 1567 | // addresses we must converge to a fixed point. We do that here. See the comment | |
| 1568 | // in Writer<ELFT>::finalizeSections(). | |
| 1569 | template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() { | |
| 1570 | ThunkCreator tc; | |
| 1571 | AArch64Err843419Patcher a64p; | |
| 1519 | 1572 | |
| 1573 | // For some targets, like x86, this loop iterates only once. | |
| 1520 | 1574 | for (;;) { |
| 1521 | bool Changed = false; | |
| 1575 | bool changed = false; | |
| 1522 | 1576 | |
| 1523 | Script->assignAddresses(); | |
| 1577 | script->assignAddresses(); | |
| 1524 | 1578 | |
| 1525 | if (Target->NeedsThunks) | |
| 1526 | Changed |= TC.createThunks(OutputSections); | |
| 1579 | if (target->needsThunks) | |
| 1580 | changed |= tc.createThunks(outputSections); | |
| 1527 | 1581 | |
| 1528 | if (Config->FixCortexA53Errata843419) { | |
| 1529 | if (Changed) | |
| 1530 | Script->assignAddresses(); | |
| 1531 | Changed |= A64P.createFixes(); | |
| 1582 | if (config->fixCortexA53Errata843419) { | |
| 1583 | if (changed) | |
| 1584 | script->assignAddresses(); | |
| 1585 | changed |= a64p.createFixes(); | |
| 1532 | 1586 | } |
| 1533 | 1587 | |
| 1534 | if (In.MipsGot) | |
| 1535 | In.MipsGot->updateAllocSize(); | |
| 1536 | ||
| 1537 | Changed |= In.RelaDyn->updateAllocSize(); | |
| 1588 | if (in.mipsGot) | |
| 1589 | in.mipsGot->updateAllocSize(); | |
| 1538 | 1590 | |
| 1539 | if (In.RelrDyn) | |
| 1540 | Changed |= In.RelrDyn->updateAllocSize(); | |
| 1591 | for (Partition &part : partitions) { | |
| 1592 | changed |= part.relaDyn->updateAllocSize(); | |
| 1593 | if (part.relrDyn) | |
| 1594 | changed |= part.relrDyn->updateAllocSize(); | |
| 1595 | } | |
| 1541 | 1596 | |
| 1542 | if (!Changed) | |
| 1597 | if (!changed) | |
| 1543 | 1598 | return; |
| 1544 | 1599 | } |
| 1545 | 1600 | } |
| 1546 | 1601 | |
| 1547 | static void finalizeSynthetic(SyntheticSection *Sec) { | |
| 1548 | if (Sec && !Sec->empty() && Sec->getParent()) | |
| 1549 | Sec->finalizeContents(); | |
| 1602 | static void finalizeSynthetic(SyntheticSection *sec) { | |
| 1603 | if (sec && sec->isNeeded() && sec->getParent()) | |
| 1604 | sec->finalizeContents(); | |
| 1550 | 1605 | } |
| 1551 | 1606 | |
| 1552 | 1607 | // In order to allow users to manipulate linker-synthesized sections, |
| ... | ... | @@ -1565,128 +1620,190 @@ static void removeUnusedSyntheticSections() { |
| 1565 | 1620 | // All input synthetic sections that can be empty are placed after |
| 1566 | 1621 | // all regular ones. We iterate over them all and exit at first |
| 1567 | 1622 | // non-synthetic. |
| 1568 | for (InputSectionBase *S : llvm::reverse(InputSections)) { | |
| 1569 | SyntheticSection *SS = dyn_cast<SyntheticSection>(S); | |
| 1570 | if (!SS) | |
| 1623 | for (InputSectionBase *s : llvm::reverse(inputSections)) { | |
| 1624 | SyntheticSection *ss = dyn_cast<SyntheticSection>(s); | |
| 1625 | if (!ss) | |
| 1571 | 1626 | return; |
| 1572 | OutputSection *OS = SS->getParent(); | |
| 1573 | if (!OS || !SS->empty()) | |
| 1627 | OutputSection *os = ss->getParent(); | |
| 1628 | if (!os || ss->isNeeded()) | |
| 1574 | 1629 | continue; |
| 1575 | 1630 | |
| 1576 | 1631 | // If we reach here, then SS is an unused synthetic section and we want to |
| 1577 | 1632 | // remove it from corresponding input section description of output section. |
| 1578 | for (BaseCommand *B : OS->SectionCommands) | |
| 1579 | if (auto *ISD = dyn_cast<InputSectionDescription>(B)) | |
| 1580 | llvm::erase_if(ISD->Sections, | |
| 1581 | [=](InputSection *IS) { return IS == SS; }); | |
| 1633 | for (BaseCommand *b : os->sectionCommands) | |
| 1634 | if (auto *isd = dyn_cast<InputSectionDescription>(b)) | |
| 1635 | llvm::erase_if(isd->sections, | |
| 1636 | [=](InputSection *isec) { return isec == ss; }); | |
| 1582 | 1637 | } |
| 1583 | 1638 | } |
| 1584 | 1639 | |
| 1585 | 1640 | // Returns true if a symbol can be replaced at load-time by a symbol |
| 1586 | 1641 | // with the same name defined in other ELF executable or DSO. |
| 1587 | static bool computeIsPreemptible(const Symbol &B) { | |
| 1588 | assert(!B.isLocal()); | |
| 1642 | static bool computeIsPreemptible(const Symbol &b) { | |
| 1643 | assert(!b.isLocal()); | |
| 1589 | 1644 | |
| 1590 | 1645 | // Only symbols that appear in dynsym can be preempted. |
| 1591 | if (!B.includeInDynsym()) | |
| 1646 | if (!b.includeInDynsym()) | |
| 1592 | 1647 | return false; |
| 1593 | 1648 | |
| 1594 | 1649 | // Only default visibility symbols can be preempted. |
| 1595 | if (B.Visibility != STV_DEFAULT) | |
| 1650 | if (b.visibility != STV_DEFAULT) | |
| 1596 | 1651 | return false; |
| 1597 | 1652 | |
| 1598 | 1653 | // At this point copy relocations have not been created yet, so any |
| 1599 | 1654 | // symbol that is not defined locally is preemptible. |
| 1600 | if (!B.isDefined()) | |
| 1655 | if (!b.isDefined()) | |
| 1601 | 1656 | return true; |
| 1602 | 1657 | |
| 1603 | 1658 | // If we have a dynamic list it specifies which local symbols are preemptible. |
| 1604 | if (Config->HasDynamicList) | |
| 1659 | if (config->hasDynamicList) | |
| 1605 | 1660 | return false; |
| 1606 | 1661 | |
| 1607 | if (!Config->Shared) | |
| 1662 | if (!config->shared) | |
| 1608 | 1663 | return false; |
| 1609 | 1664 | |
| 1610 | 1665 | // -Bsymbolic means that definitions are not preempted. |
| 1611 | if (Config->Bsymbolic || (Config->BsymbolicFunctions && B.isFunc())) | |
| 1666 | if (config->bsymbolic || (config->bsymbolicFunctions && b.isFunc())) | |
| 1612 | 1667 | return false; |
| 1613 | 1668 | return true; |
| 1614 | 1669 | } |
| 1615 | 1670 | |
| 1616 | 1671 | // Create output section objects and add them to OutputSections. |
| 1617 | 1672 | template <class ELFT> void Writer<ELFT>::finalizeSections() { |
| 1618 | Out::PreinitArray = findSection(".preinit_array"); | |
| 1619 | Out::InitArray = findSection(".init_array"); | |
| 1620 | Out::FiniArray = findSection(".fini_array"); | |
| 1673 | Out::preinitArray = findSection(".preinit_array"); | |
| 1674 | Out::initArray = findSection(".init_array"); | |
| 1675 | Out::finiArray = findSection(".fini_array"); | |
| 1621 | 1676 | |
| 1622 | 1677 | // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop |
| 1623 | 1678 | // symbols for sections, so that the runtime can get the start and end |
| 1624 | 1679 | // addresses of each section by section name. Add such symbols. |
| 1625 | if (!Config->Relocatable) { | |
| 1680 | if (!config->relocatable) { | |
| 1626 | 1681 | addStartEndSymbols(); |
| 1627 | for (BaseCommand *Base : Script->SectionCommands) | |
| 1628 | if (auto *Sec = dyn_cast<OutputSection>(Base)) | |
| 1629 | addStartStopSymbols(Sec); | |
| 1682 | for (BaseCommand *base : script->sectionCommands) | |
| 1683 | if (auto *sec = dyn_cast<OutputSection>(base)) | |
| 1684 | addStartStopSymbols(sec); | |
| 1630 | 1685 | } |
| 1631 | 1686 | |
| 1632 | 1687 | // Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type. |
| 1633 | 1688 | // It should be okay as no one seems to care about the type. |
| 1634 | 1689 | // Even the author of gold doesn't remember why gold behaves that way. |
| 1635 | 1690 | // https://sourceware.org/ml/binutils/2002-03/msg00360.html |
| 1636 | if (In.Dynamic->Parent) | |
| 1637 | Symtab->addDefined("_DYNAMIC", STV_HIDDEN, STT_NOTYPE, 0 /*Value*/, | |
| 1638 | /*Size=*/0, STB_WEAK, In.Dynamic, | |
| 1639 | /*File=*/nullptr); | |
| 1691 | if (mainPart->dynamic->parent) | |
| 1692 | symtab->addSymbol(Defined{/*file=*/nullptr, "_DYNAMIC", STB_WEAK, | |
| 1693 | STV_HIDDEN, STT_NOTYPE, | |
| 1694 | /*value=*/0, /*size=*/0, mainPart->dynamic}); | |
| 1640 | 1695 | |
| 1641 | 1696 | // Define __rel[a]_iplt_{start,end} symbols if needed. |
| 1642 | 1697 | addRelIpltSymbols(); |
| 1643 | 1698 | |
| 1644 | 1699 | // RISC-V's gp can address +/- 2 KiB, set it to .sdata + 0x800 if not defined. |
| 1645 | if (Config->EMachine == EM_RISCV) | |
| 1646 | if (!dyn_cast_or_null<Defined>(Symtab->find("__global_pointer$"))) | |
| 1647 | addOptionalRegular("__global_pointer$", findSection(".sdata"), 0x800); | |
| 1700 | // This symbol should only be defined in an executable. | |
| 1701 | if (config->emachine == EM_RISCV && !config->shared) | |
| 1702 | ElfSym::riscvGlobalPointer = | |
| 1703 | addOptionalRegular("__global_pointer$", findSection(".sdata"), 0x800, | |
| 1704 | STV_DEFAULT, STB_GLOBAL); | |
| 1705 | ||
| 1706 | if (config->emachine == EM_X86_64) { | |
| 1707 | // On targets that support TLSDESC, _TLS_MODULE_BASE_ is defined in such a | |
| 1708 | // way that: | |
| 1709 | // | |
| 1710 | // 1) Without relaxation: it produces a dynamic TLSDESC relocation that | |
| 1711 | // computes 0. | |
| 1712 | // 2) With LD->LE relaxation: _TLS_MODULE_BASE_@tpoff = 0 (lowest address in | |
| 1713 | // the TLS block). | |
| 1714 | // | |
| 1715 | // 2) is special cased in @tpoff computation. To satisfy 1), we define it as | |
| 1716 | // an absolute symbol of zero. This is different from GNU linkers which | |
| 1717 | // define _TLS_MODULE_BASE_ relative to the first TLS section. | |
| 1718 | Symbol *s = symtab->find("_TLS_MODULE_BASE_"); | |
| 1719 | if (s && s->isUndefined()) { | |
| 1720 | s->resolve(Defined{/*file=*/nullptr, s->getName(), STB_GLOBAL, STV_HIDDEN, | |
| 1721 | STT_TLS, /*value=*/0, 0, | |
| 1722 | /*section=*/nullptr}); | |
| 1723 | ElfSym::tlsModuleBase = cast<Defined>(s); | |
| 1724 | } | |
| 1725 | } | |
| 1648 | 1726 | |
| 1649 | 1727 | // This responsible for splitting up .eh_frame section into |
| 1650 | 1728 | // pieces. The relocation scan uses those pieces, so this has to be |
| 1651 | 1729 | // earlier. |
| 1652 | finalizeSynthetic(In.EhFrame); | |
| 1730 | for (Partition &part : partitions) | |
| 1731 | finalizeSynthetic(part.ehFrame); | |
| 1653 | 1732 | |
| 1654 | for (Symbol *S : Symtab->getSymbols()) | |
| 1655 | if (!S->IsPreemptible) | |
| 1656 | S->IsPreemptible = computeIsPreemptible(*S); | |
| 1733 | symtab->forEachSymbol([](Symbol *s) { | |
| 1734 | if (!s->isPreemptible) | |
| 1735 | s->isPreemptible = computeIsPreemptible(*s); | |
| 1736 | }); | |
| 1657 | 1737 | |
| 1658 | 1738 | // Scan relocations. This must be done after every symbol is declared so that |
| 1659 | 1739 | // we can correctly decide if a dynamic relocation is needed. |
| 1660 | if (!Config->Relocatable) | |
| 1740 | if (!config->relocatable) { | |
| 1661 | 1741 | forEachRelSec(scanRelocations<ELFT>); |
| 1742 | reportUndefinedSymbols<ELFT>(); | |
| 1743 | } | |
| 1662 | 1744 | |
| 1663 | if (In.Plt && !In.Plt->empty()) | |
| 1664 | In.Plt->addSymbols(); | |
| 1665 | if (In.Iplt && !In.Iplt->empty()) | |
| 1666 | In.Iplt->addSymbols(); | |
| 1745 | addIRelativeRelocs(); | |
| 1746 | ||
| 1747 | if (in.plt && in.plt->isNeeded()) | |
| 1748 | in.plt->addSymbols(); | |
| 1749 | if (in.iplt && in.iplt->isNeeded()) | |
| 1750 | in.iplt->addSymbols(); | |
| 1751 | ||
| 1752 | if (!config->allowShlibUndefined) { | |
| 1753 | // Error on undefined symbols in a shared object, if all of its DT_NEEDED | |
| 1754 | // entires are seen. These cases would otherwise lead to runtime errors | |
| 1755 | // reported by the dynamic linker. | |
| 1756 | // | |
| 1757 | // ld.bfd traces all DT_NEEDED to emulate the logic of the dynamic linker to | |
| 1758 | // catch more cases. That is too much for us. Our approach resembles the one | |
| 1759 | // used in ld.gold, achieves a good balance to be useful but not too smart. | |
| 1760 | for (SharedFile *file : sharedFiles) | |
| 1761 | file->allNeededIsKnown = | |
| 1762 | llvm::all_of(file->dtNeeded, [&](StringRef needed) { | |
| 1763 | return symtab->soNames.count(needed); | |
| 1764 | }); | |
| 1765 | ||
| 1766 | symtab->forEachSymbol([](Symbol *sym) { | |
| 1767 | if (sym->isUndefined() && !sym->isWeak()) | |
| 1768 | if (auto *f = dyn_cast_or_null<SharedFile>(sym->file)) | |
| 1769 | if (f->allNeededIsKnown) | |
| 1770 | error(toString(f) + ": undefined reference to " + toString(*sym)); | |
| 1771 | }); | |
| 1772 | } | |
| 1667 | 1773 | |
| 1668 | 1774 | // Now that we have defined all possible global symbols including linker- |
| 1669 | 1775 | // synthesized ones. Visit all symbols to give the finishing touches. |
| 1670 | for (Symbol *Sym : Symtab->getSymbols()) { | |
| 1671 | if (!includeInSymtab(*Sym)) | |
| 1672 | continue; | |
| 1673 | if (In.SymTab) | |
| 1674 | In.SymTab->addSymbol(Sym); | |
| 1675 | ||
| 1676 | if (Sym->includeInDynsym()) { | |
| 1677 | In.DynSymTab->addSymbol(Sym); | |
| 1678 | if (auto *File = dyn_cast_or_null<SharedFile<ELFT>>(Sym->File)) | |
| 1679 | if (File->IsNeeded && !Sym->isUndefined()) | |
| 1680 | InX<ELFT>::VerNeed->addSymbol(Sym); | |
| 1776 | symtab->forEachSymbol([](Symbol *sym) { | |
| 1777 | if (!includeInSymtab(*sym)) | |
| 1778 | return; | |
| 1779 | if (in.symTab) | |
| 1780 | in.symTab->addSymbol(sym); | |
| 1781 | ||
| 1782 | if (sym->includeInDynsym()) { | |
| 1783 | partitions[sym->partition - 1].dynSymTab->addSymbol(sym); | |
| 1784 | if (auto *file = dyn_cast_or_null<SharedFile>(sym->file)) | |
| 1785 | if (file->isNeeded && !sym->isUndefined()) | |
| 1786 | addVerneed(sym); | |
| 1681 | 1787 | } |
| 1788 | }); | |
| 1789 | ||
| 1790 | // We also need to scan the dynamic relocation tables of the other partitions | |
| 1791 | // and add any referenced symbols to the partition's dynsym. | |
| 1792 | for (Partition &part : MutableArrayRef<Partition>(partitions).slice(1)) { | |
| 1793 | DenseSet<Symbol *> syms; | |
| 1794 | for (const SymbolTableEntry &e : part.dynSymTab->getSymbols()) | |
| 1795 | syms.insert(e.sym); | |
| 1796 | for (DynamicReloc &reloc : part.relaDyn->relocs) | |
| 1797 | if (reloc.sym && !reloc.useSymVA && syms.insert(reloc.sym).second) | |
| 1798 | part.dynSymTab->addSymbol(reloc.sym); | |
| 1682 | 1799 | } |
| 1683 | 1800 | |
| 1684 | 1801 | // Do not proceed if there was an undefined symbol. |
| 1685 | 1802 | if (errorCount()) |
| 1686 | 1803 | return; |
| 1687 | 1804 | |
| 1688 | if (In.MipsGot) | |
| 1689 | In.MipsGot->build<ELFT>(); | |
| 1805 | if (in.mipsGot) | |
| 1806 | in.mipsGot->build(); | |
| 1690 | 1807 | |
| 1691 | 1808 | removeUnusedSyntheticSections(); |
| 1692 | 1809 | |
| ... | ... | @@ -1694,116 +1811,147 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { |
| 1694 | 1811 | |
| 1695 | 1812 | // Now that we have the final list, create a list of all the |
| 1696 | 1813 | // OutputSections for convenience. |
| 1697 | for (BaseCommand *Base : Script->SectionCommands) | |
| 1698 | if (auto *Sec = dyn_cast<OutputSection>(Base)) | |
| 1699 | OutputSections.push_back(Sec); | |
| 1814 | for (BaseCommand *base : script->sectionCommands) | |
| 1815 | if (auto *sec = dyn_cast<OutputSection>(base)) | |
| 1816 | outputSections.push_back(sec); | |
| 1700 | 1817 | |
| 1701 | 1818 | // Prefer command line supplied address over other constraints. |
| 1702 | for (OutputSection *Sec : OutputSections) { | |
| 1703 | auto I = Config->SectionStartMap.find(Sec->Name); | |
| 1704 | if (I != Config->SectionStartMap.end()) | |
| 1705 | Sec->AddrExpr = [=] { return I->second; }; | |
| 1819 | for (OutputSection *sec : outputSections) { | |
| 1820 | auto i = config->sectionStartMap.find(sec->name); | |
| 1821 | if (i != config->sectionStartMap.end()) | |
| 1822 | sec->addrExpr = [=] { return i->second; }; | |
| 1706 | 1823 | } |
| 1707 | 1824 | |
| 1708 | 1825 | // This is a bit of a hack. A value of 0 means undef, so we set it |
| 1709 | 1826 | // to 1 to make __ehdr_start defined. The section number is not |
| 1710 | 1827 | // particularly relevant. |
| 1711 | Out::ElfHeader->SectionIndex = 1; | |
| 1828 | Out::elfHeader->sectionIndex = 1; | |
| 1712 | 1829 | |
| 1713 | for (size_t I = 0, E = OutputSections.size(); I != E; ++I) { | |
| 1714 | OutputSection *Sec = OutputSections[I]; | |
| 1715 | Sec->SectionIndex = I + 1; | |
| 1716 | Sec->ShName = In.ShStrTab->addString(Sec->Name); | |
| 1830 | for (size_t i = 0, e = outputSections.size(); i != e; ++i) { | |
| 1831 | OutputSection *sec = outputSections[i]; | |
| 1832 | sec->sectionIndex = i + 1; | |
| 1833 | sec->shName = in.shStrTab->addString(sec->name); | |
| 1717 | 1834 | } |
| 1718 | 1835 | |
| 1719 | 1836 | // Binary and relocatable output does not have PHDRS. |
| 1720 | 1837 | // The headers have to be created before finalize as that can influence the |
| 1721 | 1838 | // image base and the dynamic section on mips includes the image base. |
| 1722 | if (!Config->Relocatable && !Config->OFormatBinary) { | |
| 1723 | Phdrs = Script->hasPhdrsCommands() ? Script->createPhdrs() : createPhdrs(); | |
| 1724 | addPtArmExid(Phdrs); | |
| 1725 | Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size(); | |
| 1839 | if (!config->relocatable && !config->oFormatBinary) { | |
| 1840 | for (Partition &part : partitions) { | |
| 1841 | part.phdrs = script->hasPhdrsCommands() ? script->createPhdrs() | |
| 1842 | : createPhdrs(part); | |
| 1843 | if (config->emachine == EM_ARM) { | |
| 1844 | // PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME | |
| 1845 | addPhdrForSection(part, SHT_ARM_EXIDX, PT_ARM_EXIDX, PF_R); | |
| 1846 | } | |
| 1847 | if (config->emachine == EM_MIPS) { | |
| 1848 | // Add separate segments for MIPS-specific sections. | |
| 1849 | addPhdrForSection(part, SHT_MIPS_REGINFO, PT_MIPS_REGINFO, PF_R); | |
| 1850 | addPhdrForSection(part, SHT_MIPS_OPTIONS, PT_MIPS_OPTIONS, PF_R); | |
| 1851 | addPhdrForSection(part, SHT_MIPS_ABIFLAGS, PT_MIPS_ABIFLAGS, PF_R); | |
| 1852 | } | |
| 1853 | } | |
| 1854 | Out::programHeaders->size = sizeof(Elf_Phdr) * mainPart->phdrs.size(); | |
| 1726 | 1855 | |
| 1727 | 1856 | // Find the TLS segment. This happens before the section layout loop so that |
| 1728 | // Android relocation packing can look up TLS symbol addresses. | |
| 1729 | for (PhdrEntry *P : Phdrs) | |
| 1730 | if (P->p_type == PT_TLS) | |
| 1731 | Out::TlsPhdr = P; | |
| 1857 | // Android relocation packing can look up TLS symbol addresses. We only need | |
| 1858 | // to care about the main partition here because all TLS symbols were moved | |
| 1859 | // to the main partition (see MarkLive.cpp). | |
| 1860 | for (PhdrEntry *p : mainPart->phdrs) | |
| 1861 | if (p->p_type == PT_TLS) | |
| 1862 | Out::tlsPhdr = p; | |
| 1732 | 1863 | } |
| 1733 | 1864 | |
| 1734 | 1865 | // Some symbols are defined in term of program headers. Now that we |
| 1735 | 1866 | // have the headers, we can find out which sections they point to. |
| 1736 | 1867 | setReservedSymbolSections(); |
| 1737 | 1868 | |
| 1869 | finalizeSynthetic(in.bss); | |
| 1870 | finalizeSynthetic(in.bssRelRo); | |
| 1871 | finalizeSynthetic(in.symTabShndx); | |
| 1872 | finalizeSynthetic(in.shStrTab); | |
| 1873 | finalizeSynthetic(in.strTab); | |
| 1874 | finalizeSynthetic(in.got); | |
| 1875 | finalizeSynthetic(in.mipsGot); | |
| 1876 | finalizeSynthetic(in.igotPlt); | |
| 1877 | finalizeSynthetic(in.gotPlt); | |
| 1878 | finalizeSynthetic(in.relaIplt); | |
| 1879 | finalizeSynthetic(in.relaPlt); | |
| 1880 | finalizeSynthetic(in.plt); | |
| 1881 | finalizeSynthetic(in.iplt); | |
| 1882 | finalizeSynthetic(in.ppc32Got2); | |
| 1883 | finalizeSynthetic(in.riscvSdata); | |
| 1884 | finalizeSynthetic(in.partIndex); | |
| 1885 | ||
| 1738 | 1886 | // Dynamic section must be the last one in this list and dynamic |
| 1739 | // symbol table section (DynSymTab) must be the first one. | |
| 1740 | finalizeSynthetic(In.DynSymTab); | |
| 1741 | finalizeSynthetic(In.Bss); | |
| 1742 | finalizeSynthetic(In.BssRelRo); | |
| 1743 | finalizeSynthetic(In.GnuHashTab); | |
| 1744 | finalizeSynthetic(In.HashTab); | |
| 1745 | finalizeSynthetic(In.SymTabShndx); | |
| 1746 | finalizeSynthetic(In.ShStrTab); | |
| 1747 | finalizeSynthetic(In.StrTab); | |
| 1748 | finalizeSynthetic(In.VerDef); | |
| 1749 | finalizeSynthetic(In.DynStrTab); | |
| 1750 | finalizeSynthetic(In.Got); | |
| 1751 | finalizeSynthetic(In.MipsGot); | |
| 1752 | finalizeSynthetic(In.IgotPlt); | |
| 1753 | finalizeSynthetic(In.GotPlt); | |
| 1754 | finalizeSynthetic(In.RelaDyn); | |
| 1755 | finalizeSynthetic(In.RelrDyn); | |
| 1756 | finalizeSynthetic(In.RelaIplt); | |
| 1757 | finalizeSynthetic(In.RelaPlt); | |
| 1758 | finalizeSynthetic(In.Plt); | |
| 1759 | finalizeSynthetic(In.Iplt); | |
| 1760 | finalizeSynthetic(In.EhFrameHdr); | |
| 1761 | finalizeSynthetic(InX<ELFT>::VerSym); | |
| 1762 | finalizeSynthetic(InX<ELFT>::VerNeed); | |
| 1763 | finalizeSynthetic(In.Dynamic); | |
| 1764 | ||
| 1765 | if (!Script->HasSectionsCommand && !Config->Relocatable) | |
| 1887 | // symbol table section (dynSymTab) must be the first one. | |
| 1888 | for (Partition &part : partitions) { | |
| 1889 | finalizeSynthetic(part.armExidx); | |
| 1890 | finalizeSynthetic(part.dynSymTab); | |
| 1891 | finalizeSynthetic(part.gnuHashTab); | |
| 1892 | finalizeSynthetic(part.hashTab); | |
| 1893 | finalizeSynthetic(part.verDef); | |
| 1894 | finalizeSynthetic(part.relaDyn); | |
| 1895 | finalizeSynthetic(part.relrDyn); | |
| 1896 | finalizeSynthetic(part.ehFrameHdr); | |
| 1897 | finalizeSynthetic(part.verSym); | |
| 1898 | finalizeSynthetic(part.verNeed); | |
| 1899 | finalizeSynthetic(part.dynamic); | |
| 1900 | } | |
| 1901 | ||
| 1902 | if (!script->hasSectionsCommand && !config->relocatable) | |
| 1766 | 1903 | fixSectionAlignments(); |
| 1767 | 1904 | |
| 1768 | // After link order processing .ARM.exidx sections can be deduplicated, which | |
| 1769 | // needs to be resolved before any other address dependent operation. | |
| 1905 | // SHFLinkOrder processing must be processed after relative section placements are | |
| 1906 | // known but before addresses are allocated. | |
| 1770 | 1907 | resolveShfLinkOrder(); |
| 1771 | 1908 | |
| 1772 | // Jump instructions in many ISAs have small displacements, and therefore they | |
| 1773 | // cannot jump to arbitrary addresses in memory. For example, RISC-V JAL | |
| 1774 | // instruction can target only +-1 MiB from PC. It is a linker's | |
| 1775 | // responsibility to create and insert small pieces of code between sections | |
| 1776 | // to extend the ranges if jump targets are out of range. Such code pieces are | |
| 1777 | // called "thunks". | |
| 1909 | // This is used to: | |
| 1910 | // 1) Create "thunks": | |
| 1911 | // Jump instructions in many ISAs have small displacements, and therefore | |
| 1912 | // they cannot jump to arbitrary addresses in memory. For example, RISC-V | |
| 1913 | // JAL instruction can target only +-1 MiB from PC. It is a linker's | |
| 1914 | // responsibility to create and insert small pieces of code between | |
| 1915 | // sections to extend the ranges if jump targets are out of range. Such | |
| 1916 | // code pieces are called "thunks". | |
| 1778 | 1917 | // |
| 1779 | // We add thunks at this stage. We couldn't do this before this point because | |
| 1780 | // this is the earliest point where we know sizes of sections and their | |
| 1781 | // layouts (that are needed to determine if jump targets are in range). | |
| 1782 | maybeAddThunks(); | |
| 1918 | // We add thunks at this stage. We couldn't do this before this point | |
| 1919 | // because this is the earliest point where we know sizes of sections and | |
| 1920 | // their layouts (that are needed to determine if jump targets are in | |
| 1921 | // range). | |
| 1922 | // | |
| 1923 | // 2) Update the sections. We need to generate content that depends on the | |
| 1924 | // address of InputSections. For example, MIPS GOT section content or | |
| 1925 | // android packed relocations sections content. | |
| 1926 | // | |
| 1927 | // 3) Assign the final values for the linker script symbols. Linker scripts | |
| 1928 | // sometimes using forward symbol declarations. We want to set the correct | |
| 1929 | // values. They also might change after adding the thunks. | |
| 1930 | finalizeAddressDependentContent(); | |
| 1783 | 1931 | |
| 1784 | // maybeAddThunks may have added local symbols to the static symbol table. | |
| 1785 | finalizeSynthetic(In.SymTab); | |
| 1786 | finalizeSynthetic(In.PPC64LongBranchTarget); | |
| 1932 | // finalizeAddressDependentContent may have added local symbols to the static symbol table. | |
| 1933 | finalizeSynthetic(in.symTab); | |
| 1934 | finalizeSynthetic(in.ppc64LongBranchTarget); | |
| 1787 | 1935 | |
| 1788 | 1936 | // Fill other section headers. The dynamic table is finalized |
| 1789 | 1937 | // at the end because some tags like RELSZ depend on result |
| 1790 | 1938 | // of finalizing other sections. |
| 1791 | for (OutputSection *Sec : OutputSections) | |
| 1792 | Sec->finalize<ELFT>(); | |
| 1939 | for (OutputSection *sec : outputSections) | |
| 1940 | sec->finalize(); | |
| 1793 | 1941 | } |
| 1794 | 1942 | |
| 1795 | 1943 | // Ensure data sections are not mixed with executable sections when |
| 1796 | 1944 | // -execute-only is used. -execute-only is a feature to make pages executable |
| 1797 | 1945 | // but not readable, and the feature is currently supported only on AArch64. |
| 1798 | 1946 | template <class ELFT> void Writer<ELFT>::checkExecuteOnly() { |
| 1799 | if (!Config->ExecuteOnly) | |
| 1947 | if (!config->executeOnly) | |
| 1800 | 1948 | return; |
| 1801 | 1949 | |
| 1802 | for (OutputSection *OS : OutputSections) | |
| 1803 | if (OS->Flags & SHF_EXECINSTR) | |
| 1804 | for (InputSection *IS : getInputSections(OS)) | |
| 1805 | if (!(IS->Flags & SHF_EXECINSTR)) | |
| 1806 | error("cannot place " + toString(IS) + " into " + toString(OS->Name) + | |
| 1950 | for (OutputSection *os : outputSections) | |
| 1951 | if (os->flags & SHF_EXECINSTR) | |
| 1952 | for (InputSection *isec : getInputSections(os)) | |
| 1953 | if (!(isec->flags & SHF_EXECINSTR)) | |
| 1954 | error("cannot place " + toString(isec) + " into " + toString(os->name) + | |
| 1807 | 1955 | ": -execute-only does not support intermingling data and code"); |
| 1808 | 1956 | } |
| 1809 | 1957 | |
| ... | ... | @@ -1828,24 +1976,24 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() { |
| 1828 | 1976 | // case, use the image base address as a last resort. |
| 1829 | 1977 | OutputSection *Default = findSection(".text"); |
| 1830 | 1978 | if (!Default) |
| 1831 | Default = Out::ElfHeader; | |
| 1979 | Default = Out::elfHeader; | |
| 1832 | 1980 | |
| 1833 | auto Define = [=](StringRef Start, StringRef End, OutputSection *OS) { | |
| 1834 | if (OS) { | |
| 1835 | addOptionalRegular(Start, OS, 0); | |
| 1836 | addOptionalRegular(End, OS, -1); | |
| 1981 | auto define = [=](StringRef start, StringRef end, OutputSection *os) { | |
| 1982 | if (os) { | |
| 1983 | addOptionalRegular(start, os, 0); | |
| 1984 | addOptionalRegular(end, os, -1); | |
| 1837 | 1985 | } else { |
| 1838 | addOptionalRegular(Start, Default, 0); | |
| 1839 | addOptionalRegular(End, Default, 0); | |
| 1986 | addOptionalRegular(start, Default, 0); | |
| 1987 | addOptionalRegular(end, Default, 0); | |
| 1840 | 1988 | } |
| 1841 | 1989 | }; |
| 1842 | 1990 | |
| 1843 | Define("__preinit_array_start", "__preinit_array_end", Out::PreinitArray); | |
| 1844 | Define("__init_array_start", "__init_array_end", Out::InitArray); | |
| 1845 | Define("__fini_array_start", "__fini_array_end", Out::FiniArray); | |
| 1991 | define("__preinit_array_start", "__preinit_array_end", Out::preinitArray); | |
| 1992 | define("__init_array_start", "__init_array_end", Out::initArray); | |
| 1993 | define("__fini_array_start", "__fini_array_end", Out::finiArray); | |
| 1846 | 1994 | |
| 1847 | if (OutputSection *Sec = findSection(".ARM.exidx")) | |
| 1848 | Define("__exidx_start", "__exidx_end", Sec); | |
| 1995 | if (OutputSection *sec = findSection(".ARM.exidx")) | |
| 1996 | define("__exidx_start", "__exidx_end", sec); | |
| 1849 | 1997 | } |
| 1850 | 1998 | |
| 1851 | 1999 | // If a section name is valid as a C identifier (which is rare because of |
| ... | ... | @@ -1854,22 +2002,22 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() { |
| 1854 | 2002 | // respectively. This is not requested by the ELF standard, but GNU ld and |
| 1855 | 2003 | // gold provide the feature, and used by many programs. |
| 1856 | 2004 | template <class ELFT> |
| 1857 | void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) { | |
| 1858 | StringRef S = Sec->Name; | |
| 1859 | if (!isValidCIdentifier(S)) | |
| 2005 | void Writer<ELFT>::addStartStopSymbols(OutputSection *sec) { | |
| 2006 | StringRef s = sec->name; | |
| 2007 | if (!isValidCIdentifier(s)) | |
| 1860 | 2008 | return; |
| 1861 | addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_PROTECTED); | |
| 1862 | addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_PROTECTED); | |
| 2009 | addOptionalRegular(saver.save("__start_" + s), sec, 0, STV_PROTECTED); | |
| 2010 | addOptionalRegular(saver.save("__stop_" + s), sec, -1, STV_PROTECTED); | |
| 1863 | 2011 | } |
| 1864 | 2012 | |
| 1865 | static bool needsPtLoad(OutputSection *Sec) { | |
| 1866 | if (!(Sec->Flags & SHF_ALLOC) || Sec->Noload) | |
| 2013 | static bool needsPtLoad(OutputSection *sec) { | |
| 2014 | if (!(sec->flags & SHF_ALLOC) || sec->noload) | |
| 1867 | 2015 | return false; |
| 1868 | 2016 | |
| 1869 | 2017 | // Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is |
| 1870 | 2018 | // responsible for allocating space for them, not the PT_LOAD that |
| 1871 | 2019 | // contains the TLS initialization image. |
| 1872 | if ((Sec->Flags & SHF_TLS) && Sec->Type == SHT_NOBITS) | |
| 2020 | if ((sec->flags & SHF_TLS) && sec->type == SHT_NOBITS) | |
| 1873 | 2021 | return false; |
| 1874 | 2022 | return true; |
| 1875 | 2023 | } |
| ... | ... | @@ -1878,46 +2026,93 @@ static bool needsPtLoad(OutputSection *Sec) { |
| 1878 | 2026 | // linker scripts are designed for creating two PT_LOADs only, one RX and one |
| 1879 | 2027 | // RW. This means that there is no alignment in the RO to RX transition and we |
| 1880 | 2028 | // cannot create a PT_LOAD there. |
| 1881 | static uint64_t computeFlags(uint64_t Flags) { | |
| 1882 | if (Config->Omagic) | |
| 2029 | static uint64_t computeFlags(uint64_t flags) { | |
| 2030 | if (config->omagic) | |
| 1883 | 2031 | return PF_R | PF_W | PF_X; |
| 1884 | if (Config->ExecuteOnly && (Flags & PF_X)) | |
| 1885 | return Flags & ~PF_R; | |
| 1886 | if (Config->SingleRoRx && !(Flags & PF_W)) | |
| 1887 | return Flags | PF_X; | |
| 1888 | return Flags; | |
| 2032 | if (config->executeOnly && (flags & PF_X)) | |
| 2033 | return flags & ~PF_R; | |
| 2034 | if (config->singleRoRx && !(flags & PF_W)) | |
| 2035 | return flags | PF_X; | |
| 2036 | return flags; | |
| 1889 | 2037 | } |
| 1890 | 2038 | |
| 1891 | 2039 | // Decide which program headers to create and which sections to include in each |
| 1892 | 2040 | // one. |
| 1893 | template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() { | |
| 1894 | std::vector<PhdrEntry *> Ret; | |
| 1895 | auto AddHdr = [&](unsigned Type, unsigned Flags) -> PhdrEntry * { | |
| 1896 | Ret.push_back(make<PhdrEntry>(Type, Flags)); | |
| 1897 | return Ret.back(); | |
| 2041 | template <class ELFT> | |
| 2042 | std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs(Partition &part) { | |
| 2043 | std::vector<PhdrEntry *> ret; | |
| 2044 | auto addHdr = [&](unsigned type, unsigned flags) -> PhdrEntry * { | |
| 2045 | ret.push_back(make<PhdrEntry>(type, flags)); | |
| 2046 | return ret.back(); | |
| 1898 | 2047 | }; |
| 1899 | 2048 | |
| 2049 | unsigned partNo = part.getNumber(); | |
| 2050 | bool isMain = partNo == 1; | |
| 2051 | ||
| 1900 | 2052 | // The first phdr entry is PT_PHDR which describes the program header itself. |
| 1901 | AddHdr(PT_PHDR, PF_R)->add(Out::ProgramHeaders); | |
| 2053 | if (isMain) | |
| 2054 | addHdr(PT_PHDR, PF_R)->add(Out::programHeaders); | |
| 2055 | else | |
| 2056 | addHdr(PT_PHDR, PF_R)->add(part.programHeaders->getParent()); | |
| 1902 | 2057 | |
| 1903 | 2058 | // PT_INTERP must be the second entry if exists. |
| 1904 | if (OutputSection *Cmd = findSection(".interp")) | |
| 1905 | AddHdr(PT_INTERP, Cmd->getPhdrFlags())->add(Cmd); | |
| 2059 | if (OutputSection *cmd = findSection(".interp", partNo)) | |
| 2060 | addHdr(PT_INTERP, cmd->getPhdrFlags())->add(cmd); | |
| 1906 | 2061 | |
| 1907 | 2062 | // Add the first PT_LOAD segment for regular output sections. |
| 1908 | uint64_t Flags = computeFlags(PF_R); | |
| 1909 | PhdrEntry *Load = AddHdr(PT_LOAD, Flags); | |
| 2063 | uint64_t flags = computeFlags(PF_R); | |
| 2064 | PhdrEntry *load = nullptr; | |
| 1910 | 2065 | |
| 1911 | 2066 | // Add the headers. We will remove them if they don't fit. |
| 1912 | Load->add(Out::ElfHeader); | |
| 1913 | Load->add(Out::ProgramHeaders); | |
| 2067 | // In the other partitions the headers are ordinary sections, so they don't | |
| 2068 | // need to be added here. | |
| 2069 | if (isMain) { | |
| 2070 | load = addHdr(PT_LOAD, flags); | |
| 2071 | load->add(Out::elfHeader); | |
| 2072 | load->add(Out::programHeaders); | |
| 2073 | } | |
| 2074 | ||
| 2075 | // PT_GNU_RELRO includes all sections that should be marked as | |
| 2076 | // read-only by dynamic linker after proccessing relocations. | |
| 2077 | // Current dynamic loaders only support one PT_GNU_RELRO PHDR, give | |
| 2078 | // an error message if more than one PT_GNU_RELRO PHDR is required. | |
| 2079 | PhdrEntry *relRo = make<PhdrEntry>(PT_GNU_RELRO, PF_R); | |
| 2080 | bool inRelroPhdr = false; | |
| 2081 | OutputSection *relroEnd = nullptr; | |
| 2082 | for (OutputSection *sec : outputSections) { | |
| 2083 | if (sec->partition != partNo || !needsPtLoad(sec)) | |
| 2084 | continue; | |
| 2085 | if (isRelroSection(sec)) { | |
| 2086 | inRelroPhdr = true; | |
| 2087 | if (!relroEnd) | |
| 2088 | relRo->add(sec); | |
| 2089 | else | |
| 2090 | error("section: " + sec->name + " is not contiguous with other relro" + | |
| 2091 | " sections"); | |
| 2092 | } else if (inRelroPhdr) { | |
| 2093 | inRelroPhdr = false; | |
| 2094 | relroEnd = sec; | |
| 2095 | } | |
| 2096 | } | |
| 1914 | 2097 | |
| 1915 | for (OutputSection *Sec : OutputSections) { | |
| 1916 | if (!(Sec->Flags & SHF_ALLOC)) | |
| 2098 | for (OutputSection *sec : outputSections) { | |
| 2099 | if (!(sec->flags & SHF_ALLOC)) | |
| 1917 | 2100 | break; |
| 1918 | if (!needsPtLoad(Sec)) | |
| 2101 | if (!needsPtLoad(sec)) | |
| 1919 | 2102 | continue; |
| 1920 | 2103 | |
| 2104 | // Normally, sections in partitions other than the current partition are | |
| 2105 | // ignored. But partition number 255 is a special case: it contains the | |
| 2106 | // partition end marker (.part.end). It needs to be added to the main | |
| 2107 | // partition so that a segment is created for it in the main partition, | |
| 2108 | // which will cause the dynamic loader to reserve space for the other | |
| 2109 | // partitions. | |
| 2110 | if (sec->partition != partNo) { | |
| 2111 | if (isMain && sec->partition == 255) | |
| 2112 | addHdr(PT_LOAD, computeFlags(sec->getPhdrFlags()))->add(sec); | |
| 2113 | continue; | |
| 2114 | } | |
| 2115 | ||
| 1921 | 2116 | // Segments are contiguous memory regions that has the same attributes |
| 1922 | 2117 | // (e.g. executable or writable). There is one phdr for each segment. |
| 1923 | 2118 | // Therefore, we need to create a new phdr when the next section has |
| ... | ... | @@ -1925,222 +2120,187 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() { |
| 1925 | 2120 | // region using AT or AT> linker script command, respectively. At the same |
| 1926 | 2121 | // time, we don't want to create a separate load segment for the headers, |
| 1927 | 2122 | // even if the first output section has an AT or AT> attribute. |
| 1928 | uint64_t NewFlags = computeFlags(Sec->getPhdrFlags()); | |
| 1929 | if (((Sec->LMAExpr || | |
| 1930 | (Sec->LMARegion && (Sec->LMARegion != Load->FirstSec->LMARegion))) && | |
| 1931 | Load->LastSec != Out::ProgramHeaders) || | |
| 1932 | Sec->MemRegion != Load->FirstSec->MemRegion || Flags != NewFlags) { | |
| 1933 | ||
| 1934 | Load = AddHdr(PT_LOAD, NewFlags); | |
| 1935 | Flags = NewFlags; | |
| 2123 | uint64_t newFlags = computeFlags(sec->getPhdrFlags()); | |
| 2124 | if (!load || | |
| 2125 | ((sec->lmaExpr || | |
| 2126 | (sec->lmaRegion && (sec->lmaRegion != load->firstSec->lmaRegion))) && | |
| 2127 | load->lastSec != Out::programHeaders) || | |
| 2128 | sec->memRegion != load->firstSec->memRegion || flags != newFlags || | |
| 2129 | sec == relroEnd) { | |
| 2130 | load = addHdr(PT_LOAD, newFlags); | |
| 2131 | flags = newFlags; | |
| 1936 | 2132 | } |
| 1937 | 2133 | |
| 1938 | Load->add(Sec); | |
| 2134 | load->add(sec); | |
| 1939 | 2135 | } |
| 1940 | 2136 | |
| 1941 | 2137 | // Add a TLS segment if any. |
| 1942 | PhdrEntry *TlsHdr = make<PhdrEntry>(PT_TLS, PF_R); | |
| 1943 | for (OutputSection *Sec : OutputSections) | |
| 1944 | if (Sec->Flags & SHF_TLS) | |
| 1945 | TlsHdr->add(Sec); | |
| 1946 | if (TlsHdr->FirstSec) | |
| 1947 | Ret.push_back(TlsHdr); | |
| 2138 | PhdrEntry *tlsHdr = make<PhdrEntry>(PT_TLS, PF_R); | |
| 2139 | for (OutputSection *sec : outputSections) | |
| 2140 | if (sec->partition == partNo && sec->flags & SHF_TLS) | |
| 2141 | tlsHdr->add(sec); | |
| 2142 | if (tlsHdr->firstSec) | |
| 2143 | ret.push_back(tlsHdr); | |
| 1948 | 2144 | |
| 1949 | 2145 | // Add an entry for .dynamic. |
| 1950 | if (OutputSection *Sec = In.Dynamic->getParent()) | |
| 1951 | AddHdr(PT_DYNAMIC, Sec->getPhdrFlags())->add(Sec); | |
| 2146 | if (OutputSection *sec = part.dynamic->getParent()) | |
| 2147 | addHdr(PT_DYNAMIC, sec->getPhdrFlags())->add(sec); | |
| 1952 | 2148 | |
| 1953 | // PT_GNU_RELRO includes all sections that should be marked as | |
| 1954 | // read-only by dynamic linker after proccessing relocations. | |
| 1955 | // Current dynamic loaders only support one PT_GNU_RELRO PHDR, give | |
| 1956 | // an error message if more than one PT_GNU_RELRO PHDR is required. | |
| 1957 | PhdrEntry *RelRo = make<PhdrEntry>(PT_GNU_RELRO, PF_R); | |
| 1958 | bool InRelroPhdr = false; | |
| 1959 | bool IsRelroFinished = false; | |
| 1960 | for (OutputSection *Sec : OutputSections) { | |
| 1961 | if (!needsPtLoad(Sec)) | |
| 1962 | continue; | |
| 1963 | if (isRelroSection(Sec)) { | |
| 1964 | InRelroPhdr = true; | |
| 1965 | if (!IsRelroFinished) | |
| 1966 | RelRo->add(Sec); | |
| 1967 | else | |
| 1968 | error("section: " + Sec->Name + " is not contiguous with other relro" + | |
| 1969 | " sections"); | |
| 1970 | } else if (InRelroPhdr) { | |
| 1971 | InRelroPhdr = false; | |
| 1972 | IsRelroFinished = true; | |
| 1973 | } | |
| 1974 | } | |
| 1975 | if (RelRo->FirstSec) | |
| 1976 | Ret.push_back(RelRo); | |
| 2149 | if (relRo->firstSec) | |
| 2150 | ret.push_back(relRo); | |
| 1977 | 2151 | |
| 1978 | 2152 | // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr. |
| 1979 | if (!In.EhFrame->empty() && In.EhFrameHdr && In.EhFrame->getParent() && | |
| 1980 | In.EhFrameHdr->getParent()) | |
| 1981 | AddHdr(PT_GNU_EH_FRAME, In.EhFrameHdr->getParent()->getPhdrFlags()) | |
| 1982 | ->add(In.EhFrameHdr->getParent()); | |
| 2153 | if (part.ehFrame->isNeeded() && part.ehFrameHdr && | |
| 2154 | part.ehFrame->getParent() && part.ehFrameHdr->getParent()) | |
| 2155 | addHdr(PT_GNU_EH_FRAME, part.ehFrameHdr->getParent()->getPhdrFlags()) | |
| 2156 | ->add(part.ehFrameHdr->getParent()); | |
| 1983 | 2157 | |
| 1984 | 2158 | // PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes |
| 1985 | 2159 | // the dynamic linker fill the segment with random data. |
| 1986 | if (OutputSection *Cmd = findSection(".openbsd.randomdata")) | |
| 1987 | AddHdr(PT_OPENBSD_RANDOMIZE, Cmd->getPhdrFlags())->add(Cmd); | |
| 2160 | if (OutputSection *cmd = findSection(".openbsd.randomdata", partNo)) | |
| 2161 | addHdr(PT_OPENBSD_RANDOMIZE, cmd->getPhdrFlags())->add(cmd); | |
| 1988 | 2162 | |
| 1989 | 2163 | // PT_GNU_STACK is a special section to tell the loader to make the |
| 1990 | 2164 | // pages for the stack non-executable. If you really want an executable |
| 1991 | 2165 | // stack, you can pass -z execstack, but that's not recommended for |
| 1992 | 2166 | // security reasons. |
| 1993 | unsigned Perm = PF_R | PF_W; | |
| 1994 | if (Config->ZExecstack) | |
| 1995 | Perm |= PF_X; | |
| 1996 | AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize; | |
| 2167 | unsigned perm = PF_R | PF_W; | |
| 2168 | if (config->zExecstack) | |
| 2169 | perm |= PF_X; | |
| 2170 | addHdr(PT_GNU_STACK, perm)->p_memsz = config->zStackSize; | |
| 1997 | 2171 | |
| 1998 | 2172 | // PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable |
| 1999 | 2173 | // is expected to perform W^X violations, such as calling mprotect(2) or |
| 2000 | 2174 | // mmap(2) with PROT_WRITE | PROT_EXEC, which is prohibited by default on |
| 2001 | 2175 | // OpenBSD. |
| 2002 | if (Config->ZWxneeded) | |
| 2003 | AddHdr(PT_OPENBSD_WXNEEDED, PF_X); | |
| 2004 | ||
| 2005 | // Create one PT_NOTE per a group of contiguous .note sections. | |
| 2006 | PhdrEntry *Note = nullptr; | |
| 2007 | for (OutputSection *Sec : OutputSections) { | |
| 2008 | if (Sec->Type == SHT_NOTE && (Sec->Flags & SHF_ALLOC)) { | |
| 2009 | if (!Note || Sec->LMAExpr) | |
| 2010 | Note = AddHdr(PT_NOTE, PF_R); | |
| 2011 | Note->add(Sec); | |
| 2176 | if (config->zWxneeded) | |
| 2177 | addHdr(PT_OPENBSD_WXNEEDED, PF_X); | |
| 2178 | ||
| 2179 | // Create one PT_NOTE per a group of contiguous SHT_NOTE sections with the | |
| 2180 | // same alignment. | |
| 2181 | PhdrEntry *note = nullptr; | |
| 2182 | for (OutputSection *sec : outputSections) { | |
| 2183 | if (sec->partition != partNo) | |
| 2184 | continue; | |
| 2185 | if (sec->type == SHT_NOTE && (sec->flags & SHF_ALLOC)) { | |
| 2186 | if (!note || sec->lmaExpr || note->lastSec->alignment != sec->alignment) | |
| 2187 | note = addHdr(PT_NOTE, PF_R); | |
| 2188 | note->add(sec); | |
| 2012 | 2189 | } else { |
| 2013 | Note = nullptr; | |
| 2190 | note = nullptr; | |
| 2014 | 2191 | } |
| 2015 | 2192 | } |
| 2016 | return Ret; | |
| 2193 | return ret; | |
| 2017 | 2194 | } |
| 2018 | 2195 | |
| 2019 | 2196 | template <class ELFT> |
| 2020 | void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry *> &Phdrs) { | |
| 2021 | if (Config->EMachine != EM_ARM) | |
| 2022 | return; | |
| 2023 | auto I = llvm::find_if(OutputSections, [](OutputSection *Cmd) { | |
| 2024 | return Cmd->Type == SHT_ARM_EXIDX; | |
| 2197 | void Writer<ELFT>::addPhdrForSection(Partition &part, unsigned shType, | |
| 2198 | unsigned pType, unsigned pFlags) { | |
| 2199 | unsigned partNo = part.getNumber(); | |
| 2200 | auto i = llvm::find_if(outputSections, [=](OutputSection *cmd) { | |
| 2201 | return cmd->partition == partNo && cmd->type == shType; | |
| 2025 | 2202 | }); |
| 2026 | if (I == OutputSections.end()) | |
| 2203 | if (i == outputSections.end()) | |
| 2027 | 2204 | return; |
| 2028 | 2205 | |
| 2029 | // PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME | |
| 2030 | PhdrEntry *ARMExidx = make<PhdrEntry>(PT_ARM_EXIDX, PF_R); | |
| 2031 | ARMExidx->add(*I); | |
| 2032 | Phdrs.push_back(ARMExidx); | |
| 2206 | PhdrEntry *entry = make<PhdrEntry>(pType, pFlags); | |
| 2207 | entry->add(*i); | |
| 2208 | part.phdrs.push_back(entry); | |
| 2033 | 2209 | } |
| 2034 | 2210 | |
| 2035 | 2211 | // The first section of each PT_LOAD, the first section in PT_GNU_RELRO and the |
| 2036 | 2212 | // first section after PT_GNU_RELRO have to be page aligned so that the dynamic |
| 2037 | 2213 | // linker can set the permissions. |
| 2038 | 2214 | template <class ELFT> void Writer<ELFT>::fixSectionAlignments() { |
| 2039 | auto PageAlign = [](OutputSection *Cmd) { | |
| 2040 | if (Cmd && !Cmd->AddrExpr) | |
| 2041 | Cmd->AddrExpr = [=] { | |
| 2042 | return alignTo(Script->getDot(), Config->MaxPageSize); | |
| 2215 | auto pageAlign = [](OutputSection *cmd) { | |
| 2216 | if (cmd && !cmd->addrExpr) | |
| 2217 | cmd->addrExpr = [=] { | |
| 2218 | return alignTo(script->getDot(), config->maxPageSize); | |
| 2043 | 2219 | }; |
| 2044 | 2220 | }; |
| 2045 | 2221 | |
| 2046 | for (const PhdrEntry *P : Phdrs) | |
| 2047 | if (P->p_type == PT_LOAD && P->FirstSec) | |
| 2048 | PageAlign(P->FirstSec); | |
| 2049 | ||
| 2050 | for (const PhdrEntry *P : Phdrs) { | |
| 2051 | if (P->p_type != PT_GNU_RELRO) | |
| 2052 | continue; | |
| 2053 | ||
| 2054 | if (P->FirstSec) | |
| 2055 | PageAlign(P->FirstSec); | |
| 2056 | ||
| 2057 | // Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we | |
| 2058 | // have to align it to a page. | |
| 2059 | auto End = OutputSections.end(); | |
| 2060 | auto I = std::find(OutputSections.begin(), End, P->LastSec); | |
| 2061 | if (I == End || (I + 1) == End) | |
| 2062 | continue; | |
| 2063 | ||
| 2064 | OutputSection *Cmd = (*(I + 1)); | |
| 2065 | if (needsPtLoad(Cmd)) | |
| 2066 | PageAlign(Cmd); | |
| 2222 | for (Partition &part : partitions) { | |
| 2223 | for (const PhdrEntry *p : part.phdrs) | |
| 2224 | if (p->p_type == PT_LOAD && p->firstSec) | |
| 2225 | pageAlign(p->firstSec); | |
| 2067 | 2226 | } |
| 2068 | 2227 | } |
| 2069 | 2228 | |
| 2070 | 2229 | // Compute an in-file position for a given section. The file offset must be the |
| 2071 | 2230 | // same with its virtual address modulo the page size, so that the loader can |
| 2072 | 2231 | // load executables without any address adjustment. |
| 2073 | static uint64_t computeFileOffset(OutputSection *OS, uint64_t Off) { | |
| 2232 | static uint64_t computeFileOffset(OutputSection *os, uint64_t off) { | |
| 2074 | 2233 | // File offsets are not significant for .bss sections. By convention, we keep |
| 2075 | 2234 | // section offsets monotonically increasing rather than setting to zero. |
| 2076 | if (OS->Type == SHT_NOBITS) | |
| 2077 | return Off; | |
| 2235 | if (os->type == SHT_NOBITS) | |
| 2236 | return off; | |
| 2078 | 2237 | |
| 2079 | 2238 | // If the section is not in a PT_LOAD, we just have to align it. |
| 2080 | if (!OS->PtLoad) | |
| 2081 | return alignTo(Off, OS->Alignment); | |
| 2239 | if (!os->ptLoad) | |
| 2240 | return alignTo(off, os->alignment); | |
| 2082 | 2241 | |
| 2083 | 2242 | // The first section in a PT_LOAD has to have congruent offset and address |
| 2084 | 2243 | // module the page size. |
| 2085 | OutputSection *First = OS->PtLoad->FirstSec; | |
| 2086 | if (OS == First) { | |
| 2087 | uint64_t Alignment = std::max<uint64_t>(OS->Alignment, Config->MaxPageSize); | |
| 2088 | return alignTo(Off, Alignment, OS->Addr); | |
| 2244 | OutputSection *first = os->ptLoad->firstSec; | |
| 2245 | if (os == first) { | |
| 2246 | uint64_t alignment = std::max<uint64_t>(os->alignment, config->maxPageSize); | |
| 2247 | return alignTo(off, alignment, os->addr); | |
| 2089 | 2248 | } |
| 2090 | 2249 | |
| 2091 | 2250 | // If two sections share the same PT_LOAD the file offset is calculated |
| 2092 | 2251 | // using this formula: Off2 = Off1 + (VA2 - VA1). |
| 2093 | return First->Offset + OS->Addr - First->Addr; | |
| 2252 | return first->offset + os->addr - first->addr; | |
| 2094 | 2253 | } |
| 2095 | 2254 | |
| 2096 | 2255 | // Set an in-file position to a given section and returns the end position of |
| 2097 | 2256 | // the section. |
| 2098 | static uint64_t setFileOffset(OutputSection *OS, uint64_t Off) { | |
| 2099 | Off = computeFileOffset(OS, Off); | |
| 2100 | OS->Offset = Off; | |
| 2257 | static uint64_t setFileOffset(OutputSection *os, uint64_t off) { | |
| 2258 | off = computeFileOffset(os, off); | |
| 2259 | os->offset = off; | |
| 2101 | 2260 | |
| 2102 | if (OS->Type == SHT_NOBITS) | |
| 2103 | return Off; | |
| 2104 | return Off + OS->Size; | |
| 2261 | if (os->type == SHT_NOBITS) | |
| 2262 | return off; | |
| 2263 | return off + os->size; | |
| 2105 | 2264 | } |
| 2106 | 2265 | |
| 2107 | 2266 | template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() { |
| 2108 | uint64_t Off = 0; | |
| 2109 | for (OutputSection *Sec : OutputSections) | |
| 2110 | if (Sec->Flags & SHF_ALLOC) | |
| 2111 | Off = setFileOffset(Sec, Off); | |
| 2112 | FileSize = alignTo(Off, Config->Wordsize); | |
| 2267 | uint64_t off = 0; | |
| 2268 | for (OutputSection *sec : outputSections) | |
| 2269 | if (sec->flags & SHF_ALLOC) | |
| 2270 | off = setFileOffset(sec, off); | |
| 2271 | fileSize = alignTo(off, config->wordsize); | |
| 2113 | 2272 | } |
| 2114 | 2273 | |
| 2115 | static std::string rangeToString(uint64_t Addr, uint64_t Len) { | |
| 2116 | return "[0x" + utohexstr(Addr) + ", 0x" + utohexstr(Addr + Len - 1) + "]"; | |
| 2274 | static std::string rangeToString(uint64_t addr, uint64_t len) { | |
| 2275 | return "[0x" + utohexstr(addr) + ", 0x" + utohexstr(addr + len - 1) + "]"; | |
| 2117 | 2276 | } |
| 2118 | 2277 | |
| 2119 | 2278 | // Assign file offsets to output sections. |
| 2120 | 2279 | template <class ELFT> void Writer<ELFT>::assignFileOffsets() { |
| 2121 | uint64_t Off = 0; | |
| 2122 | Off = setFileOffset(Out::ElfHeader, Off); | |
| 2123 | Off = setFileOffset(Out::ProgramHeaders, Off); | |
| 2124 | ||
| 2125 | PhdrEntry *LastRX = nullptr; | |
| 2126 | for (PhdrEntry *P : Phdrs) | |
| 2127 | if (P->p_type == PT_LOAD && (P->p_flags & PF_X)) | |
| 2128 | LastRX = P; | |
| 2129 | ||
| 2130 | for (OutputSection *Sec : OutputSections) { | |
| 2131 | Off = setFileOffset(Sec, Off); | |
| 2132 | if (Script->HasSectionsCommand) | |
| 2280 | uint64_t off = 0; | |
| 2281 | off = setFileOffset(Out::elfHeader, off); | |
| 2282 | off = setFileOffset(Out::programHeaders, off); | |
| 2283 | ||
| 2284 | PhdrEntry *lastRX = nullptr; | |
| 2285 | for (Partition &part : partitions) | |
| 2286 | for (PhdrEntry *p : part.phdrs) | |
| 2287 | if (p->p_type == PT_LOAD && (p->p_flags & PF_X)) | |
| 2288 | lastRX = p; | |
| 2289 | ||
| 2290 | for (OutputSection *sec : outputSections) { | |
| 2291 | off = setFileOffset(sec, off); | |
| 2292 | if (script->hasSectionsCommand) | |
| 2133 | 2293 | continue; |
| 2134 | 2294 | |
| 2135 | 2295 | // If this is a last section of the last executable segment and that |
| 2136 | 2296 | // segment is the last loadable segment, align the offset of the |
| 2137 | 2297 | // following section to avoid loading non-segments parts of the file. |
| 2138 | if (LastRX && LastRX->LastSec == Sec) | |
| 2139 | Off = alignTo(Off, Target->PageSize); | |
| 2298 | if (lastRX && lastRX->lastSec == sec) | |
| 2299 | off = alignTo(off, config->commonPageSize); | |
| 2140 | 2300 | } |
| 2141 | 2301 | |
| 2142 | SectionHeaderOff = alignTo(Off, Config->Wordsize); | |
| 2143 | FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr); | |
| 2302 | sectionHeaderOff = alignTo(off, config->wordsize); | |
| 2303 | fileSize = sectionHeaderOff + (outputSections.size() + 1) * sizeof(Elf_Shdr); | |
| 2144 | 2304 | |
| 2145 | 2305 | // Our logic assumes that sections have rising VA within the same segment. |
| 2146 | 2306 | // With use of linker scripts it is possible to violate this rule and get file |
| ... | ... | @@ -2151,62 +2311,49 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() { |
| 2151 | 2311 | // backwards, so we have to allow doing that to support linking them. We |
| 2152 | 2312 | // perform non-critical checks for overlaps in checkSectionOverlap(), but here |
| 2153 | 2313 | // we want to prevent file size overflows because it would crash the linker. |
| 2154 | for (OutputSection *Sec : OutputSections) { | |
| 2155 | if (Sec->Type == SHT_NOBITS) | |
| 2314 | for (OutputSection *sec : outputSections) { | |
| 2315 | if (sec->type == SHT_NOBITS) | |
| 2156 | 2316 | continue; |
| 2157 | if ((Sec->Offset > FileSize) || (Sec->Offset + Sec->Size > FileSize)) | |
| 2158 | error("unable to place section " + Sec->Name + " at file offset " + | |
| 2159 | rangeToString(Sec->Offset, Sec->Size) + | |
| 2317 | if ((sec->offset > fileSize) || (sec->offset + sec->size > fileSize)) | |
| 2318 | error("unable to place section " + sec->name + " at file offset " + | |
| 2319 | rangeToString(sec->offset, sec->size) + | |
| 2160 | 2320 | "; check your linker script for overflows"); |
| 2161 | 2321 | } |
| 2162 | 2322 | } |
| 2163 | 2323 | |
| 2164 | 2324 | // Finalize the program headers. We call this function after we assign |
| 2165 | 2325 | // file offsets and VAs to all sections. |
| 2166 | template <class ELFT> void Writer<ELFT>::setPhdrs() { | |
| 2167 | for (PhdrEntry *P : Phdrs) { | |
| 2168 | OutputSection *First = P->FirstSec; | |
| 2169 | OutputSection *Last = P->LastSec; | |
| 2170 | ||
| 2171 | if (First) { | |
| 2172 | P->p_filesz = Last->Offset - First->Offset; | |
| 2173 | if (Last->Type != SHT_NOBITS) | |
| 2174 | P->p_filesz += Last->Size; | |
| 2175 | ||
| 2176 | P->p_memsz = Last->Addr + Last->Size - First->Addr; | |
| 2177 | P->p_offset = First->Offset; | |
| 2178 | P->p_vaddr = First->Addr; | |
| 2179 | ||
| 2180 | if (!P->HasLMA) | |
| 2181 | P->p_paddr = First->getLMA(); | |
| 2326 | template <class ELFT> void Writer<ELFT>::setPhdrs(Partition &part) { | |
| 2327 | for (PhdrEntry *p : part.phdrs) { | |
| 2328 | OutputSection *first = p->firstSec; | |
| 2329 | OutputSection *last = p->lastSec; | |
| 2330 | ||
| 2331 | if (first) { | |
| 2332 | p->p_filesz = last->offset - first->offset; | |
| 2333 | if (last->type != SHT_NOBITS) | |
| 2334 | p->p_filesz += last->size; | |
| 2335 | ||
| 2336 | p->p_memsz = last->addr + last->size - first->addr; | |
| 2337 | p->p_offset = first->offset; | |
| 2338 | p->p_vaddr = first->addr; | |
| 2339 | ||
| 2340 | // File offsets in partitions other than the main partition are relative | |
| 2341 | // to the offset of the ELF headers. Perform that adjustment now. | |
| 2342 | if (part.elfHeader) | |
| 2343 | p->p_offset -= part.elfHeader->getParent()->offset; | |
| 2344 | ||
| 2345 | if (!p->hasLMA) | |
| 2346 | p->p_paddr = first->getLMA(); | |
| 2182 | 2347 | } |
| 2183 | 2348 | |
| 2184 | if (P->p_type == PT_LOAD) { | |
| 2185 | P->p_align = std::max<uint64_t>(P->p_align, Config->MaxPageSize); | |
| 2186 | } else if (P->p_type == PT_GNU_RELRO) { | |
| 2187 | P->p_align = 1; | |
| 2349 | if (p->p_type == PT_LOAD) { | |
| 2350 | p->p_align = std::max<uint64_t>(p->p_align, config->maxPageSize); | |
| 2351 | } else if (p->p_type == PT_GNU_RELRO) { | |
| 2352 | p->p_align = 1; | |
| 2188 | 2353 | // The glibc dynamic loader rounds the size down, so we need to round up |
| 2189 | 2354 | // to protect the last page. This is a no-op on FreeBSD which always |
| 2190 | 2355 | // rounds up. |
| 2191 | P->p_memsz = alignTo(P->p_memsz, Target->PageSize); | |
| 2192 | } | |
| 2193 | ||
| 2194 | if (P->p_type == PT_TLS && P->p_memsz) { | |
| 2195 | if (!Config->Shared && | |
| 2196 | (Config->EMachine == EM_ARM || Config->EMachine == EM_AARCH64)) { | |
| 2197 | // On ARM/AArch64, reserve extra space (8 words) between the thread | |
| 2198 | // pointer and an executable's TLS segment by overaligning the segment. | |
| 2199 | // This reservation is needed for backwards compatibility with Android's | |
| 2200 | // TCB, which allocates several slots after the thread pointer (e.g. | |
| 2201 | // TLS_SLOT_STACK_GUARD==5). For simplicity, this overalignment is also | |
| 2202 | // done on other operating systems. | |
| 2203 | P->p_align = std::max<uint64_t>(P->p_align, Config->Wordsize * 8); | |
| 2204 | } | |
| 2205 | ||
| 2206 | // The TLS pointer goes after PT_TLS for variant 2 targets. At least glibc | |
| 2207 | // will align it, so round up the size to make sure the offsets are | |
| 2208 | // correct. | |
| 2209 | P->p_memsz = alignTo(P->p_memsz, P->p_align); | |
| 2356 | p->p_memsz = alignTo(p->p_memsz, config->commonPageSize); | |
| 2210 | 2357 | } |
| 2211 | 2358 | } |
| 2212 | 2359 | } |
| ... | ... | @@ -2214,37 +2361,37 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() { |
| 2214 | 2361 | // A helper struct for checkSectionOverlap. |
| 2215 | 2362 | namespace { |
| 2216 | 2363 | struct SectionOffset { |
| 2217 | OutputSection *Sec; | |
| 2218 | uint64_t Offset; | |
| 2364 | OutputSection *sec; | |
| 2365 | uint64_t offset; | |
| 2219 | 2366 | }; |
| 2220 | 2367 | } // namespace |
| 2221 | 2368 | |
| 2222 | 2369 | // Check whether sections overlap for a specific address range (file offsets, |
| 2223 | 2370 | // load and virtual adresses). |
| 2224 | static void checkOverlap(StringRef Name, std::vector<SectionOffset> &Sections, | |
| 2225 | bool IsVirtualAddr) { | |
| 2226 | llvm::sort(Sections, [=](const SectionOffset &A, const SectionOffset &B) { | |
| 2227 | return A.Offset < B.Offset; | |
| 2371 | static void checkOverlap(StringRef name, std::vector<SectionOffset> &sections, | |
| 2372 | bool isVirtualAddr) { | |
| 2373 | llvm::sort(sections, [=](const SectionOffset &a, const SectionOffset &b) { | |
| 2374 | return a.offset < b.offset; | |
| 2228 | 2375 | }); |
| 2229 | 2376 | |
| 2230 | 2377 | // Finding overlap is easy given a vector is sorted by start position. |
| 2231 | 2378 | // If an element starts before the end of the previous element, they overlap. |
| 2232 | for (size_t I = 1, End = Sections.size(); I < End; ++I) { | |
| 2233 | SectionOffset A = Sections[I - 1]; | |
| 2234 | SectionOffset B = Sections[I]; | |
| 2235 | if (B.Offset >= A.Offset + A.Sec->Size) | |
| 2379 | for (size_t i = 1, end = sections.size(); i < end; ++i) { | |
| 2380 | SectionOffset a = sections[i - 1]; | |
| 2381 | SectionOffset b = sections[i]; | |
| 2382 | if (b.offset >= a.offset + a.sec->size) | |
| 2236 | 2383 | continue; |
| 2237 | 2384 | |
| 2238 | 2385 | // If both sections are in OVERLAY we allow the overlapping of virtual |
| 2239 | 2386 | // addresses, because it is what OVERLAY was designed for. |
| 2240 | if (IsVirtualAddr && A.Sec->InOverlay && B.Sec->InOverlay) | |
| 2387 | if (isVirtualAddr && a.sec->inOverlay && b.sec->inOverlay) | |
| 2241 | 2388 | continue; |
| 2242 | 2389 | |
| 2243 | errorOrWarn("section " + A.Sec->Name + " " + Name + | |
| 2244 | " range overlaps with " + B.Sec->Name + "\n>>> " + A.Sec->Name + | |
| 2245 | " range is " + rangeToString(A.Offset, A.Sec->Size) + "\n>>> " + | |
| 2246 | B.Sec->Name + " range is " + | |
| 2247 | rangeToString(B.Offset, B.Sec->Size)); | |
| 2390 | errorOrWarn("section " + a.sec->name + " " + name + | |
| 2391 | " range overlaps with " + b.sec->name + "\n>>> " + a.sec->name + | |
| 2392 | " range is " + rangeToString(a.offset, a.sec->size) + "\n>>> " + | |
| 2393 | b.sec->name + " range is " + | |
| 2394 | rangeToString(b.offset, b.sec->size)); | |
| 2248 | 2395 | } |
| 2249 | 2396 | } |
| 2250 | 2397 | |
| ... | ... | @@ -2255,11 +2402,11 @@ static void checkOverlap(StringRef Name, std::vector<SectionOffset> &Sections, |
| 2255 | 2402 | // ranges and the virtual address ranges don't overlap |
| 2256 | 2403 | template <class ELFT> void Writer<ELFT>::checkSections() { |
| 2257 | 2404 | // First, check that section's VAs fit in available address space for target. |
| 2258 | for (OutputSection *OS : OutputSections) | |
| 2259 | if ((OS->Addr + OS->Size < OS->Addr) || | |
| 2260 | (!ELFT::Is64Bits && OS->Addr + OS->Size > UINT32_MAX)) | |
| 2261 | errorOrWarn("section " + OS->Name + " at 0x" + utohexstr(OS->Addr) + | |
| 2262 | " of size 0x" + utohexstr(OS->Size) + | |
| 2405 | for (OutputSection *os : outputSections) | |
| 2406 | if ((os->addr + os->size < os->addr) || | |
| 2407 | (!ELFT::Is64Bits && os->addr + os->size > UINT32_MAX)) | |
| 2408 | errorOrWarn("section " + os->name + " at 0x" + utohexstr(os->addr) + | |
| 2409 | " of size 0x" + utohexstr(os->size) + | |
| 2263 | 2410 | " exceeds available address space"); |
| 2264 | 2411 | |
| 2265 | 2412 | // Check for overlapping file offsets. In this case we need to skip any |
| ... | ... | @@ -2267,17 +2414,17 @@ template <class ELFT> void Writer<ELFT>::checkSections() { |
| 2267 | 2414 | // the file so Sec->Offset + Sec->Size can overlap with others. If --oformat |
| 2268 | 2415 | // binary is specified only add SHF_ALLOC sections are added to the output |
| 2269 | 2416 | // file so we skip any non-allocated sections in that case. |
| 2270 | std::vector<SectionOffset> FileOffs; | |
| 2271 | for (OutputSection *Sec : OutputSections) | |
| 2272 | if (Sec->Size > 0 && Sec->Type != SHT_NOBITS && | |
| 2273 | (!Config->OFormatBinary || (Sec->Flags & SHF_ALLOC))) | |
| 2274 | FileOffs.push_back({Sec, Sec->Offset}); | |
| 2275 | checkOverlap("file", FileOffs, false); | |
| 2417 | std::vector<SectionOffset> fileOffs; | |
| 2418 | for (OutputSection *sec : outputSections) | |
| 2419 | if (sec->size > 0 && sec->type != SHT_NOBITS && | |
| 2420 | (!config->oFormatBinary || (sec->flags & SHF_ALLOC))) | |
| 2421 | fileOffs.push_back({sec, sec->offset}); | |
| 2422 | checkOverlap("file", fileOffs, false); | |
| 2276 | 2423 | |
| 2277 | 2424 | // When linking with -r there is no need to check for overlapping virtual/load |
| 2278 | 2425 | // addresses since those addresses will only be assigned when the final |
| 2279 | 2426 | // executable/shared object is created. |
| 2280 | if (Config->Relocatable) | |
| 2427 | if (config->relocatable) | |
| 2281 | 2428 | return; |
| 2282 | 2429 | |
| 2283 | 2430 | // Checking for overlapping virtual and load addresses only needs to take |
| ... | ... | @@ -2285,20 +2432,20 @@ template <class ELFT> void Writer<ELFT>::checkSections() { |
| 2285 | 2432 | // Furthermore, we also need to skip SHF_TLS sections since these will be |
| 2286 | 2433 | // mapped to other addresses at runtime and can therefore have overlapping |
| 2287 | 2434 | // ranges in the file. |
| 2288 | std::vector<SectionOffset> VMAs; | |
| 2289 | for (OutputSection *Sec : OutputSections) | |
| 2290 | if (Sec->Size > 0 && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS)) | |
| 2291 | VMAs.push_back({Sec, Sec->Addr}); | |
| 2292 | checkOverlap("virtual address", VMAs, true); | |
| 2435 | std::vector<SectionOffset> vmas; | |
| 2436 | for (OutputSection *sec : outputSections) | |
| 2437 | if (sec->size > 0 && (sec->flags & SHF_ALLOC) && !(sec->flags & SHF_TLS)) | |
| 2438 | vmas.push_back({sec, sec->addr}); | |
| 2439 | checkOverlap("virtual address", vmas, true); | |
| 2293 | 2440 | |
| 2294 | 2441 | // Finally, check that the load addresses don't overlap. This will usually be |
| 2295 | 2442 | // the same as the virtual addresses but can be different when using a linker |
| 2296 | 2443 | // script with AT(). |
| 2297 | std::vector<SectionOffset> LMAs; | |
| 2298 | for (OutputSection *Sec : OutputSections) | |
| 2299 | if (Sec->Size > 0 && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS)) | |
| 2300 | LMAs.push_back({Sec, Sec->getLMA()}); | |
| 2301 | checkOverlap("load address", LMAs, false); | |
| 2444 | std::vector<SectionOffset> lmas; | |
| 2445 | for (OutputSection *sec : outputSections) | |
| 2446 | if (sec->size > 0 && (sec->flags & SHF_ALLOC) && !(sec->flags & SHF_TLS)) | |
| 2447 | lmas.push_back({sec, sec->getLMA()}); | |
| 2448 | checkOverlap("load address", lmas, false); | |
| 2302 | 2449 | } |
| 2303 | 2450 | |
| 2304 | 2451 | // The entry point address is chosen in the following ways. |
| ... | ... | @@ -2311,89 +2458,45 @@ template <class ELFT> void Writer<ELFT>::checkSections() { |
| 2311 | 2458 | // 6. the address 0. |
| 2312 | 2459 | static uint64_t getEntryAddr() { |
| 2313 | 2460 | // Case 1, 2 or 3 |
| 2314 | if (Symbol *B = Symtab->find(Config->Entry)) | |
| 2315 | return B->getVA(); | |
| 2461 | if (Symbol *b = symtab->find(config->entry)) | |
| 2462 | return b->getVA(); | |
| 2316 | 2463 | |
| 2317 | 2464 | // Case 4 |
| 2318 | uint64_t Addr; | |
| 2319 | if (to_integer(Config->Entry, Addr)) | |
| 2320 | return Addr; | |
| 2465 | uint64_t addr; | |
| 2466 | if (to_integer(config->entry, addr)) | |
| 2467 | return addr; | |
| 2321 | 2468 | |
| 2322 | 2469 | // Case 5 |
| 2323 | if (OutputSection *Sec = findSection(".text")) { | |
| 2324 | if (Config->WarnMissingEntry) | |
| 2325 | warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" + | |
| 2326 | utohexstr(Sec->Addr)); | |
| 2327 | return Sec->Addr; | |
| 2470 | if (OutputSection *sec = findSection(".text")) { | |
| 2471 | if (config->warnMissingEntry) | |
| 2472 | warn("cannot find entry symbol " + config->entry + "; defaulting to 0x" + | |
| 2473 | utohexstr(sec->addr)); | |
| 2474 | return sec->addr; | |
| 2328 | 2475 | } |
| 2329 | 2476 | |
| 2330 | 2477 | // Case 6 |
| 2331 | if (Config->WarnMissingEntry) | |
| 2332 | warn("cannot find entry symbol " + Config->Entry + | |
| 2478 | if (config->warnMissingEntry) | |
| 2479 | warn("cannot find entry symbol " + config->entry + | |
| 2333 | 2480 | "; not setting start address"); |
| 2334 | 2481 | return 0; |
| 2335 | 2482 | } |
| 2336 | 2483 | |
| 2337 | 2484 | static uint16_t getELFType() { |
| 2338 | if (Config->Pic) | |
| 2485 | if (config->isPic) | |
| 2339 | 2486 | return ET_DYN; |
| 2340 | if (Config->Relocatable) | |
| 2487 | if (config->relocatable) | |
| 2341 | 2488 | return ET_REL; |
| 2342 | 2489 | return ET_EXEC; |
| 2343 | 2490 | } |
| 2344 | 2491 | |
| 2345 | static uint8_t getAbiVersion() { | |
| 2346 | // MIPS non-PIC executable gets ABI version 1. | |
| 2347 | if (Config->EMachine == EM_MIPS && getELFType() == ET_EXEC && | |
| 2348 | (Config->EFlags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC) | |
| 2349 | return 1; | |
| 2350 | return 0; | |
| 2351 | } | |
| 2352 | ||
| 2353 | 2492 | template <class ELFT> void Writer<ELFT>::writeHeader() { |
| 2354 | uint8_t *Buf = Buffer->getBufferStart(); | |
| 2355 | ||
| 2356 | // For executable segments, the trap instructions are written before writing | |
| 2357 | // the header. Setting Elf header bytes to zero ensures that any unused bytes | |
| 2358 | // in header are zero-cleared, instead of having trap instructions. | |
| 2359 | memset(Buf, 0, sizeof(Elf_Ehdr)); | |
| 2360 | memcpy(Buf, "\177ELF", 4); | |
| 2361 | ||
| 2362 | // Write the ELF header. | |
| 2363 | auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf); | |
| 2364 | EHdr->e_ident[EI_CLASS] = Config->Is64 ? ELFCLASS64 : ELFCLASS32; | |
| 2365 | EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB; | |
| 2366 | EHdr->e_ident[EI_VERSION] = EV_CURRENT; | |
| 2367 | EHdr->e_ident[EI_OSABI] = Config->OSABI; | |
| 2368 | EHdr->e_ident[EI_ABIVERSION] = getAbiVersion(); | |
| 2369 | EHdr->e_type = getELFType(); | |
| 2370 | EHdr->e_machine = Config->EMachine; | |
| 2371 | EHdr->e_version = EV_CURRENT; | |
| 2372 | EHdr->e_entry = getEntryAddr(); | |
| 2373 | EHdr->e_shoff = SectionHeaderOff; | |
| 2374 | EHdr->e_flags = Config->EFlags; | |
| 2375 | EHdr->e_ehsize = sizeof(Elf_Ehdr); | |
| 2376 | EHdr->e_phnum = Phdrs.size(); | |
| 2377 | EHdr->e_shentsize = sizeof(Elf_Shdr); | |
| 2378 | ||
| 2379 | if (!Config->Relocatable) { | |
| 2380 | EHdr->e_phoff = sizeof(Elf_Ehdr); | |
| 2381 | EHdr->e_phentsize = sizeof(Elf_Phdr); | |
| 2382 | } | |
| 2383 | ||
| 2384 | // Write the program header table. | |
| 2385 | auto *HBuf = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff); | |
| 2386 | for (PhdrEntry *P : Phdrs) { | |
| 2387 | HBuf->p_type = P->p_type; | |
| 2388 | HBuf->p_flags = P->p_flags; | |
| 2389 | HBuf->p_offset = P->p_offset; | |
| 2390 | HBuf->p_vaddr = P->p_vaddr; | |
| 2391 | HBuf->p_paddr = P->p_paddr; | |
| 2392 | HBuf->p_filesz = P->p_filesz; | |
| 2393 | HBuf->p_memsz = P->p_memsz; | |
| 2394 | HBuf->p_align = P->p_align; | |
| 2395 | ++HBuf; | |
| 2396 | } | |
| 2493 | writeEhdr<ELFT>(Out::bufferStart, *mainPart); | |
| 2494 | writePhdrs<ELFT>(Out::bufferStart + sizeof(Elf_Ehdr), *mainPart); | |
| 2495 | ||
| 2496 | auto *eHdr = reinterpret_cast<Elf_Ehdr *>(Out::bufferStart); | |
| 2497 | eHdr->e_type = getELFType(); | |
| 2498 | eHdr->e_entry = getEntryAddr(); | |
| 2499 | eHdr->e_shoff = sectionHeaderOff; | |
| 2397 | 2500 | |
| 2398 | 2501 | // Write the section header table. |
| 2399 | 2502 | // |
| ... | ... | @@ -2404,57 +2507,58 @@ template <class ELFT> void Writer<ELFT>::writeHeader() { |
| 2404 | 2507 | // the value. The sentinel values and fields are: |
| 2405 | 2508 | // e_shnum = 0, SHdrs[0].sh_size = number of sections. |
| 2406 | 2509 | // e_shstrndx = SHN_XINDEX, SHdrs[0].sh_link = .shstrtab section index. |
| 2407 | auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff); | |
| 2408 | size_t Num = OutputSections.size() + 1; | |
| 2409 | if (Num >= SHN_LORESERVE) | |
| 2410 | SHdrs->sh_size = Num; | |
| 2510 | auto *sHdrs = reinterpret_cast<Elf_Shdr *>(Out::bufferStart + eHdr->e_shoff); | |
| 2511 | size_t num = outputSections.size() + 1; | |
| 2512 | if (num >= SHN_LORESERVE) | |
| 2513 | sHdrs->sh_size = num; | |
| 2411 | 2514 | else |
| 2412 | EHdr->e_shnum = Num; | |
| 2515 | eHdr->e_shnum = num; | |
| 2413 | 2516 | |
| 2414 | uint32_t StrTabIndex = In.ShStrTab->getParent()->SectionIndex; | |
| 2415 | if (StrTabIndex >= SHN_LORESERVE) { | |
| 2416 | SHdrs->sh_link = StrTabIndex; | |
| 2417 | EHdr->e_shstrndx = SHN_XINDEX; | |
| 2517 | uint32_t strTabIndex = in.shStrTab->getParent()->sectionIndex; | |
| 2518 | if (strTabIndex >= SHN_LORESERVE) { | |
| 2519 | sHdrs->sh_link = strTabIndex; | |
| 2520 | eHdr->e_shstrndx = SHN_XINDEX; | |
| 2418 | 2521 | } else { |
| 2419 | EHdr->e_shstrndx = StrTabIndex; | |
| 2522 | eHdr->e_shstrndx = strTabIndex; | |
| 2420 | 2523 | } |
| 2421 | 2524 | |
| 2422 | for (OutputSection *Sec : OutputSections) | |
| 2423 | Sec->writeHeaderTo<ELFT>(++SHdrs); | |
| 2525 | for (OutputSection *sec : outputSections) | |
| 2526 | sec->writeHeaderTo<ELFT>(++sHdrs); | |
| 2424 | 2527 | } |
| 2425 | 2528 | |
| 2426 | 2529 | // Open a result file. |
| 2427 | 2530 | template <class ELFT> void Writer<ELFT>::openFile() { |
| 2428 | uint64_t MaxSize = Config->Is64 ? INT64_MAX : UINT32_MAX; | |
| 2429 | if (MaxSize < FileSize) { | |
| 2430 | error("output file too large: " + Twine(FileSize) + " bytes"); | |
| 2531 | uint64_t maxSize = config->is64 ? INT64_MAX : UINT32_MAX; | |
| 2532 | if (fileSize != size_t(fileSize) || maxSize < fileSize) { | |
| 2533 | error("output file too large: " + Twine(fileSize) + " bytes"); | |
| 2431 | 2534 | return; |
| 2432 | 2535 | } |
| 2433 | 2536 | |
| 2434 | unlinkAsync(Config->OutputFile); | |
| 2435 | unsigned Flags = 0; | |
| 2436 | if (!Config->Relocatable) | |
| 2437 | Flags = FileOutputBuffer::F_executable; | |
| 2438 | Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = | |
| 2439 | FileOutputBuffer::create(Config->OutputFile, FileSize, Flags); | |
| 2537 | unlinkAsync(config->outputFile); | |
| 2538 | unsigned flags = 0; | |
| 2539 | if (!config->relocatable) | |
| 2540 | flags = FileOutputBuffer::F_executable; | |
| 2541 | Expected<std::unique_ptr<FileOutputBuffer>> bufferOrErr = | |
| 2542 | FileOutputBuffer::create(config->outputFile, fileSize, flags); | |
| 2440 | 2543 | |
| 2441 | if (!BufferOrErr) | |
| 2442 | error("failed to open " + Config->OutputFile + ": " + | |
| 2443 | llvm::toString(BufferOrErr.takeError())); | |
| 2444 | else | |
| 2445 | Buffer = std::move(*BufferOrErr); | |
| 2544 | if (!bufferOrErr) { | |
| 2545 | error("failed to open " + config->outputFile + ": " + | |
| 2546 | llvm::toString(bufferOrErr.takeError())); | |
| 2547 | return; | |
| 2548 | } | |
| 2549 | buffer = std::move(*bufferOrErr); | |
| 2550 | Out::bufferStart = buffer->getBufferStart(); | |
| 2446 | 2551 | } |
| 2447 | 2552 | |
| 2448 | 2553 | template <class ELFT> void Writer<ELFT>::writeSectionsBinary() { |
| 2449 | uint8_t *Buf = Buffer->getBufferStart(); | |
| 2450 | for (OutputSection *Sec : OutputSections) | |
| 2451 | if (Sec->Flags & SHF_ALLOC) | |
| 2452 | Sec->writeTo<ELFT>(Buf + Sec->Offset); | |
| 2554 | for (OutputSection *sec : outputSections) | |
| 2555 | if (sec->flags & SHF_ALLOC) | |
| 2556 | sec->writeTo<ELFT>(Out::bufferStart + sec->offset); | |
| 2453 | 2557 | } |
| 2454 | 2558 | |
| 2455 | static void fillTrap(uint8_t *I, uint8_t *End) { | |
| 2456 | for (; I + 4 <= End; I += 4) | |
| 2457 | memcpy(I, &Target->TrapInstr, 4); | |
| 2559 | static void fillTrap(uint8_t *i, uint8_t *end) { | |
| 2560 | for (; i + 4 <= end; i += 4) | |
| 2561 | memcpy(i, &target->trapInstr, 4); | |
| 2458 | 2562 | } |
| 2459 | 2563 | |
| 2460 | 2564 | // Fill the last page of executable segments with trap instructions |
| ... | ... | @@ -2464,61 +2568,119 @@ static void fillTrap(uint8_t *I, uint8_t *End) { |
| 2464 | 2568 | // We'll leave other pages in segments as-is because the rest will be |
| 2465 | 2569 | // overwritten by output sections. |
| 2466 | 2570 | template <class ELFT> void Writer<ELFT>::writeTrapInstr() { |
| 2467 | if (Script->HasSectionsCommand) | |
| 2571 | if (script->hasSectionsCommand) | |
| 2468 | 2572 | return; |
| 2469 | 2573 | |
| 2470 | // Fill the last page. | |
| 2471 | uint8_t *Buf = Buffer->getBufferStart(); | |
| 2472 | for (PhdrEntry *P : Phdrs) | |
| 2473 | if (P->p_type == PT_LOAD && (P->p_flags & PF_X)) | |
| 2474 | fillTrap(Buf + alignDown(P->p_offset + P->p_filesz, Target->PageSize), | |
| 2475 | Buf + alignTo(P->p_offset + P->p_filesz, Target->PageSize)); | |
| 2476 | ||
| 2477 | // Round up the file size of the last segment to the page boundary iff it is | |
| 2478 | // an executable segment to ensure that other tools don't accidentally | |
| 2479 | // trim the instruction padding (e.g. when stripping the file). | |
| 2480 | PhdrEntry *Last = nullptr; | |
| 2481 | for (PhdrEntry *P : Phdrs) | |
| 2482 | if (P->p_type == PT_LOAD) | |
| 2483 | Last = P; | |
| 2484 | ||
| 2485 | if (Last && (Last->p_flags & PF_X)) | |
| 2486 | Last->p_memsz = Last->p_filesz = alignTo(Last->p_filesz, Target->PageSize); | |
| 2574 | for (Partition &part : partitions) { | |
| 2575 | // Fill the last page. | |
| 2576 | for (PhdrEntry *p : part.phdrs) | |
| 2577 | if (p->p_type == PT_LOAD && (p->p_flags & PF_X)) | |
| 2578 | fillTrap(Out::bufferStart + alignDown(p->firstSec->offset + p->p_filesz, | |
| 2579 | config->commonPageSize), | |
| 2580 | Out::bufferStart + alignTo(p->firstSec->offset + p->p_filesz, | |
| 2581 | config->commonPageSize)); | |
| 2582 | ||
| 2583 | // Round up the file size of the last segment to the page boundary iff it is | |
| 2584 | // an executable segment to ensure that other tools don't accidentally | |
| 2585 | // trim the instruction padding (e.g. when stripping the file). | |
| 2586 | PhdrEntry *last = nullptr; | |
| 2587 | for (PhdrEntry *p : part.phdrs) | |
| 2588 | if (p->p_type == PT_LOAD) | |
| 2589 | last = p; | |
| 2590 | ||
| 2591 | if (last && (last->p_flags & PF_X)) | |
| 2592 | last->p_memsz = last->p_filesz = | |
| 2593 | alignTo(last->p_filesz, config->commonPageSize); | |
| 2594 | } | |
| 2487 | 2595 | } |
| 2488 | 2596 | |
| 2489 | 2597 | // Write section contents to a mmap'ed file. |
| 2490 | 2598 | template <class ELFT> void Writer<ELFT>::writeSections() { |
| 2491 | uint8_t *Buf = Buffer->getBufferStart(); | |
| 2492 | ||
| 2493 | OutputSection *EhFrameHdr = nullptr; | |
| 2494 | if (In.EhFrameHdr && !In.EhFrameHdr->empty()) | |
| 2495 | EhFrameHdr = In.EhFrameHdr->getParent(); | |
| 2496 | ||
| 2497 | 2599 | // In -r or -emit-relocs mode, write the relocation sections first as in |
| 2498 | 2600 | // ELf_Rel targets we might find out that we need to modify the relocated |
| 2499 | 2601 | // section while doing it. |
| 2500 | for (OutputSection *Sec : OutputSections) | |
| 2501 | if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) | |
| 2502 | Sec->writeTo<ELFT>(Buf + Sec->Offset); | |
| 2602 | for (OutputSection *sec : outputSections) | |
| 2603 | if (sec->type == SHT_REL || sec->type == SHT_RELA) | |
| 2604 | sec->writeTo<ELFT>(Out::bufferStart + sec->offset); | |
| 2605 | ||
| 2606 | for (OutputSection *sec : outputSections) | |
| 2607 | if (sec->type != SHT_REL && sec->type != SHT_RELA) | |
| 2608 | sec->writeTo<ELFT>(Out::bufferStart + sec->offset); | |
| 2609 | } | |
| 2610 | ||
| 2611 | // Split one uint8 array into small pieces of uint8 arrays. | |
| 2612 | static std::vector<ArrayRef<uint8_t>> split(ArrayRef<uint8_t> arr, | |
| 2613 | size_t chunkSize) { | |
| 2614 | std::vector<ArrayRef<uint8_t>> ret; | |
| 2615 | while (arr.size() > chunkSize) { | |
| 2616 | ret.push_back(arr.take_front(chunkSize)); | |
| 2617 | arr = arr.drop_front(chunkSize); | |
| 2618 | } | |
| 2619 | if (!arr.empty()) | |
| 2620 | ret.push_back(arr); | |
| 2621 | return ret; | |
| 2622 | } | |
| 2503 | 2623 | |
| 2504 | for (OutputSection *Sec : OutputSections) | |
| 2505 | if (Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA) | |
| 2506 | Sec->writeTo<ELFT>(Buf + Sec->Offset); | |
| 2624 | // Computes a hash value of Data using a given hash function. | |
| 2625 | // In order to utilize multiple cores, we first split data into 1MB | |
| 2626 | // chunks, compute a hash for each chunk, and then compute a hash value | |
| 2627 | // of the hash values. | |
| 2628 | static void | |
| 2629 | computeHash(llvm::MutableArrayRef<uint8_t> hashBuf, | |
| 2630 | llvm::ArrayRef<uint8_t> data, | |
| 2631 | std::function<void(uint8_t *dest, ArrayRef<uint8_t> arr)> hashFn) { | |
| 2632 | std::vector<ArrayRef<uint8_t>> chunks = split(data, 1024 * 1024); | |
| 2633 | std::vector<uint8_t> hashes(chunks.size() * hashBuf.size()); | |
| 2634 | ||
| 2635 | // Compute hash values. | |
| 2636 | parallelForEachN(0, chunks.size(), [&](size_t i) { | |
| 2637 | hashFn(hashes.data() + i * hashBuf.size(), chunks[i]); | |
| 2638 | }); | |
| 2507 | 2639 | |
| 2508 | // The .eh_frame_hdr depends on .eh_frame section contents, therefore | |
| 2509 | // it should be written after .eh_frame is written. | |
| 2510 | if (EhFrameHdr) | |
| 2511 | EhFrameHdr->writeTo<ELFT>(Buf + EhFrameHdr->Offset); | |
| 2640 | // Write to the final output buffer. | |
| 2641 | hashFn(hashBuf.data(), hashes); | |
| 2512 | 2642 | } |
| 2513 | 2643 | |
| 2514 | 2644 | template <class ELFT> void Writer<ELFT>::writeBuildId() { |
| 2515 | if (!In.BuildId || !In.BuildId->getParent()) | |
| 2645 | if (!mainPart->buildId || !mainPart->buildId->getParent()) | |
| 2516 | 2646 | return; |
| 2517 | 2647 | |
| 2648 | if (config->buildId == BuildIdKind::Hexstring) { | |
| 2649 | for (Partition &part : partitions) | |
| 2650 | part.buildId->writeBuildId(config->buildIdVector); | |
| 2651 | return; | |
| 2652 | } | |
| 2653 | ||
| 2518 | 2654 | // Compute a hash of all sections of the output file. |
| 2519 | uint8_t *Start = Buffer->getBufferStart(); | |
| 2520 | uint8_t *End = Start + FileSize; | |
| 2521 | In.BuildId->writeBuildId({Start, End}); | |
| 2655 | size_t hashSize = mainPart->buildId->hashSize; | |
| 2656 | std::vector<uint8_t> buildId(hashSize); | |
| 2657 | llvm::ArrayRef<uint8_t> buf{Out::bufferStart, size_t(fileSize)}; | |
| 2658 | ||
| 2659 | switch (config->buildId) { | |
| 2660 | case BuildIdKind::Fast: | |
| 2661 | computeHash(buildId, buf, [](uint8_t *dest, ArrayRef<uint8_t> arr) { | |
| 2662 | write64le(dest, xxHash64(arr)); | |
| 2663 | }); | |
| 2664 | break; | |
| 2665 | case BuildIdKind::Md5: | |
| 2666 | computeHash(buildId, buf, [&](uint8_t *dest, ArrayRef<uint8_t> arr) { | |
| 2667 | memcpy(dest, MD5::hash(arr).data(), hashSize); | |
| 2668 | }); | |
| 2669 | break; | |
| 2670 | case BuildIdKind::Sha1: | |
| 2671 | computeHash(buildId, buf, [&](uint8_t *dest, ArrayRef<uint8_t> arr) { | |
| 2672 | memcpy(dest, SHA1::hash(arr).data(), hashSize); | |
| 2673 | }); | |
| 2674 | break; | |
| 2675 | case BuildIdKind::Uuid: | |
| 2676 | if (auto ec = llvm::getRandomBytes(buildId.data(), hashSize)) | |
| 2677 | error("entropy source failure: " + ec.message()); | |
| 2678 | break; | |
| 2679 | default: | |
| 2680 | llvm_unreachable("unknown BuildIdKind"); | |
| 2681 | } | |
| 2682 | for (Partition &part : partitions) | |
| 2683 | part.buildId->writeBuildId(buildId); | |
| 2522 | 2684 | } |
| 2523 | 2685 | |
| 2524 | 2686 | template void elf::writeResult<ELF32LE>(); |
deps/lld/ELF/Writer.h+13-16| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Writer.h -------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -20,16 +19,14 @@ namespace elf { |
| 20 | 19 | class InputFile; |
| 21 | 20 | class OutputSection; |
| 22 | 21 | class InputSectionBase; |
| 23 | template <class ELFT> class ObjFile; | |
| 24 | class SymbolTable; | |
| 25 | 22 | template <class ELFT> void writeResult(); |
| 26 | 23 | |
| 27 | 24 | // This describes a program header entry. |
| 28 | 25 | // Each contains type, access flags and range of output sections that will be |
| 29 | 26 | // placed in it. |
| 30 | 27 | struct PhdrEntry { |
| 31 | PhdrEntry(unsigned Type, unsigned Flags) : p_type(Type), p_flags(Flags) {} | |
| 32 | void add(OutputSection *Sec); | |
| 28 | PhdrEntry(unsigned type, unsigned flags) : p_type(type), p_flags(flags) {} | |
| 29 | void add(OutputSection *sec); | |
| 33 | 30 | |
| 34 | 31 | uint64_t p_paddr = 0; |
| 35 | 32 | uint64_t p_vaddr = 0; |
| ... | ... | @@ -40,22 +37,22 @@ struct PhdrEntry { |
| 40 | 37 | uint32_t p_type = 0; |
| 41 | 38 | uint32_t p_flags = 0; |
| 42 | 39 | |
| 43 | OutputSection *FirstSec = nullptr; | |
| 44 | OutputSection *LastSec = nullptr; | |
| 45 | bool HasLMA = false; | |
| 40 | OutputSection *firstSec = nullptr; | |
| 41 | OutputSection *lastSec = nullptr; | |
| 42 | bool hasLMA = false; | |
| 46 | 43 | |
| 47 | uint64_t LMAOffset = 0; | |
| 44 | uint64_t lmaOffset = 0; | |
| 48 | 45 | }; |
| 49 | 46 | |
| 50 | 47 | void addReservedSymbols(); |
| 51 | llvm::StringRef getOutputSectionName(const InputSectionBase *S); | |
| 48 | llvm::StringRef getOutputSectionName(const InputSectionBase *s); | |
| 52 | 49 | |
| 53 | 50 | template <class ELFT> uint32_t calcMipsEFlags(); |
| 54 | 51 | |
| 55 | uint8_t getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag, | |
| 56 | llvm::StringRef FileName); | |
| 52 | uint8_t getMipsFpAbiFlag(uint8_t oldFlag, uint8_t newFlag, | |
| 53 | llvm::StringRef fileName); | |
| 57 | 54 | |
| 58 | bool isMipsN32Abi(const InputFile *F); | |
| 55 | bool isMipsN32Abi(const InputFile *f); | |
| 59 | 56 | bool isMicroMips(); |
| 60 | 57 | bool isMipsR6(); |
| 61 | 58 | } // namespace elf |
deps/lld/LICENSE.TXT+236-20| ... | ... | @@ -1,5 +1,240 @@ |
| 1 | 1 | ============================================================================== |
| 2 | lld License | |
| 2 | The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: | |
| 3 | ============================================================================== | |
| 4 | ||
| 5 | Apache License | |
| 6 | Version 2.0, January 2004 | |
| 7 | http://www.apache.org/licenses/ | |
| 8 | ||
| 9 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | |
| 10 | ||
| 11 | 1. Definitions. | |
| 12 | ||
| 13 | "License" shall mean the terms and conditions for use, reproduction, | |
| 14 | and distribution as defined by Sections 1 through 9 of this document. | |
| 15 | ||
| 16 | "Licensor" shall mean the copyright owner or entity authorized by | |
| 17 | the copyright owner that is granting the License. | |
| 18 | ||
| 19 | "Legal Entity" shall mean the union of the acting entity and all | |
| 20 | other entities that control, are controlled by, or are under common | |
| 21 | control with that entity. For the purposes of this definition, | |
| 22 | "control" means (i) the power, direct or indirect, to cause the | |
| 23 | direction or management of such entity, whether by contract or | |
| 24 | otherwise, or (ii) ownership of fifty percent (50%) or more of the | |
| 25 | outstanding shares, or (iii) beneficial ownership of such entity. | |
| 26 | ||
| 27 | "You" (or "Your") shall mean an individual or Legal Entity | |
| 28 | exercising permissions granted by this License. | |
| 29 | ||
| 30 | "Source" form shall mean the preferred form for making modifications, | |
| 31 | including but not limited to software source code, documentation | |
| 32 | source, and configuration files. | |
| 33 | ||
| 34 | "Object" form shall mean any form resulting from mechanical | |
| 35 | transformation or translation of a Source form, including but | |
| 36 | not limited to compiled object code, generated documentation, | |
| 37 | and conversions to other media types. | |
| 38 | ||
| 39 | "Work" shall mean the work of authorship, whether in Source or | |
| 40 | Object form, made available under the License, as indicated by a | |
| 41 | copyright notice that is included in or attached to the work | |
| 42 | (an example is provided in the Appendix below). | |
| 43 | ||
| 44 | "Derivative Works" shall mean any work, whether in Source or Object | |
| 45 | form, that is based on (or derived from) the Work and for which the | |
| 46 | editorial revisions, annotations, elaborations, or other modifications | |
| 47 | represent, as a whole, an original work of authorship. For the purposes | |
| 48 | of this License, Derivative Works shall not include works that remain | |
| 49 | separable from, or merely link (or bind by name) to the interfaces of, | |
| 50 | the Work and Derivative Works thereof. | |
| 51 | ||
| 52 | "Contribution" shall mean any work of authorship, including | |
| 53 | the original version of the Work and any modifications or additions | |
| 54 | to that Work or Derivative Works thereof, that is intentionally | |
| 55 | submitted to Licensor for inclusion in the Work by the copyright owner | |
| 56 | or by an individual or Legal Entity authorized to submit on behalf of | |
| 57 | the copyright owner. For the purposes of this definition, "submitted" | |
| 58 | means any form of electronic, verbal, or written communication sent | |
| 59 | to the Licensor or its representatives, including but not limited to | |
| 60 | communication on electronic mailing lists, source code control systems, | |
| 61 | and issue tracking systems that are managed by, or on behalf of, the | |
| 62 | Licensor for the purpose of discussing and improving the Work, but | |
| 63 | excluding communication that is conspicuously marked or otherwise | |
| 64 | designated in writing by the copyright owner as "Not a Contribution." | |
| 65 | ||
| 66 | "Contributor" shall mean Licensor and any individual or Legal Entity | |
| 67 | on behalf of whom a Contribution has been received by Licensor and | |
| 68 | subsequently incorporated within the Work. | |
| 69 | ||
| 70 | 2. Grant of Copyright License. Subject to the terms and conditions of | |
| 71 | this License, each Contributor hereby grants to You a perpetual, | |
| 72 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |
| 73 | copyright license to reproduce, prepare Derivative Works of, | |
| 74 | publicly display, publicly perform, sublicense, and distribute the | |
| 75 | Work and such Derivative Works in Source or Object form. | |
| 76 | ||
| 77 | 3. Grant of Patent License. Subject to the terms and conditions of | |
| 78 | this License, each Contributor hereby grants to You a perpetual, | |
| 79 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |
| 80 | (except as stated in this section) patent license to make, have made, | |
| 81 | use, offer to sell, sell, import, and otherwise transfer the Work, | |
| 82 | where such license applies only to those patent claims licensable | |
| 83 | by such Contributor that are necessarily infringed by their | |
| 84 | Contribution(s) alone or by combination of their Contribution(s) | |
| 85 | with the Work to which such Contribution(s) was submitted. If You | |
| 86 | institute patent litigation against any entity (including a | |
| 87 | cross-claim or counterclaim in a lawsuit) alleging that the Work | |
| 88 | or a Contribution incorporated within the Work constitutes direct | |
| 89 | or contributory patent infringement, then any patent licenses | |
| 90 | granted to You under this License for that Work shall terminate | |
| 91 | as of the date such litigation is filed. | |
| 92 | ||
| 93 | 4. Redistribution. You may reproduce and distribute copies of the | |
| 94 | Work or Derivative Works thereof in any medium, with or without | |
| 95 | modifications, and in Source or Object form, provided that You | |
| 96 | meet the following conditions: | |
| 97 | ||
| 98 | (a) You must give any other recipients of the Work or | |
| 99 | Derivative Works a copy of this License; and | |
| 100 | ||
| 101 | (b) You must cause any modified files to carry prominent notices | |
| 102 | stating that You changed the files; and | |
| 103 | ||
| 104 | (c) You must retain, in the Source form of any Derivative Works | |
| 105 | that You distribute, all copyright, patent, trademark, and | |
| 106 | attribution notices from the Source form of the Work, | |
| 107 | excluding those notices that do not pertain to any part of | |
| 108 | the Derivative Works; and | |
| 109 | ||
| 110 | (d) If the Work includes a "NOTICE" text file as part of its | |
| 111 | distribution, then any Derivative Works that You distribute must | |
| 112 | include a readable copy of the attribution notices contained | |
| 113 | within such NOTICE file, excluding those notices that do not | |
| 114 | pertain to any part of the Derivative Works, in at least one | |
| 115 | of the following places: within a NOTICE text file distributed | |
| 116 | as part of the Derivative Works; within the Source form or | |
| 117 | documentation, if provided along with the Derivative Works; or, | |
| 118 | within a display generated by the Derivative Works, if and | |
| 119 | wherever such third-party notices normally appear. The contents | |
| 120 | of the NOTICE file are for informational purposes only and | |
| 121 | do not modify the License. You may add Your own attribution | |
| 122 | notices within Derivative Works that You distribute, alongside | |
| 123 | or as an addendum to the NOTICE text from the Work, provided | |
| 124 | that such additional attribution notices cannot be construed | |
| 125 | as modifying the License. | |
| 126 | ||
| 127 | You may add Your own copyright statement to Your modifications and | |
| 128 | may provide additional or different license terms and conditions | |
| 129 | for use, reproduction, or distribution of Your modifications, or | |
| 130 | for any such Derivative Works as a whole, provided Your use, | |
| 131 | reproduction, and distribution of the Work otherwise complies with | |
| 132 | the conditions stated in this License. | |
| 133 | ||
| 134 | 5. Submission of Contributions. Unless You explicitly state otherwise, | |
| 135 | any Contribution intentionally submitted for inclusion in the Work | |
| 136 | by You to the Licensor shall be under the terms and conditions of | |
| 137 | this License, without any additional terms or conditions. | |
| 138 | Notwithstanding the above, nothing herein shall supersede or modify | |
| 139 | the terms of any separate license agreement you may have executed | |
| 140 | with Licensor regarding such Contributions. | |
| 141 | ||
| 142 | 6. Trademarks. This License does not grant permission to use the trade | |
| 143 | names, trademarks, service marks, or product names of the Licensor, | |
| 144 | except as required for reasonable and customary use in describing the | |
| 145 | origin of the Work and reproducing the content of the NOTICE file. | |
| 146 | ||
| 147 | 7. Disclaimer of Warranty. Unless required by applicable law or | |
| 148 | agreed to in writing, Licensor provides the Work (and each | |
| 149 | Contributor provides its Contributions) on an "AS IS" BASIS, | |
| 150 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |
| 151 | implied, including, without limitation, any warranties or conditions | |
| 152 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | |
| 153 | PARTICULAR PURPOSE. You are solely responsible for determining the | |
| 154 | appropriateness of using or redistributing the Work and assume any | |
| 155 | risks associated with Your exercise of permissions under this License. | |
| 156 | ||
| 157 | 8. Limitation of Liability. In no event and under no legal theory, | |
| 158 | whether in tort (including negligence), contract, or otherwise, | |
| 159 | unless required by applicable law (such as deliberate and grossly | |
| 160 | negligent acts) or agreed to in writing, shall any Contributor be | |
| 161 | liable to You for damages, including any direct, indirect, special, | |
| 162 | incidental, or consequential damages of any character arising as a | |
| 163 | result of this License or out of the use or inability to use the | |
| 164 | Work (including but not limited to damages for loss of goodwill, | |
| 165 | work stoppage, computer failure or malfunction, or any and all | |
| 166 | other commercial damages or losses), even if such Contributor | |
| 167 | has been advised of the possibility of such damages. | |
| 168 | ||
| 169 | 9. Accepting Warranty or Additional Liability. While redistributing | |
| 170 | the Work or Derivative Works thereof, You may choose to offer, | |
| 171 | and charge a fee for, acceptance of support, warranty, indemnity, | |
| 172 | or other liability obligations and/or rights consistent with this | |
| 173 | License. However, in accepting such obligations, You may act only | |
| 174 | on Your own behalf and on Your sole responsibility, not on behalf | |
| 175 | of any other Contributor, and only if You agree to indemnify, | |
| 176 | defend, and hold each Contributor harmless for any liability | |
| 177 | incurred by, or claims asserted against, such Contributor by reason | |
| 178 | of your accepting any such warranty or additional liability. | |
| 179 | ||
| 180 | END OF TERMS AND CONDITIONS | |
| 181 | ||
| 182 | APPENDIX: How to apply the Apache License to your work. | |
| 183 | ||
| 184 | To apply the Apache License to your work, attach the following | |
| 185 | boilerplate notice, with the fields enclosed by brackets "[]" | |
| 186 | replaced with your own identifying information. (Don't include | |
| 187 | the brackets!) The text should be enclosed in the appropriate | |
| 188 | comment syntax for the file format. We also recommend that a | |
| 189 | file or class name and description of purpose be included on the | |
| 190 | same "printed page" as the copyright notice for easier | |
| 191 | identification within third-party archives. | |
| 192 | ||
| 193 | Copyright [yyyy] [name of copyright owner] | |
| 194 | ||
| 195 | Licensed under the Apache License, Version 2.0 (the "License"); | |
| 196 | you may not use this file except in compliance with the License. | |
| 197 | You may obtain a copy of the License at | |
| 198 | ||
| 199 | http://www.apache.org/licenses/LICENSE-2.0 | |
| 200 | ||
| 201 | Unless required by applicable law or agreed to in writing, software | |
| 202 | distributed under the License is distributed on an "AS IS" BASIS, | |
| 203 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 204 | See the License for the specific language governing permissions and | |
| 205 | limitations under the License. | |
| 206 | ||
| 207 | ||
| 208 | ---- LLVM Exceptions to the Apache 2.0 License ---- | |
| 209 | ||
| 210 | As an exception, if, as a result of your compiling your source code, portions | |
| 211 | of this Software are embedded into an Object form of such source code, you | |
| 212 | may redistribute such embedded portions in such Object form without complying | |
| 213 | with the conditions of Sections 4(a), 4(b) and 4(d) of the License. | |
| 214 | ||
| 215 | In addition, if you combine or link compiled forms of this Software with | |
| 216 | software that is licensed under the GPLv2 ("Combined Software") and if a | |
| 217 | court of competent jurisdiction determines that the patent provision (Section | |
| 218 | 3), the indemnity provision (Section 9) or other Section of the License | |
| 219 | conflicts with the conditions of the GPLv2, you may retroactively and | |
| 220 | prospectively choose to deem waived or otherwise exclude such Section(s) of | |
| 221 | the License, but only in their entirety and only with respect to the Combined | |
| 222 | Software. | |
| 223 | ||
| 224 | ============================================================================== | |
| 225 | Software from third parties included in the LLVM Project: | |
| 226 | ============================================================================== | |
| 227 | The LLVM Project contains third party software which is under different license | |
| 228 | terms. All such code will be identified clearly using at least one of two | |
| 229 | mechanisms: | |
| 230 | 1) It will be in a separate directory tree with its own `LICENSE.txt` or | |
| 231 | `LICENSE` file at the top containing the specific license and restrictions | |
| 232 | which apply to that software, or | |
| 233 | 2) It will contain specific license and restriction terms at the top of every | |
| 234 | file. | |
| 235 | ||
| 236 | ============================================================================== | |
| 237 | Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): | |
| 3 | 238 | ============================================================================== |
| 4 | 239 | University of Illinois/NCSA |
| 5 | 240 | Open Source License |
| ... | ... | @@ -41,22 +276,3 @@ CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 41 | 276 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 42 | 277 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE |
| 43 | 278 | SOFTWARE. |
| 44 | ||
| 45 | ============================================================================== | |
| 46 | The lld software contains code written by third parties. Such software will | |
| 47 | have its own individual LICENSE.TXT file in the directory in which it appears. | |
| 48 | This file will describe the copyrights, license, and restrictions which apply | |
| 49 | to that code. | |
| 50 | ||
| 51 | The disclaimer of warranty in the University of Illinois Open Source License | |
| 52 | applies to all code in the lld Distribution, and nothing in any of the | |
| 53 | other licenses gives permission to use the names of the LLVM Team or the | |
| 54 | University of Illinois to endorse or promote products derived from this | |
| 55 | Software. | |
| 56 | ||
| 57 | The following pieces of software have additional or alternate copyrights, | |
| 58 | licenses, and/or restrictions: | |
| 59 | ||
| 60 | Program Directory | |
| 61 | ------- --------- | |
| 62 | <none yet> |
deps/lld/MinGW/Driver.cpp+216-145| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- MinGW/Driver.cpp ---------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -31,10 +30,13 @@ |
| 31 | 30 | |
| 32 | 31 | #include "lld/Common/Driver.h" |
| 33 | 32 | #include "lld/Common/ErrorHandler.h" |
| 33 | #include "lld/Common/Memory.h" | |
| 34 | #include "lld/Common/Version.h" | |
| 34 | 35 | #include "llvm/ADT/ArrayRef.h" |
| 35 | 36 | #include "llvm/ADT/Optional.h" |
| 36 | 37 | #include "llvm/ADT/StringExtras.h" |
| 37 | 38 | #include "llvm/ADT/StringRef.h" |
| 39 | #include "llvm/ADT/Triple.h" | |
| 38 | 40 | #include "llvm/Option/Arg.h" |
| 39 | 41 | #include "llvm/Option/ArgList.h" |
| 40 | 42 | #include "llvm/Option/Option.h" |
| ... | ... | @@ -63,7 +65,7 @@ enum { |
| 63 | 65 | #undef PREFIX |
| 64 | 66 | |
| 65 | 67 | // Create table mapping all options defined in Options.td |
| 66 | static const opt::OptTable::Info InfoTable[] = { | |
| 68 | static const opt::OptTable::Info infoTable[] = { | |
| 67 | 69 | #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ |
| 68 | 70 | {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ |
| 69 | 71 | X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, |
| ... | ... | @@ -74,208 +76,277 @@ static const opt::OptTable::Info InfoTable[] = { |
| 74 | 76 | namespace { |
| 75 | 77 | class MinGWOptTable : public opt::OptTable { |
| 76 | 78 | public: |
| 77 | MinGWOptTable() : OptTable(InfoTable, false) {} | |
| 78 | opt::InputArgList parse(ArrayRef<const char *> Argv); | |
| 79 | MinGWOptTable() : OptTable(infoTable, false) {} | |
| 80 | opt::InputArgList parse(ArrayRef<const char *> argv); | |
| 79 | 81 | }; |
| 80 | 82 | } // namespace |
| 81 | 83 | |
| 82 | opt::InputArgList MinGWOptTable::parse(ArrayRef<const char *> Argv) { | |
| 83 | unsigned MissingIndex; | |
| 84 | unsigned MissingCount; | |
| 84 | static void printHelp(const char *argv0) { | |
| 85 | MinGWOptTable().PrintHelp( | |
| 86 | outs(), (std::string(argv0) + " [options] file...").c_str(), "lld", | |
| 87 | false /*ShowHidden*/, true /*ShowAllAliases*/); | |
| 88 | outs() << "\n"; | |
| 89 | } | |
| 85 | 90 | |
| 86 | SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size()); | |
| 87 | opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount); | |
| 91 | static cl::TokenizerCallback getQuotingStyle() { | |
| 92 | if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32) | |
| 93 | return cl::TokenizeWindowsCommandLine; | |
| 94 | return cl::TokenizeGNUCommandLine; | |
| 95 | } | |
| 88 | 96 | |
| 89 | if (MissingCount) | |
| 90 | fatal(StringRef(Args.getArgString(MissingIndex)) + ": missing argument"); | |
| 91 | for (auto *Arg : Args.filtered(OPT_UNKNOWN)) | |
| 92 | fatal("unknown argument: " + Arg->getSpelling()); | |
| 93 | if (!Args.hasArg(OPT_INPUT) && !Args.hasArg(OPT_l)) | |
| 94 | fatal("no input files"); | |
| 95 | return Args; | |
| 97 | opt::InputArgList MinGWOptTable::parse(ArrayRef<const char *> argv) { | |
| 98 | unsigned missingIndex; | |
| 99 | unsigned missingCount; | |
| 100 | ||
| 101 | SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size()); | |
| 102 | cl::ExpandResponseFiles(saver, getQuotingStyle(), vec); | |
| 103 | opt::InputArgList args = this->ParseArgs(vec, missingIndex, missingCount); | |
| 104 | ||
| 105 | if (missingCount) | |
| 106 | fatal(StringRef(args.getArgString(missingIndex)) + ": missing argument"); | |
| 107 | for (auto *arg : args.filtered(OPT_UNKNOWN)) | |
| 108 | fatal("unknown argument: " + arg->getAsString(args)); | |
| 109 | return args; | |
| 96 | 110 | } |
| 97 | 111 | |
| 98 | 112 | // Find a file by concatenating given paths. |
| 99 | static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) { | |
| 100 | SmallString<128> S; | |
| 101 | sys::path::append(S, Path1, Path2); | |
| 102 | if (sys::fs::exists(S)) | |
| 103 | return S.str().str(); | |
| 113 | static Optional<std::string> findFile(StringRef path1, const Twine &path2) { | |
| 114 | SmallString<128> s; | |
| 115 | sys::path::append(s, path1, path2); | |
| 116 | if (sys::fs::exists(s)) | |
| 117 | return s.str().str(); | |
| 104 | 118 | return None; |
| 105 | 119 | } |
| 106 | 120 | |
| 107 | 121 | // This is for -lfoo. We'll look for libfoo.dll.a or libfoo.a from search paths. |
| 108 | 122 | static std::string |
| 109 | searchLibrary(StringRef Name, ArrayRef<StringRef> SearchPaths, bool BStatic) { | |
| 110 | if (Name.startswith(":")) { | |
| 111 | for (StringRef Dir : SearchPaths) | |
| 112 | if (Optional<std::string> S = findFile(Dir, Name.substr(1))) | |
| 113 | return *S; | |
| 114 | fatal("unable to find library -l" + Name); | |
| 123 | searchLibrary(StringRef name, ArrayRef<StringRef> searchPaths, bool bStatic) { | |
| 124 | if (name.startswith(":")) { | |
| 125 | for (StringRef dir : searchPaths) | |
| 126 | if (Optional<std::string> s = findFile(dir, name.substr(1))) | |
| 127 | return *s; | |
| 128 | fatal("unable to find library -l" + name); | |
| 115 | 129 | } |
| 116 | 130 | |
| 117 | for (StringRef Dir : SearchPaths) { | |
| 118 | if (!BStatic) | |
| 119 | if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".dll.a")) | |
| 120 | return *S; | |
| 121 | if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a")) | |
| 122 | return *S; | |
| 131 | for (StringRef dir : searchPaths) { | |
| 132 | if (!bStatic) | |
| 133 | if (Optional<std::string> s = findFile(dir, "lib" + name + ".dll.a")) | |
| 134 | return *s; | |
| 135 | if (Optional<std::string> s = findFile(dir, "lib" + name + ".a")) | |
| 136 | return *s; | |
| 123 | 137 | } |
| 124 | fatal("unable to find library -l" + Name); | |
| 138 | fatal("unable to find library -l" + name); | |
| 125 | 139 | } |
| 126 | 140 | |
| 127 | 141 | // Convert Unix-ish command line arguments to Windows-ish ones and |
| 128 | 142 | // then call coff::link. |
| 129 | bool mingw::link(ArrayRef<const char *> ArgsArr, raw_ostream &Diag) { | |
| 130 | MinGWOptTable Parser; | |
| 131 | opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); | |
| 143 | bool mingw::link(ArrayRef<const char *> argsArr, raw_ostream &diag) { | |
| 144 | MinGWOptTable parser; | |
| 145 | opt::InputArgList args = parser.parse(argsArr.slice(1)); | |
| 146 | ||
| 147 | if (args.hasArg(OPT_help)) { | |
| 148 | printHelp(argsArr[0]); | |
| 149 | return true; | |
| 150 | } | |
| 151 | ||
| 152 | // A note about "compatible with GNU linkers" message: this is a hack for | |
| 153 | // scripts generated by GNU Libtool 2.4.6 (released in February 2014 and | |
| 154 | // still the newest version in March 2017) or earlier to recognize LLD as | |
| 155 | // a GNU compatible linker. As long as an output for the -v option | |
| 156 | // contains "GNU" or "with BFD", they recognize us as GNU-compatible. | |
| 157 | if (args.hasArg(OPT_v) || args.hasArg(OPT_version)) | |
| 158 | message(getLLDVersion() + " (compatible with GNU linkers)"); | |
| 159 | ||
| 160 | // The behavior of -v or --version is a bit strange, but this is | |
| 161 | // needed for compatibility with GNU linkers. | |
| 162 | if (args.hasArg(OPT_v) && !args.hasArg(OPT_INPUT) && !args.hasArg(OPT_l)) | |
| 163 | return true; | |
| 164 | if (args.hasArg(OPT_version)) | |
| 165 | return true; | |
| 132 | 166 | |
| 133 | std::vector<std::string> LinkArgs; | |
| 134 | auto Add = [&](const Twine &S) { LinkArgs.push_back(S.str()); }; | |
| 167 | if (!args.hasArg(OPT_INPUT) && !args.hasArg(OPT_l)) | |
| 168 | fatal("no input files"); | |
| 169 | ||
| 170 | std::vector<std::string> linkArgs; | |
| 171 | auto add = [&](const Twine &s) { linkArgs.push_back(s.str()); }; | |
| 135 | 172 | |
| 136 | Add("lld-link"); | |
| 137 | Add("-lldmingw"); | |
| 173 | add("lld-link"); | |
| 174 | add("-lldmingw"); | |
| 138 | 175 | |
| 139 | if (auto *A = Args.getLastArg(OPT_entry)) { | |
| 140 | StringRef S = A->getValue(); | |
| 141 | if (Args.getLastArgValue(OPT_m) == "i386pe" && S.startswith("_")) | |
| 142 | Add("-entry:" + S.substr(1)); | |
| 176 | if (auto *a = args.getLastArg(OPT_entry)) { | |
| 177 | StringRef s = a->getValue(); | |
| 178 | if (args.getLastArgValue(OPT_m) == "i386pe" && s.startswith("_")) | |
| 179 | add("-entry:" + s.substr(1)); | |
| 143 | 180 | else |
| 144 | Add("-entry:" + S); | |
| 181 | add("-entry:" + s); | |
| 182 | } | |
| 183 | ||
| 184 | if (args.hasArg(OPT_major_os_version, OPT_minor_os_version, | |
| 185 | OPT_major_subsystem_version, OPT_minor_subsystem_version)) { | |
| 186 | auto *majOSVer = args.getLastArg(OPT_major_os_version); | |
| 187 | auto *minOSVer = args.getLastArg(OPT_minor_os_version); | |
| 188 | auto *majSubSysVer = args.getLastArg(OPT_major_subsystem_version); | |
| 189 | auto *minSubSysVer = args.getLastArg(OPT_minor_subsystem_version); | |
| 190 | if (majOSVer && majSubSysVer && | |
| 191 | StringRef(majOSVer->getValue()) != StringRef(majSubSysVer->getValue())) | |
| 192 | warn("--major-os-version and --major-subsystem-version set to differing " | |
| 193 | "versions, not supported"); | |
| 194 | if (minOSVer && minSubSysVer && | |
| 195 | StringRef(minOSVer->getValue()) != StringRef(minSubSysVer->getValue())) | |
| 196 | warn("--minor-os-version and --minor-subsystem-version set to differing " | |
| 197 | "versions, not supported"); | |
| 198 | StringRef subSys = args.getLastArgValue(OPT_subs, "default"); | |
| 199 | StringRef major = majOSVer ? majOSVer->getValue() | |
| 200 | : majSubSysVer ? majSubSysVer->getValue() : "6"; | |
| 201 | StringRef minor = minOSVer ? minOSVer->getValue() | |
| 202 | : minSubSysVer ? minSubSysVer->getValue() : ""; | |
| 203 | StringRef sep = minor.empty() ? "" : "."; | |
| 204 | add("-subsystem:" + subSys + "," + major + sep + minor); | |
| 205 | } else if (auto *a = args.getLastArg(OPT_subs)) { | |
| 206 | add("-subsystem:" + StringRef(a->getValue())); | |
| 145 | 207 | } |
| 146 | 208 | |
| 147 | if (auto *A = Args.getLastArg(OPT_subs)) | |
| 148 | Add("-subsystem:" + StringRef(A->getValue())); | |
| 149 | if (auto *A = Args.getLastArg(OPT_out_implib)) | |
| 150 | Add("-implib:" + StringRef(A->getValue())); | |
| 151 | if (auto *A = Args.getLastArg(OPT_stack)) | |
| 152 | Add("-stack:" + StringRef(A->getValue())); | |
| 153 | if (auto *A = Args.getLastArg(OPT_output_def)) | |
| 154 | Add("-output-def:" + StringRef(A->getValue())); | |
| 155 | if (auto *A = Args.getLastArg(OPT_image_base)) | |
| 156 | Add("-base:" + StringRef(A->getValue())); | |
| 157 | if (auto *A = Args.getLastArg(OPT_map)) | |
| 158 | Add("-lldmap:" + StringRef(A->getValue())); | |
| 159 | ||
| 160 | if (auto *A = Args.getLastArg(OPT_o)) | |
| 161 | Add("-out:" + StringRef(A->getValue())); | |
| 162 | else if (Args.hasArg(OPT_shared)) | |
| 163 | Add("-out:a.dll"); | |
| 209 | if (auto *a = args.getLastArg(OPT_out_implib)) | |
| 210 | add("-implib:" + StringRef(a->getValue())); | |
| 211 | if (auto *a = args.getLastArg(OPT_stack)) | |
| 212 | add("-stack:" + StringRef(a->getValue())); | |
| 213 | if (auto *a = args.getLastArg(OPT_output_def)) | |
| 214 | add("-output-def:" + StringRef(a->getValue())); | |
| 215 | if (auto *a = args.getLastArg(OPT_image_base)) | |
| 216 | add("-base:" + StringRef(a->getValue())); | |
| 217 | if (auto *a = args.getLastArg(OPT_map)) | |
| 218 | add("-lldmap:" + StringRef(a->getValue())); | |
| 219 | ||
| 220 | if (auto *a = args.getLastArg(OPT_o)) | |
| 221 | add("-out:" + StringRef(a->getValue())); | |
| 222 | else if (args.hasArg(OPT_shared)) | |
| 223 | add("-out:a.dll"); | |
| 164 | 224 | else |
| 165 | Add("-out:a.exe"); | |
| 166 | ||
| 167 | if (auto *A = Args.getLastArg(OPT_pdb)) { | |
| 168 | Add("-debug"); | |
| 169 | Add("-pdb:" + StringRef(A->getValue())); | |
| 170 | } else if (Args.hasArg(OPT_strip_debug)) { | |
| 171 | Add("-debug:symtab"); | |
| 172 | } else if (!Args.hasArg(OPT_strip_all)) { | |
| 173 | Add("-debug:dwarf"); | |
| 225 | add("-out:a.exe"); | |
| 226 | ||
| 227 | if (auto *a = args.getLastArg(OPT_pdb)) { | |
| 228 | add("-debug"); | |
| 229 | StringRef v = a->getValue(); | |
| 230 | if (!v.empty()) | |
| 231 | add("-pdb:" + v); | |
| 232 | } else if (args.hasArg(OPT_strip_debug)) { | |
| 233 | add("-debug:symtab"); | |
| 234 | } else if (!args.hasArg(OPT_strip_all)) { | |
| 235 | add("-debug:dwarf"); | |
| 174 | 236 | } |
| 175 | 237 | |
| 176 | if (Args.hasArg(OPT_shared)) | |
| 177 | Add("-dll"); | |
| 178 | if (Args.hasArg(OPT_verbose)) | |
| 179 | Add("-verbose"); | |
| 180 | if (Args.hasArg(OPT_export_all_symbols)) | |
| 181 | Add("-export-all-symbols"); | |
| 182 | if (Args.hasArg(OPT_large_address_aware)) | |
| 183 | Add("-largeaddressaware"); | |
| 184 | if (Args.hasArg(OPT_kill_at)) | |
| 185 | Add("-kill-at"); | |
| 186 | ||
| 187 | if (Args.getLastArgValue(OPT_m) != "thumb2pe" && | |
| 188 | Args.getLastArgValue(OPT_m) != "arm64pe" && !Args.hasArg(OPT_dynamicbase)) | |
| 189 | Add("-dynamicbase:no"); | |
| 190 | ||
| 191 | if (Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false)) | |
| 192 | Add("-opt:ref"); | |
| 238 | if (args.hasArg(OPT_shared)) | |
| 239 | add("-dll"); | |
| 240 | if (args.hasArg(OPT_verbose)) | |
| 241 | add("-verbose"); | |
| 242 | if (args.hasArg(OPT_exclude_all_symbols)) | |
| 243 | add("-exclude-all-symbols"); | |
| 244 | if (args.hasArg(OPT_export_all_symbols)) | |
| 245 | add("-export-all-symbols"); | |
| 246 | if (args.hasArg(OPT_large_address_aware)) | |
| 247 | add("-largeaddressaware"); | |
| 248 | if (args.hasArg(OPT_kill_at)) | |
| 249 | add("-kill-at"); | |
| 250 | if (args.hasArg(OPT_appcontainer)) | |
| 251 | add("-appcontainer"); | |
| 252 | ||
| 253 | if (args.getLastArgValue(OPT_m) != "thumb2pe" && | |
| 254 | args.getLastArgValue(OPT_m) != "arm64pe" && !args.hasArg(OPT_dynamicbase)) | |
| 255 | add("-dynamicbase:no"); | |
| 256 | ||
| 257 | if (args.hasFlag(OPT_no_insert_timestamp, OPT_insert_timestamp, false)) | |
| 258 | add("-timestamp:0"); | |
| 259 | ||
| 260 | if (args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false)) | |
| 261 | add("-opt:ref"); | |
| 193 | 262 | else |
| 194 | Add("-opt:noref"); | |
| 195 | ||
| 196 | if (auto *A = Args.getLastArg(OPT_icf)) { | |
| 197 | StringRef S = A->getValue(); | |
| 198 | if (S == "all") | |
| 199 | Add("-opt:icf"); | |
| 200 | else if (S == "safe" || S == "none") | |
| 201 | Add("-opt:noicf"); | |
| 263 | add("-opt:noref"); | |
| 264 | ||
| 265 | if (auto *a = args.getLastArg(OPT_icf)) { | |
| 266 | StringRef s = a->getValue(); | |
| 267 | if (s == "all") | |
| 268 | add("-opt:icf"); | |
| 269 | else if (s == "safe" || s == "none") | |
| 270 | add("-opt:noicf"); | |
| 202 | 271 | else |
| 203 | fatal("unknown parameter: --icf=" + S); | |
| 272 | fatal("unknown parameter: --icf=" + s); | |
| 204 | 273 | } else { |
| 205 | Add("-opt:noicf"); | |
| 274 | add("-opt:noicf"); | |
| 206 | 275 | } |
| 207 | 276 | |
| 208 | if (auto *A = Args.getLastArg(OPT_m)) { | |
| 209 | StringRef S = A->getValue(); | |
| 210 | if (S == "i386pe") | |
| 211 | Add("-machine:x86"); | |
| 212 | else if (S == "i386pep") | |
| 213 | Add("-machine:x64"); | |
| 214 | else if (S == "thumb2pe") | |
| 215 | Add("-machine:arm"); | |
| 216 | else if (S == "arm64pe") | |
| 217 | Add("-machine:arm64"); | |
| 277 | if (auto *a = args.getLastArg(OPT_m)) { | |
| 278 | StringRef s = a->getValue(); | |
| 279 | if (s == "i386pe") | |
| 280 | add("-machine:x86"); | |
| 281 | else if (s == "i386pep") | |
| 282 | add("-machine:x64"); | |
| 283 | else if (s == "thumb2pe") | |
| 284 | add("-machine:arm"); | |
| 285 | else if (s == "arm64pe") | |
| 286 | add("-machine:arm64"); | |
| 218 | 287 | else |
| 219 | fatal("unknown parameter: -m" + S); | |
| 288 | fatal("unknown parameter: -m" + s); | |
| 220 | 289 | } |
| 221 | 290 | |
| 222 | for (auto *A : Args.filtered(OPT_mllvm)) | |
| 223 | Add("-mllvm:" + StringRef(A->getValue())); | |
| 291 | for (auto *a : args.filtered(OPT_mllvm)) | |
| 292 | add("-mllvm:" + StringRef(a->getValue())); | |
| 224 | 293 | |
| 225 | for (auto *A : Args.filtered(OPT_Xlink)) | |
| 226 | Add(A->getValue()); | |
| 294 | for (auto *a : args.filtered(OPT_Xlink)) | |
| 295 | add(a->getValue()); | |
| 227 | 296 | |
| 228 | if (Args.getLastArgValue(OPT_m) == "i386pe") | |
| 229 | Add("-alternatename:__image_base__=___ImageBase"); | |
| 297 | if (args.getLastArgValue(OPT_m) == "i386pe") | |
| 298 | add("-alternatename:__image_base__=___ImageBase"); | |
| 230 | 299 | else |
| 231 | Add("-alternatename:__image_base__=__ImageBase"); | |
| 300 | add("-alternatename:__image_base__=__ImageBase"); | |
| 232 | 301 | |
| 233 | for (auto *A : Args.filtered(OPT_require_defined)) | |
| 234 | Add("-include:" + StringRef(A->getValue())); | |
| 302 | for (auto *a : args.filtered(OPT_require_defined)) | |
| 303 | add("-include:" + StringRef(a->getValue())); | |
| 304 | for (auto *a : args.filtered(OPT_undefined)) | |
| 305 | add("-includeoptional:" + StringRef(a->getValue())); | |
| 235 | 306 | |
| 236 | std::vector<StringRef> SearchPaths; | |
| 237 | for (auto *A : Args.filtered(OPT_L)) { | |
| 238 | SearchPaths.push_back(A->getValue()); | |
| 239 | Add("-libpath:" + StringRef(A->getValue())); | |
| 307 | std::vector<StringRef> searchPaths; | |
| 308 | for (auto *a : args.filtered(OPT_L)) { | |
| 309 | searchPaths.push_back(a->getValue()); | |
| 310 | add("-libpath:" + StringRef(a->getValue())); | |
| 240 | 311 | } |
| 241 | 312 | |
| 242 | StringRef Prefix = ""; | |
| 243 | bool Static = false; | |
| 244 | for (auto *A : Args) { | |
| 245 | switch (A->getOption().getUnaliasedOption().getID()) { | |
| 313 | StringRef prefix = ""; | |
| 314 | bool isStatic = false; | |
| 315 | for (auto *a : args) { | |
| 316 | switch (a->getOption().getID()) { | |
| 246 | 317 | case OPT_INPUT: |
| 247 | if (StringRef(A->getValue()).endswith_lower(".def")) | |
| 248 | Add("-def:" + StringRef(A->getValue())); | |
| 318 | if (StringRef(a->getValue()).endswith_lower(".def")) | |
| 319 | add("-def:" + StringRef(a->getValue())); | |
| 249 | 320 | else |
| 250 | Add(Prefix + StringRef(A->getValue())); | |
| 321 | add(prefix + StringRef(a->getValue())); | |
| 251 | 322 | break; |
| 252 | 323 | case OPT_l: |
| 253 | Add(Prefix + searchLibrary(A->getValue(), SearchPaths, Static)); | |
| 324 | add(prefix + searchLibrary(a->getValue(), searchPaths, isStatic)); | |
| 254 | 325 | break; |
| 255 | 326 | case OPT_whole_archive: |
| 256 | Prefix = "-wholearchive:"; | |
| 327 | prefix = "-wholearchive:"; | |
| 257 | 328 | break; |
| 258 | 329 | case OPT_no_whole_archive: |
| 259 | Prefix = ""; | |
| 330 | prefix = ""; | |
| 260 | 331 | break; |
| 261 | 332 | case OPT_Bstatic: |
| 262 | Static = true; | |
| 333 | isStatic = true; | |
| 263 | 334 | break; |
| 264 | 335 | case OPT_Bdynamic: |
| 265 | Static = false; | |
| 336 | isStatic = false; | |
| 266 | 337 | break; |
| 267 | 338 | } |
| 268 | 339 | } |
| 269 | 340 | |
| 270 | if (Args.hasArg(OPT_verbose) || Args.hasArg(OPT__HASH_HASH_HASH)) | |
| 271 | outs() << llvm::join(LinkArgs, " ") << "\n"; | |
| 341 | if (args.hasArg(OPT_verbose) || args.hasArg(OPT__HASH_HASH_HASH)) | |
| 342 | outs() << llvm::join(linkArgs, " ") << "\n"; | |
| 272 | 343 | |
| 273 | if (Args.hasArg(OPT__HASH_HASH_HASH)) | |
| 344 | if (args.hasArg(OPT__HASH_HASH_HASH)) | |
| 274 | 345 | return true; |
| 275 | 346 | |
| 276 | 347 | // Repack vector of strings to vector of const char pointers for coff::link. |
| 277 | std::vector<const char *> Vec; | |
| 278 | for (const std::string &S : LinkArgs) | |
| 279 | Vec.push_back(S.c_str()); | |
| 280 | return coff::link(Vec, true); | |
| 348 | std::vector<const char *> vec; | |
| 349 | for (const std::string &s : linkArgs) | |
| 350 | vec.push_back(s.c_str()); | |
| 351 | return coff::link(vec, true); | |
| 281 | 352 | } |
deps/lld/MinGW/Options.td+51-23| ... | ... | @@ -6,20 +6,45 @@ class S<string name>: Separate<["--", "-"], name>; |
| 6 | 6 | |
| 7 | 7 | def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">, |
| 8 | 8 | HelpText<"Add a directory to the library search path">; |
| 9 | def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries">; | |
| 10 | def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">; | |
| 9 | 11 | def dynamicbase: F<"dynamicbase">, HelpText<"Enable ASLR">; |
| 10 | 12 | def entry: S<"entry">, MetaVarName<"<entry>">, |
| 11 | 13 | HelpText<"Name of entry point symbol">; |
| 14 | def exclude_all_symbols: F<"exclude-all-symbols">, | |
| 15 | HelpText<"Don't automatically export any symbols">; | |
| 12 | 16 | def export_all_symbols: F<"export-all-symbols">, |
| 13 | 17 | HelpText<"Export all symbols even if a def file or dllexport attributes are used">; |
| 14 | 18 | def gc_sections: F<"gc-sections">, HelpText<"Remove unused sections">; |
| 19 | def help: F<"help">, HelpText<"Print option help">; | |
| 15 | 20 | def icf: J<"icf=">, HelpText<"Identical code folding">; |
| 16 | 21 | def image_base: S<"image-base">, HelpText<"Base address of the program">; |
| 22 | def insert_timestamp: F<"insert-timestamp">, | |
| 23 | HelpText<"Include PE header timestamp">; | |
| 17 | 24 | def kill_at: F<"kill-at">, HelpText<"Remove @n from exported symbols">; |
| 18 | 25 | def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">, |
| 19 | 26 | HelpText<"Root name of library to use">; |
| 20 | 27 | def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">; |
| 28 | def major_os_version: Separate<["--"], "major-os-version">, | |
| 29 | HelpText<"Set the OS and subsystem major version">; | |
| 30 | def major_os_version_eq: Joined<["--"], "major-os-version=">, | |
| 31 | Alias<major_os_version>; | |
| 32 | def major_subsystem_version: Separate<["--"], "major-subsystem-version">, | |
| 33 | HelpText<"Set the OS and subsystem major version">; | |
| 34 | def major_subsystem_version_eq: Joined<["--"], "major-subsystem-version=">, | |
| 35 | Alias<major_subsystem_version>; | |
| 21 | 36 | def map: S<"Map">, HelpText<"Output a linker map">; |
| 22 | 37 | def map_eq: J<"Map=">, Alias<map>; |
| 38 | def minor_os_version: Separate<["--"], "minor-os-version">, | |
| 39 | HelpText<"Set the OS and subsystem minor version">; | |
| 40 | def minor_os_version_eq: Joined<["--"], "minor-os-version=">, | |
| 41 | Alias<minor_os_version>; | |
| 42 | def minor_subsystem_version: Separate<["--"], "minor-subsystem-version">, | |
| 43 | HelpText<"Set the OS and subsystem minor version">; | |
| 44 | def minor_subsystem_version_eq: Joined<["--"], "minor-subsystem-version=">, | |
| 45 | Alias<minor_subsystem_version>; | |
| 46 | def no_insert_timestamp: F<"no-insert-timestamp">, | |
| 47 | HelpText<"Don't include PE header timestamp">; | |
| 23 | 48 | def no_whole_archive: F<"no-whole-archive">, |
| 24 | 49 | HelpText<"No longer include all object files for following archives">; |
| 25 | 50 | def large_address_aware: Flag<["--"], "large-address-aware">, |
| ... | ... | @@ -32,14 +57,21 @@ def out_implib_eq: Joined<["--"], "out-implib=">, Alias<out_implib>; |
| 32 | 57 | def output_def: S<"output-def">, HelpText<"Output def file">; |
| 33 | 58 | def shared: F<"shared">, HelpText<"Build a shared object">; |
| 34 | 59 | def subs: S<"subsystem">, HelpText<"Specify subsystem">; |
| 60 | def subs_eq: J<"subsystem=">, Alias<subs>; | |
| 35 | 61 | def stack: S<"stack">; |
| 36 | 62 | def strip_all: F<"strip-all">, |
| 37 | 63 | HelpText<"Omit all symbol information from the output binary">; |
| 38 | 64 | def strip_debug: F<"strip-debug">, |
| 39 | 65 | HelpText<"Omit all debug information, but keep symbol information">; |
| 66 | def undefined: S<"u">, | |
| 67 | HelpText<"Include symbol in the link, if available">; | |
| 68 | def undefined_long: S<"undefined">, Alias<undefined>; | |
| 69 | def undefined_eq: J<"undefined=">, Alias<undefined>; | |
| 40 | 70 | def whole_archive: F<"whole-archive">, |
| 41 | 71 | HelpText<"Include all object files for following archives">; |
| 72 | def v: Flag<["-"], "v">, HelpText<"Display the version number">; | |
| 42 | 73 | def verbose: F<"verbose">, HelpText<"Verbose mode">; |
| 74 | def version: F<"version">, HelpText<"Display the version number and exit">; | |
| 43 | 75 | def require_defined: S<"require-defined">, |
| 44 | 76 | HelpText<"Force symbol to be added to symbol table as an undefined one">; |
| 45 | 77 | def require_defined_eq: J<"require-defined=">, Alias<require_defined>; |
| ... | ... | @@ -47,40 +79,36 @@ def require_defined_eq: J<"require-defined=">, Alias<require_defined>; |
| 47 | 79 | // LLD specific options |
| 48 | 80 | def _HASH_HASH_HASH : Flag<["-"], "###">, |
| 49 | 81 | HelpText<"Print (but do not run) the commands to run for this compilation">; |
| 82 | def appcontainer: F<"appcontainer">, HelpText<"Set the appcontainer flag in the executable">; | |
| 50 | 83 | def mllvm: S<"mllvm">; |
| 51 | def pdb: S<"pdb">, HelpText<"Specify output PDB debug information file">; | |
| 84 | def pdb: S<"pdb">, HelpText<"Output PDB debug info file, chosen implicitly if the argument is empty">; | |
| 85 | def pdb_eq: J<"pdb=">, Alias<pdb>; | |
| 52 | 86 | def Xlink : J<"Xlink=">, MetaVarName<"<arg>">, |
| 53 | 87 | HelpText<"Pass <arg> to the COFF linker">; |
| 54 | 88 | |
| 55 | // Currently stubs to avoid errors | |
| 56 | def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries">; | |
| 57 | def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">; | |
| 58 | def O: Joined<["-"], "O">, HelpText<"Optimize output file size">; | |
| 59 | def build_id: F<"build-id">; | |
| 60 | def disable_auto_image_base: F<"disable-auto-image-base">; | |
| 61 | def enable_auto_image_base: F<"enable-auto-image-base">; | |
| 62 | def enable_auto_import: F<"enable-auto-import">; | |
| 63 | def end_group: F<"end-group">; | |
| 64 | def full_shutdown: Flag<["--"], "full-shutdown">; | |
| 65 | def high_entropy_va: F<"high-entropy-va">, HelpText<"Enable 64-bit ASLR">; | |
| 66 | def major_image_version: S<"major-image-version">; | |
| 67 | def minor_image_version: S<"minor-image-version">; | |
| 68 | def no_seh: F<"no-seh">; | |
| 69 | def nxcompat: F<"nxcompat">, HelpText<"Enable data execution prevention">; | |
| 70 | def pic_executable: F<"pic-executable">; | |
| 71 | def sysroot: J<"sysroot">, HelpText<"Sysroot">; | |
| 72 | def start_group: F<"start-group">; | |
| 73 | def tsaware: F<"tsaware">, HelpText<"Create Terminal Server aware executable">; | |
| 74 | def v: Flag<["-"], "v">, HelpText<"Display the version number">; | |
| 75 | def version: F<"version">, HelpText<"Display the version number and exit">; | |
| 76 | ||
| 77 | 89 | // Alias |
| 78 | 90 | def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>; |
| 79 | 91 | def alias_strip_s: Flag<["-"], "s">, Alias<strip_all>; |
| 80 | 92 | def alias_strip_S: Flag<["-"], "S">, Alias<strip_debug>; |
| 81 | 93 | |
| 82 | 94 | // Ignored options |
| 95 | def: Joined<["-"], "O">; | |
| 96 | def: F<"build-id">; | |
| 97 | def: F<"disable-auto-image-base">; | |
| 98 | def: F<"enable-auto-image-base">; | |
| 99 | def: F<"enable-auto-import">, HelpText<"Ignored; listed for libtool compatibility">; | |
| 100 | def: F<"end-group">; | |
| 101 | def: Flag<["--"], "full-shutdown">; | |
| 102 | def: F<"high-entropy-va">; | |
| 103 | def: S<"major-image-version">; | |
| 104 | def: S<"minor-image-version">; | |
| 105 | def: F<"no-seh">; | |
| 106 | def: F<"nxcompat">; | |
| 107 | def: F<"pic-executable">; | |
| 83 | 108 | def: S<"plugin">; |
| 84 | 109 | def: J<"plugin=">; |
| 85 | 110 | def: S<"plugin-opt">; |
| 86 | 111 | def: J<"plugin-opt=">; |
| 112 | def: J<"sysroot">; | |
| 113 | def: F<"start-group">; | |
| 114 | def: F<"tsaware">; |
deps/lld/docs/NewLLD.rst+8| ... | ... | @@ -307,3 +307,11 @@ Glossary |
| 307 | 307 | On Unix, your program is generally not guaranteed to be safe with ICF, |
| 308 | 308 | although large programs happen to work correctly. |
| 309 | 309 | LLD works fine with ICF for example. |
| 310 | ||
| 311 | Other Info | |
| 312 | ---------- | |
| 313 | ||
| 314 | .. toctree:: | |
| 315 | :maxdepth: 1 | |
| 316 | ||
| 317 | missingkeyfunction |
deps/lld/docs/Partitions.rst created+116| ... | ... | @@ -0,0 +1,116 @@ |
| 1 | Partitions | |
| 2 | ========== | |
| 3 | ||
| 4 | .. warning:: | |
| 5 | ||
| 6 | This feature is currently experimental, and its interface is subject | |
| 7 | to change. | |
| 8 | ||
| 9 | LLD's partitioning feature allows a program (which may be an executable | |
| 10 | or a shared library) to be split into multiple pieces, or partitions. A | |
| 11 | partitioned program consists of a main partition together with a number of | |
| 12 | loadable partitions. The loadable partitions depend on the main partition | |
| 13 | in a similar way to a regular ELF shared object dependency, but unlike a | |
| 14 | shared object, the main partition and the loadable partitions share a virtual | |
| 15 | address space at link time, and each loadable partition is assigned a fixed | |
| 16 | offset from the main partition. This allows the loadable partitions to refer | |
| 17 | to code and data in the main partition directly without the binary size and | |
| 18 | performance overhead of PLTs, GOTs or symbol table entries. | |
| 19 | ||
| 20 | Usage | |
| 21 | ----- | |
| 22 | ||
| 23 | A program that uses the partitioning feature must decide which symbols are | |
| 24 | going to be used as the "entry points" for each partition. An entry point | |
| 25 | could, for example, be the equivalent of the partition's ``main`` function, or | |
| 26 | there could be a group of functions that expose the functionality implemented | |
| 27 | by the partition. The intent is that in order to use a loadable partition, | |
| 28 | the program will use ``dlopen``/``dlsym`` or similar functions to dynamically | |
| 29 | load the partition at its assigned address, look up an entry point by name | |
| 30 | and call it. Note, however, that the standard ``dlopen`` function does not | |
| 31 | allow specifying a load address. On Android, the ``android_dlopen_ext`` | |
| 32 | function may be used together with the ``ANDROID_DLEXT_RESERVED_ADDRESS`` | |
| 33 | flag to load a shared object at a specific address. | |
| 34 | ||
| 35 | Once the entry points have been decided, the translation unit(s) | |
| 36 | containing the entry points should be compiled using the Clang compiler flag | |
| 37 | ``-fsymbol-partition=<soname>``, where ``<soname>`` is the intended soname | |
| 38 | of the partition. The resulting object files are passed to the linker in | |
| 39 | the usual way. | |
| 40 | ||
| 41 | The linker will then use these entry points to automatically split the program | |
| 42 | into partitions according to which sections of the program are reachable from | |
| 43 | which entry points, similarly to how ``--gc-sections`` removes unused parts of | |
| 44 | a program. Any sections that are only reachable from a loadable partition's | |
| 45 | entry point are assigned to that partition, while all other sections are | |
| 46 | assigned to the main partition, including sections only reachable from | |
| 47 | loadable partitions. | |
| 48 | ||
| 49 | The following diagram illustrates how sections are assigned to partitions. Each | |
| 50 | section is colored according to its assigned partition. | |
| 51 | ||
| 52 | .. image:: partitions.svg | |
| 53 | ||
| 54 | The result of linking a program that uses partitions is essentially an | |
| 55 | ELF file with all of the partitions concatenated together. This file is | |
| 56 | referred to as a combined output file. To extract a partition from the | |
| 57 | combined output file, the ``llvm-objcopy`` tool should be used together | |
| 58 | with the flag ``--extract-main-partition`` to extract the main partition, or | |
| 59 | ``-extract-partition=<soname>`` to extract one of the loadable partitions. | |
| 60 | An example command sequence is shown below: | |
| 61 | ||
| 62 | .. code-block:: shell | |
| 63 | ||
| 64 | # Compile the main program. | |
| 65 | clang -ffunction-sections -fdata-sections -c main.c | |
| 66 | ||
| 67 | # Compile a feature to be placed in a loadable partition. | |
| 68 | # Note that this is likely to be a separate build step to the main partition. | |
| 69 | clang -ffunction-sections -fdata-sections -fsymbol-partition=libfeature.so -c feature.c | |
| 70 | ||
| 71 | # Link the combined output file. | |
| 72 | clang main.o feature.o -fuse-ld=lld -shared -o libcombined.so -Wl,-soname,libmain.so -Wl,--gc-sections | |
| 73 | ||
| 74 | # Extract the partitions. | |
| 75 | llvm-objcopy libcombined.so libmain.so --extract-main-partition | |
| 76 | llvm-objcopy libcombined.so libfeature.so --extract-partition=libfeature.so | |
| 77 | ||
| 78 | In order to allow a program to discover the names of its loadable partitions | |
| 79 | and the locations of their reserved regions, the linker creates a partition | |
| 80 | index, which is an array of structs with the following definition: | |
| 81 | ||
| 82 | .. code-block:: c | |
| 83 | ||
| 84 | struct partition_index_entry { | |
| 85 | int32_t name_offset; | |
| 86 | int32_t addr_offset; | |
| 87 | uint32_t size; | |
| 88 | }; | |
| 89 | ||
| 90 | The ``name_offset`` field is a relative pointer to a null-terminated string | |
| 91 | containing the soname of the partition, the ``addr_offset`` field is a | |
| 92 | relative pointer to its load address and the ``size`` field contains the | |
| 93 | size of the region reserved for the partition. To derive an absolute pointer | |
| 94 | from the relative pointer fields in this data structure, the address of the | |
| 95 | field should be added to the value stored in the field. | |
| 96 | ||
| 97 | The program may discover the location of the partition index using the | |
| 98 | linker-defined symbols ``__part_index_begin`` and ``__part_index_end``. | |
| 99 | ||
| 100 | Restrictions | |
| 101 | ------------ | |
| 102 | ||
| 103 | This feature is currently only supported in the ELF linker. | |
| 104 | ||
| 105 | The partitioning feature may not currently be used together with the | |
| 106 | ``SECTIONS`` or ``PHDRS`` linker script features, nor may it be used with the | |
| 107 | ``--section-start``, ``-Ttext``, ``-Tdata`` or ``-Tbss`` flags. All of these | |
| 108 | features assume a single set of output sections and/or program headers, which | |
| 109 | makes their semantics ambiguous in the presence of more than one partition. | |
| 110 | ||
| 111 | The partitioning feature may not currently be used on the MIPS architecture | |
| 112 | because it is unclear whether the MIPS multi-GOT ABI is compatible with | |
| 113 | partitions. | |
| 114 | ||
| 115 | The current implementation only supports creating up to 254 partitions due | |
| 116 | to implementation limitations. This limit may be relaxed in the future. |
deps/lld/docs/ReleaseNotes.rst+50-79| ... | ... | @@ -1,19 +1,22 @@ |
| 1 | 1 | ======================= |
| 2 | lld 8.0.0 Release Notes | |
| 2 | lld 9.0.0 Release Notes | |
| 3 | 3 | ======================= |
| 4 | 4 | |
| 5 | 5 | .. contents:: |
| 6 | 6 | :local: |
| 7 | 7 | |
| 8 | .. warning:: | |
| 9 | These are in-progress notes for the upcoming LLVM 9.0.0 release. | |
| 10 | Release notes for previous releases can be found on | |
| 11 | `the Download Page <https://releases.llvm.org/download.html>`_. | |
| 12 | ||
| 8 | 13 | Introduction |
| 9 | 14 | ============ |
| 10 | 15 | |
| 11 | lld is a high-performance linker that supports ELF (Unix), COFF (Windows), | |
| 12 | Mach-O (macOS), MinGW and WebAssembly. lld is command-line-compatible with | |
| 13 | GNU linkers and Microsoft link.exe and is significantly faster than the | |
| 14 | system default linkers. | |
| 15 | ||
| 16 | lld 8.0.0 has lots of feature improvements and bug fixes. | |
| 16 | This document contains the release notes for the lld linker, release 9.0.0. | |
| 17 | Here we describe the status of lld, including major improvements | |
| 18 | from the previous release. All lld releases may be downloaded | |
| 19 | from the `LLVM releases web site <https://llvm.org/releases/>`_. | |
| 17 | 20 | |
| 18 | 21 | Non-comprehensive list of changes in this release |
| 19 | 22 | ================================================= |
| ... | ... | @@ -21,101 +24,69 @@ Non-comprehensive list of changes in this release |
| 21 | 24 | ELF Improvements |
| 22 | 25 | ---------------- |
| 23 | 26 | |
| 24 | * lld now supports RISC-V. (`r339364 | |
| 25 | <https://reviews.llvm.org/rL339364>`_) | |
| 26 | ||
| 27 | * Default image base address has changed from 65536 to 2 MiB for i386 | |
| 28 | and 4 MiB for AArch64 to make lld-generated executables work better | |
| 29 | with automatic superpage promotion. FreeBSD can promote contiguous | |
| 30 | non-superpages to a superpage if they are aligned to the superpage | |
| 31 | size. (`r342746 <https://reviews.llvm.org/rL342746>`_) | |
| 32 | ||
| 33 | * lld now attempts to place a ``.note`` segment in the first page of a | |
| 34 | generated file, so that you can find some important information | |
| 35 | (``.note.gnu.build-id`` in particular) in a core file even if a core | |
| 36 | file is truncated by ulimit. | |
| 37 | (`r349524 <https://reviews.llvm.org/rL349524>`_) | |
| 38 | ||
| 39 | * lld now reports an error if ``_GLOBAL_OFFSET_TABLE_`` symbol is | |
| 40 | defined by an input object file, as the symbol is supposed to be | |
| 41 | synthesized by the linker. | |
| 42 | (`r347854 <https://reviews.llvm.org/rL347854>`_) | |
| 43 | ||
| 44 | * lld/Hexagon can now link Linux kernel and musl libc for Qualcomm | |
| 45 | Hexagon ISA. | |
| 46 | ||
| 47 | * Initial MSP430 ISA support has landed. | |
| 27 | * ld.lld now has typo suggestions for flags: | |
| 28 | ``$ ld.lld --call-shared`` now prints | |
| 29 | ``unknown argument '--call-shared', did you mean '--call_shared'``. | |
| 48 | 30 | |
| 49 | * lld now uses the ``sigrie`` instruction as a trap instruction for | |
| 50 | MIPS targets. | |
| 51 | ||
| 52 | * lld now creates a TLS segment for AArch64 with a slightly larger | |
| 53 | alignment requirement, so that the loader makes a few bytes room | |
| 54 | before each TLS segment at runtime. The aim of this change is to | |
| 55 | make room to accomodate nonstandard Android TLS slots while keeping | |
| 56 | the compatibility with the standard AArch64 ABI. | |
| 57 | (`r350681 <https://reviews.llvm.org/rL350681>`_) | |
| 58 | ||
| 59 | * The following flags have been added: ``--call-graph-profile``, | |
| 60 | ``--no-call-graph-profile``, ``--warn-ifunc-textrel``, | |
| 61 | ``-z interpose``, ``-z global``, ``-z nodefaultlib`` | |
| 31 | * ... | |
| 62 | 32 | |
| 63 | 33 | COFF Improvements |
| 64 | 34 | ----------------- |
| 65 | 35 | |
| 66 | * PDB GUID is set to hash of PDB contents instead to a random byte | |
| 67 | sequence for build reproducibility. | |
| 36 | * Like the ELF driver, lld-link now has typo suggestions for flags. | |
| 37 | ||
| 38 | * lld-link now correctly reports duplicate symbol errors for obj files | |
| 39 | that were compiled with /Gy. | |
| 68 | 40 | |
| 69 | * ``/pdbsourcepath:`` is now also used to make ``"cwd"``, ``"exe"``, ``"pdb"`` | |
| 70 | in the env block of PDB outputs absolute if they are relative, and to make | |
| 71 | paths to obj files referenced in PDB outputs absolute if they are relative. | |
| 72 | Together with the previous item, this makes it possible to generate | |
| 73 | executables and PDBs that are fully deterministic and independent of the | |
| 74 | absolute path to the build directory, so that different machines building | |
| 75 | the same code in different directories can produce exactly the same output. | |
| 41 | * lld-link now correctly reports duplicate symbol errors when several res | |
| 42 | input files define resources with the same type, name, and language. | |
| 43 | This can be demoted to a warning using ``/force:multipleres``. | |
| 76 | 44 | |
| 77 | * The following flags have been added: ``/force:multiple`` | |
| 45 | * Having more than two ``/natvis:`` now works correctly; it used to not | |
| 46 | work for larger binaries before. | |
| 78 | 47 | |
| 79 | * lld now can link against import libraries produced by GNU tools. | |
| 48 | * Undefined symbols are now printed only in demangled form. Pass | |
| 49 | ``/demangle:no`` to see raw symbol names instead. | |
| 80 | 50 | |
| 81 | * lld can create thunks for ARM and ARM64, to allow linking larger images | |
| 82 | (over 16 MB for ARM and over 128 MB for ARM64) | |
| 51 | * The following flags have been added: ``/functionpadmin``, ``/swaprun:``, | |
| 52 | ``/threads:no`` | |
| 83 | 53 | |
| 84 | 54 | * Several speed and memory usage improvements. |
| 85 | 55 | |
| 86 | * lld now creates debug info for typedefs. | |
| 56 | * Range extension thunks are now created for ARM64, if needed | |
| 87 | 57 | |
| 88 | * lld can now link obj files produced by ``cl.exe /Z7 /Yc``. | |
| 58 | * lld-link now supports resource object files created by GNU windres and | |
| 59 | MS cvtres, not only llvm-cvtres | |
| 89 | 60 | |
| 90 | * lld now understands ``%_PDB%`` and ``%_EXT%`` in ``/pdbaltpath:``. | |
| 61 | * The generated thunks for delayimports now share the majority of code | |
| 62 | among thunks, significantly reducing the overhead of using delayimport | |
| 91 | 63 | |
| 92 | * Undefined symbols are now printed in demangled form in addition to raw form. | |
| 64 | * ... | |
| 93 | 65 | |
| 94 | 66 | MinGW Improvements |
| 95 | 67 | ------------------ |
| 96 | 68 | |
| 97 | * lld can now automatically import data variables from DLLs without the | |
| 98 | use of the dllimport attribute. | |
| 69 | * lld now correctly links crtend.o as the last object file, handling | |
| 70 | terminators for the sections such as .eh_frame properly, fixing | |
| 71 | DWARF exception handling with libgcc and gcc's crtend.o. | |
| 99 | 72 | |
| 100 | * lld can now use existing normal MinGW sysroots with import libraries and | |
| 101 | CRT startup object files for GNU binutils. lld can handle most object | |
| 102 | files produced by GCC, and thus works as a drop-in replacement for | |
| 103 | ld.bfd in such environments. (There are known issues with linking crtend.o | |
| 104 | from GCC in setups with DWARF exceptions though, where object files are | |
| 105 | linked in a different order than with GNU ld, inserting a DWARF exception | |
| 106 | table terminator too early.) | |
| 73 | * lld now also handles DWARF unwind info generated by GCC, when linking | |
| 74 | with libgcc | |
| 107 | 75 | |
| 108 | * lld now supports COFF embedded directives for linking to nondefault | |
| 109 | libraries, just like for the normal COFF target. | |
| 76 | * Many more GNU ld options are now supported, which e.g. allows the lld | |
| 77 | MinGW frontend to be called by GCC | |
| 78 | ||
| 79 | * PDB output can be requested without manually specifying the PDB file | |
| 80 | name, with the new option ``-pdb=`` with an empty value to the option. | |
| 81 | (The old existing syntax ``-pdb <filename>`` was more cumbersome to use | |
| 82 | with an empty parameter value.) | |
| 83 | ||
| 84 | MachO Improvements | |
| 85 | ------------------ | |
| 110 | 86 | |
| 111 | * Actually generate a codeview build id signature, even if not creating a PDB. | |
| 112 | Previously, the ``--build-id`` option did not actually generate a build id | |
| 113 | unless ``--pdb`` was specified. | |
| 87 | * Item 1. | |
| 114 | 88 | |
| 115 | 89 | WebAssembly Improvements |
| 116 | 90 | ------------------------ |
| 117 | 91 | |
| 118 | * Add initial support for creating shared libraries (-shared). | |
| 119 | Note: The shared library format is still under active development and may | |
| 120 | undergo significant changes in future versions. | |
| 121 | See: https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md | |
| 92 | * ... |
deps/lld/docs/WebAssembly.rst+65-13| ... | ... | @@ -4,21 +4,17 @@ WebAssembly lld port |
| 4 | 4 | The WebAssembly version of lld takes WebAssembly binaries as inputs and produces |
| 5 | 5 | a WebAssembly binary as its output. For the most part it tries to mimic the |
| 6 | 6 | behaviour of traditional ELF linkers and specifically the ELF lld port. Where |
| 7 | possible that command line flags and the semantics should be the same. | |
| 7 | possible the command line flags and the semantics should be the same. | |
| 8 | 8 | |
| 9 | 9 | |
| 10 | 10 | Object file format |
| 11 | 11 | ------------------ |
| 12 | 12 | |
| 13 | The format the input object files that lld expects is specified as part of the | |
| 14 | the WebAssembly tool conventions | |
| 15 | https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md. | |
| 16 | ||
| 17 | This is object format that the llvm will produce when run with the | |
| 18 | ``wasm32-unknown-unknown`` target. To build llvm with WebAssembly support | |
| 19 | currently requires enabling the experimental backed using | |
| 20 | ``-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly``. | |
| 13 | The WebAssembly object file format used by LLVM and LLD is specified as part of | |
| 14 | the WebAssembly tool conventions on linking_. | |
| 21 | 15 | |
| 16 | This is the object format that the llvm will produce when run with the | |
| 17 | ``wasm32-unknown-unknown`` target. | |
| 22 | 18 | |
| 23 | 19 | Usage |
| 24 | 20 | ----- |
| ... | ... | @@ -88,10 +84,52 @@ WebAssembly-specific options: |
| 88 | 84 | By default the function table is neither imported nor exported, but defined |
| 89 | 85 | for internal use only. |
| 90 | 86 | |
| 91 | When building shared libraries symbols are exported if they are marked | |
| 92 | as ``visibility=default``. When building executables only the entry point is | |
| 93 | exported by default. In addition any symbol included on the command line via | |
| 94 | ``--export`` is also exported. | |
| 87 | Behaviour | |
| 88 | --------- | |
| 89 | ||
| 90 | In general, where possible, the WebAssembly linker attempts to emulate the | |
| 91 | behaviour of a traditional ELF linker, and in particular the ELF port of lld. | |
| 92 | For more specific details on how this is achieved see the tool conventions on | |
| 93 | linking_. | |
| 94 | ||
| 95 | Function Signatures | |
| 96 | ~~~~~~~~~~~~~~~~~~~ | |
| 97 | ||
| 98 | One way in which the WebAssembly linker differs from traditional native linkers | |
| 99 | is that function signature checking is strict in WebAssembly. It is a | |
| 100 | validation error for a module to contain a call site that doesn't agree with | |
| 101 | the target signature. Even though this is undefined behaviour in C/C++, it is not | |
| 102 | uncommon to find this in real-world C/C++ programs. For example, a call site in | |
| 103 | one compilation unit which calls a function defined in another compilation | |
| 104 | unit but with too many arguments. | |
| 105 | ||
| 106 | In order not to generate such invalid modules, lld has two modes of handling such | |
| 107 | mismatches: it can simply error-out or it can create stub functions that will | |
| 108 | trap at runtime (functions that contain only an ``unreachable`` instruction) | |
| 109 | and use these stub functions at the otherwise invalid call sites. | |
| 110 | ||
| 111 | The default behaviour is to generate these stub function and to produce | |
| 112 | a warning. The ``--falal-warnings`` flag can be used to disable this behaviour | |
| 113 | and error out if mismatched are found. | |
| 114 | ||
| 115 | Imports and Exports | |
| 116 | ~~~~~~~~~~~~~~~~~~~ | |
| 117 | ||
| 118 | When building a shared library any symbols marked as ``visibility=default`` will | |
| 119 | be exported. When building an executable, only the entry point and symbols | |
| 120 | flagged as ``WASM_SYMBOL_EXPORTED`` are exported by default. In LLVM the | |
| 121 | ``WASM_SYMBOL_EXPORTED`` flag is applied to any symbol in the ``llvm.used`` list | |
| 122 | which corresponds to ``__attribute__((used))`` in C/C++ sources. | |
| 123 | ||
| 124 | In addition, symbols can be exported via the linker command line using | |
| 125 | ``--export``. | |
| 126 | ||
| 127 | Finally, just like with native ELF linker the ``--export-dynamic`` flag can be | |
| 128 | used to export symbol in the executable which are marked as | |
| 129 | ``visibility=default``. | |
| 130 | ||
| 131 | Garbage Collection | |
| 132 | ~~~~~~~~~~~~~~~~~~ | |
| 95 | 133 | |
| 96 | 134 | Since WebAssembly is designed with size in mind the linker defaults to |
| 97 | 135 | ``--gc-sections`` which means that all unused functions and data segments will |
| ... | ... | @@ -103,6 +141,18 @@ The symbols which are preserved by default are: |
| 103 | 141 | - Any symbol which is to be exported. |
| 104 | 142 | - Any symbol transitively referenced by the above. |
| 105 | 143 | |
| 144 | Weak Undefined Functions | |
| 145 | ~~~~~~~~~~~~~~~~~~~~~~~~ | |
| 146 | ||
| 147 | On native platforms, calls to weak undefined functions end up as calls to the | |
| 148 | null function pointer. With WebAssembly, direct calls must reference a defined | |
| 149 | function (with the correct signature). In order to handle this case the linker | |
| 150 | will generate function a stub containing only the ``unreachable`` instruction | |
| 151 | and use this for any direct references to an undefined weak function. | |
| 152 | ||
| 153 | For example a runtime call to a weak undefined function ``foo`` will up trapping | |
| 154 | on ``unreachable`` inside and linker-generated function called | |
| 155 | ``undefined:foo``. | |
| 106 | 156 | |
| 107 | 157 | Missing features |
| 108 | 158 | ---------------- |
| ... | ... | @@ -112,3 +162,5 @@ Missing features |
| 112 | 162 | - No support for creating shared libraries. The spec for shared libraries in |
| 113 | 163 | WebAssembly is still in flux: |
| 114 | 164 | https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md |
| 165 | ||
| 166 | .. _linking: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md |
deps/lld/docs/conf.py+2-2| ... | ... | @@ -48,9 +48,9 @@ copyright = u'2011-%d, LLVM Project' % date.today().year |
| 48 | 48 | # built documents. |
| 49 | 49 | # |
| 50 | 50 | # The short version. |
| 51 | version = '8' | |
| 51 | version = '9' | |
| 52 | 52 | # The full version, including alpha/beta/rc tags. |
| 53 | release = '8' | |
| 53 | release = '9' | |
| 54 | 54 | |
| 55 | 55 | # The language for content autogenerated by Sphinx. Refer to documentation |
| 56 | 56 | # for a list of supported languages. |
deps/lld/docs/getting_started.rst+8-27| ... | ... | @@ -28,23 +28,15 @@ On Unix-like Systems |
| 28 | 28 | .. _libc++: http://libcxx.llvm.org/ |
| 29 | 29 | .. _Python 2.4: http://python.org/download/ |
| 30 | 30 | |
| 31 | 2. Check out LLVM:: | |
| 31 | 2. Check out LLVM and subprojects (including lld):: | |
| 32 | 32 | |
| 33 | $ cd path/to/llvm-project | |
| 34 | $ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm | |
| 35 | ||
| 36 | 3. Check out lld:: | |
| 37 | ||
| 38 | $ cd llvm/tools | |
| 39 | $ svn co http://llvm.org/svn/llvm-project/lld/trunk lld | |
| 40 | ||
| 41 | * lld can also be checked out to ``path/to/llvm-project`` and built as an external | |
| 42 | project. | |
| 33 | $ git clone https://github.com/llvm/llvm-project.git | |
| 43 | 34 | |
| 44 | 35 | 4. Build LLVM and lld:: |
| 45 | 36 | |
| 46 | $ cd path/to/llvm-build/llvm (out of source build required) | |
| 47 | $ cmake -G "Unix Makefiles" path/to/llvm-project/llvm | |
| 37 | $ cd llvm-project | |
| 38 | $ mkdir build && cd build | |
| 39 | $ cmake -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS=lld ../llvm | |
| 48 | 40 | $ make |
| 49 | 41 | |
| 50 | 42 | * If you want to build with clang and it is not the default compiler or |
| ... | ... | @@ -71,23 +63,12 @@ Using Visual Studio |
| 71 | 63 | .. _Visual Studio 12 (2013) or later: http://www.microsoft.com/visualstudio/11/en-us |
| 72 | 64 | .. _Python 2.4: http://python.org/download/ |
| 73 | 65 | |
| 74 | #. Check out LLVM:: | |
| 75 | ||
| 76 | $ cd path/to/llvm-project | |
| 77 | $ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm | |
| 78 | ||
| 79 | #. Check out lld:: | |
| 80 | ||
| 81 | $ cd llvm/tools | |
| 82 | $ svn co http://llvm.org/svn/llvm-project/lld/trunk lld | |
| 83 | ||
| 84 | * lld can also be checked out to ``path/to/llvm-project`` and built as an external | |
| 85 | project. | |
| 66 | #. Check out LLVM as above. | |
| 86 | 67 | |
| 87 | 68 | #. Generate Visual Studio project files:: |
| 88 | 69 | |
| 89 | $ cd path/to/llvm-build/llvm (out of source build required) | |
| 90 | $ cmake -G "Visual Studio 11" path/to/llvm-project/llvm | |
| 70 | $ cd llvm-project/build (out of source build required) | |
| 71 | $ cmake -G "Visual Studio 11" -DLLVM_ENABLE_PROJECTS=lld ../llvm | |
| 91 | 72 | |
| 92 | 73 | #. Build |
| 93 | 74 |
deps/lld/docs/index.rst+2-1| ... | ... | @@ -106,7 +106,7 @@ build that tree. You need `cmake` and of course a C++ compiler. |
| 106 | 106 | |
| 107 | 107 | .. code-block:: console |
| 108 | 108 | |
| 109 | $ git clone https://github.com/llvm-project/llvm-project-20170507 llvm-project | |
| 109 | $ git clone https://github.com/llvm/llvm-project llvm-project | |
| 110 | 110 | $ mkdir build |
| 111 | 111 | $ cd build |
| 112 | 112 | $ cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS=lld -DCMAKE_INSTALL_PREFIX=/usr/local ../llvm-project/llvm |
| ... | ... | @@ -174,4 +174,5 @@ document soon. |
| 174 | 174 | WebAssembly |
| 175 | 175 | windows_support |
| 176 | 176 | missingkeyfunction |
| 177 | Partitions | |
| 177 | 178 | ReleaseNotes |
deps/lld/docs/ld.lld.1+109-8| ... | ... | @@ -1,9 +1,10 @@ |
| 1 | .\" This file is distributed under the University of Illinois Open Source | |
| 2 | .\" License. See LICENSE.TXT for details. | |
| 1 | .\" Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 2 | .\" See https://llvm.org/LICENSE.txt for license information. | |
| 3 | .\" SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 3 | 4 | .\" |
| 4 | 5 | .\" This man page documents only lld's ELF linking support, obtained originally |
| 5 | 6 | .\" from FreeBSD. |
| 6 | .Dd September 26, 2018 | |
| 7 | .Dd May 12, 2019 | |
| 7 | 8 | .Dt LD.LLD 1 |
| 8 | 9 | .Os |
| 9 | 10 | .Sh NAME |
| ... | ... | @@ -45,6 +46,9 @@ as a native linker as well as a cross linker. |
| 45 | 46 | .It Fl -allow-multiple-definition |
| 46 | 47 | Do not error if a symbol is defined multiple times. |
| 47 | 48 | The first definition will be used. |
| 49 | .It Fl -allow-shlib-undefined | |
| 50 | Allow unresolved references in shared libraries. | |
| 51 | This option is enabled by default when linking a shared library. | |
| 48 | 52 | .It Fl -apply-dynamic-relocs |
| 49 | 53 | Apply link-time values for dynamic relocations. |
| 50 | 54 | .It Fl -as-needed |
| ... | ... | @@ -178,6 +182,8 @@ Set the |
| 178 | 182 | field to the specified value. |
| 179 | 183 | .It Fl -fini Ns = Ns Ar symbol |
| 180 | 184 | Specify a finalizer function. |
| 185 | .It Fl -force-bti | |
| 186 | Force enable AArch64 BTI instruction in PLT, warn if Input ELF file does not have GNU_PROPERTY_AARCH64_FEATURE_1_BTI property. | |
| 181 | 187 | .It Fl -format Ns = Ns Ar input-format , Fl b Ar input-format |
| 182 | 188 | Specify the format of the inputs following this option. |
| 183 | 189 | .Ar input-format |
| ... | ... | @@ -213,6 +219,15 @@ Enable identical code folding. |
| 213 | 219 | Enable safe identical code folding. |
| 214 | 220 | .It Fl -icf Ns = Ns Cm none |
| 215 | 221 | Disable identical code folding. |
| 222 | .It Fl -ignore-data-address-equality | |
| 223 | Ignore address equality of data. C/C++ requires each data to have a unique | |
| 224 | address. This option allows lld to do unsafe optimization that breaks the | |
| 225 | requirement: create copies of read-only data or merge two or more read-only data | |
| 226 | that happen to have the same value. | |
| 227 | .It Fl -ignore-function-address-equality | |
| 228 | Ignore address equality of functions. This option allows non-PIC calls to a | |
| 229 | function with non-default visibility in a shared object. The function may have | |
| 230 | different addresses within the executable and within the shared object. | |
| 216 | 231 | .It Fl -image-base Ns = Ns Ar value |
| 217 | 232 | Set the base address to |
| 218 | 233 | .Ar value . |
| ... | ... | @@ -241,6 +256,11 @@ Set target emulation. |
| 241 | 256 | .It Fl -Map Ns = Ns Ar file , Fl M Ar file |
| 242 | 257 | Print a link map to |
| 243 | 258 | .Ar file . |
| 259 | .It Fl -nmagic , Fl n | |
| 260 | Do not page align sections, link against static libraries. | |
| 261 | .It Fl -no-allow-shlib-undefined | |
| 262 | Do not allow unresolved references in shared libraries. | |
| 263 | This option is enabled by default when linking an executable. | |
| 244 | 264 | .It Fl -no-as-needed |
| 245 | 265 | Always set |
| 246 | 266 | .Dv DT_NEEDED |
| ... | ... | @@ -259,6 +279,12 @@ section. |
| 259 | 279 | Disable garbage collection of unused sections. |
| 260 | 280 | .It Fl -no-gnu-unique |
| 261 | 281 | Disable STB_GNU_UNIQUE symbol binding. |
| 282 | .It Fl -no-merge-exidx-entries | |
| 283 | Disable merging .ARM.exidx entries. | |
| 284 | .It Fl -no-nmagic | |
| 285 | Page align sections. | |
| 286 | .It Fl -no-omagic | |
| 287 | Do not set the text data sections to be writable, page align sections. | |
| 262 | 288 | .It Fl -no-rosegment |
| 263 | 289 | Do not put read-only non-executable sections in their own segment. |
| 264 | 290 | .It Fl -no-threads |
| ... | ... | @@ -267,9 +293,11 @@ Do not run the linker multi-threaded. |
| 267 | 293 | Report version scripts that refer undefined symbols. |
| 268 | 294 | .It Fl -no-undefined |
| 269 | 295 | Report unresolved symbols even if the linker is creating a shared library. |
| 296 | .It Fl -no-warn-symbol-ordering | |
| 297 | Do not warn about problems with the symbol ordering file or call graph profile. | |
| 270 | 298 | .It Fl -no-whole-archive |
| 271 | 299 | Restores the default behavior of loading archive members. |
| 272 | .It Fl -no-pie | |
| 300 | .It Fl -no-pie , Fl -no-pic-executable | |
| 273 | 301 | Do not create a position independent executable. |
| 274 | 302 | .It Fl -noinhibit-exec |
| 275 | 303 | Retain the executable output file whenever it is still usable. |
| ... | ... | @@ -305,15 +333,62 @@ is |
| 305 | 333 | .Cm binary , |
| 306 | 334 | which produces output with no ELF header. |
| 307 | 335 | .It Fl -omagic , Fl N |
| 308 | Set the text and data sections to be readable and writable. | |
| 336 | Set the text and data sections to be readable and writable, do not page align sections, link against static libraries. | |
| 309 | 337 | .It Fl -opt-remarks-filename Ar file |
| 310 | 338 | Write optimization remarks in YAML format to |
| 311 | 339 | .Ar file . |
| 340 | .It Fl -opt-remarks-passes Ar pass-regex | |
| 341 | Filter optimization remarks by only allowing the passes matching | |
| 342 | .Ar pass-regex . | |
| 312 | 343 | .It Fl -opt-remarks-with-hotness |
| 313 | 344 | Include hotness information in the optimization remarks file. |
| 345 | .It Fl -orphan-handling Ns = Ns Ar mode | |
| 346 | Control how orphan sections are handled. An orphan section is one not | |
| 347 | specifically mentioned in a linker script. | |
| 348 | .Ar mode | |
| 349 | may be: | |
| 350 | .Pp | |
| 351 | .Bl -tag -width 2n -compact | |
| 352 | .It Cm place | |
| 353 | Place orphan sections in suitable output sections. | |
| 354 | .It Cm warn | |
| 355 | Place orphan sections as for | |
| 356 | .Cm place | |
| 357 | and also report a warning. | |
| 358 | .It Cm error | |
| 359 | Place orphan sections as for | |
| 360 | .Cm place | |
| 361 | and also report an error. | |
| 362 | .El | |
| 363 | .Pp | |
| 364 | .Cm place | |
| 365 | is the default. | |
| 366 | .It Fl -pack-dyn-relocs Ns = Ns Ar format | |
| 367 | Pack dynamic relocations in the given format. | |
| 368 | .Ar format | |
| 369 | may be: | |
| 370 | .Pp | |
| 371 | .Bl -tag -width 2n -compact | |
| 372 | .It Cm none | |
| 373 | Don't pack. Dynamic relocations are encoded in SHT_REL(A). | |
| 374 | .It Cm android | |
| 375 | Pack dynamic relocations in SHT_ANDROID_REL(A). | |
| 376 | .It Cm relr | |
| 377 | Pack relative relocations in SHT_RELR, and the rest of dynamic relocations in SHT_REL(A). | |
| 378 | .It Cm android+relr | |
| 379 | Pack relative relocations in SHT_RELR, and the rest of dynamic relocations in SHT_ANDROID_REL(A). | |
| 380 | .El | |
| 381 | .Pp | |
| 382 | .Cm none | |
| 383 | is the default. If | |
| 384 | .Fl -use-android-relr-tags | |
| 385 | is specified, use SHT_ANDROID_RELR instead of SHT_RELR. | |
| 386 | .Pp | |
| 387 | .It Fl -pac-plt | |
| 388 | AArch64 only, use pointer authentication in PLT. | |
| 314 | 389 | .It Fl -pic-veneer |
| 315 | 390 | Always generate position independent thunks. |
| 316 | .It Fl -pie | |
| 391 | .It Fl -pie , Fl -pic-executable | |
| 317 | 392 | Create a position independent executable. |
| 318 | 393 | .It Fl -print-gc-sections |
| 319 | 394 | List removed unused sections. |
| ... | ... | @@ -358,6 +433,8 @@ Set |
| 358 | 433 | .Dv DT_SONAME |
| 359 | 434 | to |
| 360 | 435 | .Ar value . |
| 436 | .It Fl -sort-common | |
| 437 | This option is ignored for GNU compatibility. | |
| 361 | 438 | .It Fl -sort-section Ns = Ns Ar value |
| 362 | 439 | Specifies sections sorting rule when linkerscript is used. |
| 363 | 440 | .It Fl -start-lib |
| ... | ... | @@ -427,11 +504,27 @@ Print the names of the input files. |
| 427 | 504 | Trace references to |
| 428 | 505 | .Ar symbol . |
| 429 | 506 | .It Fl -undefined Ns = Ns Ar symbol , Fl u Ar symbol |
| 430 | Force | |
| 507 | If | |
| 431 | 508 | .Ar symbol |
| 432 | to be an undefined symbol during linking. | |
| 509 | is not defined after symbol resolution, and there's a static library | |
| 510 | that contains an object file defining the symbol, load the member | |
| 511 | to include the object file in the output file. | |
| 512 | .It Fl -undefined-glob Ns = Ns Ar pattern | |
| 513 | Synonym for | |
| 514 | .Fl -undefined , | |
| 515 | except that it takes a glob pattern. In a glob pattern, | |
| 516 | .Cm * | |
| 517 | matches zero or more characters, | |
| 518 | .Cm ? | |
| 519 | matches any single character, and | |
| 520 | .Cm [...] | |
| 521 | matches the characters within brackets. All symbols that match | |
| 522 | a given pattern are handled as if they were given as arguments of | |
| 523 | .Fl -undefined . | |
| 433 | 524 | .It Fl -unresolved-symbols Ns = Ns Ar value |
| 434 | 525 | Determine how to handle unresolved symbols. |
| 526 | .It Fl -use-android-relr-tags | |
| 527 | Use SHT_ANDROID_RELR / DT_ANDROID_RELR* tags instead of SHT_RELR / DT_RELR*. | |
| 435 | 528 | .It Fl v |
| 436 | 529 | Display the version number and proceed with linking if object files are |
| 437 | 530 | specified. |
| ... | ... | @@ -479,6 +572,14 @@ Sets the |
| 479 | 572 | .Dv DYNAMIC |
| 480 | 573 | section. |
| 481 | 574 | Different loaders can decide how to handle this flag on their own. |
| 575 | .It Cm ifunc-noplt | |
| 576 | Do not emit PLT entries for ifunc symbols. | |
| 577 | Instead, emit text relocations referencing the resolver. | |
| 578 | This is an experimental optimization and only suitable for standalone | |
| 579 | environments where text relocations do not have the usual drawbacks. | |
| 580 | This option must be combined with the | |
| 581 | .Fl z Li notext | |
| 582 | option. | |
| 482 | 583 | .It Cm initfirst |
| 483 | 584 | Sets the |
| 484 | 585 | .Dv DF_1_INITFIRST |
deps/lld/docs/missingkeyfunction.rst+16-15| ... | ... | @@ -4,23 +4,24 @@ Missing Key Function |
| 4 | 4 | If your build failed with a linker error something like this:: |
| 5 | 5 | |
| 6 | 6 | foo.cc:28: error: undefined reference to 'vtable for C' |
| 7 | the vtable symbol may be undefined because the class is missing its key function (see https://lld.llvm.org/missingkeyfunction) | |
| 7 | the vtable symbol may be undefined because the class is missing its key function | |
| 8 | (see https://lld.llvm.org/missingkeyfunction) | |
| 8 | 9 | |
| 9 | 10 | it's likely that your class C has a key function (defined by the ABI as the first |
| 10 | non-pure, non-inline, virtual method), but you haven't actually defined it. | |
| 11 | non-pure, non-inline, virtual function), but you haven't actually defined it. | |
| 11 | 12 | |
| 12 | 13 | When a class has a key function, the compiler emits the vtable (and some other |
| 13 | 14 | things as well) only in the translation unit that defines that key function. Thus, |
| 14 | 15 | if you're missing the key function, you'll also be missing the vtable. If no other |
| 15 | function calls your missing method, you won't see any undefined reference errors | |
| 16 | function calls your missing function, you won't see any undefined reference errors | |
| 16 | 17 | for it, but you will see undefined references to the vtable symbol. |
| 17 | 18 | |
| 18 | When a class has no non-pure, non-inline, virtual methods, there is no key | |
| 19 | method, and the compiler is forced to emit the vtable in every translation unit | |
| 19 | When a class has no non-pure, non-inline, virtual functions, there is no key | |
| 20 | function, and the compiler is forced to emit the vtable in every translation unit | |
| 20 | 21 | that references the class. In this case, it is emitted in a COMDAT section, |
| 21 | 22 | which allows the linker to eliminate all duplicate copies. This is still |
| 22 | 23 | wasteful in terms of object file size and link time, so it's always advisable to |
| 23 | ensure there is at least one eligible method that can serve as the key function. | |
| 24 | ensure there is at least one eligible function that can serve as the key function. | |
| 24 | 25 | |
| 25 | 26 | Here are the most common mistakes that lead to this error: |
| 26 | 27 | |
| ... | ... | @@ -36,8 +37,8 @@ Say you have a base class declared in a header file:: |
| 36 | 37 | ... |
| 37 | 38 | }; |
| 38 | 39 | |
| 39 | Here, ``~B`` is the first non-pure, non-inline, virtual method, so it is the key | |
| 40 | method. If you forget to define ``B::~B`` in your source file, the compiler will | |
| 40 | Here, ``~B`` is the first non-pure, non-inline, virtual function, so it is the key | |
| 41 | function. If you forget to define ``B::~B`` in your source file, the compiler will | |
| 41 | 42 | not emit the vtable for ``B``, and you'll get an undefined reference to "vtable |
| 42 | 43 | for B". |
| 43 | 44 | |
| ... | ... | @@ -47,10 +48,10 @@ the first eligible key function and it's easy to forget to implement them. It's |
| 47 | 48 | also more likely that you won't have any direct references to the destructor, so |
| 48 | 49 | you won't see any undefined reference errors that point directly to the problem. |
| 49 | 50 | |
| 50 | The solution in this case is to implement the missing method. | |
| 51 | The solution in this case is to implement the missing function. | |
| 51 | 52 | |
| 52 | Forgetting to declare a virtual method in an abstract class as pure | |
| 53 | ------------------------------------------------------------------- | |
| 53 | Forgetting to declare a virtual function in an abstract class as pure | |
| 54 | --------------------------------------------------------------------- | |
| 54 | 55 | |
| 55 | 56 | Say you have an abstract base class declared in a header file:: |
| 56 | 57 | |
| ... | ... | @@ -65,18 +66,18 @@ Say you have an abstract base class declared in a header file:: |
| 65 | 66 | }; |
| 66 | 67 | |
| 67 | 68 | This base class is intended to be abstract, but you forgot to mark one of the |
| 68 | methods pure. Here, ``A::bar``, being non-pure, is nominated as the key function, | |
| 69 | functions pure. Here, ``A::bar``, being non-pure, is nominated as the key function, | |
| 69 | 70 | and as a result, the vtable for ``A`` is not emitted, because the compiler is |
| 70 | 71 | waiting for a translation unit that defines ``A::bar``. |
| 71 | 72 | |
| 72 | 73 | The solution in this case is to add the missing ``= 0`` to the declaration of |
| 73 | 74 | ``A::bar``. |
| 74 | 75 | |
| 75 | Key method is defined, but the linker doesn't see it | |
| 76 | ---------------------------------------------------- | |
| 76 | Key function is defined, but the linker doesn't see it | |
| 77 | ------------------------------------------------------ | |
| 77 | 78 | |
| 78 | 79 | It's also possible that you have defined the key function somewhere, but the |
| 79 | object file containing the definition of that method isn't being linked into | |
| 80 | object file containing the definition of that function isn't being linked into | |
| 80 | 81 | your application. |
| 81 | 82 | |
| 82 | 83 | The solution in this case is to check your dependencies to make sure that |
deps/lld/docs/partitions.dot created+22| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | digraph G { | |
| 2 | part_main [label="Main partition",shape=plaintext]; | |
| 3 | part1 [label="Loadable partition 1",shape=plaintext]; | |
| 4 | part2 [label="Loadable partition 2",shape=plaintext]; | |
| 5 | main [style=filled,fillcolor=lightblue]; | |
| 6 | f1 [style=filled,fillcolor=lightsalmon]; | |
| 7 | f2 [style=filled,fillcolor=palegreen]; | |
| 8 | f3 [style=filled,fillcolor=lightblue]; | |
| 9 | f4 [style=filled,fillcolor=lightsalmon]; | |
| 10 | f5 [style=filled,fillcolor=lightblue]; | |
| 11 | f6 [style=filled,fillcolor=palegreen]; | |
| 12 | part_main -> main; | |
| 13 | main -> f3; | |
| 14 | part1 -> f1; | |
| 15 | f1 -> f3; | |
| 16 | f1 -> f4; | |
| 17 | f1 -> f5; | |
| 18 | part2 -> f2; | |
| 19 | f2 -> f3; | |
| 20 | f2 -> f5; | |
| 21 | f2 -> f6; | |
| 22 | } |
deps/lld/docs/partitions.svg created+110| ... | ... | @@ -0,0 +1,110 @@ |
| 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
| 2 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" | |
| 3 | "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | |
| 4 | <!-- Generated by graphviz version 2.38.0 (20140413.2041) | |
| 5 | --> | |
| 6 | <!-- Title: G Pages: 1 --> | |
| 7 | <svg width="393pt" height="188pt" | |
| 8 | viewBox="0.00 0.00 393.00 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> | |
| 9 | <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 184)"> | |
| 10 | <title>G</title> | |
| 11 | <polygon fill="white" stroke="none" points="-4,4 -4,-184 389,-184 389,4 -4,4"/> | |
| 12 | <!-- part_main --> | |
| 13 | <g id="node1" class="node"><title>part_main</title> | |
| 14 | <text text-anchor="middle" x="47.5" y="-158.3" font-family="Times,serif" font-size="14.00">Main partition</text> | |
| 15 | </g> | |
| 16 | <!-- main --> | |
| 17 | <g id="node4" class="node"><title>main</title> | |
| 18 | <ellipse fill="lightblue" stroke="black" cx="75.5" cy="-90" rx="28.6953" ry="18"/> | |
| 19 | <text text-anchor="middle" x="75.5" y="-86.3" font-family="Times,serif" font-size="14.00">main</text> | |
| 20 | </g> | |
| 21 | <!-- part_main&#45;&gt;main --> | |
| 22 | <g id="edge1" class="edge"><title>part_main&#45;&gt;main</title> | |
| 23 | <path fill="none" stroke="black" d="M54.4214,-143.697C57.6218,-135.696 61.492,-126.02 65.0381,-117.155"/> | |
| 24 | <polygon fill="black" stroke="black" points="68.3868,-118.207 68.8511,-107.622 61.8874,-115.607 68.3868,-118.207"/> | |
| 25 | </g> | |
| 26 | <!-- part1 --> | |
| 27 | <g id="node2" class="node"><title>part1</title> | |
| 28 | <text text-anchor="middle" x="176.5" y="-158.3" font-family="Times,serif" font-size="14.00">Loadable partition 1</text> | |
| 29 | </g> | |
| 30 | <!-- f1 --> | |
| 31 | <g id="node5" class="node"><title>f1</title> | |
| 32 | <ellipse fill="lightsalmon" stroke="black" cx="176.5" cy="-90" rx="27" ry="18"/> | |
| 33 | <text text-anchor="middle" x="176.5" y="-86.3" font-family="Times,serif" font-size="14.00">f1</text> | |
| 34 | </g> | |
| 35 | <!-- part1&#45;&gt;f1 --> | |
| 36 | <g id="edge3" class="edge"><title>part1&#45;&gt;f1</title> | |
| 37 | <path fill="none" stroke="black" d="M176.5,-143.697C176.5,-135.983 176.5,-126.712 176.5,-118.112"/> | |
| 38 | <polygon fill="black" stroke="black" points="180,-118.104 176.5,-108.104 173,-118.104 180,-118.104"/> | |
| 39 | </g> | |
| 40 | <!-- part2 --> | |
| 41 | <g id="node3" class="node"><title>part2</title> | |
| 42 | <text text-anchor="middle" x="321.5" y="-158.3" font-family="Times,serif" font-size="14.00">Loadable partition 2</text> | |
| 43 | </g> | |
| 44 | <!-- f2 --> | |
| 45 | <g id="node6" class="node"><title>f2</title> | |
| 46 | <ellipse fill="palegreen" stroke="black" cx="284.5" cy="-90" rx="27" ry="18"/> | |
| 47 | <text text-anchor="middle" x="284.5" y="-86.3" font-family="Times,serif" font-size="14.00">f2</text> | |
| 48 | </g> | |
| 49 | <!-- part2&#45;&gt;f2 --> | |
| 50 | <g id="edge7" class="edge"><title>part2&#45;&gt;f2</title> | |
| 51 | <path fill="none" stroke="black" d="M312.354,-143.697C307.97,-135.403 302.636,-125.311 297.813,-116.187"/> | |
| 52 | <polygon fill="black" stroke="black" points="300.801,-114.35 293.034,-107.145 294.612,-117.621 300.801,-114.35"/> | |
| 53 | </g> | |
| 54 | <!-- f3 --> | |
| 55 | <g id="node7" class="node"><title>f3</title> | |
| 56 | <ellipse fill="lightblue" stroke="black" cx="104.5" cy="-18" rx="27" ry="18"/> | |
| 57 | <text text-anchor="middle" x="104.5" y="-14.3" font-family="Times,serif" font-size="14.00">f3</text> | |
| 58 | </g> | |
| 59 | <!-- main&#45;&gt;f3 --> | |
| 60 | <g id="edge2" class="edge"><title>main&#45;&gt;f3</title> | |
| 61 | <path fill="none" stroke="black" d="M82.3726,-72.411C85.7675,-64.2164 89.9422,-54.1395 93.7473,-44.9548"/> | |
| 62 | <polygon fill="black" stroke="black" points="97.0828,-46.0481 97.6767,-35.4699 90.6158,-43.3689 97.0828,-46.0481"/> | |
| 63 | </g> | |
| 64 | <!-- f1&#45;&gt;f3 --> | |
| 65 | <g id="edge4" class="edge"><title>f1&#45;&gt;f3</title> | |
| 66 | <path fill="none" stroke="black" d="M161.93,-74.8345C151.75,-64.9376 137.976,-51.5462 126.469,-40.3591"/> | |
| 67 | <polygon fill="black" stroke="black" points="128.905,-37.8461 119.296,-33.3847 124.026,-42.865 128.905,-37.8461"/> | |
| 68 | </g> | |
| 69 | <!-- f4 --> | |
| 70 | <g id="node8" class="node"><title>f4</title> | |
| 71 | <ellipse fill="lightsalmon" stroke="black" cx="176.5" cy="-18" rx="27" ry="18"/> | |
| 72 | <text text-anchor="middle" x="176.5" y="-14.3" font-family="Times,serif" font-size="14.00">f4</text> | |
| 73 | </g> | |
| 74 | <!-- f1&#45;&gt;f4 --> | |
| 75 | <g id="edge5" class="edge"><title>f1&#45;&gt;f4</title> | |
| 76 | <path fill="none" stroke="black" d="M176.5,-71.6966C176.5,-63.9827 176.5,-54.7125 176.5,-46.1124"/> | |
| 77 | <polygon fill="black" stroke="black" points="180,-46.1043 176.5,-36.1043 173,-46.1044 180,-46.1043"/> | |
| 78 | </g> | |
| 79 | <!-- f5 --> | |
| 80 | <g id="node9" class="node"><title>f5</title> | |
| 81 | <ellipse fill="lightblue" stroke="black" cx="248.5" cy="-18" rx="27" ry="18"/> | |
| 82 | <text text-anchor="middle" x="248.5" y="-14.3" font-family="Times,serif" font-size="14.00">f5</text> | |
| 83 | </g> | |
| 84 | <!-- f1&#45;&gt;f5 --> | |
| 85 | <g id="edge6" class="edge"><title>f1&#45;&gt;f5</title> | |
| 86 | <path fill="none" stroke="black" d="M191.07,-74.8345C201.25,-64.9376 215.024,-51.5462 226.531,-40.3591"/> | |
| 87 | <polygon fill="black" stroke="black" points="228.974,-42.865 233.704,-33.3847 224.095,-37.8461 228.974,-42.865"/> | |
| 88 | </g> | |
| 89 | <!-- f2&#45;&gt;f3 --> | |
| 90 | <g id="edge8" class="edge"><title>f2&#45;&gt;f3</title> | |
| 91 | <path fill="none" stroke="black" d="M260.806,-81.0022C232.063,-71.1346 182.266,-53.5073 140.5,-36 138.683,-35.2385 136.825,-34.4358 134.957,-33.6106"/> | |
| 92 | <polygon fill="black" stroke="black" points="136.231,-30.3452 125.68,-29.3829 133.328,-36.7149 136.231,-30.3452"/> | |
| 93 | </g> | |
| 94 | <!-- f2&#45;&gt;f5 --> | |
| 95 | <g id="edge9" class="edge"><title>f2&#45;&gt;f5</title> | |
| 96 | <path fill="none" stroke="black" d="M276.15,-72.7646C271.788,-64.2831 266.353,-53.7144 261.459,-44.1974"/> | |
| 97 | <polygon fill="black" stroke="black" points="264.49,-42.4395 256.804,-35.1473 258.265,-45.6409 264.49,-42.4395"/> | |
| 98 | </g> | |
| 99 | <!-- f6 --> | |
| 100 | <g id="node10" class="node"><title>f6</title> | |
| 101 | <ellipse fill="palegreen" stroke="black" cx="320.5" cy="-18" rx="27" ry="18"/> | |
| 102 | <text text-anchor="middle" x="320.5" y="-14.3" font-family="Times,serif" font-size="14.00">f6</text> | |
| 103 | </g> | |
| 104 | <!-- f2&#45;&gt;f6 --> | |
| 105 | <g id="edge10" class="edge"><title>f2&#45;&gt;f6</title> | |
| 106 | <path fill="none" stroke="black" d="M292.85,-72.7646C297.212,-64.2831 302.647,-53.7144 307.541,-44.1974"/> | |
| 107 | <polygon fill="black" stroke="black" points="310.735,-45.6409 312.196,-35.1473 304.51,-42.4395 310.735,-45.6409"/> | |
| 108 | </g> | |
| 109 | </g> | |
| 110 | </svg> |
deps/lld/docs/sphinx_intro.rst+2-2| ... | ... | @@ -43,8 +43,8 @@ to install it using: |
| 43 | 43 | Use your distribution's standard package management tool to install it, |
| 44 | 44 | i.e., ``apt-get install easy_install`` or ``yum install easy_install``. |
| 45 | 45 | |
| 46 | Mac OS X | |
| 47 | All modern Mac OS X systems come with ``easy_install`` as part of the base | |
| 46 | macOS | |
| 47 | All modern macOS systems come with ``easy_install`` as part of the base | |
| 48 | 48 | system. |
| 49 | 49 | |
| 50 | 50 | Windows |
deps/lld/include/lld/Common/Args.h+14-9| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Args.h ---------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -11,6 +10,7 @@ |
| 11 | 10 | #define LLD_ARGS_H |
| 12 | 11 | |
| 13 | 12 | #include "lld/Common/LLVM.h" |
| 13 | #include "llvm/Support/CodeGen.h" | |
| 14 | 14 | #include "llvm/Support/MemoryBuffer.h" |
| 15 | 15 | #include <vector> |
| 16 | 16 | |
| ... | ... | @@ -22,15 +22,20 @@ class InputArgList; |
| 22 | 22 | |
| 23 | 23 | namespace lld { |
| 24 | 24 | namespace args { |
| 25 | int getInteger(llvm::opt::InputArgList &Args, unsigned Key, int Default); | |
| 26 | std::vector<StringRef> getStrings(llvm::opt::InputArgList &Args, int Id); | |
| 27 | 25 | |
| 28 | uint64_t getZOptionValue(llvm::opt::InputArgList &Args, int Id, StringRef Key, | |
| 26 | llvm::CodeGenOpt::Level getCGOptLevel(int optLevelLTO); | |
| 27 | ||
| 28 | int64_t getInteger(llvm::opt::InputArgList &args, unsigned key, | |
| 29 | int64_t Default); | |
| 30 | ||
| 31 | std::vector<StringRef> getStrings(llvm::opt::InputArgList &args, int id); | |
| 32 | ||
| 33 | uint64_t getZOptionValue(llvm::opt::InputArgList &args, int id, StringRef key, | |
| 29 | 34 | uint64_t Default); |
| 30 | 35 | |
| 31 | std::vector<StringRef> getLines(MemoryBufferRef MB); | |
| 36 | std::vector<StringRef> getLines(MemoryBufferRef mb); | |
| 32 | 37 | |
| 33 | StringRef getFilenameWithoutExe(StringRef Path); | |
| 38 | StringRef getFilenameWithoutExe(StringRef path); | |
| 34 | 39 | |
| 35 | 40 | } // namespace args |
| 36 | 41 | } // namespace lld |
deps/lld/include/lld/Common/Driver.h+13-14| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lld/Common/Driver.h - Linker Driver Emulator -----------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -15,28 +14,28 @@ |
| 15 | 14 | |
| 16 | 15 | namespace lld { |
| 17 | 16 | namespace coff { |
| 18 | bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly, | |
| 19 | llvm::raw_ostream &Diag = llvm::errs()); | |
| 17 | bool link(llvm::ArrayRef<const char *> args, bool canExitEarly, | |
| 18 | llvm::raw_ostream &diag = llvm::errs()); | |
| 20 | 19 | } |
| 21 | 20 | |
| 22 | 21 | namespace mingw { |
| 23 | bool link(llvm::ArrayRef<const char *> Args, | |
| 24 | llvm::raw_ostream &Diag = llvm::errs()); | |
| 22 | bool link(llvm::ArrayRef<const char *> args, | |
| 23 | llvm::raw_ostream &diag = llvm::errs()); | |
| 25 | 24 | } |
| 26 | 25 | |
| 27 | 26 | namespace elf { |
| 28 | bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly, | |
| 29 | llvm::raw_ostream &Diag = llvm::errs()); | |
| 27 | bool link(llvm::ArrayRef<const char *> args, bool canExitEarly, | |
| 28 | llvm::raw_ostream &diag = llvm::errs()); | |
| 30 | 29 | } |
| 31 | 30 | |
| 32 | 31 | namespace mach_o { |
| 33 | bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly, | |
| 34 | llvm::raw_ostream &Diag = llvm::errs()); | |
| 32 | bool link(llvm::ArrayRef<const char *> args, bool canExitEarly, | |
| 33 | llvm::raw_ostream &diag = llvm::errs()); | |
| 35 | 34 | } |
| 36 | 35 | |
| 37 | 36 | namespace wasm { |
| 38 | bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly, | |
| 39 | llvm::raw_ostream &Diag = llvm::errs()); | |
| 37 | bool link(llvm::ArrayRef<const char *> args, bool canExitEarly, | |
| 38 | llvm::raw_ostream &diag = llvm::errs()); | |
| 40 | 39 | } |
| 41 | 40 | } |
| 42 | 41 |
deps/lld/include/lld/Common/ErrorHandler.h+49-49| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- ErrorHandler.h -------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -83,74 +82,75 @@ namespace lld { |
| 83 | 82 | |
| 84 | 83 | class ErrorHandler { |
| 85 | 84 | public: |
| 86 | uint64_t ErrorCount = 0; | |
| 87 | uint64_t ErrorLimit = 20; | |
| 88 | StringRef ErrorLimitExceededMsg = "too many errors emitted, stopping now"; | |
| 89 | StringRef LogName = "lld"; | |
| 90 | llvm::raw_ostream *ErrorOS = &llvm::errs(); | |
| 91 | bool ColorDiagnostics = llvm::errs().has_colors(); | |
| 92 | bool ExitEarly = true; | |
| 93 | bool FatalWarnings = false; | |
| 94 | bool Verbose = false; | |
| 95 | ||
| 96 | void error(const Twine &Msg); | |
| 97 | LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); | |
| 98 | void log(const Twine &Msg); | |
| 99 | void message(const Twine &Msg); | |
| 100 | void warn(const Twine &Msg); | |
| 101 | ||
| 102 | std::unique_ptr<llvm::FileOutputBuffer> OutputBuffer; | |
| 85 | uint64_t errorCount = 0; | |
| 86 | uint64_t errorLimit = 20; | |
| 87 | StringRef errorLimitExceededMsg = "too many errors emitted, stopping now"; | |
| 88 | StringRef logName = "lld"; | |
| 89 | llvm::raw_ostream *errorOS = &llvm::errs(); | |
| 90 | bool colorDiagnostics = llvm::errs().has_colors(); | |
| 91 | bool exitEarly = true; | |
| 92 | bool fatalWarnings = false; | |
| 93 | bool verbose = false; | |
| 94 | bool vsDiagnostics = false; | |
| 95 | ||
| 96 | void error(const Twine &msg); | |
| 97 | LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &msg); | |
| 98 | void log(const Twine &msg); | |
| 99 | void message(const Twine &msg); | |
| 100 | void warn(const Twine &msg); | |
| 101 | ||
| 102 | std::unique_ptr<llvm::FileOutputBuffer> outputBuffer; | |
| 103 | 103 | |
| 104 | 104 | private: |
| 105 | void print(StringRef S, raw_ostream::Colors C); | |
| 105 | void printHeader(StringRef s, raw_ostream::Colors c, const Twine &msg); | |
| 106 | 106 | }; |
| 107 | 107 | |
| 108 | 108 | /// Returns the default error handler. |
| 109 | 109 | ErrorHandler &errorHandler(); |
| 110 | 110 | |
| 111 | inline void error(const Twine &Msg) { errorHandler().error(Msg); } | |
| 112 | inline LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg) { | |
| 113 | errorHandler().fatal(Msg); | |
| 111 | inline void error(const Twine &msg) { errorHandler().error(msg); } | |
| 112 | inline LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &msg) { | |
| 113 | errorHandler().fatal(msg); | |
| 114 | 114 | } |
| 115 | inline void log(const Twine &Msg) { errorHandler().log(Msg); } | |
| 116 | inline void message(const Twine &Msg) { errorHandler().message(Msg); } | |
| 117 | inline void warn(const Twine &Msg) { errorHandler().warn(Msg); } | |
| 118 | inline uint64_t errorCount() { return errorHandler().ErrorCount; } | |
| 115 | inline void log(const Twine &msg) { errorHandler().log(msg); } | |
| 116 | inline void message(const Twine &msg) { errorHandler().message(msg); } | |
| 117 | inline void warn(const Twine &msg) { errorHandler().warn(msg); } | |
| 118 | inline uint64_t errorCount() { return errorHandler().errorCount; } | |
| 119 | 119 | |
| 120 | LLVM_ATTRIBUTE_NORETURN void exitLld(int Val); | |
| 120 | LLVM_ATTRIBUTE_NORETURN void exitLld(int val); | |
| 121 | 121 | |
| 122 | void diagnosticHandler(const llvm::DiagnosticInfo &DI); | |
| 123 | void checkError(Error E); | |
| 122 | void diagnosticHandler(const llvm::DiagnosticInfo &di); | |
| 123 | void checkError(Error e); | |
| 124 | 124 | |
| 125 | 125 | // check functions are convenient functions to strip errors |
| 126 | 126 | // from error-or-value objects. |
| 127 | template <class T> T check(ErrorOr<T> E) { | |
| 128 | if (auto EC = E.getError()) | |
| 129 | fatal(EC.message()); | |
| 130 | return std::move(*E); | |
| 127 | template <class T> T check(ErrorOr<T> e) { | |
| 128 | if (auto ec = e.getError()) | |
| 129 | fatal(ec.message()); | |
| 130 | return std::move(*e); | |
| 131 | 131 | } |
| 132 | 132 | |
| 133 | template <class T> T check(Expected<T> E) { | |
| 134 | if (!E) | |
| 135 | fatal(llvm::toString(E.takeError())); | |
| 136 | return std::move(*E); | |
| 133 | template <class T> T check(Expected<T> e) { | |
| 134 | if (!e) | |
| 135 | fatal(llvm::toString(e.takeError())); | |
| 136 | return std::move(*e); | |
| 137 | 137 | } |
| 138 | 138 | |
| 139 | 139 | template <class T> |
| 140 | T check2(ErrorOr<T> E, llvm::function_ref<std::string()> Prefix) { | |
| 141 | if (auto EC = E.getError()) | |
| 142 | fatal(Prefix() + ": " + EC.message()); | |
| 143 | return std::move(*E); | |
| 140 | T check2(ErrorOr<T> e, llvm::function_ref<std::string()> prefix) { | |
| 141 | if (auto ec = e.getError()) | |
| 142 | fatal(prefix() + ": " + ec.message()); | |
| 143 | return std::move(*e); | |
| 144 | 144 | } |
| 145 | 145 | |
| 146 | 146 | template <class T> |
| 147 | T check2(Expected<T> E, llvm::function_ref<std::string()> Prefix) { | |
| 148 | if (!E) | |
| 149 | fatal(Prefix() + ": " + toString(E.takeError())); | |
| 150 | return std::move(*E); | |
| 147 | T check2(Expected<T> e, llvm::function_ref<std::string()> prefix) { | |
| 148 | if (!e) | |
| 149 | fatal(prefix() + ": " + toString(e.takeError())); | |
| 150 | return std::move(*e); | |
| 151 | 151 | } |
| 152 | 152 | |
| 153 | inline std::string toString(const Twine &S) { return S.str(); } | |
| 153 | inline std::string toString(const Twine &s) { return s.str(); } | |
| 154 | 154 | |
| 155 | 155 | // To evaluate the second argument lazily, we use C macro. |
| 156 | 156 | #define CHECK(E, S) check2((E), [&] { return toString(S); }) |
deps/lld/include/lld/Common/Filesystem.h created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | //===- Filesystem.h ---------------------------------------------*- C++ -*-===// | |
| 2 | // | |
| 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 | |
| 6 | // | |
| 7 | //===----------------------------------------------------------------------===// | |
| 8 | ||
| 9 | #ifndef LLD_FILESYSTEM_H | |
| 10 | #define LLD_FILESYSTEM_H | |
| 11 | ||
| 12 | #include "lld/Common/LLVM.h" | |
| 13 | #include <system_error> | |
| 14 | ||
| 15 | namespace lld { | |
| 16 | void unlinkAsync(StringRef path); | |
| 17 | std::error_code tryCreateFile(StringRef path); | |
| 18 | } // namespace lld | |
| 19 | ||
| 20 | #endif |
deps/lld/include/lld/Common/LLVM.h+5-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===--- LLVM.h - Import various common LLVM datatypes ----------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -30,6 +29,7 @@ class Twine; |
| 30 | 29 | class MemoryBuffer; |
| 31 | 30 | class MemoryBufferRef; |
| 32 | 31 | template <typename T> class ArrayRef; |
| 32 | template <typename T> class MutableArrayRef; | |
| 33 | 33 | template <unsigned InternalLen> class SmallString; |
| 34 | 34 | template <typename T, unsigned N> class SmallVector; |
| 35 | 35 | template <typename T> class ErrorOr; |
| ... | ... | @@ -63,6 +63,7 @@ using llvm::isa; |
| 63 | 63 | |
| 64 | 64 | // ADT's. |
| 65 | 65 | using llvm::ArrayRef; |
| 66 | using llvm::MutableArrayRef; | |
| 66 | 67 | using llvm::Error; |
| 67 | 68 | using llvm::ErrorOr; |
| 68 | 69 | using llvm::Expected; |
deps/lld/include/lld/Common/Memory.h+12-13| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Memory.h -------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -29,30 +28,30 @@ |
| 29 | 28 | namespace lld { |
| 30 | 29 | |
| 31 | 30 | // Use this arena if your object doesn't have a destructor. |
| 32 | extern llvm::BumpPtrAllocator BAlloc; | |
| 33 | extern llvm::StringSaver Saver; | |
| 31 | extern llvm::BumpPtrAllocator bAlloc; | |
| 32 | extern llvm::StringSaver saver; | |
| 34 | 33 | |
| 35 | 34 | void freeArena(); |
| 36 | 35 | |
| 37 | 36 | // These two classes are hack to keep track of all |
| 38 | 37 | // SpecificBumpPtrAllocator instances. |
| 39 | 38 | struct SpecificAllocBase { |
| 40 | SpecificAllocBase() { Instances.push_back(this); } | |
| 39 | SpecificAllocBase() { instances.push_back(this); } | |
| 41 | 40 | virtual ~SpecificAllocBase() = default; |
| 42 | 41 | virtual void reset() = 0; |
| 43 | static std::vector<SpecificAllocBase *> Instances; | |
| 42 | static std::vector<SpecificAllocBase *> instances; | |
| 44 | 43 | }; |
| 45 | 44 | |
| 46 | 45 | template <class T> struct SpecificAlloc : public SpecificAllocBase { |
| 47 | void reset() override { Alloc.DestroyAll(); } | |
| 48 | llvm::SpecificBumpPtrAllocator<T> Alloc; | |
| 46 | void reset() override { alloc.DestroyAll(); } | |
| 47 | llvm::SpecificBumpPtrAllocator<T> alloc; | |
| 49 | 48 | }; |
| 50 | 49 | |
| 51 | 50 | // Use this arena if your object has a destructor. |
| 52 | 51 | // Your destructor will be invoked from freeArena(). |
| 53 | template <typename T, typename... U> T *make(U &&... Args) { | |
| 54 | static SpecificAlloc<T> Alloc; | |
| 55 | return new (Alloc.Alloc.Allocate()) T(std::forward<U>(Args)...); | |
| 52 | template <typename T, typename... U> T *make(U &&... args) { | |
| 53 | static SpecificAlloc<T> alloc; | |
| 54 | return new (alloc.alloc.Allocate()) T(std::forward<U>(args)...); | |
| 56 | 55 | } |
| 57 | 56 | |
| 58 | 57 | } // namespace lld |
deps/lld/include/lld/Common/Reproduce.h+6-11| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Reproduce.h - Utilities for creating reproducers ---------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -23,17 +22,13 @@ namespace lld { |
| 23 | 22 | // Makes a given pathname an absolute path first, and then remove |
| 24 | 23 | // beginning /. For example, "../foo.o" is converted to "home/john/foo.o", |
| 25 | 24 | // assuming that the current directory is "/home/john/bar". |
| 26 | std::string relativeToRoot(StringRef Path); | |
| 25 | std::string relativeToRoot(StringRef path); | |
| 27 | 26 | |
| 28 | 27 | // Quote a given string if it contains a space character. |
| 29 | std::string quote(StringRef S); | |
| 30 | ||
| 31 | // Rewrite the given path if a file exists with that pathname, otherwise | |
| 32 | // returns the original path. | |
| 33 | std::string rewritePath(StringRef S); | |
| 28 | std::string quote(StringRef s); | |
| 34 | 29 | |
| 35 | 30 | // Returns the string form of the given argument. |
| 36 | std::string toString(const llvm::opt::Arg &Arg); | |
| 31 | std::string toString(const llvm::opt::Arg &arg); | |
| 37 | 32 | } |
| 38 | 33 | |
| 39 | 34 | #endif |
deps/lld/include/lld/Common/Strings.h+11-12| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Strings.h ------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -20,25 +19,25 @@ |
| 20 | 19 | namespace lld { |
| 21 | 20 | // Returns a demangled C++ symbol name. If Name is not a mangled |
| 22 | 21 | // name, it returns Optional::None. |
| 23 | llvm::Optional<std::string> demangleItanium(llvm::StringRef Name); | |
| 24 | llvm::Optional<std::string> demangleMSVC(llvm::StringRef S); | |
| 22 | llvm::Optional<std::string> demangleItanium(llvm::StringRef name); | |
| 23 | llvm::Optional<std::string> demangleMSVC(llvm::StringRef s); | |
| 25 | 24 | |
| 26 | std::vector<uint8_t> parseHex(llvm::StringRef S); | |
| 27 | bool isValidCIdentifier(llvm::StringRef S); | |
| 25 | std::vector<uint8_t> parseHex(llvm::StringRef s); | |
| 26 | bool isValidCIdentifier(llvm::StringRef s); | |
| 28 | 27 | |
| 29 | 28 | // Write the contents of the a buffer to a file |
| 30 | void saveBuffer(llvm::StringRef Buffer, const llvm::Twine &Path); | |
| 29 | void saveBuffer(llvm::StringRef buffer, const llvm::Twine &path); | |
| 31 | 30 | |
| 32 | 31 | // This class represents multiple glob patterns. |
| 33 | 32 | class StringMatcher { |
| 34 | 33 | public: |
| 35 | 34 | StringMatcher() = default; |
| 36 | explicit StringMatcher(llvm::ArrayRef<llvm::StringRef> Pat); | |
| 35 | explicit StringMatcher(llvm::ArrayRef<llvm::StringRef> pat); | |
| 37 | 36 | |
| 38 | bool match(llvm::StringRef S) const; | |
| 37 | bool match(llvm::StringRef s) const; | |
| 39 | 38 | |
| 40 | 39 | private: |
| 41 | std::vector<llvm::GlobPattern> Patterns; | |
| 40 | std::vector<llvm::GlobPattern> patterns; | |
| 42 | 41 | }; |
| 43 | 42 | |
| 44 | 43 | } // namespace lld |
deps/lld/include/lld/Common/TargetOptionsCommandFlags.h+7-8| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===-- TargetOptionsCommandFlags.h ----------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -16,8 +15,8 @@ |
| 16 | 15 | #include "llvm/Target/TargetOptions.h" |
| 17 | 16 | |
| 18 | 17 | namespace lld { |
| 19 | llvm::TargetOptions InitTargetOptionsFromCodeGenFlags(); | |
| 20 | llvm::Optional<llvm::CodeModel::Model> GetCodeModelFromCMModel(); | |
| 21 | std::string GetCPUStr(); | |
| 22 | std::vector<std::string> GetMAttrs(); | |
| 18 | llvm::TargetOptions initTargetOptionsFromCodeGenFlags(); | |
| 19 | llvm::Optional<llvm::CodeModel::Model> getCodeModelFromCMModel(); | |
| 20 | std::string getCPUStr(); | |
| 21 | std::vector<std::string> getMAttrs(); | |
| 23 | 22 | } |
deps/lld/include/lld/Common/Threads.h+20-14| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Threads.h ------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -64,21 +63,28 @@ |
| 64 | 63 | |
| 65 | 64 | namespace lld { |
| 66 | 65 | |
| 67 | extern bool ThreadsEnabled; | |
| 66 | extern bool threadsEnabled; | |
| 67 | ||
| 68 | template <typename R, class FuncTy> void parallelForEach(R &&range, FuncTy fn) { | |
| 69 | if (threadsEnabled) | |
| 70 | for_each(llvm::parallel::par, std::begin(range), std::end(range), fn); | |
| 71 | else | |
| 72 | for_each(llvm::parallel::seq, std::begin(range), std::end(range), fn); | |
| 73 | } | |
| 68 | 74 | |
| 69 | template <typename R, class FuncTy> void parallelForEach(R &&Range, FuncTy Fn) { | |
| 70 | if (ThreadsEnabled) | |
| 71 | for_each(llvm::parallel::par, std::begin(Range), std::end(Range), Fn); | |
| 75 | inline void parallelForEachN(size_t begin, size_t end, | |
| 76 | llvm::function_ref<void(size_t)> fn) { | |
| 77 | if (threadsEnabled) | |
| 78 | for_each_n(llvm::parallel::par, begin, end, fn); | |
| 72 | 79 | else |
| 73 | for_each(llvm::parallel::seq, std::begin(Range), std::end(Range), Fn); | |
| 80 | for_each_n(llvm::parallel::seq, begin, end, fn); | |
| 74 | 81 | } |
| 75 | 82 | |
| 76 | inline void parallelForEachN(size_t Begin, size_t End, | |
| 77 | llvm::function_ref<void(size_t)> Fn) { | |
| 78 | if (ThreadsEnabled) | |
| 79 | for_each_n(llvm::parallel::par, Begin, End, Fn); | |
| 83 | template <typename R, class FuncTy> void parallelSort(R &&range, FuncTy fn) { | |
| 84 | if (threadsEnabled) | |
| 85 | sort(llvm::parallel::par, std::begin(range), std::end(range), fn); | |
| 80 | 86 | else |
| 81 | for_each_n(llvm::parallel::seq, Begin, End, Fn); | |
| 87 | sort(llvm::parallel::seq, std::begin(range), std::end(range), fn); | |
| 82 | 88 | } |
| 83 | 89 | |
| 84 | 90 | } // namespace lld |
deps/lld/include/lld/Common/Timer.h+14-15| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Timer.h ----------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -22,18 +21,18 @@ namespace lld { |
| 22 | 21 | class Timer; |
| 23 | 22 | |
| 24 | 23 | struct ScopedTimer { |
| 25 | explicit ScopedTimer(Timer &T); | |
| 24 | explicit ScopedTimer(Timer &t); | |
| 26 | 25 | |
| 27 | 26 | ~ScopedTimer(); |
| 28 | 27 | |
| 29 | 28 | void stop(); |
| 30 | 29 | |
| 31 | Timer *T = nullptr; | |
| 30 | Timer *t = nullptr; | |
| 32 | 31 | }; |
| 33 | 32 | |
| 34 | 33 | class Timer { |
| 35 | 34 | public: |
| 36 | Timer(llvm::StringRef Name, Timer &Parent); | |
| 35 | Timer(llvm::StringRef name, Timer &parent); | |
| 37 | 36 | |
| 38 | 37 | static Timer &root(); |
| 39 | 38 | |
| ... | ... | @@ -44,14 +43,14 @@ public: |
| 44 | 43 | double millis() const; |
| 45 | 44 | |
| 46 | 45 | private: |
| 47 | explicit Timer(llvm::StringRef Name); | |
| 48 | void print(int Depth, double TotalDuration, bool Recurse = true) const; | |
| 49 | ||
| 50 | std::chrono::time_point<std::chrono::high_resolution_clock> StartTime; | |
| 51 | std::chrono::nanoseconds Total; | |
| 52 | std::vector<Timer *> Children; | |
| 53 | std::string Name; | |
| 54 | Timer *Parent; | |
| 46 | explicit Timer(llvm::StringRef name); | |
| 47 | void print(int depth, double totalDuration, bool recurse = true) const; | |
| 48 | ||
| 49 | std::chrono::time_point<std::chrono::high_resolution_clock> startTime; | |
| 50 | std::chrono::nanoseconds total; | |
| 51 | std::vector<Timer *> children; | |
| 52 | std::string name; | |
| 53 | Timer *parent; | |
| 55 | 54 | }; |
| 56 | 55 | |
| 57 | 56 | } // namespace lld |
deps/lld/include/lld/Common/Version.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lld/Common/Version.h - LLD Version Number ----------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
deps/lld/include/lld/Core/AbsoluteAtom.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Core/AbsoluteAtom.h - An absolute Atom -----------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/Core/ArchiveLibraryFile.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Core/ArchiveLibraryFile.h - Models static library ------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/Core/Atom.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Core/Atom.h - A node in linking graph --------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/Core/DefinedAtom.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Core/DefinedAtom.h - An Atom with content --------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/Core/Error.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Error.h - system_error extensions for lld ----------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
deps/lld/include/lld/Core/File.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Core/File.h - A Container of Atoms ---------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/Core/Instrumentation.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- include/Core/Instrumentation.h - Instrumentation API ---------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | /// |
deps/lld/include/lld/Core/LinkingContext.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lld/Core/LinkingContext.h - Linker Target Info Interface -*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/Core/Node.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lld/Core/Node.h - Input file class -----------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | /// |
deps/lld/include/lld/Core/Pass.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===------ Core/Pass.h - Base class for linker passes ----------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/Core/PassManager.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lld/Core/PassManager.h - Manage linker passes ----------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/Core/Reader.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lld/Core/Reader.h - Abstract File Format Reading Interface ---------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/Core/Reference.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Core/References.h - A Reference to Another Atom ----------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/Core/Resolver.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Core/Resolver.h - Resolves Atom References -------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/Core/SharedLibraryAtom.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Core/SharedLibraryAtom.h - A Shared Library Atom -------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/Core/SharedLibraryFile.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Core/SharedLibraryFile.h - Models shared libraries as Atoms --------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/Core/Simple.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lld/Core/Simple.h - Simple implementations of Atom and File --------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | /// |
deps/lld/include/lld/Core/SymbolTable.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Core/SymbolTable.h - Main Symbol Table -----------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/Core/UndefinedAtom.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Core/UndefinedAtom.h - An Undefined Atom ---------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/Core/Writer.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lld/Core/Writer.h - Abstract File Format Interface -----------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/ReaderWriter/MachOLinkingContext.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lld/ReaderWriter/MachOLinkingContext.h -----------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/include/lld/ReaderWriter/YamlContext.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lld/ReaderWriter/YamlContext.h - object used in YAML I/O context ---===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/Core/DefinedAtom.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- DefinedAtom.cpp ------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/Core/Error.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Error.cpp - system_error extensions for lld --------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/Core/File.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Core/File.cpp - A Container of Atoms -------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/Core/LinkingContext.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/Core/LinkingContext.cpp - Linker Context Object Interface ------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/Core/Reader.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/Core/Reader.cpp ------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/Core/Resolver.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Core/Resolver.cpp - Resolves Atom References -----------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/Core/SymbolTable.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Core/SymbolTable.cpp - Main Symbol Table ---------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/Core/Writer.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/Core/Writer.cpp ------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/Driver/DarwinLdDriver.cpp+15-16| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/Driver/DarwinLdDriver.cpp --------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | /// |
| ... | ... | @@ -334,8 +333,8 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx) { |
| 334 | 333 | Twine(unknownArg->getAsString(parsedArgs))); |
| 335 | 334 | } |
| 336 | 335 | |
| 337 | errorHandler().Verbose = parsedArgs.hasArg(OPT_v); | |
| 338 | errorHandler().ErrorLimit = args::getInteger(parsedArgs, OPT_error_limit, 20); | |
| 336 | errorHandler().verbose = parsedArgs.hasArg(OPT_v); | |
| 337 | errorHandler().errorLimit = args::getInteger(parsedArgs, OPT_error_limit, 20); | |
| 339 | 338 | |
| 340 | 339 | // Figure out output kind ( -dylib, -r, -bundle, -preload, or -static ) |
| 341 | 340 | llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE; |
| ... | ... | @@ -638,7 +637,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx) { |
| 638 | 637 | |
| 639 | 638 | // Now that we've constructed the final set of search paths, print out those |
| 640 | 639 | // search paths in verbose mode. |
| 641 | if (errorHandler().Verbose) { | |
| 640 | if (errorHandler().verbose) { | |
| 642 | 641 | message("Library search paths:"); |
| 643 | 642 | for (auto path : ctx.searchDirs()) { |
| 644 | 643 | message(" " + path); |
| ... | ... | @@ -1146,13 +1145,13 @@ static void createFiles(MachOLinkingContext &ctx, bool Implicit) { |
| 1146 | 1145 | /// This is where the link is actually performed. |
| 1147 | 1146 | bool link(llvm::ArrayRef<const char *> args, bool CanExitEarly, |
| 1148 | 1147 | raw_ostream &Error) { |
| 1149 | errorHandler().LogName = args::getFilenameWithoutExe(args[0]); | |
| 1150 | errorHandler().ErrorLimitExceededMsg = | |
| 1148 | errorHandler().logName = args::getFilenameWithoutExe(args[0]); | |
| 1149 | errorHandler().errorLimitExceededMsg = | |
| 1151 | 1150 | "too many errors emitted, stopping now (use " |
| 1152 | 1151 | "'-error-limit 0' to see all errors)"; |
| 1153 | errorHandler().ErrorOS = &Error; | |
| 1154 | errorHandler().ExitEarly = CanExitEarly; | |
| 1155 | errorHandler().ColorDiagnostics = Error.has_colors(); | |
| 1152 | errorHandler().errorOS = &Error; | |
| 1153 | errorHandler().exitEarly = CanExitEarly; | |
| 1154 | errorHandler().colorDiagnostics = Error.has_colors(); | |
| 1156 | 1155 | |
| 1157 | 1156 | MachOLinkingContext ctx; |
| 1158 | 1157 | if (!parse(args, ctx)) |
| ... | ... | @@ -1197,9 +1196,9 @@ bool link(llvm::ArrayRef<const char *> args, bool CanExitEarly, |
| 1197 | 1196 | if (auto ec = pm.runOnFile(*merged)) { |
| 1198 | 1197 | // FIXME: This should be passed to logAllUnhandledErrors but it needs |
| 1199 | 1198 | // to be passed a Twine instead of a string. |
| 1200 | *errorHandler().ErrorOS << "Failed to run passes on file '" | |
| 1199 | *errorHandler().errorOS << "Failed to run passes on file '" | |
| 1201 | 1200 | << ctx.outputPath() << "': "; |
| 1202 | logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS, | |
| 1201 | logAllUnhandledErrors(std::move(ec), *errorHandler().errorOS, | |
| 1203 | 1202 | std::string()); |
| 1204 | 1203 | return false; |
| 1205 | 1204 | } |
| ... | ... | @@ -1211,9 +1210,9 @@ bool link(llvm::ArrayRef<const char *> args, bool CanExitEarly, |
| 1211 | 1210 | if (auto ec = ctx.writeFile(*merged)) { |
| 1212 | 1211 | // FIXME: This should be passed to logAllUnhandledErrors but it needs |
| 1213 | 1212 | // to be passed a Twine instead of a string. |
| 1214 | *errorHandler().ErrorOS << "Failed to write file '" << ctx.outputPath() | |
| 1213 | *errorHandler().errorOS << "Failed to write file '" << ctx.outputPath() | |
| 1215 | 1214 | << "': "; |
| 1216 | logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS, | |
| 1215 | logAllUnhandledErrors(std::move(ec), *errorHandler().errorOS, | |
| 1217 | 1216 | std::string()); |
| 1218 | 1217 | return false; |
| 1219 | 1218 | } |
deps/lld/lib/ReaderWriter/FileArchive.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/FileArchive.cpp -----------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/ArchHandler.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/FileFormat/MachO/ArchHandler.cpp -------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/ArchHandler.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/FileFormat/MachO/ArchHandler.h ---------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/FileFormat/MachO/ArchHandler_arm.cpp ---------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/FileFormat/MachO/ArchHandler_arm64.cpp -------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/FileFormat/MachO/ArchHandler_x86.cpp ---------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp+4-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/FileFormat/MachO/ArchHandler_x86_64.cpp ------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -622,6 +621,7 @@ void ArchHandler_x86_64::applyFixupFinal( |
| 622 | 621 | // Fall into llvm_unreachable(). |
| 623 | 622 | break; |
| 624 | 623 | } |
| 624 | llvm_unreachable("invalid x86_64 Reference Kind"); | |
| 625 | 625 | } |
| 626 | 626 | |
| 627 | 627 | void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref, |
deps/lld/lib/ReaderWriter/MachO/Atoms.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/Atoms.h ---------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp+7-12| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/CompactUnwindPass.cpp -------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | /// |
| ... | ... | @@ -388,12 +387,9 @@ private: |
| 388 | 387 | |
| 389 | 388 | // Gather the personality functions now, so that they're in deterministic |
| 390 | 389 | // order (derived from the DefinedAtom order). |
| 391 | if (unwindEntry.personalityFunction) { | |
| 392 | auto pFunc = std::find(personalities.begin(), personalities.end(), | |
| 393 | unwindEntry.personalityFunction); | |
| 394 | if (pFunc == personalities.end()) | |
| 395 | personalities.push_back(unwindEntry.personalityFunction); | |
| 396 | } | |
| 390 | if (unwindEntry.personalityFunction && | |
| 391 | !llvm::count(personalities, unwindEntry.personalityFunction)) | |
| 392 | personalities.push_back(unwindEntry.personalityFunction); | |
| 397 | 393 | } |
| 398 | 394 | } |
| 399 | 395 | |
| ... | ... | @@ -552,8 +548,7 @@ private: |
| 552 | 548 | } |
| 553 | 549 | } |
| 554 | 550 | |
| 555 | auto personality = std::find(personalities.begin(), personalities.end(), | |
| 556 | entry.personalityFunction); | |
| 551 | auto personality = llvm::find(personalities, entry.personalityFunction); | |
| 557 | 552 | uint32_t personalityIdx = personality == personalities.end() |
| 558 | 553 | ? 0 |
| 559 | 554 | : personality - personalities.begin() + 1; |
deps/lld/lib/ReaderWriter/MachO/DebugInfo.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/File.h ----------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/ExecutableAtoms.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/ExecutableAtoms.h ---------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/File.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/File.h ----------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/FlatNamespaceFile.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/FlatNamespaceFile.h -------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/GOTPass.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/GOTPass.cpp -----------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | /// |
deps/lld/lib/ReaderWriter/MachO/LayoutPass.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===-- ReaderWriter/MachO/LayoutPass.cpp - Layout atoms ------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/LayoutPass.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===------ lib/ReaderWriter/MachO/LayoutPass.h - Handles Layout of atoms -===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp+8-11| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/MachOLinkingContext.cpp ---------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -768,8 +767,7 @@ void MachOLinkingContext::registerDylib(MachODylibFile *dylib, |
| 768 | 767 | bool upward) const { |
| 769 | 768 | std::lock_guard<std::mutex> lock(_dylibsMutex); |
| 770 | 769 | |
| 771 | if (std::find(_allDylibs.begin(), | |
| 772 | _allDylibs.end(), dylib) == _allDylibs.end()) | |
| 770 | if (!llvm::count(_allDylibs, dylib)) | |
| 773 | 771 | _allDylibs.push_back(dylib); |
| 774 | 772 | _pathToDylibMap[dylib->installName()] = dylib; |
| 775 | 773 | // If path is different than install name, register path too. |
| ... | ... | @@ -1016,11 +1014,10 @@ static bool isLibrary(const std::unique_ptr<Node> &elem) { |
| 1016 | 1014 | // new undefines from libraries. |
| 1017 | 1015 | void MachOLinkingContext::finalizeInputFiles() { |
| 1018 | 1016 | std::vector<std::unique_ptr<Node>> &elements = getNodes(); |
| 1019 | std::stable_sort(elements.begin(), elements.end(), | |
| 1020 | [](const std::unique_ptr<Node> &a, | |
| 1021 | const std::unique_ptr<Node> &b) { | |
| 1022 | return !isLibrary(a) && isLibrary(b); | |
| 1023 | }); | |
| 1017 | llvm::stable_sort(elements, [](const std::unique_ptr<Node> &a, | |
| 1018 | const std::unique_ptr<Node> &b) { | |
| 1019 | return !isLibrary(a) && isLibrary(b); | |
| 1020 | }); | |
| 1024 | 1021 | size_t numLibs = std::count_if(elements.begin(), elements.end(), isLibrary); |
| 1025 | 1022 | elements.push_back(llvm::make_unique<GroupEnd>(numLibs)); |
| 1026 | 1023 | } |
deps/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h+5-5| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/MachONormalizedFile.h -----------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -288,7 +287,8 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb, |
| 288 | 287 | /// Takes in-memory normalized view and writes a mach-o object file. |
| 289 | 288 | llvm::Error writeBinary(const NormalizedFile &file, StringRef path); |
| 290 | 289 | |
| 291 | size_t headerAndLoadCommandsSize(const NormalizedFile &file); | |
| 290 | size_t headerAndLoadCommandsSize(const NormalizedFile &file, | |
| 291 | bool includeFunctionStarts); | |
| 292 | 292 | |
| 293 | 293 | |
| 294 | 294 | /// Parses a yaml encoded mach-o file to produce an in-memory normalized view. |
deps/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp ---------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h ------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp+20-14| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp ---------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -109,7 +108,7 @@ private: |
| 109 | 108 | class MachOFileLayout { |
| 110 | 109 | public: |
| 111 | 110 | /// All layout computation is done in the constructor. |
| 112 | MachOFileLayout(const NormalizedFile &file); | |
| 111 | MachOFileLayout(const NormalizedFile &file, bool alwaysIncludeFunctionStarts); | |
| 113 | 112 | |
| 114 | 113 | /// Returns the final file size as computed in the constructor. |
| 115 | 114 | size_t size() const; |
| ... | ... | @@ -123,7 +122,8 @@ public: |
| 123 | 122 | llvm::Error writeBinary(StringRef path); |
| 124 | 123 | |
| 125 | 124 | private: |
| 126 | uint32_t loadCommandsSize(uint32_t &count); | |
| 125 | uint32_t loadCommandsSize(uint32_t &count, | |
| 126 | bool alwaysIncludeFunctionStarts); | |
| 127 | 127 | void buildFileOffsets(); |
| 128 | 128 | void writeMachHeader(); |
| 129 | 129 | llvm::Error writeLoadCommands(); |
| ... | ... | @@ -232,8 +232,9 @@ private: |
| 232 | 232 | ByteBuffer _exportTrie; |
| 233 | 233 | }; |
| 234 | 234 | |
| 235 | size_t headerAndLoadCommandsSize(const NormalizedFile &file) { | |
| 236 | MachOFileLayout layout(file); | |
| 235 | size_t headerAndLoadCommandsSize(const NormalizedFile &file, | |
| 236 | bool includeFunctionStarts) { | |
| 237 | MachOFileLayout layout(file, includeFunctionStarts); | |
| 237 | 238 | return layout.headerAndLoadCommandsSize(); |
| 238 | 239 | } |
| 239 | 240 | |
| ... | ... | @@ -250,7 +251,8 @@ size_t MachOFileLayout::headerAndLoadCommandsSize() const { |
| 250 | 251 | return _endOfLoadCommands; |
| 251 | 252 | } |
| 252 | 253 | |
| 253 | MachOFileLayout::MachOFileLayout(const NormalizedFile &file) | |
| 254 | MachOFileLayout::MachOFileLayout(const NormalizedFile &file, | |
| 255 | bool alwaysIncludeFunctionStarts) | |
| 254 | 256 | : _file(file), |
| 255 | 257 | _is64(MachOLinkingContext::is64Bit(file.arch)), |
| 256 | 258 | _swap(!MachOLinkingContext::isHostEndian(file.arch)), |
| ... | ... | @@ -271,7 +273,7 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file) |
| 271 | 273 | _endOfLoadCommands += sizeof(version_min_command); |
| 272 | 274 | _countOfLoadCommands++; |
| 273 | 275 | } |
| 274 | if (!_file.functionStarts.empty()) { | |
| 276 | if (!_file.functionStarts.empty() || alwaysIncludeFunctionStarts) { | |
| 275 | 277 | _endOfLoadCommands += sizeof(linkedit_data_command); |
| 276 | 278 | _countOfLoadCommands++; |
| 277 | 279 | } |
| ... | ... | @@ -326,7 +328,8 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file) |
| 326 | 328 | } else { |
| 327 | 329 | // Final linked images have one load command per segment. |
| 328 | 330 | _endOfLoadCommands = _startOfLoadCommands |
| 329 | + loadCommandsSize(_countOfLoadCommands); | |
| 331 | + loadCommandsSize(_countOfLoadCommands, | |
| 332 | alwaysIncludeFunctionStarts); | |
| 330 | 333 | |
| 331 | 334 | // Assign section file offsets. |
| 332 | 335 | buildFileOffsets(); |
| ... | ... | @@ -375,7 +378,8 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file) |
| 375 | 378 | } |
| 376 | 379 | } |
| 377 | 380 | |
| 378 | uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) { | |
| 381 | uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count, | |
| 382 | bool alwaysIncludeFunctionStarts) { | |
| 379 | 383 | uint32_t size = 0; |
| 380 | 384 | count = 0; |
| 381 | 385 | |
| ... | ... | @@ -445,7 +449,7 @@ uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) { |
| 445 | 449 | } |
| 446 | 450 | |
| 447 | 451 | // Add LC_FUNCTION_STARTS if needed |
| 448 | if (!_file.functionStarts.empty()) { | |
| 452 | if (!_file.functionStarts.empty() || alwaysIncludeFunctionStarts) { | |
| 449 | 453 | size += sizeof(linkedit_data_command); |
| 450 | 454 | ++count; |
| 451 | 455 | } |
| ... | ... | @@ -1007,6 +1011,7 @@ llvm::Error MachOFileLayout::writeLoadCommands() { |
| 1007 | 1011 | lc += sizeof(linkedit_data_command); |
| 1008 | 1012 | } |
| 1009 | 1013 | } |
| 1014 | assert(lc == &_buffer[_endOfLoadCommands]); | |
| 1010 | 1015 | return llvm::Error::success(); |
| 1011 | 1016 | } |
| 1012 | 1017 | |
| ... | ... | @@ -1018,6 +1023,7 @@ void MachOFileLayout::writeSectionContent() { |
| 1018 | 1023 | if (s.content.empty()) |
| 1019 | 1024 | continue; |
| 1020 | 1025 | uint32_t offset = _sectInfo[&s].fileOffset; |
| 1026 | assert(offset >= _endOfLoadCommands); | |
| 1021 | 1027 | uint8_t *p = &_buffer[offset]; |
| 1022 | 1028 | memcpy(p, &s.content[0], s.content.size()); |
| 1023 | 1029 | p += s.content.size(); |
| ... | ... | @@ -1543,7 +1549,7 @@ llvm::Error MachOFileLayout::writeBinary(StringRef path) { |
| 1543 | 1549 | |
| 1544 | 1550 | /// Takes in-memory normalized view and writes a mach-o object file. |
| 1545 | 1551 | llvm::Error writeBinary(const NormalizedFile &file, StringRef path) { |
| 1546 | MachOFileLayout layout(file); | |
| 1552 | MachOFileLayout layout(file, false); | |
| 1547 | 1553 | return layout.writeBinary(path); |
| 1548 | 1554 | } |
| 1549 | 1555 |
deps/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp+5-5| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp ------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -588,7 +587,8 @@ void Util::layoutSectionsInTextSegment(size_t hlcSize, SegmentInfo *seg, |
| 588 | 587 | |
| 589 | 588 | void Util::assignAddressesToSections(const NormalizedFile &file) { |
| 590 | 589 | // NOTE!: Keep this in sync with organizeSections. |
| 591 | size_t hlcSize = headerAndLoadCommandsSize(file); | |
| 590 | size_t hlcSize = headerAndLoadCommandsSize(file, | |
| 591 | _ctx.generateFunctionStartsLoadCommand()); | |
| 592 | 592 | uint64_t address = 0; |
| 593 | 593 | for (SegmentInfo *seg : _segmentInfos) { |
| 594 | 594 | if (seg->name.equals("__PAGEZERO")) { |
deps/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp --------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp -----------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/MachOPasses.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/MachOPasses.h -------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/ObjCPass.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/ObjCPass.cpp -------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
deps/lld/lib/ReaderWriter/MachO/SectCreateFile.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===---- lib/ReaderWriter/MachO/SectCreateFile.h ---------------*- c++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/MachO/ShimPass.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/ShimPass.cpp -------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
deps/lld/lib/ReaderWriter/MachO/StubsPass.cpp+5-7| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/StubsPass.cpp ---------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -271,9 +270,8 @@ public: |
| 271 | 270 | mergedFile.addAtom(*helperCacheNLPAtom); |
| 272 | 271 | |
| 273 | 272 | // Add reference to dyld_stub_binder in libSystem.dylib |
| 274 | auto I = std::find_if( | |
| 275 | mergedFile.sharedLibrary().begin(), mergedFile.sharedLibrary().end(), | |
| 276 | [&](const SharedLibraryAtom *atom) { | |
| 273 | auto I = llvm::find_if( | |
| 274 | mergedFile.sharedLibrary(), [&](const SharedLibraryAtom *atom) { | |
| 277 | 275 | return atom->name().equals(_stubInfo.binderSymbolName); |
| 278 | 276 | }); |
| 279 | 277 | assert(I != mergedFile.sharedLibrary().end() && |
deps/lld/lib/ReaderWriter/MachO/TLVPass.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/TLVPass.cpp -----------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | /// |
deps/lld/lib/ReaderWriter/MachO/WriterMachO.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/MachO/WriterMachO.cpp -----------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lib/ReaderWriter/YAML/ReaderWriterYAML.cpp -------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/test/CMakeLists.txt+5-3| ... | ... | @@ -14,7 +14,9 @@ if(LLD_BUILT_STANDALONE) |
| 14 | 14 | endif() |
| 15 | 15 | |
| 16 | 16 | llvm_canonicalize_cmake_booleans( |
| 17 | HAVE_LIBZ) | |
| 17 | HAVE_LIBZ | |
| 18 | LLVM_LIBXML2_ENABLED | |
| 19 | ) | |
| 18 | 20 | |
| 19 | 21 | configure_lit_site_cfg( |
| 20 | 22 | ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in |
| ... | ... | @@ -32,8 +34,8 @@ configure_lit_site_cfg( |
| 32 | 34 | set(LLD_TEST_DEPS lld) |
| 33 | 35 | if (NOT LLD_BUILT_STANDALONE) |
| 34 | 36 | list(APPEND LLD_TEST_DEPS |
| 35 | FileCheck count llc llvm-ar llvm-as llvm-bcanalyzer llvm-config llvm-dis | |
| 36 | llvm-dwarfdump llvm-lib llvm-mc llvm-nm llvm-objcopy llvm-objdump | |
| 37 | FileCheck count llc llvm-ar llvm-as llvm-bcanalyzer llvm-config llvm-cvtres | |
| 38 | llvm-dis llvm-dwarfdump llvm-lib llvm-mc llvm-nm llvm-objcopy llvm-objdump | |
| 37 | 39 | llvm-pdbutil llvm-readelf llvm-readobj not obj2yaml opt yaml2obj |
| 38 | 40 | ) |
| 39 | 41 | endif() |
deps/lld/test/COFF/Inputs/combined-resources-2.rc+36-36| ... | ... | @@ -1,36 +1,36 @@ |
| 1 | #include "windows.h" | |
| 2 | ||
| 3 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US | |
| 4 | randomdat RCDATA | |
| 5 | { | |
| 6 | 	"this is a random bit of data that means nothing\0", | |
| 7 | 	0x23a9, | |
| 8 | 	0x140e, | |
| 9 | 	194292, | |
| 10 | } | |
| 11 | ||
| 12 | LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED | |
| 13 | randomdat RCDATA | |
| 14 | { | |
| 15 | 	"zhe4 shi4 yi1ge4 sui2ji1 de shu4ju4, zhe4 yi4wei4zhe shen2me\0", | |
| 16 | 	0x23a9, | |
| 17 | 	0x140e, | |
| 18 | 	194292, | |
| 19 | } | |
| 20 | ||
| 21 | LANGUAGE LANG_GERMAN, SUBLANG_GERMAN_LUXEMBOURG | |
| 22 | randomdat RCDATA | |
| 23 | { | |
| 24 | 	"Dies ist ein zufälliges Bit von Daten, die nichts bedeutet\0", | |
| 25 | 	0x23a9, | |
| 26 | 	0x140e, | |
| 27 | 	194292, | |
| 28 | } | |
| 29 | ||
| 30 | LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED | |
| 31 | myaccelerators ACCELERATORS | |
| 32 | { | |
| 33 | 	"^C", 999, VIRTKEY, ALT | |
| 34 | 	"D", 1100, VIRTKEY, CONTROL, SHIFT | |
| 35 | 	"^R", 444, ASCII, NOINVERT | |
| 36 | } | |
| 1 | #include "windows.h" | |
| 2 | ||
| 3 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US | |
| 4 | randomdat RCDATA | |
| 5 | { | |
| 6 | 	"this is a random bit of data that means nothing\0", | |
| 7 | 	0x23a9, | |
| 8 | 	0x140e, | |
| 9 | 	194292, | |
| 10 | } | |
| 11 | ||
| 12 | LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED | |
| 13 | randomdat RCDATA | |
| 14 | { | |
| 15 | 	"zhe4 shi4 yi1ge4 sui2ji1 de shu4ju4, zhe4 yi4wei4zhe shen2me\0", | |
| 16 | 	0x23a9, | |
| 17 | 	0x140e, | |
| 18 | 	194292, | |
| 19 | } | |
| 20 | ||
| 21 | LANGUAGE LANG_GERMAN, SUBLANG_GERMAN_LUXEMBOURG | |
| 22 | randomdat RCDATA | |
| 23 | { | |
| 24 | 	"Dies ist ein zufälliges Bit von Daten, die nichts bedeutet\0", | |
| 25 | 	0x23a9, | |
| 26 | 	0x140e, | |
| 27 | 	194292, | |
| 28 | } | |
| 29 | ||
| 30 | LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED | |
| 31 | myaccelerators ACCELERATORS | |
| 32 | { | |
| 33 | 	"^C", 999, VIRTKEY, ALT | |
| 34 | 	"D", 1100, VIRTKEY, CONTROL, SHIFT | |
| 35 | 	"^R", 444, ASCII, NOINVERT | |
| 36 | } |
deps/lld/test/COFF/Inputs/crt-dyn-initializer-order_1.yaml+15-15| ... | ... | @@ -1,15 +1,15 @@ |
| 1 | --- !COFF | |
| 2 | header: | |
| 3 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 4 | Characteristics: [ ] | |
| 5 | sections: | |
| 6 | - Name: '.CRT$XCU' | |
| 7 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 8 | Alignment: 1 | |
| 9 | SectionData: 55 | |
| 10 | - Name: '.CRT$XCU' | |
| 11 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 12 | Alignment: 1 | |
| 13 | SectionData: 70 | |
| 14 | symbols: | |
| 15 | ... | |
| 1 | --- !COFF | |
| 2 | header: | |
| 3 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 4 | Characteristics: [ ] | |
| 5 | sections: | |
| 6 | - Name: '.CRT$XCU' | |
| 7 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 8 | Alignment: 1 | |
| 9 | SectionData: 55 | |
| 10 | - Name: '.CRT$XCU' | |
| 11 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 12 | Alignment: 1 | |
| 13 | SectionData: 70 | |
| 14 | symbols: | |
| 15 | ... |
deps/lld/test/COFF/Inputs/crt-dyn-initializer-order_2.yaml+19-19| ... | ... | @@ -1,19 +1,19 @@ |
| 1 | --- !COFF | |
| 2 | header: | |
| 3 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 4 | Characteristics: [ ] | |
| 5 | sections: | |
| 6 | - Name: '.CRT$XCU' | |
| 7 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 8 | Alignment: 1 | |
| 9 | SectionData: 10 | |
| 10 | - Name: '.CRT$XCU' | |
| 11 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 12 | Alignment: 1 | |
| 13 | SectionData: 11 | |
| 14 | - Name: '.CRT$XCU' | |
| 15 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 16 | Alignment: 1 | |
| 17 | SectionData: 12 | |
| 18 | symbols: | |
| 19 | ... | |
| 1 | --- !COFF | |
| 2 | header: | |
| 3 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 4 | Characteristics: [ ] | |
| 5 | sections: | |
| 6 | - Name: '.CRT$XCU' | |
| 7 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 8 | Alignment: 1 | |
| 9 | SectionData: 10 | |
| 10 | - Name: '.CRT$XCU' | |
| 11 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 12 | Alignment: 1 | |
| 13 | SectionData: 11 | |
| 14 | - Name: '.CRT$XCU' | |
| 15 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 16 | Alignment: 1 | |
| 17 | SectionData: 12 | |
| 18 | symbols: | |
| 19 | ... |
deps/lld/test/COFF/Inputs/delayimporttables-dll1.yaml created+57| ... | ... | @@ -0,0 +1,57 @@ |
| 1 | --- !COFF | |
| 2 | header: | |
| 3 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 4 | Characteristics: [ ] | |
| 5 | sections: | |
| 6 | - Name: .drectve | |
| 7 | Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] | |
| 8 | Alignment: 1 | |
| 9 | SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D455322202F4558504F52543A6F6E65202F4558504F52543A74776F20 | |
| 10 | - Name: '.text$mn' | |
| 11 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] | |
| 12 | Alignment: 16 | |
| 13 | SectionData: C20000CCCCCCCCCCCCCCCCCCCCCCCCCCC20000CCCCCCCCCCCCCCCCCCCCCCCCCC4C894424188954241048894C240833C0C3 | |
| 14 | symbols: | |
| 15 | - Name: .drectve | |
| 16 | Value: 0 | |
| 17 | SectionNumber: 1 | |
| 18 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 19 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 20 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 21 | SectionDefinition: | |
| 22 | Length: 71 | |
| 23 | NumberOfRelocations: 0 | |
| 24 | NumberOfLinenumbers: 0 | |
| 25 | CheckSum: 4081356488 | |
| 26 | Number: 0 | |
| 27 | - Name: '.text$mn' | |
| 28 | Value: 0 | |
| 29 | SectionNumber: 2 | |
| 30 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 31 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 32 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 33 | SectionDefinition: | |
| 34 | Length: 49 | |
| 35 | NumberOfRelocations: 0 | |
| 36 | NumberOfLinenumbers: 0 | |
| 37 | CheckSum: 405845281 | |
| 38 | Number: 0 | |
| 39 | - Name: one | |
| 40 | Value: 0 | |
| 41 | SectionNumber: 2 | |
| 42 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 43 | ComplexType: IMAGE_SYM_DTYPE_FUNCTION | |
| 44 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 45 | - Name: two | |
| 46 | Value: 16 | |
| 47 | SectionNumber: 2 | |
| 48 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 49 | ComplexType: IMAGE_SYM_DTYPE_FUNCTION | |
| 50 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 51 | - Name: DllMain | |
| 52 | Value: 32 | |
| 53 | SectionNumber: 2 | |
| 54 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 55 | ComplexType: IMAGE_SYM_DTYPE_FUNCTION | |
| 56 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 57 | ... |
deps/lld/test/COFF/Inputs/delayimporttables-dll2.yaml created+57| ... | ... | @@ -0,0 +1,57 @@ |
| 1 | --- !COFF | |
| 2 | header: | |
| 3 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 4 | Characteristics: [ ] | |
| 5 | sections: | |
| 6 | - Name: .drectve | |
| 7 | Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] | |
| 8 | Alignment: 1 | |
| 9 | SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D455322202F4558504F52543A6C656674202F4558504F52543A726967687420 | |
| 10 | - Name: '.text$mn' | |
| 11 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] | |
| 12 | Alignment: 16 | |
| 13 | SectionData: C20000CCCCCCCCCCCCCCCCCCCCCCCCCCC20000CCCCCCCCCCCCCCCCCCCCCCCCCC4C894424188954241048894C240833C0C3 | |
| 14 | symbols: | |
| 15 | - Name: .drectve | |
| 16 | Value: 0 | |
| 17 | SectionNumber: 1 | |
| 18 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 19 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 20 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 21 | SectionDefinition: | |
| 22 | Length: 74 | |
| 23 | NumberOfRelocations: 0 | |
| 24 | NumberOfLinenumbers: 0 | |
| 25 | CheckSum: 127731413 | |
| 26 | Number: 0 | |
| 27 | - Name: '.text$mn' | |
| 28 | Value: 0 | |
| 29 | SectionNumber: 2 | |
| 30 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 31 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 32 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 33 | SectionDefinition: | |
| 34 | Length: 49 | |
| 35 | NumberOfRelocations: 0 | |
| 36 | NumberOfLinenumbers: 0 | |
| 37 | CheckSum: 405845281 | |
| 38 | Number: 0 | |
| 39 | - Name: left | |
| 40 | Value: 0 | |
| 41 | SectionNumber: 2 | |
| 42 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 43 | ComplexType: IMAGE_SYM_DTYPE_FUNCTION | |
| 44 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 45 | - Name: right | |
| 46 | Value: 16 | |
| 47 | SectionNumber: 2 | |
| 48 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 49 | ComplexType: IMAGE_SYM_DTYPE_FUNCTION | |
| 50 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 51 | - Name: DllMain | |
| 52 | Value: 32 | |
| 53 | SectionNumber: 2 | |
| 54 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 55 | ComplexType: IMAGE_SYM_DTYPE_FUNCTION | |
| 56 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 57 | ... |
deps/lld/test/COFF/Inputs/eh_frame_terminator-crtend.s created+3| ... | ... | @@ -0,0 +1,3 @@ |
| 1 | .section .eh_frame,"dr" | |
| 2 | __FRAME_END__: | |
| 3 | .byte 3 |
deps/lld/test/COFF/Inputs/eh_frame_terminator-otherfunc.s created+7| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | .text | |
| 2 | .globl otherfunc | |
| 3 | otherfunc: | |
| 4 | ret | |
| 5 | ||
| 6 | .section .eh_frame,"dr" | |
| 7 | .byte 2 |
deps/lld/test/COFF/Inputs/failmismatch1.ll created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | ; ModuleID = 'test.cpp' | |
| 2 | ||
| 3 | ; Function Attrs: noinline nounwind optnone sspstrong uwtable | |
| 4 | define dso_local i32 @"?f@@YAHXZ"() #0 { | |
| 5 | ret i32 0 | |
| 6 | } | |
| 7 | ||
| 8 | !llvm.linker.options = !{!0} | |
| 9 | !llvm.module.flags = !{!1, !2} | |
| 10 | !llvm.ident = !{!3} | |
| 11 | ||
| 12 | !0 = !{!"/FAILIFMISMATCH:\22TEST=1\22"} | |
| 13 | !1 = !{i32 1, !"wchar_size", i32 2} | |
| 14 | !2 = !{i32 7, !"PIC Level", i32 2} | |
| 15 | !3 = !{!"clang version 7.0.1 (tags/RELEASE_701/final)"} |
deps/lld/test/COFF/Inputs/failmismatch2.ll created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | ; ModuleID = 'test2.cpp' | |
| 2 | ||
| 3 | ; Function Attrs: noinline norecurse nounwind optnone sspstrong uwtable | |
| 4 | define dso_local i32 @main() #0 { | |
| 5 | %1 = alloca i32, align 4 | |
| 6 | store i32 0, i32* %1, align 4 | |
| 7 | %2 = call i32 @"?f@@YAHXZ"() | |
| 8 | ret i32 %2 | |
| 9 | } | |
| 10 | ||
| 11 | declare dso_local i32 @"?f@@YAHXZ"() #1 | |
| 12 | ||
| 13 | !llvm.linker.options = !{!0} | |
| 14 | !llvm.module.flags = !{!1, !2} | |
| 15 | !llvm.ident = !{!3} | |
| 16 | ||
| 17 | !0 = !{!"/FAILIFMISMATCH:\22TEST=2\22"} | |
| 18 | !1 = !{i32 1, !"wchar_size", i32 2} | |
| 19 | !2 = !{i32 7, !"PIC Level", i32 2} | |
| 20 | !3 = !{!"clang version 7.0.1 (tags/RELEASE_701/final)"} |
deps/lld/test/COFF/Inputs/hello32.yaml+6| ... | ... | @@ -79,4 +79,10 @@ symbols: |
| 79 | 79 | SimpleType: IMAGE_SYM_TYPE_NULL |
| 80 | 80 | ComplexType: IMAGE_SYM_DTYPE_FUNCTION |
| 81 | 81 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL |
| 82 | - Name: '@feat.00' | |
| 83 | Value: 1 | |
| 84 | SectionNumber: -1 | |
| 85 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 86 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 87 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 82 | 88 | ... |
deps/lld/test/COFF/Inputs/id.res created| Binary files /dev/null and b/deps/lld/test/COFF/Inputs/id.res differ |
deps/lld/test/COFF/Inputs/id.res.o created| Binary files /dev/null and b/deps/lld/test/COFF/Inputs/id.res.o differ |
deps/lld/test/COFF/Inputs/no-ipi-stream-obj.obj.yaml created+13| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | --- !COFF | |
| 2 | header: | |
| 3 | Machine: IMAGE_FILE_MACHINE_I386 | |
| 4 | sections: | |
| 5 | - Name: '.debug$T' | |
| 6 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] | |
| 7 | Types: | |
| 8 | - Kind: LF_TYPESERVER2 | |
| 9 | TypeServer2: | |
| 10 | Guid: '{01234567-0123-0123-0123-0123456789AB}' | |
| 11 | Age: 1 | |
| 12 | Name: 'no-ipi-stream-pdb.pdb' | |
| 13 | symbols: |
deps/lld/test/COFF/Inputs/no-ipi-stream-pdb.pdb.yaml created+2| ... | ... | @@ -0,0 +1,2 @@ |
| 1 | PdbStream: | |
| 2 | Guid: '{01234567-0123-0123-0123-0123456789AB}' |
deps/lld/test/COFF/Inputs/pdb-diff.cpp+10-10| ... | ... | @@ -1,10 +1,10 @@ |
| 1 | // Build with cl: | |
| 2 | // cl.exe /Z7 pdb-diff.cpp /link /debug /pdb:pdb-diff-cl.pdb | |
| 3 | // /nodefaultlib /entry:main | |
| 4 | // Build with lld (after running the above cl command): | |
| 5 | // lld-link.exe /debug /pdb:pdb-diff-lld.pdb /nodefaultlib | |
| 6 | // /entry:main pdb-diff.obj | |
| 7 | ||
| 8 | void *__purecall = 0; | |
| 9 | ||
| 10 | int main() { return 42; } | |
| 1 | // Build with cl: | |
| 2 | // cl.exe /Z7 pdb-diff.cpp /link /debug /pdb:pdb-diff-cl.pdb | |
| 3 | // /nodefaultlib /entry:main | |
| 4 | // Build with lld (after running the above cl command): | |
| 5 | // lld-link.exe /debug /pdb:pdb-diff-lld.pdb /nodefaultlib | |
| 6 | // /entry:main pdb-diff.obj | |
| 7 | ||
| 8 | void *__purecall = 0; | |
| 9 | ||
| 10 | int main() { return 42; } |
deps/lld/test/COFF/Inputs/pdb-file-statics-a.yaml+1| ... | ... | @@ -1280,6 +1280,7 @@ sections: |
| 1280 | 1280 | Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] |
| 1281 | 1281 | Alignment: 4 |
| 1282 | 1282 | SectionData: '' |
| 1283 | SizeOfRawData: 4 | |
| 1283 | 1284 | - Name: '.text$mn' |
| 1284 | 1285 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] |
| 1285 | 1286 | Alignment: 4 |
deps/lld/test/COFF/Inputs/pdb-file-statics-b.yaml+1| ... | ... | @@ -1255,6 +1255,7 @@ sections: |
| 1255 | 1255 | Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] |
| 1256 | 1256 | Alignment: 4 |
| 1257 | 1257 | SectionData: '' |
| 1258 | SizeOfRawData: 4 | |
| 1258 | 1259 | - Name: '.text$mn' |
| 1259 | 1260 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] |
| 1260 | 1261 | Alignment: 4 |
deps/lld/test/COFF/Inputs/pdb-global-constants-a.s created+214| ... | ... | @@ -0,0 +1,214 @@ |
| 1 | 	.text | |
| 2 | 	.def	 @feat.00; | |
| 3 | 	.scl	3; | |
| 4 | 	.type	0; | |
| 5 | 	.endef | |
| 6 | 	.globl	@feat.00 | |
| 7 | .set @feat.00, 0 | |
| 8 | 	.file	"t.cpp" | |
| 9 | 	.def	 main; | |
| 10 | 	.scl	2; | |
| 11 | 	.type	32; | |
| 12 | 	.endef | |
| 13 | 	.globl	main # -- Begin function main | |
| 14 | 	.p2align	4, 0x90 | |
| 15 | main: # @main | |
| 16 | .Lfunc_begin0: | |
| 17 | 	.cv_func_id 0 | |
| 18 | 	.cv_file	1 "C:\\src\\testing\\t.cpp" "D28AB0CC784E17E5DF9BBB49CB629C81" 1 | |
| 19 | 	.cv_loc	0 1 4 0 # t.cpp:4:0 | |
| 20 | .seh_proc main | |
| 21 | # %bb.0: # %entry | |
| 22 | 	pushq	%rax | |
| 23 | 	.seh_stackalloc 8 | |
| 24 | 	.seh_endprologue | |
| 25 | 	movl	$0, 4(%rsp) | |
| 26 | .Ltmp0: | |
| 27 | 	movl	$83, %eax | |
| 28 | 	popq	%rcx | |
| 29 | 	retq | |
| 30 | .Ltmp1: | |
| 31 | .Lfunc_end0: | |
| 32 | 	.seh_handlerdata | |
| 33 | 	.text | |
| 34 | 	.seh_endproc | |
| 35 | # -- End function | |
| 36 | 	.section	.debug$S,"dr" | |
| 37 | 	.p2align	2 | |
| 38 | 	.long	4 # Debug section magic | |
| 39 | 	.long	241 | |
| 40 | 	.long	.Ltmp3-.Ltmp2 # Subsection size | |
| 41 | .Ltmp2: | |
| 42 | 	.short	.Ltmp5-.Ltmp4 # Record length | |
| 43 | .Ltmp4: | |
| 44 | 	.short	4412 # Record kind: S_COMPILE3 | |
| 45 | 	.long	1 # Flags and language | |
| 46 | 	.short	208 # CPUType | |
| 47 | 	.short	9 # Frontend version | |
| 48 | 	.short	0 | |
| 49 | 	.short	0 | |
| 50 | 	.short	0 | |
| 51 | 	.short	9000 # Backend version | |
| 52 | 	.short	0 | |
| 53 | 	.short	0 | |
| 54 | 	.short	0 | |
| 55 | 	.asciz	"clang version 9.0.0 (https://github.com/llvm/llvm-project.git ad522e17b285b1f2667163d52da5abf0968ec650)" # Null-terminated compiler version string | |
| 56 | 	.p2align	2 | |
| 57 | .Ltmp5: | |
| 58 | .Ltmp3: | |
| 59 | 	.p2align	2 | |
| 60 | 	.long	241 # Symbol subsection for main | |
| 61 | 	.long	.Ltmp7-.Ltmp6 # Subsection size | |
| 62 | .Ltmp6: | |
| 63 | 	.short	.Ltmp9-.Ltmp8 # Record length | |
| 64 | .Ltmp8: | |
| 65 | 	.short	4423 # Record kind: S_GPROC32_ID | |
| 66 | 	.long	0 # PtrParent | |
| 67 | 	.long	0 # PtrEnd | |
| 68 | 	.long	0 # PtrNext | |
| 69 | 	.long	.Lfunc_end0-main # Code size | |
| 70 | 	.long	0 # Offset after prologue | |
| 71 | 	.long	0 # Offset before epilogue | |
| 72 | 	.long	4098 # Function type index | |
| 73 | 	.secrel32	main # Function section relative address | |
| 74 | 	.secidx	main # Function section index | |
| 75 | 	.byte	0 # Flags | |
| 76 | 	.asciz	"main" # Function name | |
| 77 | 	.p2align	2 | |
| 78 | .Ltmp9: | |
| 79 | 	.short	.Ltmp11-.Ltmp10 # Record length | |
| 80 | .Ltmp10: | |
| 81 | 	.short	4114 # Record kind: S_FRAMEPROC | |
| 82 | 	.long	8 # FrameSize | |
| 83 | 	.long	0 # Padding | |
| 84 | 	.long	0 # Offset of padding | |
| 85 | 	.long	0 # Bytes of callee saved registers | |
| 86 | 	.long	0 # Exception handler offset | |
| 87 | 	.short	0 # Exception handler section | |
| 88 | 	.long	81920 # Flags (defines frame register) | |
| 89 | 	.p2align	2 | |
| 90 | .Ltmp11: | |
| 91 | 	.short	2 # Record length | |
| 92 | 	.short	4431 # Record kind: S_PROC_ID_END | |
| 93 | .Ltmp7: | |
| 94 | 	.p2align	2 | |
| 95 | 	.cv_linetable	0, main, .Lfunc_end0 | |
| 96 | 	.long	241 # Symbol subsection for globals | |
| 97 | 	.long	.Ltmp13-.Ltmp12 # Subsection size | |
| 98 | .Ltmp12: | |
| 99 | 	.short	.Ltmp15-.Ltmp14 # Record length | |
| 100 | .Ltmp14: | |
| 101 | 	.short	4359 # Record kind: S_CONSTANT | |
| 102 | 	.long	4099 # Type | |
| 103 | 	.byte	0x29, 0x00 # Value | |
| 104 | 	.asciz	"Foo" # Name | |
| 105 | 	.p2align	2 | |
| 106 | .Ltmp15: | |
| 107 | 	.short	.Ltmp17-.Ltmp16 # Record length | |
| 108 | .Ltmp16: | |
| 109 | 	.short	4359 # Record kind: S_CONSTANT | |
| 110 | 	.long	4099 # Type | |
| 111 | 	.byte	0x2a, 0x00 # Value | |
| 112 | 	.asciz	"Bar" # Name | |
| 113 | 	.p2align	2 | |
| 114 | .Ltmp17: | |
| 115 | .Ltmp13: | |
| 116 | 	.p2align	2 | |
| 117 | 	.cv_filechecksums # File index to string table offset subsection | |
| 118 | 	.cv_stringtable # String table | |
| 119 | 	.long	241 | |
| 120 | 	.long	.Ltmp19-.Ltmp18 # Subsection size | |
| 121 | .Ltmp18: | |
| 122 | 	.short	.Ltmp21-.Ltmp20 # Record length | |
| 123 | .Ltmp20: | |
| 124 | 	.short	4428 # Record kind: S_BUILDINFO | |
| 125 | 	.long	4102 # LF_BUILDINFO index | |
| 126 | 	.p2align	2 | |
| 127 | .Ltmp21: | |
| 128 | .Ltmp19: | |
| 129 | 	.p2align	2 | |
| 130 | 	.section	.debug$T,"dr" | |
| 131 | 	.p2align	2 | |
| 132 | 	.long	4 # Debug section magic | |
| 133 | 	# ArgList (0x1000) { | |
| 134 | 	# TypeLeafKind: LF_ARGLIST (0x1201) | |
| 135 | 	# NumArgs: 0 | |
| 136 | 	# Arguments [ | |
| 137 | 	# ] | |
| 138 | 	# } | |
| 139 | 	.byte	0x06, 0x00, 0x01, 0x12 | |
| 140 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 141 | 	# Procedure (0x1001) { | |
| 142 | 	# TypeLeafKind: LF_PROCEDURE (0x1008) | |
| 143 | 	# ReturnType: int (0x74) | |
| 144 | 	# CallingConvention: NearC (0x0) | |
| 145 | 	# FunctionOptions [ (0x0) | |
| 146 | 	# ] | |
| 147 | 	# NumParameters: 0 | |
| 148 | 	# ArgListType: () (0x1000) | |
| 149 | 	# } | |
| 150 | 	.byte	0x0e, 0x00, 0x08, 0x10 | |
| 151 | 	.byte	0x74, 0x00, 0x00, 0x00 | |
| 152 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 153 | 	.byte	0x00, 0x10, 0x00, 0x00 | |
| 154 | 	# FuncId (0x1002) { | |
| 155 | 	# TypeLeafKind: LF_FUNC_ID (0x1601) | |
| 156 | 	# ParentScope: 0x0 | |
| 157 | 	# FunctionType: int () (0x1001) | |
| 158 | 	# Name: main | |
| 159 | 	# } | |
| 160 | 	.byte	0x12, 0x00, 0x01, 0x16 | |
| 161 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 162 | 	.byte	0x01, 0x10, 0x00, 0x00 | |
| 163 | 	.byte	0x6d, 0x61, 0x69, 0x6e | |
| 164 | 	.byte	0x00, 0xf3, 0xf2, 0xf1 | |
| 165 | 	# Modifier (0x1003) { | |
| 166 | 	# TypeLeafKind: LF_MODIFIER (0x1001) | |
| 167 | 	# ModifiedType: int (0x74) | |
| 168 | 	# Modifiers [ (0x1) | |
| 169 | 	# Const (0x1) | |
| 170 | 	# ] | |
| 171 | 	# } | |
| 172 | 	.byte	0x0a, 0x00, 0x01, 0x10 | |
| 173 | 	.byte	0x74, 0x00, 0x00, 0x00 | |
| 174 | 	.byte	0x01, 0x00, 0xf2, 0xf1 | |
| 175 | 	# StringId (0x1004) { | |
| 176 | 	# TypeLeafKind: LF_STRING_ID (0x1605) | |
| 177 | 	# Id: 0x0 | |
| 178 | 	# StringData: C:\src\testing | |
| 179 | 	# } | |
| 180 | 	.byte	0x16, 0x00, 0x05, 0x16 | |
| 181 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 182 | 	.byte	0x43, 0x3a, 0x5c, 0x73 | |
| 183 | 	.byte	0x72, 0x63, 0x5c, 0x74 | |
| 184 | 	.byte	0x65, 0x73, 0x74, 0x69 | |
| 185 | 	.byte	0x6e, 0x67, 0x00, 0xf1 | |
| 186 | 	# StringId (0x1005) { | |
| 187 | 	# TypeLeafKind: LF_STRING_ID (0x1605) | |
| 188 | 	# Id: 0x0 | |
| 189 | 	# StringData: t.cpp | |
| 190 | 	# } | |
| 191 | 	.byte	0x0e, 0x00, 0x05, 0x16 | |
| 192 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 193 | 	.byte	0x74, 0x2e, 0x63, 0x70 | |
| 194 | 	.byte	0x70, 0x00, 0xf2, 0xf1 | |
| 195 | 	# BuildInfo (0x1006) { | |
| 196 | 	# TypeLeafKind: LF_BUILDINFO (0x1603) | |
| 197 | 	# NumArgs: 5 | |
| 198 | 	# Arguments [ | |
| 199 | 	# ArgType: C:\src\testing (0x1004) | |
| 200 | 	# ArgType: 0x0 | |
| 201 | 	# ArgType: t.cpp (0x1005) | |
| 202 | 	# ArgType: 0x0 | |
| 203 | 	# ArgType: 0x0 | |
| 204 | 	# ] | |
| 205 | 	# } | |
| 206 | 	.byte	0x1a, 0x00, 0x03, 0x16 | |
| 207 | 	.byte	0x05, 0x00, 0x04, 0x10 | |
| 208 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 209 | 	.byte	0x00, 0x00, 0x05, 0x10 | |
| 210 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 211 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 212 | 	.byte	0x00, 0x00, 0xf2, 0xf1 | |
| 213 | ||
| 214 | 	.addrsig |
deps/lld/test/COFF/Inputs/pdb-global-constants-b.s created+204| ... | ... | @@ -0,0 +1,204 @@ |
| 1 | 	.text | |
| 2 | 	.def	 @feat.00; | |
| 3 | 	.scl	3; | |
| 4 | 	.type	0; | |
| 5 | 	.endef | |
| 6 | 	.globl	@feat.00 | |
| 7 | .set @feat.00, 0 | |
| 8 | 	.file	"t2.cpp" | |
| 9 | 	.def	 "?foobar@@YAHXZ"; | |
| 10 | 	.scl	2; | |
| 11 | 	.type	32; | |
| 12 | 	.endef | |
| 13 | 	.globl	"?foobar@@YAHXZ" # -- Begin function ?foobar@@YAHXZ | |
| 14 | 	.p2align	4, 0x90 | |
| 15 | "?foobar@@YAHXZ": # @"?foobar@@YAHXZ" | |
| 16 | .Lfunc_begin0: | |
| 17 | 	.cv_func_id 0 | |
| 18 | # %bb.0: # %entry | |
| 19 | 	.cv_file	1 "C:\\src\\testing\\t2.cpp" "C9D7AF07363FDE8EC16D73EC30039C5B" 1 | |
| 20 | 	.cv_loc	0 1 5 0 # t2.cpp:5:0 | |
| 21 | 	movl	$84, %eax | |
| 22 | 	retq | |
| 23 | .Ltmp0: | |
| 24 | .Lfunc_end0: | |
| 25 | # -- End function | |
| 26 | 	.section	.debug$S,"dr" | |
| 27 | 	.p2align	2 | |
| 28 | 	.long	4 # Debug section magic | |
| 29 | 	.long	241 | |
| 30 | 	.long	.Ltmp2-.Ltmp1 # Subsection size | |
| 31 | .Ltmp1: | |
| 32 | 	.short	.Ltmp4-.Ltmp3 # Record length | |
| 33 | .Ltmp3: | |
| 34 | 	.short	4412 # Record kind: S_COMPILE3 | |
| 35 | 	.long	1 # Flags and language | |
| 36 | 	.short	208 # CPUType | |
| 37 | 	.short	9 # Frontend version | |
| 38 | 	.short	0 | |
| 39 | 	.short	0 | |
| 40 | 	.short	0 | |
| 41 | 	.short	9000 # Backend version | |
| 42 | 	.short	0 | |
| 43 | 	.short	0 | |
| 44 | 	.short	0 | |
| 45 | 	.asciz	"clang version 9.0.0 (https://github.com/llvm/llvm-project.git ad522e17b285b1f2667163d52da5abf0968ec650)" # Null-terminated compiler version string | |
| 46 | 	.p2align	2 | |
| 47 | .Ltmp4: | |
| 48 | .Ltmp2: | |
| 49 | 	.p2align	2 | |
| 50 | 	.long	241 # Symbol subsection for foobar | |
| 51 | 	.long	.Ltmp6-.Ltmp5 # Subsection size | |
| 52 | .Ltmp5: | |
| 53 | 	.short	.Ltmp8-.Ltmp7 # Record length | |
| 54 | .Ltmp7: | |
| 55 | 	.short	4423 # Record kind: S_GPROC32_ID | |
| 56 | 	.long	0 # PtrParent | |
| 57 | 	.long	0 # PtrEnd | |
| 58 | 	.long	0 # PtrNext | |
| 59 | 	.long	.Lfunc_end0-"?foobar@@YAHXZ" # Code size | |
| 60 | 	.long	0 # Offset after prologue | |
| 61 | 	.long	0 # Offset before epilogue | |
| 62 | 	.long	4098 # Function type index | |
| 63 | 	.secrel32	"?foobar@@YAHXZ" # Function section relative address | |
| 64 | 	.secidx	"?foobar@@YAHXZ" # Function section index | |
| 65 | 	.byte	0 # Flags | |
| 66 | 	.asciz	"foobar" # Function name | |
| 67 | 	.p2align	2 | |
| 68 | .Ltmp8: | |
| 69 | 	.short	.Ltmp10-.Ltmp9 # Record length | |
| 70 | .Ltmp9: | |
| 71 | 	.short	4114 # Record kind: S_FRAMEPROC | |
| 72 | 	.long	0 # FrameSize | |
| 73 | 	.long	0 # Padding | |
| 74 | 	.long	0 # Offset of padding | |
| 75 | 	.long	0 # Bytes of callee saved registers | |
| 76 | 	.long	0 # Exception handler offset | |
| 77 | 	.short	0 # Exception handler section | |
| 78 | 	.long	0 # Flags (defines frame register) | |
| 79 | 	.p2align	2 | |
| 80 | .Ltmp10: | |
| 81 | 	.short	2 # Record length | |
| 82 | 	.short	4431 # Record kind: S_PROC_ID_END | |
| 83 | .Ltmp6: | |
| 84 | 	.p2align	2 | |
| 85 | 	.cv_linetable	0, "?foobar@@YAHXZ", .Lfunc_end0 | |
| 86 | 	.long	241 # Symbol subsection for globals | |
| 87 | 	.long	.Ltmp12-.Ltmp11 # Subsection size | |
| 88 | .Ltmp11: | |
| 89 | 	.short	.Ltmp14-.Ltmp13 # Record length | |
| 90 | .Ltmp13: | |
| 91 | 	.short	4359 # Record kind: S_CONSTANT | |
| 92 | 	.long	4099 # Type | |
| 93 | 	.byte	0x2a, 0x00 # Value | |
| 94 | 	.asciz	"Foo" # Name | |
| 95 | 	.p2align	2 | |
| 96 | .Ltmp14: | |
| 97 | 	.short	.Ltmp16-.Ltmp15 # Record length | |
| 98 | .Ltmp15: | |
| 99 | 	.short	4359 # Record kind: S_CONSTANT | |
| 100 | 	.long	4099 # Type | |
| 101 | 	.byte	0x2a, 0x00 # Value | |
| 102 | 	.asciz	"Bar" # Name | |
| 103 | 	.p2align	2 | |
| 104 | .Ltmp16: | |
| 105 | .Ltmp12: | |
| 106 | 	.p2align	2 | |
| 107 | 	.cv_filechecksums # File index to string table offset subsection | |
| 108 | 	.cv_stringtable # String table | |
| 109 | 	.long	241 | |
| 110 | 	.long	.Ltmp18-.Ltmp17 # Subsection size | |
| 111 | .Ltmp17: | |
| 112 | 	.short	.Ltmp20-.Ltmp19 # Record length | |
| 113 | .Ltmp19: | |
| 114 | 	.short	4428 # Record kind: S_BUILDINFO | |
| 115 | 	.long	4102 # LF_BUILDINFO index | |
| 116 | 	.p2align	2 | |
| 117 | .Ltmp20: | |
| 118 | .Ltmp18: | |
| 119 | 	.p2align	2 | |
| 120 | 	.section	.debug$T,"dr" | |
| 121 | 	.p2align	2 | |
| 122 | 	.long	4 # Debug section magic | |
| 123 | 	# ArgList (0x1000) { | |
| 124 | 	# TypeLeafKind: LF_ARGLIST (0x1201) | |
| 125 | 	# NumArgs: 0 | |
| 126 | 	# Arguments [ | |
| 127 | 	# ] | |
| 128 | 	# } | |
| 129 | 	.byte	0x06, 0x00, 0x01, 0x12 | |
| 130 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 131 | 	# Procedure (0x1001) { | |
| 132 | 	# TypeLeafKind: LF_PROCEDURE (0x1008) | |
| 133 | 	# ReturnType: int (0x74) | |
| 134 | 	# CallingConvention: NearC (0x0) | |
| 135 | 	# FunctionOptions [ (0x0) | |
| 136 | 	# ] | |
| 137 | 	# NumParameters: 0 | |
| 138 | 	# ArgListType: () (0x1000) | |
| 139 | 	# } | |
| 140 | 	.byte	0x0e, 0x00, 0x08, 0x10 | |
| 141 | 	.byte	0x74, 0x00, 0x00, 0x00 | |
| 142 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 143 | 	.byte	0x00, 0x10, 0x00, 0x00 | |
| 144 | 	# FuncId (0x1002) { | |
| 145 | 	# TypeLeafKind: LF_FUNC_ID (0x1601) | |
| 146 | 	# ParentScope: 0x0 | |
| 147 | 	# FunctionType: int () (0x1001) | |
| 148 | 	# Name: foobar | |
| 149 | 	# } | |
| 150 | 	.byte	0x12, 0x00, 0x01, 0x16 | |
| 151 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 152 | 	.byte	0x01, 0x10, 0x00, 0x00 | |
| 153 | 	.byte	0x66, 0x6f, 0x6f, 0x62 | |
| 154 | 	.byte	0x61, 0x72, 0x00, 0xf1 | |
| 155 | 	# Modifier (0x1003) { | |
| 156 | 	# TypeLeafKind: LF_MODIFIER (0x1001) | |
| 157 | 	# ModifiedType: int (0x74) | |
| 158 | 	# Modifiers [ (0x1) | |
| 159 | 	# Const (0x1) | |
| 160 | 	# ] | |
| 161 | 	# } | |
| 162 | 	.byte	0x0a, 0x00, 0x01, 0x10 | |
| 163 | 	.byte	0x74, 0x00, 0x00, 0x00 | |
| 164 | 	.byte	0x01, 0x00, 0xf2, 0xf1 | |
| 165 | 	# StringId (0x1004) { | |
| 166 | 	# TypeLeafKind: LF_STRING_ID (0x1605) | |
| 167 | 	# Id: 0x0 | |
| 168 | 	# StringData: C:\src\testing | |
| 169 | 	# } | |
| 170 | 	.byte	0x16, 0x00, 0x05, 0x16 | |
| 171 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 172 | 	.byte	0x43, 0x3a, 0x5c, 0x73 | |
| 173 | 	.byte	0x72, 0x63, 0x5c, 0x74 | |
| 174 | 	.byte	0x65, 0x73, 0x74, 0x69 | |
| 175 | 	.byte	0x6e, 0x67, 0x00, 0xf1 | |
| 176 | 	# StringId (0x1005) { | |
| 177 | 	# TypeLeafKind: LF_STRING_ID (0x1605) | |
| 178 | 	# Id: 0x0 | |
| 179 | 	# StringData: t2.cpp | |
| 180 | 	# } | |
| 181 | 	.byte	0x0e, 0x00, 0x05, 0x16 | |
| 182 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 183 | 	.byte	0x74, 0x32, 0x2e, 0x63 | |
| 184 | 	.byte	0x70, 0x70, 0x00, 0xf1 | |
| 185 | 	# BuildInfo (0x1006) { | |
| 186 | 	# TypeLeafKind: LF_BUILDINFO (0x1603) | |
| 187 | 	# NumArgs: 5 | |
| 188 | 	# Arguments [ | |
| 189 | 	# ArgType: C:\src\testing (0x1004) | |
| 190 | 	# ArgType: 0x0 | |
| 191 | 	# ArgType: t2.cpp (0x1005) | |
| 192 | 	# ArgType: 0x0 | |
| 193 | 	# ArgType: 0x0 | |
| 194 | 	# ] | |
| 195 | 	# } | |
| 196 | 	.byte	0x1a, 0x00, 0x03, 0x16 | |
| 197 | 	.byte	0x05, 0x00, 0x04, 0x10 | |
| 198 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 199 | 	.byte	0x00, 0x00, 0x05, 0x10 | |
| 200 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 201 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 202 | 	.byte	0x00, 0x00, 0xf2, 0xf1 | |
| 203 | ||
| 204 | 	.addrsig |
deps/lld/test/COFF/Inputs/pdb-globals.yaml+1-1| ... | ... | @@ -70,6 +70,7 @@ sections: |
| 70 | 70 | Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] |
| 71 | 71 | Alignment: 4 |
| 72 | 72 | SectionData: '' |
| 73 | SizeOfRawData: 4 | |
| 73 | 74 | - Name: .text |
| 74 | 75 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] |
| 75 | 76 | Alignment: 16 |
| ... | ... | @@ -263,7 +264,6 @@ sections: |
| 263 | 264 | - Name: '.debug$T' |
| 264 | 265 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] |
| 265 | 266 | Alignment: 4 |
| 266 | SectionData: 0400000006000112000000000E000810740000000000000000100000160001160000000001100000476C6F62616C46756E6300F10A000210700400000A8000000E0001120200000074000000031000000E0008107400000000000200041000001200011600000000051000006D61696E00F3F2F13200051500008002000000000000000000000000000048656C6C6F506F696E74002E3F415548656C6C6F506F696E74404000F2F1260003120D15030074000000000058000D15030074000000040059000D1503007400000008005A0032000515030000020810000000000000000000000C0048656C6C6F506F696E74002E3F415548656C6C6F506F696E74404000F2F13E00051600000000643A5C7372635C6C6C766D2D6D6F6E6F5C6C6C645C746573745C636F66665C696E707574735C7064622D676C6F62616C732E63707000F2F10E000616091000000A100000060000000A000210071000000A8000001A00091003000000071000000C1000000B000000001000000000000016000216071000000D10000048656C6C6F506F696E7400F11600011600000000011000004C6F63616C46756E6300F2F10A000110740000000100F2F10A000210101000000A800000 | |
| 267 | 267 | Types: |
| 268 | 268 | - Kind: LF_ARGLIST |
| 269 | 269 | ArgList: |
deps/lld/test/COFF/Inputs/pdb-type-server-invalid-path.yaml created+121| ... | ... | @@ -0,0 +1,121 @@ |
| 1 | --- !COFF | |
| 2 | header: | |
| 3 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 4 | Characteristics: [ ] | |
| 5 | sections: | |
| 6 | - Name: '.debug$S' | |
| 7 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] | |
| 8 | Alignment: 1 | |
| 9 | Subsections: | |
| 10 | - !Symbols | |
| 11 | Records: | |
| 12 | - Kind: S_GPROC32_ID | |
| 13 | ProcSym: | |
| 14 | CodeSize: 3 | |
| 15 | DbgStart: 0 | |
| 16 | DbgEnd: 2 | |
| 17 | FunctionType: 4199 | |
| 18 | Flags: [ ] | |
| 19 | DisplayName: main | |
| 20 | - Kind: S_FRAMEPROC | |
| 21 | FrameProcSym: | |
| 22 | TotalFrameBytes: 0 | |
| 23 | PaddingFrameBytes: 0 | |
| 24 | OffsetToPadding: 0 | |
| 25 | BytesOfCalleeSavedRegisters: 0 | |
| 26 | OffsetOfExceptionHandler: 0 | |
| 27 | SectionIdOfExceptionHandler: 0 | |
| 28 | Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] | |
| 29 | - Kind: S_PROC_ID_END | |
| 30 | ScopeEndSym: | |
| 31 | - !Lines | |
| 32 | CodeSize: 3 | |
| 33 | Flags: [ ] | |
| 34 | RelocOffset: 0 | |
| 35 | RelocSegment: 0 | |
| 36 | Blocks: | |
| 37 | - FileName: 'c:\src\llvm-project\build\t.c' | |
| 38 | Lines: | |
| 39 | - Offset: 0 | |
| 40 | LineStart: 1 | |
| 41 | IsStatement: true | |
| 42 | EndDelta: 0 | |
| 43 | Columns: | |
| 44 | - !FileChecksums | |
| 45 | Checksums: | |
| 46 | - FileName: 'c:\src\llvm-project\build\t.c' | |
| 47 | Kind: MD5 | |
| 48 | Checksum: 270A878DCC1B845655B162F56C4F5020 | |
| 49 | - !StringTable | |
| 50 | Strings: | |
| 51 | - 'c:\src\llvm-project\build\t.c' | |
| 52 | Relocations: | |
| 53 | - VirtualAddress: 44 | |
| 54 | SymbolName: main | |
| 55 | Type: IMAGE_REL_AMD64_SECREL | |
| 56 | - VirtualAddress: 48 | |
| 57 | SymbolName: main | |
| 58 | Type: IMAGE_REL_AMD64_SECTION | |
| 59 | - VirtualAddress: 100 | |
| 60 | SymbolName: main | |
| 61 | Type: IMAGE_REL_AMD64_SECREL | |
| 62 | - VirtualAddress: 104 | |
| 63 | SymbolName: main | |
| 64 | Type: IMAGE_REL_AMD64_SECTION | |
| 65 | - Name: '.debug$T' | |
| 66 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] | |
| 67 | Alignment: 1 | |
| 68 | Types: | |
| 69 | - Kind: LF_TYPESERVER2 | |
| 70 | TypeServer2: | |
| 71 | Guid: '{8DABD2A0-28FF-CB43-9BAF-175B77B76414}' | |
| 72 | Age: 1 | |
| 73 | Name: 'c:\some_invalid_path_AABB98765\pdb-diff-cl.pdb' | |
| 74 | - Name: '.text$mn' | |
| 75 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] | |
| 76 | Alignment: 16 | |
| 77 | SectionData: 33C0C3 | |
| 78 | symbols: | |
| 79 | - Name: '.debug$S' | |
| 80 | Value: 0 | |
| 81 | SectionNumber: 1 | |
| 82 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 83 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 84 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 85 | SectionDefinition: | |
| 86 | Length: 328 | |
| 87 | NumberOfRelocations: 4 | |
| 88 | NumberOfLinenumbers: 0 | |
| 89 | CheckSum: 0 | |
| 90 | Number: 0 | |
| 91 | - Name: '.debug$T' | |
| 92 | Value: 0 | |
| 93 | SectionNumber: 2 | |
| 94 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 95 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 96 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 97 | SectionDefinition: | |
| 98 | Length: 564 | |
| 99 | NumberOfRelocations: 0 | |
| 100 | NumberOfLinenumbers: 0 | |
| 101 | CheckSum: 0 | |
| 102 | Number: 0 | |
| 103 | - Name: '.text$mn' | |
| 104 | Value: 0 | |
| 105 | SectionNumber: 3 | |
| 106 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 107 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 108 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 109 | SectionDefinition: | |
| 110 | Length: 3 | |
| 111 | NumberOfRelocations: 0 | |
| 112 | NumberOfLinenumbers: 0 | |
| 113 | CheckSum: 4021952397 | |
| 114 | Number: 0 | |
| 115 | - Name: main | |
| 116 | Value: 0 | |
| 117 | SectionNumber: 3 | |
| 118 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 119 | ComplexType: IMAGE_SYM_DTYPE_FUNCTION | |
| 120 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 121 | ... |
deps/lld/test/COFF/Inputs/pdb_comdat_bar.yaml+1| ... | ... | @@ -190,6 +190,7 @@ sections: |
| 190 | 190 | Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] |
| 191 | 191 | Alignment: 4 |
| 192 | 192 | SectionData: '' |
| 193 | SizeOfRawData: 4 | |
| 193 | 194 | - Name: '.text$mn' |
| 194 | 195 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] |
| 195 | 196 | Alignment: 16 |
deps/lld/test/COFF/Inputs/thinlto-empty.ll created+2| ... | ... | @@ -0,0 +1,2 @@ |
| 1 | target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" | |
| 2 | target triple = "x86_64-pc-windows-msvc19.0.24215" |
deps/lld/test/COFF/Inputs/thinlto.ll created+6| ... | ... | @@ -0,0 +1,6 @@ |
| 1 | target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" | |
| 2 | target triple = "x86_64-pc-windows-msvc19.0.24215" | |
| 3 | ||
| 4 | define void @g() { | |
| 5 | ret void | |
| 6 | } |
deps/lld/test/COFF/Inputs/tlssup.s created+10| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | .section .tls,"dw" | |
| 2 | .byte 0xaa | |
| 3 | ||
| 4 | .section .tls$ZZZ,"dw" | |
| 5 | .byte 0xff | |
| 6 | ||
| 7 | .globl _tls_index | |
| 8 | .data | |
| 9 | _tls_index: | |
| 10 | .int 0 |
deps/lld/test/COFF/Inputs/undefined-symbol-lto-a.ll created+82| ... | ... | @@ -0,0 +1,82 @@ |
| 1 | ; ModuleID = 't.obj' | |
| 2 | source_filename = "t.cpp" | |
| 3 | target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" | |
| 4 | target triple = "x86_64-pc-windows-msvc19.21.27702" | |
| 5 | ||
| 6 | %struct.Init = type { %struct.S } | |
| 7 | %struct.S = type { i32 (...)** } | |
| 8 | %rtti.CompleteObjectLocator = type { i32, i32, i32, i32, i32, i32 } | |
| 9 | %rtti.TypeDescriptor7 = type { i8**, i8*, [8 x i8] } | |
| 10 | %rtti.ClassHierarchyDescriptor = type { i32, i32, i32, i32 } | |
| 11 | %rtti.BaseClassDescriptor = type { i32, i32, i32, i32, i32, i32, i32 } | |
| 12 | ||
| 13 | $"??_SS@@6B@" = comdat largest | |
| 14 | ||
| 15 | $"??_R4S@@6B@" = comdat any | |
| 16 | ||
| 17 | $"??_R0?AUS@@@8" = comdat any | |
| 18 | ||
| 19 | $"??_R3S@@8" = comdat any | |
| 20 | ||
| 21 | $"??_R2S@@8" = comdat any | |
| 22 | ||
| 23 | $"??_R1A@?0A@EA@S@@8" = comdat any | |
| 24 | ||
| 25 | @"?d@@3UInit@@A" = dso_local local_unnamed_addr global %struct.Init zeroinitializer, align 8 | |
| 26 | @anon.bcb2691509de99310dddb690fcdb4cdc.0 = private unnamed_addr constant { [2 x i8*] } { [2 x i8*] [i8* bitcast (%rtti.CompleteObjectLocator* @"??_R4S@@6B@" to i8*), i8* bitcast (void (%struct.S*)* @"?foo@S@@UEAAXXZ" to i8*)] }, comdat($"??_SS@@6B@"), !type !0 | |
| 27 | @"??_R4S@@6B@" = linkonce_odr constant %rtti.CompleteObjectLocator { i32 1, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor7* @"??_R0?AUS@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.ClassHierarchyDescriptor* @"??_R3S@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.CompleteObjectLocator* @"??_R4S@@6B@" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat | |
| 28 | @"??_7type_info@@6B@" = external constant i8* | |
| 29 | @"??_R0?AUS@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"??_7type_info@@6B@", i8* null, [8 x i8] c".?AUS@@\00" }, comdat | |
| 30 | @__ImageBase = external dso_local constant i8 | |
| 31 | @"??_R3S@@8" = linkonce_odr constant %rtti.ClassHierarchyDescriptor { i32 0, i32 0, i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint ([2 x i32]* @"??_R2S@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat | |
| 32 | @"??_R2S@@8" = linkonce_odr constant [2 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.BaseClassDescriptor* @"??_R1A@?0A@EA@S@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0], comdat | |
| 33 | @"??_R1A@?0A@EA@S@@8" = linkonce_odr constant %rtti.BaseClassDescriptor { i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor7* @"??_R0?AUS@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 0, i32 -1, i32 0, i32 64, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.ClassHierarchyDescriptor* @"??_R3S@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat | |
| 34 | @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_t.cpp, i8* null }] | |
| 35 | ||
| 36 | @"??_SS@@6B@" = unnamed_addr alias i8*, getelementptr inbounds ({ [2 x i8*] }, { [2 x i8*] }* @anon.bcb2691509de99310dddb690fcdb4cdc.0, i32 0, i32 0, i32 1) | |
| 37 | ||
| 38 | declare dso_local void @"?undefined_ref@@YAXXZ"() local_unnamed_addr #0 | |
| 39 | ||
| 40 | declare dllimport void @"?foo@S@@UEAAXXZ"(%struct.S*) unnamed_addr #0 | |
| 41 | ||
| 42 | ; Function Attrs: nounwind sspstrong uwtable | |
| 43 | define internal void @_GLOBAL__sub_I_t.cpp() #1 { | |
| 44 | entry: | |
| 45 | store i32 (...)** bitcast (i8** @"??_SS@@6B@" to i32 (...)**), i32 (...)*** getelementptr inbounds (%struct.Init, %struct.Init* @"?d@@3UInit@@A", i64 0, i32 0, i32 0), align 8 | |
| 46 | tail call void @"?undefined_ref@@YAXXZ"() #2 | |
| 47 | ret void | |
| 48 | } | |
| 49 | ||
| 50 | attributes #0 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } | |
| 51 | attributes #1 = { nounwind sspstrong uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } | |
| 52 | attributes #2 = { nounwind } | |
| 53 | ||
| 54 | !llvm.linker.options = !{!1, !2} | |
| 55 | !llvm.module.flags = !{!3, !4, !5, !6} | |
| 56 | !llvm.ident = !{!7} | |
| 57 | ||
| 58 | !0 = !{i64 8, !"?AUS@@"} | |
| 59 | !1 = !{!"/DEFAULTLIB:libcmt.lib"} | |
| 60 | !2 = !{!"/DEFAULTLIB:oldnames.lib"} | |
| 61 | !3 = !{i32 1, !"wchar_size", i32 2} | |
| 62 | !4 = !{i32 7, !"PIC Level", i32 2} | |
| 63 | !5 = !{i32 1, !"ThinLTO", i32 0} | |
| 64 | !6 = !{i32 1, !"EnableSplitLTOUnit", i32 0} | |
| 65 | !7 = !{!"clang version 9.0.0 (git@github.com:llvm/llvm-project.git 1a285c27fdf6407ceed3398e015d00559f5f533d)"} | |
| 66 | ||
| 67 | ^0 = module: (path: "t.obj", hash: (0, 0, 0, 0, 0)) | |
| 68 | ^1 = gv: (name: "__ImageBase") ; guid = 434928772013489304 | |
| 69 | ^2 = gv: (name: "??_R2S@@8", summaries: (variable: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^1, ^6)))) ; guid = 2160898732728284029 | |
| 70 | ^3 = gv: (name: "llvm.global_ctors", summaries: (variable: (module: ^0, flags: (linkage: appending, notEligibleToImport: 1, live: 1, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^14)))) ; guid = 2412314959268824392 | |
| 71 | ^4 = gv: (name: "?foo@S@@UEAAXXZ") ; guid = 6578172636330484861 | |
| 72 | ^5 = gv: (name: "??_SS@@6B@", summaries: (alias: (module: ^0, flags: (linkage: external, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), aliasee: ^10))) ; guid = 8774897714842691026 | |
| 73 | ^6 = gv: (name: "??_R1A@?0A@EA@S@@8", summaries: (variable: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^11, ^1, ^8)))) ; guid = 9397802696236423453 | |
| 74 | ^7 = gv: (name: "?undefined_ref@@YAXXZ") ; guid = 9774674600202276560 | |
| 75 | ^8 = gv: (name: "??_R3S@@8", summaries: (variable: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^1, ^2)))) ; guid = 10685958509605791599 | |
| 76 | ^9 = gv: (name: "??_7type_info@@6B@") ; guid = 10826752452437539368 | |
| 77 | ^10 = gv: (name: "anon.bcb2691509de99310dddb690fcdb4cdc.0", summaries: (variable: (module: ^0, flags: (linkage: private, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), vTableFuncs: ((virtFunc: ^4, offset: 8)), refs: (^13, ^4)))) ; guid = 11510395461204283992 | |
| 78 | ^11 = gv: (name: "??_R0?AUS@@@8", summaries: (variable: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^9)))) ; guid = 12346607659584231960 | |
| 79 | ^12 = gv: (name: "?d@@3UInit@@A", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 1)))) ; guid = 14563354643524156382 | |
| 80 | ^13 = gv: (name: "??_R4S@@6B@", summaries: (variable: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^13, ^11, ^1, ^8)))) ; guid = 14703528065171087394 | |
| 81 | ^14 = gv: (name: "_GLOBAL__sub_I_t.cpp", summaries: (function: (module: ^0, flags: (linkage: internal, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 3, calls: ((callee: ^7)), refs: (^12, ^5)))) ; guid = 15085897428757412588 | |
| 82 | ^15 = typeidCompatibleVTable: (name: "?AUS@@", summary: ((offset: 8, ^10))) ; guid = 13986515119763165370 |
deps/lld/test/COFF/Inputs/undefined-symbol-lto-b.ll created+29| ... | ... | @@ -0,0 +1,29 @@ |
| 1 | ; ModuleID = 'b.obj' | |
| 2 | source_filename = "b.cpp" | |
| 3 | target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" | |
| 4 | target triple = "x86_64-pc-windows-msvc19.21.27702" | |
| 5 | ||
| 6 | %struct.S = type { i32 (...)** } | |
| 7 | ||
| 8 | ; Function Attrs: norecurse nounwind readnone sspstrong uwtable | |
| 9 | define dso_local void @"?foo@S@@UEAAXXZ"(%struct.S* nocapture %this) unnamed_addr #0 align 2 { | |
| 10 | entry: | |
| 11 | ret void | |
| 12 | } | |
| 13 | ||
| 14 | attributes #0 = { norecurse nounwind readnone sspstrong uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } | |
| 15 | ||
| 16 | !llvm.linker.options = !{!0, !1} | |
| 17 | !llvm.module.flags = !{!2, !3, !4, !5} | |
| 18 | !llvm.ident = !{!6} | |
| 19 | ||
| 20 | !0 = !{!"/DEFAULTLIB:libcmt.lib"} | |
| 21 | !1 = !{!"/DEFAULTLIB:oldnames.lib"} | |
| 22 | !2 = !{i32 1, !"wchar_size", i32 2} | |
| 23 | !3 = !{i32 7, !"PIC Level", i32 2} | |
| 24 | !4 = !{i32 1, !"ThinLTO", i32 0} | |
| 25 | !5 = !{i32 1, !"EnableSplitLTOUnit", i32 0} | |
| 26 | !6 = !{!"clang version 9.0.0 (git@github.com:llvm/llvm-project.git 1a285c27fdf6407ceed3398e015d00559f5f533d)"} | |
| 27 | ||
| 28 | ^0 = module: (path: "b.obj", hash: (0, 0, 0, 0, 0)) | |
| 29 | ^1 = gv: (name: "?foo@S@@UEAAXXZ", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 1, funcFlags: (readNone: 1, readOnly: 0, noRecurse: 1, returnDoesNotAlias: 0, noInline: 0)))) ; guid = 6578172636330484861 |
deps/lld/test/COFF/allow-unknown-debug-info.test created+26| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | # RUN: yaml2obj %s > %t.obj | |
| 2 | # RUN: lld-link -safeseh:no /dll /noentry /debug %t.obj 2>&1 | FileCheck %s | |
| 3 | ||
| 4 | # CHECK: ignoring section .debug$S with unrecognized magic 0x1 | |
| 5 | ||
| 6 | --- !COFF | |
| 7 | header: | |
| 8 | Machine: IMAGE_FILE_MACHINE_I386 | |
| 9 | Characteristics: [] | |
| 10 | sections: | |
| 11 | - Name: '.debug$S' | |
| 12 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] | |
| 13 | SectionData: 01000000 | |
| 14 | symbols: | |
| 15 | - Name: '.debug$S' | |
| 16 | Value: 0 | |
| 17 | SectionNumber: 1 | |
| 18 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 19 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 20 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 21 | SectionDefinition: | |
| 22 | Length: 4 | |
| 23 | NumberOfRelocations: 0 | |
| 24 | NumberOfLinenumbers: 0 | |
| 25 | CheckSum: 0 | |
| 26 | Number: 0 |
deps/lld/test/COFF/arm64-delayimport.yaml+27-26| ... | ... | @@ -3,35 +3,36 @@ |
| 3 | 3 | # RUN: yaml2obj < %s > %t.obj |
| 4 | 4 | # RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj %p/Inputs/library-arm64.lib /alternatename:__delayLoadHelper2=main /delayload:library.dll |
| 5 | 5 | # RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix DISASM |
| 6 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s -check-prefix IMPORTS | |
| 6 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck %s -check-prefix IMPORTS | |
| 7 | 7 | |
| 8 | 8 | # DISASM: 140001014: 11 00 00 d0 adrp x17, #8192 |
| 9 | 9 | # DISASM: 140001018: 31 22 00 91 add x17, x17, #8 |
| 10 | # DISASM: 14000101c: fd 7b b3 a9 stp x29, x30, [sp, #-208]! | |
| 11 | # DISASM: 140001020: fd 03 00 91 mov x29, sp | |
| 12 | # DISASM: 140001024: e0 07 01 a9 stp x0, x1, [sp, #16] | |
| 13 | # DISASM: 140001028: e2 0f 02 a9 stp x2, x3, [sp, #32] | |
| 14 | # DISASM: 14000102c: e4 17 03 a9 stp x4, x5, [sp, #48] | |
| 15 | # DISASM: 140001030: e6 1f 04 a9 stp x6, x7, [sp, #64] | |
| 16 | # DISASM: 140001034: e0 87 02 ad stp q0, q1, [sp, #80] | |
| 17 | # DISASM: 140001038: e2 8f 03 ad stp q2, q3, [sp, #112] | |
| 18 | # DISASM: 14000103c: e4 97 04 ad stp q4, q5, [sp, #144] | |
| 19 | # DISASM: 140001040: e6 9f 05 ad stp q6, q7, [sp, #176] | |
| 20 | # DISASM: 140001044: e1 03 11 aa mov x1, x17 | |
| 21 | # DISASM: 140001048: 00 00 00 b0 adrp x0, #4096 | |
| 22 | # DISASM: 14000104c: 00 00 00 91 add x0, x0, #0 | |
| 23 | # DISASM: 140001050: ec ff ff 97 bl #-80 <.text> | |
| 24 | # DISASM: 140001054: f0 03 00 aa mov x16, x0 | |
| 25 | # DISASM: 140001058: e6 9f 45 ad ldp q6, q7, [sp, #176] | |
| 26 | # DISASM: 14000105c: e4 97 44 ad ldp q4, q5, [sp, #144] | |
| 27 | # DISASM: 140001060: e2 8f 43 ad ldp q2, q3, [sp, #112] | |
| 28 | # DISASM: 140001064: e0 87 42 ad ldp q0, q1, [sp, #80] | |
| 29 | # DISASM: 140001068: e6 1f 44 a9 ldp x6, x7, [sp, #64] | |
| 30 | # DISASM: 14000106c: e4 17 43 a9 ldp x4, x5, [sp, #48] | |
| 31 | # DISASM: 140001070: e2 0f 42 a9 ldp x2, x3, [sp, #32] | |
| 32 | # DISASM: 140001074: e0 07 41 a9 ldp x0, x1, [sp, #16] | |
| 33 | # DISASM: 140001078: fd 7b cd a8 ldp x29, x30, [sp], #208 | |
| 34 | # DISASM: 14000107c: 00 02 1f d6 br x16 | |
| 10 | # DISASM: 14000101c: 01 00 00 14 b #4 <.text+0x20> | |
| 11 | # DISASM: 140001020: fd 7b b3 a9 stp x29, x30, [sp, #-208]! | |
| 12 | # DISASM: 140001024: fd 03 00 91 mov x29, sp | |
| 13 | # DISASM: 140001028: e0 07 01 a9 stp x0, x1, [sp, #16] | |
| 14 | # DISASM: 14000102c: e2 0f 02 a9 stp x2, x3, [sp, #32] | |
| 15 | # DISASM: 140001030: e4 17 03 a9 stp x4, x5, [sp, #48] | |
| 16 | # DISASM: 140001034: e6 1f 04 a9 stp x6, x7, [sp, #64] | |
| 17 | # DISASM: 140001038: e0 87 02 ad stp q0, q1, [sp, #80] | |
| 18 | # DISASM: 14000103c: e2 8f 03 ad stp q2, q3, [sp, #112] | |
| 19 | # DISASM: 140001040: e4 97 04 ad stp q4, q5, [sp, #144] | |
| 20 | # DISASM: 140001044: e6 9f 05 ad stp q6, q7, [sp, #176] | |
| 21 | # DISASM: 140001048: e1 03 11 aa mov x1, x17 | |
| 22 | # DISASM: 14000104c: 00 00 00 b0 adrp x0, #4096 | |
| 23 | # DISASM: 140001050: 00 00 00 91 add x0, x0, #0 | |
| 24 | # DISASM: 140001054: eb ff ff 97 bl #-84 <.text> | |
| 25 | # DISASM: 140001058: f0 03 00 aa mov x16, x0 | |
| 26 | # DISASM: 14000105c: e6 9f 45 ad ldp q6, q7, [sp, #176] | |
| 27 | # DISASM: 140001060: e4 97 44 ad ldp q4, q5, [sp, #144] | |
| 28 | # DISASM: 140001064: e2 8f 43 ad ldp q2, q3, [sp, #112] | |
| 29 | # DISASM: 140001068: e0 87 42 ad ldp q0, q1, [sp, #80] | |
| 30 | # DISASM: 14000106c: e6 1f 44 a9 ldp x6, x7, [sp, #64] | |
| 31 | # DISASM: 140001070: e4 17 43 a9 ldp x4, x5, [sp, #48] | |
| 32 | # DISASM: 140001074: e2 0f 42 a9 ldp x2, x3, [sp, #32] | |
| 33 | # DISASM: 140001078: e0 07 41 a9 ldp x0, x1, [sp, #16] | |
| 34 | # DISASM: 14000107c: fd 7b cd a8 ldp x29, x30, [sp], #208 | |
| 35 | # DISASM: 140001080: 00 02 1f d6 br x16 | |
| 35 | 36 | |
| 36 | 37 | # IMPORTS: Format: COFF-ARM64 |
| 37 | 38 | # IMPORTS: Arch: aarch64 |
deps/lld/test/COFF/arm64-import2.test+3-1| ... | ... | @@ -4,14 +4,16 @@ |
| 4 | 4 | # RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE |
| 5 | 5 | # RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj %p/Inputs/library-arm64.lib %p/Inputs/library2-arm64.lib |
| 6 | 6 | # RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER |
| 7 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s -check-prefix IMPORTS | |
| 7 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck %s -check-prefix IMPORTS | |
| 8 | 8 | |
| 9 | 9 | # BEFORE: Disassembly of section .text: |
| 10 | # BEFORE-EMPTY: | |
| 10 | 11 | # BEFORE: 0: 00 00 00 94 bl #0 |
| 11 | 12 | # BEFORE: 4: 00 00 00 94 bl #0 |
| 12 | 13 | # BEFORE: 8: c0 03 5f d6 ret |
| 13 | 14 | |
| 14 | 15 | # AFTER: Disassembly of section .text: |
| 16 | # AFTER-EMPTY: | |
| 15 | 17 | # AFTER: 140001000: 03 00 00 94 bl #12 |
| 16 | 18 | # AFTER: 140001004: 05 00 00 94 bl #20 |
| 17 | 19 | # AFTER: 140001008: c0 03 5f d6 ret |
deps/lld/test/COFF/arm64-magic.yaml+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | 2 | # RUN: lld-link /out:%t.exe /entry:mainCRTStartup /subsystem:console %t.obj |
| 3 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s | |
| 3 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck %s | |
| 4 | 4 | |
| 5 | 5 | # CHECK: Format: COFF-ARM64 |
| 6 | 6 | # CHECK: Arch: aarch64 |
deps/lld/test/COFF/arm64-relocs-imports.test+14-7| ... | ... | @@ -6,6 +6,7 @@ |
| 6 | 6 | # RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER |
| 7 | 7 | |
| 8 | 8 | # BEFORE: Disassembly of section .text: |
| 9 | # BEFORE-EMPTY: | |
| 9 | 10 | # BEFORE: 0: fe 0f 1f f8 str x30, [sp, #-16]! |
| 10 | 11 | # BEFORE: 4: 00 00 00 90 adrp x0, #0 |
| 11 | 12 | # BEFORE: 8: 00 08 00 91 add x0, x0, #2 |
| ... | ... | @@ -45,12 +46,14 @@ |
| 45 | 46 | # BEFORE: 90: 20 1a 09 30 adr x0, #74565 |
| 46 | 47 | # BEFORE: 94: 01 00 00 54 b.ne #0 |
| 47 | 48 | # BEFORE: 98: 00 00 00 36 tbz w0, #0, #0 |
| 49 | # BEFORE: 9c: 01 00 00 00 udf #1 | |
| 48 | 50 | |
| 49 | 51 | # AFTER: Disassembly of section .text: |
| 52 | # AFTER-EMPTY: | |
| 50 | 53 | # AFTER: 140001000: fe 0f 1f f8 str x30, [sp, #-16]! |
| 51 | 54 | # AFTER: 140001004: 00 00 00 b0 adrp x0, #4096 |
| 52 | 55 | # AFTER: 140001008: 00 18 00 91 add x0, x0, #6 |
| 53 | # AFTER: 14000100c: 24 00 00 94 bl #144 | |
| 56 | # AFTER: 14000100c: 25 00 00 94 bl #148 | |
| 54 | 57 | # AFTER: 140001010: 00 21 40 39 ldrb w0, [x8, #8] |
| 55 | 58 | # AFTER: 140001014: 00 11 40 79 ldrh w0, [x8, #8] |
| 56 | 59 | # AFTER: 140001018: 00 09 40 b9 ldr w0, [x8, #8] |
| ... | ... | @@ -84,11 +87,12 @@ |
| 84 | 87 | # AFTER: 140001088: 00 c4 41 f9 ldr x0, [x0, #904] |
| 85 | 88 | # AFTER: 14000108c: 03 00 00 00 udf #3 |
| 86 | 89 | # AFTER: 140001090: e0 95 09 30 adr x0, #78525 |
| 87 | # AFTER: 140001094: 41 00 00 54 b.ne #8 | |
| 88 | # AFTER: 140001098: 20 00 00 36 tbz w0, #0, #4 | |
| 89 | # AFTER: 14000109c: 10 00 00 b0 adrp x16, #4096 | |
| 90 | # AFTER: 1400010a0: 10 2a 40 f9 ldr x16, [x16, #80] | |
| 91 | # AFTER: 1400010a4: 00 02 1f d6 br x16 | |
| 90 | # AFTER: 140001094: 61 00 00 54 b.ne #12 | |
| 91 | # AFTER: 140001098: 40 00 00 36 tbz w0, #0, #8 | |
| 92 | # AFTER: 14000109c: 61 ff ff ff <unknown> | |
| 93 | # AFTER: 1400010a0: 10 00 00 b0 adrp x16, #4096 | |
| 94 | # AFTER: 1400010a4: 10 2a 40 f9 ldr x16, [x16, #80] | |
| 95 | # AFTER: 1400010a8: 00 02 1f d6 br x16 | |
| 92 | 96 | |
| 93 | 97 | --- !COFF |
| 94 | 98 | header: |
| ... | ... | @@ -98,7 +102,7 @@ sections: |
| 98 | 102 | - Name: .text |
| 99 | 103 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] |
| 100 | 104 | Alignment: 4 |
| 101 | SectionData: FE0F1FF80000009000080091000000940001403900014079000140B9000140F90001003900010079000100B9000100F90001403D0001407D000140BD000140FD0001C03D0001003D0001007D000100BD000100FD0001803D000540F9201A01B000FC4FF9E0031F2AFE0741F8C0035FD6080000000000000001000000010000000000009100004091000040f901000000201a09300100005400000036 | |
| 105 | SectionData: FE0F1FF80000009000080091000000940001403900014079000140B9000140F90001003900010079000100B9000100F90001403D0001407D000140BD000140FD0001C03D0001003D0001007D000100BD000100FD0001803D000540F9201A01B000FC4FF9E0031F2AFE0741F8C0035FD6080000000000000001000000010000000000009100004091000040f901000000201a0930010000540000003601000000 | |
| 102 | 106 | Relocations: |
| 103 | 107 | - VirtualAddress: 4 |
| 104 | 108 | SymbolName: .Lstr |
| ... | ... | @@ -202,6 +206,9 @@ sections: |
| 202 | 206 | - VirtualAddress: 152 |
| 203 | 207 | SymbolName: function |
| 204 | 208 | Type: IMAGE_REL_ARM64_BRANCH14 |
| 209 | - VirtualAddress: 156 | |
| 210 | SymbolName: main | |
| 211 | Type: IMAGE_REL_ARM64_REL32 | |
| 205 | 212 | - Name: .data |
| 206 | 213 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] |
| 207 | 214 | Alignment: 4 |
deps/lld/test/COFF/armnt-blx23t.test+2| ... | ... | @@ -6,6 +6,7 @@ |
| 6 | 6 | # RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER |
| 7 | 7 | |
| 8 | 8 | # BEFORE: Disassembly of section .text: |
| 9 | # BEFORE-EMPTY: | |
| 9 | 10 | # BEFORE: 0: 70 47 bx lr |
| 10 | 11 | # BEFORE: 2: 00 bf nop |
| 11 | 12 | # BEFORE: 4: 2d e9 00 48 push.w {r11, lr} |
| ... | ... | @@ -16,6 +17,7 @@ |
| 16 | 17 | # BEFORE: 12: bd e8 00 88 pop.w {r11, pc} |
| 17 | 18 | |
| 18 | 19 | # AFTER: Disassembly of section .text: |
| 20 | # AFTER-EMPTY: | |
| 19 | 21 | # AFTER: 1000: 70 47 bx lr |
| 20 | 22 | # AFTER: 1002: 00 bf nop |
| 21 | 23 | # AFTER: 1004: 2d e9 00 48 push.w {r11, lr} |
deps/lld/test/COFF/armnt-branch24t.test+2| ... | ... | @@ -6,12 +6,14 @@ |
| 6 | 6 | # RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER |
| 7 | 7 | |
| 8 | 8 | # BEFORE: Disassembly of section .text: |
| 9 | # BEFORE-EMPTY: | |
| 9 | 10 | # BEFORE: 0: 70 47 bx lr |
| 10 | 11 | # BEFORE: 2: 00 bf nop |
| 11 | 12 | # BEFORE: 4: 20 20 movs r0, #32 |
| 12 | 13 | # BEFORE: 6: 00 f0 00 b8 b.w #0 |
| 13 | 14 | |
| 14 | 15 | # AFTER: Disassembly of section .text: |
| 16 | # AFTER-EMPTY: | |
| 15 | 17 | # AFTER: .text: |
| 16 | 18 | # AFTER: 1000: 70 47 bx lr |
| 17 | 19 | # AFTER: 1002: 00 bf nop |
deps/lld/test/COFF/armnt-entry-point.test+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | # RUN: yaml2obj < %p/Inputs/armnt-executable.obj.yaml > %t.obj |
| 2 | 2 | # RUN: lld-link /out:%t.exe /entry:mainCRTStartup /subsystem:console %t.obj |
| 3 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s | |
| 3 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck %s | |
| 4 | 4 | |
| 5 | 5 | CHECK: AddressOfEntryPoint: 0x1001 |
deps/lld/test/COFF/armnt-imports.test+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | 2 | # RUN: lld-link /out:%t.exe /subsystem:console %t.obj \ |
| 3 | 3 | # RUN: /entry:mainCRTStartup %p/Inputs/library.lib |
| 4 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s | |
| 4 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: Import { |
| 7 | 7 | # CHECK: Name: library.dll |
deps/lld/test/COFF/armnt-mov32t-exec.test+2| ... | ... | @@ -6,6 +6,7 @@ |
| 6 | 6 | # RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER |
| 7 | 7 | |
| 8 | 8 | # BEFORE: Disassembly of section .text: |
| 9 | # BEFORE-EMPTY: | |
| 9 | 10 | # BEFORE: 0: 70 47 bx lr |
| 10 | 11 | # BEFORE: 2: 00 bf nop |
| 11 | 12 | # BEFORE: 4: 40 f2 00 00 movw r0, #0 |
| ... | ... | @@ -13,6 +14,7 @@ |
| 13 | 14 | # BEFORE: c: 70 47 bx lr |
| 14 | 15 | |
| 15 | 16 | # AFTER: Disassembly of section .text: |
| 17 | # AFTER-EMPTY: | |
| 16 | 18 | # AFTER: 1000: 70 47 bx lr |
| 17 | 19 | # AFTER: 1002: 00 bf nop |
| 18 | 20 | # AFTER: 1004: 41 f2 01 00 movw r0, #4097 |
deps/lld/test/COFF/armnt-movt32t.test+2| ... | ... | @@ -6,11 +6,13 @@ |
| 6 | 6 | # RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER |
| 7 | 7 | |
| 8 | 8 | # BEFORE: Disassembly of section .text: |
| 9 | # BEFORE-EMPTY: | |
| 9 | 10 | # BEFORE: 0: 40 f2 00 00 movw r0, #0 |
| 10 | 11 | # BEFORE: 4: c0 f2 00 00 movt r0, #0 |
| 11 | 12 | # BEFORE: 8: 70 47 bx lr |
| 12 | 13 | |
| 13 | 14 | # AFTER: Disassembly of section .text: |
| 15 | # AFTER-EMPTY: | |
| 14 | 16 | # AFTER: 0: 42 f2 00 00 movw r0, #8192 |
| 15 | 17 | # AFTER: 4: c0 f2 40 00 movt r0, #64 |
| 16 | 18 | # AFTER: 8: 70 47 bx lr |
deps/lld/test/COFF/armnt-rel32.yaml created+47| ... | ... | @@ -0,0 +1,47 @@ |
| 1 | # REQUIRES: arm | |
| 2 | ||
| 3 | # RUN: yaml2obj < %s > %t.obj | |
| 4 | # RUN: llvm-objdump -s %t.obj | FileCheck %s -check-prefix BEFORE | |
| 5 | # RUN: lld-link /entry:function /subsystem:console /out:%t.exe %t.obj | |
| 6 | # RUN: llvm-objdump -s %t.exe | FileCheck %s -check-prefix AFTER | |
| 7 | ||
| 8 | # BEFORE: Contents of section .text: | |
| 9 | # BEFORE: 0000 704700bf 01000000 01000000 | |
| 10 | ||
| 11 | # AFTER: Contents of section .text: | |
| 12 | # AFTER: 401000 704700bf faffffff f50f0000 | |
| 13 | ||
| 14 | --- !COFF | |
| 15 | header: | |
| 16 | Machine: IMAGE_FILE_MACHINE_ARMNT | |
| 17 | Characteristics: [] | |
| 18 | sections: | |
| 19 | - Name: .text | |
| 20 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] | |
| 21 | Alignment: 4 | |
| 22 | SectionData: 704700BF0100000001000000 | |
| 23 | Relocations: | |
| 24 | - VirtualAddress: 4 | |
| 25 | SymbolName: function | |
| 26 | Type: IMAGE_REL_ARM_REL32 | |
| 27 | - VirtualAddress: 8 | |
| 28 | SymbolName: data | |
| 29 | Type: IMAGE_REL_ARM_REL32 | |
| 30 | - Name: .rdata | |
| 31 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 32 | Alignment: 1 | |
| 33 | SectionData: 00 | |
| 34 | symbols: | |
| 35 | - Name: function | |
| 36 | Value: 0 | |
| 37 | SectionNumber: 1 | |
| 38 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 39 | ComplexType: IMAGE_SYM_DTYPE_FUNCTION | |
| 40 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 41 | - Name: data | |
| 42 | Value: 0 | |
| 43 | SectionNumber: 2 | |
| 44 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 45 | ComplexType: IMAGE_SYM_DTYPE_FUNCTION | |
| 46 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 47 | ... |
deps/lld/test/COFF/associative-comdat-empty.test created+56| ... | ... | @@ -0,0 +1,56 @@ |
| 1 | # RUN: yaml2obj < %s > %t.obj | |
| 2 | # RUN: not lld-link /include:symbol /dll /noentry /nodefaultlib %t.obj /out:%t.exe 2>&1 | FileCheck %s | |
| 3 | ||
| 4 | # Tests an associative comdat being associated with an empty section errors. | |
| 5 | # CHECK: lld-link: error: {{.*}}: associative comdat .text$ac1 (sec 1) has invalid reference to section .text$nm (sec 2) | |
| 6 | # CHECK-NOT: lld-link: error: | |
| 7 | ||
| 8 | --- !COFF | |
| 9 | header: | |
| 10 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 11 | Characteristics: [ ] | |
| 12 | sections: | |
| 13 | - Name: '.text$ac1' | |
| 14 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] | |
| 15 | Alignment: 1 | |
| 16 | SectionData: '01000000' | |
| 17 | - Name: '.text$nm' | |
| 18 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] | |
| 19 | Alignment: 1 | |
| 20 | SectionData: '01000000' | |
| 21 | symbols: | |
| 22 | - Name: '.text$ac1' | |
| 23 | Value: 0 | |
| 24 | SectionNumber: 1 | |
| 25 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 26 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 27 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 28 | SectionDefinition: | |
| 29 | Length: 4 | |
| 30 | NumberOfRelocations: 0 | |
| 31 | NumberOfLinenumbers: 0 | |
| 32 | CheckSum: 3099354981 | |
| 33 | Number: 2 | |
| 34 | Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE | |
| 35 | - Name: '.text$nm' | |
| 36 | Value: 0 | |
| 37 | SectionNumber: 2 | |
| 38 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 39 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 40 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 41 | SectionDefinition: | |
| 42 | Length: 0 | |
| 43 | NumberOfRelocations: 0 | |
| 44 | NumberOfLinenumbers: 0 | |
| 45 | CheckSum: 3099354981 | |
| 46 | Number: 4 | |
| 47 | Selection: IMAGE_COMDAT_SELECT_ANY | |
| 48 | - Name: assocsym | |
| 49 | Value: 0 | |
| 50 | SectionNumber: 1 | |
| 51 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 52 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 53 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 54 | ... | |
| 55 | ||
| 56 |
deps/lld/test/COFF/associative-comdat-mingw-i386.s created+37| ... | ... | @@ -0,0 +1,37 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -triple=i686-windows-gnu %s -filetype=obj -o %t.obj | |
| 4 | ||
| 5 | # RUN: lld-link -lldmingw -entry:main %t.obj -out:%t.exe | |
| 6 | # RUN: llvm-objdump -s %t.exe | FileCheck %s | |
| 7 | ||
| 8 | # Check that the .eh_frame comdat was included, even if it had no symbols, | |
| 9 | # due to associativity with the symbol _foo. | |
| 10 | ||
| 11 | # CHECK: Contents of section .eh_fram: | |
| 12 | # CHECK: 403000 42 | |
| 13 | ||
| 14 | .text | |
| 15 | .def _main; | |
| 16 | .scl 2; | |
| 17 | .type 32; | |
| 18 | .endef | |
| 19 | .globl _main | |
| 20 | .p2align 4, 0x90 | |
| 21 | _main: | |
| 22 | call _foo | |
| 23 | ret | |
| 24 | ||
| 25 | .section .eh_frame$foo,"dr" | |
| 26 | .linkonce discard | |
| 27 | .byte 0x42 | |
| 28 | ||
| 29 | .def _foo; | |
| 30 | .scl 2; | |
| 31 | .type 32; | |
| 32 | .endef | |
| 33 | .section .text$foo,"xr",discard,foo | |
| 34 | .globl _foo | |
| 35 | .p2align 4 | |
| 36 | _foo: | |
| 37 | ret |
deps/lld/test/COFF/associative-comdat-mingw.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: llvm-mc -triple=x86_64-windows-gnu %S/Inputs/associative-comdat-mingw-2.s -filetype=obj -o %t2.obj |
| 5 | 5 | |
| 6 | 6 | # RUN: lld-link -lldmingw -entry:main %t1.obj %t2.obj -out:%t.gc.exe -verbose |
| 7 | # RUN: llvm-readobj -sections %t.gc.exe | FileCheck %s | |
| 7 | # RUN: llvm-readobj --sections %t.gc.exe | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | # CHECK: Sections [ |
| 10 | 10 | # CHECK: Section { |
deps/lld/test/COFF/associative-comdat-order.test created+97| ... | ... | @@ -0,0 +1,97 @@ |
| 1 | # Tests that an associative comdat being associated with another | |
| 2 | # associated comdat later in the file produces an error. | |
| 3 | # RUN: sed -e s/ASSOC1/2/ -e s/ASSOC2/3/ %s | yaml2obj > %t.obj | |
| 4 | # RUN: not lld-link /include:symbol /dll /noentry /nodefaultlib %t.obj /out:%t.exe 2>&1 | FileCheck --check-prefix=FORWARD %s | |
| 5 | # FORWARD: lld-link: error: {{.*}}: associative comdat .text$ac1 (sec 1) has invalid reference to section .text$ac2 (sec 2) | |
| 6 | # FORWARD-NOT: lld-link: error: | |
| 7 | ||
| 8 | # Tests that an associative comdat being associated with another | |
| 9 | # associated comdat earlier in the file works. | |
| 10 | # RUN: sed -e s/ASSOC1/3/ -e s/ASSOC2/1/ %s | yaml2obj > %t.obj | |
| 11 | ||
| 12 | # RUN: lld-link /include:symbol /dll /noentry /nodefaultlib %t.obj /out:%t.exe | |
| 13 | # RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=BACKWARD %s | |
| 14 | # BACKWARD: Contents of section .text: | |
| 15 | # BACKWARD: 180001000 01000000 02000000 03000000 ............ | |
| 16 | ||
| 17 | # RUN: lld-link /dll /noentry /nodefaultlib %t.obj /out:%t.exe | |
| 18 | # RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=BACKWARDDROP %s | |
| 19 | # BACKWARDDROP-NOT: Contents of section .text: | |
| 20 | ||
| 21 | --- !COFF | |
| 22 | header: | |
| 23 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 24 | Characteristics: [ ] | |
| 25 | sections: | |
| 26 | - Name: '.text$ac1' | |
| 27 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] | |
| 28 | Alignment: 1 | |
| 29 | SectionData: '01000000' | |
| 30 | - Name: '.text$ac2' | |
| 31 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] | |
| 32 | Alignment: 1 | |
| 33 | SectionData: '02000000' | |
| 34 | - Name: '.text$nm' | |
| 35 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] | |
| 36 | Alignment: 1 | |
| 37 | SectionData: '03000000' | |
| 38 | symbols: | |
| 39 | - Name: '.text$ac1' | |
| 40 | Value: 0 | |
| 41 | SectionNumber: 1 | |
| 42 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 43 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 44 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 45 | SectionDefinition: | |
| 46 | Length: 4 | |
| 47 | NumberOfRelocations: 0 | |
| 48 | NumberOfLinenumbers: 0 | |
| 49 | CheckSum: 3099354981 | |
| 50 | Number: ASSOC1 | |
| 51 | Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE | |
| 52 | - Name: '.text$ac2' | |
| 53 | Value: 0 | |
| 54 | SectionNumber: 2 | |
| 55 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 56 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 57 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 58 | SectionDefinition: | |
| 59 | Length: 4 | |
| 60 | NumberOfRelocations: 0 | |
| 61 | NumberOfLinenumbers: 0 | |
| 62 | CheckSum: 3099354981 | |
| 63 | Number: ASSOC2 | |
| 64 | Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE | |
| 65 | - Name: '.text$nm' | |
| 66 | Value: 0 | |
| 67 | SectionNumber: 3 | |
| 68 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 69 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 70 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 71 | SectionDefinition: | |
| 72 | Length: 4 | |
| 73 | NumberOfRelocations: 0 | |
| 74 | NumberOfLinenumbers: 0 | |
| 75 | CheckSum: 3099354981 | |
| 76 | Number: 4 | |
| 77 | Selection: IMAGE_COMDAT_SELECT_ANY | |
| 78 | - Name: symbol | |
| 79 | Value: 0 | |
| 80 | SectionNumber: 3 | |
| 81 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 82 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 83 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 84 | - Name: assocsym2 | |
| 85 | Value: 0 | |
| 86 | SectionNumber: 1 | |
| 87 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 88 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 89 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 90 | - Name: assocsym | |
| 91 | Value: 0 | |
| 92 | SectionNumber: 2 | |
| 93 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 94 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 95 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 96 | ... | |
| 97 |
deps/lld/test/COFF/associative-comdat.s+2-2| ... | ... | @@ -3,10 +3,10 @@ |
| 3 | 3 | # RUN: llvm-mc -triple=x86_64-windows-msvc %S/Inputs/associative-comdat-2.s -filetype=obj -o %t2.obj |
| 4 | 4 | |
| 5 | 5 | # RUN: lld-link -entry:main %t1.obj %t2.obj -out:%t.gc.exe |
| 6 | # RUN: llvm-readobj -sections %t.gc.exe | FileCheck %s | |
| 6 | # RUN: llvm-readobj --sections %t.gc.exe | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | # RUN: lld-link -entry:main %t1.obj %t2.obj -opt:noref -out:%t.nogc.exe |
| 9 | # RUN: llvm-readobj -sections %t.nogc.exe | FileCheck %s | |
| 9 | # RUN: llvm-readobj --sections %t.nogc.exe | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | # CHECK: Sections [ |
| 12 | 12 | # CHECK: Section { |
deps/lld/test/COFF/autoimport-arm-data.s+1-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: llvm-mc -triple=armv7-windows-gnu %s -filetype=obj -o %t.obj |
| 8 | 8 | # RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib -verbose |
| 9 | 9 | |
| 10 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s | |
| 10 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s | |
| 11 | 11 | # RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=CONTENTS %s |
| 12 | 12 | |
| 13 | 13 | # IMPORTS: Import { |
deps/lld/test/COFF/autoimport-arm64-data.s+1-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: llvm-mc -triple=aarch64-windows-gnu %s -filetype=obj -o %t.obj |
| 8 | 8 | # RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib -verbose |
| 9 | 9 | |
| 10 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s | |
| 10 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s | |
| 11 | 11 | # RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=CONTENTS %s |
| 12 | 12 | |
| 13 | 13 | # IMPORTS: Import { |
deps/lld/test/COFF/autoimport-gnu-implib.s+1-1| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | # RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj |
| 10 | 10 | # RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-implib.a -verbose |
| 11 | 11 | |
| 12 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s | |
| 12 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s | |
| 13 | 13 | |
| 14 | 14 | # IMPORTS: Import { |
| 15 | 15 | # IMPORTS-NEXT: Name: foo.dll |
deps/lld/test/COFF/autoimport-refptr.s+2-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj |
| 8 | 8 | # RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib -verbose |
| 9 | 9 | |
| 10 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s | |
| 10 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s | |
| 11 | 11 | # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s |
| 12 | 12 | # RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=CONTENTS %s |
| 13 | 13 | |
| ... | ... | @@ -19,6 +19,7 @@ |
| 19 | 19 | # IMPORTS-NEXT: } |
| 20 | 20 | |
| 21 | 21 | # DISASM: Disassembly of section .text: |
| 22 | # DISASM-EMPTY: | |
| 22 | 23 | # DISASM: .text: |
| 23 | 24 | # Relative offset at 0x1002 pointing at the IAT at 0x2060 |
| 24 | 25 | # DISASM: 140001000: 48 8b 05 59 10 00 00 movq 4185(%rip), %rax |
deps/lld/test/COFF/autoimport-x86.s+2-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj |
| 8 | 8 | # RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib -verbose |
| 9 | 9 | |
| 10 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s | |
| 10 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s | |
| 11 | 11 | # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s |
| 12 | 12 | # RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=CONTENTS %s |
| 13 | 13 | |
| ... | ... | @@ -19,6 +19,7 @@ |
| 19 | 19 | # IMPORTS-NEXT: } |
| 20 | 20 | |
| 21 | 21 | # DISASM: Disassembly of section .text: |
| 22 | # DISASM-EMPTY: | |
| 22 | 23 | # DISASM: .text: |
| 23 | 24 | # Relative offset at 0x1002 pointing at the IAT at 0x2080. |
| 24 | 25 | # DISASM: 140001000: 8b 05 7a 10 00 00 movl 4218(%rip), %eax |
deps/lld/test/COFF/base.test+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | 2 | |
| 3 | 3 | # RUN: lld-link /out:%t.exe /entry:main %t.obj |
| 4 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DEFAULT-HEADER %s | |
| 4 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=DEFAULT-HEADER %s | |
| 5 | 5 | # RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=DEFAULT-TEXT %s |
| 6 | 6 | |
| 7 | 7 | # DEFAULT-HEADER: ImageBase: 0x140000000 |
| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | # DEFAULT-TEXT-NEXT: 1000 00000040 01000000 |
| 10 | 10 | |
| 11 | 11 | # RUN: lld-link /out:%t.exe /entry:main %t.obj /base:0x280000000 |
| 12 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BASE-HEADER %s | |
| 12 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=BASE-HEADER %s | |
| 13 | 13 | # RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=BASE-TEXT %s |
| 14 | 14 | |
| 15 | 15 | # BASE-HEADER: ImageBase: 0x280000000 |
deps/lld/test/COFF/baserel.test+4-4| ... | ... | @@ -1,10 +1,10 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | 2 | # |
| 3 | 3 | # RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib |
| 4 | # RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck %s -check-prefix=BASEREL | |
| 4 | # RUN: llvm-readobj --coff-basereloc %t.exe | FileCheck %s -check-prefix=BASEREL | |
| 5 | 5 | # |
| 6 | 6 | # RUN: lld-link /out:%t.exe /entry:main /fixed %t.obj %p/Inputs/std64.lib |
| 7 | # RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck %s -check-prefix=NOBASEREL | |
| 7 | # RUN: llvm-readobj --coff-basereloc %t.exe | FileCheck %s -check-prefix=NOBASEREL | |
| 8 | 8 | # |
| 9 | 9 | # BASEREL: BaseReloc [ |
| 10 | 10 | # BASEREL-NEXT: Entry { |
| ... | ... | @@ -44,11 +44,11 @@ |
| 44 | 44 | # NOBASEREL-NEXT: ] |
| 45 | 45 | # |
| 46 | 46 | # RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib |
| 47 | # RUN: llvm-readobj -file-headers -sections %t.exe | FileCheck %s \ | |
| 47 | # RUN: llvm-readobj --file-headers --sections %t.exe | FileCheck %s \ | |
| 48 | 48 | # RUN: --check-prefix=BASEREL-HEADER |
| 49 | 49 | # |
| 50 | 50 | # RUN: lld-link /out:%t.exe /entry:main /fixed %t.obj %p/Inputs/std64.lib |
| 51 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s \ | |
| 51 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck %s \ | |
| 52 | 52 | # RUN: --check-prefix=NOBASEREL-HEADER |
| 53 | 53 | # |
| 54 | 54 | # BASEREL-HEADER-NOT: IMAGE_FILE_RELOCS_STRIPPED |
deps/lld/test/COFF/color-diagnostics.test created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | # Windows command prompt doesn't support ANSI escape sequences. | |
| 2 | # REQUIRES: shell | |
| 3 | ||
| 4 | # RUN: not lld-link -xyz --color-diagnostics /nosuchfile 2>&1 \ | |
| 5 | # RUN: | FileCheck -check-prefix=COLOR %s | |
| 6 | # RUN: not lld-link -xyz --color-diagnostics=always /nosuchfile 2>&1 \ | |
| 7 | # RUN: | FileCheck -check-prefix=COLOR %s | |
| 8 | ||
| 9 | # COLOR: {{lld-link: .\[0;1;35mwarning: .\[0mignoring unknown argument '-xyz'}} | |
| 10 | # COLOR: {{lld-link: .\[0;1;31merror: .\[0mcould not open '/nosuchfile'}} | |
| 11 | ||
| 12 | # RUN: not lld-link /nosuchfile 2>&1 | FileCheck -check-prefix=NOCOLOR %s | |
| 13 | # RUN: not lld-link -color-diagnostics=never /nosuchfile 2>&1 \ | |
| 14 | # RUN: | FileCheck -check-prefix=NOCOLOR %s | |
| 15 | # RUN: not lld-link -color-diagnostics=always -no-color-diagnostics \ | |
| 16 | # RUN: /nosuchfile 2>&1 | FileCheck -check-prefix=NOCOLOR %s | |
| 17 | ||
| 18 | # NOCOLOR: lld-link: error: could not open '/nosuchfile' |
deps/lld/test/COFF/combined-resources.test+1-1| ... | ... | @@ -8,7 +8,7 @@ |
| 8 | 8 | # RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/resource.res \ |
| 9 | 9 | # RUN: %p/Inputs/combined-resources.res %p/Inputs/combined-resources-2.res |
| 10 | 10 | |
| 11 | # RUN: llvm-readobj -coff-resources -file-headers -section-data %t.exe | \ | |
| 11 | # RUN: llvm-readobj --coff-resources --file-headers --section-data %t.exe | \ | |
| 12 | 12 | # RUN: FileCheck %s |
| 13 | 13 | |
| 14 | 14 | CHECK: ResourceTableRVA: 0x2000 |
deps/lld/test/COFF/comdat-selection-associative-largest.s created+45| ... | ... | @@ -0,0 +1,45 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # Tests handling of several comdats with "largest" selection type that each | |
| 4 | # has an associative comdat. | |
| 5 | ||
| 6 | # Create obj files. | |
| 7 | # RUN: sed -e s/TYPE/.byte/ -e s/SIZE/1/ %s | llvm-mc -triple x86_64-pc-win32 -filetype=obj -o %t.1.obj | |
| 8 | # RUN: sed -e s/TYPE/.short/ -e s/SIZE/2/ %s | llvm-mc -triple x86_64-pc-win32 -filetype=obj -o %t.2.obj | |
| 9 | # RUN: sed -e s/TYPE/.long/ -e s/SIZE/4/ %s | llvm-mc -triple x86_64-pc-win32 -filetype=obj -o %t.4.obj | |
| 10 | ||
| 11 | .section .text$ac, "", associative, symbol | |
| 12 | assocsym: | |
| 13 | .long SIZE | |
| 14 | ||
| 15 | .section .text$nm, "", largest, symbol | |
| 16 | .globl symbol | |
| 17 | symbol: | |
| 18 | TYPE SIZE | |
| 19 | ||
| 20 | # Pass the obj files in different orders and check that only the associative | |
| 21 | # comdat of the largest obj file makes it into the output, independent of | |
| 22 | # the order of the obj files on the command line. | |
| 23 | ||
| 24 | # FIXME: Make these pass when /opt:noref is passed. | |
| 25 | ||
| 26 | # RUN: lld-link /include:symbol /dll /noentry /nodefaultlib %t.1.obj %t.2.obj %t.4.obj /out:%t.exe | |
| 27 | # RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=ALL124 %s | |
| 28 | # ALL124: Contents of section .text: | |
| 29 | # ALL124: 180001000 04000000 04000000 .... | |
| 30 | ||
| 31 | # RUN: lld-link /include:symbol /dll /noentry /nodefaultlib %t.4.obj %t.2.obj %t.1.obj /out:%t.exe | |
| 32 | # RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=ALL421 %s | |
| 33 | # ALL421: Contents of section .text: | |
| 34 | # ALL421: 180001000 04000000 04000000 .... | |
| 35 | ||
| 36 | # RUN: lld-link /include:symbol /dll /noentry /nodefaultlib %t.2.obj %t.4.obj %t.1.obj /out:%t.exe | |
| 37 | # RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=ALL241 %s | |
| 38 | # ALL241: Contents of section .text: | |
| 39 | # ALL241: 180001000 04000000 04000000 .... | |
| 40 | ||
| 41 | # RUN: lld-link /include:symbol /dll /noentry /nodefaultlib %t.2.obj %t.1.obj /out:%t.exe | |
| 42 | # RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=JUST21 %s | |
| 43 | # JUST21: Contents of section .text: | |
| 44 | # JUST21: 180001000 02000000 0200 .... | |
| 45 |
deps/lld/test/COFF/comdat-selection.s created+107| ... | ... | @@ -0,0 +1,107 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # Tests handling of the comdat selection type. | |
| 4 | # (Except associative which is tested in associative-comdat.s and | |
| 5 | # comdat-selection-associate-largest.s instead.) | |
| 6 | ||
| 7 | # Create obj files with each selection type. | |
| 8 | # RUN: sed -e s/SEL/discard/ %s | llvm-mc -triple x86_64-pc-win32 -filetype=obj -o %t.discard.obj | |
| 9 | # RUN: sed -e s/SEL/discard/ -e s/.long/.short/ -e s/1/2/ %s | llvm-mc -triple x86_64-pc-win32 -filetype=obj -o %t.discard.short.2.obj | |
| 10 | # RUN: sed -e s/SEL/one_only/ %s | llvm-mc -triple x86_64-pc-win32 -filetype=obj -o %t.one_only.obj | |
| 11 | # RUN: sed -e s/SEL/same_size/ %s | llvm-mc -triple x86_64-pc-win32 -filetype=obj -o %t.same_size.obj | |
| 12 | # RUN: sed -e s/SEL/same_size/ -e s/.long/.short/ %s | llvm-mc -triple x86_64-pc-win32 -filetype=obj -o %t.same_size.short.obj | |
| 13 | # RUN: sed -e s/SEL/same_contents/ %s | llvm-mc -triple x86_64-pc-win32 -filetype=obj -o %t.same_contents.obj | |
| 14 | # RUN: sed -e s/SEL/same_contents/ -e s/.long/.short/ %s | llvm-mc -triple x86_64-pc-win32 -filetype=obj -o %t.same_contents.short.obj | |
| 15 | # RUN: sed -e s/SEL/same_contents/ -e s/1/2/ %s | llvm-mc -triple x86_64-pc-win32 -filetype=obj -o %t.same_contents.2.obj | |
| 16 | # RUN: sed -e s/SEL/largest/ %s | llvm-mc -triple x86_64-pc-win32 -filetype=obj -o %t.largest.obj | |
| 17 | # RUN: sed -e s/SEL/largest/ -e s/.long/.short/ -e s/1/2/ %s | llvm-mc -triple x86_64-pc-win32 -filetype=obj -o %t.largest.short.2.obj | |
| 18 | # RUN: sed -e s/SEL/newest/ %s | llvm-mc -triple x86_64-pc-win32 -filetype=obj -o %t.newest.obj | |
| 19 | ||
| 20 | .section .text$nm, "", SEL, symbol | |
| 21 | .globl symbol | |
| 22 | symbol: | |
| 23 | .long 1 | |
| 24 | ||
| 25 | # First, pass each selection type twice. All should link fine except for | |
| 26 | # one_only which should report a duplicate symbol error and newest which | |
| 27 | # link.exe (and hence lld-link) doesn't understand. | |
| 28 | ||
| 29 | # RUN: cp %t.discard.obj %t.obj && lld-link /dll /noentry /nodefaultlib %t.discard.obj %t.obj | |
| 30 | # RUN: cp %t.one_only.obj %t.obj && not lld-link /dll /noentry /nodefaultlib %t.one_only.obj %t.obj 2>&1 | FileCheck --check-prefix=ONEONE %s | |
| 31 | # ONEONE: lld-link: error: duplicate symbol: symbol | |
| 32 | # RUN: cp %t.same_size.obj %t.obj && lld-link /dll /noentry /nodefaultlib %t.same_size.obj %t.obj | |
| 33 | # RUN: cp %t.same_contents.obj %t.obj && lld-link /dll /noentry /nodefaultlib %t.same_contents.obj %t.obj | |
| 34 | # RUN: cp %t.largest.obj %t.obj && lld-link /dll /noentry /nodefaultlib %t.largest.obj %t.obj | |
| 35 | # RUN: cp %t.newest.obj %t.obj && not lld-link /dll /noentry /nodefaultlib %t.newest.obj %t.obj 2>&1 | FileCheck --check-prefix=NEWNEW %s | |
| 36 | # NEWNEW: lld-link: error: unknown comdat type 7 for symbol | |
| 37 | ||
| 38 | # /force doesn't affect errors about unknown comdat types. | |
| 39 | # RUN: cp %t.newest.obj %t.obj && not lld-link /force /dll /noentry /nodefaultlib %t.newest.obj %t.obj 2>&1 | FileCheck --check-prefix=NEWNEWFORCE %s | |
| 40 | # NEWNEWFORCE: lld-link: error: unknown comdat type 7 for symbol | |
| 41 | ||
| 42 | # Check that same_size, same_contents, largest do what they're supposed to. | |
| 43 | ||
| 44 | # Check that the "same_size" selection produces an error if passed two symbols | |
| 45 | # with different size. | |
| 46 | # RUN: not lld-link /dll /noentry /nodefaultlib %t.same_size.obj %t.same_size.short.obj 2>&1 | FileCheck --check-prefix=SAMESIZEDUPE %s | |
| 47 | # SAMESIZEDUPE: lld-link: error: duplicate symbol: symbol | |
| 48 | ||
| 49 | # Check that the "same_contents" selection produces an error if passed two | |
| 50 | # symbols with different contents. | |
| 51 | # RUN: not lld-link /dll /noentry /nodefaultlib %t.same_contents.obj %t.same_contents.2.obj 2>&1 | FileCheck --check-prefix=SAMECONTENTSDUPE1 %s | |
| 52 | # SAMECONTENTSDUPE1: lld-link: error: duplicate symbol: symbol | |
| 53 | # RUN: not lld-link /dll /noentry /nodefaultlib %t.same_contents.obj %t.same_contents.2.obj 2>&1 | FileCheck --check-prefix=SAMECONTENTSDUPE2 %s | |
| 54 | # SAMECONTENTSDUPE2: lld-link: error: duplicate symbol: symbol | |
| 55 | ||
| 56 | # Check that the "largest" selection picks the larger comdat (independent of | |
| 57 | # the order the .obj files are passed on the commandline). | |
| 58 | # RUN: lld-link /opt:noref /include:symbol /dll /noentry /nodefaultlib %t.largest.obj %t.largest.short.2.obj /out:%t.exe | |
| 59 | # RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=LARGEST1 %s | |
| 60 | # LARGEST1: Contents of section .text: | |
| 61 | # LARGEST1: 180001000 01000000 .... | |
| 62 | ||
| 63 | # FIXME: Make this pass when /opt:noref is passed. | |
| 64 | # RUN: lld-link /include:symbol /dll /noentry /nodefaultlib %t.largest.short.2.obj %t.largest.obj /out:%t.exe | |
| 65 | # RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=LARGEST2 %s | |
| 66 | # LARGEST2: Contents of section .text: | |
| 67 | # LARGEST2: 180001000 01000000 .... | |
| 68 | ||
| 69 | ||
| 70 | # Test linking the same symbol with different comdat selection types. | |
| 71 | # link.exe generally rejects this, except for "largest" which is allowed to | |
| 72 | # combine with everything (https://bugs.llvm.org/show_bug.cgi?id=40094#c7). | |
| 73 | # lld-link rejects all comdat selection type mismatches. Spot-test just a few | |
| 74 | # combinations. | |
| 75 | ||
| 76 | # RUN: not lld-link /verbose /dll /noentry /nodefaultlib %t.discard.obj %t.one_only.obj 2>&1 | FileCheck --check-prefix=DISCARDONE %s | |
| 77 | # DISCARDONE: lld-link: conflicting comdat type for symbol: 2 in | |
| 78 | # DISCARDONE: lld-link: error: duplicate symbol: symbol | |
| 79 | # RUN: lld-link /verbose /force /dll /noentry /nodefaultlib %t.discard.obj %t.one_only.obj 2>&1 | FileCheck --check-prefix=DISCARDONEFORCE %s | |
| 80 | # DISCARDONEFORCE: lld-link: conflicting comdat type for symbol: 2 in | |
| 81 | # DISCARDONEFORCE: lld-link: warning: duplicate symbol: symbol | |
| 82 | ||
| 83 | # Make sure the error isn't depending on the order of .obj files. | |
| 84 | # RUN: not lld-link /verbose /dll /noentry /nodefaultlib %t.one_only.obj %t.discard.obj 2>&1 | FileCheck --check-prefix=ONEDISCARD %s | |
| 85 | # ONEDISCARD: lld-link: conflicting comdat type for symbol: 1 in | |
| 86 | # ONEDISCARD: lld-link: error: duplicate symbol: symbol | |
| 87 | ||
| 88 | # RUN: not lld-link /verbose /dll /noentry /nodefaultlib %t.same_contents.obj %t.same_size.obj 2>&1 | FileCheck --check-prefix=CONTENTSSIZE %s | |
| 89 | # CONTENTSSIZE: lld-link: conflicting comdat type for symbol: 4 in | |
| 90 | # CONTENTSSIZE: lld-link: error: duplicate symbol: symbol | |
| 91 | ||
| 92 | # Check that linking one 'discard' and one 'largest' has the effect of | |
| 93 | # 'largest'. | |
| 94 | # RUN: lld-link /dll /noentry /nodefaultlib %t.discard.short.2.obj %t.largest.obj | |
| 95 | # RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=DISCARDLARGEST %s | |
| 96 | # DISCARDLARGEST: Contents of section .text: | |
| 97 | # DISCARDLARGEST: 180001000 01000000 .... | |
| 98 | # RUN: lld-link /dll /noentry /nodefaultlib %t.largest.obj %t.discard.short.2.obj | |
| 99 | # RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=LARGESTDISCARD %s | |
| 100 | # LARGESTDISCARD: Contents of section .text: | |
| 101 | # LARGESTDISCARD: 180001000 01000000 .... | |
| 102 | ||
| 103 | ||
| 104 | # These cases are accepted by link.exe but not by lld-link. | |
| 105 | # RUN: not lld-link /verbose /dll /noentry /nodefaultlib %t.largest.obj %t.one_only.obj 2>&1 | FileCheck --check-prefix=LARGESTONE %s | |
| 106 | # LARGESTONE: lld-link: conflicting comdat type for symbol: 6 in | |
| 107 | # LARGESTONE: lld-link: error: duplicate symbol: symbol |
deps/lld/test/COFF/common-replacement.s+1-1| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | |
| 6 | 6 | # RUN: lld-link -lldmingw -entry:main %t1.obj %t2.obj -out:%t.exe -verbose 2>&1 \ |
| 7 | 7 | # RUN: | FileCheck -check-prefix VERBOSE %s |
| 8 | # RUN: llvm-readobj -s %t.exe | FileCheck -check-prefix SECTIONS %s | |
| 8 | # RUN: llvm-readobj -S %t.exe | FileCheck -check-prefix SECTIONS %s | |
| 9 | 9 | |
| 10 | 10 | # VERBOSE: -aligncomm:"foo",2 |
| 11 | 11 |
deps/lld/test/COFF/common.test+1-1| ... | ... | @@ -79,7 +79,7 @@ symbols: |
| 79 | 79 | ComplexType: IMAGE_SYM_DTYPE_NULL |
| 80 | 80 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL |
| 81 | 81 | - Name: bssdata16 |
| 82 | Value: 16 | |
| 82 | Value: 15 | |
| 83 | 83 | SectionNumber: 0 |
| 84 | 84 | SimpleType: IMAGE_SYM_TYPE_NULL |
| 85 | 85 | ComplexType: IMAGE_SYM_DTYPE_NULL |
deps/lld/test/COFF/conflict-mangled.test+5-2| ... | ... | @@ -1,10 +1,13 @@ |
| 1 | # REQUIRES: system-windows | |
| 2 | 1 | # RUN: yaml2obj < %s > %t1.obj |
| 3 | 2 | # RUN: yaml2obj < %s > %t2.obj |
| 4 | 3 | # RUN: not lld-link /out:%t.exe %t1.obj %t2.obj >& %t.log |
| 5 | 4 | # RUN: FileCheck %s < %t.log |
| 5 | # RUN: not lld-link /out:%t.exe /demangle %t1.obj %t2.obj 2>&1 | FileCheck %s | |
| 6 | # RUN: not lld-link /out:%t.exe /demangle:no %t1.obj %t2.obj 2>&1 | FileCheck --check-prefix=NODEMANGLE %s | |
| 6 | 7 | |
| 7 | # CHECK: duplicate symbol: "int __cdecl mangled(void)" (?mangled@@YAHXZ) in {{.+}}1.obj and in {{.+}}2.obj | |
| 8 | # NODEMANGLE: duplicate symbol: ?mangled@@YAHXZ in {{.+}}1.obj and in {{.+}}2.obj | |
| 9 | ||
| 10 | # CHECK: duplicate symbol: int __cdecl mangled(void) in {{.+}}1.obj and in {{.+}}2.obj | |
| 8 | 11 | |
| 9 | 12 | --- !COFF |
| 10 | 13 | header: |
deps/lld/test/COFF/constant-export.test+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # RUN: mkdir -p %t |
| 2 | 2 | # RUN: yaml2obj -o %t/constant-export.obj %s |
| 3 | 3 | # RUN: lld-link /machine:x86 /dll /entry:__CFConstantStringClassReference -out:%t/constant-export.dll %t/constant-export.obj |
| 4 | # RUN: llvm-readobj -coff-exports %t/constant-export.lib | FileCheck %s | |
| 4 | # RUN: llvm-readobj --coff-exports %t/constant-export.lib | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: Type: const |
| 7 | 7 | # CHECK: Name type: noprefix |
deps/lld/test/COFF/constant.test+2-2| ... | ... | @@ -2,5 +2,5 @@ REQUIRES: x86 |
| 2 | 2 | RUN: mkdir -p %t |
| 3 | 3 | RUN: llvm-mc -triple i686-unknown-windows-msvc -filetype obj -o %t/import.o %S/Inputs/constant-import.s |
| 4 | 4 | RUN: llc -mtriple i686-unknown-windows-msvc -filetype obj -o %t/export.o %S/Inputs/constant-export.ll |
| 5 | RUN: lld-link -machine:x86 -dll -out:%t/export.dll %t/export.o -entry:__CFConstantStringClassReference | |
| 6 | RUN: lld-link -machine:x86 -dll -out:%t/import.dll %t/import.o %t/export.lib | |
| 5 | RUN: lld-link -safeseh:no -machine:x86 -dll -out:%t/export.dll %t/export.o -entry:__CFConstantStringClassReference | |
| 6 | RUN: lld-link -safeseh:no -machine:x86 -dll -out:%t/import.dll %t/import.o %t/export.lib |
deps/lld/test/COFF/could-not-open.test+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | RUN: not lld-link 01 2>&1 | FileCheck %s |
| 2 | 2 | |
| 3 | CHECK: could not open 01 | |
| 3 | CHECK: could not open '01' | |
| 4 | 4 | CHECK-NOT: /machine is not specified |
| 5 | 5 | CHECK-NOT: subsystem must be defined |
deps/lld/test/COFF/crt-chars.test+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: yaml2obj %s > %t.obj |
| 2 | 2 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj |
| 3 | # RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s | |
| 3 | # RUN: llvm-readobj --sections --section-data %t.dll | FileCheck %s | |
| 4 | 4 | |
| 5 | 5 | # CHECK: Name: .CRT |
| 6 | 6 | # CHECK: Characteristics [ |
deps/lld/test/COFF/crt-dyn-initializer-order.test+100-100| ... | ... | @@ -1,100 +1,100 @@ |
| 1 | # // a.cpp | |
| 2 | # #include <iostream> | |
| 3 | # #include <vector> | |
| 4 | # | |
| 5 | # template <int Magic> struct TemplatedObject { | |
| 6 | # static std::vector<TemplatedObject<Magic> *> Instances; | |
| 7 | # TemplatedObject() { Instances.push_back(this); } | |
| 8 | # }; | |
| 9 | # | |
| 10 | # using Object = TemplatedObject<0>; | |
| 11 | # template <> std::vector<Object *> Object::Instances{}; | |
| 12 | # Object idle{}; | |
| 13 | # | |
| 14 | # int main() { | |
| 15 | # if (Object::Instances.size() == 0) | |
| 16 | # std::cout << "It's broken" << std::endl; | |
| 17 | # else | |
| 18 | # std::cout << "It works!" << std::endl; | |
| 19 | # return 0; | |
| 20 | # } | |
| 21 | # // using `clang-cl /c a.cpp | lld-link a.obj` works | |
| 22 | # // using `cl /c a.cpp | lld-link a.obj` fails without lld/COFF/Writer.cpp/Writer::sortSectionChunks() | |
| 23 | ||
| 24 | # RUN: yaml2obj %s > %t.obj | |
| 25 | # RUN: yaml2obj %S/Inputs/crt-dyn-initializer-order_1.yaml > %t1.obj | |
| 26 | # RUN: yaml2obj %S/Inputs/crt-dyn-initializer-order_2.yaml > %t2.obj | |
| 27 | ||
| 28 | # CHECK: Name: .CRT | |
| 29 | # CHECK: Characteristics [ | |
| 30 | # CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | |
| 31 | # CHECK-NEXT: IMAGE_SCN_MEM_READ | |
| 32 | # CHECK-NEXT: ] | |
| 33 | # CHECK-NEXT: SectionData ( | |
| 34 | ||
| 35 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj %t1.obj %t2.obj | |
| 36 | # RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE1 | |
| 37 | # CASE1-NEXT: 01020304 55701011 1205 | |
| 38 | ||
| 39 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj %t2.obj %t1.obj | |
| 40 | # RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE2 | |
| 41 | # CASE2-NEXT: 01020304 10111255 7005 | |
| 42 | ||
| 43 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t1.obj %t2.obj %t.obj | |
| 44 | # RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE3 | |
| 45 | # CASE3-NEXT: 01557010 11120203 0405 | |
| 46 | ||
| 47 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t1.obj %t.obj %t2.obj | |
| 48 | # RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE4 | |
| 49 | # CASE4-NEXT: 01557002 03041011 1205 | |
| 50 | ||
| 51 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t2.obj %t1.obj %t.obj | |
| 52 | # RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE5 | |
| 53 | # CASE5-NEXT: 01101112 55700203 0405 | |
| 54 | ||
| 55 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t2.obj %t.obj %t1.obj | |
| 56 | # RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE6 | |
| 57 | # CASE6-NEXT: 01101112 02030455 7005 | |
| 58 | ||
| 59 | # CHECK-NEXT: ) | |
| 60 | ||
| 61 | --- !COFF | |
| 62 | header: | |
| 63 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 64 | Characteristics: [ ] | |
| 65 | sections: | |
| 66 | - Name: '.CRT$XCA' | |
| 67 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 68 | Alignment: 1 | |
| 69 | SectionData: 01 | |
| 70 | - Name: '.CRT$XCU' | |
| 71 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 72 | Alignment: 1 | |
| 73 | SectionData: 02 | |
| 74 | - Name: '.CRT$XCU' | |
| 75 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_LNK_COMDAT ] | |
| 76 | Alignment: 1 | |
| 77 | SectionData: 03 | |
| 78 | - Name: '.CRT$XCU' | |
| 79 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 80 | Alignment: 1 | |
| 81 | SectionData: 04 | |
| 82 | - Name: '.CRT$XCZ' | |
| 83 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 84 | Alignment: 1 | |
| 85 | SectionData: 05 | |
| 86 | symbols: | |
| 87 | - Name: '.CRT$XCU' | |
| 88 | Value: 0 | |
| 89 | SectionNumber: 3 | |
| 90 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 91 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 92 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 93 | SectionDefinition: | |
| 94 | Length: 1 | |
| 95 | NumberOfRelocations: 0 | |
| 96 | NumberOfLinenumbers: 0 | |
| 97 | CheckSum: 1 | |
| 98 | Number: 2 | |
| 99 | Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE | |
| 100 | ... | |
| 1 | # // a.cpp | |
| 2 | # #include <iostream> | |
| 3 | # #include <vector> | |
| 4 | # | |
| 5 | # template <int Magic> struct TemplatedObject { | |
| 6 | # static std::vector<TemplatedObject<Magic> *> Instances; | |
| 7 | # TemplatedObject() { Instances.push_back(this); } | |
| 8 | # }; | |
| 9 | # | |
| 10 | # using Object = TemplatedObject<0>; | |
| 11 | # template <> std::vector<Object *> Object::Instances{}; | |
| 12 | # Object idle{}; | |
| 13 | # | |
| 14 | # int main() { | |
| 15 | # if (Object::Instances.size() == 0) | |
| 16 | # std::cout << "It's broken" << std::endl; | |
| 17 | # else | |
| 18 | # std::cout << "It works!" << std::endl; | |
| 19 | # return 0; | |
| 20 | # } | |
| 21 | # // using `clang-cl /c a.cpp | lld-link a.obj` works | |
| 22 | # // using `cl /c a.cpp | lld-link a.obj` fails without lld/COFF/Writer.cpp/Writer::sortSectionChunks() | |
| 23 | ||
| 24 | # RUN: yaml2obj %s > %t.obj | |
| 25 | # RUN: yaml2obj %S/Inputs/crt-dyn-initializer-order_1.yaml > %t1.obj | |
| 26 | # RUN: yaml2obj %S/Inputs/crt-dyn-initializer-order_2.yaml > %t2.obj | |
| 27 | ||
| 28 | # CHECK: Name: .CRT | |
| 29 | # CHECK: Characteristics [ | |
| 30 | # CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | |
| 31 | # CHECK-NEXT: IMAGE_SCN_MEM_READ | |
| 32 | # CHECK-NEXT: ] | |
| 33 | # CHECK-NEXT: SectionData ( | |
| 34 | ||
| 35 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj %t1.obj %t2.obj | |
| 36 | # RUN: llvm-readobj --sections --section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE1 | |
| 37 | # CASE1-NEXT: 01020304 55701011 1205 | |
| 38 | ||
| 39 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj %t2.obj %t1.obj | |
| 40 | # RUN: llvm-readobj --sections --section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE2 | |
| 41 | # CASE2-NEXT: 01020304 10111255 7005 | |
| 42 | ||
| 43 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t1.obj %t2.obj %t.obj | |
| 44 | # RUN: llvm-readobj --sections --section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE3 | |
| 45 | # CASE3-NEXT: 01557010 11120203 0405 | |
| 46 | ||
| 47 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t1.obj %t.obj %t2.obj | |
| 48 | # RUN: llvm-readobj --sections --section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE4 | |
| 49 | # CASE4-NEXT: 01557002 03041011 1205 | |
| 50 | ||
| 51 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t2.obj %t1.obj %t.obj | |
| 52 | # RUN: llvm-readobj --sections --section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE5 | |
| 53 | # CASE5-NEXT: 01101112 55700203 0405 | |
| 54 | ||
| 55 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t2.obj %t.obj %t1.obj | |
| 56 | # RUN: llvm-readobj --sections --section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE6 | |
| 57 | # CASE6-NEXT: 01101112 02030455 7005 | |
| 58 | ||
| 59 | # CHECK-NEXT: ) | |
| 60 | ||
| 61 | --- !COFF | |
| 62 | header: | |
| 63 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 64 | Characteristics: [ ] | |
| 65 | sections: | |
| 66 | - Name: '.CRT$XCA' | |
| 67 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 68 | Alignment: 1 | |
| 69 | SectionData: 01 | |
| 70 | - Name: '.CRT$XCU' | |
| 71 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 72 | Alignment: 1 | |
| 73 | SectionData: 02 | |
| 74 | - Name: '.CRT$XCU' | |
| 75 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_LNK_COMDAT ] | |
| 76 | Alignment: 1 | |
| 77 | SectionData: 03 | |
| 78 | - Name: '.CRT$XCU' | |
| 79 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 80 | Alignment: 1 | |
| 81 | SectionData: 04 | |
| 82 | - Name: '.CRT$XCZ' | |
| 83 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] | |
| 84 | Alignment: 1 | |
| 85 | SectionData: 05 | |
| 86 | symbols: | |
| 87 | - Name: '.CRT$XCU' | |
| 88 | Value: 0 | |
| 89 | SectionNumber: 3 | |
| 90 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 91 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 92 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 93 | SectionDefinition: | |
| 94 | Length: 1 | |
| 95 | NumberOfRelocations: 0 | |
| 96 | NumberOfLinenumbers: 0 | |
| 97 | CheckSum: 1 | |
| 98 | Number: 2 | |
| 99 | Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE | |
| 100 | ... |
deps/lld/test/COFF/debug-reloc.s+4-4| ... | ... | @@ -3,10 +3,10 @@ |
| 3 | 3 | # RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj |
| 4 | 4 | |
| 5 | 5 | # RUN: lld-link -lldmingw -debug:dwarf -out:%t.exe -entry:mainfunc -subsystem:console %t.obj |
| 6 | # RUN: llvm-readobj -sections %t.exe | FileCheck %s -check-prefix SECTIONS | |
| 7 | # RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck %s -check-prefix RELOCS | |
| 8 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s -check-prefix HEADERS | |
| 9 | # RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck %s -check-prefix DEBUG | |
| 6 | # RUN: llvm-readobj --sections %t.exe | FileCheck %s -check-prefix SECTIONS | |
| 7 | # RUN: llvm-readobj --coff-basereloc %t.exe | FileCheck %s -check-prefix RELOCS | |
| 8 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck %s -check-prefix HEADERS | |
| 9 | # RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck %s -check-prefix DEBUG | |
| 10 | 10 | |
| 11 | 11 | # SECTIONS: Number: 3 |
| 12 | 12 | # SECTIONS-NEXT: Name: .buildid (2E 62 75 69 6C 64 69 64) |
deps/lld/test/COFF/def-export-stdcall.s+7-7| ... | ... | @@ -1,9 +1,9 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=i686-windows-msvc %s -o %t.obj |
| 3 | 3 | # RUN: echo -e "LIBRARY foo\nEXPORTS\n stdcall\n fastcall\n vectorcall\n _underscored" > %t.def |
| 4 | # RUN: lld-link -entry:dllmain -dll -def:%t.def %t.obj -out:%t.dll -implib:%t.lib | |
| 4 | # RUN: lld-link -safeseh:no -entry:dllmain -dll -def:%t.def %t.obj -out:%t.dll -implib:%t.lib | |
| 5 | 5 | # RUN: llvm-readobj %t.lib | FileCheck -check-prefix UNDECORATED-IMPLIB %s |
| 6 | # RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix UNDECORATED-EXPORTS %s | |
| 6 | # RUN: llvm-readobj --coff-exports %t.dll | FileCheck -check-prefix UNDECORATED-EXPORTS %s | |
| 7 | 7 | |
| 8 | 8 | # UNDECORATED-IMPLIB: Name type: noprefix |
| 9 | 9 | # UNDECORATED-IMPLIB-NEXT: __imp___underscored |
| ... | ... | @@ -25,9 +25,9 @@ |
| 25 | 25 | |
| 26 | 26 | |
| 27 | 27 | # RUN: echo -e "LIBRARY foo\nEXPORTS\n _stdcall@8\n @fastcall@8\n vectorcall@@8" > %t.def |
| 28 | # RUN: lld-link -entry:dllmain -dll -def:%t.def %t.obj -out:%t.dll -implib:%t.lib | |
| 28 | # RUN: lld-link -safeseh:no -entry:dllmain -dll -def:%t.def %t.obj -out:%t.dll -implib:%t.lib | |
| 29 | 29 | # RUN: llvm-readobj %t.lib | FileCheck -check-prefix DECORATED-IMPLIB %s |
| 30 | # RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix DECORATED-EXPORTS %s | |
| 30 | # RUN: llvm-readobj --coff-exports %t.dll | FileCheck -check-prefix DECORATED-EXPORTS %s | |
| 31 | 31 | |
| 32 | 32 | # DECORATED-IMPLIB: Name type: name |
| 33 | 33 | # DECORATED-IMPLIB-NEXT: __imp_@fastcall@8 |
| ... | ... | @@ -48,7 +48,7 @@ |
| 48 | 48 | # RUN: echo -e "LIBRARY foo\nEXPORTS\n stdcall@8\n @fastcall@8\n vectorcall@@8" > %t.def |
| 49 | 49 | # RUN: lld-link -lldmingw -entry:dllmain -dll -def:%t.def %t.obj -out:%t.dll -implib:%t.lib |
| 50 | 50 | # RUN: llvm-readobj %t.lib | FileCheck -check-prefix DECORATED-MINGW-IMPLIB %s |
| 51 | # RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix DECORATED-MINGW-EXPORTS %s | |
| 51 | # RUN: llvm-readobj --coff-exports %t.dll | FileCheck -check-prefix DECORATED-MINGW-EXPORTS %s | |
| 52 | 52 | |
| 53 | 53 | # DECORATED-MINGW-IMPLIB: Name type: name |
| 54 | 54 | # DECORATED-MINGW-IMPLIB-NEXT: __imp_@fastcall@8 |
| ... | ... | @@ -68,11 +68,11 @@ |
| 68 | 68 | |
| 69 | 69 | # RUN: lld-link -lldmingw -kill-at -entry:dllmain -dll -def:%t.def %t.obj -out:%t.dll -implib:%t.lib |
| 70 | 70 | # RUN: llvm-readobj %t.lib | FileCheck -check-prefix MINGW-KILL-AT-IMPLIB %s |
| 71 | # RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix MINGW-KILL-AT-EXPORTS %s | |
| 71 | # RUN: llvm-readobj --coff-exports %t.dll | FileCheck -check-prefix MINGW-KILL-AT-EXPORTS %s | |
| 72 | 72 | |
| 73 | 73 | # RUN: lld-link -lldmingw -kill-at -entry:dllmain -dll %t.obj -out:%t.dll -implib:%t.lib |
| 74 | 74 | # RUN: llvm-readobj %t.lib | FileCheck -check-prefix MINGW-KILL-AT-IMPLIB %s |
| 75 | # RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix MINGW-KILL-AT-EXPORTS %s | |
| 75 | # RUN: llvm-readobj --coff-exports %t.dll | FileCheck -check-prefix MINGW-KILL-AT-EXPORTS %s | |
| 76 | 76 | |
| 77 | 77 | # MINGW-KILL-AT-IMPLIB: Name type: noprefix |
| 78 | 78 | # MINGW-KILL-AT-IMPLIB: __imp__fastcall |
deps/lld/test/COFF/delayimports-armnt.yaml+5-4| ... | ... | @@ -3,8 +3,8 @@ |
| 3 | 3 | # RUN: lld-link %t.obj %p/Inputs/library.lib /subsystem:console \ |
| 4 | 4 | # RUN: /entry:mainCRTStartup /alternatename:__delayLoadHelper2=mainCRTStartup \ |
| 5 | 5 | # RUN: /delayload:library.dll /out:%t.exe |
| 6 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s | |
| 7 | # RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s | |
| 6 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s | |
| 7 | # RUN: llvm-readobj --coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s | |
| 8 | 8 | # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s |
| 9 | 9 | |
| 10 | 10 | # IMPORT: Format: COFF-ARM |
| ... | ... | @@ -35,7 +35,7 @@ |
| 35 | 35 | # BASEREL-NEXT: } |
| 36 | 36 | # BASEREL-NEXT: Entry { |
| 37 | 37 | # BASEREL-NEXT: Type: ARM_MOV32(T) |
| 38 | # BASEREL-NEXT: Address: 0x1022 | |
| 38 | # BASEREL-NEXT: Address: 0x1026 | |
| 39 | 39 | # BASEREL-NEXT: } |
| 40 | 40 | # BASEREL-NEXT: Entry { |
| 41 | 41 | # BASEREL-NEXT: Type: ABSOLUTE |
| ... | ... | @@ -53,13 +53,14 @@ |
| 53 | 53 | # |
| 54 | 54 | # DISASM: 40100c: 43 f2 08 0c movw r12, #12296 |
| 55 | 55 | # DISASM-NEXT: c0 f2 40 0c movt r12, #64 |
| 56 | # DISASM-NEXT: 00 f0 00 b8 b.w #0 | |
| 56 | 57 | # DISASM-NEXT: 2d e9 0f 48 push.w {r0, r1, r2, r3, r11, lr} |
| 57 | 58 | # DISASM-NEXT: 0d f2 10 0b addw r11, sp, #16 |
| 58 | 59 | # DISASM-NEXT: 2d ed 10 0b vpush {d0, d1, d2, d3, d4, d5, d6, d7} |
| 59 | 60 | # DISASM-NEXT: 61 46 mov r1, r12 |
| 60 | 61 | # DISASM-NEXT: 42 f2 00 00 movw r0, #8192 |
| 61 | 62 | # DISASM-NEXT: c0 f2 40 00 movt r0, #64 |
| 62 | # DISASM-NEXT: ff f7 e9 ff bl #-46 | |
| 63 | # DISASM-NEXT: ff f7 e7 ff bl #-50 | |
| 63 | 64 | # DISASM-NEXT: 84 46 mov r12, r0 |
| 64 | 65 | # DISASM-NEXT: bd ec 10 0b vpop {d0, d1, d2, d3, d4, d5, d6, d7} |
| 65 | 66 | # DISASM-NEXT: bd e8 0f 48 pop.w {r0, r1, r2, r3, r11, lr} |
deps/lld/test/COFF/delayimports.test+4-4| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | 1 | # RUN: lld-link /out:%t.exe /entry:main /subsystem:console \ |
| 2 | 2 | # RUN: %p/Inputs/hello64.obj %p/Inputs/std64.lib /delayload:STD64.DLL \ |
| 3 | 3 | # RUN: /alternatename:__delayLoadHelper2=main |
| 4 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s | |
| 5 | # RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s | |
| 4 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s | |
| 5 | # RUN: llvm-readobj --coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s | |
| 6 | 6 | |
| 7 | 7 | IMPORT: DelayImport { |
| 8 | 8 | IMPORT-NEXT: Name: std64.dll |
| ... | ... | @@ -18,11 +18,11 @@ IMPORT-NEXT: Address: 0x140001066 |
| 18 | 18 | IMPORT-NEXT: } |
| 19 | 19 | IMPORT-NEXT: Import { |
| 20 | 20 | IMPORT-NEXT: Symbol: (50) |
| 21 | IMPORT-NEXT: Address: 0x1400010BD | |
| 21 | IMPORT-NEXT: Address: 0x140001072 | |
| 22 | 22 | IMPORT-NEXT: } |
| 23 | 23 | IMPORT-NEXT: Import { |
| 24 | 24 | IMPORT-NEXT: Symbol: MessageBoxA (0) |
| 25 | IMPORT-NEXT: Address: 0x140001114 | |
| 25 | IMPORT-NEXT: Address: 0x14000107E | |
| 26 | 26 | IMPORT-NEXT: } |
| 27 | 27 | IMPORT-NEXT: } |
| 28 | 28 |
deps/lld/test/COFF/delayimports32.test+20-22| ... | ... | @@ -1,10 +1,10 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj |
| 3 | # RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \ | |
| 3 | # RUN: lld-link -safeseh:no %t.obj %p/Inputs/std32.lib /subsystem:console \ | |
| 4 | 4 | # RUN: /entry:main@0 /alternatename:___delayLoadHelper2@8=_main@0 \ |
| 5 | 5 | # RUN: /delayload:std32.dll /out:%t.exe |
| 6 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s | |
| 7 | # RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s | |
| 6 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s | |
| 7 | # RUN: llvm-readobj --coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s | |
| 8 | 8 | # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s |
| 9 | 9 | |
| 10 | 10 | IMPORT: Format: COFF-i386 |
| ... | ... | @@ -24,7 +24,7 @@ IMPORT-NEXT: Address: 0x401029 |
| 24 | 24 | IMPORT-NEXT: } |
| 25 | 25 | IMPORT-NEXT: Import { |
| 26 | 26 | IMPORT-NEXT: Symbol: MessageBoxA (0) |
| 27 | IMPORT-NEXT: Address: 0x40103E | |
| 27 | IMPORT-NEXT: Address: 0x401033 | |
| 28 | 28 | IMPORT-NEXT: } |
| 29 | 29 | IMPORT-NEXT: } |
| 30 | 30 | |
| ... | ... | @@ -47,19 +47,19 @@ BASEREL-NEXT: Address: 0x1025 |
| 47 | 47 | BASEREL-NEXT: } |
| 48 | 48 | BASEREL-NEXT: Entry { |
| 49 | 49 | BASEREL-NEXT: Type: HIGHLOW |
| 50 | BASEREL-NEXT: Address: 0x102C | |
| 50 | BASEREL-NEXT: Address: 0x102A | |
| 51 | 51 | BASEREL-NEXT: } |
| 52 | 52 | BASEREL-NEXT: Entry { |
| 53 | 53 | BASEREL-NEXT: Type: HIGHLOW |
| 54 | BASEREL-NEXT: Address: 0x1031 | |
| 54 | BASEREL-NEXT: Address: 0x1034 | |
| 55 | 55 | BASEREL-NEXT: } |
| 56 | 56 | BASEREL-NEXT: Entry { |
| 57 | 57 | BASEREL-NEXT: Type: HIGHLOW |
| 58 | 58 | BASEREL-NEXT: Address: 0x1041 |
| 59 | 59 | BASEREL-NEXT: } |
| 60 | 60 | BASEREL-NEXT: Entry { |
| 61 | BASEREL-NEXT: Type: HIGHLOW | |
| 62 | BASEREL-NEXT: Address: 0x1046 | |
| 61 | BASEREL-NEXT: Type: ABSOLUTE | |
| 62 | BASEREL-NEXT: Address: 0x1000 | |
| 63 | 63 | BASEREL-NEXT: } |
| 64 | 64 | BASEREL-NEXT: Entry { |
| 65 | 65 | BASEREL-NEXT: Type: HIGHLOW |
| ... | ... | @@ -71,17 +71,15 @@ BASEREL-NEXT: Address: 0x3024 |
| 71 | 71 | BASEREL-NEXT: } |
| 72 | 72 | BASEREL-NEXT: ] |
| 73 | 73 | |
| 74 | DISASM: 102b: 68 20 30 40 00 pushl $4206624 | |
| 75 | DISASM-NEXT: 1030: 68 00 20 40 00 pushl $4202496 | |
| 76 | DISASM-NEXT: 1035: e8 c6 ff ff ff calll -58 <.text> | |
| 77 | DISASM-NEXT: 103a: 5a popl %edx | |
| 78 | DISASM-NEXT: 103b: 59 popl %ecx | |
| 79 | DISASM-NEXT: 103c: ff e0 jmpl *%eax | |
| 80 | DISASM-NEXT: 103e: 51 pushl %ecx | |
| 81 | DISASM-NEXT: 103f: 52 pushl %edx | |
| 82 | DISASM-NEXT: 1040: 68 24 30 40 00 pushl $4206628 | |
| 83 | DISASM-NEXT: 1045: 68 00 20 40 00 pushl $4202496 | |
| 84 | DISASM-NEXT: 104a: e8 b1 ff ff ff calll -79 <.text> | |
| 85 | DISASM-NEXT: 104f: 5a popl %edx | |
| 86 | DISASM-NEXT: 1050: 59 popl %ecx | |
| 87 | DISASM-NEXT: 1051: ff e0 jmpl *%eax | |
| 74 | DISASM: 1029: b8 20 30 40 00 movl $4206624, %eax | |
| 75 | DISASM-NEXT: 102e: e9 0a 00 00 00 jmp 10 <.text+0x3d> | |
| 76 | DISASM-NEXT: 1033: b8 24 30 40 00 movl $4206628, %eax | |
| 77 | DISASM-NEXT: 1038: e9 00 00 00 00 jmp 0 <.text+0x3d> | |
| 78 | DISASM-NEXT: 103d: 51 pushl %ecx | |
| 79 | DISASM-NEXT: 103e: 52 pushl %edx | |
| 80 | DISASM-NEXT: 103f: 50 pushl %eax | |
| 81 | DISASM-NEXT: 1040: 68 00 20 40 00 pushl $4202496 | |
| 82 | DISASM-NEXT: 1045: e8 b6 ff ff ff calll -74 <.text> | |
| 83 | DISASM-NEXT: 104a: 5a popl %edx | |
| 84 | DISASM-NEXT: 104b: 59 popl %ecx | |
| 85 | DISASM-NEXT: 104c: ff e0 jmpl *%eax |
deps/lld/test/COFF/delayimporttables.yaml created+122| ... | ... | @@ -0,0 +1,122 @@ |
| 1 | # RUN: yaml2obj %p/Inputs/delayimporttables-dll1.yaml > %t1.obj | |
| 2 | # RUN: yaml2obj %p/Inputs/delayimporttables-dll2.yaml > %t2.obj | |
| 3 | # RUN: yaml2obj %s > %t.obj | |
| 4 | # RUN: lld-link /nodefaultlib /entry:DllMain /out:%T/delayimporttables-dll1.dll /dll /implib:%t-dll1.lib %t1.obj | |
| 5 | # RUN: lld-link /nodefaultlib /entry:DllMain /out:%T/delayimporttables-dll2.dll /dll /implib:%t-dll2.lib %t2.obj | |
| 6 | # RUN: lld-link /nodefaultlib /entry:main /out:%t.exe /delayload:delayimporttables-dll1.dll /delayload:delayimporttables-dll2.dll %t.obj %t-dll1.lib %t-dll2.lib | |
| 7 | # RUN: llvm-readobj --coff-imports %t.exe |FileCheck %s | |
| 8 | ||
| 9 | # CHECK: Format: COFF-x86-64 | |
| 10 | # CHECK-NEXT: Arch: x86_64 | |
| 11 | # CHECK-NEXT: AddressSize: 64bit | |
| 12 | # CHECK-NEXT: DelayImport { | |
| 13 | # CHECK-NEXT: Name: delayimporttables-dll1.dll | |
| 14 | # CHECK-NEXT: Attributes: 0x1 | |
| 15 | # CHECK-NEXT: ModuleHandle: 0x3000 | |
| 16 | # CHECK-NEXT: ImportAddressTable: 0x3010 | |
| 17 | # CHECK-NEXT: ImportNameTable: 0x2060 | |
| 18 | # CHECK-NEXT: BoundDelayImportTable: 0x0 | |
| 19 | # CHECK-NEXT: UnloadDelayImportTable: 0x0 | |
| 20 | # CHECK-NEXT: Import { | |
| 21 | # CHECK-NEXT: Symbol: one (0) | |
| 22 | # CHECK-NEXT: Address: 0x14000104D | |
| 23 | # CHECK-NEXT: } | |
| 24 | # CHECK-NEXT: Import { | |
| 25 | # CHECK-NEXT: Symbol: two (0) | |
| 26 | # CHECK-NEXT: Address: 0x140001059 | |
| 27 | # CHECK-NEXT: } | |
| 28 | # CHECK-NEXT: } | |
| 29 | # CHECK-NEXT: DelayImport { | |
| 30 | # CHECK-NEXT: Name: delayimporttables-dll2.dll | |
| 31 | # CHECK-NEXT: Attributes: 0x1 | |
| 32 | # CHECK-NEXT: ModuleHandle: 0x3008 | |
| 33 | # CHECK-NEXT: ImportAddressTable: 0x3028 | |
| 34 | # CHECK-NEXT: ImportNameTable: 0x2078 | |
| 35 | # CHECK-NEXT: BoundDelayImportTable: 0x0 | |
| 36 | # CHECK-NEXT: UnloadDelayImportTable: 0x0 | |
| 37 | # CHECK-NEXT: Import { | |
| 38 | # CHECK-NEXT: Symbol: left (0) | |
| 39 | # CHECK-NEXT: Address: 0x1400010B8 | |
| 40 | # CHECK-NEXT: } | |
| 41 | # CHECK-NEXT: Import { | |
| 42 | # CHECK-NEXT: Symbol: right (0) | |
| 43 | # CHECK-NEXT: Address: 0x1400010C4 | |
| 44 | # CHECK-NEXT: } | |
| 45 | # CHECK-NEXT: } | |
| 46 | ||
| 47 | --- !COFF | |
| 48 | header: | |
| 49 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 50 | Characteristics: [ ] | |
| 51 | sections: | |
| 52 | - Name: .drectve | |
| 53 | Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] | |
| 54 | Alignment: 1 | |
| 55 | SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220 | |
| 56 | - Name: '.text$mn' | |
| 57 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] | |
| 58 | Alignment: 16 | |
| 59 | SectionData: 4889542410894C24084883EC28FF1500000000FF1500000000FF1500000000FF150000000033C04883C428C3CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC488954241048894C240833C0C3 | |
| 60 | Relocations: | |
| 61 | - VirtualAddress: 15 | |
| 62 | SymbolName: __imp_one | |
| 63 | Type: IMAGE_REL_AMD64_REL32 | |
| 64 | - VirtualAddress: 21 | |
| 65 | SymbolName: __imp_two | |
| 66 | Type: IMAGE_REL_AMD64_REL32 | |
| 67 | - VirtualAddress: 27 | |
| 68 | SymbolName: __imp_left | |
| 69 | Type: IMAGE_REL_AMD64_REL32 | |
| 70 | - VirtualAddress: 33 | |
| 71 | SymbolName: __imp_right | |
| 72 | Type: IMAGE_REL_AMD64_REL32 | |
| 73 | symbols: | |
| 74 | - Name: .drectve | |
| 75 | Value: 0 | |
| 76 | SectionNumber: 1 | |
| 77 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 78 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 79 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 80 | SectionDefinition: | |
| 81 | Length: 47 | |
| 82 | NumberOfRelocations: 0 | |
| 83 | NumberOfLinenumbers: 0 | |
| 84 | CheckSum: 0 | |
| 85 | Number: 0 | |
| 86 | - Name: __imp_one | |
| 87 | Value: 0 | |
| 88 | SectionNumber: 0 | |
| 89 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 90 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 91 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 92 | - Name: __imp_two | |
| 93 | Value: 0 | |
| 94 | SectionNumber: 0 | |
| 95 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 96 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 97 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 98 | - Name: __imp_left | |
| 99 | Value: 0 | |
| 100 | SectionNumber: 0 | |
| 101 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 102 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 103 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 104 | - Name: __imp_right | |
| 105 | Value: 0 | |
| 106 | SectionNumber: 0 | |
| 107 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 108 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 109 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 110 | - Name: main | |
| 111 | Value: 0 | |
| 112 | SectionNumber: 2 | |
| 113 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 114 | ComplexType: IMAGE_SYM_DTYPE_FUNCTION | |
| 115 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 116 | - Name: __delayLoadHelper2 | |
| 117 | Value: 64 | |
| 118 | SectionNumber: 2 | |
| 119 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 120 | ComplexType: IMAGE_SYM_DTYPE_FUNCTION | |
| 121 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 122 | ... |
deps/lld/test/COFF/dll.test+2-2| ... | ... | @@ -42,10 +42,10 @@ EXPORT-LTO-NEXT: 3 0x1030 exportfn3 |
| 42 | 42 | # RUN: /export:exportfn1 /export:exportfn2 |
| 43 | 43 | # RUN: yaml2obj < %p/Inputs/import.yaml > %t2.obj |
| 44 | 44 | # RUN: lld-link /out:%t2.exe /entry:main %t2.obj %t2.lib |
| 45 | # RUN: llvm-readobj -coff-imports %t2.exe | FileCheck -check-prefix=IMPORT %s | |
| 45 | # RUN: llvm-readobj --coff-imports %t2.exe | FileCheck -check-prefix=IMPORT %s | |
| 46 | 46 | |
| 47 | 47 | # RUN: lld-link /out:%t2.lto.exe /entry:main %t2.obj %t.lto.lib |
| 48 | # RUN: llvm-readobj -coff-imports %t2.lto.exe | FileCheck -check-prefix=IMPORT %s | |
| 48 | # RUN: llvm-readobj --coff-imports %t2.lto.exe | FileCheck -check-prefix=IMPORT %s | |
| 49 | 49 | |
| 50 | 50 | IMPORT: Symbol: exportfn1 |
| 51 | 51 | IMPORT: Symbol: exportfn2 |
deps/lld/test/COFF/dllexport.s+2-2| ... | ... | @@ -1,9 +1,9 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=i686-windows-msvc %s -o %t.obj |
| 3 | 3 | |
| 4 | # RUN: lld-link -entry:dllmain -dll %t.obj -out:%t.dll -implib:%t.lib | |
| 4 | # RUN: lld-link -safeseh:no -entry:dllmain -dll %t.obj -out:%t.dll -implib:%t.lib | |
| 5 | 5 | # RUN: llvm-readobj %t.lib | FileCheck -check-prefix DECORATED-IMPLIB %s |
| 6 | # RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix DECORATED-EXPORTS %s | |
| 6 | # RUN: llvm-readobj --coff-exports %t.dll | FileCheck -check-prefix DECORATED-EXPORTS %s | |
| 7 | 7 | |
| 8 | 8 | # DECORATED-IMPLIB: Name type: name |
| 9 | 9 | # DECORATED-IMPLIB-NEXT: __imp_@fastcall@8 |
deps/lld/test/COFF/dllimport-gc.test+2-2| ... | ... | @@ -6,11 +6,11 @@ |
| 6 | 6 | # RUN: yaml2obj < %s > %t.obj |
| 7 | 7 | |
| 8 | 8 | # RUN: lld-link /out:%t1.exe /entry:main %t.obj %t-oldname.obj %t.lib |
| 9 | # RUN: llvm-readobj -coff-imports %t1.exe | FileCheck -check-prefix=REF %s | |
| 9 | # RUN: llvm-readobj --coff-imports %t1.exe | FileCheck -check-prefix=REF %s | |
| 10 | 10 | # REF-NOT: Symbol: exportfn1 |
| 11 | 11 | |
| 12 | 12 | # RUN: lld-link /out:%t2.exe /entry:main %t.obj %t-oldname.obj %t.lib /opt:noref |
| 13 | # RUN: llvm-readobj -coff-imports %t2.exe | FileCheck -check-prefix=NOREF %s | |
| 13 | # RUN: llvm-readobj --coff-imports %t2.exe | FileCheck -check-prefix=NOREF %s | |
| 14 | 14 | # NOREF: Symbol: exportfn1 |
| 15 | 15 | |
| 16 | 16 | --- !COFF |
deps/lld/test/COFF/driver.test+23-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: not lld-link nosuchfile.obj >& %t.log |
| 2 | 2 | # RUN: FileCheck -check-prefix=MISSING %s < %t.log |
| 3 | MISSING: nosuchfile.obj: {{[Nn]}}o such file or directory | |
| 3 | MISSING: 'nosuchfile.obj': {{[Nn]}}o such file or directory | |
| 4 | 4 | |
| 5 | 5 | # RUN: lld-link --version | FileCheck -check-prefix=VERSION %s |
| 6 | 6 | VERSION: {{LLD [0-9]+\.[0-9]+}} |
| ... | ... | @@ -15,3 +15,25 @@ LIBHELP: OVERVIEW: LLVM Lib |
| 15 | 15 | |
| 16 | 16 | # RUN: not lld-link /WX /lib 2>&1 | FileCheck -check-prefix=LIBBAD %s |
| 17 | 17 | LIBBAD: ignoring /lib since it's not the first argument |
| 18 | ||
| 19 | # RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj | |
| 20 | # RUN: not lld-link /out:/ %t.obj 2>&1 | FileCheck -check-prefix=DIR %s | |
| 21 | DIR: cannot open output file | |
| 22 | ||
| 23 | # RUN: not lld-link -version 2>&1 | FileCheck -check-prefix=SPELLVERSION %s | |
| 24 | SPELLVERSION: ignoring unknown argument '-version', did you mean '--version' | |
| 25 | SPELLVERSION: no input files | |
| 26 | ||
| 27 | # RUN: not lld-link -nodefaultlibs 2>&1 | FileCheck -check-prefix=SPELLNODEFAULTLIB %s | |
| 28 | SPELLNODEFAULTLIB: ignoring unknown argument '-nodefaultlibs', did you mean '-nodefaultlib' | |
| 29 | SPELLNODEFAULTLIB: no input files | |
| 30 | ||
| 31 | # RUN: not lld-link /nodefaultlibs 2>&1 | FileCheck -check-prefix=SPELLNODEFAULTLIB_SLASH %s | |
| 32 | SPELLNODEFAULTLIB_SLASH: could not open '/nodefaultlibs': {{.*}}; did you mean '/nodefaultlib' | |
| 33 | SPELLNODEFAULTLIB_SLASH-NOT: no input files | |
| 34 | ||
| 35 | # Getting flags as typo corrections for normal input files is a side effect | |
| 36 | # of how spell checking for /-style flags is implemented. | |
| 37 | # RUN: not lld-link force 2>&1 | FileCheck -check-prefix=SPELLFORCE %s | |
| 38 | SPELLFORCE: could not open 'force': {{.*}}; did you mean '/force' | |
| 39 | SPELLFORCE-NOT: no input files |
deps/lld/test/COFF/eh_frame_suffix_sorting.s created+39| ... | ... | @@ -0,0 +1,39 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -triple=i686-windows-gnu %s -filetype=obj -o %t.main.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=i686-windows-gnu \ | |
| 5 | # RUN: %p/Inputs/eh_frame_terminator-crtend.s -o %t.crtend.o | |
| 6 | ||
| 7 | # RUN: lld-link -lldmingw -entry:main %t.main.o %t.crtend.o -out:%t.exe | |
| 8 | # RUN: llvm-objdump -s %t.exe | FileCheck %s | |
| 9 | ||
| 10 | # Check that the contents of .eh_frame$foo was placed before .eh_frame from | |
| 11 | # crtend.o, even if the former had a section name suffix. | |
| 12 | ||
| 13 | # CHECK: Contents of section .eh_fram: | |
| 14 | # CHECK: 403000 4203 | |
| 15 | ||
| 16 | .text | |
| 17 | .def _main; | |
| 18 | .scl 2; | |
| 19 | .type 32; | |
| 20 | .endef | |
| 21 | .globl _main | |
| 22 | .p2align 4, 0x90 | |
| 23 | _main: | |
| 24 | call _foo | |
| 25 | ret | |
| 26 | ||
| 27 | .section .eh_frame$foo,"dr" | |
| 28 | .linkonce discard | |
| 29 | .byte 0x42 | |
| 30 | ||
| 31 | .def _foo; | |
| 32 | .scl 2; | |
| 33 | .type 32; | |
| 34 | .endef | |
| 35 | .section .text$foo,"xr",discard,foo | |
| 36 | .globl _foo | |
| 37 | .p2align 4 | |
| 38 | _foo: | |
| 39 | ret |
deps/lld/test/COFF/eh_frame_terminator.s created+26| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-windows-gnu %s -o %t.main.o | |
| 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-windows-gnu \ | |
| 4 | // RUN: %p/Inputs/eh_frame_terminator-otherfunc.s -o %t.otherfunc.o | |
| 5 | // RUN: llvm-mc -filetype=obj -triple=x86_64-windows-gnu \ | |
| 6 | // RUN: %p/Inputs/eh_frame_terminator-crtend.s -o %t.crtend.o | |
| 7 | // RUN: rm -f %t.otherfunc.lib | |
| 8 | // RUN: llvm-ar rcs %t.otherfunc.lib %t.otherfunc.o | |
| 9 | // RUN: lld-link -lldmingw %t.main.o %t.otherfunc.lib %t.crtend.o -out:%t.exe | |
| 10 | // RUN: llvm-objdump -s %t.exe | FileCheck %s | |
| 11 | ||
| 12 | .text | |
| 13 | .globl main | |
| 14 | main: | |
| 15 | call otherfunc | |
| 16 | ret | |
| 17 | ||
| 18 | .globl mainCRTStartup | |
| 19 | mainCRTStartup: | |
| 20 | call main | |
| 21 | ||
| 22 | .section .eh_frame,"dr" | |
| 23 | .byte 1 | |
| 24 | ||
| 25 | // CHECK: Contents of section .eh_fram: | |
| 26 | // CHECK-NEXT: 140003000 010203 |
deps/lld/test/COFF/entry-drectve.test+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | # RUN: lld-link /subsystem:console /out:%t.exe %t.obj | |
| 2 | # RUN: lld-link -safeseh:no /subsystem:console /out:%t.exe %t.obj | |
| 3 | 3 | |
| 4 | 4 | --- !COFF |
| 5 | 5 | header: |
deps/lld/test/COFF/entry-inference-mingw.s+3-3| ... | ... | @@ -5,9 +5,9 @@ |
| 5 | 5 | # RUN: lld-link -lldmingw %t.o -out:%t-cui.exe -subsystem:console 2>&1 | FileCheck -allow-empty -check-prefix=LINK %s |
| 6 | 6 | # RUN: lld-link -lldmingw %t.o -out:%t-gui.exe -subsystem:windows 2>&1 | FileCheck -allow-empty -check-prefix=LINK %s |
| 7 | 7 | |
| 8 | # RUN: llvm-readobj -file-headers %t-default.exe | FileCheck -check-prefix=CUI %s | |
| 9 | # RUN: llvm-readobj -file-headers %t-cui.exe | FileCheck -check-prefix=CUI %s | |
| 10 | # RUN: llvm-readobj -file-headers %t-gui.exe | FileCheck -check-prefix=GUI %s | |
| 8 | # RUN: llvm-readobj --file-headers %t-default.exe | FileCheck -check-prefix=CUI %s | |
| 9 | # RUN: llvm-readobj --file-headers %t-cui.exe | FileCheck -check-prefix=CUI %s | |
| 10 | # RUN: llvm-readobj --file-headers %t-gui.exe | FileCheck -check-prefix=GUI %s | |
| 11 | 11 | |
| 12 | 12 | # Check that this doesn't print any warnings. |
| 13 | 13 | # LINK-NOT: found both wmain and main |
deps/lld/test/COFF/entry-inference332.test+2-2| ... | ... | @@ -1,9 +1,9 @@ |
| 1 | 1 | # RUN: sed -e s/ENTRYNAME/_mainCRTStartup/ %s | yaml2obj > %t.obj |
| 2 | # RUN: lld-link /subsystem:console /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1 | |
| 2 | # RUN: lld-link -safeseh:no /subsystem:console /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1 | |
| 3 | 3 | # RUN: FileCheck %s < %t.log |
| 4 | 4 | |
| 5 | 5 | # RUN: sed -e s/ENTRYNAME/?mainCRTStartup@@YAHXZ/ %s | yaml2obj > %t.obj |
| 6 | # RUN: lld-link /subsystem:console /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1 | |
| 6 | # RUN: lld-link -safeseh:no /subsystem:console /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1 | |
| 7 | 7 | # RUN: FileCheck %s < %t.log |
| 8 | 8 | |
| 9 | 9 | # CHECK: Entry name inferred: _mainCRTStartup |
deps/lld/test/COFF/error-limit.test+10-10| ... | ... | @@ -1,26 +1,26 @@ |
| 1 | 1 | RUN: not lld-link 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 \ |
| 2 | 2 | RUN: 21 22 2>&1 | FileCheck -check-prefix=DEFAULT %s |
| 3 | 3 | |
| 4 | DEFAULT: could not open 01 | |
| 5 | DEFAULT: could not open 20 | |
| 4 | DEFAULT: could not open '01' | |
| 5 | DEFAULT: could not open '20' | |
| 6 | 6 | DEFAULT-NEXT: too many errors emitted, stopping now (use /errorlimit:0 to see all errors) |
| 7 | DEFAULT-NOT: could not open 21 | |
| 7 | DEFAULT-NOT: could not open '21' | |
| 8 | 8 | |
| 9 | 9 | RUN: not lld-link /errorlimit:5 01 02 03 04 05 06 07 08 09 10 2>&1 \ |
| 10 | 10 | RUN: | FileCheck -check-prefix=LIMIT5 %s |
| 11 | 11 | |
| 12 | LIMIT5: could not open 01 | |
| 13 | LIMIT5: could not open 05 | |
| 12 | LIMIT5: could not open '01' | |
| 13 | LIMIT5: could not open '05' | |
| 14 | 14 | LIMIT5-NEXT: too many errors emitted, stopping now (use /errorlimit:0 to see all errors) |
| 15 | LIMIT5-NOT: could not open 06 | |
| 15 | LIMIT5-NOT: could not open '06' | |
| 16 | 16 | |
| 17 | 17 | RUN: not lld-link /errorlimit:0 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 \ |
| 18 | 18 | RUN: 16 17 18 19 20 21 22 2>&1 | FileCheck -check-prefix=UNLIMITED %s |
| 19 | 19 | |
| 20 | UNLIMITED: could not open 01 | |
| 21 | UNLIMITED: could not open 20 | |
| 22 | UNLIMITED: could not open 21 | |
| 23 | UNLIMITED: could not open 22 | |
| 20 | UNLIMITED: could not open '01' | |
| 21 | UNLIMITED: could not open '20' | |
| 22 | UNLIMITED: could not open '21' | |
| 23 | UNLIMITED: could not open '22' | |
| 24 | 24 | UNLIMITED-NOT: too many errors emitted, stopping now (use /errorlimit:0 to see all errors) |
| 25 | 25 | |
| 26 | 26 | RUN: not lld-link /errorlimit:XYZ 01 02 03 04 05 06 07 08 09 10 11 12 13 14 \ |
deps/lld/test/COFF/exclude-all.s created+31| ... | ... | @@ -0,0 +1,31 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -triple=i686-windows-gnu %s -filetype=obj -o %t.obj | |
| 4 | ||
| 5 | # RUN: lld-link -lldmingw -exclude-all-symbols -dll -out:%t.dll -entry:DllMainCRTStartup@12 %t.obj | |
| 6 | # RUN: llvm-readobj --coff-exports %t.dll | FileCheck %s -check-prefix=NO-EXPORTS | |
| 7 | ||
| 8 | # NO-EXPORTS-NOT: Name: | |
| 9 | ||
| 10 | .global _foobar | |
| 11 | .global _DllMainCRTStartup@12 | |
| 12 | .global _dataSym | |
| 13 | .text | |
| 14 | _DllMainCRTStartup@12: | |
| 15 | ret | |
| 16 | _foobar: | |
| 17 | ret | |
| 18 | .data | |
| 19 | _dataSym: | |
| 20 | .int 4 | |
| 21 | ||
| 22 | # Test specifying -exclude-all-symbols, on an object file that contains | |
| 23 | # dllexport directive for some of the symbols. In this case, the dllexported | |
| 24 | # symbols are still exported. | |
| 25 | ||
| 26 | # RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj | |
| 27 | # | |
| 28 | # RUN: lld-link -safeseh:no -out:%t.dll -dll %t.obj -lldmingw -exclude-all-symbols -output-def:%t.def | |
| 29 | # RUN: llvm-readobj --coff-exports %t.dll | FileCheck -check-prefix=DLLEXPORT %s | |
| 30 | ||
| 31 | # DLLEXPORT: Name: exportfn3 |
deps/lld/test/COFF/export-all.s+5-5| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: llvm-mc -triple=i686-windows-gnu %s -filetype=obj -o %t.obj |
| 4 | 4 | |
| 5 | 5 | # RUN: lld-link -lldmingw -dll -out:%t.dll -entry:DllMainCRTStartup@12 %t.obj -implib:%t.lib |
| 6 | # RUN: llvm-readobj -coff-exports %t.dll | grep Name: | FileCheck %s | |
| 6 | # RUN: llvm-readobj --coff-exports %t.dll | grep Name: | FileCheck %s | |
| 7 | 7 | # RUN: llvm-readobj %t.lib | FileCheck -check-prefix=IMPLIB %s |
| 8 | 8 | |
| 9 | 9 | # CHECK: Name: |
| ... | ... | @@ -42,8 +42,8 @@ __imp__unexported: |
| 42 | 42 | |
| 43 | 43 | # RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj |
| 44 | 44 | # |
| 45 | # RUN: lld-link -out:%t.dll -dll %t.obj -lldmingw -export-all-symbols -output-def:%t.def | |
| 46 | # RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix=CHECK2 %s | |
| 45 | # RUN: lld-link -safeseh:no -out:%t.dll -dll %t.obj -lldmingw -export-all-symbols -output-def:%t.def | |
| 46 | # RUN: llvm-readobj --coff-exports %t.dll | FileCheck -check-prefix=CHECK2 %s | |
| 47 | 47 | # RUN: cat %t.def | FileCheck -check-prefix=CHECK2-DEF %s |
| 48 | 48 | |
| 49 | 49 | # Note, this will actually export _DllMainCRTStartup as well, since |
| ... | ... | @@ -69,7 +69,7 @@ __imp__unexported: |
| 69 | 69 | # RUN: llvm-ar rcs %T/libs/libmingwex.a %T/libs/mingwfunc.o |
| 70 | 70 | # RUN: echo -e ".global crtfunc\n.text\ncrtfunc:\nret\n" > %T/libs/crtfunc.s |
| 71 | 71 | # RUN: llvm-mc -triple=x86_64-windows-gnu %T/libs/crtfunc.s -filetype=obj -o %T/libs/crt2.o |
| 72 | # RUN: lld-link -out:%t.dll -dll -entry:DllMainCRTStartup %t.main.obj -lldmingw %T/libs/crt2.o %T/libs/libmingwex.a -output-def:%t.def | |
| 72 | # RUN: lld-link -safeseh:no -out:%t.dll -dll -entry:DllMainCRTStartup %t.main.obj -lldmingw %T/libs/crt2.o %T/libs/libmingwex.a -output-def:%t.def | |
| 73 | 73 | # RUN: echo "EOF" >> %t.def |
| 74 | 74 | # RUN: cat %t.def | FileCheck -check-prefix=CHECK-EXCLUDE %s |
| 75 | 75 | |
| ... | ... | @@ -80,7 +80,7 @@ __imp__unexported: |
| 80 | 80 | # Test that libraries included with -wholearchive: are autoexported, even if |
| 81 | 81 | # they are in a library that otherwise normally would be excluded. |
| 82 | 82 | |
| 83 | # RUN: lld-link -out:%t.dll -dll -entry:DllMainCRTStartup %t.main.obj -lldmingw %T/libs/crt2.o -wholearchive:%T/libs/libmingwex.a -output-def:%t.def | |
| 83 | # RUN: lld-link -safeseh:no -out:%t.dll -dll -entry:DllMainCRTStartup %t.main.obj -lldmingw %T/libs/crt2.o -wholearchive:%T/libs/libmingwex.a -output-def:%t.def | |
| 84 | 84 | # RUN: echo "EOF" >> %t.def |
| 85 | 85 | # RUN: cat %t.def | FileCheck -check-prefix=CHECK-WHOLEARCHIVE %s |
| 86 | 86 |
deps/lld/test/COFF/export-stdcall.s created+32| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -triple i686-windows-msvc %s -o %t.obj -filetype=obj | |
| 3 | # RUN: lld-link -safeseh:no %t.obj -out:%t.dll -dll -nodefaultlib -noentry -export:foo_std=bar_std -export:foo_fast=bar_fast | |
| 4 | # RUN: llvm-nm %t.lib | FileCheck %s | |
| 5 | ||
| 6 | # MSVC fudges the lookup of 'bar' to allow it to find the stdcall function | |
| 7 | # _bar_std@8, and then exports _foo_std@8. Same for fastcall and other mangling | |
| 8 | # schemes. | |
| 9 | ||
| 10 | # CHECK: export-stdcall.s.tmp.dll: | |
| 11 | # CHECK: 00000000 T @foo_fast@8 | |
| 12 | # CHECK: 00000000 T __imp_@foo_fast@8 | |
| 13 | ||
| 14 | # CHECK: export-stdcall.s.tmp.dll: | |
| 15 | # CHECK: 00000000 T __imp__foo_std@8 | |
| 16 | # CHECK: 00000000 T _foo_std@8 | |
| 17 | ||
| 18 | 	.text | |
| 19 | 	.def	 _bar_std@8; .scl	2; .type	32; .endef | |
| 20 | 	.globl	_bar_std@8 | |
| 21 | _bar_std@8: | |
| 22 | 	movl	8(%esp), %eax | |
| 23 | 	movl	4(%esp), %ecx | |
| 24 | 	leal	42(%ecx,%eax), %eax | |
| 25 | 	retl	$8 | |
| 26 | ||
| 27 | 	.def	 @bar_fast@8; .scl	2; .type	32; .endef | |
| 28 | 	.globl	@bar_fast@8 | |
| 29 | @bar_fast@8: | |
| 30 | 	leal	42(%ecx,%eax), %eax | |
| 31 | 	retl | |
| 32 |
deps/lld/test/COFF/export-weak-alias.s created+33| ... | ... | @@ -0,0 +1,33 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -triple x86_64-windows-msvc %s -o %t.obj -filetype=obj | |
| 3 | # RUN: lld-link %t.obj -out:%t.dll -dll -nodefaultlib -noentry | |
| 4 | # RUN: llvm-nm %t.lib | FileCheck %s | |
| 5 | ||
| 6 | # CHECK: export-weak-alias.s.tmp.dll: | |
| 7 | # CHECK: 00000000 T __imp_foo_dll{{$}} | |
| 8 | # CHECK: 00000000 T foo_dll{{$}} | |
| 9 | ||
| 10 | 	.text | |
| 11 | 	.def	 @feat.00; | |
| 12 | 	.scl	3; | |
| 13 | 	.type	0; | |
| 14 | 	.endef | |
| 15 | 	.globl	@feat.00 | |
| 16 | .set @feat.00, 0 | |
| 17 | 	.file	"t.c" | |
| 18 | 	.def	 foo_def; | |
| 19 | 	.scl	2; | |
| 20 | 	.type	32; | |
| 21 | 	.endef | |
| 22 | 	.globl	foo_def # -- Begin function foo_def | |
| 23 | 	.p2align	4, 0x90 | |
| 24 | foo_def: # @foo_def | |
| 25 | # %bb.0: # %entry | |
| 26 | 	movl	$42, %eax | |
| 27 | 	retq | |
| 28 | # -- End function | |
| 29 | 	.section	.drectve,"yn" | |
| 30 | 	.ascii	" /alternatename:foo=foo_def" | |
| 31 | 	.ascii	" /export:foo_dll=foo" | |
| 32 | ||
| 33 | 	.addrsig |
deps/lld/test/COFF/export32.test+10-10| ... | ... | @@ -1,11 +1,11 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | 2 | # |
| 3 | # RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 | |
| 3 | # RUN: lld-link -safeseh:no /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 | |
| 4 | 4 | # RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s |
| 5 | 5 | # |
| 6 | # RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 /merge:.edata=.rdata | |
| 6 | # RUN: lld-link -safeseh:no /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 /merge:.edata=.rdata | |
| 7 | 7 | # RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s |
| 8 | # RUN: llvm-readobj -file-headers -sections %t.dll | FileCheck -check-prefix=HEADER-MERGE %s | |
| 8 | # RUN: llvm-readobj --file-headers --sections %t.dll | FileCheck -check-prefix=HEADER-MERGE %s | |
| 9 | 9 | |
| 10 | 10 | # CHECK1: Export Table: |
| 11 | 11 | # CHECK1: DLL name: export32.test.tmp.dll |
| ... | ... | @@ -20,7 +20,7 @@ |
| 20 | 20 | # HEADER-MERGE-NEXT: VirtualSize: 0x7E |
| 21 | 21 | # HEADER-MERGE-NEXT: VirtualAddress: 0x2000 |
| 22 | 22 | |
| 23 | # RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1,@5 \ | |
| 23 | # RUN: lld-link -safeseh:no /out:%t.dll /dll %t.obj /export:exportfn1,@5 \ | |
| 24 | 24 | # RUN: /export:exportfn2 /export:mangled |
| 25 | 25 | # RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK2 %s |
| 26 | 26 | |
| ... | ... | @@ -37,7 +37,7 @@ |
| 37 | 37 | # CHECK2-NEXT: 7 0x1010 exportfn3 |
| 38 | 38 | # CHECK2-NEXT: 8 0x1010 mangled |
| 39 | 39 | |
| 40 | # RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1,@5,noname /export:exportfn2 | |
| 40 | # RUN: lld-link -safeseh:no /out:%t.dll /dll %t.obj /export:exportfn1,@5,noname /export:exportfn2 | |
| 41 | 41 | # RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK3 %s |
| 42 | 42 | |
| 43 | 43 | # CHECK3: Export Table: |
| ... | ... | @@ -51,7 +51,7 @@ |
| 51 | 51 | # CHECK3-NEXT: 5 0x1008 |
| 52 | 52 | # CHECK3-NEXT: 6 0x1010 exportfn2 |
| 53 | 53 | |
| 54 | # RUN: lld-link /out:%t.dll /dll %t.obj /export:f1=exportfn1 /export:f2=exportfn2 | |
| 54 | # RUN: lld-link -safeseh:no /out:%t.dll /dll %t.obj /export:f1=exportfn1 /export:f2=exportfn2 | |
| 55 | 55 | # RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK4 %s |
| 56 | 56 | |
| 57 | 57 | # CHECK4: Export Table: |
| ... | ... | @@ -64,12 +64,12 @@ |
| 64 | 64 | |
| 65 | 65 | # RUN: echo "EXPORTS exportfn1 @3" > %t.def |
| 66 | 66 | # RUN: echo "fn2=exportfn2 @2" >> %t.def |
| 67 | # RUN: lld-link /out:%t.dll /dll %t.obj /def:%t.def | |
| 67 | # RUN: lld-link -safeseh:no /out:%t.dll /dll %t.obj /def:%t.def | |
| 68 | 68 | # RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK5 %s |
| 69 | 69 | |
| 70 | 70 | # RUN: echo "EXPORTS exportfn1 @ 3" > %t.def |
| 71 | 71 | # RUN: echo "fn2=exportfn2 @ 2" >> %t.def |
| 72 | # RUN: lld-link /out:%t.dll /dll %t.obj /def:%t.def | |
| 72 | # RUN: lld-link -safeseh:no /out:%t.dll /dll %t.obj /def:%t.def | |
| 73 | 73 | # RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK5 %s |
| 74 | 74 | |
| 75 | 75 | # CHECK5: Export Table: |
| ... | ... | @@ -81,14 +81,14 @@ |
| 81 | 81 | # CHECK5-NEXT: 3 0x1008 exportfn1 |
| 82 | 82 | # CHECK5-NEXT: 4 0x1010 exportfn3 |
| 83 | 83 | |
| 84 | # RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \ | |
| 84 | # RUN: lld-link -safeseh:no /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \ | |
| 85 | 85 | # RUN: /export:exportfn1 /export:exportfn2,@5 >& %t.log |
| 86 | 86 | # RUN: FileCheck -check-prefix=CHECK6 %s < %t.log |
| 87 | 87 | |
| 88 | 88 | # CHECK6: duplicate /export option: _exportfn2 |
| 89 | 89 | # CHECK6-NOT: duplicate /export option: _exportfn1 |
| 90 | 90 | |
| 91 | # RUN: lld-link /out:%t.dll /dll %t.obj /export:foo=mangled | |
| 91 | # RUN: lld-link -safeseh:no /out:%t.dll /dll %t.obj /export:foo=mangled | |
| 92 | 92 | # RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK7 %s |
| 93 | 93 | |
| 94 | 94 | # CHECK7: Export Table: |
deps/lld/test/COFF/failifmismatch.test+29-8| ... | ... | @@ -1,11 +1,32 @@ |
| 1 | # RUN: lld-link /entry:main /subsystem:console /out:%t.exe \ | |
| 2 | # RUN: %p/Inputs/ret42.obj | |
| 1 | REQUIRES: x86 | |
| 3 | 2 | |
| 4 | # RUN: lld-link /entry:main /subsystem:console /out:%t.exe \ | |
| 5 | # RUN: %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k2=v1 | |
| 3 | RUN: lld-link /entry:main /subsystem:console /out:%t.exe \ | |
| 4 | RUN: %p/Inputs/ret42.obj | |
| 6 | 5 | |
| 7 | # RUN: lld-link /entry:main /subsystem:console /out:%t.exe \ | |
| 8 | # RUN: %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v1 | |
| 6 | RUN: lld-link /entry:main /subsystem:console /out:%t.exe \ | |
| 7 | RUN: %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k2=v1 | |
| 9 | 8 | |
| 10 | # RUN: not lld-link /entry:main /subsystem:console /out:%t.exe \ | |
| 11 | # RUN: %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v2 | |
| 9 | RUN: lld-link /entry:main /subsystem:console /out:%t.exe \ | |
| 10 | RUN: %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v1 | |
| 11 | ||
| 12 | RUN: not lld-link /entry:main /subsystem:console /out:%t.exe \ | |
| 13 | RUN: %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v2 2>&1 | FileCheck %s | |
| 14 | ||
| 15 | RUN: llc < %p/Inputs/failmismatch1.ll -mtriple x86_64-windows-msvc -filetype obj -o %t1.obj | |
| 16 | RUN: llc < %p/Inputs/failmismatch2.ll -mtriple x86_64-windows-msvc -filetype obj -o %t2.obj | |
| 17 | RUN: not lld-link %t1.obj %t2.obj 2>&1 | FileCheck %s -check-prefix OBJ | |
| 18 | ||
| 19 | RUN: llvm-lib %t1.obj /out:%t.lib | |
| 20 | RUN: not lld-link %t.lib %t2.obj 2>&1 | FileCheck %s -check-prefix LIB | |
| 21 | ||
| 22 | CHECK: lld-link: error: /failifmismatch: mismatch detected for 'k1': | |
| 23 | CHECK-NEXT: >>> cmd-line has value v1 | |
| 24 | CHECK-NEXT: >>> cmd-line has value v2 | |
| 25 | ||
| 26 | OBJ: lld-link: error: /failifmismatch: mismatch detected for 'TEST': | |
| 27 | OBJ-NEXT: >>> {{.*}}failifmismatch.test.tmp1.obj has value 1 | |
| 28 | OBJ-NEXT: >>> {{.*}}failifmismatch.test.tmp2.obj has value 2 | |
| 29 | ||
| 30 | LIB: lld-link: error: /failifmismatch: mismatch detected for 'TEST': | |
| 31 | LIB-NEXT: >>> {{.*}}failifmismatch.test.tmp2.obj has value 2 | |
| 32 | LIB-NEXT: >>> failifmismatch.test.tmp.lib(failifmismatch.test.tmp1.obj) has value 1 |
deps/lld/test/COFF/filealign.test created+51| ... | ... | @@ -0,0 +1,51 @@ |
| 1 | # RUN: yaml2obj < %s > %t.obj | |
| 2 | ||
| 3 | # RUN: lld-link /out:%t.exe /entry:main %t.obj | |
| 4 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=DEFAULT-HEADER %s | |
| 5 | ||
| 6 | # DEFAULT-HEADER: FileAlignment: 512 | |
| 7 | ||
| 8 | # RUN: lld-link /out:%t.exe /entry:main %t.obj /filealign:4096 | |
| 9 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=FILEALIGN-HEADER %s | |
| 10 | ||
| 11 | # FILEALIGN-HEADER: FileAlignment: 4096 | |
| 12 | ||
| 13 | --- !COFF | |
| 14 | header: | |
| 15 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 16 | Characteristics: [] | |
| 17 | sections: | |
| 18 | - Name: .text | |
| 19 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] | |
| 20 | Alignment: 4096 | |
| 21 | SectionData: 0000000000000000 | |
| 22 | Relocations: | |
| 23 | - VirtualAddress: 0 | |
| 24 | SymbolName: __ImageBase | |
| 25 | Type: IMAGE_REL_AMD64_ADDR64 | |
| 26 | symbols: | |
| 27 | - Name: .text | |
| 28 | Value: 0 | |
| 29 | SectionNumber: 1 | |
| 30 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 31 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 32 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 33 | SectionDefinition: | |
| 34 | Length: 8 | |
| 35 | NumberOfRelocations: 1 | |
| 36 | NumberOfLinenumbers: 0 | |
| 37 | CheckSum: 0 | |
| 38 | Number: 0 | |
| 39 | - Name: main | |
| 40 | Value: 0 | |
| 41 | SectionNumber: 1 | |
| 42 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 43 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 44 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 45 | - Name: __ImageBase | |
| 46 | Value: 0 | |
| 47 | SectionNumber: 0 | |
| 48 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 49 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 50 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 51 | ... |
deps/lld/test/COFF/fixed.test+8-8| ... | ... | @@ -1,22 +1,22 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj |
| 3 | 3 | # |
| 4 | # RUN: lld-link %t.obj /fixed %p/Inputs/std32.lib /subsystem:console \ | |
| 4 | # RUN: lld-link -safeseh:no %t.obj /fixed %p/Inputs/std32.lib /subsystem:console \ | |
| 5 | 5 | # RUN: /entry:main@0 /debug /out:%t.fixed.exe |
| 6 | # RUN: llvm-readobj -file-headers %t.fixed.exe | \ | |
| 6 | # RUN: llvm-readobj --file-headers %t.fixed.exe | \ | |
| 7 | 7 | # RUN: FileCheck -check-prefix=EXEFIXED %s |
| 8 | 8 | # |
| 9 | # RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \ | |
| 9 | # RUN: lld-link -safeseh:no %t.obj %p/Inputs/std32.lib /subsystem:console \ | |
| 10 | 10 | # RUN: /entry:main@0 /debug /out:%t.exe |
| 11 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=EXEREL %s | |
| 11 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=EXEREL %s | |
| 12 | 12 | # |
| 13 | 13 | # RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj |
| 14 | 14 | # |
| 15 | # RUN: lld-link %t.obj /dll /fixed /debug /out:%t.fixed.dll | |
| 16 | # RUN: llvm-readobj -file-headers %t.fixed.dll | FileCheck -check-prefix=DLLFIXED %s | |
| 15 | # RUN: lld-link -safeseh:no %t.obj /dll /fixed /debug /out:%t.fixed.dll | |
| 16 | # RUN: llvm-readobj --file-headers %t.fixed.dll | FileCheck -check-prefix=DLLFIXED %s | |
| 17 | 17 | # |
| 18 | # RUN: lld-link %t.obj /dll /debug /out:%t.dll | |
| 19 | # RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=DLLREL %s | |
| 18 | # RUN: lld-link -safeseh:no %t.obj /dll /debug /out:%t.dll | |
| 19 | # RUN: llvm-readobj --file-headers %t.dll | FileCheck -check-prefix=DLLREL %s | |
| 20 | 20 | |
| 21 | 21 | EXEFIXED-NOT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE |
| 22 | 22 | DLLFIXED-NOT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE |
deps/lld/test/COFF/force-multipleres.test created+21| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | // Check that lld-link rejects duplicate resources, unless | |
| 2 | // /force or /force:multipleres is passed. | |
| 3 | // The input was generated with the following command, using the original Windows | |
| 4 | // rc.exe: | |
| 5 | // > rc /fo id.res /nologo id.rc | |
| 6 | // > rc /fo name.res /nologo name.rc | |
| 7 | ||
| 8 | RUN: rm -rf %t.dir | |
| 9 | RUN: mkdir %t.dir | |
| 10 | RUN: cp %S/Inputs/id.res %t.dir/id1.res | |
| 11 | RUN: cp %S/Inputs/id.res %t.dir/id2.res | |
| 12 | ||
| 13 | RUN: not lld-link /machine:x64 /nodefaultlib /noentry /dll %t.dir/id1.res %t.dir/id2.res 2>&1 | \ | |
| 14 | RUN: FileCheck -check-prefix=ERR %s | |
| 15 | ERR: error: duplicate resource: type STRINGTABLE (ID 6)/name ID 3/language 1033, in {{.*}}id1.res and in {{.*}}id2.res | |
| 16 | ||
| 17 | RUN: lld-link /force /machine:x64 /nodefaultlib /noentry /dll %t.dir/id1.res %t.dir/id2.res 2>&1 | \ | |
| 18 | RUN: FileCheck -check-prefix=WARN %s | |
| 19 | RUN: lld-link /force:multipleres /machine:x64 /nodefaultlib /noentry /dll %t.dir/id1.res %t.dir/id2.res 2>&1 | \ | |
| 20 | RUN: FileCheck -check-prefix=WARN %s | |
| 21 | WARN: warning: duplicate resource: type STRINGTABLE (ID 6)/name ID 3/language 1033, in {{.*}}id1.res and in {{.*}}id2.res |
deps/lld/test/COFF/functionpadmin.test created+147| ... | ... | @@ -0,0 +1,147 @@ |
| 1 | // ---- precomp-a.obj - x86_64, hotpatch | |
| 2 | RUN: lld-link %S/Inputs/precomp-a.obj /out:%t.exe /nodefaultlib /force | |
| 3 | RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix BASE | |
| 4 | ||
| 5 | RUN: lld-link %S/Inputs/precomp-a.obj /out:%t.exe /nodefaultlib /force /functionpadmin | |
| 6 | RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix PADDED | |
| 7 | ||
| 8 | RUN: lld-link %S/Inputs/precomp-a.obj /out:%t.exe /nodefaultlib /force /functionpadmin:17 | |
| 9 | RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix PADDED-MORE | |
| 10 | ||
| 11 | // ---- Many arguments | |
| 12 | RUN: lld-link %S/Inputs/precomp-a.obj /out:%t.exe /nodefaultlib /force /functionpadmin:17 /functionpadmin | |
| 13 | RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix PADDED | |
| 14 | ||
| 15 | RUN: lld-link %S/Inputs/precomp-a.obj /out:%t.exe /nodefaultlib /force /functionpadmin /functionpadmin:17 | |
| 16 | RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix PADDED-MORE | |
| 17 | ||
| 18 | RUN: not lld-link %S/Inputs/precomp-a.obj /out:%t.exe /nodefaultlib /force /functionpadmin:zz 2>&1 | FileCheck %s --check-prefix FAIL | |
| 19 | ||
| 20 | // ---- precomp-a.obj, precomp-b.obj - x86_64, hotpatch - Ensure several functions are properly padded | |
| 21 | RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /out:%t.exe /nodefaultlib /force | |
| 22 | RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix MULTI-BASE | |
| 23 | ||
| 24 | RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /out:%t.exe /nodefaultlib /force /functionpadmin | |
| 25 | RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix MULTI-BASE-PADDED | |
| 26 | ||
| 27 | RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /out:%t.exe /nodefaultlib /force /functionpadmin:17 | |
| 28 | RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix MULTI-BASE-PADDED-MORE | |
| 29 | ||
| 30 | // ---- pdb-diff.obj - x86, no hotpatch - No padding is applied | |
| 31 | RUN: lld-link %S/Inputs/pdb-diff.obj /out:%t.exe /nodefaultlib /force /functionpadmin | |
| 32 | RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix NO-HOTPATCH | |
| 33 | ||
| 34 | // ---- hello64.obj - MASM, x86_64, no hotpatch - No padding is applied | |
| 35 | RUN: lld-link %S/Inputs/hello64.obj /out:%t.exe /nodefaultlib /force /functionpadmin | |
| 36 | RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix HELLO | |
| 37 | ||
| 38 | // ---- std64.lib - Import library, x86_64 - Ensure thunks are padded | |
| 39 | RUN: lld-link %S/Inputs/std64.lib /entry:ExitProcess /out:%t.exe /nodefaultlib /force /subsystem:console | |
| 40 | RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix THUNKS-NO-PAD | |
| 41 | RUN: llvm-readobj --file-headers %t.exe | FileCheck %s --check-prefix THUNKS-NO-PAD-ENTRY | |
| 42 | ||
| 43 | RUN: lld-link %S/Inputs/std64.lib /entry:ExitProcess /out:%t.exe /nodefaultlib /force /functionpadmin /subsystem:console | |
| 44 | RUN: llvm-objdump -s %t.exe | FileCheck %s --check-prefix THUNKS-PAD | |
| 45 | RUN: llvm-readobj --file-headers %t.exe | FileCheck %s --check-prefix THUNKS-PAD-ENTRY | |
| 46 | ||
| 47 | BASE: Contents of section .text: | |
| 48 | BASE-NEXT: 140001000 4883ec28 b161e8f5 efffbf33 c04883c4 H..(.a.....3.H.. | |
| 49 | BASE-NEXT: 140001010 28c3 (. | |
| 50 | BASE-NEXT: Contents of section .rdata: | |
| 51 | BASE-NEXT: 140002000 01040100 04420000 .....B.. | |
| 52 | BASE-NEXT: Contents of section .pdata: | |
| 53 | BASE-NEXT: 140003000 00100000 12100000 00200000 ......... .. | |
| 54 | ||
| 55 | PADDED: Contents of section .text: | |
| 56 | PADDED-NEXT: 140001000 cccccccc cccccccc cccccccc cccccccc ................ | |
| 57 | PADDED-NEXT: 140001010 4883ec28 b161e8e5 efffbf33 c04883c4 H..(.a.....3.H.. | |
| 58 | PADDED-NEXT: 140001020 28c3 (. | |
| 59 | PADDED-NEXT: Contents of section .rdata: | |
| 60 | PADDED-NEXT: 140002000 01040100 04420000 .....B.. | |
| 61 | PADDED-NEXT: Contents of section .pdata: | |
| 62 | PADDED-NEXT: 140003000 10100000 22100000 00200000 ....".... .. | |
| 63 | ||
| 64 | PADDED-MORE: Contents of section .text: | |
| 65 | PADDED-MORE-NEXT: 140001000 cccccccc cccccccc cccccccc cccccccc ................ | |
| 66 | PADDED-MORE-NEXT: 140001010 cccccccc cccccccc cccccccc cccccccc ................ | |
| 67 | PADDED-MORE-NEXT: 140001020 4883ec28 b161e8d5 efffbf33 c04883c4 H..(.a.....3.H.. | |
| 68 | PADDED-MORE-NEXT: 140001030 28c3 (. | |
| 69 | PADDED-MORE-NEXT: Contents of section .rdata: | |
| 70 | PADDED-MORE-NEXT: 140002000 01040100 04420000 .....B.. | |
| 71 | PADDED-MORE-NEXT: Contents of section .pdata: | |
| 72 | PADDED-MORE-NEXT: 140003000 20100000 32100000 00200000 ...2.... .. | |
| 73 | ||
| 74 | FAIL: lld-link: error: /functionpadmin: invalid argument: zz | |
| 75 | ||
| 76 | MULTI-BASE: Contents of section .text: | |
| 77 | MULTI-BASE-NEXT: 140001000 4883ec28 b161e815 00000033 c04883c4 H..(.a.....3.H.. | |
| 78 | MULTI-BASE-NEXT: 140001010 28c3cccc cccccccc cccccccc cccccccc (............... | |
| 79 | MULTI-BASE-NEXT: 140001020 884c2408 0fbe4424 08c3 .L$...D$.. | |
| 80 | MULTI-BASE-NEXT: Contents of section .rdata: | |
| 81 | MULTI-BASE-NEXT: 140002000 01040100 04420000 .....B.. | |
| 82 | MULTI-BASE-NEXT: Contents of section .pdata: | |
| 83 | MULTI-BASE-NEXT: 140004000 00100000 12100000 00200000 ......... .. | |
| 84 | ||
| 85 | MULTI-BASE-PADDED: Contents of section .text: | |
| 86 | MULTI-BASE-PADDED-NEXT: 140001000 cccccccc cccccccc cccccccc cccccccc ................ | |
| 87 | MULTI-BASE-PADDED-NEXT: 140001010 4883ec28 b161e815 00000033 c04883c4 H..(.a.....3.H.. | |
| 88 | MULTI-BASE-PADDED-NEXT: 140001020 28c3cccc cccccccc cccccccc cccccccc (............... | |
| 89 | MULTI-BASE-PADDED-NEXT: 140001030 884c2408 0fbe4424 08c3 .L$...D$.. | |
| 90 | MULTI-BASE-PADDED-NEXT: Contents of section .rdata: | |
| 91 | MULTI-BASE-PADDED-NEXT: 140002000 01040100 04420000 .....B.. | |
| 92 | MULTI-BASE-PADDED-NEXT: Contents of section .pdata: | |
| 93 | MULTI-BASE-PADDED-NEXT: 140004000 10100000 22100000 00200000 ....".... .. | |
| 94 | ||
| 95 | MULTI-BASE-PADDED-MORE: Contents of section .text: | |
| 96 | MULTI-BASE-PADDED-MORE-NEXT: 140001000 cccccccc cccccccc cccccccc cccccccc ................ | |
| 97 | MULTI-BASE-PADDED-MORE-NEXT: 140001010 cccccccc cccccccc cccccccc cccccccc ................ | |
| 98 | MULTI-BASE-PADDED-MORE-NEXT: 140001020 4883ec28 b161e825 00000033 c04883c4 H..(.a.%...3.H.. | |
| 99 | MULTI-BASE-PADDED-MORE-NEXT: 140001030 28c3cccc cccccccc cccccccc cccccccc (............... | |
| 100 | MULTI-BASE-PADDED-MORE-NEXT: 140001040 cccccccc cccccccc cccccccc cccccccc ................ | |
| 101 | MULTI-BASE-PADDED-MORE-NEXT: 140001050 884c2408 0fbe4424 08c3 .L$...D$.. | |
| 102 | MULTI-BASE-PADDED-MORE-NEXT: Contents of section .rdata: | |
| 103 | MULTI-BASE-PADDED-MORE-NEXT: 140002000 01040100 04420000 .....B.. | |
| 104 | MULTI-BASE-PADDED-MORE-NEXT: Contents of section .pdata: | |
| 105 | MULTI-BASE-PADDED-MORE-NEXT: 140004000 20100000 32100000 00200000 ...2.... .. | |
| 106 | ||
| 107 | ||
| 108 | NO-HOTPATCH: Contents of section .text: | |
| 109 | NO-HOTPATCH-NEXT: 401000 558becb8 2a000000 5dc3 U...*...]. | |
| 110 | ||
| 111 | HELLO: Contents of section .text: | |
| 112 | HELLO-NEXT: 140001000 4883ec28 48c7c100 00000048 8d15f40f H..(H......H.... | |
| 113 | HELLO-NEXT: 140001010 00004c8d 05e70f00 0041b900 000000e8 ..L......A...... | |
| 114 | HELLO-NEXT: 140001020 dcefffbf b9000000 00e8d2ef ffbfe8cd ................ | |
| 115 | HELLO-NEXT: 140001030 efffbf ... | |
| 116 | HELLO-NEXT: Contents of section .data: | |
| 117 | HELLO-NEXT: 140002000 48656c6c 6f004865 6c6c6f20 576f726c Hello.Hello Worl | |
| 118 | HELLO-NEXT: 140002010 642100 d!. | |
| 119 | ||
| 120 | THUNKS-NO-PAD: Contents of section .text: | |
| 121 | THUNKS-NO-PAD-NEXT: 140001000 ff253210 0000 .%2... | |
| 122 | THUNKS-NO-PAD-NEXT: Contents of section .rdata: | |
| 123 | THUNKS-NO-PAD-NEXT: 140002000 28200000 00000000 00000000 56200000 ( ..........V .. | |
| 124 | THUNKS-NO-PAD-NEXT: 140002010 38200000 00000000 00000000 00000000 8 .............. | |
| 125 | THUNKS-NO-PAD-NEXT: 140002020 00000000 00000000 48200000 00000000 ........H ...... | |
| 126 | THUNKS-NO-PAD-NEXT: 140002030 00000000 00000000 48200000 00000000 ........H ...... | |
| 127 | THUNKS-NO-PAD-NEXT: 140002040 00000000 00000000 00004578 69745072 ..........ExitPr | |
| 128 | THUNKS-NO-PAD-NEXT: 140002050 6f636573 73007374 6436342e 646c6c00 ocess.std64.dll. | |
| 129 | ||
| 130 | THUNKS-NO-PAD-ENTRY-LABEL: ImageOptionalHeader { | |
| 131 | THUNKS-NO-PAD-ENTRY: AddressOfEntryPoint: 0x1000 | |
| 132 | THUNKS-NO-PAD-ENTRY-NEXT: BaseOfCode: 0x1000 | |
| 133 | ||
| 134 | THUNKS-PAD: Contents of section .text: | |
| 135 | THUNKS-PAD-NEXT: 140001000 cccccccc cccccccc cccccccc cccccccc ................ | |
| 136 | THUNKS-PAD-NEXT: 140001010 ff252210 0000 .%"... | |
| 137 | THUNKS-PAD-NEXT: Contents of section .rdata: | |
| 138 | THUNKS-PAD-NEXT: 140002000 28200000 00000000 00000000 56200000 ( ..........V .. | |
| 139 | THUNKS-PAD-NEXT: 140002010 38200000 00000000 00000000 00000000 8 .............. | |
| 140 | THUNKS-PAD-NEXT: 140002020 00000000 00000000 48200000 00000000 ........H ...... | |
| 141 | THUNKS-PAD-NEXT: 140002030 00000000 00000000 48200000 00000000 ........H ...... | |
| 142 | THUNKS-PAD-NEXT: 140002040 00000000 00000000 00004578 69745072 ..........ExitPr | |
| 143 | THUNKS-PAD-NEXT: 140002050 6f636573 73007374 6436342e 646c6c00 ocess.std64.dll. | |
| 144 | ||
| 145 | THUNKS-PAD-ENTRY-LABEL: ImageOptionalHeader { | |
| 146 | THUNKS-PAD-ENTRY: AddressOfEntryPoint: 0x1010 | |
| 147 | THUNKS-PAD-ENTRY-NEXT: BaseOfCode: 0x1000 |
deps/lld/test/COFF/gfids-corrupt.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj |
| 3 | 3 | # RUN: lld-link %t.obj -opt:noref -guard:nolongjmp -out:%t.exe -entry:main 2>&1 | FileCheck %s --check-prefix=ERRS |
| 4 | # RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s | |
| 4 | # RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # ERRS: warning: ignoring .gfids$y symbol table index section in object {{.*}}gfids-corrupt{{.*}} |
| 7 | 7 | # ERRS: warning: ignoring invalid symbol table index in section .gfids$y in object {{.*}}gfids-corrupt{{.*}} |
deps/lld/test/COFF/gfids-export.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -triple x86_64-pc-win32 %s -filetype=obj -o %t.obj |
| 3 | 3 | # RUN: lld-link %t.obj -guard:cf -dll -out:%t.dll -noentry |
| 4 | # RUN: llvm-readobj -coff-load-config %t.dll | FileCheck %s --check-prefix=CHECK | |
| 4 | # RUN: llvm-readobj --coff-load-config %t.dll | FileCheck %s --check-prefix=CHECK | |
| 5 | 5 | |
| 6 | 6 | # There should be a single entry in the table for the exported symbol. |
| 7 | 7 | # |
deps/lld/test/COFF/gfids-fallback.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: grep -B99999 [S]PLITMARKER %s | llvm-mc -triple x86_64-windows-msvc -filetype=obj -o %t1.obj |
| 3 | 3 | # RUN: grep -A99999 [S]PLITMARKER %s | llvm-mc -triple x86_64-windows-msvc -filetype=obj -o %t2.obj |
| 4 | 4 | # RUN: lld-link %t1.obj %t2.obj -guard:nolongjmp -out:%t.exe -entry:main -opt:noref |
| 5 | # RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s | |
| 5 | # RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: ImageBase: 0x140000000 |
| 8 | 8 | # CHECK: LoadConfig [ |
deps/lld/test/COFF/gfids-gc.s+3-3| ... | ... | @@ -1,11 +1,11 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj |
| 3 | 3 | # RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:noref -entry:main |
| 4 | # RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC | |
| 4 | # RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC | |
| 5 | 5 | # RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:noref -entry:main -debug:dwarf |
| 6 | # RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC | |
| 6 | # RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC | |
| 7 | 7 | # RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:ref -entry:main |
| 8 | # RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-GC | |
| 8 | # RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-GC | |
| 9 | 9 | |
| 10 | 10 | # This assembly is meant to mimic what CL emits for this kind of C code when |
| 11 | 11 | # /Gw (-fdata-sections) is enabled: |
deps/lld/test/COFF/gfids-icf.s+11-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj |
| 3 | 3 | # RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:icf -entry:main |
| 4 | # RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK | |
| 4 | # RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK | |
| 5 | 5 | |
| 6 | 6 | # This assembly is meant to mimic what CL emits for this kind of C code: |
| 7 | 7 | # int icf1() { return 42; } |
| ... | ... | @@ -35,6 +35,16 @@ |
| 35 | 35 | # CHECK-NEXT: 0x14000{{.*}} |
| 36 | 36 | # CHECK-NEXT: ] |
| 37 | 37 | |
| 38 | # There should be no .gfids section in the output exectuable when we link with | |
| 39 | # -guard:cf or with no -guard:cf/nolongjmp flag. | |
| 40 | # RUN: llvm-readobj --sections %t.exe | FileCheck %s --check-prefix NOGFIDSEC | |
| 41 | # RUN: lld-link %t.obj -out:%t.exe -opt:icf -entry:main | |
| 42 | # RUN: llvm-readobj --sections %t.exe | FileCheck %s --check-prefix NOGFIDSEC | |
| 43 | ||
| 44 | # NOGFIDSEC: Sections [ | |
| 45 | # NOGFIDSEC: Section { | |
| 46 | # NOGFIDSEC: Name: .text | |
| 47 | # NOGFIDSEC-NOT: Name: .gfids | |
| 38 | 48 | |
| 39 | 49 | # Indicate that gfids are present. |
| 40 | 50 | .def @feat.00; .scl 3; .type 0; .endef |
deps/lld/test/COFF/gfids-relocations32.s+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -triple i686-pc-win32 %s -filetype=obj -o %t.obj |
| 3 | # RUN: lld-link %t.obj -guard:cf -out:%t.exe -entry:main | |
| 4 | # RUN: llvm-readobj -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK | |
| 3 | # RUN: lld-link -safeseh:no %t.obj -guard:cf -out:%t.exe -entry:main | |
| 4 | # RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK | |
| 5 | 5 | |
| 6 | 6 | # Only f and _main should go in the table. |
| 7 | 7 | # (use /lldmap:map.txt to check their addresses). |
deps/lld/test/COFF/gfids-relocations64.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -triple x86_64-pc-win32 %s -filetype=obj -o %t.obj |
| 3 | 3 | # RUN: lld-link %t.obj -guard:cf -out:%t.exe -entry:main |
| 4 | # RUN: llvm-readobj -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK | |
| 4 | # RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK | |
| 5 | 5 | |
| 6 | 6 | # f, g, and main go in the table. |
| 7 | 7 | # Including g isn't strictly necessary since it's not an indirect call target, |
deps/lld/test/COFF/guard-longjmp.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj |
| 3 | 3 | # RUN: lld-link %t.obj -guard:cf -out:%t.exe -entry:main |
| 4 | # RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s | |
| 4 | # RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: ImageBase: 0x140000000 |
| 7 | 7 | # CHECK: LoadConfig [ |
deps/lld/test/COFF/guardcf-align.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: > %T/guardcf-align-foobar.obj |
| 5 | 5 | # RUN: lld-link -out:%T/guardcf-align.exe -entry:main -guard:cf \ |
| 6 | 6 | # RUN: %t.obj %T/guardcf-align-foobar.obj |
| 7 | # RUN: llvm-readobj -coff-load-config %T/guardcf-align.exe | FileCheck %s | |
| 7 | # RUN: llvm-readobj --coff-load-config %T/guardcf-align.exe | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | # Check that the gfids table contains at least one entry that ends in 0 |
| 10 | 10 | # and no entries that end in something other than 0. |
deps/lld/test/COFF/guardcf-lto.ll+1-1| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | |
| 10 | 10 | ; RUN: llvm-as %s -o %t.bc |
| 11 | 11 | ; RUN: lld-link -entry:main -guard:cf -dll %t.bc %t.lib %t.ldcfg.obj -out:%t.dll |
| 12 | ; RUN: llvm-readobj -coff-load-config %t.dll | FileCheck %s | |
| 12 | ; RUN: llvm-readobj --coff-load-config %t.dll | FileCheck %s | |
| 13 | 13 | |
| 14 | 14 | ; There must be *two* entries in the table: DLL entry point, and my_handler. |
| 15 | 15 |
deps/lld/test/COFF/guardcf-thunk.s created+43| ... | ... | @@ -0,0 +1,43 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # Make a DLL that exports exportfn1. | |
| 4 | # RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj | |
| 5 | # RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /implib:%t.lib | |
| 6 | ||
| 7 | # Make an obj that takes the address of that exported function. | |
| 8 | # RUN: llvm-mc -filetype=obj -triple=x86_64-windows-msvc %s -o %t2.obj | |
| 9 | # RUN: lld-link -entry:main -guard:cf %t2.obj %t.lib -nodefaultlib -out:%t.exe | |
| 10 | # RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s | |
| 11 | ||
| 12 | # Check that the gfids table contains *exactly* two entries, one for exportfn1 | |
| 13 | # and one for main. | |
| 14 | # CHECK: GuardFidTable [ | |
| 15 | # CHECK-NEXT: 0x{{[0-9A-Fa-f]+0$}} | |
| 16 | # CHECK-NEXT: 0x{{[0-9A-Fa-f]+0$}} | |
| 17 | # CHECK-NEXT: ] | |
| 18 | ||
| 19 | ||
| 20 | .def @feat.00; | |
| 21 | .scl 3; | |
| 22 | .type 0; | |
| 23 | .endef | |
| 24 | .globl @feat.00 | |
| 25 | @feat.00 = 0x001 | |
| 26 | ||
| 27 | .section .text,"rx" | |
| 28 | .def main; .scl 2; .type 32; .endef | |
| 29 | .global main | |
| 30 | main: | |
| 31 | leaq exportfn1(%rip), %rax | |
| 32 | retq | |
| 33 | ||
| 34 | .section .rdata,"dr" | |
| 35 | .globl _load_config_used | |
| 36 | _load_config_used: | |
| 37 | .long 256 | |
| 38 | .fill 124, 1, 0 | |
| 39 | .quad __guard_fids_table | |
| 40 | .quad __guard_fids_count | |
| 41 | .long __guard_flags | |
| 42 | .fill 128, 1, 0 | |
| 43 |
deps/lld/test/COFF/header-size.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-windows %s -o %t.obj |
| 3 | 3 | // RUN: lld-link -entry:main -subsystem:console %t.obj -out:%t.exe |
| 4 | // RUN: llvm-readobj -sections %t.exe | FileCheck %s | |
| 4 | // RUN: llvm-readobj --sections %t.exe | FileCheck %s | |
| 5 | 5 | .globl main |
| 6 | 6 | main: |
| 7 | 7 | ret |
deps/lld/test/COFF/heap.test+5-5| ... | ... | @@ -1,25 +1,25 @@ |
| 1 | 1 | # RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj |
| 2 | 2 | |
| 3 | 3 | # RUN: lld-link /out:%t.exe /entry:main %t.obj |
| 4 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DEFAULT %s | |
| 4 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=DEFAULT %s | |
| 5 | 5 | |
| 6 | 6 | DEFAULT: SizeOfHeapReserve: 1048576 |
| 7 | 7 | DEFAULT: SizeOfHeapCommit: 4096 |
| 8 | 8 | |
| 9 | 9 | # RUN: lld-link /out:%t.exe /entry:main /heap:0x3000 %t.obj |
| 10 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s | |
| 10 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s | |
| 11 | 11 | # RUN: echo "HEAPSIZE 12288" > %t.def |
| 12 | 12 | # RUN: lld-link /out:%t.exe /entry:main /def:%t.def %t.obj |
| 13 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s | |
| 13 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s | |
| 14 | 14 | |
| 15 | 15 | CHECK1: SizeOfHeapReserve: 12288 |
| 16 | 16 | CHECK1: SizeOfHeapCommit: 4096 |
| 17 | 17 | |
| 18 | 18 | # RUN: lld-link /out:%t.exe /entry:main /heap:0x5000,0x3000 %t.obj |
| 19 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s | |
| 19 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s | |
| 20 | 20 | # RUN: echo "HEAPSIZE 20480,12288" > %t.def |
| 21 | 21 | # RUN: lld-link /out:%t.exe /entry:main /def:%t.def %t.obj |
| 22 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s | |
| 22 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s | |
| 23 | 23 | |
| 24 | 24 | CHECK2: SizeOfHeapReserve: 20480 |
| 25 | 25 | CHECK2: SizeOfHeapCommit: 12288 |
deps/lld/test/COFF/hello32.test+5-6| ... | ... | @@ -1,9 +1,9 @@ |
| 1 | 1 | # RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj |
| 2 | # RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \ | |
| 2 | # RUN: lld-link -safeseh:no %t.obj %p/Inputs/std32.lib /subsystem:console \ | |
| 3 | 3 | # RUN: /entry:main@0 /out:%t.exe /appcontainer |
| 4 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s | |
| 5 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s | |
| 6 | # RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s | |
| 4 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=HEADER %s | |
| 5 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s | |
| 6 | # RUN: llvm-readobj --coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s | |
| 7 | 7 | |
| 8 | 8 | HEADER: Format: COFF-i386 |
| 9 | 9 | HEADER-NEXT: Arch: i386 |
| ... | ... | @@ -42,10 +42,9 @@ HEADER-NEXT: MinorSubsystemVersion: 0 |
| 42 | 42 | HEADER-NEXT: SizeOfImage: 20480 |
| 43 | 43 | HEADER-NEXT: SizeOfHeaders: 1024 |
| 44 | 44 | HEADER-NEXT: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3) |
| 45 | HEADER-NEXT: Characteristics [ (0x9540) | |
| 45 | HEADER-NEXT: Characteristics [ (0x9140) | |
| 46 | 46 | HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_APPCONTAINER (0x1000) |
| 47 | 47 | HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE (0x40) |
| 48 | HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_NO_SEH (0x400) | |
| 49 | 48 | HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT (0x100) |
| 50 | 49 | HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000) |
| 51 | 50 | HEADER-NEXT: ] |
deps/lld/test/COFF/icf-pdata.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc %s -triple x86_64-windows-msvc -filetype=obj -o %t.obj |
| 3 | 3 | # RUN: lld-link %t.obj -dll -noentry -out:%t.dll -merge:.xdata=.xdata |
| 4 | # RUN: llvm-readobj -sections -coff-exports %t.dll | FileCheck %s | |
| 4 | # RUN: llvm-readobj --sections --coff-exports %t.dll | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: Name: .pdata |
| 7 | 7 | # CHECK-NEXT: VirtualSize: 0x18 |
deps/lld/test/COFF/icf-xdata.s+2-2| ... | ... | @@ -2,9 +2,9 @@ |
| 2 | 2 | # RUN: llvm-mc %s -triple x86_64-windows-msvc -filetype=obj -o %t.obj |
| 3 | 3 | # RUN: lld-link %t.obj -dll -noentry -out:%t.dll -merge:.xdata=.xdata 2>&1 \ |
| 4 | 4 | # RUN: | FileCheck %s --check-prefix=WARN |
| 5 | # RUN: llvm-readobj -sections %t.dll | FileCheck %s --check-prefix=XDATA | |
| 5 | # RUN: llvm-readobj --sections %t.dll | FileCheck %s --check-prefix=XDATA | |
| 6 | 6 | # RUN: lld-link %t.obj -dll -noentry -out:%t.dll |
| 7 | # RUN: llvm-readobj -sections %t.dll | FileCheck %s --check-prefix=RDATA | |
| 7 | # RUN: llvm-readobj --sections %t.dll | FileCheck %s --check-prefix=RDATA | |
| 8 | 8 | |
| 9 | 9 | # There shouldn't be much xdata, because all three .pdata entries (12 bytes |
| 10 | 10 | # each) should use the same .xdata unwind info. |
deps/lld/test/COFF/imports-gnu-autoexport.s+1-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: llvm-ar rcs %t-implib.a %t-dabcdh.o %t-dabcds00000.o %t-dabcdt.o |
| 8 | 8 | # RUN: lld-link -lldmingw -dll -out:%t.dll -entry:main -subsystem:console \ |
| 9 | 9 | # RUN: %p/Inputs/hello64.obj %p/Inputs/std64.lib %t-implib.a -include:func |
| 10 | # RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix=EXPORT %s | |
| 10 | # RUN: llvm-readobj --coff-exports %t.dll | FileCheck -check-prefix=EXPORT %s | |
| 11 | 11 | |
| 12 | 12 | # Check that only the single normal symbol was exported, none of the symbols |
| 13 | 13 | # from the import library. |
deps/lld/test/COFF/imports-gnu.test+1-1| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | # Not linking with -lldmingw; one can link to GNU import libs even if not targeting MinGW. |
| 10 | 10 | # RUN: lld-link -out:%t.exe -entry:main -subsystem:console \ |
| 11 | 11 | # RUN: %p/Inputs/hello64.obj %p/Inputs/std64.lib %t-implib.a -include:func |
| 12 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s | |
| 12 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s | |
| 13 | 13 | |
| 14 | 14 | # Check that import entries from both libraries show up. |
| 15 | 15 |
deps/lld/test/COFF/imports-mangle.test+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | 2 | # RUN: lld-link /out:%t.exe /opt:noref /entry:main \ |
| 3 | 3 | # RUN: %t.obj %p/Inputs/imports-mangle.lib |
| 4 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s | |
| 4 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: Import { |
| 7 | 7 | # CHECK: Symbol: sym4 (0) |
deps/lld/test/COFF/imports.test+4-3| ... | ... | @@ -4,14 +4,15 @@ |
| 4 | 4 | # RUN: lld-link /out:%t.exe /entry:main /subsystem:console \ |
| 5 | 5 | # RUN: %p/Inputs/hello64.obj %p/Inputs/std64.lib |
| 6 | 6 | # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=TEXT %s |
| 7 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s | |
| 7 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s | |
| 8 | 8 | |
| 9 | 9 | # RUN: lld-link /out:%t.exe /entry:main /subsystem:console \ |
| 10 | 10 | # RUN: %p/Inputs/hello64.obj %p/Inputs/std64.lib /include:ExitProcess |
| 11 | 11 | # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=TEXT %s |
| 12 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s | |
| 12 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s | |
| 13 | 13 | |
| 14 | 14 | TEXT: Disassembly of section .text: |
| 15 | TEXT-EMPTY: | |
| 15 | 16 | TEXT-NEXT: .text: |
| 16 | 17 | TEXT-NEXT: subq $40, %rsp |
| 17 | 18 | TEXT-NEXT: movq $0, %rcx |
| ... | ... | @@ -37,7 +38,7 @@ IMPORT-NEXT: } |
| 37 | 38 | |
| 38 | 39 | # RUN: lld-link /out:%t.exe /entry:main /subsystem:console /merge:.rdata=.text \ |
| 39 | 40 | # RUN: %p/Inputs/hello64.obj %p/Inputs/std64.lib /include:ExitProcess |
| 40 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=MERGE %s | |
| 41 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=MERGE %s | |
| 41 | 42 | |
| 42 | 43 | MERGE: Import { |
| 43 | 44 | MERGE-NEXT: Name: std64.dll |
deps/lld/test/COFF/includeoptional.yaml created+39| ... | ... | @@ -0,0 +1,39 @@ |
| 1 | # RUN: yaml2obj < %s > %t.main.obj | |
| 2 | # RUN: yaml2obj < %p/Inputs/include1c.yaml > %t.lib.obj | |
| 3 | # RUN: rm -f %t.lib.lib | |
| 4 | # RUN: llvm-ar cru %t.lib.lib %t.lib.obj | |
| 5 | # RUN: lld-link /out:%t.exe /entry:main /includeoptional:bar /includeoptional:actuallymissing %t.main.obj %t.lib.lib /verbose >& %t.log | |
| 6 | # RUN: FileCheck %s < %t.log | |
| 7 | ||
| 8 | # CHECK: includeoptional.yaml.tmp.main.obj | |
| 9 | # CHECK: includeoptional.yaml.tmp.lib.lib | |
| 10 | # CHECK: includeoptional.yaml.tmp.lib.lib(includeoptional.yaml.tmp.lib.obj) for bar | |
| 11 | --- !COFF | |
| 12 | header: | |
| 13 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 14 | Characteristics: [] | |
| 15 | sections: | |
| 16 | - Name: .text | |
| 17 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] | |
| 18 | Alignment: 4 | |
| 19 | SectionData: B800000000506800000000680000000050E80000000050E800000000 | |
| 20 | symbols: | |
| 21 | - Name: .text | |
| 22 | Value: 0 | |
| 23 | SectionNumber: 1 | |
| 24 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 25 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 26 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 27 | SectionDefinition: | |
| 28 | Length: 28 | |
| 29 | NumberOfRelocations: 4 | |
| 30 | NumberOfLinenumbers: 0 | |
| 31 | CheckSum: 0 | |
| 32 | Number: 0 | |
| 33 | - Name: main | |
| 34 | Value: 0 | |
| 35 | SectionNumber: 1 | |
| 36 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 37 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 38 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 39 | ... |
deps/lld/test/COFF/includeoptional2.yaml created+44| ... | ... | @@ -0,0 +1,44 @@ |
| 1 | # RUN: yaml2obj < %s > %t.obj | |
| 2 | # RUN: not lld-link /out:%t.exe /entry:main /includeoptional:undeffunc %t.obj /verbose 2>&1 | FileCheck %s | |
| 3 | ||
| 4 | # CHECK: error: undefined symbol: undeffunc | |
| 5 | ||
| 6 | --- !COFF | |
| 7 | header: | |
| 8 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 9 | Characteristics: [] | |
| 10 | sections: | |
| 11 | - Name: .text | |
| 12 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] | |
| 13 | Alignment: 4 | |
| 14 | SectionData: B800000000506800000000680000000050E80000000050E800000000 | |
| 15 | Relocations: | |
| 16 | - VirtualAddress: 17 | |
| 17 | SymbolName: undeffunc | |
| 18 | Type: IMAGE_REL_AMD64_REL32 | |
| 19 | symbols: | |
| 20 | - Name: .text | |
| 21 | Value: 0 | |
| 22 | SectionNumber: 1 | |
| 23 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 24 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 25 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 26 | SectionDefinition: | |
| 27 | Length: 28 | |
| 28 | NumberOfRelocations: 1 | |
| 29 | NumberOfLinenumbers: 0 | |
| 30 | CheckSum: 0 | |
| 31 | Number: 0 | |
| 32 | - Name: main | |
| 33 | Value: 0 | |
| 34 | SectionNumber: 1 | |
| 35 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 36 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 37 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 38 | - Name: undeffunc | |
| 39 | Value: 0 | |
| 40 | SectionNumber: 0 | |
| 41 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 42 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 43 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 44 | ... |
deps/lld/test/COFF/invalid-debug-type.test+8-3| ... | ... | @@ -1,6 +1,11 @@ |
| 1 | 1 | # RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj |
| 2 | 2 | # RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj |
| 3 | # RUN: lld-link /debug /debugtype:invalid /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ | |
| 4 | # RUN: %t1.obj %t2.obj 2>&1 | FileCheck %s | |
| 3 | # RUN: lld-link /debug /debugtype:invalid /pdb:%t.pdb /dll /out:%t.dll \ | |
| 4 | # RUN: /entry:main /nodefaultlib %t1.obj %t2.obj 2>&1 | FileCheck %s | |
| 5 | # CHECK: /debugtype: unknown option 'invalid' | |
| 5 | 6 | |
| 6 | # CHECK: /debugtype: unknown option: invalid | |
| \ No newline at end of file | ||
| 7 | # RUN: lld-link /debug /debugtype:invalid,foo /pdb:%t.pdb /dll /out:%t.dll \ | |
| 8 | # RUN: /entry:main /nodefaultlib %t1.obj %t2.obj 2>&1 | \ | |
| 9 | # RUN: FileCheck --check-prefix=TWO %s | |
| 10 | # TWO: /debugtype: unknown option 'invalid' | |
| 11 | # TWO: /debugtype: unknown option 'foo' |
deps/lld/test/COFF/largeaddressaware.test+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj |
| 2 | # RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \ | |
| 2 | # RUN: lld-link -safeseh:no %t.obj %p/Inputs/std32.lib /subsystem:console \ | |
| 3 | 3 | # RUN: /entry:main@0 /out:%t.exe /largeaddressaware |
| 4 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s | |
| 4 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=HEADER %s | |
| 5 | 5 | |
| 6 | 6 | HEADER: Format: COFF-i386 |
| 7 | 7 | HEADER-NEXT: Arch: i386 |
deps/lld/test/COFF/lib-module-asm.ll created+22| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | ; REQUIRES: x86 | |
| 2 | ; PR41803: llvm-link /lib on object with module asm crashes | |
| 3 | ; RUN: rm -f %t.lib | |
| 4 | ; RUN: llvm-as -o %t.obj %s | |
| 5 | ; RUN: lld-link /lib /out:%t.lib %t.obj | |
| 6 | ; RUN: llvm-nm -M %t.lib | FileCheck %s | |
| 7 | ||
| 8 | target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" | |
| 9 | target triple = "i386-pc-windows-msvc19.11.0" | |
| 10 | ||
| 11 | module asm ".global global_asm_sym" | |
| 12 | module asm "global_asm_sym:" | |
| 13 | module asm "local_asm_sym:" | |
| 14 | module asm ".long undef_asm_sym" | |
| 15 | ||
| 16 | ; CHECK: Archive map | |
| 17 | ; CHECK-NEXT: global_asm_sym in {{.*}}lib-module-asm.ll.tmp.obj | |
| 18 | ||
| 19 | ; CHECK: lib-module-asm.ll.tmp.obj:{{$}} | |
| 20 | ; CHECK-NEXT: T global_asm_sym | |
| 21 | ; CHECK-NEXT: t local_asm_sym | |
| 22 | ; CHECK-NEXT: U undef_asm_sym |
deps/lld/test/COFF/line-error.yaml+160-160| ... | ... | @@ -1,160 +1,160 @@ |
| 1 | # RUN: yaml2obj %s -o %t.obj | |
| 2 | # RUN: not lld-link %t.obj /subsystem:console 2>&1 | FileCheck %s | |
| 3 | ||
| 4 | # CHECK: lld-link: error: undefined symbol: function | |
| 5 | # CHECK-NEXT: >>> referenced by {{.*}}line-error.yaml.tmp.obj:(caller1) | |
| 6 | # CHECK-NEXT: >>> referenced by E:\file.cpp:1935 | |
| 7 | # CHECK-NEXT: >>> {{.*}}line-error.yaml.tmp.obj:(caller22) | |
| 8 | ||
| 9 | --- !COFF | |
| 10 | header: | |
| 11 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 12 | Characteristics: [ ] | |
| 13 | sections: | |
| 14 | - Name: .text | |
| 15 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] | |
| 16 | Alignment: 16 | |
| 17 | SectionData: 488B0500000000488B51284881C2D80000004889C148FF2500000000 | |
| 18 | Relocations: | |
| 19 | - VirtualAddress: 3 | |
| 20 | SymbolName: function | |
| 21 | Type: IMAGE_REL_AMD64_REL32 | |
| 22 | - Name: .text | |
| 23 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] | |
| 24 | Alignment: 16 | |
| 25 | SectionData: 488B0500000000488B51084881C2D80000004889C148FF2500000000 | |
| 26 | Relocations: | |
| 27 | - VirtualAddress: 3 | |
| 28 | SymbolName: function | |
| 29 | Type: IMAGE_REL_AMD64_REL32 | |
| 30 | - Name: '.debug$S' | |
| 31 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] | |
| 32 | Alignment: 4 | |
| 33 | Subsections: | |
| 34 | - !FileChecksums | |
| 35 | Checksums: | |
| 36 | - FileName: 'E:\file.cpp' | |
| 37 | Kind: MD5 | |
| 38 | Checksum: D72EDEF8B8E50C364A330F9CB3CD904B | |
| 39 | - !StringTable | |
| 40 | Strings: | |
| 41 | - 'E:\file.cpp' | |
| 42 | - Name: '.debug$S' | |
| 43 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] | |
| 44 | Alignment: 4 | |
| 45 | Subsections: | |
| 46 | - !Lines | |
| 47 | CodeSize: 28 | |
| 48 | Flags: [ ] | |
| 49 | RelocOffset: 0 | |
| 50 | RelocSegment: 0 | |
| 51 | Blocks: [] | |
| 52 | Relocations: | |
| 53 | - VirtualAddress: 12 | |
| 54 | SymbolName: caller1 | |
| 55 | Type: IMAGE_REL_AMD64_SECREL | |
| 56 | - Name: '.debug$S' | |
| 57 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] | |
| 58 | Alignment: 4 | |
| 59 | Subsections: | |
| 60 | - !Lines | |
| 61 | CodeSize: 28 | |
| 62 | Flags: [ ] | |
| 63 | RelocOffset: 0 | |
| 64 | RelocSegment: 0 | |
| 65 | Blocks: | |
| 66 | - FileName: 'E:\file.cpp' | |
| 67 | Lines: | |
| 68 | - Offset: 11 | |
| 69 | LineStart: 1935 | |
| 70 | IsStatement: false | |
| 71 | EndDelta: 0 | |
| 72 | Columns: [] | |
| 73 | Relocations: | |
| 74 | - VirtualAddress: 12 | |
| 75 | SymbolName: caller22 | |
| 76 | Type: IMAGE_REL_AMD64_SECREL | |
| 77 | symbols: | |
| 78 | - Name: .text | |
| 79 | Value: 0 | |
| 80 | SectionNumber: 1 | |
| 81 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 82 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 83 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 84 | SectionDefinition: | |
| 85 | Length: 28 | |
| 86 | NumberOfRelocations: 2 | |
| 87 | NumberOfLinenumbers: 0 | |
| 88 | CheckSum: 2430089736 | |
| 89 | Number: 1 | |
| 90 | Selection: IMAGE_COMDAT_SELECT_NODUPLICATES | |
| 91 | - Name: caller1 | |
| 92 | Value: 0 | |
| 93 | SectionNumber: 1 | |
| 94 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 95 | ComplexType: IMAGE_SYM_DTYPE_FUNCTION | |
| 96 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 97 | - Name: .text | |
| 98 | Value: 0 | |
| 99 | SectionNumber: 2 | |
| 100 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 101 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 102 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 103 | SectionDefinition: | |
| 104 | Length: 28 | |
| 105 | NumberOfRelocations: 2 | |
| 106 | NumberOfLinenumbers: 0 | |
| 107 | CheckSum: 3449717304 | |
| 108 | Number: 2 | |
| 109 | Selection: IMAGE_COMDAT_SELECT_NODUPLICATES | |
| 110 | - Name: caller22 | |
| 111 | Value: 0 | |
| 112 | SectionNumber: 2 | |
| 113 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 114 | ComplexType: IMAGE_SYM_DTYPE_FUNCTION | |
| 115 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 116 | - Name: '.debug$S' | |
| 117 | Value: 0 | |
| 118 | SectionNumber: 3 | |
| 119 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 120 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 121 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 122 | SectionDefinition: | |
| 123 | Length: 767204 | |
| 124 | NumberOfRelocations: 0 | |
| 125 | NumberOfLinenumbers: 0 | |
| 126 | CheckSum: 4280093374 | |
| 127 | Number: 3 | |
| 128 | - Name: '.debug$S' | |
| 129 | Value: 0 | |
| 130 | SectionNumber: 4 | |
| 131 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 132 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 133 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 134 | SectionDefinition: | |
| 135 | Length: 296 | |
| 136 | NumberOfRelocations: 1 | |
| 137 | NumberOfLinenumbers: 0 | |
| 138 | CheckSum: 1957793731 | |
| 139 | Number: 1 | |
| 140 | Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE | |
| 141 | - Name: '.debug$S' | |
| 142 | Value: 0 | |
| 143 | SectionNumber: 5 | |
| 144 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 145 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 146 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 147 | SectionDefinition: | |
| 148 | Length: 276 | |
| 149 | NumberOfRelocations: 1 | |
| 150 | NumberOfLinenumbers: 0 | |
| 151 | CheckSum: 1957793731 | |
| 152 | Number: 2 | |
| 153 | Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE | |
| 154 | - Name: function | |
| 155 | Value: 0 | |
| 156 | SectionNumber: 0 | |
| 157 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 158 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 159 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 160 | ... | |
| 1 | # RUN: yaml2obj %s -o %t.obj | |
| 2 | # RUN: not lld-link %t.obj /subsystem:console 2>&1 | FileCheck %s | |
| 3 | ||
| 4 | # CHECK: lld-link: error: undefined symbol: function | |
| 5 | # CHECK-NEXT: >>> referenced by {{.*}}line-error.yaml.tmp.obj:(caller1) | |
| 6 | # CHECK-NEXT: >>> referenced by E:\file.cpp:1935 | |
| 7 | # CHECK-NEXT: >>> {{.*}}line-error.yaml.tmp.obj:(caller22) | |
| 8 | ||
| 9 | --- !COFF | |
| 10 | header: | |
| 11 | Machine: IMAGE_FILE_MACHINE_AMD64 | |
| 12 | Characteristics: [ ] | |
| 13 | sections: | |
| 14 | - Name: .text | |
| 15 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] | |
| 16 | Alignment: 16 | |
| 17 | SectionData: 488B0500000000488B51284881C2D80000004889C148FF2500000000 | |
| 18 | Relocations: | |
| 19 | - VirtualAddress: 3 | |
| 20 | SymbolName: function | |
| 21 | Type: IMAGE_REL_AMD64_REL32 | |
| 22 | - Name: .text | |
| 23 | Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] | |
| 24 | Alignment: 16 | |
| 25 | SectionData: 488B0500000000488B51084881C2D80000004889C148FF2500000000 | |
| 26 | Relocations: | |
| 27 | - VirtualAddress: 3 | |
| 28 | SymbolName: function | |
| 29 | Type: IMAGE_REL_AMD64_REL32 | |
| 30 | - Name: '.debug$S' | |
| 31 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] | |
| 32 | Alignment: 4 | |
| 33 | Subsections: | |
| 34 | - !FileChecksums | |
| 35 | Checksums: | |
| 36 | - FileName: 'E:\file.cpp' | |
| 37 | Kind: MD5 | |
| 38 | Checksum: D72EDEF8B8E50C364A330F9CB3CD904B | |
| 39 | - !StringTable | |
| 40 | Strings: | |
| 41 | - 'E:\file.cpp' | |
| 42 | - Name: '.debug$S' | |
| 43 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] | |
| 44 | Alignment: 4 | |
| 45 | Subsections: | |
| 46 | - !Lines | |
| 47 | CodeSize: 28 | |
| 48 | Flags: [ ] | |
| 49 | RelocOffset: 0 | |
| 50 | RelocSegment: 0 | |
| 51 | Blocks: [] | |
| 52 | Relocations: | |
| 53 | - VirtualAddress: 12 | |
| 54 | SymbolName: caller1 | |
| 55 | Type: IMAGE_REL_AMD64_SECREL | |
| 56 | - Name: '.debug$S' | |
| 57 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] | |
| 58 | Alignment: 4 | |
| 59 | Subsections: | |
| 60 | - !Lines | |
| 61 | CodeSize: 28 | |
| 62 | Flags: [ ] | |
| 63 | RelocOffset: 0 | |
| 64 | RelocSegment: 0 | |
| 65 | Blocks: | |
| 66 | - FileName: 'E:\file.cpp' | |
| 67 | Lines: | |
| 68 | - Offset: 11 | |
| 69 | LineStart: 1935 | |
| 70 | IsStatement: false | |
| 71 | EndDelta: 0 | |
| 72 | Columns: [] | |
| 73 | Relocations: | |
| 74 | - VirtualAddress: 12 | |
| 75 | SymbolName: caller22 | |
| 76 | Type: IMAGE_REL_AMD64_SECREL | |
| 77 | symbols: | |
| 78 | - Name: .text | |
| 79 | Value: 0 | |
| 80 | SectionNumber: 1 | |
| 81 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 82 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 83 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 84 | SectionDefinition: | |
| 85 | Length: 28 | |
| 86 | NumberOfRelocations: 2 | |
| 87 | NumberOfLinenumbers: 0 | |
| 88 | CheckSum: 2430089736 | |
| 89 | Number: 1 | |
| 90 | Selection: IMAGE_COMDAT_SELECT_NODUPLICATES | |
| 91 | - Name: caller1 | |
| 92 | Value: 0 | |
| 93 | SectionNumber: 1 | |
| 94 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 95 | ComplexType: IMAGE_SYM_DTYPE_FUNCTION | |
| 96 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 97 | - Name: .text | |
| 98 | Value: 0 | |
| 99 | SectionNumber: 2 | |
| 100 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 101 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 102 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 103 | SectionDefinition: | |
| 104 | Length: 28 | |
| 105 | NumberOfRelocations: 2 | |
| 106 | NumberOfLinenumbers: 0 | |
| 107 | CheckSum: 3449717304 | |
| 108 | Number: 2 | |
| 109 | Selection: IMAGE_COMDAT_SELECT_NODUPLICATES | |
| 110 | - Name: caller22 | |
| 111 | Value: 0 | |
| 112 | SectionNumber: 2 | |
| 113 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 114 | ComplexType: IMAGE_SYM_DTYPE_FUNCTION | |
| 115 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 116 | - Name: '.debug$S' | |
| 117 | Value: 0 | |
| 118 | SectionNumber: 3 | |
| 119 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 120 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 121 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 122 | SectionDefinition: | |
| 123 | Length: 767204 | |
| 124 | NumberOfRelocations: 0 | |
| 125 | NumberOfLinenumbers: 0 | |
| 126 | CheckSum: 4280093374 | |
| 127 | Number: 3 | |
| 128 | - Name: '.debug$S' | |
| 129 | Value: 0 | |
| 130 | SectionNumber: 4 | |
| 131 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 132 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 133 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 134 | SectionDefinition: | |
| 135 | Length: 296 | |
| 136 | NumberOfRelocations: 1 | |
| 137 | NumberOfLinenumbers: 0 | |
| 138 | CheckSum: 1957793731 | |
| 139 | Number: 1 | |
| 140 | Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE | |
| 141 | - Name: '.debug$S' | |
| 142 | Value: 0 | |
| 143 | SectionNumber: 5 | |
| 144 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 145 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 146 | StorageClass: IMAGE_SYM_CLASS_STATIC | |
| 147 | SectionDefinition: | |
| 148 | Length: 276 | |
| 149 | NumberOfRelocations: 1 | |
| 150 | NumberOfLinenumbers: 0 | |
| 151 | CheckSum: 1957793731 | |
| 152 | Number: 2 | |
| 153 | Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE | |
| 154 | - Name: function | |
| 155 | Value: 0 | |
| 156 | SectionNumber: 0 | |
| 157 | SimpleType: IMAGE_SYM_TYPE_NULL | |
| 158 | ComplexType: IMAGE_SYM_DTYPE_NULL | |
| 159 | StorageClass: IMAGE_SYM_CLASS_EXTERNAL | |
| 160 | ... |
deps/lld/test/COFF/linkrepro-pdb.test+14-1| ... | ... | @@ -4,6 +4,19 @@ RUN: rm -rf %t && mkdir -p %t && cd %t |
| 4 | 4 | RUN: yaml2obj %S/Inputs/pdb-type-server-simple-a.yaml -o a.obj |
| 5 | 5 | RUN: yaml2obj %S/Inputs/pdb-type-server-simple-b.yaml -o b.obj |
| 6 | 6 | RUN: llvm-pdbutil yaml2pdb %S/Inputs/pdb-type-server-simple-ts.yaml -pdb ts.pdb |
| 7 | RUN: lld-link a.obj b.obj -entry:main -debug -out:t.exe -pdb:t.pdb -nodefaultlib -linkrepro:. | |
| 7 | RUN: lld-link a.obj b.obj -entry:main -debug -out:%t.exe -pdb:%t.pdb -nodefaultlib -linkrepro:. | |
| 8 | 8 | RUN: tar xOf repro.tar repro/%:t/ts.pdb > repro-ts.pdb |
| 9 | 9 | RUN: diff ts.pdb repro-ts.pdb |
| 10 | ||
| 11 | RUN: tar xf repro.tar | |
| 12 | RUN: cat repro/response.txt | FileCheck -check-prefix=PDB %s | |
| 13 | ||
| 14 | PDB: -out:linkrepro-pdb.test.tmp.exe | |
| 15 | PDB-NEXT: -pdb:linkrepro-pdb.test.tmp.pdb | |
| 16 | ||
| 17 | RUN: yaml2obj < %p/Inputs/export.yaml > %t1.obj | |
| 18 | RUN: lld-link /out:%t1.dll /dll %t1.obj /implib:%t1.lib /export:exportfn1 /export:exportfn2 /linkrepro:. | |
| 19 | RUN: tar xf repro.tar | |
| 20 | RUN: cat repro/response.txt | FileCheck -check-prefix=IMP %s | |
| 21 | ||
| 22 | IMP: /implib:linkrepro-pdb.test.tmp1.lib |
deps/lld/test/COFF/loadcfg.ll+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | ; REQUIRES: x86 |
| 2 | 2 | ; RUN: llvm-as -o %t.obj %s |
| 3 | 3 | ; RUN: lld-link /out:%t.exe %t.obj /entry:main /subsystem:console |
| 4 | ; RUN: llvm-readobj -file-headers %t.exe | FileCheck %s | |
| 4 | ; RUN: llvm-readobj --file-headers %t.exe | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | ; CHECK: LoadConfigTableRVA: 0x2000 |
| 7 | 7 | ; CHECK: LoadConfigTableSize: 0x70 |
deps/lld/test/COFF/loadcfg.test+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | 2 | # RUN: lld-link /out:%t.exe %t.obj /entry:main /subsystem:console |
| 3 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s | |
| 3 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck %s | |
| 4 | 4 | |
| 5 | 5 | # CHECK: LoadConfigTableRVA: 0x2000 |
| 6 | 6 | # CHECK: LoadConfigTableSize: 0x70 |
deps/lld/test/COFF/loadcfg32.test+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | # RUN: lld-link /out:%t.exe %t.obj /entry:main /subsystem:console | |
| 3 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s | |
| 2 | # RUN: lld-link -safeseh:no /out:%t.exe %t.obj /entry:main /subsystem:console | |
| 3 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck %s | |
| 4 | 4 | |
| 5 | 5 | # CHECK: LoadConfigTableRVA: 0x2000 |
| 6 | 6 | # CHECK: LoadConfigTableSize: 0x40 |
deps/lld/test/COFF/locally-imported-arm64.test+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | 2 | # RUN: lld-link /out:%t.exe /entry:main %t.obj |
| 3 | 3 | # RUN: llvm-objdump -s %t.exe | FileCheck %s |
| 4 | # RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s | |
| 4 | # RUN: llvm-readobj --coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: Contents of section .text: |
| 7 | 7 | # CHECK-NEXT: 1000 00200000 |
deps/lld/test/COFF/locally-imported.test+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | 2 | # RUN: lld-link /out:%t.exe /entry:main %t.obj 2>&1 | FileCheck -check-prefix=WARN %s |
| 3 | 3 | # RUN: llvm-objdump -s %t.exe | FileCheck %s |
| 4 | # RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s | |
| 4 | # RUN: llvm-readobj --coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s | |
| 5 | 5 | |
| 6 | 6 | # WARN: warning: [[INPUT:.+]]: locally defined symbol imported: main (defined in [[INPUT]]) |
| 7 | 7 |
deps/lld/test/COFF/locally-imported32.test+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | # RUN: lld-link /out:%t.exe /entry:main %t.obj | |
| 2 | # RUN: lld-link -safeseh:no /out:%t.exe /entry:main %t.obj | |
| 3 | 3 | # RUN: llvm-objdump -s %t.exe | FileCheck %s |
| 4 | 4 | |
| 5 | 5 | # CHECK: Contents of section .text: |
deps/lld/test/COFF/long-section-name.test+2-2| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | 2 | # RUN: lld-link /out:%t.exe /entry:main %t.obj |
| 3 | # RUN: llvm-readobj -sections %t.exe | FileCheck %s | |
| 3 | # RUN: llvm-readobj --sections %t.exe | FileCheck %s | |
| 4 | 4 | # RUN: lld-link /debug /out:%t2.exe /entry:main %t.obj |
| 5 | # RUN: llvm-readobj -sections %t2.exe | FileCheck %s | |
| 5 | # RUN: llvm-readobj --sections %t2.exe | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: Name: .eh_fram ( |
| 8 | 8 | # CHECK: Name: .data_long_section_name |
deps/lld/test/COFF/lto-comdat.ll+9-6| ... | ... | @@ -14,40 +14,42 @@ |
| 14 | 14 | ; Check that, when we use an LTO main with LTO objects, we optimize away all |
| 15 | 15 | ; of f1, f2, and comdat. |
| 16 | 16 | ; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat1.lto.obj %T/comdat2.lto.obj |
| 17 | ; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-11 %s | |
| 17 | ; RUN: llvm-readobj --file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-11 %s | |
| 18 | 18 | ; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-11 %s |
| 19 | 19 | ; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat.lto.lib |
| 20 | ; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-11 %s | |
| 20 | ; RUN: llvm-readobj --file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-11 %s | |
| 21 | 21 | ; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-11 %s |
| 22 | 22 | |
| 23 | 23 | ; Check that, when we use a non-LTO main with LTO objects, we pick the comdat |
| 24 | 24 | ; implementation in LTO, elide calls to it from inside LTO, and retain the |
| 25 | 25 | ; call to comdat from main. |
| 26 | 26 | ; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.obj %T/comdat1.lto.obj %T/comdat2.lto.obj |
| 27 | ; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-01 %s | |
| 27 | ; RUN: llvm-readobj --file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-01 %s | |
| 28 | 28 | ; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-01 %s |
| 29 | 29 | ; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.obj %T/comdat.lto.lib |
| 30 | ; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-01 %s | |
| 30 | ; RUN: llvm-readobj --file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-01 %s | |
| 31 | 31 | ; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-01 %s |
| 32 | 32 | |
| 33 | 33 | ; Check that, when we use an LTO main with non-LTO objects, we pick the comdat |
| 34 | 34 | ; implementation in LTO, elide the call to it from inside LTO, and keep the |
| 35 | 35 | ; calls to comdat from the non-LTO objects. |
| 36 | 36 | ; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat1.obj %T/comdat2.obj |
| 37 | ; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-10 %s | |
| 37 | ; RUN: llvm-readobj --file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-10 %s | |
| 38 | 38 | ; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-10 %s |
| 39 | 39 | ; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat.lib |
| 40 | ; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-10 %s | |
| 40 | ; RUN: llvm-readobj --file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-10 %s | |
| 41 | 41 | ; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-10 %s |
| 42 | 42 | |
| 43 | 43 | ; HEADERS-11: AddressOfEntryPoint: 0x1000 |
| 44 | 44 | ; TEXT-11: Disassembly of section .text: |
| 45 | ; TEXT-11-EMPTY: | |
| 45 | 46 | ; TEXT-11-NEXT: .text: |
| 46 | 47 | ; TEXT-11-NEXT: xorl	%eax, %eax |
| 47 | 48 | ; TEXT-11-NEXT: retq |
| 48 | 49 | |
| 49 | 50 | ; HEADERS-01: AddressOfEntryPoint: 0x1000 |
| 50 | 51 | ; TEXT-01: Disassembly of section .text: |
| 52 | ; TEXT-01-EMPTY: | |
| 51 | 53 | ; TEXT-01-NEXT: .text: |
| 52 | 54 | ; TEXT-01-NEXT: subq	$40, %rsp |
| 53 | 55 | ; TEXT-01-NEXT: callq	23 |
| ... | ... | @@ -65,6 +67,7 @@ |
| 65 | 67 | |
| 66 | 68 | ; HEADERS-10: AddressOfEntryPoint: 0x1020 |
| 67 | 69 | ; TEXT-10: Disassembly of section .text: |
| 70 | ; TEXT-10-EMPTY: | |
| 68 | 71 | ; TEXT-10-NEXT: .text: |
| 69 | 72 | ; TEXT-10-NEXT: subq	$40, %rsp |
| 70 | 73 | ; TEXT-10-NEXT: callq	55 |
deps/lld/test/COFF/lto-icf.ll+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | |
| 5 | 5 | ; RUN: llvm-as %s -o %t.bc |
| 6 | 6 | ; RUN: lld-link -opt:icf -dll -noentry %t.bc -out:%t.dll |
| 7 | ; RUN: llvm-readobj -coff-exports %t.dll | FileCheck %s | |
| 7 | ; RUN: llvm-readobj --coff-exports %t.dll | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | ; CHECK: Export { |
| 10 | 10 | ; CHECK: Export { |
deps/lld/test/COFF/lto-lazy-reference.ll+4| ... | ... | @@ -9,6 +9,10 @@ |
| 9 | 9 | target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" |
| 10 | 10 | target triple = "i686-pc-windows-msvc18.0.0" |
| 11 | 11 | |
| 12 | ; Define fltused, since we don't link against the MS C runtime but are | |
| 13 | ; using floats. | |
| 14 | @_fltused = dllexport global i32 0, align 4 | |
| 15 | ||
| 12 | 16 | define double @main(double %x) { |
| 13 | 17 | entry: |
| 14 | 18 | ; When compiled, this defines the __real@40800000 symbol, which already has a |
deps/lld/test/COFF/lto-new-symbol.ll+4| ... | ... | @@ -5,6 +5,10 @@ |
| 5 | 5 | target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" |
| 6 | 6 | target triple = "x86_64-pc-windows-msvc" |
| 7 | 7 | |
| 8 | ; Define fltused, since we don't link against the MS C runtime but are | |
| 9 | ; using floats. | |
| 10 | @_fltused = dllexport global i32 0, align 4 | |
| 11 | ||
| 8 | 12 | define void @foo(<4 x i32>* %p, <4 x float>* %q, i1 %t) nounwind { |
| 9 | 13 | entry: |
| 10 | 14 | br label %loop |
deps/lld/test/COFF/lto.ll+9-6| ... | ... | @@ -10,30 +10,31 @@ |
| 10 | 10 | ; RUN: llvm-ar cru %T/foo.lib %T/foo.obj |
| 11 | 11 | |
| 12 | 12 | ; RUN: lld-link /out:%T/main.exe /entry:main /include:f2 /subsystem:console %T/main.lto.obj %T/foo.lto.obj |
| 13 | ; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-11 %s | |
| 13 | ; RUN: llvm-readobj --file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-11 %s | |
| 14 | 14 | ; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-11 %s |
| 15 | 15 | ; RUN: lld-link /out:%T/main.exe /entry:main /include:f2 /subsystem:console %T/main.lto.obj %T/foo.lto.lib /verbose 2>&1 | FileCheck -check-prefix=VERBOSE %s |
| 16 | ; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-11 %s | |
| 16 | ; RUN: llvm-readobj --file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-11 %s | |
| 17 | 17 | ; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-11 %s |
| 18 | 18 | |
| 19 | 19 | ; RUN: lld-link /out:%T/main.exe /entry:main /subsystem:console %T/main.obj %T/foo.lto.obj |
| 20 | ; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-01 %s | |
| 20 | ; RUN: llvm-readobj --file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-01 %s | |
| 21 | 21 | ; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-01 %s |
| 22 | 22 | ; RUN: lld-link /out:%T/main.exe /entry:main /subsystem:console %T/main.obj %T/foo.lto.lib |
| 23 | ; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-01 %s | |
| 23 | ; RUN: llvm-readobj --file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-01 %s | |
| 24 | 24 | ; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-01 %s |
| 25 | 25 | |
| 26 | 26 | ; RUN: lld-link /out:%T/main.exe /entry:main /subsystem:console %T/main.lto.obj %T/foo.obj |
| 27 | ; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-10 %s | |
| 27 | ; RUN: llvm-readobj --file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-10 %s | |
| 28 | 28 | ; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-10 %s |
| 29 | 29 | ; RUN: lld-link /out:%T/main.exe /entry:main /subsystem:console %T/main.lto.obj %T/foo.lib |
| 30 | ; RUN: llvm-readobj -file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-10 %s | |
| 30 | ; RUN: llvm-readobj --file-headers %T/main.exe | FileCheck -check-prefix=HEADERS-10 %s | |
| 31 | 31 | ; RUN: llvm-objdump -d %T/main.exe | FileCheck -check-prefix=TEXT-10 %s |
| 32 | 32 | |
| 33 | 33 | ; VERBOSE: foo.lto.lib({{.*}}foo.lto.obj) |
| 34 | 34 | |
| 35 | 35 | ; HEADERS-11: AddressOfEntryPoint: 0x1000 |
| 36 | 36 | ; TEXT-11: Disassembly of section .text: |
| 37 | ; TEXT-11-EMPTY: | |
| 37 | 38 | ; TEXT-11-NEXT: .text: |
| 38 | 39 | ; TEXT-11-NEXT: xorl	%eax, %eax |
| 39 | 40 | ; TEXT-11-NEXT: retq |
| ... | ... | @@ -55,6 +56,7 @@ |
| 55 | 56 | |
| 56 | 57 | ; HEADERS-01: AddressOfEntryPoint: 0x1000 |
| 57 | 58 | ; TEXT-01: Disassembly of section .text: |
| 59 | ; TEXT-01-EMPTY: | |
| 58 | 60 | ; TEXT-01-NEXT: .text: |
| 59 | 61 | ; TEXT-01-NEXT: subq	$40, %rsp |
| 60 | 62 | ; TEXT-01-NEXT: callq	23 |
| ... | ... | @@ -81,6 +83,7 @@ |
| 81 | 83 | |
| 82 | 84 | ; HEADERS-10: AddressOfEntryPoint: 0x1020 |
| 83 | 85 | ; TEXT-10: Disassembly of section .text: |
| 86 | ; TEXT-10-EMPTY: | |
| 84 | 87 | ; TEXT-10-NEXT: .text: |
| 85 | 88 | ; TEXT-10-NEXT: retq |
| 86 | 89 | ; TEXT-10-NEXT: nop |
deps/lld/test/COFF/machine.test+8-8| ... | ... | @@ -1,18 +1,18 @@ |
| 1 | 1 | # RUN: yaml2obj %p/Inputs/machine-x64.yaml > %t.obj |
| 2 | # RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj | |
| 3 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=AMD64 %s | |
| 4 | # RUN: lld-link /entry:main /subsystem:console /machine:x64 \ | |
| 2 | # RUN: lld-link -safeseh:no /entry:main /subsystem:console /out:%t.exe %t.obj | |
| 3 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=AMD64 %s | |
| 4 | # RUN: lld-link -safeseh:no /entry:main /subsystem:console /machine:x64 \ | |
| 5 | 5 | # RUN: /out:%t.exe %t.obj |
| 6 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=AMD64 %s | |
| 6 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=AMD64 %s | |
| 7 | 7 | |
| 8 | 8 | AMD64: Machine: IMAGE_FILE_MACHINE_AMD64 |
| 9 | 9 | |
| 10 | 10 | # RUN: yaml2obj %p/Inputs/machine-x86.yaml > %t.obj |
| 11 | # RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj | |
| 12 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=I386 %s | |
| 13 | # RUN: lld-link /entry:main /subsystem:console /machine:x86 \ | |
| 11 | # RUN: lld-link -safeseh:no /entry:main /subsystem:console /out:%t.exe %t.obj | |
| 12 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=I386 %s | |
| 13 | # RUN: lld-link -safeseh:no /entry:main /subsystem:console /machine:x86 \ | |
| 14 | 14 | # RUN: /out:%t.exe %t.obj /fixed |
| 15 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=I386 %s | |
| 15 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=I386 %s | |
| 16 | 16 | |
| 17 | 17 | I386: Machine: IMAGE_FILE_MACHINE_I386 |
| 18 | 18 |
deps/lld/test/COFF/manifestinput.test+2-2| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | # RUN: /manifest:embed \ |
| 6 | 6 | # RUN: /manifestuac:"level='requireAdministrator'" \ |
| 7 | 7 | # RUN: /manifestinput:%p/Inputs/manifestinput.test %t.obj |
| 8 | # RUN: llvm-readobj -coff-resources -file-headers %t.exe | FileCheck %s \ | |
| 8 | # RUN: llvm-readobj --coff-resources --file-headers %t.exe | FileCheck %s \ | |
| 9 | 9 | # RUN: -check-prefix TEST_EMBED |
| 10 | 10 | |
| 11 | 11 | TEST_EMBED: ResourceTableRVA: 0x2000 |
| ... | ... | @@ -14,7 +14,7 @@ TEST_EMBED-DAG: Resources [ |
| 14 | 14 | TEST_EMBED-NEXT: Total Number of Resources: 1 |
| 15 | 15 | TEST_EMBED-DAG: Number of String Entries: 0 |
| 16 | 16 | TEST_EMBED-NEXT: Number of ID Entries: 1 |
| 17 | TEST_EMBED-NEXT: Type: kRT_MANIFEST (ID 24) [ | |
| 17 | TEST_EMBED-NEXT: Type: MANIFEST (ID 24) [ | |
| 18 | 18 | TEST_EMBED-NEXT: Table Offset: 0x18 |
| 19 | 19 | TEST_EMBED-NEXT: Number of String Entries: 0 |
| 20 | 20 | TEST_EMBED-NEXT: Number of ID Entries: 1 |
deps/lld/test/COFF/merge.test+2-2| ... | ... | @@ -1,11 +1,11 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | 2 | # RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \ |
| 3 | 3 | # RUN: /merge:.foo=.abc /merge:.bar=.def %t.obj /debug |
| 4 | # RUN: llvm-readobj -sections %t.exe | FileCheck %s | |
| 4 | # RUN: llvm-readobj --sections %t.exe | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \ |
| 7 | 7 | # RUN: /merge:.foo=.bar /merge:.bar=.abc %t.obj /debug |
| 8 | # RUN: llvm-readobj -sections %t.exe | FileCheck --check-prefix=CHECK2 %s | |
| 8 | # RUN: llvm-readobj --sections %t.exe | FileCheck --check-prefix=CHECK2 %s | |
| 9 | 9 | |
| 10 | 10 | # RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \ |
| 11 | 11 | # RUN: /merge:.rsrc=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RSRC %s |
deps/lld/test/COFF/multiple-resource-objs.test created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | # RUN: llvm-cvtres /out:%t_resource.obj %S/Inputs/resource.res | |
| 2 | # RUN: llvm-cvtres /out:%t_id.obj %S/Inputs/id.res | |
| 3 | # RUN: not lld-link /out:%t.exe /dll /noentry %t_id.obj %t_resource.obj 2>&1 | \ | |
| 4 | # RUN: FileCheck --check-prefix=TWOOBJ %s | |
| 5 | ||
| 6 | TWOOBJ: error: {{.*}}_resource.obj: more than one resource obj file not allowed, already got {{.*}}_id.obj | |
| 7 | ||
| 8 | # RUN: not lld-link /out:%t.exe /dll /noentry %S/Inputs/id.res %t_resource.obj 2>&1 | \ | |
| 9 | # RUN: FileCheck --check-prefix=OBJRES %s | |
| 10 | ||
| 11 | OBJRES: error: internal .obj file created from .res files: more than one resource obj file not allowed, already got {{.*}}_resource.obj |
deps/lld/test/COFF/no-idata.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj |
| 4 | 4 | # RUN: lld-link -out:%t.exe -entry:main -subsystem:console %t.obj |
| 5 | 5 | # RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=DUMP %s |
| 6 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DIRECTORY %s | |
| 6 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=DIRECTORY %s | |
| 7 | 7 | |
| 8 | 8 | .text |
| 9 | 9 | .global main |
deps/lld/test/COFF/no-ipi-stream.test created+4| ... | ... | @@ -0,0 +1,4 @@ |
| 1 | # RUN: rm -rf %t && mkdir %t | |
| 2 | # RUN: yaml2obj < %p/Inputs/no-ipi-stream-obj.obj.yaml > %t/no-ipi-stream-obj.obj | |
| 3 | # RUN: llvm-pdbutil yaml2pdb %p/Inputs/no-ipi-stream-pdb.pdb.yaml -pdb=%t/no-ipi-stream-pdb.pdb | |
| 4 | # RUN: lld-link -safeseh:no /dll /noentry /debug %t/no-ipi-stream-obj.obj |
deps/lld/test/COFF/nodefaultlib.test+9-2| ... | ... | @@ -19,8 +19,8 @@ |
| 19 | 19 | # RUN: /nodefaultlib:std64.lib >& %t.log || true |
| 20 | 20 | # RUN: FileCheck -check-prefix=CHECK3 %s < %t.log |
| 21 | 21 | |
| 22 | CHECK1: error: could not open hello64.obj: {{[Nn]}}o such file or directory | |
| 23 | CHECK2: error: could not open hello64: {{[Nn]}}o such file or directory | |
| 22 | CHECK1: error: could not open 'hello64.obj': {{[Nn]}}o such file or directory | |
| 23 | CHECK2: error: could not open 'hello64': {{[Nn]}}o such file or directory | |
| 24 | 24 | CHECK3: error: undefined symbol: MessageBoxA |
| 25 | 25 | CHECK3-NEXT: >>> referenced by {{.*}}hello64.obj:(main) |
| 26 | 26 | |
| ... | ... | @@ -29,3 +29,10 @@ CHECK3-NEXT: >>> referenced by {{.*}}hello64.obj:(main) |
| 29 | 29 | |
| 30 | 30 | # RUN: env LIB=%T lld-link /out:%t.exe /entry:main \ |
| 31 | 31 | # RUN: /subsystem:console hello64.obj /defaultlib:std64.lib |
| 32 | ||
| 33 | MSVC stamps uppercase references in OBJ directives, thus ensure that passing lowercase 'libcmt' and 'oldnames' to /nodefaultlib works. | |
| 34 | # RUN: lld-link %S/Inputs/precomp.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib:libcmt /nodefaultlib:oldnames /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf | |
| 35 | # RUN: llvm-pdbutil dump -modules %t.pdb | FileCheck %s -check-prefix UPPERCASE | |
| 36 | ||
| 37 | UPPERCASE-NOT: OLDNAMES | |
| 38 | UPPERCASE-NOT: LIBCMT |
deps/lld/test/COFF/noentry.test+2-2| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | 1 | # RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj |
| 2 | 2 | # RUN: lld-link /out:%t.dll /dll %t.obj |
| 3 | # RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=ENTRY %s | |
| 3 | # RUN: llvm-readobj --file-headers %t.dll | FileCheck -check-prefix=ENTRY %s | |
| 4 | 4 | # RUN: lld-link /out:%t.dll /dll /noentry %t.obj |
| 5 | # RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=NOENTRY %s | |
| 5 | # RUN: llvm-readobj --file-headers %t.dll | FileCheck -check-prefix=NOENTRY %s | |
| 6 | 6 | |
| 7 | 7 | ENTRY: AddressOfEntryPoint: 0x1000 |
| 8 | 8 | NOENTRY: AddressOfEntryPoint: 0x0 |
deps/lld/test/COFF/options.test+60-20| ... | ... | @@ -1,65 +1,105 @@ |
| 1 | 1 | # RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj |
| 2 | 2 | |
| 3 | 3 | # RUN: lld-link /out:%t.exe /entry:main %t.obj |
| 4 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BIND %s | |
| 4 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=BIND %s | |
| 5 | 5 | # RUN: lld-link /allowbind /out:%t.exe /entry:main %t.obj |
| 6 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BIND %s | |
| 6 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=BIND %s | |
| 7 | 7 | BIND-NOT: IMAGE_DLL_CHARACTERISTICS_NO_BIND |
| 8 | 8 | |
| 9 | 9 | # RUN: lld-link /allowbind:no /out:%t.exe /entry:main %t.obj |
| 10 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOBIND %s | |
| 10 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=NOBIND %s | |
| 11 | 11 | NOBIND: IMAGE_DLL_CHARACTERISTICS_NO_BIND |
| 12 | 12 | |
| 13 | 13 | # RUN: lld-link /out:%t.exe /entry:main %t.obj |
| 14 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ISO %s | |
| 14 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=ISO %s | |
| 15 | 15 | # RUN: lld-link /allowisolation /out:%t.exe /entry:main %t.obj |
| 16 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ISO %s | |
| 16 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=ISO %s | |
| 17 | 17 | ISO-NOT: IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION |
| 18 | 18 | |
| 19 | 19 | # RUN: lld-link /allowisolation:no /out:%t.exe /entry:main %t.obj |
| 20 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOISO %s | |
| 20 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=NOISO %s | |
| 21 | 21 | NOISO: IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION |
| 22 | 22 | |
| 23 | 23 | # RUN: lld-link /out:%t.exe /entry:main %t.obj |
| 24 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ENT %s | |
| 24 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=ENT %s | |
| 25 | 25 | # RUN: lld-link /out:%t.exe /entry:main /highentropyva %t.obj |
| 26 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ENT %s | |
| 26 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=ENT %s | |
| 27 | 27 | ENT: IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA |
| 28 | 28 | |
| 29 | 29 | # RUN: lld-link /out:%t.exe /highentropyva:no /out:%t.exe /entry:main %t.obj |
| 30 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOENT %s | |
| 30 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=NOENT %s | |
| 31 | 31 | NOENT-NOT: IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA |
| 32 | 32 | |
| 33 | 33 | # RUN: lld-link /out:%t.exe /entry:main /integritycheck %t.obj |
| 34 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=INT %s | |
| 34 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=INT %s | |
| 35 | 35 | INT: IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY |
| 36 | 36 | |
| 37 | 37 | # RUN: lld-link /out:%t.exe /entry:main %t.obj |
| 38 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOINT %s | |
| 38 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=NOINT %s | |
| 39 | 39 | # RUN: lld-link /out:%t.exe /integritycheck:no /out:%t.exe /entry:main %t.obj |
| 40 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOINT %s | |
| 40 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=NOINT %s | |
| 41 | 41 | NOINT-NOT: IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY |
| 42 | 42 | |
| 43 | 43 | # RUN: lld-link /out:%t.exe /entry:main %t.obj |
| 44 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NXCOMPAT %s | |
| 44 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=NXCOMPAT %s | |
| 45 | 45 | # RUN: lld-link /out:%t.exe /entry:main /nxcompat %t.obj |
| 46 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NXCOMPAT %s | |
| 46 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=NXCOMPAT %s | |
| 47 | 47 | NXCOMPAT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT |
| 48 | 48 | |
| 49 | 49 | # RUN: lld-link /out:%t.exe /nxcompat:no /out:%t.exe /entry:main %t.obj |
| 50 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NONXCOMPAT %s | |
| 50 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=NONXCOMPAT %s | |
| 51 | 51 | NONXCOMPAT-NOT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT |
| 52 | 52 | |
| 53 | # RUN: lld-link /out:%t.exe /entry:main /swaprun:CD %t.obj | |
| 54 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=SWAPCD %s | |
| 55 | # RUN: lld-link /out:%t.exe /entry:main /swaprun:cd,net %t.obj | |
| 56 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=SWAPCD %s | |
| 57 | SWAPCD: IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP | |
| 58 | ||
| 59 | # RUN: lld-link /out:%t.exe /entry:main %t.obj | |
| 60 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=NOSWAPCD %s | |
| 61 | NOSWAPCD-NOT: IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP | |
| 62 | ||
| 63 | # RUN: lld-link /out:%t.exe /entry:main /swaprun:NeT %t.obj | |
| 64 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=SWAPNET %s | |
| 65 | # RUN: lld-link /out:%t.exe /entry:main /swaprun:net,cd,cd,net %t.obj | |
| 66 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=SWAPNET %s | |
| 67 | SWAPNET: IMAGE_FILE_NET_RUN_FROM_SWAP | |
| 68 | ||
| 69 | # RUN: lld-link /out:%t.exe /entry:main %t.obj | |
| 70 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=NOSWAPNET %s | |
| 71 | NOSWAPNET-NOT: IMAGE_FILE_NET_RUN_FROM_SWAP | |
| 72 | ||
| 73 | # RUN: not lld-link /out:%t.exe /entry:main /swaprun: %t.obj 2>&1 | \ | |
| 74 | # RUN: FileCheck -check-prefix=SWAPERR1 %s | |
| 75 | # RUN: not lld-link /out:%t.exe /entry:main /swaprun:cd, %t.obj 2>&1 | \ | |
| 76 | # RUN: FileCheck -check-prefix=SWAPERR1 %s | |
| 77 | # RUN: not lld-link /out:%t.exe /entry:main /swaprun:,, %t.obj 2>&1 | \ | |
| 78 | # RUN: FileCheck -check-prefix=SWAPERR1 %s | |
| 79 | # RUN: not lld-link /out:%t.exe /entry:main /swaprun:,cd %t.obj 2>&1 | \ | |
| 80 | # RUN: FileCheck -check-prefix=SWAPERR1 %s | |
| 81 | SWAPERR1: /swaprun: missing argument | |
| 82 | ||
| 83 | # RUN: not lld-link /out:%t.exe /entry:main /swaprun:foo %t.obj 2>&1 | \ | |
| 84 | # RUN: FileCheck -check-prefix=SWAPERR2 %s | |
| 85 | # RUN: not lld-link /out:%t.exe /entry:main /swaprun:cd,foo,net %t.obj 2>&1 | \ | |
| 86 | # RUN: FileCheck -check-prefix=SWAPERR2 %s | |
| 87 | SWAPERR2: /swaprun: invalid argument: foo | |
| 88 | ||
| 89 | # RUN: not lld-link /out:%t.exe /entry:main /swaprun:cdfoo,net %t.obj 2>&1 | \ | |
| 90 | # RUN: FileCheck -check-prefix=SWAPERR3 %s | |
| 91 | SWAPERR3: /swaprun: invalid argument: cdfoo | |
| 92 | ||
| 53 | 93 | # RUN: lld-link /out:%t.exe /entry:main %t.obj |
| 54 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=TSAWARE %s | |
| 94 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=TSAWARE %s | |
| 55 | 95 | # RUN: lld-link /out:%t.exe /entry:main /tsaware %t.obj |
| 56 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=TSAWARE %s | |
| 96 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=TSAWARE %s | |
| 57 | 97 | TSAWARE: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE |
| 58 | 98 | |
| 59 | 99 | # RUN: lld-link /tsaware:no /out:%t.exe /entry:main %t.obj |
| 60 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOTSAWARE %s | |
| 100 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=NOTSAWARE %s | |
| 61 | 101 | # RUN: lld-link /dll /out:%t.dll /entry:main %t.obj |
| 62 | # RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=NOTSAWARE %s | |
| 102 | # RUN: llvm-readobj --file-headers %t.dll | FileCheck -check-prefix=NOTSAWARE %s | |
| 63 | 103 | # RUN: lld-link /tsaware /dll /out:%t.dll /entry:main %t.obj |
| 64 | # RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=NOTSAWARE %s | |
| 104 | # RUN: llvm-readobj --file-headers %t.dll | FileCheck -check-prefix=NOTSAWARE %s | |
| 65 | 105 | NOTSAWARE-NOT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE |
deps/lld/test/COFF/order-i386.test+2-2| ... | ... | @@ -3,12 +3,12 @@ |
| 3 | 3 | # RUN: echo fn1 > %t.order |
| 4 | 4 | # RUN: echo fn2 >> %t.order |
| 5 | 5 | |
| 6 | # RUN: lld-link -entry:fn1 -subsystem:console -opt:noref %t.obj \ | |
| 6 | # RUN: lld-link -safeseh:no -entry:fn1 -subsystem:console -opt:noref %t.obj \ | |
| 7 | 7 | # RUN: -lldmap:- -out:%t.exe -order:@%t.order | FileCheck %s |
| 8 | 8 | # CHECK: fn1 |
| 9 | 9 | # CHECK: fn2 |
| 10 | 10 | |
| 11 | # RUN: lld-link -entry:fn1 -subsystem:console -opt:noref %t.obj \ | |
| 11 | # RUN: lld-link -safeseh:no -entry:fn1 -subsystem:console -opt:noref %t.obj \ | |
| 12 | 12 | # RUN: -lldmap:- -out:%t.exe | FileCheck -check-prefix=DEFAULT %s |
| 13 | 13 | # DEFAULT: fn2 |
| 14 | 14 | # DEFAULT: fn1 |
deps/lld/test/COFF/output-chars.test+4-4| ... | ... | @@ -1,12 +1,12 @@ |
| 1 | 1 | # RUN: yaml2obj %s > %t.obj |
| 2 | 2 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj |
| 3 | # RUN: llvm-readobj -sections %t.dll | FileCheck %s | |
| 3 | # RUN: llvm-readobj --sections %t.dll | FileCheck %s | |
| 4 | 4 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj /section:.foo,rwe |
| 5 | # RUN: llvm-readobj -sections %t.dll | FileCheck --check-prefix=SECTION %s | |
| 5 | # RUN: llvm-readobj --sections %t.dll | FileCheck --check-prefix=SECTION %s | |
| 6 | 6 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj /merge:.foo=.bar |
| 7 | # RUN: llvm-readobj -sections -section-data %t.dll | FileCheck --check-prefix=MERGE %s | |
| 7 | # RUN: llvm-readobj --sections --section-data %t.dll | FileCheck --check-prefix=MERGE %s | |
| 8 | 8 | # RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj /merge:.foo=.bar /section:.foo,rwe |
| 9 | # RUN: llvm-readobj -sections %t.dll | FileCheck --check-prefix=MERGE-SECTION %s | |
| 9 | # RUN: llvm-readobj --sections %t.dll | FileCheck --check-prefix=MERGE-SECTION %s | |
| 10 | 10 | |
| 11 | 11 | # CHECK: Name: .foo |
| 12 | 12 | # CHECK: Characteristics [ |
deps/lld/test/COFF/pdb-comdat.test+2-2| ... | ... | @@ -48,9 +48,9 @@ CHECK-NEXT: module = 2, sum name = 0, offset = 120 |
| 48 | 48 | CHECK-NEXT: 128 | S_PROCREF [size = 20] `foo` |
| 49 | 49 | CHECK-NEXT: module = 1, sum name = 0, offset = 208 |
| 50 | 50 | CHECK-NEXT: 104 | S_GDATA32 [size = 24] `global` |
| 51 | CHECK-NEXT: type = 0x0074 (int), addr = 0000:0000 | |
| 51 | CHECK-NEXT: type = 0x0074 (int), addr = 0003:0000 | |
| 52 | 52 | CHECK-NEXT: 168 | S_GDATA32 [size = 24] `global` |
| 53 | CHECK-NEXT: type = 0x0074 (int), addr = 0000:0000 | |
| 53 | CHECK-NEXT: type = 0x0074 (int), addr = 0003:0000 | |
| 54 | 54 | |
| 55 | 55 | CHECK: Symbols |
| 56 | 56 | CHECK: ============================================================ |
deps/lld/test/COFF/pdb-debug-f.s+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -triple=i386-pc-win32 -filetype=obj -o %t.obj %s |
| 3 | # RUN: lld-link /subsystem:console /debug /nodefaultlib /entry:foo /out:%t.exe /pdb:%t.pdb %t.obj | |
| 3 | # RUN: lld-link -safeseh:no /subsystem:console /debug /nodefaultlib /entry:foo /out:%t.exe /pdb:%t.pdb %t.obj | |
| 4 | 4 | # RUN: llvm-pdbutil dump -fpo %t.pdb | FileCheck %s |
| 5 | 5 | |
| 6 | 6 | # CHECK: Old FPO Data |
deps/lld/test/COFF/pdb-exe-path-dots.test+1-1| ... | ... | @@ -5,6 +5,6 @@ RUN: mkdir %t |
| 5 | 5 | RUN: mkdir %t/foo |
| 6 | 6 | RUN: lld-link /debug /pdb:%t/foo/./out.pdb /out:%t/out.exe /entry:main /nodefaultlib \ |
| 7 | 7 | RUN: %t1.obj %t2.obj |
| 8 | RUN: llvm-readobj -coff-debug-directory %t/out.exe | FileCheck %s | |
| 8 | RUN: llvm-readobj --coff-debug-directory %t/out.exe | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | CHECK: PDBFileName: {{.*}}tmp{{/|\\}}foo{{/|\\}}out.pdb |
| \ No newline at end of file |
deps/lld/test/COFF/pdb-global-constants.test created+28| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj %S/Inputs/pdb-global-constants-a.s -o %t-a.obj -triple x86_64-windows-msvc | |
| 3 | # RUN: llvm-mc -filetype=obj %S/Inputs/pdb-global-constants-b.s -o %t-b.obj -triple x86_64-windows-msvc | |
| 4 | # RUN: lld-link -entry:main -nodefaultlib %t-a.obj %t-b.obj -out:%t.exe -pdb:%t.pdb -debug | |
| 5 | # RUN: llvm-pdbutil dump -globals %t.pdb | FileCheck %s | |
| 6 | ||
| 7 | # Test that lld deduplicates S_CONSTANT records with the same name and value. | |
| 8 | # | |
| 9 | # Compiled from this C code, using | |
| 10 | # clang t.cpp -g -gcodeview -S | |
| 11 | # | |
| 12 | # %t-a.cpp: | |
| 13 | # const int Foo = 41; | |
| 14 | # const int Bar = 42; | |
| 15 | # int main() { return Foo + Bar; } | |
| 16 | # | |
| 17 | # %t-b.cpp: | |
| 18 | # const int Foo = 42; | |
| 19 | # const int Bar = 42; | |
| 20 | # int foobar() { return Foo + Bar; } | |
| 21 | ||
| 22 | CHECK: Global Symbols | |
| 23 | CHECK: 88 | S_CONSTANT [size = 16] `Bar` | |
| 24 | CHECK-NEXT: type = 0x1002 (const int), value = 42 | |
| 25 | CHECK-NEXT: 72 | S_CONSTANT [size = 16] `Foo` | |
| 26 | CHECK-NEXT: type = 0x1002 (const int), value = 41 | |
| 27 | CHECK-NEXT: 128 | S_CONSTANT [size = 16] `Foo` | |
| 28 | CHECK-NEXT: type = 0x1002 (const int), value = 42 |
deps/lld/test/COFF/pdb-global-gc.yaml+1| ... | ... | @@ -23,6 +23,7 @@ |
| 23 | 23 | # CHECK: ============================================================ |
| 24 | 24 | # CHECK-NEXT: Mod 0000 | `{{.*}}pdb-global-gc.yaml.tmp.obj`: |
| 25 | 25 | # CHECK-NEXT: Mod 0001 | `{{.*}}pdb-global-gc.yaml.tmp2.obj`: |
| 26 | # CHECK-NEXT: Error loading module stream 1. The specified stream could not be loaded. Module stream not present | |
| 26 | 27 | # CHECK-NEXT: Mod 0002 | `* Linker *`: |
| 27 | 28 | |
| 28 | 29 | --- !COFF |
deps/lld/test/COFF/pdb-globals.test+5| ... | ... | @@ -2,6 +2,11 @@ RUN: yaml2obj %S/Inputs/pdb-globals.yaml > %t.obj |
| 2 | 2 | RUN: lld-link /debug /nodefaultlib /entry:main /out:%t.exe /pdb:%t.pdb %t.obj |
| 3 | 3 | RUN: llvm-pdbutil dump -symbols -globals %t.pdb | FileCheck %s |
| 4 | 4 | |
| 5 | RUN: lld-link /debug /nodefaultlib /entry:main /out:%t.exe /pdb:%t.pdb %t.obj /threads | |
| 6 | RUN: llvm-pdbutil dump -symbols -globals %t.pdb | FileCheck %s | |
| 7 | RUN: lld-link /debug /nodefaultlib /entry:main /out:%t.exe /pdb:%t.pdb %t.obj /threads:no | |
| 8 | RUN: llvm-pdbutil dump -symbols -globals %t.pdb | FileCheck %s | |
| 9 | ||
| 5 | 10 | # Test that we correctly distribute symbols between the globals and module |
| 6 | 11 | # symbol streams. Specifically: |
| 7 | 12 | # * S_UDT, S_GDATA32, and S_CONSTANT end up in the globals stream, and are |
deps/lld/test/COFF/pdb-inlinees-extrafiles.s created+334| ... | ... | @@ -0,0 +1,334 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj %s -o %t.obj -triple x86_64-windows-msvc | |
| 3 | # RUN: lld-link -entry:main -nodefaultlib %t.obj -out:%t.exe -pdb:%t.pdb -debug | |
| 4 | # RUN: llvm-pdbutil dump -il %t.pdb | FileCheck %s | |
| 5 | ||
| 6 | # The assembly was hand written to model the following C code. As of this | |
| 7 | # writing, clang does not emit extra files for inlinees, so it had to be hand | |
| 8 | # written. | |
| 9 | ||
| 10 | # // t1.h: | |
| 11 | # ++x; | |
| 12 | # #include "t2.h" | |
| 13 | # ++x; | |
| 14 | ||
| 15 | # // t2.h: | |
| 16 | # ++x; | |
| 17 | # __debugbreak(); | |
| 18 | # ++x; | |
| 19 | ||
| 20 | # // t.c: | |
| 21 | # volatile int x; | |
| 22 | # static __forceinline void inlinee_1(void) { | |
| 23 | # ++x; | |
| 24 | # #include "t1.inc" | |
| 25 | # ++x; | |
| 26 | # } | |
| 27 | # int main() { | |
| 28 | # ++x; | |
| 29 | # inlinee_1(); | |
| 30 | # ++x; | |
| 31 | # return x; | |
| 32 | # } | |
| 33 | ||
| 34 | # CHECK: Inlinee Lines | |
| 35 | # CHECK: Mod 0000 | `{{.*}}pdb-inlinees-extrafiles.s.tmp.obj`: | |
| 36 | # CHECK-NEXT: Inlinee | Line | Source File | |
| 37 | # CHECK-NEXT: 0x1000 | 7 | C:\src\llvm-project\build\t.c (MD5: A79D837C976E9F0463A474D74E2EE9E7) | |
| 38 | # CHECK-NEXT: C:\src\llvm-project\build\t1.h (MD5: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | |
| 39 | # CHECK-NEXT: C:\src\llvm-project\build\t2.h (MD5: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | |
| 40 | ||
| 41 | 	.text | |
| 42 | 	.def	 @feat.00; | |
| 43 | 	.scl	3; | |
| 44 | 	.type	0; | |
| 45 | 	.endef | |
| 46 | 	.globl	@feat.00 | |
| 47 | .set @feat.00, 0 | |
| 48 | 	.intel_syntax noprefix | |
| 49 | 	.file	"t.c" | |
| 50 | 	.def	 main; | |
| 51 | 	.scl	2; | |
| 52 | 	.type	32; | |
| 53 | 	.endef | |
| 54 | 	.section	.text,"xr",one_only,main | |
| 55 | 	.globl	main # -- Begin function main | |
| 56 | main: # @main | |
| 57 | .Lfunc_begin0: | |
| 58 | 	.cv_func_id 0 | |
| 59 | # %bb.0: # %entry | |
| 60 | 	.cv_file	1 "C:\\src\\llvm-project\\build\\t.c" "A79D837C976E9F0463A474D74E2EE9E7" 1 | |
| 61 | 	.cv_file	2 "C:\\src\\llvm-project\\build\\t1.h" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" 1 | |
| 62 | 	.cv_file	3 "C:\\src\\llvm-project\\build\\t2.h" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" 1 | |
| 63 | 	.cv_loc	0 1 13 0 # t.c:13:0 | |
| 64 | 	inc	dword ptr [rip + x] | |
| 65 | .Ltmp0: | |
| 66 | 	.cv_inline_site_id 1 within 0 inlined_at 1 14 0 | |
| 67 | 	.cv_loc	1 1 3 0 # t.c:3:0 | |
| 68 | 	inc	dword ptr [rip + x] | |
| 69 | .Ltmp1: | |
| 70 | 	.cv_loc	1 2 1 0 # t1.h:1:0 | |
| 71 | 	inc	dword ptr [rip + x] | |
| 72 | 	.cv_loc	1 3 1 0 # t2.h:1:0 | |
| 73 | 	inc	dword ptr [rip + x] | |
| 74 | 	.cv_loc	1 3 2 0 # t2.h:2:0 | |
| 75 | 	int3 | |
| 76 | 	.cv_loc	1 3 3 0 # t2.h:3:0 | |
| 77 | 	inc	dword ptr [rip + x] | |
| 78 | 	.cv_loc	1 2 3 0 # t1.h:3:0 | |
| 79 | 	inc	dword ptr [rip + x] | |
| 80 | .Ltmp2: | |
| 81 | 	.cv_loc	1 1 5 0 # t.c:5:0 | |
| 82 | 	inc	dword ptr [rip + x] | |
| 83 | .Ltmp3: | |
| 84 | 	.cv_loc	0 1 15 0 # t.c:15:0 | |
| 85 | 	inc	dword ptr [rip + x] | |
| 86 | 	.cv_loc	0 1 16 0 # t.c:16:0 | |
| 87 | 	mov	eax, dword ptr [rip + x] | |
| 88 | 	ret | |
| 89 | .Ltmp4: | |
| 90 | .Lfunc_end0: | |
| 91 | # -- End function | |
| 92 | 	.comm	x,4,2 # @x | |
| 93 | 	.section	.debug$S,"dr" | |
| 94 | 	.p2align	2 | |
| 95 | 	.long	4 # Debug section magic | |
| 96 | 	.long	241 | |
| 97 | 	.long	.Ltmp6-.Ltmp5 # Subsection size | |
| 98 | .Ltmp5: | |
| 99 | 	.short	.Ltmp8-.Ltmp7 # Record length | |
| 100 | .Ltmp7: | |
| 101 | 	.short	4412 # Record kind: S_COMPILE3 | |
| 102 | 	.long	0 # Flags and language | |
| 103 | 	.short	208 # CPUType | |
| 104 | 	.short	9 # Frontend version | |
| 105 | 	.short	0 | |
| 106 | 	.short	0 | |
| 107 | 	.short	0 | |
| 108 | 	.short	9000 # Backend version | |
| 109 | 	.short	0 | |
| 110 | 	.short	0 | |
| 111 | 	.short	0 | |
| 112 | 	.asciz	"clang version 9.0.0 (git@github.com:llvm/llvm-project.git aa762a56caf3ef2b0b41c501e66d3ef32903a2d0)" # Null-terminated compiler version string | |
| 113 | 	.p2align	2 | |
| 114 | .Ltmp8: | |
| 115 | .Ltmp6: | |
| 116 | 	.p2align	2 | |
| 117 | 	.long	246 # Inlinee lines subsection | |
| 118 | 	.long	.Ltmp10-.Ltmp9 # Subsection size | |
| 119 | .Ltmp9: | |
| 120 | 	.long	1 # Inlinee lines signature, extra files | |
| 121 | ||
| 122 | # Inlined function inlinee_1 starts at t.c:7 | |
| 123 | 	.long	4098 # Type index of inlined function | |
| 124 | 	.cv_filechecksumoffset	1 # Offset into filechecksum table | |
| 125 | 	.long	7 # Starting line number | |
| 126 | 	.long 2 | |
| 127 | 	.cv_filechecksumoffset	2 # Offset into filechecksum table | |
| 128 | 	.cv_filechecksumoffset	3 # Offset into filechecksum table | |
| 129 | ||
| 130 | .Ltmp10: | |
| 131 | 	.p2align	2 | |
| 132 | 	.section	.debug$S,"dr",associative,main | |
| 133 | 	.p2align	2 | |
| 134 | 	.long	4 # Debug section magic | |
| 135 | 	.long	241 # Symbol subsection for main | |
| 136 | 	.long	.Ltmp12-.Ltmp11 # Subsection size | |
| 137 | .Ltmp11: | |
| 138 | 	.short	.Ltmp14-.Ltmp13 # Record length | |
| 139 | .Ltmp13: | |
| 140 | 	.short	4423 # Record kind: S_GPROC32_ID | |
| 141 | 	.long	0 # PtrParent | |
| 142 | 	.long	0 # PtrEnd | |
| 143 | 	.long	0 # PtrNext | |
| 144 | 	.long	.Lfunc_end0-main # Code size | |
| 145 | 	.long	0 # Offset after prologue | |
| 146 | 	.long	0 # Offset before epilogue | |
| 147 | 	.long	4101 # Function type index | |
| 148 | 	.secrel32	main # Function section relative address | |
| 149 | 	.secidx	main # Function section index | |
| 150 | 	.byte	0 # Flags | |
| 151 | 	.asciz	"main" # Function name | |
| 152 | 	.p2align	2 | |
| 153 | .Ltmp14: | |
| 154 | 	.short	.Ltmp16-.Ltmp15 # Record length | |
| 155 | .Ltmp15: | |
| 156 | 	.short	4114 # Record kind: S_FRAMEPROC | |
| 157 | 	.long	0 # FrameSize | |
| 158 | 	.long	0 # Padding | |
| 159 | 	.long	0 # Offset of padding | |
| 160 | 	.long	0 # Bytes of callee saved registers | |
| 161 | 	.long	0 # Exception handler offset | |
| 162 | 	.short	0 # Exception handler section | |
| 163 | 	.long	0 # Flags (defines frame register) | |
| 164 | 	.p2align	2 | |
| 165 | .Ltmp16: | |
| 166 | 	.short	.Ltmp18-.Ltmp17 # Record length | |
| 167 | .Ltmp17: | |
| 168 | 	.short	4429 # Record kind: S_INLINESITE | |
| 169 | 	.long	0 # PtrParent | |
| 170 | 	.long	0 # PtrEnd | |
| 171 | 	.long	4098 # Inlinee type index | |
| 172 | 	.cv_inline_linetable	1 1 7 .Lfunc_begin0 .Lfunc_end0 | |
| 173 | 	.p2align	2 | |
| 174 | .Ltmp18: | |
| 175 | 	.short	2 # Record length | |
| 176 | 	.short	4430 # Record kind: S_INLINESITE_END | |
| 177 | 	.short	2 # Record length | |
| 178 | 	.short	4431 # Record kind: S_PROC_ID_END | |
| 179 | .Ltmp12: | |
| 180 | 	.p2align	2 | |
| 181 | 	.cv_linetable	0, main, .Lfunc_end0 | |
| 182 | 	.section	.debug$S,"dr" | |
| 183 | 	.long	241 # Symbol subsection for globals | |
| 184 | 	.long	.Ltmp22-.Ltmp21 # Subsection size | |
| 185 | .Ltmp21: | |
| 186 | 	.short	.Ltmp24-.Ltmp23 # Record length | |
| 187 | .Ltmp23: | |
| 188 | 	.short	4365 # Record kind: S_GDATA32 | |
| 189 | 	.long	4102 # Type | |
| 190 | 	.secrel32	x # DataOffset | |
| 191 | 	.secidx	x # Segment | |
| 192 | 	.asciz	"x" # Name | |
| 193 | 	.p2align	2 | |
| 194 | .Ltmp24: | |
| 195 | .Ltmp22: | |
| 196 | 	.p2align	2 | |
| 197 | 	.cv_filechecksums # File index to string table offset subsection | |
| 198 | 	.cv_stringtable # String table | |
| 199 | 	.long	241 | |
| 200 | 	.long	.Ltmp26-.Ltmp25 # Subsection size | |
| 201 | .Ltmp25: | |
| 202 | 	.short	.Ltmp28-.Ltmp27 # Record length | |
| 203 | .Ltmp27: | |
| 204 | 	.short	4428 # Record kind: S_BUILDINFO | |
| 205 | 	.long	4105 # LF_BUILDINFO index | |
| 206 | 	.p2align	2 | |
| 207 | .Ltmp28: | |
| 208 | .Ltmp26: | |
| 209 | 	.p2align	2 | |
| 210 | 	.section	.debug$T,"dr" | |
| 211 | 	.p2align	2 | |
| 212 | 	.long	4 # Debug section magic | |
| 213 | 	# ArgList (0x1000) { | |
| 214 | 	# TypeLeafKind: LF_ARGLIST (0x1201) | |
| 215 | 	# NumArgs: 0 | |
| 216 | 	# Arguments [ | |
| 217 | 	# ] | |
| 218 | 	# } | |
| 219 | 	.byte	0x06, 0x00, 0x01, 0x12 | |
| 220 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 221 | 	# Procedure (0x1001) { | |
| 222 | 	# TypeLeafKind: LF_PROCEDURE (0x1008) | |
| 223 | 	# ReturnType: void (0x3) | |
| 224 | 	# CallingConvention: NearC (0x0) | |
| 225 | 	# FunctionOptions [ (0x0) | |
| 226 | 	# ] | |
| 227 | 	# NumParameters: 0 | |
| 228 | 	# ArgListType: () (0x1000) | |
| 229 | 	# } | |
| 230 | 	.byte	0x0e, 0x00, 0x08, 0x10 | |
| 231 | 	.byte	0x03, 0x00, 0x00, 0x00 | |
| 232 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 233 | 	.byte	0x00, 0x10, 0x00, 0x00 | |
| 234 | 	# FuncId (0x1002) { | |
| 235 | 	# TypeLeafKind: LF_FUNC_ID (0x1601) | |
| 236 | 	# ParentScope: 0x0 | |
| 237 | 	# FunctionType: void () (0x1001) | |
| 238 | 	# Name: inlinee_1 | |
| 239 | 	# } | |
| 240 | 	.byte	0x16, 0x00, 0x01, 0x16 | |
| 241 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 242 | 	.byte	0x01, 0x10, 0x00, 0x00 | |
| 243 | 	.byte	0x69, 0x6e, 0x6c, 0x69 | |
| 244 | 	.byte	0x6e, 0x65, 0x65, 0x5f | |
| 245 | 	.byte	0x31, 0x00, 0xf2, 0xf1 | |
| 246 | 	# FuncId (0x1003) { | |
| 247 | 	# TypeLeafKind: LF_FUNC_ID (0x1601) | |
| 248 | 	# ParentScope: 0x0 | |
| 249 | 	# FunctionType: void () (0x1001) | |
| 250 | 	# Name: inlinee_2 | |
| 251 | 	# } | |
| 252 | 	.byte	0x16, 0x00, 0x01, 0x16 | |
| 253 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 254 | 	.byte	0x01, 0x10, 0x00, 0x00 | |
| 255 | 	.byte	0x69, 0x6e, 0x6c, 0x69 | |
| 256 | 	.byte	0x6e, 0x65, 0x65, 0x5f | |
| 257 | 	.byte	0x32, 0x00, 0xf2, 0xf1 | |
| 258 | 	# Procedure (0x1004) { | |
| 259 | 	# TypeLeafKind: LF_PROCEDURE (0x1008) | |
| 260 | 	# ReturnType: int (0x74) | |
| 261 | 	# CallingConvention: NearC (0x0) | |
| 262 | 	# FunctionOptions [ (0x0) | |
| 263 | 	# ] | |
| 264 | 	# NumParameters: 0 | |
| 265 | 	# ArgListType: () (0x1000) | |
| 266 | 	# } | |
| 267 | 	.byte	0x0e, 0x00, 0x08, 0x10 | |
| 268 | 	.byte	0x74, 0x00, 0x00, 0x00 | |
| 269 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 270 | 	.byte	0x00, 0x10, 0x00, 0x00 | |
| 271 | 	# FuncId (0x1005) { | |
| 272 | 	# TypeLeafKind: LF_FUNC_ID (0x1601) | |
| 273 | 	# ParentScope: 0x0 | |
| 274 | 	# FunctionType: int () (0x1004) | |
| 275 | 	# Name: main | |
| 276 | 	# } | |
| 277 | 	.byte	0x12, 0x00, 0x01, 0x16 | |
| 278 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 279 | 	.byte	0x04, 0x10, 0x00, 0x00 | |
| 280 | 	.byte	0x6d, 0x61, 0x69, 0x6e | |
| 281 | 	.byte	0x00, 0xf3, 0xf2, 0xf1 | |
| 282 | 	# Modifier (0x1006) { | |
| 283 | 	# TypeLeafKind: LF_MODIFIER (0x1001) | |
| 284 | 	# ModifiedType: int (0x74) | |
| 285 | 	# Modifiers [ (0x2) | |
| 286 | 	# Volatile (0x2) | |
| 287 | 	# ] | |
| 288 | 	# } | |
| 289 | 	.byte	0x0a, 0x00, 0x01, 0x10 | |
| 290 | 	.byte	0x74, 0x00, 0x00, 0x00 | |
| 291 | 	.byte	0x02, 0x00, 0xf2, 0xf1 | |
| 292 | 	# StringId (0x1007) { | |
| 293 | 	# TypeLeafKind: LF_STRING_ID (0x1605) | |
| 294 | 	# Id: 0x0 | |
| 295 | 	# StringData: C:\src\llvm-project\build | |
| 296 | 	# } | |
| 297 | 	.byte	0x22, 0x00, 0x05, 0x16 | |
| 298 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 299 | 	.byte	0x43, 0x3a, 0x5c, 0x73 | |
| 300 | 	.byte	0x72, 0x63, 0x5c, 0x6c | |
| 301 | 	.byte	0x6c, 0x76, 0x6d, 0x2d | |
| 302 | 	.byte	0x70, 0x72, 0x6f, 0x6a | |
| 303 | 	.byte	0x65, 0x63, 0x74, 0x5c | |
| 304 | 	.byte	0x62, 0x75, 0x69, 0x6c | |
| 305 | 	.byte	0x64, 0x00, 0xf2, 0xf1 | |
| 306 | 	# StringId (0x1008) { | |
| 307 | 	# TypeLeafKind: LF_STRING_ID (0x1605) | |
| 308 | 	# Id: 0x0 | |
| 309 | 	# StringData: t.c | |
| 310 | 	# } | |
| 311 | 	.byte	0x0a, 0x00, 0x05, 0x16 | |
| 312 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 313 | 	.byte	0x74, 0x2e, 0x63, 0x00 | |
| 314 | 	# BuildInfo (0x1009) { | |
| 315 | 	# TypeLeafKind: LF_BUILDINFO (0x1603) | |
| 316 | 	# NumArgs: 5 | |
| 317 | 	# Arguments [ | |
| 318 | 	# ArgType: C:\src\llvm-project\build (0x1007) | |
| 319 | 	# ArgType: 0x0 | |
| 320 | 	# ArgType: t.c (0x1008) | |
| 321 | 	# ArgType: 0x0 | |
| 322 | 	# ArgType: 0x0 | |
| 323 | 	# ] | |
| 324 | 	# } | |
| 325 | 	.byte	0x1a, 0x00, 0x03, 0x16 | |
| 326 | 	.byte	0x05, 0x00, 0x07, 0x10 | |
| 327 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 328 | 	.byte	0x00, 0x00, 0x08, 0x10 | |
| 329 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 330 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 331 | 	.byte	0x00, 0x00, 0xf2, 0xf1 | |
| 332 | ||
| 333 | 	.addrsig | |
| 334 | 	.addrsig_sym x |
deps/lld/test/COFF/pdb-inlinees.s created+332| ... | ... | @@ -0,0 +1,332 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj %s -o %t.obj -triple x86_64-windows-msvc | |
| 3 | # RUN: lld-link -entry:main -nodefaultlib %t.obj -out:%t.exe -pdb:%t.pdb -debug | |
| 4 | # RUN: llvm-pdbutil dump -il %t.pdb | FileCheck %s | |
| 5 | ||
| 6 | # Compiled from this C code, with modifications to test multiple file checksums: | |
| 7 | # volatile int x; | |
| 8 | # static __forceinline void inlinee_2(void) { | |
| 9 | # ++x; | |
| 10 | # __debugbreak(); | |
| 11 | # ++x; | |
| 12 | # } | |
| 13 | # static __forceinline void inlinee_1(void) { | |
| 14 | # ++x; | |
| 15 | # inlinee_2(); | |
| 16 | # ++x; | |
| 17 | # } | |
| 18 | # int main() { | |
| 19 | # ++x; | |
| 20 | # inlinee_1(); | |
| 21 | # ++x; | |
| 22 | # return x; | |
| 23 | # } | |
| 24 | ||
| 25 | # CHECK: Inlinee Lines | |
| 26 | # CHECK: Mod 0000 | `{{.*}}pdb-inlinees.s.tmp.obj`: | |
| 27 | # CHECK-NEXT: Inlinee | Line | Source File | |
| 28 | # CHECK-NEXT: 0x1000 | 7 | C:\src\llvm-project\build\t.c (MD5: A79D837C976E9F0463A474D74E2EE9E7) | |
| 29 | # CHECK-NEXT: 0x1001 | 2 | C:\src\llvm-project\build\file2.h (MD5: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) | |
| 30 | ||
| 31 | 	.text | |
| 32 | 	.def	 @feat.00; | |
| 33 | 	.scl	3; | |
| 34 | 	.type	0; | |
| 35 | 	.endef | |
| 36 | 	.globl	@feat.00 | |
| 37 | .set @feat.00, 0 | |
| 38 | 	.intel_syntax noprefix | |
| 39 | 	.file	"t.c" | |
| 40 | 	.def	 main; | |
| 41 | 	.scl	2; | |
| 42 | 	.type	32; | |
| 43 | 	.endef | |
| 44 | 	.section	.text,"xr",one_only,main | |
| 45 | 	.globl	main # -- Begin function main | |
| 46 | main: # @main | |
| 47 | .Lfunc_begin0: | |
| 48 | 	.cv_func_id 0 | |
| 49 | # %bb.0: # %entry | |
| 50 | 	.cv_file	1 "C:\\src\\llvm-project\\build\\t.c" "A79D837C976E9F0463A474D74E2EE9E7" 1 | |
| 51 | 	.cv_file	2 "C:\\src\\llvm-project\\build\\file2.h" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" 1 | |
| 52 | 	.cv_loc	0 1 13 0 # t.c:13:0 | |
| 53 | 	inc	dword ptr [rip + x] | |
| 54 | .Ltmp0: | |
| 55 | 	.cv_inline_site_id 1 within 0 inlined_at 1 14 0 | |
| 56 | 	.cv_loc	1 1 8 0 # t.c:8:0 | |
| 57 | 	inc	dword ptr [rip + x] | |
| 58 | .Ltmp1: | |
| 59 | 	.cv_inline_site_id 2 within 1 inlined_at 1 9 0 | |
| 60 | 	.cv_loc	2 2 3 0 # file2.h:3:0 | |
| 61 | 	inc	dword ptr [rip + x] | |
| 62 | 	.cv_loc	2 2 4 0 # file2.h:4:0 | |
| 63 | 	int3 | |
| 64 | 	.cv_loc	2 2 5 0 # file2.h:5:0 | |
| 65 | 	inc	dword ptr [rip + x] | |
| 66 | .Ltmp2: | |
| 67 | 	.cv_loc	1 1 10 0 # t.c:10:0 | |
| 68 | 	inc	dword ptr [rip + x] | |
| 69 | .Ltmp3: | |
| 70 | 	.cv_loc	0 1 15 0 # t.c:15:0 | |
| 71 | 	inc	dword ptr [rip + x] | |
| 72 | 	.cv_loc	0 1 16 0 # t.c:16:0 | |
| 73 | 	mov	eax, dword ptr [rip + x] | |
| 74 | 	ret | |
| 75 | .Ltmp4: | |
| 76 | .Lfunc_end0: | |
| 77 | # -- End function | |
| 78 | 	.comm	x,4,2 # @x | |
| 79 | 	.section	.debug$S,"dr" | |
| 80 | 	.p2align	2 | |
| 81 | 	.long	4 # Debug section magic | |
| 82 | 	.long	241 | |
| 83 | 	.long	.Ltmp6-.Ltmp5 # Subsection size | |
| 84 | .Ltmp5: | |
| 85 | 	.short	.Ltmp8-.Ltmp7 # Record length | |
| 86 | .Ltmp7: | |
| 87 | 	.short	4412 # Record kind: S_COMPILE3 | |
| 88 | 	.long	0 # Flags and language | |
| 89 | 	.short	208 # CPUType | |
| 90 | 	.short	9 # Frontend version | |
| 91 | 	.short	0 | |
| 92 | 	.short	0 | |
| 93 | 	.short	0 | |
| 94 | 	.short	9000 # Backend version | |
| 95 | 	.short	0 | |
| 96 | 	.short	0 | |
| 97 | 	.short	0 | |
| 98 | 	.asciz	"clang version 9.0.0 (git@github.com:llvm/llvm-project.git aa762a56caf3ef2b0b41c501e66d3ef32903a2d0)" # Null-terminated compiler version string | |
| 99 | 	.p2align	2 | |
| 100 | .Ltmp8: | |
| 101 | .Ltmp6: | |
| 102 | 	.p2align	2 | |
| 103 | 	.long	246 # Inlinee lines subsection | |
| 104 | 	.long	.Ltmp10-.Ltmp9 # Subsection size | |
| 105 | .Ltmp9: | |
| 106 | 	.long	0 # Inlinee lines signature | |
| 107 | ||
| 108 | # Inlined function inlinee_1 starts at t.c:7 | |
| 109 | 	.long	4098 # Type index of inlined function | |
| 110 | 	.cv_filechecksumoffset	1 # Offset into filechecksum table | |
| 111 | 	.long	7 # Starting line number | |
| 112 | ||
| 113 | # Inlined function inlinee_2 starts at file2.h:2 | |
| 114 | 	.long	4099 # Type index of inlined function | |
| 115 | 	.cv_filechecksumoffset	2 # Offset into filechecksum table | |
| 116 | 	.long	2 # Starting line number | |
| 117 | .Ltmp10: | |
| 118 | 	.p2align	2 | |
| 119 | 	.section	.debug$S,"dr",associative,main | |
| 120 | 	.p2align	2 | |
| 121 | 	.long	4 # Debug section magic | |
| 122 | 	.long	241 # Symbol subsection for main | |
| 123 | 	.long	.Ltmp12-.Ltmp11 # Subsection size | |
| 124 | .Ltmp11: | |
| 125 | 	.short	.Ltmp14-.Ltmp13 # Record length | |
| 126 | .Ltmp13: | |
| 127 | 	.short	4423 # Record kind: S_GPROC32_ID | |
| 128 | 	.long	0 # PtrParent | |
| 129 | 	.long	0 # PtrEnd | |
| 130 | 	.long	0 # PtrNext | |
| 131 | 	.long	.Lfunc_end0-main # Code size | |
| 132 | 	.long	0 # Offset after prologue | |
| 133 | 	.long	0 # Offset before epilogue | |
| 134 | 	.long	4101 # Function type index | |
| 135 | 	.secrel32	main # Function section relative address | |
| 136 | 	.secidx	main # Function section index | |
| 137 | 	.byte	0 # Flags | |
| 138 | 	.asciz	"main" # Function name | |
| 139 | 	.p2align	2 | |
| 140 | .Ltmp14: | |
| 141 | 	.short	.Ltmp16-.Ltmp15 # Record length | |
| 142 | .Ltmp15: | |
| 143 | 	.short	4114 # Record kind: S_FRAMEPROC | |
| 144 | 	.long	0 # FrameSize | |
| 145 | 	.long	0 # Padding | |
| 146 | 	.long	0 # Offset of padding | |
| 147 | 	.long	0 # Bytes of callee saved registers | |
| 148 | 	.long	0 # Exception handler offset | |
| 149 | 	.short	0 # Exception handler section | |
| 150 | 	.long	0 # Flags (defines frame register) | |
| 151 | 	.p2align	2 | |
| 152 | .Ltmp16: | |
| 153 | 	.short	.Ltmp18-.Ltmp17 # Record length | |
| 154 | .Ltmp17: | |
| 155 | 	.short	4429 # Record kind: S_INLINESITE | |
| 156 | 	.long	0 # PtrParent | |
| 157 | 	.long	0 # PtrEnd | |
| 158 | 	.long	4098 # Inlinee type index | |
| 159 | 	.cv_inline_linetable	1 1 7 .Lfunc_begin0 .Lfunc_end0 | |
| 160 | 	.p2align	2 | |
| 161 | .Ltmp18: | |
| 162 | 	.short	.Ltmp20-.Ltmp19 # Record length | |
| 163 | .Ltmp19: | |
| 164 | 	.short	4429 # Record kind: S_INLINESITE | |
| 165 | 	.long	0 # PtrParent | |
| 166 | 	.long	0 # PtrEnd | |
| 167 | 	.long	4099 # Inlinee type index | |
| 168 | 	.cv_inline_linetable	2 2 2 .Lfunc_begin0 .Lfunc_end0 | |
| 169 | 	.p2align	2 | |
| 170 | .Ltmp20: | |
| 171 | 	.short	2 # Record length | |
| 172 | 	.short	4430 # Record kind: S_INLINESITE_END | |
| 173 | 	.short	2 # Record length | |
| 174 | 	.short	4430 # Record kind: S_INLINESITE_END | |
| 175 | 	.short	2 # Record length | |
| 176 | 	.short	4431 # Record kind: S_PROC_ID_END | |
| 177 | .Ltmp12: | |
| 178 | 	.p2align	2 | |
| 179 | 	.cv_linetable	0, main, .Lfunc_end0 | |
| 180 | 	.section	.debug$S,"dr" | |
| 181 | 	.long	241 # Symbol subsection for globals | |
| 182 | 	.long	.Ltmp22-.Ltmp21 # Subsection size | |
| 183 | .Ltmp21: | |
| 184 | 	.short	.Ltmp24-.Ltmp23 # Record length | |
| 185 | .Ltmp23: | |
| 186 | 	.short	4365 # Record kind: S_GDATA32 | |
| 187 | 	.long	4102 # Type | |
| 188 | 	.secrel32	x # DataOffset | |
| 189 | 	.secidx	x # Segment | |
| 190 | 	.asciz	"x" # Name | |
| 191 | 	.p2align	2 | |
| 192 | .Ltmp24: | |
| 193 | .Ltmp22: | |
| 194 | 	.p2align	2 | |
| 195 | 	.cv_filechecksums # File index to string table offset subsection | |
| 196 | 	.cv_stringtable # String table | |
| 197 | 	.long	241 | |
| 198 | 	.long	.Ltmp26-.Ltmp25 # Subsection size | |
| 199 | .Ltmp25: | |
| 200 | 	.short	.Ltmp28-.Ltmp27 # Record length | |
| 201 | .Ltmp27: | |
| 202 | 	.short	4428 # Record kind: S_BUILDINFO | |
| 203 | 	.long	4105 # LF_BUILDINFO index | |
| 204 | 	.p2align	2 | |
| 205 | .Ltmp28: | |
| 206 | .Ltmp26: | |
| 207 | 	.p2align	2 | |
| 208 | 	.section	.debug$T,"dr" | |
| 209 | 	.p2align	2 | |
| 210 | 	.long	4 # Debug section magic | |
| 211 | 	# ArgList (0x1000) { | |
| 212 | 	# TypeLeafKind: LF_ARGLIST (0x1201) | |
| 213 | 	# NumArgs: 0 | |
| 214 | 	# Arguments [ | |
| 215 | 	# ] | |
| 216 | 	# } | |
| 217 | 	.byte	0x06, 0x00, 0x01, 0x12 | |
| 218 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 219 | 	# Procedure (0x1001) { | |
| 220 | 	# TypeLeafKind: LF_PROCEDURE (0x1008) | |
| 221 | 	# ReturnType: void (0x3) | |
| 222 | 	# CallingConvention: NearC (0x0) | |
| 223 | 	# FunctionOptions [ (0x0) | |
| 224 | 	# ] | |
| 225 | 	# NumParameters: 0 | |
| 226 | 	# ArgListType: () (0x1000) | |
| 227 | 	# } | |
| 228 | 	.byte	0x0e, 0x00, 0x08, 0x10 | |
| 229 | 	.byte	0x03, 0x00, 0x00, 0x00 | |
| 230 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 231 | 	.byte	0x00, 0x10, 0x00, 0x00 | |
| 232 | 	# FuncId (0x1002) { | |
| 233 | 	# TypeLeafKind: LF_FUNC_ID (0x1601) | |
| 234 | 	# ParentScope: 0x0 | |
| 235 | 	# FunctionType: void () (0x1001) | |
| 236 | 	# Name: inlinee_1 | |
| 237 | 	# } | |
| 238 | 	.byte	0x16, 0x00, 0x01, 0x16 | |
| 239 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 240 | 	.byte	0x01, 0x10, 0x00, 0x00 | |
| 241 | 	.byte	0x69, 0x6e, 0x6c, 0x69 | |
| 242 | 	.byte	0x6e, 0x65, 0x65, 0x5f | |
| 243 | 	.byte	0x31, 0x00, 0xf2, 0xf1 | |
| 244 | 	# FuncId (0x1003) { | |
| 245 | 	# TypeLeafKind: LF_FUNC_ID (0x1601) | |
| 246 | 	# ParentScope: 0x0 | |
| 247 | 	# FunctionType: void () (0x1001) | |
| 248 | 	# Name: inlinee_2 | |
| 249 | 	# } | |
| 250 | 	.byte	0x16, 0x00, 0x01, 0x16 | |
| 251 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 252 | 	.byte	0x01, 0x10, 0x00, 0x00 | |
| 253 | 	.byte	0x69, 0x6e, 0x6c, 0x69 | |
| 254 | 	.byte	0x6e, 0x65, 0x65, 0x5f | |
| 255 | 	.byte	0x32, 0x00, 0xf2, 0xf1 | |
| 256 | 	# Procedure (0x1004) { | |
| 257 | 	# TypeLeafKind: LF_PROCEDURE (0x1008) | |
| 258 | 	# ReturnType: int (0x74) | |
| 259 | 	# CallingConvention: NearC (0x0) | |
| 260 | 	# FunctionOptions [ (0x0) | |
| 261 | 	# ] | |
| 262 | 	# NumParameters: 0 | |
| 263 | 	# ArgListType: () (0x1000) | |
| 264 | 	# } | |
| 265 | 	.byte	0x0e, 0x00, 0x08, 0x10 | |
| 266 | 	.byte	0x74, 0x00, 0x00, 0x00 | |
| 267 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 268 | 	.byte	0x00, 0x10, 0x00, 0x00 | |
| 269 | 	# FuncId (0x1005) { | |
| 270 | 	# TypeLeafKind: LF_FUNC_ID (0x1601) | |
| 271 | 	# ParentScope: 0x0 | |
| 272 | 	# FunctionType: int () (0x1004) | |
| 273 | 	# Name: main | |
| 274 | 	# } | |
| 275 | 	.byte	0x12, 0x00, 0x01, 0x16 | |
| 276 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 277 | 	.byte	0x04, 0x10, 0x00, 0x00 | |
| 278 | 	.byte	0x6d, 0x61, 0x69, 0x6e | |
| 279 | 	.byte	0x00, 0xf3, 0xf2, 0xf1 | |
| 280 | 	# Modifier (0x1006) { | |
| 281 | 	# TypeLeafKind: LF_MODIFIER (0x1001) | |
| 282 | 	# ModifiedType: int (0x74) | |
| 283 | 	# Modifiers [ (0x2) | |
| 284 | 	# Volatile (0x2) | |
| 285 | 	# ] | |
| 286 | 	# } | |
| 287 | 	.byte	0x0a, 0x00, 0x01, 0x10 | |
| 288 | 	.byte	0x74, 0x00, 0x00, 0x00 | |
| 289 | 	.byte	0x02, 0x00, 0xf2, 0xf1 | |
| 290 | 	# StringId (0x1007) { | |
| 291 | 	# TypeLeafKind: LF_STRING_ID (0x1605) | |
| 292 | 	# Id: 0x0 | |
| 293 | 	# StringData: C:\src\llvm-project\build | |
| 294 | 	# } | |
| 295 | 	.byte	0x22, 0x00, 0x05, 0x16 | |
| 296 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 297 | 	.byte	0x43, 0x3a, 0x5c, 0x73 | |
| 298 | 	.byte	0x72, 0x63, 0x5c, 0x6c | |
| 299 | 	.byte	0x6c, 0x76, 0x6d, 0x2d | |
| 300 | 	.byte	0x70, 0x72, 0x6f, 0x6a | |
| 301 | 	.byte	0x65, 0x63, 0x74, 0x5c | |
| 302 | 	.byte	0x62, 0x75, 0x69, 0x6c | |
| 303 | 	.byte	0x64, 0x00, 0xf2, 0xf1 | |
| 304 | 	# StringId (0x1008) { | |
| 305 | 	# TypeLeafKind: LF_STRING_ID (0x1605) | |
| 306 | 	# Id: 0x0 | |
| 307 | 	# StringData: t.c | |
| 308 | 	# } | |
| 309 | 	.byte	0x0a, 0x00, 0x05, 0x16 | |
| 310 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 311 | 	.byte	0x74, 0x2e, 0x63, 0x00 | |
| 312 | 	# BuildInfo (0x1009) { | |
| 313 | 	# TypeLeafKind: LF_BUILDINFO (0x1603) | |
| 314 | 	# NumArgs: 5 | |
| 315 | 	# Arguments [ | |
| 316 | 	# ArgType: C:\src\llvm-project\build (0x1007) | |
| 317 | 	# ArgType: 0x0 | |
| 318 | 	# ArgType: t.c (0x1008) | |
| 319 | 	# ArgType: 0x0 | |
| 320 | 	# ArgType: 0x0 | |
| 321 | 	# ] | |
| 322 | 	# } | |
| 323 | 	.byte	0x1a, 0x00, 0x03, 0x16 | |
| 324 | 	.byte	0x05, 0x00, 0x07, 0x10 | |
| 325 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 326 | 	.byte	0x00, 0x00, 0x08, 0x10 | |
| 327 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 328 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 329 | 	.byte	0x00, 0x00, 0xf2, 0xf1 | |
| 330 | ||
| 331 | 	.addrsig | |
| 332 | 	.addrsig_sym x |
deps/lld/test/COFF/pdb-lib.s+4-4| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=i686-windows-msvc %s -o foo.obj |
| 4 | 4 | # RUN: llc %S/Inputs/bar.ll -filetype=obj -mtriple=i686-windows-msvc -o bar.obj |
| 5 | 5 | # RUN: llvm-lib bar.obj -out:bar.lib |
| 6 | # RUN: lld-link -debug -pdb:foo.pdb foo.obj bar.lib -out:foo.exe -entry:main | |
| 6 | # RUN: lld-link -safeseh:no -debug -pdb:foo.pdb foo.obj bar.lib -out:foo.exe -entry:main | |
| 7 | 7 | # RUN: llvm-pdbutil dump -modules %t/foo.pdb | FileCheck %s |
| 8 | 8 | |
| 9 | 9 | # Make sure that the PDB has module descriptors. foo.obj and bar.lib should be |
| ... | ... | @@ -13,15 +13,15 @@ |
| 13 | 13 | # CHECK-NEXT: ============================================================ |
| 14 | 14 | # CHECK-NEXT: Mod 0000 | `{{.*pdb-lib.s.tmp[/\\]foo.obj}}`: |
| 15 | 15 | # CHECK-NEXT: Obj: `{{.*pdb-lib.s.tmp[/\\]foo.obj}}`: |
| 16 | # CHECK-NEXT: debug stream: 10, # files: 0, has ec info: false | |
| 16 | # CHECK-NEXT: debug stream: 65535, # files: 0, has ec info: false | |
| 17 | 17 | # CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 `` |
| 18 | 18 | # CHECK-NEXT: Mod 0001 | `bar.obj`: |
| 19 | 19 | # CHECK-NEXT: Obj: `{{.*pdb-lib.s.tmp[/\\]bar.lib}}`: |
| 20 | # CHECK-NEXT: debug stream: 11, # files: 0, has ec info: false | |
| 20 | # CHECK-NEXT: debug stream: 65535, # files: 0, has ec info: false | |
| 21 | 21 | # CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 `` |
| 22 | 22 | # CHECK-NEXT: Mod 0002 | `* Linker *`: |
| 23 | 23 | # CHECK-NEXT: Obj: ``: |
| 24 | # CHECK-NEXT: debug stream: 12, # files: 0, has ec info: false | |
| 24 | # CHECK-NEXT: debug stream: 10, # files: 0, has ec info: false | |
| 25 | 25 | # CHECK-NEXT: pdb file ni: 1 `{{.*foo.pdb}}`, src file ni: 0 `` |
| 26 | 26 | |
| 27 | 27 | .def _main; |
deps/lld/test/COFF/pdb-publics-import.test+148-5| ... | ... | @@ -8,7 +8,48 @@ RUN: /export:exportfn1 /export:exportfn2 |
| 8 | 8 | RUN: yaml2obj < %p/Inputs/import.yaml > %t2.obj |
| 9 | 9 | RUN: lld-link /out:%t2.exe /pdb:%t2.pdb /pdbaltpath:test.pdb \ |
| 10 | 10 | RUN: /debug /entry:main %t2.obj %t1.lib |
| 11 | RUN: llvm-pdbutil dump %t2.pdb -publics -section-contribs | FileCheck %s | |
| 11 | RUN: llvm-pdbutil dump %t2.pdb -all | FileCheck %s | |
| 12 | ||
| 13 | CHECK: Streams | |
| 14 | CHECK-NEXT: ============================================================ | |
| 15 | CHECK-LABEL: Stream 10 ( 256 bytes): [Module "Import:pdb-publics-import.test.tmp1.dll"] | |
| 16 | ||
| 17 | CHECK: Module Stats | |
| 18 | CHECK-NEXT: ============================================================ | |
| 19 | CHECK-NEXT: Mod 0000 | `{{.*}}pdb-publics-import.test.tmp2.obj`: | |
| 20 | CHECK-NEXT: Mod 0 (debug info not present): [{{.*}}pdb-publics-import.test.tmp2.obj] | |
| 21 | CHECK-NEXT: Mod 0001 | `pdb-publics-import.test.tmp1.dll`: | |
| 22 | CHECK-NEXT: Mod 1 (debug info not present): [pdb-publics-import.test.tmp1.dll] | |
| 23 | CHECK-NEXT: Mod 0002 | `Import:pdb-publics-import.test.tmp1.dll`: | |
| 24 | CHECK-NEXT: Stream 10, 256 bytes | |
| 25 | ||
| 26 | CHECK: Modules | |
| 27 | CHECK-NEXT: ============================================================ | |
| 28 | CHECK-NEXT: Mod 0000 | `{{.*}}pdb-publics-import.test.tmp2.obj`: | |
| 29 | CHECK-NEXT: SC[.text] | mod = 0, 0001:0000, size = 8, data crc = 0, reloc crc = 0 | |
| 30 | CHECK-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_EXECUTE | | |
| 31 | CHECK-NEXT: IMAGE_SCN_MEM_READ | |
| 32 | CHECK-NEXT: Obj: `{{.*}}pdb-publics-import.test.tmp2.obj`: | |
| 33 | CHECK-NEXT: debug stream: 65535, # files: 0, has ec info: false | |
| 34 | CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 `` | |
| 35 | CHECK-NEXT: Mod 0001 | `pdb-publics-import.test.tmp1.dll`: | |
| 36 | CHECK-NEXT: SC[???] | mod = 65535, 65535:0000, size = -1, data crc = 0, reloc crc = 0 | |
| 37 | CHECK-NEXT: none | |
| 38 | CHECK-NEXT: Obj: `{{.*}}pdb-publics-import.test.tmp1.lib`: | |
| 39 | CHECK-NEXT: debug stream: 65535, # files: 0, has ec info: false | |
| 40 | CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 `` | |
| 41 | CHECK-NEXT: Mod 0002 | `Import:pdb-publics-import.test.tmp1.dll`: | |
| 42 | CHECK-NEXT: SC[.text] | mod = 2, 0001:0032, size = 6, data crc = 0, reloc crc = 0 | |
| 43 | CHECK-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | |
| 44 | CHECK-NEXT: Obj: `{{.*}}pdb-publics-import.test.tmp1.lib`: | |
| 45 | CHECK-NEXT: debug stream: 10, # files: 0, has ec info: false | |
| 46 | CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 `` | |
| 47 | CHECK-NEXT: Mod 0003 | `* Linker *`: | |
| 48 | CHECK-NEXT: SC[???] | mod = 65535, 65535:0000, size = -1, data crc = 0, reloc crc = 0 | |
| 49 | CHECK-NEXT: none | |
| 50 | CHECK-NEXT: Obj: ``: | |
| 51 | CHECK-NEXT: debug stream: 11, # files: 0, has ec info: false | |
| 52 | CHECK-NEXT: pdb file ni: 1 `{{.*}}pdb-publics-import.test.tmp2.pdb`, src file ni: 0 `` | |
| 12 | 53 | |
| 13 | 54 | CHECK: Public Symbols |
| 14 | 55 | CHECK-NEXT: ============================================================ |
| ... | ... | @@ -24,6 +65,86 @@ CHECK-NEXT: flags = none, addr = 0002:0136 |
| 24 | 65 | CHECK-NEXT: 0 | S_PUB32 [size = 32] `__imp_exportfn1` |
| 25 | 66 | CHECK-NEXT: flags = none, addr = 0002:0128 |
| 26 | 67 | |
| 68 | CHECK: Symbols | |
| 69 | CHECK-NEXT: ============================================================ | |
| 70 | CHECK-NEXT: Mod 0000 | `{{.*}}pdb-publics-import.test.tmp2.obj`: | |
| 71 | CHECK-NEXT: Error loading module stream 0. The specified stream could not be loaded. Module stream not present | |
| 72 | CHECK-NEXT: Mod 0001 | `pdb-publics-import.test.tmp1.dll`: | |
| 73 | CHECK-NEXT: Error loading module stream 1. The specified stream could not be loaded. Module stream not present | |
| 74 | CHECK-NEXT: Mod 0002 | `Import:pdb-publics-import.test.tmp1.dll`: | |
| 75 | CHECK-NEXT: 4 | S_OBJNAME [size = 44] sig=0, `pdb-publics-import.test.tmp1.dll` | |
| 76 | CHECK-NEXT: 48 | S_COMPILE3 [size = 40] | |
| 77 | CHECK-NEXT: machine = intel x86-x64, Ver = LLVM Linker, language = link | |
| 78 | CHECK-NEXT: frontend = 0.0.0.0, backend = 14.10.25019.0 | |
| 79 | CHECK-NEXT: flags = none | |
| 80 | CHECK-NEXT: 88 | S_THUNK32 [size = 36] `exportfn1` | |
| 81 | CHECK-NEXT: parent = 0, end = 124, next = 0 | |
| 82 | CHECK-NEXT: kind = thunk, size = 6, addr = 0001:0016 | |
| 83 | CHECK-NEXT: 124 | S_END [size = 4] | |
| 84 | CHECK-NEXT: 128 | S_OBJNAME [size = 44] sig=0, `pdb-publics-import.test.tmp1.dll` | |
| 85 | CHECK-NEXT: 172 | S_COMPILE3 [size = 40] | |
| 86 | CHECK-NEXT: machine = intel x86-x64, Ver = LLVM Linker, language = link | |
| 87 | CHECK-NEXT: frontend = 0.0.0.0, backend = 14.10.25019.0 | |
| 88 | CHECK-NEXT: flags = none | |
| 89 | CHECK-NEXT: 212 | S_THUNK32 [size = 36] `exportfn2` | |
| 90 | CHECK-NEXT: parent = 0, end = 248, next = 0 | |
| 91 | CHECK-NEXT: kind = thunk, size = 6, addr = 0001:0032 | |
| 92 | CHECK-NEXT: 248 | S_END [size = 4] | |
| 93 | CHECK-NEXT: Mod 0003 | `* Linker *`: | |
| 94 | CHECK-NEXT: 4 | S_OBJNAME [size = 20] sig=0, `* Linker *` | |
| 95 | CHECK-NEXT: 24 | S_COMPILE3 [size = 40] | |
| 96 | CHECK-NEXT: machine = intel x86-x64, Ver = LLVM Linker, language = link | |
| 97 | CHECK-NEXT: frontend = 0.0.0.0, backend = 14.10.25019.0 | |
| 98 | CHECK-NEXT: flags = none | |
| 99 | CHECK-NEXT: 64 | S_ENVBLOCK [size = {{[0-9]+}}] | |
| 100 | CHECK: {{[0-9]+}} | S_SECTION [size = 28] `.text` | |
| 101 | CHECK-NEXT: length = 38, alignment = 12, rva = 4096, section # = 1 | |
| 102 | CHECK-NEXT: characteristics = | |
| 103 | CHECK-NEXT: code | |
| 104 | CHECK-NEXT: execute permissions | |
| 105 | CHECK-NEXT: read permissions | |
| 106 | CHECK-NEXT: {{[0-9]+}} | S_COFFGROUP [size = 24] `.text` | |
| 107 | CHECK-NEXT: length = 8, addr = 0001:0000 | |
| 108 | CHECK-NEXT: characteristics = | |
| 109 | CHECK-NEXT: code | |
| 110 | CHECK-NEXT: execute permissions | |
| 111 | CHECK-NEXT: read permissions | |
| 112 | CHECK-NEXT: {{[0-9]+}} | S_SECTION [size = 28] `.rdata` | |
| 113 | CHECK-NEXT: length = 209, alignment = 12, rva = 8192, section # = 2 | |
| 114 | CHECK-NEXT: characteristics = | |
| 115 | CHECK-NEXT: initialized data | |
| 116 | CHECK-NEXT: read permissions | |
| 117 | CHECK-NEXT: {{[0-9]+}} | S_COFFGROUP [size = 28] `.idata$2` | |
| 118 | CHECK-NEXT: length = 40, addr = 0002:0061 | |
| 119 | CHECK-NEXT: characteristics = | |
| 120 | CHECK-NEXT: initialized data | |
| 121 | CHECK-NEXT: read permissions | |
| 122 | CHECK-NEXT: write permissions | |
| 123 | CHECK-NEXT: {{[0-9]+}} | S_COFFGROUP [size = 28] `.idata$4` | |
| 124 | CHECK-NEXT: length = 24, addr = 0002:0104 | |
| 125 | CHECK-NEXT: characteristics = | |
| 126 | CHECK-NEXT: initialized data | |
| 127 | CHECK-NEXT: read permissions | |
| 128 | CHECK-NEXT: write permissions | |
| 129 | CHECK-NEXT: {{[0-9]+}} | S_COFFGROUP [size = 28] `.idata$5` | |
| 130 | CHECK-NEXT: length = 24, addr = 0002:0128 | |
| 131 | CHECK-NEXT: characteristics = | |
| 132 | CHECK-NEXT: initialized data | |
| 133 | CHECK-NEXT: read permissions | |
| 134 | CHECK-NEXT: write permissions | |
| 135 | CHECK-NEXT: {{[0-9]+}} | S_COFFGROUP [size = 28] `.idata$6` | |
| 136 | CHECK-NEXT: length = 24, addr = 0002:0152 | |
| 137 | CHECK-NEXT: characteristics = | |
| 138 | CHECK-NEXT: initialized data | |
| 139 | CHECK-NEXT: read permissions | |
| 140 | CHECK-NEXT: write permissions | |
| 141 | CHECK-NEXT: {{[0-9]+}} | S_COFFGROUP [size = 28] `.idata$7` | |
| 142 | CHECK-NEXT: length = 33, addr = 0002:0176 | |
| 143 | CHECK-NEXT: characteristics = | |
| 144 | CHECK-NEXT: initialized data | |
| 145 | CHECK-NEXT: read permissions | |
| 146 | CHECK-NEXT: write permissions | |
| 147 | ||
| 27 | 148 | CHECK: Section Contributions |
| 28 | 149 | CHECK-NEXT: ============================================================ |
| 29 | 150 | main |
| ... | ... | @@ -31,13 +152,35 @@ CHECK-NEXT: SC[.text] | mod = 0, 0001:0000, size = 8, data crc = 0, reloc cr |
| 31 | 152 | CHECK-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_EXECUTE | |
| 32 | 153 | CHECK-NEXT: IMAGE_SCN_MEM_READ |
| 33 | 154 | exportfn1 thunk |
| 34 | CHECK-NEXT: SC[.text] | mod = 1, 0001:0016, size = 6, data crc = 0, reloc crc = 0 | |
| 155 | CHECK-NEXT: SC[.text] | mod = 3, 0001:0016, size = 6, data crc = 0, reloc crc = 0 | |
| 35 | 156 | CHECK-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ |
| 36 | 157 | exportfn2 thunk |
| 37 | CHECK-NEXT: SC[.text] | mod = 1, 0001:0032, size = 6, data crc = 0, reloc crc = 0 | |
| 158 | CHECK-NEXT: SC[.text] | mod = 3, 0001:0032, size = 6, data crc = 0, reloc crc = 0 | |
| 38 | 159 | CHECK-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ |
| 39 | 160 | .rdata debug directory data chunks |
| 40 | CHECK-NEXT: SC[.rdata] | mod = 1, 0002:0000, size = 28, data crc = 0, reloc crc = 0 | |
| 161 | CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0000, size = 28, data crc = 0, reloc crc = 0 | |
| 162 | CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | |
| 163 | CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0028, size = 33, data crc = 0, reloc crc = 0 | |
| 164 | CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | |
| 165 | CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0061, size = 20, data crc = 0, reloc crc = 0 | |
| 166 | CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | |
| 167 | CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0081, size = 20, data crc = 0, reloc crc = 0 | |
| 168 | CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | |
| 169 | CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0104, size = 8, data crc = 0, reloc crc = 0 | |
| 170 | CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | |
| 171 | CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0112, size = 8, data crc = 0, reloc crc = 0 | |
| 172 | CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | |
| 173 | CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0120, size = 8, data crc = 0, reloc crc = 0 | |
| 174 | CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | |
| 175 | CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0128, size = 8, data crc = 0, reloc crc = 0 | |
| 176 | CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | |
| 177 | CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0136, size = 8, data crc = 0, reloc crc = 0 | |
| 178 | CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | |
| 179 | CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0144, size = 8, data crc = 0, reloc crc = 0 | |
| 180 | CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | |
| 181 | CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0152, size = 12, data crc = 0, reloc crc = 0 | |
| 182 | CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | |
| 183 | CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0164, size = 12, data crc = 0, reloc crc = 0 | |
| 41 | 184 | CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
| 42 | CHECK-NEXT: SC[.rdata] | mod = 1, 0002:0028, size = 33, data crc = 0, reloc crc = 0 | |
| 185 | CHECK-NEXT: SC[.rdata] | mod = 3, 0002:0176, size = 33, data crc = 0, reloc crc = 0 | |
| 43 | 186 | CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
deps/lld/test/COFF/pdb-safeseh.yaml+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | # RUN: yaml2obj %s -o %t.obj |
| 2 | # RUN: lld-link -debug -entry:main -out:%t.exe -pdb:%t.pdb %t.obj | |
| 2 | # RUN: lld-link -safeseh:no -debug -entry:main -out:%t.exe -pdb:%t.pdb %t.obj | |
| 3 | 3 | # RUN: llvm-pdbutil dump -globals %t.pdb | FileCheck %s |
| 4 | 4 | |
| 5 | 5 | # There is an S_GDATA32 symbol record with .secrel32 and .secidx relocations in |
deps/lld/test/COFF/pdb-tpi-hash-size.test created+10| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | # RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj | |
| 2 | # RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj | |
| 3 | # RUN: rm -f %t.dll %t.pdb | |
| 4 | # RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll \ | |
| 5 | # RUN: /entry:main /nodefaultlib %t1.obj %t2.obj | |
| 6 | ||
| 7 | # RUN: llvm-pdbutil dump -types -type-extras %t.pdb | FileCheck %s | |
| 8 | ||
| 9 | CHECK: Hash Key Size: 4 | |
| 10 | CHECK-NEXT: Num Hash Buckets: 262143 |
deps/lld/test/COFF/pdb-type-server-invalid-signature.yaml+12-4| ... | ... | @@ -1,22 +1,30 @@ |
| 1 | 1 | |
| 2 | # Test linking an OBJ with a reference to an out-of-date PDB type server | |
| 2 | 3 | # RUN: cd %S/Inputs |
| 3 | 4 | # RUN: yaml2obj %s -o %t.obj |
| 4 | 5 | # RUN: lld-link %t.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s |
| 5 | 6 | # RUN: cd %S |
| 6 | 7 | |
| 7 | # CHECK: warning: Cannot use debug info for {{.*}}.obj | |
| 8 | # CHECK: warning: Cannot use debug info for '{{.*}}.obj' | |
| 8 | 9 | # CHECK-NEXT: The signature does not match; the file(s) might be out of date |
| 9 | 10 | |
| 10 | # Also test a valid match | |
| 11 | ||
| 11 | # Also test linking an OBJ with a reference to *valid* PDB type server | |
| 12 | 12 | # RUN: cd %S/Inputs |
| 13 | 13 | # RUN: yaml2obj %S/Inputs/pdb-type-server-valid-signature.yaml -o %t2.obj |
| 14 | 14 | # RUN: lld-link %t2.obj -out:%t2.exe -debug -pdb:%t2.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s -check-prefix=VALID-SIGNATURE -allow-empty |
| 15 | 15 | # RUN: cd %S |
| 16 | 16 | |
| 17 | # VALID-SIGNATURE-NOT: warning: Cannot use debug info for {{.*}}.obj | |
| 17 | # VALID-SIGNATURE-NOT: warning: Cannot use debug info for '{{.*}}.obj' | |
| 18 | 18 | # VALID-SIGNATURE-NOT: The signature does not match; the file(s) might be out of date |
| 19 | 19 | |
| 20 | # Test an invalid path reference to a PDB type server; as a fallback LLD should try to load the PDB in the same path as the OBJ | |
| 21 | # RUN: yaml2obj %S/Inputs/pdb-type-server-invalid-path.yaml -o %t3.obj | |
| 22 | # RUN: cp %S/Inputs/pdb-diff-cl.pdb %T | |
| 23 | # RUN: lld-link %t3.obj -out:%t3.exe -debug -pdb:%t3.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s -check-prefix=INVALID-PATH -allow-empty | |
| 24 | ||
| 25 | # INVALID-PATH-NOT: warning: Cannot use debug info for '{{.*}}3.obj' [LNK4099] | |
| 26 | # INVALID-PATH-NOT: failed to load reference 'c:\some_invalid_path_AABB98765\pdb-diff-cl.pdb': {{[Nn]}}o such file or directory | |
| 27 | ||
| 20 | 28 | --- !COFF |
| 21 | 29 | header: |
| 22 | 30 | Machine: IMAGE_FILE_MACHINE_AMD64 |
deps/lld/test/COFF/pdb-type-server-simple.test+12-1| ... | ... | @@ -20,7 +20,7 @@ RUN: rm -rf %t && mkdir -p %t && cd %t |
| 20 | 20 | RUN: yaml2obj %S/Inputs/pdb-type-server-simple-a.yaml -o a.obj |
| 21 | 21 | RUN: yaml2obj %S/Inputs/pdb-type-server-simple-b.yaml -o b.obj |
| 22 | 22 | RUN: llvm-pdbutil yaml2pdb %S/Inputs/pdb-type-server-simple-ts.yaml -pdb ts.pdb |
| 23 | RUN: lld-link a.obj b.obj -entry:main -debug -out:t.exe -pdb:t.pdb -nodefaultlib | |
| 23 | RUN: lld-link a.obj b.obj -entry:main -debug -out:t.exe -pdb:t.pdb -nodefaultlib /summary | FileCheck %s -check-prefix SUMMARY | |
| 24 | 24 | RUN: llvm-pdbutil dump -symbols -types -ids -globals %t/t.pdb | FileCheck %s |
| 25 | 25 | |
| 26 | 26 | |
| ... | ... | @@ -95,3 +95,14 @@ CHECK: type = [[FOO_PTR]] (Foo*), register = RSP, offset = 8 |
| 95 | 95 | CHECK: 196 | S_END [size = 4] |
| 96 | 96 | CHECK: 200 | S_BUILDINFO [size = 8] BuildId = `[[B_BUILD]]` |
| 97 | 97 | CHECK-LABEL: Mod 0002 | `* Linker *`: |
| 98 | ||
| 99 | SUMMARY: Summary | |
| 100 | SUMMARY-NEXT: -------------------------------------------------------------------------------- | |
| 101 | SUMMARY-NEXT: 2 Input OBJ files (expanded from all cmd-line inputs) | |
| 102 | SUMMARY-NEXT: 1 PDB type server dependencies | |
| 103 | SUMMARY-NEXT: 0 Precomp OBJ dependencies | |
| 104 | SUMMARY-NEXT: 25 Merged TPI records | |
| 105 | SUMMARY-NEXT: 3 Output PDB strings | |
| 106 | SUMMARY-NEXT: 4 Global symbol records | |
| 107 | SUMMARY-NEXT: 14 Module symbol records | |
| 108 | SUMMARY-NEXT: 2 Public symbol records | |
| \ No newline at end of file |
deps/lld/test/COFF/pdb-unknown-subsection.s created+60| ... | ... | @@ -0,0 +1,60 @@ |
| 1 | # Check that unknown symbol subsections are ignored with a warning, and a PDB | |
| 2 | # is produced anyway. | |
| 3 | ||
| 4 | # REQUIRES: x86 | |
| 5 | # RUN: llvm-mc -triple=i386-pc-win32 -filetype=obj -o %t.obj %s | |
| 6 | # RUN: lld-link -safeseh:no -subsystem:console -debug -nodefaultlib -entry:foo -out:%t.exe -pdb:%t.pdb %t.obj 2>&1 | FileCheck %s --check-prefix=WARNING | |
| 7 | # RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s | |
| 8 | ||
| 9 | # WARNING-NOT: ignoring unknown | |
| 10 | # WARNING: ignoring unknown debug$S subsection kind 0xFF | |
| 11 | # WARNING-NOT: ignoring unknown | |
| 12 | ||
| 13 | # CHECK: Symbols | |
| 14 | # CHECK: 4 | S_COMPILE3 [size = 52] | |
| 15 | # CHECK: machine = intel x86-x64, Ver = clang version SENTINEL, language = c | |
| 16 | ||
| 17 | .text | |
| 18 | _foo: | |
| 19 | ret | |
| 20 | ||
| 21 | .global _foo | |
| 22 | ||
| 23 | .section .debug$S,"dr" | |
| 24 | 	.p2align	2 | |
| 25 | 	.long	4 # Debug section magic | |
| 26 | 	.long	0xF1 # Symbol subsection | |
| 27 | 	.long	.Ltmp6-.Ltmp5 # Subsection size | |
| 28 | .Ltmp5: | |
| 29 | 	.short	.Ltmp8-.Ltmp7 # Record length | |
| 30 | .Ltmp7: | |
| 31 | 	.short	4412 # Record kind: S_COMPILE3 | |
| 32 | 	.long	0 # Flags and language | |
| 33 | 	.short	208 # CPUType | |
| 34 | 	.short	9 # Frontend version | |
| 35 | 	.short	0 | |
| 36 | 	.short	0 | |
| 37 | 	.short	0 | |
| 38 | 	.short	9000 # Backend version | |
| 39 | 	.short	0 | |
| 40 | 	.short	0 | |
| 41 | 	.short	0 | |
| 42 | 	.asciz	"clang version SENTINEL" # Null-terminated compiler version string | |
| 43 | 	.p2align	2 | |
| 44 | .Ltmp8: | |
| 45 | .Ltmp6: | |
| 46 | 	.long	0xFF # Unknown subsection kind | |
| 47 | 	.long	4 # Subsection size | |
| 48 | 	.long 0 | |
| 49 | 	.long	0x800000F1 # Unknown subsection kind | |
| 50 | 	.long	4 # Subsection size | |
| 51 | 	.long 0 | |
| 52 | 	.long	0x800000F2 # Unknown subsection kind | |
| 53 | 	.long	4 # Subsection size | |
| 54 | 	.long 0 | |
| 55 | 	.long	0x800000F3 # Unknown subsection kind | |
| 56 | 	.long	4 # Subsection size | |
| 57 | 	.long 0 | |
| 58 | 	.long	0x800000F4 # Unknown subsection kind | |
| 59 | 	.long	4 # Subsection size | |
| 60 | 	.long 0 |
deps/lld/test/COFF/pdb.test+18-18| ... | ... | @@ -134,7 +134,7 @@ RAW-NEXT: Obj: `{{.*}}pdb.test.tmp2.obj`: |
| 134 | 134 | RAW-NEXT: debug stream: 12, # files: 1, has ec info: false |
| 135 | 135 | RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 `` |
| 136 | 136 | RAW-NEXT: Mod 0002 | `* Linker *`: |
| 137 | RAW-NEXT: SC[???] | mod = 2, 0000:0000, size = 0, data crc = 0, reloc crc = 0 | |
| 137 | RAW-NEXT: SC[???] | mod = 65535, 65535:0000, size = -1, data crc = 0, reloc crc = 0 | |
| 138 | 138 | RAW-NEXT: none |
| 139 | 139 | RAW-NEXT: Obj: ``: |
| 140 | 140 | RAW-NEXT: debug stream: 13, # files: 0, has ec info: false |
| ... | ... | @@ -142,40 +142,40 @@ RAW-NEXT: pdb file ni: 1 `{{.*pdb.test.tmp.pdb}}`, src file ni: 0 ` |
| 142 | 142 | RAW: Types (TPI Stream) |
| 143 | 143 | RAW-NEXT: ============================================================ |
| 144 | 144 | RAW-NEXT: Showing 5 records |
| 145 | RAW-NEXT: 0x1000 | LF_ARGLIST [size = 8, hash = 0xEC0] | |
| 146 | RAW-NEXT: 0x1001 | LF_PROCEDURE [size = 16, hash = 0x7BC] | |
| 145 | RAW-NEXT: 0x1000 | LF_ARGLIST [size = 8, hash = 0x32484] | |
| 146 | RAW-NEXT: 0x1001 | LF_PROCEDURE [size = 16, hash = 0x27EE9] | |
| 147 | 147 | RAW-NEXT: return type = 0x0074 (int), # args = 0, param list = 0x1000 |
| 148 | 148 | RAW-NEXT: calling conv = cdecl, options = None |
| 149 | RAW-NEXT: 0x1002 | LF_POINTER [size = 12, hash = 0x884] | |
| 149 | RAW-NEXT: 0x1002 | LF_POINTER [size = 12, hash = 0x39732] | |
| 150 | 150 | RAW-NEXT: referent = 0x1001, mode = pointer, opts = None, kind = ptr64 |
| 151 | RAW-NEXT: 0x1003 | LF_ARGLIST [size = 12, hash = 0x936] | |
| 151 | RAW-NEXT: 0x1003 | LF_ARGLIST [size = 12, hash = 0x1FC10] | |
| 152 | 152 | RAW-NEXT: <no type>: `` |
| 153 | RAW-NEXT: 0x1004 | LF_PROCEDURE [size = 16, hash = 0x852] | |
| 153 | RAW-NEXT: 0x1004 | LF_PROCEDURE [size = 16, hash = 0x1BD3] | |
| 154 | 154 | RAW-NEXT: return type = 0x0074 (int), # args = 0, param list = 0x1003 |
| 155 | 155 | RAW-NEXT: calling conv = cdecl, options = None |
| 156 | 156 | RAW: Types (IPI Stream) |
| 157 | 157 | RAW-NEXT: ============================================================ |
| 158 | 158 | RAW-NEXT: Showing 12 records |
| 159 | RAW-NEXT: 0x1000 | LF_FUNC_ID [size = 20, hash = 0x330] | |
| 159 | RAW-NEXT: 0x1000 | LF_FUNC_ID [size = 20, hash = 0x38E5A] | |
| 160 | 160 | RAW-NEXT: name = main, type = 0x1004, parent scope = <no type> |
| 161 | RAW-NEXT: 0x1001 | LF_FUNC_ID [size = 16, hash = 0x120] | |
| 161 | RAW-NEXT: 0x1001 | LF_FUNC_ID [size = 16, hash = 0xD08E] | |
| 162 | 162 | RAW-NEXT: name = foo, type = 0x1001, parent scope = <no type> |
| 163 | RAW-NEXT: 0x1002 | LF_STRING_ID [size = 16, hash = 0x757] ID: <no type>, String: D:\b | |
| 164 | RAW-NEXT: 0x1003 | LF_STRING_ID [size = 36, hash = 0xC3A] ID: <no type>, String: C:\vs14\VC\BIN\amd64\cl.exe | |
| 165 | RAW-NEXT: 0x1004 | LF_STRING_ID [size = 260, hash = 0x433] ID: <no type>, String: -Z7 -c -MT -IC:\vs14\VC\INCLUDE -IC:\vs14\VC\ATLMFC\INCLUDE -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.10150.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared" | |
| 166 | RAW-NEXT: 0x1005 | LF_SUBSTR_LIST [size = 12, hash = 0x759] | |
| 163 | RAW-NEXT: 0x1002 | LF_STRING_ID [size = 16, hash = 0x3EBD9] ID: <no type>, String: D:\b | |
| 164 | RAW-NEXT: 0x1003 | LF_STRING_ID [size = 36, hash = 0xD327] ID: <no type>, String: C:\vs14\VC\BIN\amd64\cl.exe | |
| 165 | RAW-NEXT: 0x1004 | LF_STRING_ID [size = 260, hash = 0x2FA6A] ID: <no type>, String: -Z7 -c -MT -IC:\vs14\VC\INCLUDE -IC:\vs14\VC\ATLMFC\INCLUDE -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.10150.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared" | |
| 166 | RAW-NEXT: 0x1005 | LF_SUBSTR_LIST [size = 12, hash = 0x6053] | |
| 167 | 167 | RAW-NEXT: 0x1004: `-Z7 -c -MT -IC:\vs14\VC\INCLUDE -IC:\vs14\VC\ATLMFC\INCLUDE -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.10150.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared"` |
| 168 | RAW-NEXT: 0x1006 | LF_STRING_ID [size = 132, hash = 0xF57] ID: 0x1005, String: -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X | |
| 169 | RAW-NEXT: 0x1007 | LF_STRING_ID [size = 24, hash = 0x2D1] ID: <no type>, String: ret42-main.c | |
| 170 | RAW-NEXT: 0x1008 | LF_STRING_ID [size = 24, hash = 0xB8B] ID: <no type>, String: D:\b\vc140.pdb | |
| 171 | RAW-NEXT: 0x1009 | LF_BUILDINFO [size = 28, hash = 0xA8C] | |
| 168 | RAW-NEXT: 0x1006 | LF_STRING_ID [size = 132, hash = 0xCAC7] ID: 0x1005, String: -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X | |
| 169 | RAW-NEXT: 0x1007 | LF_STRING_ID [size = 24, hash = 0x21783] ID: <no type>, String: ret42-main.c | |
| 170 | RAW-NEXT: 0x1008 | LF_STRING_ID [size = 24, hash = 0x1DB87] ID: <no type>, String: D:\b\vc140.pdb | |
| 171 | RAW-NEXT: 0x1009 | LF_BUILDINFO [size = 28, hash = 0x5E91] | |
| 172 | 172 | RAW-NEXT: 0x1002: `D:\b` |
| 173 | 173 | RAW-NEXT: 0x1003: `C:\vs14\VC\BIN\amd64\cl.exe` |
| 174 | 174 | RAW-NEXT: 0x1007: `ret42-main.c` |
| 175 | 175 | RAW-NEXT: 0x1008: `D:\b\vc140.pdb` |
| 176 | 176 | RAW-NEXT: 0x1006: ` -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X` |
| 177 | RAW-NEXT: 0x100A | LF_STRING_ID [size = 20, hash = 0x39C] ID: <no type>, String: ret42-sub.c | |
| 178 | RAW-NEXT: 0x100B | LF_BUILDINFO [size = 28, hash = 0xAD7] | |
| 177 | RAW-NEXT: 0x100A | LF_STRING_ID [size = 20, hash = 0x7C68] ID: <no type>, String: ret42-sub.c | |
| 178 | RAW-NEXT: 0x100B | LF_BUILDINFO [size = 28, hash = 0x254D2] | |
| 179 | 179 | RAW-NEXT: 0x1002: `D:\b` |
| 180 | 180 | RAW-NEXT: 0x1003: `C:\vs14\VC\BIN\amd64\cl.exe` |
| 181 | 181 | RAW-NEXT: 0x100A: `ret42-sub.c` |
deps/lld/test/COFF/pdbaltpath.test+9-9| ... | ... | @@ -1,39 +1,39 @@ |
| 1 | 1 | # RUN: yaml2obj %p/Inputs/empty.yaml > %t.obj |
| 2 | 2 | |
| 3 | 3 | # RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:hello.pdb |
| 4 | # RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix HELLO %s | |
| 4 | # RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck --check-prefix HELLO %s | |
| 5 | 5 | # HELLO: PDBFileName: hello.pdb |
| 6 | 6 | |
| 7 | 7 | # RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:%_Pdb% |
| 8 | # RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix PDBVAR %s | |
| 8 | # RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck --check-prefix PDBVAR %s | |
| 9 | 9 | # PDBVAR: PDBFileName: pdbaltpath.test.tmp.pdb |
| 10 | 10 | |
| 11 | 11 | # RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:foo%_ExT%.pdb |
| 12 | # RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix EXTVAR %s | |
| 12 | # RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck --check-prefix EXTVAR %s | |
| 13 | 13 | # EXTVAR: PDBFileName: fooexe.pdb |
| 14 | 14 | |
| 15 | 15 | # RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:%_PDB |
| 16 | # RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix NOCLOSE %s | |
| 16 | # RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck --check-prefix NOCLOSE %s | |
| 17 | 17 | # NOCLOSE: PDBFileName: %_PDB |
| 18 | 18 | |
| 19 | 19 | # RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:foo%_PDB |
| 20 | # RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix NOCLOSE2 %s | |
| 20 | # RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck --check-prefix NOCLOSE2 %s | |
| 21 | 21 | # NOCLOSE2: PDBFileName: foo%_PDB |
| 22 | 22 | |
| 23 | 23 | # RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:foo%_PDB%bar%_EXT |
| 24 | # RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix CLOSEONE %s | |
| 24 | # RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck --check-prefix CLOSEONE %s | |
| 25 | 25 | # CLOSEONE: PDBFileName: foopdbaltpath.test.tmp.pdbbar%_EXT |
| 26 | 26 | |
| 27 | 27 | # RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:foo%_PDB%bar%_EXT% |
| 28 | # RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix CLOSETWO %s | |
| 28 | # RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck --check-prefix CLOSETWO %s | |
| 29 | 29 | # CLOSETWO: PDBFileName: foopdbaltpath.test.tmp.pdbbarexe |
| 30 | 30 | |
| 31 | 31 | # RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:foo%_PDB%bar%_EXT%a |
| 32 | # RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix CLOSETWO2 %s | |
| 32 | # RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck --check-prefix CLOSETWO2 %s | |
| 33 | 33 | # CLOSETWO2: PDBFileName: foopdbaltpath.test.tmp.pdbbarexea |
| 34 | 34 | |
| 35 | 35 | # RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:foo%FoO%bar%r%a 2>&1 | FileCheck --check-prefix UNKNOWN-WARN %s |
| 36 | # RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix ENVVARS %s | |
| 36 | # RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck --check-prefix ENVVARS %s | |
| 37 | 37 | # UNKNOWN-WARN: only %_PDB% and %_EXT% supported in /pdbaltpath:, keeping %FoO% as literal |
| 38 | 38 | # UNKNOWN-WARN: only %_PDB% and %_EXT% supported in /pdbaltpath:, keeping %r% as literal |
| 39 | 39 | # ENVVARS: PDBFileName: foo%FoO%bar%r%a |
deps/lld/test/COFF/precomp-link.test+54-42| ... | ... | @@ -1,42 +1,54 @@ |
| 1 | RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf | |
| 2 | RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s | |
| 3 | ||
| 4 | RUN: lld-link %S/Inputs/precomp.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf | |
| 5 | RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s | |
| 6 | ||
| 7 | RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-invalid.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf 2>&1 | FileCheck %s -check-prefix FAILURE | |
| 8 | ||
| 9 | RUN: not lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf 2>&1 | FileCheck %s -check-prefix FAILURE-MISSING-PRECOMPOBJ | |
| 10 | ||
| 11 | FAILURE: warning: Cannot use debug info for 'precomp-invalid.obj' [LNK4099] | |
| 12 | FAILURE-NEXT: failed to load reference '{{.*}}precomp.obj': The signature does not match; the file(s) might be out of date. | |
| 13 | ||
| 14 | FAILURE-MISSING-PRECOMPOBJ: warning: Cannot use debug info for 'precomp-a.obj' [LNK4099] | |
| 15 | FAILURE-MISSING-PRECOMPOBJ-NEXT: failed to load reference '{{.*}}precomp.obj': The path to this file must be provided on the command-line | |
| 16 | ||
| 17 | CHECK: Types (TPI Stream) | |
| 18 | CHECK-NOT: LF_PRECOMP | |
| 19 | CHECK-NOT: LF_ENDPRECOMP | |
| 20 | ||
| 21 | // precomp.h | |
| 22 | #pragma once | |
| 23 | int Function(char A); | |
| 24 | ||
| 25 | // precomp.cpp | |
| 26 | #include "precomp.h" | |
| 27 | ||
| 28 | // a.cpp | |
| 29 | #include "precomp.h" | |
| 30 | int main(void) { | |
| 31 | Function('a'); | |
| 32 | return 0; | |
| 33 | } | |
| 34 | ||
| 35 | // b.cpp | |
| 36 | #include "precomp.h" | |
| 37 | int Function(char a) { | |
| 38 | return (int)a; | |
| 39 | } | |
| 40 | ||
| 41 | // cl.exe precomp.cpp /Z7 /Ycprecomp.h /c | |
| 42 | // cl.exe a.cpp b.cpp /Z7 /Yuprecomp.h /c | |
| 1 | RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf /summary | FileCheck %s -check-prefix SUMMARY | |
| 2 | RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s | |
| 3 | ||
| 4 | RUN: lld-link %S/Inputs/precomp.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf | |
| 5 | RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s | |
| 6 | ||
| 7 | RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-invalid.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf 2>&1 | FileCheck %s -check-prefix FAILURE | |
| 8 | ||
| 9 | RUN: not lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf 2>&1 | FileCheck %s -check-prefix FAILURE-MISSING-PRECOMPOBJ | |
| 10 | ||
| 11 | FAILURE: warning: Cannot use debug info for '{{.*}}precomp-invalid.obj' [LNK4099] | |
| 12 | FAILURE-NEXT: failed to load reference '{{.*}}precomp.obj': The signature does not match; the file(s) might be out of date. | |
| 13 | ||
| 14 | FAILURE-MISSING-PRECOMPOBJ: warning: Cannot use debug info for '{{.*}}precomp-a.obj' [LNK4099] | |
| 15 | FAILURE-MISSING-PRECOMPOBJ-NEXT: failed to load reference '{{.*}}precomp.obj': The path to this file must be provided on the command-line | |
| 16 | ||
| 17 | CHECK: Types (TPI Stream) | |
| 18 | CHECK-NOT: LF_PRECOMP | |
| 19 | CHECK-NOT: LF_ENDPRECOMP | |
| 20 | ||
| 21 | ||
| 22 | SUMMARY: Summary | |
| 23 | SUMMARY-NEXT: -------------------------------------------------------------------------------- | |
| 24 | SUMMARY-NEXT: 3 Input OBJ files (expanded from all cmd-line inputs) | |
| 25 | SUMMARY-NEXT: 0 PDB type server dependencies | |
| 26 | SUMMARY-NEXT: 1 Precomp OBJ dependencies | |
| 27 | SUMMARY-NEXT: 1044 Merged TPI records | |
| 28 | SUMMARY-NEXT: 5 Output PDB strings | |
| 29 | SUMMARY-NEXT: 167 Global symbol records | |
| 30 | SUMMARY-NEXT: 20 Module symbol records | |
| 31 | SUMMARY-NEXT: 3 Public symbol records | |
| 32 | ||
| 33 | // precomp.h | |
| 34 | #pragma once | |
| 35 | int Function(char A); | |
| 36 | ||
| 37 | // precomp.cpp | |
| 38 | #include "precomp.h" | |
| 39 | ||
| 40 | // a.cpp | |
| 41 | #include "precomp.h" | |
| 42 | int main(void) { | |
| 43 | Function('a'); | |
| 44 | return 0; | |
| 45 | } | |
| 46 | ||
| 47 | // b.cpp | |
| 48 | #include "precomp.h" | |
| 49 | int Function(char a) { | |
| 50 | return (int)a; | |
| 51 | } | |
| 52 | ||
| 53 | // cl.exe precomp.cpp /Z7 /Ycprecomp.h /c | |
| 54 | // cl.exe a.cpp b.cpp /Z7 /Yuprecomp.h /c |
deps/lld/test/COFF/reloc-x86.test+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: yaml2obj < %s > %t.obj |
| 3 | # RUN: lld-link /out:%t.exe /entry:main /base:0x400000 %t.obj | |
| 3 | # RUN: lld-link -safeseh:no /out:%t.exe /entry:main /base:0x400000 %t.obj | |
| 4 | 4 | # RUN: llvm-objdump -d %t.exe | FileCheck %s |
| 5 | 5 | |
| 6 | 6 | # CHECK: .text: |
deps/lld/test/COFF/resource-objs.test created+5| ... | ... | @@ -0,0 +1,5 @@ |
| 1 | # RUN: lld-link /out:%t.exe /dll /noentry %S/Inputs/id.res.o | |
| 2 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s | |
| 3 | ||
| 4 | CHECK: ResourceTableRVA: 0x1000 | |
| 5 | CHECK: ResourceTableSize: 0x80 |
deps/lld/test/COFF/resource.test+2-2| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | EXE: {{H.e.l.l.o}} |
| 8 | 8 | |
| 9 | 9 | # Verify the resource tree layout in the final executable. |
| 10 | # RUN: llvm-readobj -file-headers -coff-resources -section-data %t.exe | \ | |
| 10 | # RUN: llvm-readobj --file-headers --coff-resources --section-data %t.exe | \ | |
| 11 | 11 | # RUN: FileCheck --check-prefix=RESOURCE_INFO %s |
| 12 | 12 | |
| 13 | 13 | RESOURCE_INFO: ResourceTableRVA: 0x2000 |
| ... | ... | @@ -17,7 +17,7 @@ RESOURCE_INFO-NEXT: Total Number of Resources: 1 |
| 17 | 17 | RESOURCE_INFO-NEXT: Base Table Address: 0x600 |
| 18 | 18 | RESOURCE_INFO-DAG: Number of String Entries: 0 |
| 19 | 19 | RESOURCE_INFO-NEXT: Number of ID Entries: 1 |
| 20 | RESOURCE_INFO-NEXT: Type: kRT_STRING (ID 6) [ | |
| 20 | RESOURCE_INFO-NEXT: Type: STRINGTABLE (ID 6) [ | |
| 21 | 21 | RESOURCE_INFO-NEXT: Table Offset: 0x18 |
| 22 | 22 | RESOURCE_INFO-NEXT: Number of String Entries: 0 |
| 23 | 23 | RESOURCE_INFO-NEXT: Number of ID Entries: 1 |
deps/lld/test/COFF/responsefile.test+4-4| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: echo /out:%t.exe /entry:main %t.obj > %t.rsp |
| 4 | 4 | # RUN: lld-link @%t.rsp /heap:0x3000 |
| 5 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s | |
| 5 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck %s | |
| 6 | 6 | CHECK: SizeOfHeapReserve: 12288 |
| 7 | 7 | |
| 8 | 8 | # RUN: not lld-link --rsp-quoting=foobar @%t.rsp 2>&1 | \ |
| ... | ... | @@ -12,14 +12,14 @@ INVRSP: invalid response file quoting: foobar |
| 12 | 12 | # RUN: echo "blah\foo" > %t.rsp |
| 13 | 13 | # RUN: not lld-link @%t.rsp 2>&1 | \ |
| 14 | 14 | # RUN: FileCheck --check-prefix=DEFRSP %s |
| 15 | DEFRSP: error: could not open blah\foo | |
| 15 | DEFRSP: error: could not open 'blah\foo' | |
| 16 | 16 | |
| 17 | 17 | # RUN: echo "blah\foo" > %t.rsp |
| 18 | 18 | # RUN: not lld-link --rsp-quoting=windows @%t.rsp 2>&1 | \ |
| 19 | 19 | # RUN: FileCheck --check-prefix=WINRSP %s |
| 20 | WINRSP: error: could not open blah\foo | |
| 20 | WINRSP: error: could not open 'blah\foo' | |
| 21 | 21 | |
| 22 | 22 | # RUN: echo "blah\foo" > %t.rsp |
| 23 | 23 | # RUN: not lld-link --rsp-quoting=posix @%t.rsp 2>&1 | \ |
| 24 | 24 | # RUN: FileCheck --check-prefix=POSRSP %s |
| 25 | POSRSP: error: could not open blahfoo | |
| 25 | POSRSP: error: could not open 'blahfoo' |
deps/lld/test/COFF/rsds.test+7-7| ... | ... | @@ -2,29 +2,29 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: rm -f %t.dll %t.pdb |
| 4 | 4 | # RUN: lld-link /debug /pdbaltpath:test.pdb /dll /out:%t.dll /entry:DllMain %t.obj |
| 5 | # RUN: llvm-readobj -coff-debug-directory %t.dll > %t.1.txt | |
| 5 | # RUN: llvm-readobj --coff-debug-directory %t.dll > %t.1.txt | |
| 6 | 6 | # RUN: lld-link /debug /pdbaltpath:test.pdb /dll /out:%t.dll /entry:DllMain %t.obj |
| 7 | # RUN: llvm-readobj -coff-debug-directory %t.dll > %t.2.txt | |
| 7 | # RUN: llvm-readobj --coff-debug-directory %t.dll > %t.2.txt | |
| 8 | 8 | # RUN: cat %t.1.txt %t.2.txt | FileCheck %s |
| 9 | 9 | |
| 10 | 10 | # RUN: rm -f %t.dll %t.pdb |
| 11 | 11 | # RUN: lld-link /debug /pdb:%t1.pdb /dll /out:%t.dll /entry:DllMain %t.obj |
| 12 | # RUN: llvm-readobj -coff-debug-directory %t.dll > %t.3.txt | |
| 12 | # RUN: llvm-readobj --coff-debug-directory %t.dll > %t.3.txt | |
| 13 | 13 | # RUN: lld-link /debug /pdb:%t2.pdb /dll /out:%t.dll /entry:DllMain %t.obj |
| 14 | # RUN: llvm-readobj -coff-debug-directory %t.dll > %t.4.txt | |
| 14 | # RUN: llvm-readobj --coff-debug-directory %t.dll > %t.4.txt | |
| 15 | 15 | # RUN: cat %t.3.txt %t.4.txt | FileCheck --check-prefix TWOPDBS %s |
| 16 | 16 | |
| 17 | 17 | # RUN: rm -f %t.dll %t.pdb |
| 18 | 18 | # RUN: lld-link /Brepro /dll /out:%t.dll /entry:DllMain %t.obj |
| 19 | # RUN: llvm-readobj -coff-debug-directory %t.dll | FileCheck --check-prefix REPRO %s | |
| 19 | # RUN: llvm-readobj --coff-debug-directory %t.dll | FileCheck --check-prefix REPRO %s | |
| 20 | 20 | |
| 21 | 21 | # RUN: rm -f %t.dll %t.pdb |
| 22 | 22 | # RUN: lld-link /Brepro /debug /dll /out:%t.dll /entry:DllMain %t.obj |
| 23 | # RUN: llvm-readobj -coff-debug-directory %t.dll | FileCheck --check-prefix REPRODEBUG %s | |
| 23 | # RUN: llvm-readobj --coff-debug-directory %t.dll | FileCheck --check-prefix REPRODEBUG %s | |
| 24 | 24 | |
| 25 | 25 | # RUN: rm -f %t.dll %t.pdb |
| 26 | 26 | # RUN: lld-link /lldmingw /debug:dwarf /dll /out:%t.dll /entry:DllMain %t.obj |
| 27 | # RUN: llvm-readobj -coff-debug-directory %t.dll | FileCheck --check-prefix MINGW %s | |
| 27 | # RUN: llvm-readobj --coff-debug-directory %t.dll | FileCheck --check-prefix MINGW %s | |
| 28 | 28 | |
| 29 | 29 | # CHECK: File: [[FILE:.*]].dll |
| 30 | 30 | # CHECK: DebugDirectory [ |
deps/lld/test/COFF/s_udt.s+442-442| ... | ... | @@ -27,450 +27,450 @@ |
| 27 | 27 | # CHECK-NEXT: ============================================================ |
| 28 | 28 | # CHECK: {{.*}} | S_GPROC32 [size = 44] `main` |
| 29 | 29 | # CHECK-NEXT: parent = 0, end = 252, addr = 0001:0000, code size = 52 |
| 30 | # CHECK-NEXT: type = `0x1002 (int (int, char**))`, debug start = 0, debug end = 0, flags = none | |
| 30 | # CHECK-NEXT: type = `0x1002 (int (int, char**))`, debug start = 0, debug end = 0, flags = none | |
| 31 | 31 | # CHECK-NOT: {{.*}} | S_END |
| 32 | 32 | # CHECK: {{.*}} | S_UDT [size = 28] `main::LocalTypedef` |
| 33 | 33 | # CHECK-NEXT: original type = 0x1004 |
| 34 | # CHECK: {{.*}} | S_END [size = 4] | |
| 35 | ||
| 36 | # source code to re-generate: | |
| 37 | # clang-cl /Z7 /GS- /GR- /c foo.cpp | |
| 38 | # | |
| 39 | # struct Struct { | |
| 40 | # int x; | |
| 41 | # }; | |
| 42 | # | |
| 43 | # using IntTypedef = int; | |
| 44 | # using StructTypedef = Struct; | |
| 45 | # Struct S; | |
| 46 | # StructTypedef SS; | |
| 47 | # IntTypedef I; | |
| 48 | # | |
| 49 | # int main(int argc, char **argv) { | |
| 50 | # using LocalTypedef = Struct*; | |
| 51 | # LocalTypedef SPtr; | |
| 52 | # return I + S.x + SS.x + SPtr->x; | |
| 34 | # CHECK: {{.*}} | S_END [size = 4] | |
| 35 | ||
| 36 | # source code to re-generate: | |
| 37 | # clang-cl /Z7 /GS- /GR- /c foo.cpp | |
| 38 | # | |
| 39 | # struct Struct { | |
| 40 | # int x; | |
| 41 | # }; | |
| 42 | # | |
| 43 | # using IntTypedef = int; | |
| 44 | # using StructTypedef = Struct; | |
| 45 | # Struct S; | |
| 46 | # StructTypedef SS; | |
| 47 | # IntTypedef I; | |
| 48 | # | |
| 49 | # int main(int argc, char **argv) { | |
| 50 | # using LocalTypedef = Struct*; | |
| 51 | # LocalTypedef SPtr; | |
| 52 | # return I + S.x + SS.x + SPtr->x; | |
| 53 | 53 | # } |
| 54 | 54 | |
| 55 | 	.text | |
| 56 | 	.def	 @feat.00; | |
| 57 | 	.scl	3; | |
| 58 | 	.type	0; | |
| 59 | 	.endef | |
| 60 | 	.globl	@feat.00 | |
| 61 | .set @feat.00, 0 | |
| 62 | 	.intel_syntax noprefix | |
| 63 | 	.def	 main; | |
| 64 | 	.scl	2; | |
| 65 | 	.type	32; | |
| 66 | 	.endef | |
| 67 | 	.globl	main # -- Begin function main | |
| 68 | 	.p2align	4, 0x90 | |
| 69 | main: # @main | |
| 70 | .Lfunc_begin0: | |
| 71 | 	.cv_func_id 0 | |
| 72 | 	.cv_file	1 "D:\\src\\llvmbuild\\cl\\Debug\\x64\\foo.cpp" "2B62298EE3EEF94E1D81FDFE18BD46A6" 1 | |
| 73 | 	.cv_loc	0 1 12 0 # foo.cpp:12:0 | |
| 74 | .seh_proc main | |
| 75 | # %bb.0: # %entry | |
| 76 | 	sub	rsp, 32 | |
| 77 | 	.seh_stackalloc 32 | |
| 78 | 	.seh_endprologue | |
| 79 | 	mov	dword ptr [rsp + 28], 0 | |
| 80 | 	mov	qword ptr [rsp + 16], rdx | |
| 81 | 	mov	dword ptr [rsp + 12], ecx | |
| 82 | .Ltmp0: | |
| 83 | 	.cv_loc	0 1 15 0 # foo.cpp:15:0 | |
| 84 | 	mov	ecx, dword ptr [rip + "?I@@3HA"] | |
| 85 | 	add	ecx, dword ptr [rip + "?S@@3UStruct@@A"] | |
| 86 | 	add	ecx, dword ptr [rip + "?SS@@3UStruct@@A"] | |
| 87 | 	mov	rdx, qword ptr [rsp] | |
| 88 | 	add	ecx, dword ptr [rdx] | |
| 89 | 	mov	eax, ecx | |
| 90 | 	add	rsp, 32 | |
| 91 | 	ret | |
| 92 | .Ltmp1: | |
| 93 | .Lfunc_end0: | |
| 94 | 	.seh_handlerdata | |
| 95 | 	.text | |
| 96 | 	.seh_endproc | |
| 97 | # -- End function | |
| 98 | 	.bss | |
| 99 | 	.globl	"?S@@3UStruct@@A" # @"?S@@3UStruct@@A" | |
| 100 | 	.p2align	2 | |
| 101 | "?S@@3UStruct@@A": | |
| 102 | 	.zero	4 | |
| 103 | ||
| 104 | 	.globl	"?SS@@3UStruct@@A" # @"?SS@@3UStruct@@A" | |
| 105 | 	.p2align	2 | |
| 106 | "?SS@@3UStruct@@A": | |
| 107 | 	.zero	4 | |
| 108 | ||
| 109 | 	.globl	"?I@@3HA" # @"?I@@3HA" | |
| 110 | 	.p2align	2 | |
| 111 | "?I@@3HA": | |
| 112 | 	.long	0 # 0x0 | |
| 113 | ||
| 114 | 	.section	.drectve,"yn" | |
| 115 | 	.ascii	" /DEFAULTLIB:libcmt.lib" | |
| 116 | 	.ascii	" /DEFAULTLIB:oldnames.lib" | |
| 117 | 	.section	.debug$S,"dr" | |
| 118 | 	.p2align	2 | |
| 119 | 	.long	4 # Debug section magic | |
| 120 | 	.long	241 | |
| 121 | 	.long	.Ltmp3-.Ltmp2 # Subsection size | |
| 122 | .Ltmp2: | |
| 123 | 	.short	.Ltmp5-.Ltmp4 # Record length | |
| 124 | .Ltmp4: | |
| 125 | 	.short	4412 # Record kind: S_COMPILE3 | |
| 126 | 	.long	1 # Flags and language | |
| 127 | 	.short	208 # CPUType | |
| 128 | 	.short	8 # Frontend version | |
| 129 | 	.short	0 | |
| 130 | 	.short	0 | |
| 131 | 	.short	0 | |
| 132 | 	.short	8000 # Backend version | |
| 133 | 	.short	0 | |
| 134 | 	.short	0 | |
| 135 | 	.short	0 | |
| 136 | 	.asciz	"clang version 8.0.0 " # Null-terminated compiler version string | |
| 137 | .Ltmp5: | |
| 138 | .Ltmp3: | |
| 139 | 	.p2align	2 | |
| 140 | 	.long	241 # Symbol subsection for main | |
| 141 | 	.long	.Ltmp7-.Ltmp6 # Subsection size | |
| 142 | .Ltmp6: | |
| 143 | 	.short	.Ltmp9-.Ltmp8 # Record length | |
| 144 | .Ltmp8: | |
| 145 | 	.short	4423 # Record kind: S_GPROC32_ID | |
| 146 | 	.long	0 # PtrParent | |
| 147 | 	.long	0 # PtrEnd | |
| 148 | 	.long	0 # PtrNext | |
| 149 | 	.long	.Lfunc_end0-main # Code size | |
| 150 | 	.long	0 # Offset after prologue | |
| 151 | 	.long	0 # Offset before epilogue | |
| 152 | 	.long	4099 # Function type index | |
| 153 | 	.secrel32	main # Function section relative address | |
| 154 | 	.secidx	main # Function section index | |
| 155 | 	.byte	0 # Flags | |
| 156 | 	.asciz	"main" # Function name | |
| 157 | .Ltmp9: | |
| 158 | 	.short	.Ltmp11-.Ltmp10 # Record length | |
| 159 | .Ltmp10: | |
| 160 | 	.short	4114 # Record kind: S_FRAMEPROC | |
| 161 | 	.long	32 # FrameSize | |
| 162 | 	.long	0 # Padding | |
| 163 | 	.long	0 # Offset of padding | |
| 164 | 	.long	0 # Bytes of callee saved registers | |
| 165 | 	.long	0 # Exception handler offset | |
| 166 | 	.short	0 # Exception handler section | |
| 167 | 	.long	81920 # Flags (defines frame register) | |
| 168 | .Ltmp11: | |
| 169 | 	.short	.Ltmp13-.Ltmp12 # Record length | |
| 170 | .Ltmp12: | |
| 171 | 	.short	4414 # Record kind: S_LOCAL | |
| 172 | 	.long	116 # TypeIndex | |
| 173 | 	.short	1 # Flags | |
| 174 | 	.asciz	"argc" | |
| 175 | .Ltmp13: | |
| 176 | 	.cv_def_range	 .Ltmp0 .Ltmp1, "B\021\f\000\000\000" | |
| 177 | 	.short	.Ltmp15-.Ltmp14 # Record length | |
| 178 | .Ltmp14: | |
| 179 | 	.short	4414 # Record kind: S_LOCAL | |
| 180 | 	.long	4096 # TypeIndex | |
| 181 | 	.short	1 # Flags | |
| 182 | 	.asciz	"argv" | |
| 183 | .Ltmp15: | |
| 184 | 	.cv_def_range	 .Ltmp0 .Ltmp1, "B\021\020\000\000\000" | |
| 185 | 	.short	.Ltmp17-.Ltmp16 # Record length | |
| 186 | .Ltmp16: | |
| 187 | 	.short	4414 # Record kind: S_LOCAL | |
| 188 | 	.long	4101 # TypeIndex | |
| 189 | 	.short	0 # Flags | |
| 190 | 	.asciz	"SPtr" | |
| 191 | .Ltmp17: | |
| 192 | 	.cv_def_range	 .Ltmp0 .Ltmp1, "B\021\000\000\000\000" | |
| 193 | 	.short	.Ltmp19-.Ltmp18 # Record length | |
| 194 | .Ltmp18: | |
| 195 | 	.short	4360 # Record kind: S_UDT | |
| 196 | 	.long	4101 # Type | |
| 197 | 	.asciz	"main::LocalTypedef" | |
| 198 | .Ltmp19: | |
| 199 | 	.short	2 # Record length | |
| 200 | 	.short	4431 # Record kind: S_PROC_ID_END | |
| 201 | .Ltmp7: | |
| 202 | 	.p2align	2 | |
| 203 | 	.cv_linetable	0, main, .Lfunc_end0 | |
| 204 | 	.long	241 # Symbol subsection for globals | |
| 205 | 	.long	.Ltmp21-.Ltmp20 # Subsection size | |
| 206 | .Ltmp20: | |
| 207 | 	.short	.Ltmp23-.Ltmp22 # Record length | |
| 208 | .Ltmp22: | |
| 209 | 	.short	4365 # Record kind: S_GDATA32 | |
| 210 | 	.long	4103 # Type | |
| 211 | 	.secrel32	"?S@@3UStruct@@A" # DataOffset | |
| 212 | 	.secidx	"?S@@3UStruct@@A" # Segment | |
| 213 | 	.asciz	"S" # Name | |
| 214 | .Ltmp23: | |
| 215 | 	.short	.Ltmp25-.Ltmp24 # Record length | |
| 216 | .Ltmp24: | |
| 217 | 	.short	4365 # Record kind: S_GDATA32 | |
| 218 | 	.long	4100 # Type | |
| 219 | 	.secrel32	"?SS@@3UStruct@@A" # DataOffset | |
| 220 | 	.secidx	"?SS@@3UStruct@@A" # Segment | |
| 221 | 	.asciz	"SS" # Name | |
| 222 | .Ltmp25: | |
| 223 | 	.short	.Ltmp27-.Ltmp26 # Record length | |
| 224 | .Ltmp26: | |
| 225 | 	.short	4365 # Record kind: S_GDATA32 | |
| 226 | 	.long	116 # Type | |
| 227 | 	.secrel32	"?I@@3HA" # DataOffset | |
| 228 | 	.secidx	"?I@@3HA" # Segment | |
| 229 | 	.asciz	"I" # Name | |
| 230 | .Ltmp27: | |
| 231 | .Ltmp21: | |
| 232 | 	.p2align	2 | |
| 233 | 	.long	241 | |
| 234 | 	.long	.Ltmp29-.Ltmp28 # Subsection size | |
| 235 | .Ltmp28: | |
| 236 | 	.short	.Ltmp31-.Ltmp30 # Record length | |
| 237 | .Ltmp30: | |
| 238 | 	.short	4360 # Record kind: S_UDT | |
| 239 | 	.long	4103 # Type | |
| 240 | 	.asciz	"Struct" | |
| 241 | .Ltmp31: | |
| 242 | 	.short	.Ltmp33-.Ltmp32 # Record length | |
| 243 | .Ltmp32: | |
| 244 | 	.short	4360 # Record kind: S_UDT | |
| 245 | 	.long	4100 # Type | |
| 246 | 	.asciz	"StructTypedef" | |
| 247 | .Ltmp33: | |
| 248 | 	.short	.Ltmp35-.Ltmp34 # Record length | |
| 249 | .Ltmp34: | |
| 250 | 	.short	4360 # Record kind: S_UDT | |
| 251 | 	.long	116 # Type | |
| 252 | 	.asciz	"IntTypedef" | |
| 253 | .Ltmp35: | |
| 254 | .Ltmp29: | |
| 255 | 	.p2align	2 | |
| 256 | 	.cv_filechecksums # File index to string table offset subsection | |
| 257 | 	.cv_stringtable # String table | |
| 258 | 	.long	241 | |
| 259 | 	.long	.Ltmp37-.Ltmp36 # Subsection size | |
| 260 | .Ltmp36: | |
| 261 | 	.short	6 # Record length | |
| 262 | 	.short	4428 # Record kind: S_BUILDINFO | |
| 263 | 	.long	4108 # LF_BUILDINFO index | |
| 264 | .Ltmp37: | |
| 265 | 	.p2align	2 | |
| 266 | 	.section	.debug$T,"dr" | |
| 267 | 	.p2align	2 | |
| 268 | 	.long	4 # Debug section magic | |
| 269 | 	# Pointer (0x1000) { | |
| 270 | 	# TypeLeafKind: LF_POINTER (0x1002) | |
| 271 | 	# PointeeType: char* (0x670) | |
| 272 | 	# PtrType: Near64 (0xC) | |
| 273 | 	# PtrMode: Pointer (0x0) | |
| 274 | 	# IsFlat: 0 | |
| 275 | 	# IsConst: 0 | |
| 276 | 	# IsVolatile: 0 | |
| 277 | 	# IsUnaligned: 0 | |
| 278 | 	# IsRestrict: 0 | |
| 279 | 	# IsThisPtr&: 0 | |
| 280 | 	# IsThisPtr&&: 0 | |
| 281 | 	# SizeOf: 8 | |
| 282 | 	# } | |
| 283 | 	.byte	0x0a, 0x00, 0x02, 0x10 | |
| 284 | 	.byte	0x70, 0x06, 0x00, 0x00 | |
| 285 | 	.byte	0x0c, 0x00, 0x01, 0x00 | |
| 286 | 	# ArgList (0x1001) { | |
| 287 | 	# TypeLeafKind: LF_ARGLIST (0x1201) | |
| 288 | 	# NumArgs: 2 | |
| 289 | 	# Arguments [ | |
| 290 | 	# ArgType: int (0x74) | |
| 291 | 	# ArgType: char** (0x1000) | |
| 292 | 	# ] | |
| 293 | 	# } | |
| 294 | 	.byte	0x0e, 0x00, 0x01, 0x12 | |
| 295 | 	.byte	0x02, 0x00, 0x00, 0x00 | |
| 296 | 	.byte	0x74, 0x00, 0x00, 0x00 | |
| 297 | 	.byte	0x00, 0x10, 0x00, 0x00 | |
| 298 | 	# Procedure (0x1002) { | |
| 299 | 	# TypeLeafKind: LF_PROCEDURE (0x1008) | |
| 300 | 	# ReturnType: int (0x74) | |
| 301 | 	# CallingConvention: NearC (0x0) | |
| 302 | 	# FunctionOptions [ (0x0) | |
| 303 | 	# ] | |
| 304 | 	# NumParameters: 2 | |
| 305 | 	# ArgListType: (int, char**) (0x1001) | |
| 306 | 	# } | |
| 307 | 	.byte	0x0e, 0x00, 0x08, 0x10 | |
| 308 | 	.byte	0x74, 0x00, 0x00, 0x00 | |
| 309 | 	.byte	0x00, 0x00, 0x02, 0x00 | |
| 310 | 	.byte	0x01, 0x10, 0x00, 0x00 | |
| 311 | 	# FuncId (0x1003) { | |
| 312 | 	# TypeLeafKind: LF_FUNC_ID (0x1601) | |
| 313 | 	# ParentScope: 0x0 | |
| 314 | 	# FunctionType: int (int, char**) (0x1002) | |
| 315 | 	# Name: main | |
| 316 | 	# } | |
| 317 | 	.byte	0x12, 0x00, 0x01, 0x16 | |
| 318 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 319 | 	.byte	0x02, 0x10, 0x00, 0x00 | |
| 320 | 	.byte	0x6d, 0x61, 0x69, 0x6e | |
| 321 | 	.byte	0x00, 0xf3, 0xf2, 0xf1 | |
| 322 | 	# Struct (0x1004) { | |
| 323 | 	# TypeLeafKind: LF_STRUCTURE (0x1505) | |
| 324 | 	# MemberCount: 0 | |
| 325 | 	# Properties [ (0x280) | |
| 326 | 	# ForwardReference (0x80) | |
| 327 | 	# HasUniqueName (0x200) | |
| 328 | 	# ] | |
| 329 | 	# FieldList: 0x0 | |
| 330 | 	# DerivedFrom: 0x0 | |
| 331 | 	# VShape: 0x0 | |
| 332 | 	# SizeOf: 0 | |
| 333 | 	# Name: Struct | |
| 334 | 	# LinkageName: .?AUStruct@@ | |
| 335 | 	# } | |
| 336 | 	.byte	0x2a, 0x00, 0x05, 0x15 | |
| 337 | 	.byte	0x00, 0x00, 0x80, 0x02 | |
| 338 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 339 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 340 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 341 | 	.byte	0x00, 0x00, 0x53, 0x74 | |
| 342 | 	.byte	0x72, 0x75, 0x63, 0x74 | |
| 343 | 	.byte	0x00, 0x2e, 0x3f, 0x41 | |
| 344 | 	.byte	0x55, 0x53, 0x74, 0x72 | |
| 345 | 	.byte	0x75, 0x63, 0x74, 0x40 | |
| 346 | 	.byte	0x40, 0x00, 0xf2, 0xf1 | |
| 347 | 	# Pointer (0x1005) { | |
| 348 | 	# TypeLeafKind: LF_POINTER (0x1002) | |
| 349 | 	# PointeeType: Struct (0x1004) | |
| 350 | 	# PtrType: Near64 (0xC) | |
| 351 | 	# PtrMode: Pointer (0x0) | |
| 352 | 	# IsFlat: 0 | |
| 353 | 	# IsConst: 0 | |
| 354 | 	# IsVolatile: 0 | |
| 355 | 	# IsUnaligned: 0 | |
| 356 | 	# IsRestrict: 0 | |
| 357 | 	# IsThisPtr&: 0 | |
| 358 | 	# IsThisPtr&&: 0 | |
| 359 | 	# SizeOf: 8 | |
| 360 | 	# } | |
| 361 | 	.byte	0x0a, 0x00, 0x02, 0x10 | |
| 362 | 	.byte	0x04, 0x10, 0x00, 0x00 | |
| 363 | 	.byte	0x0c, 0x00, 0x01, 0x00 | |
| 364 | 	# FieldList (0x1006) { | |
| 365 | 	# TypeLeafKind: LF_FIELDLIST (0x1203) | |
| 366 | 	# DataMember { | |
| 367 | 	# TypeLeafKind: LF_MEMBER (0x150D) | |
| 368 | 	# AccessSpecifier: Public (0x3) | |
| 369 | 	# Type: int (0x74) | |
| 370 | 	# FieldOffset: 0x0 | |
| 371 | 	# Name: x | |
| 372 | 	# } | |
| 373 | 	# } | |
| 374 | 	.byte	0x0e, 0x00, 0x03, 0x12 | |
| 375 | 	.byte	0x0d, 0x15, 0x03, 0x00 | |
| 376 | 	.byte	0x74, 0x00, 0x00, 0x00 | |
| 377 | 	.byte	0x00, 0x00, 0x78, 0x00 | |
| 378 | 	# Struct (0x1007) { | |
| 379 | 	# TypeLeafKind: LF_STRUCTURE (0x1505) | |
| 380 | 	# MemberCount: 1 | |
| 381 | 	# Properties [ (0x200) | |
| 382 | 	# HasUniqueName (0x200) | |
| 383 | 	# ] | |
| 384 | 	# FieldList: <field list> (0x1006) | |
| 385 | 	# DerivedFrom: 0x0 | |
| 386 | 	# VShape: 0x0 | |
| 387 | 	# SizeOf: 4 | |
| 388 | 	# Name: Struct | |
| 389 | 	# LinkageName: .?AUStruct@@ | |
| 390 | 	# } | |
| 391 | 	.byte	0x2a, 0x00, 0x05, 0x15 | |
| 392 | 	.byte	0x01, 0x00, 0x00, 0x02 | |
| 393 | 	.byte	0x06, 0x10, 0x00, 0x00 | |
| 394 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 395 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 396 | 	.byte	0x04, 0x00, 0x53, 0x74 | |
| 397 | 	.byte	0x72, 0x75, 0x63, 0x74 | |
| 398 | 	.byte	0x00, 0x2e, 0x3f, 0x41 | |
| 399 | 	.byte	0x55, 0x53, 0x74, 0x72 | |
| 400 | 	.byte	0x75, 0x63, 0x74, 0x40 | |
| 401 | 	.byte	0x40, 0x00, 0xf2, 0xf1 | |
| 402 | 	# StringId (0x1008) { | |
| 403 | 	# TypeLeafKind: LF_STRING_ID (0x1605) | |
| 404 | 	# Id: 0x0 | |
| 405 | 	# StringData: D:\src\llvmbuild\cl\Debug\x64\foo.cpp | |
| 406 | 	# } | |
| 407 | 	.byte	0x2e, 0x00, 0x05, 0x16 | |
| 408 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 409 | 	.byte	0x44, 0x3a, 0x5c, 0x73 | |
| 410 | 	.byte	0x72, 0x63, 0x5c, 0x6c | |
| 411 | 	.byte	0x6c, 0x76, 0x6d, 0x62 | |
| 412 | 	.byte	0x75, 0x69, 0x6c, 0x64 | |
| 413 | 	.byte	0x5c, 0x63, 0x6c, 0x5c | |
| 414 | 	.byte	0x44, 0x65, 0x62, 0x75 | |
| 415 | 	.byte	0x67, 0x5c, 0x78, 0x36 | |
| 416 | 	.byte	0x34, 0x5c, 0x66, 0x6f | |
| 417 | 	.byte	0x6f, 0x2e, 0x63, 0x70 | |
| 418 | 	.byte	0x70, 0x00, 0xf2, 0xf1 | |
| 419 | 	# UdtSourceLine (0x1009) { | |
| 420 | 	# TypeLeafKind: LF_UDT_SRC_LINE (0x1606) | |
| 421 | 	# UDT: Struct (0x1007) | |
| 422 | 	# SourceFile: D:\src\llvmbuild\cl\Debug\x64\foo.cpp (0x1008) | |
| 423 | 	# LineNumber: 1 | |
| 424 | 	# } | |
| 425 | 	.byte	0x0e, 0x00, 0x06, 0x16 | |
| 426 | 	.byte	0x07, 0x10, 0x00, 0x00 | |
| 427 | 	.byte	0x08, 0x10, 0x00, 0x00 | |
| 428 | 	.byte	0x01, 0x00, 0x00, 0x00 | |
| 429 | 	# StringId (0x100A) { | |
| 430 | 	# TypeLeafKind: LF_STRING_ID (0x1605) | |
| 431 | 	# Id: 0x0 | |
| 432 | 	# StringData: D:\\src\\llvmbuild\\cl\\Debug\\x64 | |
| 433 | 	# } | |
| 434 | 	.byte	0x2a, 0x00, 0x05, 0x16 | |
| 435 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 436 | 	.byte	0x44, 0x3a, 0x5c, 0x5c | |
| 437 | 	.byte	0x73, 0x72, 0x63, 0x5c | |
| 438 | 	.byte	0x5c, 0x6c, 0x6c, 0x76 | |
| 439 | 	.byte	0x6d, 0x62, 0x75, 0x69 | |
| 440 | 	.byte	0x6c, 0x64, 0x5c, 0x5c | |
| 441 | 	.byte	0x63, 0x6c, 0x5c, 0x5c | |
| 442 | 	.byte	0x44, 0x65, 0x62, 0x75 | |
| 443 | 	.byte	0x67, 0x5c, 0x5c, 0x78 | |
| 444 | 	.byte	0x36, 0x34, 0x00, 0xf1 | |
| 445 | 	# StringId (0x100B) { | |
| 446 | 	# TypeLeafKind: LF_STRING_ID (0x1605) | |
| 447 | 	# Id: 0x0 | |
| 448 | 	# StringData: foo.cpp | |
| 449 | 	# } | |
| 450 | 	.byte	0x0e, 0x00, 0x05, 0x16 | |
| 451 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 452 | 	.byte	0x66, 0x6f, 0x6f, 0x2e | |
| 453 | 	.byte	0x63, 0x70, 0x70, 0x00 | |
| 454 | 	# BuildInfo (0x100C) { | |
| 455 | 	# TypeLeafKind: LF_BUILDINFO (0x1603) | |
| 456 | 	# NumArgs: 5 | |
| 457 | 	# Arguments [ | |
| 458 | 	# ArgType: D:\\src\\llvmbuild\\cl\\Debug\\x64 (0x100A) | |
| 459 | 	# ArgType: 0x0 | |
| 460 | 	# ArgType: foo.cpp (0x100B) | |
| 461 | 	# ArgType: 0x0 | |
| 462 | 	# ArgType: 0x0 | |
| 463 | 	# ] | |
| 464 | 	# } | |
| 465 | 	.byte	0x1a, 0x00, 0x03, 0x16 | |
| 466 | 	.byte	0x05, 0x00, 0x0a, 0x10 | |
| 467 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 468 | 	.byte	0x00, 0x00, 0x0b, 0x10 | |
| 469 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 470 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 471 | 	.byte	0x00, 0x00, 0xf2, 0xf1 | |
| 472 | ||
| 473 | 	.addrsig | |
| 474 | 	.addrsig_sym "?S@@3UStruct@@A" | |
| 475 | 	.addrsig_sym "?SS@@3UStruct@@A" | |
| 476 | 	.addrsig_sym "?I@@3HA" | |
| 55 | 	.text | |
| 56 | 	.def	 @feat.00; | |
| 57 | 	.scl	3; | |
| 58 | 	.type	0; | |
| 59 | 	.endef | |
| 60 | 	.globl	@feat.00 | |
| 61 | .set @feat.00, 0 | |
| 62 | 	.intel_syntax noprefix | |
| 63 | 	.def	 main; | |
| 64 | 	.scl	2; | |
| 65 | 	.type	32; | |
| 66 | 	.endef | |
| 67 | 	.globl	main # -- Begin function main | |
| 68 | 	.p2align	4, 0x90 | |
| 69 | main: # @main | |
| 70 | .Lfunc_begin0: | |
| 71 | 	.cv_func_id 0 | |
| 72 | 	.cv_file	1 "D:\\src\\llvmbuild\\cl\\Debug\\x64\\foo.cpp" "2B62298EE3EEF94E1D81FDFE18BD46A6" 1 | |
| 73 | 	.cv_loc	0 1 12 0 # foo.cpp:12:0 | |
| 74 | .seh_proc main | |
| 75 | # %bb.0: # %entry | |
| 76 | 	sub	rsp, 32 | |
| 77 | 	.seh_stackalloc 32 | |
| 78 | 	.seh_endprologue | |
| 79 | 	mov	dword ptr [rsp + 28], 0 | |
| 80 | 	mov	qword ptr [rsp + 16], rdx | |
| 81 | 	mov	dword ptr [rsp + 12], ecx | |
| 82 | .Ltmp0: | |
| 83 | 	.cv_loc	0 1 15 0 # foo.cpp:15:0 | |
| 84 | 	mov	ecx, dword ptr [rip + "?I@@3HA"] | |
| 85 | 	add	ecx, dword ptr [rip + "?S@@3UStruct@@A"] | |
| 86 | 	add	ecx, dword ptr [rip + "?SS@@3UStruct@@A"] | |
| 87 | 	mov	rdx, qword ptr [rsp] | |
| 88 | 	add	ecx, dword ptr [rdx] | |
| 89 | 	mov	eax, ecx | |
| 90 | 	add	rsp, 32 | |
| 91 | 	ret | |
| 92 | .Ltmp1: | |
| 93 | .Lfunc_end0: | |
| 94 | 	.seh_handlerdata | |
| 95 | 	.text | |
| 96 | 	.seh_endproc | |
| 97 | # -- End function | |
| 98 | 	.bss | |
| 99 | 	.globl	"?S@@3UStruct@@A" # @"?S@@3UStruct@@A" | |
| 100 | 	.p2align	2 | |
| 101 | "?S@@3UStruct@@A": | |
| 102 | 	.zero	4 | |
| 103 | ||
| 104 | 	.globl	"?SS@@3UStruct@@A" # @"?SS@@3UStruct@@A" | |
| 105 | 	.p2align	2 | |
| 106 | "?SS@@3UStruct@@A": | |
| 107 | 	.zero	4 | |
| 108 | ||
| 109 | 	.globl	"?I@@3HA" # @"?I@@3HA" | |
| 110 | 	.p2align	2 | |
| 111 | "?I@@3HA": | |
| 112 | 	.long	0 # 0x0 | |
| 113 | ||
| 114 | 	.section	.drectve,"yn" | |
| 115 | 	.ascii	" /DEFAULTLIB:libcmt.lib" | |
| 116 | 	.ascii	" /DEFAULTLIB:oldnames.lib" | |
| 117 | 	.section	.debug$S,"dr" | |
| 118 | 	.p2align	2 | |
| 119 | 	.long	4 # Debug section magic | |
| 120 | 	.long	241 | |
| 121 | 	.long	.Ltmp3-.Ltmp2 # Subsection size | |
| 122 | .Ltmp2: | |
| 123 | 	.short	.Ltmp5-.Ltmp4 # Record length | |
| 124 | .Ltmp4: | |
| 125 | 	.short	4412 # Record kind: S_COMPILE3 | |
| 126 | 	.long	1 # Flags and language | |
| 127 | 	.short	208 # CPUType | |
| 128 | 	.short	8 # Frontend version | |
| 129 | 	.short	0 | |
| 130 | 	.short	0 | |
| 131 | 	.short	0 | |
| 132 | 	.short	8000 # Backend version | |
| 133 | 	.short	0 | |
| 134 | 	.short	0 | |
| 135 | 	.short	0 | |
| 136 | 	.asciz	"clang version 8.0.0 " # Null-terminated compiler version string | |
| 137 | .Ltmp5: | |
| 138 | .Ltmp3: | |
| 139 | 	.p2align	2 | |
| 140 | 	.long	241 # Symbol subsection for main | |
| 141 | 	.long	.Ltmp7-.Ltmp6 # Subsection size | |
| 142 | .Ltmp6: | |
| 143 | 	.short	.Ltmp9-.Ltmp8 # Record length | |
| 144 | .Ltmp8: | |
| 145 | 	.short	4423 # Record kind: S_GPROC32_ID | |
| 146 | 	.long	0 # PtrParent | |
| 147 | 	.long	0 # PtrEnd | |
| 148 | 	.long	0 # PtrNext | |
| 149 | 	.long	.Lfunc_end0-main # Code size | |
| 150 | 	.long	0 # Offset after prologue | |
| 151 | 	.long	0 # Offset before epilogue | |
| 152 | 	.long	4099 # Function type index | |
| 153 | 	.secrel32	main # Function section relative address | |
| 154 | 	.secidx	main # Function section index | |
| 155 | 	.byte	0 # Flags | |
| 156 | 	.asciz	"main" # Function name | |
| 157 | .Ltmp9: | |
| 158 | 	.short	.Ltmp11-.Ltmp10 # Record length | |
| 159 | .Ltmp10: | |
| 160 | 	.short	4114 # Record kind: S_FRAMEPROC | |
| 161 | 	.long	32 # FrameSize | |
| 162 | 	.long	0 # Padding | |
| 163 | 	.long	0 # Offset of padding | |
| 164 | 	.long	0 # Bytes of callee saved registers | |
| 165 | 	.long	0 # Exception handler offset | |
| 166 | 	.short	0 # Exception handler section | |
| 167 | 	.long	81920 # Flags (defines frame register) | |
| 168 | .Ltmp11: | |
| 169 | 	.short	.Ltmp13-.Ltmp12 # Record length | |
| 170 | .Ltmp12: | |
| 171 | 	.short	4414 # Record kind: S_LOCAL | |
| 172 | 	.long	116 # TypeIndex | |
| 173 | 	.short	1 # Flags | |
| 174 | 	.asciz	"argc" | |
| 175 | .Ltmp13: | |
| 176 | 	.cv_def_range	 .Ltmp0 .Ltmp1, "B\021\f\000\000\000" | |
| 177 | 	.short	.Ltmp15-.Ltmp14 # Record length | |
| 178 | .Ltmp14: | |
| 179 | 	.short	4414 # Record kind: S_LOCAL | |
| 180 | 	.long	4096 # TypeIndex | |
| 181 | 	.short	1 # Flags | |
| 182 | 	.asciz	"argv" | |
| 183 | .Ltmp15: | |
| 184 | 	.cv_def_range	 .Ltmp0 .Ltmp1, "B\021\020\000\000\000" | |
| 185 | 	.short	.Ltmp17-.Ltmp16 # Record length | |
| 186 | .Ltmp16: | |
| 187 | 	.short	4414 # Record kind: S_LOCAL | |
| 188 | 	.long	4101 # TypeIndex | |
| 189 | 	.short	0 # Flags | |
| 190 | 	.asciz	"SPtr" | |
| 191 | .Ltmp17: | |
| 192 | 	.cv_def_range	 .Ltmp0 .Ltmp1, "B\021\000\000\000\000" | |
| 193 | 	.short	.Ltmp19-.Ltmp18 # Record length | |
| 194 | .Ltmp18: | |
| 195 | 	.short	4360 # Record kind: S_UDT | |
| 196 | 	.long	4101 # Type | |
| 197 | 	.asciz	"main::LocalTypedef" | |
| 198 | .Ltmp19: | |
| 199 | 	.short	2 # Record length | |
| 200 | 	.short	4431 # Record kind: S_PROC_ID_END | |
| 201 | .Ltmp7: | |
| 202 | 	.p2align	2 | |
| 203 | 	.cv_linetable	0, main, .Lfunc_end0 | |
| 204 | 	.long	241 # Symbol subsection for globals | |
| 205 | 	.long	.Ltmp21-.Ltmp20 # Subsection size | |
| 206 | .Ltmp20: | |
| 207 | 	.short	.Ltmp23-.Ltmp22 # Record length | |
| 208 | .Ltmp22: | |
| 209 | 	.short	4365 # Record kind: S_GDATA32 | |
| 210 | 	.long	4103 # Type | |
| 211 | 	.secrel32	"?S@@3UStruct@@A" # DataOffset | |
| 212 | 	.secidx	"?S@@3UStruct@@A" # Segment | |
| 213 | 	.asciz	"S" # Name | |
| 214 | .Ltmp23: | |
| 215 | 	.short	.Ltmp25-.Ltmp24 # Record length | |
| 216 | .Ltmp24: | |
| 217 | 	.short	4365 # Record kind: S_GDATA32 | |
| 218 | 	.long	4100 # Type | |
| 219 | 	.secrel32	"?SS@@3UStruct@@A" # DataOffset | |
| 220 | 	.secidx	"?SS@@3UStruct@@A" # Segment | |
| 221 | 	.asciz	"SS" # Name | |
| 222 | .Ltmp25: | |
| 223 | 	.short	.Ltmp27-.Ltmp26 # Record length | |
| 224 | .Ltmp26: | |
| 225 | 	.short	4365 # Record kind: S_GDATA32 | |
| 226 | 	.long	116 # Type | |
| 227 | 	.secrel32	"?I@@3HA" # DataOffset | |
| 228 | 	.secidx	"?I@@3HA" # Segment | |
| 229 | 	.asciz	"I" # Name | |
| 230 | .Ltmp27: | |
| 231 | .Ltmp21: | |
| 232 | 	.p2align	2 | |
| 233 | 	.long	241 | |
| 234 | 	.long	.Ltmp29-.Ltmp28 # Subsection size | |
| 235 | .Ltmp28: | |
| 236 | 	.short	.Ltmp31-.Ltmp30 # Record length | |
| 237 | .Ltmp30: | |
| 238 | 	.short	4360 # Record kind: S_UDT | |
| 239 | 	.long	4103 # Type | |
| 240 | 	.asciz	"Struct" | |
| 241 | .Ltmp31: | |
| 242 | 	.short	.Ltmp33-.Ltmp32 # Record length | |
| 243 | .Ltmp32: | |
| 244 | 	.short	4360 # Record kind: S_UDT | |
| 245 | 	.long	4100 # Type | |
| 246 | 	.asciz	"StructTypedef" | |
| 247 | .Ltmp33: | |
| 248 | 	.short	.Ltmp35-.Ltmp34 # Record length | |
| 249 | .Ltmp34: | |
| 250 | 	.short	4360 # Record kind: S_UDT | |
| 251 | 	.long	116 # Type | |
| 252 | 	.asciz	"IntTypedef" | |
| 253 | .Ltmp35: | |
| 254 | .Ltmp29: | |
| 255 | 	.p2align	2 | |
| 256 | 	.cv_filechecksums # File index to string table offset subsection | |
| 257 | 	.cv_stringtable # String table | |
| 258 | 	.long	241 | |
| 259 | 	.long	.Ltmp37-.Ltmp36 # Subsection size | |
| 260 | .Ltmp36: | |
| 261 | 	.short	6 # Record length | |
| 262 | 	.short	4428 # Record kind: S_BUILDINFO | |
| 263 | 	.long	4108 # LF_BUILDINFO index | |
| 264 | .Ltmp37: | |
| 265 | 	.p2align	2 | |
| 266 | 	.section	.debug$T,"dr" | |
| 267 | 	.p2align	2 | |
| 268 | 	.long	4 # Debug section magic | |
| 269 | 	# Pointer (0x1000) { | |
| 270 | 	# TypeLeafKind: LF_POINTER (0x1002) | |
| 271 | 	# PointeeType: char* (0x670) | |
| 272 | 	# PtrType: Near64 (0xC) | |
| 273 | 	# PtrMode: Pointer (0x0) | |
| 274 | 	# IsFlat: 0 | |
| 275 | 	# IsConst: 0 | |
| 276 | 	# IsVolatile: 0 | |
| 277 | 	# IsUnaligned: 0 | |
| 278 | 	# IsRestrict: 0 | |
| 279 | 	# IsThisPtr&: 0 | |
| 280 | 	# IsThisPtr&&: 0 | |
| 281 | 	# SizeOf: 8 | |
| 282 | 	# } | |
| 283 | 	.byte	0x0a, 0x00, 0x02, 0x10 | |
| 284 | 	.byte	0x70, 0x06, 0x00, 0x00 | |
| 285 | 	.byte	0x0c, 0x00, 0x01, 0x00 | |
| 286 | 	# ArgList (0x1001) { | |
| 287 | 	# TypeLeafKind: LF_ARGLIST (0x1201) | |
| 288 | 	# NumArgs: 2 | |
| 289 | 	# Arguments [ | |
| 290 | 	# ArgType: int (0x74) | |
| 291 | 	# ArgType: char** (0x1000) | |
| 292 | 	# ] | |
| 293 | 	# } | |
| 294 | 	.byte	0x0e, 0x00, 0x01, 0x12 | |
| 295 | 	.byte	0x02, 0x00, 0x00, 0x00 | |
| 296 | 	.byte	0x74, 0x00, 0x00, 0x00 | |
| 297 | 	.byte	0x00, 0x10, 0x00, 0x00 | |
| 298 | 	# Procedure (0x1002) { | |
| 299 | 	# TypeLeafKind: LF_PROCEDURE (0x1008) | |
| 300 | 	# ReturnType: int (0x74) | |
| 301 | 	# CallingConvention: NearC (0x0) | |
| 302 | 	# FunctionOptions [ (0x0) | |
| 303 | 	# ] | |
| 304 | 	# NumParameters: 2 | |
| 305 | 	# ArgListType: (int, char**) (0x1001) | |
| 306 | 	# } | |
| 307 | 	.byte	0x0e, 0x00, 0x08, 0x10 | |
| 308 | 	.byte	0x74, 0x00, 0x00, 0x00 | |
| 309 | 	.byte	0x00, 0x00, 0x02, 0x00 | |
| 310 | 	.byte	0x01, 0x10, 0x00, 0x00 | |
| 311 | 	# FuncId (0x1003) { | |
| 312 | 	# TypeLeafKind: LF_FUNC_ID (0x1601) | |
| 313 | 	# ParentScope: 0x0 | |
| 314 | 	# FunctionType: int (int, char**) (0x1002) | |
| 315 | 	# Name: main | |
| 316 | 	# } | |
| 317 | 	.byte	0x12, 0x00, 0x01, 0x16 | |
| 318 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 319 | 	.byte	0x02, 0x10, 0x00, 0x00 | |
| 320 | 	.byte	0x6d, 0x61, 0x69, 0x6e | |
| 321 | 	.byte	0x00, 0xf3, 0xf2, 0xf1 | |
| 322 | 	# Struct (0x1004) { | |
| 323 | 	# TypeLeafKind: LF_STRUCTURE (0x1505) | |
| 324 | 	# MemberCount: 0 | |
| 325 | 	# Properties [ (0x280) | |
| 326 | 	# ForwardReference (0x80) | |
| 327 | 	# HasUniqueName (0x200) | |
| 328 | 	# ] | |
| 329 | 	# FieldList: 0x0 | |
| 330 | 	# DerivedFrom: 0x0 | |
| 331 | 	# VShape: 0x0 | |
| 332 | 	# SizeOf: 0 | |
| 333 | 	# Name: Struct | |
| 334 | 	# LinkageName: .?AUStruct@@ | |
| 335 | 	# } | |
| 336 | 	.byte	0x2a, 0x00, 0x05, 0x15 | |
| 337 | 	.byte	0x00, 0x00, 0x80, 0x02 | |
| 338 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 339 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 340 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 341 | 	.byte	0x00, 0x00, 0x53, 0x74 | |
| 342 | 	.byte	0x72, 0x75, 0x63, 0x74 | |
| 343 | 	.byte	0x00, 0x2e, 0x3f, 0x41 | |
| 344 | 	.byte	0x55, 0x53, 0x74, 0x72 | |
| 345 | 	.byte	0x75, 0x63, 0x74, 0x40 | |
| 346 | 	.byte	0x40, 0x00, 0xf2, 0xf1 | |
| 347 | 	# Pointer (0x1005) { | |
| 348 | 	# TypeLeafKind: LF_POINTER (0x1002) | |
| 349 | 	# PointeeType: Struct (0x1004) | |
| 350 | 	# PtrType: Near64 (0xC) | |
| 351 | 	# PtrMode: Pointer (0x0) | |
| 352 | 	# IsFlat: 0 | |
| 353 | 	# IsConst: 0 | |
| 354 | 	# IsVolatile: 0 | |
| 355 | 	# IsUnaligned: 0 | |
| 356 | 	# IsRestrict: 0 | |
| 357 | 	# IsThisPtr&: 0 | |
| 358 | 	# IsThisPtr&&: 0 | |
| 359 | 	# SizeOf: 8 | |
| 360 | 	# } | |
| 361 | 	.byte	0x0a, 0x00, 0x02, 0x10 | |
| 362 | 	.byte	0x04, 0x10, 0x00, 0x00 | |
| 363 | 	.byte	0x0c, 0x00, 0x01, 0x00 | |
| 364 | 	# FieldList (0x1006) { | |
| 365 | 	# TypeLeafKind: LF_FIELDLIST (0x1203) | |
| 366 | 	# DataMember { | |
| 367 | 	# TypeLeafKind: LF_MEMBER (0x150D) | |
| 368 | 	# AccessSpecifier: Public (0x3) | |
| 369 | 	# Type: int (0x74) | |
| 370 | 	# FieldOffset: 0x0 | |
| 371 | 	# Name: x | |
| 372 | 	# } | |
| 373 | 	# } | |
| 374 | 	.byte	0x0e, 0x00, 0x03, 0x12 | |
| 375 | 	.byte	0x0d, 0x15, 0x03, 0x00 | |
| 376 | 	.byte	0x74, 0x00, 0x00, 0x00 | |
| 377 | 	.byte	0x00, 0x00, 0x78, 0x00 | |
| 378 | 	# Struct (0x1007) { | |
| 379 | 	# TypeLeafKind: LF_STRUCTURE (0x1505) | |
| 380 | 	# MemberCount: 1 | |
| 381 | 	# Properties [ (0x200) | |
| 382 | 	# HasUniqueName (0x200) | |
| 383 | 	# ] | |
| 384 | 	# FieldList: <field list> (0x1006) | |
| 385 | 	# DerivedFrom: 0x0 | |
| 386 | 	# VShape: 0x0 | |
| 387 | 	# SizeOf: 4 | |
| 388 | 	# Name: Struct | |
| 389 | 	# LinkageName: .?AUStruct@@ | |
| 390 | 	# } | |
| 391 | 	.byte	0x2a, 0x00, 0x05, 0x15 | |
| 392 | 	.byte	0x01, 0x00, 0x00, 0x02 | |
| 393 | 	.byte	0x06, 0x10, 0x00, 0x00 | |
| 394 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 395 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 396 | 	.byte	0x04, 0x00, 0x53, 0x74 | |
| 397 | 	.byte	0x72, 0x75, 0x63, 0x74 | |
| 398 | 	.byte	0x00, 0x2e, 0x3f, 0x41 | |
| 399 | 	.byte	0x55, 0x53, 0x74, 0x72 | |
| 400 | 	.byte	0x75, 0x63, 0x74, 0x40 | |
| 401 | 	.byte	0x40, 0x00, 0xf2, 0xf1 | |
| 402 | 	# StringId (0x1008) { | |
| 403 | 	# TypeLeafKind: LF_STRING_ID (0x1605) | |
| 404 | 	# Id: 0x0 | |
| 405 | 	# StringData: D:\src\llvmbuild\cl\Debug\x64\foo.cpp | |
| 406 | 	# } | |
| 407 | 	.byte	0x2e, 0x00, 0x05, 0x16 | |
| 408 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 409 | 	.byte	0x44, 0x3a, 0x5c, 0x73 | |
| 410 | 	.byte	0x72, 0x63, 0x5c, 0x6c | |
| 411 | 	.byte	0x6c, 0x76, 0x6d, 0x62 | |
| 412 | 	.byte	0x75, 0x69, 0x6c, 0x64 | |
| 413 | 	.byte	0x5c, 0x63, 0x6c, 0x5c | |
| 414 | 	.byte	0x44, 0x65, 0x62, 0x75 | |
| 415 | 	.byte	0x67, 0x5c, 0x78, 0x36 | |
| 416 | 	.byte	0x34, 0x5c, 0x66, 0x6f | |
| 417 | 	.byte	0x6f, 0x2e, 0x63, 0x70 | |
| 418 | 	.byte	0x70, 0x00, 0xf2, 0xf1 | |
| 419 | 	# UdtSourceLine (0x1009) { | |
| 420 | 	# TypeLeafKind: LF_UDT_SRC_LINE (0x1606) | |
| 421 | 	# UDT: Struct (0x1007) | |
| 422 | 	# SourceFile: D:\src\llvmbuild\cl\Debug\x64\foo.cpp (0x1008) | |
| 423 | 	# LineNumber: 1 | |
| 424 | 	# } | |
| 425 | 	.byte	0x0e, 0x00, 0x06, 0x16 | |
| 426 | 	.byte	0x07, 0x10, 0x00, 0x00 | |
| 427 | 	.byte	0x08, 0x10, 0x00, 0x00 | |
| 428 | 	.byte	0x01, 0x00, 0x00, 0x00 | |
| 429 | 	# StringId (0x100A) { | |
| 430 | 	# TypeLeafKind: LF_STRING_ID (0x1605) | |
| 431 | 	# Id: 0x0 | |
| 432 | 	# StringData: D:\\src\\llvmbuild\\cl\\Debug\\x64 | |
| 433 | 	# } | |
| 434 | 	.byte	0x2a, 0x00, 0x05, 0x16 | |
| 435 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 436 | 	.byte	0x44, 0x3a, 0x5c, 0x5c | |
| 437 | 	.byte	0x73, 0x72, 0x63, 0x5c | |
| 438 | 	.byte	0x5c, 0x6c, 0x6c, 0x76 | |
| 439 | 	.byte	0x6d, 0x62, 0x75, 0x69 | |
| 440 | 	.byte	0x6c, 0x64, 0x5c, 0x5c | |
| 441 | 	.byte	0x63, 0x6c, 0x5c, 0x5c | |
| 442 | 	.byte	0x44, 0x65, 0x62, 0x75 | |
| 443 | 	.byte	0x67, 0x5c, 0x5c, 0x78 | |
| 444 | 	.byte	0x36, 0x34, 0x00, 0xf1 | |
| 445 | 	# StringId (0x100B) { | |
| 446 | 	# TypeLeafKind: LF_STRING_ID (0x1605) | |
| 447 | 	# Id: 0x0 | |
| 448 | 	# StringData: foo.cpp | |
| 449 | 	# } | |
| 450 | 	.byte	0x0e, 0x00, 0x05, 0x16 | |
| 451 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 452 | 	.byte	0x66, 0x6f, 0x6f, 0x2e | |
| 453 | 	.byte	0x63, 0x70, 0x70, 0x00 | |
| 454 | 	# BuildInfo (0x100C) { | |
| 455 | 	# TypeLeafKind: LF_BUILDINFO (0x1603) | |
| 456 | 	# NumArgs: 5 | |
| 457 | 	# Arguments [ | |
| 458 | 	# ArgType: D:\\src\\llvmbuild\\cl\\Debug\\x64 (0x100A) | |
| 459 | 	# ArgType: 0x0 | |
| 460 | 	# ArgType: foo.cpp (0x100B) | |
| 461 | 	# ArgType: 0x0 | |
| 462 | 	# ArgType: 0x0 | |
| 463 | 	# ] | |
| 464 | 	# } | |
| 465 | 	.byte	0x1a, 0x00, 0x03, 0x16 | |
| 466 | 	.byte	0x05, 0x00, 0x0a, 0x10 | |
| 467 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 468 | 	.byte	0x00, 0x00, 0x0b, 0x10 | |
| 469 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 470 | 	.byte	0x00, 0x00, 0x00, 0x00 | |
| 471 | 	.byte	0x00, 0x00, 0xf2, 0xf1 | |
| 472 | ||
| 473 | 	.addrsig | |
| 474 | 	.addrsig_sym "?S@@3UStruct@@A" | |
| 475 | 	.addrsig_sym "?SS@@3UStruct@@A" | |
| 476 | 	.addrsig_sym "?I@@3HA" |
deps/lld/test/COFF/safeseh-md.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -triple i686-windows-msvc %s -filetype=obj -o %t.obj |
| 3 | 3 | # RUN: lld-link %t.obj %S/Inputs/except_handler3.lib -safeseh -out:%t.exe -opt:noref -entry:main |
| 4 | # RUN: llvm-readobj -coff-load-config %t.exe | FileCheck %s | |
| 4 | # RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: SEHTable [ |
| 7 | 7 | # CHECK-NEXT: 0x |
deps/lld/test/COFF/safeseh-no.s created+57| ... | ... | @@ -0,0 +1,57 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -triple i686-windows-msvc %s -filetype=obj -o %t.obj | |
| 3 | # RUN: not lld-link %t.obj -safeseh -out:%t.exe -entry:main 2>&1 | FileCheck %s --check-prefix=ERROR | |
| 4 | # safe seh should be on by default. | |
| 5 | # RUN: not lld-link %t.obj -out:%t.exe -entry:main 2>&1 | FileCheck %s --check-prefix=ERROR | |
| 6 | # RUN: lld-link %t.obj -safeseh:no -out:%t.exe -entry:main | |
| 7 | # RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s | |
| 8 | # -lldmingw should also turn off safeseh by default. | |
| 9 | # RUN: lld-link %t.obj -lldmingw -out:%t.exe -entry:main | |
| 10 | # RUN: llvm-readobj --file-headers --coff-load-config %t.exe | FileCheck %s | |
| 11 | ||
| 12 | # ERROR: /safeseh: {{.*}}safeseh-no.s.tmp.obj is not compatible with SEH | |
| 13 | ||
| 14 | # CHECK: Characteristics [ | |
| 15 | # CHECK-NOT: IMAGE_DLL_CHARACTERISTICS_NO_SEH | |
| 16 | # CHECK: ] | |
| 17 | # CHECK: LoadConfig [ | |
| 18 | # CHECK: Size: 0x48 | |
| 19 | # CHECK: SEHandlerTable: 0x0 | |
| 20 | # CHECK: SEHandlerCount: 0 | |
| 21 | # CHECK: ] | |
| 22 | # CHECK-NOT: SEHTable | |
| 23 | ||
| 24 | ||
| 25 | # Explicitly mark the object as not having safeseh. LLD should error unless | |
| 26 | # -safeseh:no is passed. | |
| 27 | .def @feat.00; .scl 3; .type 0; .endef | |
| 28 | .globl @feat.00 | |
| 29 | @feat.00 = 0 | |
| 30 | ||
| 31 | .def _main; | |
| 32 | .scl 2; | |
| 33 | .type 32; | |
| 34 | .endef | |
| 35 | .section .text,"xr",one_only,_main | |
| 36 | .globl _main | |
| 37 | _main: | |
| 38 | movl $42, %eax | |
| 39 | ret | |
| 40 | ||
| 41 | # Add a handler to create an .sxdata section, which -safeseh:no should ignore. | |
| 42 | .def _my_handler; .scl 3; .type 32; | |
| 43 | .endef | |
| 44 | .section .text,"xr",one_only,_my_handler | |
| 45 | _my_handler: | |
| 46 | ret | |
| 47 | .safeseh _my_handler | |
| 48 | ||
| 49 | ||
| 50 | .section .rdata,"dr" | |
| 51 | .globl __load_config_used | |
| 52 | __load_config_used: | |
| 53 | .long 72 | |
| 54 | .fill 60, 1, 0 | |
| 55 | .long ___safe_se_handler_table | |
| 56 | .long ___safe_se_handler_count | |
| 57 |
deps/lld/test/COFF/safeseh-notable.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -triple i686-windows-msvc %s -filetype=obj -o %t.obj |
| 3 | 3 | # RUN: lld-link %t.obj -safeseh -out:%t.exe -entry:main |
| 4 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s | |
| 4 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # This object lacks a _load_config_used global, so we set |
| 7 | 7 | # IMAGE_DLL_CHARACTERISTICS_NO_SEH even though there is an exception handler. |
deps/lld/test/COFF/safeseh.s+3-3| ... | ... | @@ -1,11 +1,11 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -triple i686-windows-msvc %s -filetype=obj -o %t.obj |
| 3 | 3 | # RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:noref -entry:main |
| 4 | # RUN: llvm-readobj -coff-basereloc -coff-load-config -file-headers %t.exe | FileCheck %s --check-prefix=CHECK-NOGC | |
| 4 | # RUN: llvm-readobj --coff-basereloc --coff-load-config --file-headers %t.exe | FileCheck %s --check-prefix=CHECK-NOGC | |
| 5 | 5 | # RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:noref -entry:main -debug:dwarf |
| 6 | # RUN: llvm-readobj -coff-basereloc -coff-load-config -file-headers %t.exe | FileCheck %s --check-prefix=CHECK-NOGC | |
| 6 | # RUN: llvm-readobj --coff-basereloc --coff-load-config --file-headers %t.exe | FileCheck %s --check-prefix=CHECK-NOGC | |
| 7 | 7 | # RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:ref -entry:main |
| 8 | # RUN: llvm-readobj -coff-basereloc -coff-load-config -file-headers %t.exe | FileCheck %s --check-prefix=CHECK-GC | |
| 8 | # RUN: llvm-readobj --coff-basereloc --coff-load-config --file-headers %t.exe | FileCheck %s --check-prefix=CHECK-GC | |
| 9 | 9 | |
| 10 | 10 | # __safe_se_handler_table needs to be relocated against ImageBase. |
| 11 | 11 | # check that the relocation is present. |
deps/lld/test/COFF/section.test+4-4| ... | ... | @@ -1,19 +1,19 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | 2 | # RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \ |
| 3 | 3 | # RUN: /section:.foo,r %t.obj |
| 4 | # RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=R %s | |
| 4 | # RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=R %s | |
| 5 | 5 | |
| 6 | 6 | # RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \ |
| 7 | 7 | # RUN: /section:.foo,w %t.obj |
| 8 | # RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=W %s | |
| 8 | # RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=W %s | |
| 9 | 9 | |
| 10 | 10 | # RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \ |
| 11 | 11 | # RUN: /section:.foo,e %t.obj |
| 12 | # RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=E %s | |
| 12 | # RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=E %s | |
| 13 | 13 | |
| 14 | 14 | # RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \ |
| 15 | 15 | # RUN: /section:.foo,s %t.obj |
| 16 | # RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=S %s | |
| 16 | # RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=S %s | |
| 17 | 17 | |
| 18 | 18 | # R: Characteristics [ |
| 19 | 19 | # R-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA |
deps/lld/test/COFF/sort-debug.test+5-4| ... | ... | @@ -1,12 +1,12 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | 2 | # RUN: lld-link /debug /out:%t.exe /entry:main %t.obj |
| 3 | # RUN: llvm-readobj -sections %t.exe | FileCheck %s | |
| 3 | # RUN: llvm-readobj --sections %t.exe | FileCheck %s | |
| 4 | 4 | # RUN: lld-link /debug:dwarf /out:%t.exe /entry:main %t.obj |
| 5 | # RUN: llvm-readobj -sections %t.exe | FileCheck %s | |
| 5 | # RUN: llvm-readobj --sections %t.exe | FileCheck %s | |
| 6 | 6 | # RUN: lld-link /out:%t.exe /entry:main %t.obj |
| 7 | # RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=NODEBUG %s | |
| 7 | # RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=NODEBUG %s | |
| 8 | 8 | # RUN: lld-link /debug:symtab /out:%t.exe /entry:main %t.obj |
| 9 | # RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=NODEBUG %s | |
| 9 | # RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=NODEBUG %s | |
| 10 | 10 | |
| 11 | 11 | # CHECK: Name: .text |
| 12 | 12 | # CHECK: Name: .reloc |
| ... | ... | @@ -45,6 +45,7 @@ sections: |
| 45 | 45 | Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] |
| 46 | 46 | Alignment: 4 |
| 47 | 47 | SectionData: '' |
| 48 | SizeOfRawData: 4 | |
| 48 | 49 | - Name: '.debug$S' |
| 49 | 50 | Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] |
| 50 | 51 | Alignment: 1 |
deps/lld/test/COFF/stack.test+5-5| ... | ... | @@ -1,25 +1,25 @@ |
| 1 | 1 | # RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj |
| 2 | 2 | |
| 3 | 3 | # RUN: lld-link /out:%t.exe /entry:main %t.obj |
| 4 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DEFAULT %s | |
| 4 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=DEFAULT %s | |
| 5 | 5 | |
| 6 | 6 | DEFAULT: SizeOfStackReserve: 1048576 |
| 7 | 7 | DEFAULT: SizeOfStackCommit: 4096 |
| 8 | 8 | |
| 9 | 9 | # RUN: lld-link /out:%t.exe /entry:main %t.obj /stack:0x3000 |
| 10 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s | |
| 10 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s | |
| 11 | 11 | # RUN: echo "STACKSIZE 12288" > %t.def |
| 12 | 12 | # RUN: lld-link /out:%t.exe /entry:main /def:%t.def %t.obj |
| 13 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s | |
| 13 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s | |
| 14 | 14 | |
| 15 | 15 | CHECK1: SizeOfStackReserve: 12288 |
| 16 | 16 | CHECK1: SizeOfStackCommit: 4096 |
| 17 | 17 | |
| 18 | 18 | # RUN: lld-link /out:%t.exe /entry:main %t.obj /stack:0x5000,0x3000 |
| 19 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s | |
| 19 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s | |
| 20 | 20 | # RUN: echo "STACKSIZE 20480,12288" > %t.def |
| 21 | 21 | # RUN: lld-link /out:%t.exe /entry:main /def:%t.def %t.obj |
| 22 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s | |
| 22 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s | |
| 23 | 23 | |
| 24 | 24 | CHECK2: SizeOfStackReserve: 20480 |
| 25 | 25 | CHECK2: SizeOfStackCommit: 12288 |
deps/lld/test/COFF/strtab-size.s+2-2| ... | ... | @@ -12,8 +12,8 @@ |
| 12 | 12 | # output SymbolCount: 0 (and dumpbin.exe would error out with "invalid file |
| 13 | 13 | # or disk full, cannot seek to 0x1602"). |
| 14 | 14 | |
| 15 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s | |
| 16 | # CHECK: SymbolCount: 199 | |
| 15 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck %s | |
| 16 | # CHECK: SymbolCount: 197 | |
| 17 | 17 | |
| 18 | 18 | .global main |
| 19 | 19 | .text |
deps/lld/test/COFF/subsystem-drectve.test+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | # RUN: lld-link /dll /noentry /out:%t.dll %t.obj | |
| 3 | # RUN: llvm-readobj -file-headers %t.dll | FileCheck %s | |
| 2 | # RUN: lld-link -safeseh:no /dll /noentry /out:%t.dll %t.obj | |
| 3 | # RUN: llvm-readobj --file-headers %t.dll | FileCheck %s | |
| 4 | 4 | |
| 5 | 5 | # CHECK: MajorOperatingSystemVersion: 42 |
| 6 | 6 | # CHECK: MinorOperatingSystemVersion: 43 |
deps/lld/test/COFF/subsystem-inference-mingw.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.o |
| 3 | 3 | |
| 4 | 4 | # RUN: lld-link -lldmingw %t.o -out:%t.exe |
| 5 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s | |
| 5 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: AddressOfEntryPoint: 0x1001 |
| 8 | 8 | # CHECK: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3) |
deps/lld/test/COFF/subsystem-inference.test+8-4| ... | ... | @@ -1,18 +1,22 @@ |
| 1 | 1 | # RUN: sed -e s/ENTRYNAME/main/ %s | yaml2obj > %t.obj |
| 2 | 2 | # RUN: lld-link /out:%t.exe %t.obj |
| 3 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=MAIN %s | |
| 3 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=MAIN %s | |
| 4 | # RUN: lld-link /out:%t.exe %t.obj /subsystem:default,6.0 | |
| 5 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=MAIN %s | |
| 4 | 6 | |
| 5 | 7 | # RUN: sed s/ENTRYNAME/wmain/ %s | yaml2obj > %t.obj |
| 6 | 8 | # RUN: lld-link /out:%t.exe %t.obj |
| 7 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WMAIN %s | |
| 9 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=WMAIN %s | |
| 8 | 10 | |
| 9 | 11 | # RUN: sed s/ENTRYNAME/WinMain/ %s | yaml2obj > %t.obj |
| 10 | 12 | # RUN: lld-link /out:%t.exe %t.obj |
| 11 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WINMAIN %s | |
| 13 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=WINMAIN %s | |
| 14 | # RUN: lld-link /out:%t.exe %t.obj /subsystem:default,6.0 | |
| 15 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=WINMAIN %s | |
| 12 | 16 | |
| 13 | 17 | # RUN: sed s/ENTRYNAME/wWinMain/ %s | yaml2obj > %t.obj |
| 14 | 18 | # RUN: lld-link /out:%t.exe %t.obj |
| 15 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WWINMAIN %s | |
| 19 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=WWINMAIN %s | |
| 16 | 20 | |
| 17 | 21 | # MAIN: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI |
| 18 | 22 | # WMAIN: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI |
deps/lld/test/COFF/subsystem-inference2.test+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: yaml2obj %s > %t.obj |
| 2 | 2 | # RUN: lld-link /out:%t.exe %t.obj 2>&1 | FileCheck -check-prefix=WARN %s |
| 3 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s | |
| 3 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck %s | |
| 4 | 4 | |
| 5 | 5 | # WARN: warning: found main and WinMain; defaulting to /subsystem:console |
| 6 | 6 | # CHECK: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI |
deps/lld/test/COFF/subsystem-inference32.test+8-8| ... | ... | @@ -1,18 +1,18 @@ |
| 1 | 1 | # RUN: sed -e s/ENTRYNAME/_main/ %s | yaml2obj > %t.obj |
| 2 | # RUN: lld-link /out:%t.exe %t.obj | |
| 3 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=MAIN %s | |
| 2 | # RUN: lld-link -safeseh:no /out:%t.exe %t.obj | |
| 3 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=MAIN %s | |
| 4 | 4 | |
| 5 | 5 | # RUN: sed s/ENTRYNAME/_wmain/ %s | yaml2obj > %t.obj |
| 6 | # RUN: lld-link /out:%t.exe %t.obj | |
| 7 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WMAIN %s | |
| 6 | # RUN: lld-link -safeseh:no /out:%t.exe %t.obj | |
| 7 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=WMAIN %s | |
| 8 | 8 | |
| 9 | 9 | # RUN: sed s/ENTRYNAME/_WinMain@16/ %s | yaml2obj > %t.obj |
| 10 | # RUN: lld-link /out:%t.exe %t.obj | |
| 11 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WINMAIN %s | |
| 10 | # RUN: lld-link -safeseh:no /out:%t.exe %t.obj | |
| 11 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=WINMAIN %s | |
| 12 | 12 | |
| 13 | 13 | # RUN: sed s/ENTRYNAME/_wWinMain@16/ %s | yaml2obj > %t.obj |
| 14 | # RUN: lld-link /out:%t.exe %t.obj | |
| 15 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WWINMAIN %s | |
| 14 | # RUN: lld-link -safeseh:no /out:%t.exe %t.obj | |
| 15 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=WWINMAIN %s | |
| 16 | 16 | |
| 17 | 17 | # MAIN: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI |
| 18 | 18 | # WMAIN: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI |
deps/lld/test/COFF/subsystem.test+11-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: lld-link /entry:main /out:%t.exe /subsystem:windows \ |
| 2 | 2 | # RUN: %p/Inputs/ret42.obj |
| 3 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s | |
| 3 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s | |
| 4 | 4 | |
| 5 | 5 | CHECK1: MajorOperatingSystemVersion: 6 |
| 6 | 6 | CHECK1: MinorOperatingSystemVersion: 0 |
| ... | ... | @@ -10,10 +10,19 @@ CHECK1: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI |
| 10 | 10 | |
| 11 | 11 | # RUN: lld-link /entry:main /out:%t.exe /subsystem:windows,8.9 \ |
| 12 | 12 | # RUN: %p/Inputs/ret42.obj |
| 13 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s | |
| 13 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s | |
| 14 | 14 | |
| 15 | 15 | CHECK2: MajorOperatingSystemVersion: 8 |
| 16 | 16 | CHECK2: MinorOperatingSystemVersion: 9 |
| 17 | 17 | CHECK2: MajorSubsystemVersion: 8 |
| 18 | 18 | CHECK2: MinorSubsystemVersion: 9 |
| 19 | 19 | CHECK2: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI |
| 20 | ||
| 21 | # RUN: lld-link /entry:main /out:%t.exe /subsystem:default,8.9 \ | |
| 22 | # RUN: %p/Inputs/ret42.obj | |
| 23 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=CHECK3 %s | |
| 24 | ||
| 25 | CHECK3: MajorOperatingSystemVersion: 8 | |
| 26 | CHECK3: MinorOperatingSystemVersion: 9 | |
| 27 | CHECK3: MajorSubsystemVersion: 8 | |
| 28 | CHECK3: MinorSubsystemVersion: 9 |
deps/lld/test/COFF/symtab-gc.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: lld-link -dll -entry:f -out:%t.dll -implib:%t.lib %tobject.obj |
| 5 | 5 | # RUN: llvm-mc -filetype=obj -triple=x86_64-windows-msvc -o %tmain.obj %s |
| 6 | 6 | # RUN: lld-link -entry:main -out:%t.exe -opt:ref -debug:dwarf %tmain.obj %t.lib |
| 7 | # RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s | |
| 7 | # RUN: llvm-readobj --coff-imports %t.exe | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | # CHECK-NOT: Symbol: f |
| 10 | 10 |
deps/lld/test/COFF/symtab.test+4-4| ... | ... | @@ -1,13 +1,13 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | 2 | # RUN: lld-link /debug:dwarf /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib |
| 3 | # RUN: llvm-readobj -symbols %t.exe | FileCheck %s | |
| 3 | # RUN: llvm-readobj --symbols %t.exe | FileCheck %s | |
| 4 | 4 | # RUN: lld-link /debug:dwarf /opt:noref /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib |
| 5 | # RUN: llvm-readobj -symbols %t.exe | FileCheck %s | |
| 5 | # RUN: llvm-readobj --symbols %t.exe | FileCheck %s | |
| 6 | 6 | # RUN: lld-link /debug:symtab /opt:noref /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib |
| 7 | # RUN: llvm-readobj -symbols %t.exe | FileCheck %s | |
| 7 | # RUN: llvm-readobj --symbols %t.exe | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | # RUN: lld-link /debug /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib |
| 10 | # RUN: llvm-readobj -symbols %t.exe | FileCheck -check-prefix=NO %s | |
| 10 | # RUN: llvm-readobj --symbols %t.exe | FileCheck -check-prefix=NO %s | |
| 11 | 11 | |
| 12 | 12 | # CHECK: Symbols [ |
| 13 | 13 | # CHECK-NEXT: Symbol { |
deps/lld/test/COFF/thinlto-archivecollision.ll created+29| ... | ... | @@ -0,0 +1,29 @@ |
| 1 | ; REQUIRES: x86 | |
| 2 | ; RUN: rm -fr %t | |
| 3 | ; RUN: mkdir %t %t/a %t/b | |
| 4 | ; RUN: opt -thinlto-bc -o %t/main.obj %s | |
| 5 | ; RUN: opt -thinlto-bc -o %t/a/bar.obj %S/Inputs/lto-dep.ll | |
| 6 | ; RUN: opt -thinlto-bc -o %t/b/bar.obj %S/Inputs/bar.ll | |
| 7 | ; RUN: llvm-ar crs %t/libbar.lib %t/a/bar.obj %t/b/bar.obj | |
| 8 | ; RUN: lld-link -out:%t/main.exe -entry:main -lldsavetemps \ | |
| 9 | ; RUN: -subsystem:console %t/main.obj %t/libbar.lib | |
| 10 | ; RUN: FileCheck %s < %t/main.exe.resolution.txt | |
| 11 | ||
| 12 | ; CHECK: {{/|\\\\thinlto-archivecollision.ll.tmp/main.obj$}} | |
| 13 | ; CHECK: {{^-r=.*/|\\\\thinlto-archivecollision.ll.tmp/main.obj,main,px$}} | |
| 14 | ; CHECK: {{/|\\\\thinlto-archivecollision.ll.tmp/libbar.libbar.obj[0-9]+$}} | |
| 15 | ; CHECK-NEXT: {{^-r=.*/|\\\\thinlto-archivecollision.ll.tmp/libbar.libbar.obj[0-9]+,foo,p$}} | |
| 16 | ; CHECK-NEXT: {{/|\\\\thinlto-archivecollision.ll.tmp/libbar.libbar.obj[0-9]+$}} | |
| 17 | ; CHECK-NEXT: {{^-r=.*/|\\\\thinlto-archivecollision.ll.tmp/libbar.libbar.obj[0-9]+,bar,p$}} | |
| 18 | ||
| 19 | target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" | |
| 20 | target triple = "x86_64-pc-windows-msvc" | |
| 21 | ||
| 22 | declare void @bar() | |
| 23 | declare void @foo() | |
| 24 | ||
| 25 | define i32 @main() { | |
| 26 | call void @foo() | |
| 27 | call void @bar() | |
| 28 | ret i32 0 | |
| 29 | } |
deps/lld/test/COFF/thinlto-archives.ll+4-4| ... | ... | @@ -13,10 +13,10 @@ |
| 13 | 13 | |
| 14 | 14 | ; CHECK: {{/thinlto-archives/main.obj$}} |
| 15 | 15 | ; CHECK: {{^-r=.*/thinlto-archives/main.obj,main,px$}} |
| 16 | ; CHECK: {{/thinlto-archives/a.libbar.obj$}} | |
| 17 | ; CHECK-NEXT: {{^-r=.*/thinlto-archives/a.libbar.obj,foo,p$}} | |
| 18 | ; CHECK-NEXT: {{/thinlto-archives/b.libbar.obj$}} | |
| 19 | ; CHECK-NEXT: {{^-r=.*/thinlto-archives/b.libbar.obj,bar,p$}} | |
| 16 | ; CHECK: {{/thinlto-archives/a.libbar.obj[0-9]+$}} | |
| 17 | ; CHECK-NEXT: {{^-r=.*/thinlto-archives/a.libbar.obj[0-9]+,foo,p$}} | |
| 18 | ; CHECK-NEXT: {{/thinlto-archives/b.libbar.obj[0-9]+$}} | |
| 19 | ; CHECK-NEXT: {{^-r=.*/thinlto-archives/b.libbar.obj[0-9]+,bar,p$}} | |
| 20 | 20 | |
| 21 | 21 | target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" |
| 22 | 22 | target triple = "x86_64-pc-windows-msvc" |
deps/lld/test/COFF/thinlto-emit-imports.ll created+59| ... | ... | @@ -0,0 +1,59 @@ |
| 1 | ; REQUIRES: x86 | |
| 2 | ||
| 3 | ; Generate summary sections and test lld handling. | |
| 4 | ; RUN: opt -module-summary %s -o %t1.obj | |
| 5 | ; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.obj | |
| 6 | ||
| 7 | ; Include a file with an empty module summary index, to ensure that the expected | |
| 8 | ; output files are created regardless, for a distributed build system. | |
| 9 | ; RUN: opt -module-summary %p/Inputs/thinlto-empty.ll -o %t3.obj | |
| 10 | ||
| 11 | ; Ensure lld generates imports files if requested for distributed backends. | |
| 12 | ; RUN: rm -f %t3.obj.imports %t3.obj.thinlto.bc | |
| 13 | ; RUN: lld-link -entry:main -thinlto-index-only \ | |
| 14 | ; RUN: -thinlto-emit-imports-files %t1.obj %t2.obj %t3.obj -out:%t4.exe | |
| 15 | ||
| 16 | ; The imports file for this module contains the bitcode file for | |
| 17 | ; Inputs/thinlto.ll | |
| 18 | ; RUN: cat %t1.obj.imports | count 1 | |
| 19 | ; RUN: cat %t1.obj.imports | FileCheck %s --check-prefix=IMPORTS1 | |
| 20 | ; IMPORTS1: thinlto-emit-imports.ll.tmp2.obj | |
| 21 | ||
| 22 | ; The imports file for Input/thinlto.ll is empty as it does not import anything. | |
| 23 | ; RUN: cat %t2.obj.imports | count 0 | |
| 24 | ||
| 25 | ; The imports file for Input/thinlto_empty.ll is empty but should exist. | |
| 26 | ; RUN: cat %t3.obj.imports | count 0 | |
| 27 | ||
| 28 | ; The index file should be created even for the input with an empty summary. | |
| 29 | ; RUN: ls %t3.obj.thinlto.bc | |
| 30 | ||
| 31 | ; Ensure lld generates error if unable to write to imports file. | |
| 32 | ; RUN: rm -f %t3.obj.imports | |
| 33 | ; RUN: touch %t3.obj.imports | |
| 34 | ; RUN: chmod 400 %t3.obj.imports | |
| 35 | ; RUN: not lld-link -entry:main -thinlto-index-only \ | |
| 36 | ; RUN: -thinlto-emit-imports-files %t1.obj %t2.obj %t3.obj \ | |
| 37 | ; RUN: -out:%t4.exe 2>&1 | FileCheck %s --check-prefix=ERR | |
| 38 | ; ERR: cannot open {{.*}}3.obj.imports: {{P|p}}ermission denied | |
| 39 | ||
| 40 | ; Ensure lld doesn't generate import files when thinlto-index-only is not enabled | |
| 41 | ; RUN: rm -f %t1.obj.imports | |
| 42 | ; RUN: rm -f %t2.obj.imports | |
| 43 | ; RUN: rm -f %t3.obj.imports | |
| 44 | ; RUN: lld-link -entry:main -thinlto-emit-imports-files \ | |
| 45 | ; RUN: %t1.obj %t2.obj %t3.obj -out:%t4.exe | |
| 46 | ; RUN: not ls %t1.obj.imports | |
| 47 | ; RUN: not ls %t2.obj.imports | |
| 48 | ; RUN: not ls %t3.obj.imports | |
| 49 | ||
| 50 | target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" | |
| 51 | target triple = "x86_64-pc-windows-msvc19.0.24215" | |
| 52 | ||
| 53 | declare void @g(...) | |
| 54 | ||
| 55 | define void @main() { | |
| 56 | entry: | |
| 57 | call void (...) @g() | |
| 58 | ret void | |
| 59 | } |
deps/lld/test/COFF/thinlto-index-only.ll created+52| ... | ... | @@ -0,0 +1,52 @@ |
| 1 | ; REQUIRES: x86 | |
| 2 | ||
| 3 | ; Basic ThinLTO tests. | |
| 4 | ; RUN: opt -thinlto-bc %s -o %t1.obj | |
| 5 | ; RUN: opt -thinlto-bc %p/Inputs/thinlto.ll -o %t2.obj | |
| 6 | ; RUN: opt -thinlto-bc %p/Inputs/thinlto-empty.ll -o %t3.obj | |
| 7 | ||
| 8 | ; Ensure lld generates an index and not a binary if requested. | |
| 9 | ; RUN: rm -f %t4.exe | |
| 10 | ; RUN: lld-link -thinlto-index-only -entry:main %t1.obj %t2.obj -out:%t4.exe | |
| 11 | ; RUN: llvm-bcanalyzer -dump %t1.obj.thinlto.bc | FileCheck %s --check-prefix=BACKEND1 | |
| 12 | ; RUN: llvm-bcanalyzer -dump %t2.obj.thinlto.bc | FileCheck %s --check-prefix=BACKEND2 | |
| 13 | ; RUN: not test -e %t4.exe | |
| 14 | ||
| 15 | ; The backend index for this module contains summaries from itself and | |
| 16 | ; Inputs/thinlto.ll, as it imports from the latter. | |
| 17 | ; BACKEND1: <MODULE_STRTAB_BLOCK | |
| 18 | ; BACKEND1-NEXT: <ENTRY {{.*}} record string = '{{.*}}thinlto-index-only.ll.tmp{{.*}}.obj' | |
| 19 | ; BACKEND1: <ENTRY {{.*}} record string = '{{.*}}thinlto-index-only.ll.tmp{{.*}}.obj' | |
| 20 | ; BACKEND1-NOT: <ENTRY | |
| 21 | ; BACKEND1: </MODULE_STRTAB_BLOCK | |
| 22 | ; BACKEND1: <GLOBALVAL_SUMMARY_BLOCK | |
| 23 | ; BACKEND1: <VERSION | |
| 24 | ; BACKEND1: <FLAGS | |
| 25 | ; BACKEND1: <VALUE_GUID op0={{1|2}} op1={{-5300342847281564238|-2624081020897602054}} | |
| 26 | ; BACKEND1: <VALUE_GUID op0={{1|2}} op1={{-5300342847281564238|-2624081020897602054}} | |
| 27 | ; BACKEND1: <COMBINED | |
| 28 | ; BACKEND1: <COMBINED | |
| 29 | ; BACKEND1: </GLOBALVAL_SUMMARY_BLOCK | |
| 30 | ||
| 31 | ; The backend index for Input/thinlto.ll contains summaries from itself only, | |
| 32 | ; as it does not import anything. | |
| 33 | ; BACKEND2: <MODULE_STRTAB_BLOCK | |
| 34 | ; BACKEND2-NEXT: <ENTRY {{.*}} record string = '{{.*}}thinlto-index-only.ll.tmp2.obj' | |
| 35 | ; BACKEND2-NOT: <ENTRY | |
| 36 | ; BACKEND2: </MODULE_STRTAB_BLOCK | |
| 37 | ; BACKEND2-NEXT: <GLOBALVAL_SUMMARY_BLOCK | |
| 38 | ; BACKEND2-NEXT: <VERSION | |
| 39 | ; BACKEND2-NEXT: <FLAGS | |
| 40 | ; BACKEND2-NEXT: <VALUE_GUID op0=1 op1=-5300342847281564238 | |
| 41 | ; BACKEND2-NEXT: <COMBINED | |
| 42 | ; BACKEND2-NEXT: </GLOBALVAL_SUMMARY_BLOCK | |
| 43 | ||
| 44 | target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" | |
| 45 | target triple = "x86_64-pc-windows-msvc19.0.24215" | |
| 46 | ||
| 47 | declare void @g(...) | |
| 48 | ||
| 49 | define void @main() { | |
| 50 | call void (...) @g() | |
| 51 | ret void | |
| 52 | } |
deps/lld/test/COFF/thinlto-object-suffix-replace.ll created+50| ... | ... | @@ -0,0 +1,50 @@ |
| 1 | ; REQUIRES: x86 | |
| 2 | ||
| 3 | ; Test to make sure the thinlto-object-suffix-replace option is handled | |
| 4 | ; correctly. | |
| 5 | ||
| 6 | ; Generate bitcode file with summary, as well as a minimized bitcode without | |
| 7 | ; the debug metadata for the thin link. | |
| 8 | ; RUN: opt -thinlto-bc %s -thin-link-bitcode-file=%t1.thinlink.bc -o %t1.obj | |
| 9 | ||
| 10 | ; First perform the thin link on the normal bitcode file, and save the | |
| 11 | ; resulting index. | |
| 12 | ; RUN: lld-link -thinlto-index-only -entry:main %t1.obj -out:%t3.exe | |
| 13 | ; RUN: cp %t1.obj.thinlto.bc %t1.obj.thinlto.bc.orig | |
| 14 | ||
| 15 | ; Next perform the thin link on the minimized bitcode file, and compare dump | |
| 16 | ; of the resulting index to the above dump to ensure they are identical. | |
| 17 | ; RUN: rm -f %t1.obj.thinlto.bc | |
| 18 | ; Make sure it isn't inadvertently using the regular bitcode file. | |
| 19 | ; RUN: rm -f %t1.obj | |
| 20 | ; RUN: lld-link -entry:main -thinlto-index-only \ | |
| 21 | ; RUN: -thinlto-object-suffix-replace:".thinlink.bc;.obj" \ | |
| 22 | ; RUN: %t1.thinlink.bc -out:%t3.exe | |
| 23 | ; RUN: diff %t1.obj.thinlto.bc.orig %t1.obj.thinlto.bc | |
| 24 | ||
| 25 | ; Ensure lld generates error if suffix replace option not in 'old;new' format. | |
| 26 | ; RUN: rm -f %t1.obj.thinlto.bc | |
| 27 | ; RUN: not lld-link -entry:main -thinlto-index-only \ | |
| 28 | ; RUN: -thinlto-object-suffix-replace:"abc:def" %t1.thinlink.bc \ | |
| 29 | ; RUN: -out:%t3.exe 2>&1 | FileCheck %s --check-prefix=ERR1 | |
| 30 | ; ERR1: -thinlto-object-suffix-replace: expects 'old;new' format, but got abc:def | |
| 31 | ||
| 32 | ; If filename does not end with old suffix, no suffix change should occur, | |
| 33 | ; so ".thinlto.bc" will simply be appended to the input file name. | |
| 34 | ; RUN: rm -f %t1.thinlink.bc.thinlto.bc | |
| 35 | ; RUN: lld-link -entry:main -thinlto-index-only \ | |
| 36 | ; RUN: -thinlto-object-suffix-replace:".abc;.obj" %t1.thinlink.bc -out:%t3.exe | |
| 37 | ; RUN: ls %t1.thinlink.bc.thinlto.bc | |
| 38 | ||
| 39 | target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" | |
| 40 | target triple = "x86_64-pc-windows-msvc19.0.24215" | |
| 41 | ||
| 42 | define void @main() { | |
| 43 | entry: | |
| 44 | ret void | |
| 45 | } | |
| 46 | ||
| 47 | !llvm.dbg.cu = !{} | |
| 48 | ||
| 49 | !1 = !{i32 2, !"Debug Info Version", i32 3} | |
| 50 | !llvm.module.flags = !{!1} |
deps/lld/test/COFF/thinlto-prefix-replace.ll created+26| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | ; REQUIRES: x86 | |
| 2 | ; Check that changing the output path via thinlto-prefix-replace works | |
| 3 | ; RUN: mkdir -p %t/oldpath | |
| 4 | ; RUN: opt -module-summary %s -o %t/oldpath/t.obj | |
| 5 | ||
| 6 | ; Ensure that there is no existing file at the new path, so we properly | |
| 7 | ; test the creation of the new file there. | |
| 8 | ; RUN: rm -f %t/newpath/t.obj.thinlto.bc | |
| 9 | ; RUN: lld-link -entry:main -thinlto-index-only \ | |
| 10 | ; RUN: -thinlto-prefix-replace:"%t/oldpath/;%t/newpath/" %t/oldpath/t.obj \ | |
| 11 | ; RUN: -out:%t/t.exe | |
| 12 | ; RUN: ls %t/newpath/t.obj.thinlto.bc | |
| 13 | ||
| 14 | ; Ensure that lld errors if prefix replace option is not in 'old;new' format. | |
| 15 | ; RUN: rm -f %t/newpath/t.obj.thinlto.bc | |
| 16 | ; RUN: not lld-link -entry:main -thinlto-index-only \ | |
| 17 | ; RUN: -thinlto-prefix-replace:"abc:def" %t/oldpath/t.obj \ | |
| 18 | ; RUN: -out:%t/t.exe 2>&1 | FileCheck --check-prefix=ERR %s | |
| 19 | ; ERR: -thinlto-prefix-replace: expects 'old;new' format, but got abc:def | |
| 20 | ||
| 21 | target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" | |
| 22 | target triple = "x86_64-pc-windows-msvc19.0.24215" | |
| 23 | ||
| 24 | define void @main() { | |
| 25 | ret void | |
| 26 | } |
deps/lld/test/COFF/timestamp.test+3-3| ... | ... | @@ -3,9 +3,9 @@ RUN: yaml2obj %p/Inputs/generic.yaml > %t.obj |
| 3 | 3 | RUN: lld-link %t.obj /debug /Brepro /entry:main /nodefaultlib /out:%t.1.exe |
| 4 | 4 | RUN: lld-link %t.obj /debug /Brepro /entry:main /nodefaultlib /out:%t.2.exe |
| 5 | 5 | RUN: lld-link %t.obj /debug /timestamp:0 /entry:main /nodefaultlib /out:%t.3.exe |
| 6 | RUN: llvm-readobj -file-headers -coff-debug-directory %t.1.exe | FileCheck %s --check-prefix=HASH | |
| 7 | RUN: llvm-readobj -file-headers -coff-debug-directory %t.2.exe | FileCheck %s --check-prefix=HASH | |
| 8 | RUN: llvm-readobj -file-headers -coff-debug-directory %t.3.exe | FileCheck %s --check-prefix=ZERO | |
| 6 | RUN: llvm-readobj --file-headers --coff-debug-directory %t.1.exe | FileCheck %s --check-prefix=HASH | |
| 7 | RUN: llvm-readobj --file-headers --coff-debug-directory %t.2.exe | FileCheck %s --check-prefix=HASH | |
| 8 | RUN: llvm-readobj --file-headers --coff-debug-directory %t.3.exe | FileCheck %s --check-prefix=ZERO | |
| 9 | 9 | |
| 10 | 10 | HASH: ImageFileHeader { |
| 11 | 11 | HASH: TimeDateStamp: [[STAMP:.*]] |
deps/lld/test/COFF/tls.test+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | 2 | # RUN: lld-link /out:%t.exe /entry:main %t.obj |
| 3 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s | |
| 3 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck %s | |
| 4 | 4 | |
| 5 | 5 | # CHECK: TLSTableRVA: 0x1000 |
| 6 | 6 | # CHECK: TLSTableSize: 0x28 |
deps/lld/test/COFF/tls32.test+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | # RUN: lld-link /out:%t.exe /entry:main %t.obj | |
| 3 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s | |
| 2 | # RUN: lld-link -safeseh:no /out:%t.exe /entry:main %t.obj | |
| 3 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck %s | |
| 4 | 4 | |
| 5 | 5 | # CHECK: TLSTableRVA: 0x1000 |
| 6 | 6 | # CHECK: TLSTableSize: 0x18 |
deps/lld/test/COFF/tls_suffix_sorting.s created+27| ... | ... | @@ -0,0 +1,27 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -triple=x86_64-windows-gnu %S/Inputs/tlssup.s -filetype=obj -o %t.tlssup.o | |
| 4 | # RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.main.o | |
| 5 | ||
| 6 | # RUN: lld-link -lldmingw -entry:main %t.main.o %t.tlssup.o -out:%t.exe | |
| 7 | # RUN: llvm-objdump -s %t.exe | FileCheck %s | |
| 8 | ||
| 9 | # Check that .tls$$foo is sorted after the start marker (aa) and before the | |
| 10 | # end marker (ff). | |
| 11 | ||
| 12 | # CHECK: Contents of section .tls: | |
| 13 | # CHECK: 140004000 aabbff | |
| 14 | ||
| 15 | .text | |
| 16 | .globl main | |
| 17 | main: | |
| 18 | movl _tls_index(%rip), %eax | |
| 19 | movq %gs:88, %rcx | |
| 20 | movq (%rcx,%rax,8), %rax | |
| 21 | movb foo@SECREL32(%rax), %al | |
| 22 | ret | |
| 23 | ||
| 24 | .section .tls$$foo,"dw" | |
| 25 | .linkonce discard | |
| 26 | foo: | |
| 27 | .byte 0xbb |
deps/lld/test/COFF/undefined-symbol-cv.s+3-3| ... | ... | @@ -2,19 +2,19 @@ |
| 2 | 2 | # RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s |
| 3 | 3 | # RUN: not lld-link /out:%t.exe %t.obj 2>&1 | FileCheck %s |
| 4 | 4 | |
| 5 | # CHECK: error: undefined symbol: "int __cdecl foo(void)" (?foo@@YAHXZ) | |
| 5 | # CHECK: error: undefined symbol: int __cdecl foo(void) | |
| 6 | 6 | # CHECK-NEXT: >>> referenced by file1.cpp:1 |
| 7 | 7 | # CHECK-NEXT: >>> {{.*}}.obj:(main) |
| 8 | 8 | # CHECK-NEXT: >>> referenced by file1.cpp:2 |
| 9 | 9 | # CHECK-NEXT: >>> {{.*}}.obj:(main) |
| 10 | 10 | # CHECK-EMPTY: |
| 11 | # CHECK-NEXT: error: undefined symbol: "int __cdecl bar(void)" (?bar@@YAHXZ) | |
| 11 | # CHECK-NEXT: error: undefined symbol: int __cdecl bar(void) | |
| 12 | 12 | # CHECK-NEXT: >>> referenced by file2.cpp:3 |
| 13 | 13 | # CHECK-NEXT: >>> {{.*}}.obj:(main) |
| 14 | 14 | # CHECK-NEXT: >>> referenced by file1.cpp:4 |
| 15 | 15 | # CHECK-NEXT: >>> {{.*}}.obj:(f1) |
| 16 | 16 | # CHECK-EMPTY: |
| 17 | # CHECK-NEXT: error: undefined symbol: "int __cdecl baz(void)" (?baz@@YAHXZ) | |
| 17 | # CHECK-NEXT: error: undefined symbol: int __cdecl baz(void) | |
| 18 | 18 | # CHECK-NEXT: >>> referenced by file1.cpp:5 |
| 19 | 19 | # CHECK-NEXT: >>> {{.*}}.obj:(f2) |
| 20 | 20 |
deps/lld/test/COFF/undefined-symbol-lto.test created+31| ... | ... | @@ -0,0 +1,31 @@ |
| 1 | REQUIRES: x86 | |
| 2 | ||
| 3 | RUN: rm -rf %t && mkdir -p %t && cd %t | |
| 4 | RUN: llvm-as %S/Inputs/undefined-symbol-lto-a.ll -o t.obj | |
| 5 | RUN: llvm-as %S/Inputs/undefined-symbol-lto-b.ll -o b.obj | |
| 6 | RUN: llvm-lib b.obj -out:b.lib | |
| 7 | RUN: not lld-link -entry:main -nodefaultlib t.obj b.lib -subsystem:console 2>&1 | FileCheck %s | |
| 8 | ||
| 9 | CHECK: undefined symbol: main | |
| 10 | CHECK: undefined symbol: void __cdecl undefined_ref(void) | |
| 11 | CHECK: referenced by | |
| 12 | ||
| 13 | Originally reported as PR42536. | |
| 14 | ||
| 15 | a.ll corresponds to this C++: | |
| 16 | ||
| 17 | struct __declspec(dllimport) S { | |
| 18 | virtual void foo(); | |
| 19 | }; | |
| 20 | void undefined_ref(); | |
| 21 | struct Init { | |
| 22 | Init() { undefined_ref(); } | |
| 23 | S c; | |
| 24 | } d; | |
| 25 | ||
| 26 | b.ll is from this C++: | |
| 27 | ||
| 28 | struct S { | |
| 29 | virtual void foo(); | |
| 30 | }; | |
| 31 | void S::foo() {} |
deps/lld/test/COFF/undefined-symbol-multi.s created+47| ... | ... | @@ -0,0 +1,47 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s | |
| 3 | ||
| 4 | # All references to a single undefined symbol count as a single error -- but | |
| 5 | # at most 10 references are printed. | |
| 6 | # RUN: echo ".globl bar" > %t.moreref.s | |
| 7 | # RUN: echo "bar:" >> %t.moreref.s | |
| 8 | # RUN: echo ' call "?foo@@YAHXZ"' >> %t.moreref.s | |
| 9 | # RUN: echo ' call "?foo@@YAHXZ"' >> %t.moreref.s | |
| 10 | # RUN: echo ' call "?foo@@YAHXZ"' >> %t.moreref.s | |
| 11 | # RUN: echo ' call "?foo@@YAHXZ"' >> %t.moreref.s | |
| 12 | # RUN: echo ' call "?foo@@YAHXZ"' >> %t.moreref.s | |
| 13 | # RUN: echo ' call "?foo@@YAHXZ"' >> %t.moreref.s | |
| 14 | # RUN: echo ' call "?foo@@YAHXZ"' >> %t.moreref.s | |
| 15 | # RUN: echo ' call "?foo@@YAHXZ"' >> %t.moreref.s | |
| 16 | # RUN: echo ' call "?foo@@YAHXZ"' >> %t.moreref.s | |
| 17 | # RUN: echo ' call "?foo@@YAHXZ"' >> %t.moreref.s | |
| 18 | # RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t2.obj %t.moreref.s | |
| 19 | # RUN: not lld-link /out:/dev/null %t.obj %t2.obj 2>&1 | FileCheck %s | |
| 20 | ||
| 21 | # CHECK: error: undefined symbol: int __cdecl foo(void) | |
| 22 | # CHECK-NEXT: >>> referenced by {{.*}}tmp.obj:(main) | |
| 23 | # CHECK-NEXT: >>> referenced by {{.*}}tmp.obj:(main) | |
| 24 | # CHECK-NEXT: >>> referenced by {{.*}}tmp2.obj:(bar) | |
| 25 | # CHECK-NEXT: >>> referenced by {{.*}}tmp2.obj:(bar) | |
| 26 | # CHECK-NEXT: >>> referenced by {{.*}}tmp2.obj:(bar) | |
| 27 | # CHECK-NEXT: >>> referenced by {{.*}}tmp2.obj:(bar) | |
| 28 | # CHECK-NEXT: >>> referenced by {{.*}}tmp2.obj:(bar) | |
| 29 | # CHECK-NEXT: >>> referenced by {{.*}}tmp2.obj:(bar) | |
| 30 | # CHECK-NEXT: >>> referenced by {{.*}}tmp2.obj:(bar) | |
| 31 | # CHECK-NEXT: >>> referenced by {{.*}}tmp2.obj:(bar) | |
| 32 | # CHECK-NEXT: >>> referenced 2 more times | |
| 33 | # CHECK-EMPTY: | |
| 34 | # CHECK-NEXT: error: undefined symbol: int __cdecl bar(void) | |
| 35 | # CHECK-NEXT: >>> referenced by {{.*}}.obj:(main) | |
| 36 | # CHECK-NEXT: >>> referenced by {{.*}}.obj:(f1) | |
| 37 | ||
| 38 | .section .text,"xr",one_only,main | |
| 39 | .globl main | |
| 40 | main: | |
| 41 | 	call	"?foo@@YAHXZ" | |
| 42 | 	call	"?foo@@YAHXZ" | |
| 43 | 	call	"?bar@@YAHXZ" | |
| 44 | ||
| 45 | f1: | |
| 46 | 	call	"?bar@@YAHXZ" | |
| 47 | .Lfunc_end1: |
deps/lld/test/COFF/undefined-symbol.s+9-3| ... | ... | @@ -1,16 +1,22 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s |
| 3 | 3 | # RUN: not lld-link /out:%t.exe %t.obj 2>&1 | FileCheck %s |
| 4 | # RUN: not lld-link /out:%t.exe /demangle %t.obj 2>&1 | FileCheck %s | |
| 5 | # RUN: not lld-link /out:%t.exe /demangle:no %t.obj 2>&1 | FileCheck --check-prefix=NODEMANGLE %s | |
| 4 | 6 | |
| 5 | # CHECK: error: undefined symbol: "int __cdecl foo(void)" (?foo@@YAHXZ) | |
| 7 | # NODEMANGLE: error: undefined symbol: ?foo@@YAHXZ | |
| 8 | # NODEMANGLE: error: undefined symbol: ?bar@@YAHXZ | |
| 9 | # NODEMANGLE: error: undefined symbol: __imp_?baz@@YAHXZ | |
| 10 | ||
| 11 | # CHECK: error: undefined symbol: int __cdecl foo(void) | |
| 6 | 12 | # CHECK-NEXT: >>> referenced by {{.*}}.obj:(main) |
| 7 | 13 | # CHECK-NEXT: >>> referenced by {{.*}}.obj:(main) |
| 8 | 14 | # CHECK-EMPTY: |
| 9 | # CHECK-NEXT: error: undefined symbol: "int __cdecl bar(void)" (?bar@@YAHXZ) | |
| 15 | # CHECK-NEXT: error: undefined symbol: int __cdecl bar(void) | |
| 10 | 16 | # CHECK-NEXT: >>> referenced by {{.*}}.obj:(main) |
| 11 | 17 | # CHECK-NEXT: >>> referenced by {{.*}}.obj:(f1) |
| 12 | 18 | # CHECK-EMPTY: |
| 13 | # CHECK-NEXT: error: undefined symbol: "__declspec(dllimport) int __cdecl baz(void)" (__imp_?baz@@YAHXZ) | |
| 19 | # CHECK-NEXT: error: undefined symbol: __declspec(dllimport) int __cdecl baz(void) | |
| 14 | 20 | # CHECK-NEXT: >>> referenced by {{.*}}.obj:(f2) |
| 15 | 21 | |
| 16 | 22 | .section .text,"xr",one_only,main |
deps/lld/test/COFF/unwind.test+2-2| ... | ... | @@ -1,11 +1,11 @@ |
| 1 | 1 | # RUN: yaml2obj < %s > %t.obj |
| 2 | 2 | # |
| 3 | 3 | # RUN: lld-link /out:%t.exe /entry:main %t.obj |
| 4 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s | |
| 4 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=HEADER %s | |
| 5 | 5 | # RUN: llvm-objdump -unwind-info %t.exe | FileCheck -check-prefix=UNWIND %s |
| 6 | 6 | # |
| 7 | 7 | # RUN: lld-link /merge:.pdata=.rdata /out:%t.exe /entry:main %t.obj |
| 8 | # RUN: llvm-readobj -file-headers -sections %t.exe | FileCheck -check-prefix=HEADER-MERGE %s | |
| 8 | # RUN: llvm-readobj --file-headers --sections %t.exe | FileCheck -check-prefix=HEADER-MERGE %s | |
| 9 | 9 | # |
| 10 | 10 | # HEADER: ExceptionTableRVA: 0x3000 |
| 11 | 11 | # |
deps/lld/test/COFF/used-lto.ll created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | ; REQUIRES: x86 | |
| 2 | ; RUN: llvm-as -o %t.obj %s | |
| 3 | ; RUN: lld-link -dll -debug -opt:ref -noentry -out:%t.dll %t.obj | |
| 4 | ; RUN: llvm-pdbutil dump -publics %t.pdb | FileCheck %s | |
| 5 | ||
| 6 | ; CHECK: S_PUB32 {{.*}} `foo` | |
| 7 | ||
| 8 | target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" | |
| 9 | target triple = "x86_64-pc-windows-msvc" | |
| 10 | ||
| 11 | @llvm.used = appending global [1 x i8*] [i8* bitcast (void ()* @foo to i8*)], section "llvm.metadata" | |
| 12 | ||
| 13 | define void @foo() { | |
| 14 | ret void | |
| 15 | } |
deps/lld/test/COFF/version.test+3-3| ... | ... | @@ -1,19 +1,19 @@ |
| 1 | 1 | # RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj |
| 2 | 2 | |
| 3 | 3 | # RUN: lld-link /out:%t.exe /entry:main %t.obj |
| 4 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DEFAULT %s | |
| 4 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=DEFAULT %s | |
| 5 | 5 | |
| 6 | 6 | DEFAULT: MajorImageVersion: 0 |
| 7 | 7 | DEFAULT: MinorImageVersion: 0 |
| 8 | 8 | |
| 9 | 9 | # RUN: lld-link /out:%t.exe /entry:main %t.obj /version:11 |
| 10 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s | |
| 10 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=CHECK1 %s | |
| 11 | 11 | |
| 12 | 12 | CHECK1: MajorImageVersion: 11 |
| 13 | 13 | CHECK1: MinorImageVersion: 0 |
| 14 | 14 | |
| 15 | 15 | # RUN: lld-link /out:%t.exe /entry:main %t.obj /version:11.22 |
| 16 | # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s | |
| 16 | # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=CHECK2 %s | |
| 17 | 17 | |
| 18 | 18 | CHECK2: MajorImageVersion: 11 |
| 19 | 19 | CHECK2: MinorImageVersion: 22 |
deps/lld/test/COFF/wx.s+5-5| ... | ... | @@ -1,15 +1,15 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s |
| 4 | # RUN: not lld-link /out:%t.exe /entry:main -notarealoption /WX %t.obj 2>&1 | \ | |
| 4 | # RUN: not lld-link /out:%t.exe /entry:main -notarealopt=ion /WX %t.obj 2>&1 | \ | |
| 5 | 5 | # RUN: FileCheck -check-prefix=ERROR %s |
| 6 | # RUN: not lld-link /out:%t.exe /entry:main -notarealoption /WX:NO /WX %t.obj 2>&1 | \ | |
| 6 | # RUN: not lld-link /out:%t.exe /entry:main -notarealopt=ion /WX:NO /WX %t.obj 2>&1 | \ | |
| 7 | 7 | # RUN: FileCheck -check-prefix=ERROR %s |
| 8 | # RUN: lld-link /out:%t.exe /entry:main -notarealoption /WX /WX:NO %t.obj 2>&1 | \ | |
| 8 | # RUN: lld-link /out:%t.exe /entry:main -notarealopt=ion /WX /WX:NO %t.obj 2>&1 | \ | |
| 9 | 9 | # RUN: FileCheck -check-prefix=WARNING %s |
| 10 | 10 | |
| 11 | # ERROR: error: ignoring unknown argument: -notarealoption | |
| 12 | # WARNING: warning: ignoring unknown argument: -notarealoption | |
| 11 | # ERROR: error: ignoring unknown argument '-notarealopt=ion' | |
| 12 | # WARNING: warning: ignoring unknown argument '-notarealopt=ion' | |
| 13 | 13 | |
| 14 | 14 | .text |
| 15 | 15 | .global main |
deps/lld/test/ELF/Inputs/aarch64-addrifunc.s created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | .text | |
| 2 | .globl myfunc | |
| 3 | .globl func1 | |
| 4 | .type func1, %function | |
| 5 | func1: | |
| 6 | adrp x8, :got: myfunc | |
| 7 | ldr x8, [x8, :got_lo12: myfunc] | |
| 8 | ret |
deps/lld/test/ELF/Inputs/aarch64-bti1.s created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | .section ".note.gnu.property", "a" | |
| 2 | .long 4 | |
| 3 | .long 0x10 | |
| 4 | .long 0x5 | |
| 5 | .asciz "GNU" | |
| 6 | ||
| 7 | .long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND | |
| 8 | .long 4 | |
| 9 | .long 1 // GNU_PROPERTY_AARCH64_FEATURE_1_BTI | |
| 10 | .long 0 | |
| 11 | ||
| 12 | .text | |
| 13 | .globl func2 | |
| 14 | .type func2,@function | |
| 15 | func2: | |
| 16 | .globl func3 | |
| 17 | .type func3, @function | |
| 18 | bl func3 | |
| 19 | ret |
deps/lld/test/ELF/Inputs/aarch64-btipac1.s created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | .section ".note.gnu.property", "a" | |
| 2 | .long 4 | |
| 3 | .long 0x10 | |
| 4 | .long 0x5 | |
| 5 | .asciz "GNU" | |
| 6 | ||
| 7 | .long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND | |
| 8 | .long 4 | |
| 9 | .long 3 // GNU_PROPERTY_AARCH64_FEATURE_1_PAC and BTI | |
| 10 | .long 0 | |
| 11 | ||
| 12 | .text | |
| 13 | .globl func2 | |
| 14 | .type func2,@function | |
| 15 | func2: | |
| 16 | .globl func3 | |
| 17 | .type func3, @function | |
| 18 | bl func3 | |
| 19 | ret |
deps/lld/test/ELF/Inputs/aarch64-func2.s created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | .text | |
| 2 | .globl func2 | |
| 3 | .type func2,@function | |
| 4 | func2: | |
| 5 | .globl func3 | |
| 6 | .type func3, @function | |
| 7 | bl func3 | |
| 8 | ret |
deps/lld/test/ELF/Inputs/aarch64-func3-bti.s created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | .section ".note.gnu.property", "a" | |
| 2 | .long 4 | |
| 3 | .long 0x10 | |
| 4 | .long 0x5 | |
| 5 | .asciz "GNU" | |
| 6 | ||
| 7 | .long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND | |
| 8 | .long 4 | |
| 9 | .long 1 // GNU_PROPERTY_AARCH64_FEATURE_1_BTI | |
| 10 | .long 0 | |
| 11 | ||
| 12 | .text | |
| 13 | .globl func3 | |
| 14 | .type func3,@function | |
| 15 | func3: | |
| 16 | ret |
deps/lld/test/ELF/Inputs/aarch64-func3-btipac.s created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | .section ".note.gnu.property", "a" | |
| 2 | .long 4 | |
| 3 | .long 0x10 | |
| 4 | .long 0x5 | |
| 5 | .asciz "GNU" | |
| 6 | ||
| 7 | .long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND | |
| 8 | .long 4 | |
| 9 | .long 3 // GNU_PROPERTY_AARCH64_FEATURE_1_PAC | |
| 10 | .long 0 | |
| 11 | ||
| 12 | .text | |
| 13 | .globl func3 | |
| 14 | .type func3,@function | |
| 15 | func3: | |
| 16 | ret |
deps/lld/test/ELF/Inputs/aarch64-func3-pac.s created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | .section ".note.gnu.property", "a" | |
| 2 | .long 4 | |
| 3 | .long 0x10 | |
| 4 | .long 0x5 | |
| 5 | .asciz "GNU" | |
| 6 | ||
| 7 | .long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND | |
| 8 | .long 4 | |
| 9 | .long 2 // GNU_PROPERTY_AARCH64_FEATURE_1_PAC | |
| 10 | .long 0 | |
| 11 | ||
| 12 | .text | |
| 13 | .globl func3 | |
| 14 | .type func3,@function | |
| 15 | func3: | |
| 16 | ret |
deps/lld/test/ELF/Inputs/aarch64-func3.s created+5| ... | ... | @@ -0,0 +1,5 @@ |
| 1 | .text | |
| 2 | .globl func3 | |
| 3 | .type func3,@function | |
| 4 | func3: | |
| 5 | ret |
deps/lld/test/ELF/Inputs/aarch64-nobti.s created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | .text | |
| 2 | .globl func2 | |
| 3 | .type func2,@function | |
| 4 | func2: | |
| 5 | .globl func3 | |
| 6 | .type func3, @function | |
| 7 | bl func3 | |
| 8 | ret |
deps/lld/test/ELF/Inputs/aarch64-nopac.s created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | .text | |
| 2 | .globl func2 | |
| 3 | .type func2,@function | |
| 4 | func2: | |
| 5 | .globl func3 | |
| 6 | .type func3, @function | |
| 7 | bl func3 | |
| 8 | ret |
deps/lld/test/ELF/Inputs/aarch64-pac1.s created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | .section ".note.gnu.property", "a" | |
| 2 | .long 4 | |
| 3 | .long 0x10 | |
| 4 | .long 0x5 | |
| 5 | .asciz "GNU" | |
| 6 | ||
| 7 | .long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND | |
| 8 | .long 4 | |
| 9 | .long 2 // GNU_PROPERTY_AARCH64_FEATURE_1_PAC | |
| 10 | .long 0 | |
| 11 | ||
| 12 | .text | |
| 13 | .globl func2 | |
| 14 | .type func2,@function | |
| 15 | func2: | |
| 16 | .globl func3 | |
| 17 | .type func3, @function | |
| 18 | bl func3 | |
| 19 | ret |
deps/lld/test/ELF/Inputs/bad-reloc-target.test deleted-21| ... | ... | @@ -1,21 +0,0 @@ |
| 1 | --- !ELF | |
| 2 | FileHeader: | |
| 3 | Class: ELFCLASS64 | |
| 4 | Data: ELFDATA2LSB | |
| 5 | Type: ET_REL | |
| 6 | Machine: EM_X86_64 | |
| 7 | Sections: | |
| 8 | - Name: .text | |
| 9 | Type: SHT_PROGBITS | |
| 10 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 11 | - Name: .rela.text | |
| 12 | Type: SHT_RELA | |
| 13 | Link: .symtab | |
| 14 | Info: 99 | |
| 15 | Relocations: | |
| 16 | - Offset: 0x0000000000000000 | |
| 17 | Symbol: foo | |
| 18 | Type: R_X86_64_64 | |
| 19 | Symbols: | |
| 20 | Global: | |
| 21 | - Name: foo | |
| \ No newline at end of file |
deps/lld/test/ELF/Inputs/comdat-discarded-reloc.s+7-5| ... | ... | @@ -1,6 +1,8 @@ |
| 1 | .section .text.bar1,"aG",@progbits,group,comdat | |
| 1 | .global bar, _start | |
| 2 | 2 | |
| 3 | .section .text.bar2 | |
| 4 | .global bar | |
| 5 | bar: | |
| 6 | .quad .text.bar1 | |
| 3 | .section .text.foo,"aG",@progbits,group,comdat | |
| 4 | ||
| 5 | .section .text | |
| 6 | _start: | |
| 7 | .quad .text.foo | |
| 8 | .quad bar |
deps/lld/test/ELF/Inputs/deplibs-lib_bar.s created+2| ... | ... | @@ -0,0 +1,2 @@ |
| 1 | .global bar | |
| 2 | bar: |
deps/lld/test/ELF/Inputs/deplibs-lib_foo.s created+2| ... | ... | @@ -0,0 +1,2 @@ |
| 1 | .global foo | |
| 2 | foo: |
deps/lld/test/ELF/Inputs/dtrace-r.o deleted| Binary files a/deps/lld/test/ELF/Inputs/dtrace-r.o and /dev/null differ |
deps/lld/test/ELF/Inputs/dummy-shared.s created+2| ... | ... | @@ -0,0 +1,2 @@ |
| 1 | .globl bar | |
| 2 | bar: |
deps/lld/test/ELF/Inputs/gdb-index-multiple-cu-2.s+1-1| ... | ... | @@ -31,7 +31,7 @@ _start: |
| 31 | 31 | 	.byte	0 |
| 32 | 32 | .Lcu_end0: |
| 33 | 33 | |
| 34 | # .debug_gnu_pubnames has just one set, associated with .Lcu_begin1 (CuIndex: 1) | |
| 34 | # .debug_gnu_pubnames has just one set, associated with .Lcu_begin1 (cuIndex: 1) | |
| 35 | 35 | .section .debug_gnu_pubnames,"",@progbits |
| 36 | 36 | 	.long	.LpubNames_end0 - .LpubNames_begin0 |
| 37 | 37 | .LpubNames_begin0: |
deps/lld/test/ELF/Inputs/gnu-ifunc-canon-ro-abs.s created+2| ... | ... | @@ -0,0 +1,2 @@ |
| 1 | .rodata | |
| 2 | .8byte ifunc |
deps/lld/test/ELF/Inputs/gnu-ifunc-canon-ro-pcrel.s created+2| ... | ... | @@ -0,0 +1,2 @@ |
| 1 | .rodata | |
| 2 | .4byte ifunc - . |
deps/lld/test/ELF/Inputs/gnu-ifunc-canon-rw-addend.s created+2| ... | ... | @@ -0,0 +1,2 @@ |
| 1 | .data | |
| 2 | .8byte ifunc + 1 |
deps/lld/test/ELF/Inputs/i386-cet1.s created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | .section ".note.gnu.property", "a" | |
| 2 | .align 4 | |
| 3 | .long 4 | |
| 4 | .long 12 | |
| 5 | .long 5 | |
| 6 | .asciz "GNU" | |
| 7 | ||
| 8 | .long 0xc0000002 | |
| 9 | .long 4 | |
| 10 | .long 3 | |
| 11 | ||
| 12 | .text | |
| 13 | .globl func2 | |
| 14 | .type func2,@function | |
| 15 | func2: | |
| 16 | ret |
deps/lld/test/ELF/Inputs/i386-cet2.s created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | .section ".note.gnu.property", "a" | |
| 2 | .align 4 | |
| 3 | .long 4 | |
| 4 | .long 24 | |
| 5 | .long 5 | |
| 6 | .asciz "GNU" | |
| 7 | ||
| 8 | .long 0xc0000000 | |
| 9 | .long 4 | |
| 10 | .long 0 | |
| 11 | ||
| 12 | .long 0xc0000002 | |
| 13 | .long 4 | |
| 14 | .long 3 | |
| 15 | ||
| 16 | .text | |
| 17 | .globl func2 | |
| 18 | .type func2,@function | |
| 19 | func2: | |
| 20 | ret |
deps/lld/test/ELF/Inputs/i386-cet3.s created+5| ... | ... | @@ -0,0 +1,5 @@ |
| 1 | .text | |
| 2 | .globl func2 | |
| 3 | .type func2,@function | |
| 4 | func2: | |
| 5 | ret |
deps/lld/test/ELF/Inputs/i386-cet4.s created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | .section ".note.gnu.property", "a" | |
| 2 | .align 4 | |
| 3 | .long 4 | |
| 4 | .long 12 | |
| 5 | .long 5 | |
| 6 | .asciz "GNU" | |
| 7 | ||
| 8 | .long 0xc0000002 | |
| 9 | .long 4 | |
| 10 | .long 0xfffffffd | |
| 11 | ||
| 12 | .text | |
| 13 | .globl func2 | |
| 14 | .type func2,@function | |
| 15 | func2: | |
| 16 | ret |
deps/lld/test/ELF/Inputs/i386-reloc-16-error.s deleted-3| ... | ... | @@ -1,3 +0,0 @@ |
| 1 | .globl foo | |
| 2 | .hidden foo | |
| 3 | foo = 65536 |
deps/lld/test/ELF/Inputs/i386-reloc-16.s deleted-3| ... | ... | @@ -1,3 +0,0 @@ |
| 1 | .globl foo | |
| 2 | .hidden foo | |
| 3 | foo = 0xffff |
deps/lld/test/ELF/Inputs/i386-reloc-8-error.s deleted-3| ... | ... | @@ -1,3 +0,0 @@ |
| 1 | .globl foo | |
| 2 | .hidden foo | |
| 3 | foo = 256 |
deps/lld/test/ELF/Inputs/i386-reloc-8.s deleted-3| ... | ... | @@ -1,3 +0,0 @@ |
| 1 | .globl foo | |
| 2 | .hidden foo | |
| 3 | foo = 0xff |
deps/lld/test/ELF/Inputs/i386-static-tls-model1.s created+9| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | .section ".tdata", "awT", @progbits | |
| 2 | .globl var | |
| 3 | var: | |
| 4 | ||
| 5 | .section .foo, "aw" | |
| 6 | .global _start | |
| 7 | _start: | |
| 8 | movl $var@tpoff, %edx # R_386_TLS_LE_32 | |
| 9 | movl %gs:0, %ecx |
deps/lld/test/ELF/Inputs/i386-static-tls-model2.s created+9| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | .section ".tdata", "awT", @progbits | |
| 2 | .globl var | |
| 3 | var: | |
| 4 | ||
| 5 | .section .foo, "aw" | |
| 6 | .global _start | |
| 7 | _start: | |
| 8 | movl %gs:0, %eax | |
| 9 | addl var@gotntpoff(%ebx), %eax # R_386_TLS_GOTIE |
deps/lld/test/ELF/Inputs/i386-static-tls-model3.s created+9| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | .section ".tdata", "awT", @progbits | |
| 2 | .globl var | |
| 3 | var: | |
| 4 | ||
| 5 | .section .foo, "aw" | |
| 6 | .global _start | |
| 7 | _start: | |
| 8 | movl %gs:0, %eax | |
| 9 | addl var@indntpoff, %eax # R_386_TLS_IE |
deps/lld/test/ELF/Inputs/i386-static-tls-model4.s created+9| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | .section ".tdata", "awT", @progbits | |
| 2 | .globl var | |
| 3 | var: | |
| 4 | ||
| 5 | .section .foo, "aw" | |
| 6 | .global _start | |
| 7 | _start: | |
| 8 | movl %gs:0, %eax | |
| 9 | leal var@ntpoff(%eax), %eax # R_386_TLS_LE |
deps/lld/test/ELF/Inputs/ppc64-sort-small-cm-relocs-input2.s created+23| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | .text | |
| 2 | ||
| 3 | .global set | |
| 4 | .type set,@function | |
| 5 | set: | |
| 6 | .Lgep: | |
| 7 | addis 2, 12, .TOC.-.Lgep@ha | |
| 8 | addi 2, 2, .TOC.-.Lgep@l | |
| 9 | .Llep: | |
| 10 | .localentry	set, .Llep-.Lgep | |
| 11 | addis 5, 2, .LC0@toc@ha | |
| 12 | addis 6, 2, .LC1@toc@ha | |
| 13 | ld 5, .LC0@toc@l(5) | |
| 14 | ld 6, .LC1@toc@l(6) | |
| 15 | stw 3, 0(5) | |
| 16 | stw 4, 0(6) | |
| 17 | blr | |
| 18 | ||
| 19 | .section .toc,"aw",@progbits | |
| 20 | .LC0: | |
| 21 | .tc c[TC],c | |
| 22 | .LC1: | |
| 23 | .tc d[TC],d |
deps/lld/test/ELF/Inputs/ppc64-sort-small-cm-relocs-input3.s created+41| ... | ... | @@ -0,0 +1,41 @@ |
| 1 | .text | |
| 2 | .global getA | |
| 3 | .type getA,@function | |
| 4 | getA: | |
| 5 | .LgepA: | |
| 6 | addis 2, 12, .TOC.-.LgepA@ha | |
| 7 | addi 2, 2, .TOC.-.LgepA@l | |
| 8 | .LlepA: | |
| 9 | .localentry getA, .LlepA-.LgepA | |
| 10 | ld 3, .LC0@toc(2) | |
| 11 | lwa 3, 0(3) | |
| 12 | blr | |
| 13 | ||
| 14 | .global getB | |
| 15 | .type getB,@function | |
| 16 | getB: | |
| 17 | .LgepB: | |
| 18 | addis 2, 12, .TOC.-.LgepB@ha | |
| 19 | addi 2, 2, .TOC.-.LgepB@l | |
| 20 | .LlepB: | |
| 21 | .localentry getB, .LlepB-.LgepB | |
| 22 | ld 3, .LC1@toc(2) | |
| 23 | lwa 3, 0(3) | |
| 24 | blr | |
| 25 | ||
| 26 | .section .toc,"aw",@progbits | |
| 27 | .LC0: | |
| 28 | .tc a[TC],a | |
| 29 | .LConst1: | |
| 30 | .quad 0xa | |
| 31 | .LC1: | |
| 32 | .tc b[TC],b | |
| 33 | .Lconst2: | |
| 34 | .quad 0xaabbccddeeff | |
| 35 | ||
| 36 | .type b,@object | |
| 37 | .data | |
| 38 | .global b | |
| 39 | b: | |
| 40 | .long 22 | |
| 41 | .size b, 4 |
deps/lld/test/ELF/Inputs/ppc64-sort-small-cm-relocs-input4.s created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | .text | |
| 2 | .global getRodata | |
| 3 | .type getRodata,@function | |
| 4 | getRodata: | |
| 5 | .Lgep: | |
| 6 | addis 2, 12, .TOC.-.Lgep@ha | |
| 7 | addi 2, 2, .TOC.-.Lgep@l | |
| 8 | .Llep: | |
| 9 | .localentry getRodata, .Llep-.Lgep | |
| 10 | lwa 3, .LC0@toc(2) | |
| 11 | blr | |
| 12 | ||
| 13 | .section .rodata,"aMS",@progbits,8 | |
| 14 | .quad _start | |
| 15 | ||
| 16 | .section .toc,"aw",@progbits | |
| 17 | .LC0: | |
| 18 | .tc .rodata[TC], .rodata |
deps/lld/test/ELF/Inputs/ppc64-toc-relax-shared.s created+7| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | .data | |
| 2 | ||
| 3 | .type shared,@object | |
| 4 | .globl shared | |
| 5 | shared: | |
| 6 | .long 8 | |
| 7 | .size shared, 4 |
deps/lld/test/ELF/Inputs/ppc64-toc-relax.s created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | .data | |
| 2 | ||
| 3 | .globl default, hidden | |
| 4 | .hidden hidden | |
| 5 | ||
| 6 | default: | |
| 7 | hidden: | |
| 8 | .long 0 | |
| 9 | ||
| 10 | .space 65532 | |
| 11 | ||
| 12 | .globl hidden2 | |
| 13 | .hidden hidden2 | |
| 14 | hidden2: | |
| 15 | .long 0 |
deps/lld/test/ELF/Inputs/print-icf.s+9-9| ... | ... | @@ -1,9 +1,9 @@ |
| 1 | .section .text.f6, "ax" | |
| 2 | f6: | |
| 3 | mov $60, %rax | |
| 4 | mov $42, %rdi | |
| 5 | syscall | |
| 6 | ||
| 7 | .section .text.f7, "ax" | |
| 8 | f7: | |
| 9 | mov $0, %rax | |
| 1 | .section .text.f6, "ax" | |
| 2 | f6: | |
| 3 | mov $60, %rax | |
| 4 | mov $42, %rdi | |
| 5 | syscall | |
| 6 | ||
| 7 | .section .text.f7, "ax" | |
| 8 | f7: | |
| 9 | mov $0, %rax |
deps/lld/test/ELF/Inputs/shf-info-link.test+2-2| ... | ... | @@ -17,5 +17,5 @@ Sections: |
| 17 | 17 | Symbol: foo |
| 18 | 18 | Type: R_X86_64_64 |
| 19 | 19 | Symbols: |
| 20 | Global: | |
| 21 | - Name: foo | |
| 20 | - Name: foo | |
| 21 | Binding: STB_GLOBAL |
deps/lld/test/ELF/Inputs/vs-diagnostics-duplicate2.s created+31| ... | ... | @@ -0,0 +1,31 @@ |
| 1 | .global foo, bar | |
| 2 | ||
| 3 | .text | |
| 4 | foo: | |
| 5 | nop | |
| 6 | ||
| 7 | .file 1 "duplicate2.s" | |
| 8 | .loc 1 20 | |
| 9 | bar: | |
| 10 | nop | |
| 11 | ||
| 12 | .section .debug_abbrev,"",@progbits | |
| 13 | .byte 1 # Abbreviation Code | |
| 14 | .byte 17 # DW_TAG_compile_unit | |
| 15 | .byte 0 # DW_CHILDREN_no | |
| 16 | .byte 16 # DW_AT_stmt_list | |
| 17 | .byte 23 # DW_FORM_sec_offset | |
| 18 | .byte 0 # EOM(1) | |
| 19 | .byte 0 # EOM(2) | |
| 20 | .byte 0 # EOM(3) | |
| 21 | ||
| 22 | .section .debug_info,"",@progbits | |
| 23 | .long .Lend0 - .Lbegin0 # Length of Unit | |
| 24 | .Lbegin0: | |
| 25 | .short 4 # DWARF version number | |
| 26 | .long .debug_abbrev # Offset Into Abbrev. Section | |
| 27 | .byte 8 # Address Size (in bytes) | |
| 28 | .byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit | |
| 29 | .long .debug_line # DW_AT_stmt_list | |
| 30 | .Lend0: | |
| 31 | .section .debug_line,"",@progbits |
deps/lld/test/ELF/Inputs/vs-diagnostics-duplicate3.s created+6| ... | ... | @@ -0,0 +1,6 @@ |
| 1 | .file "duplicate3.s" | |
| 2 | ||
| 3 | .global baz | |
| 4 | .text | |
| 5 | baz: | |
| 6 | nop |
deps/lld/test/ELF/Inputs/x86-64-cet1.s created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | .section ".note.gnu.property", "a" | |
| 2 | .align 4 | |
| 3 | .long 4 | |
| 4 | .long 16 | |
| 5 | .long 5 | |
| 6 | .asciz "GNU" | |
| 7 | ||
| 8 | .long 0xc0000002 | |
| 9 | .long 4 | |
| 10 | .long 3 | |
| 11 | .long 0 | |
| 12 | ||
| 13 | .text | |
| 14 | .globl func2 | |
| 15 | .type func2,@function | |
| 16 | func2: | |
| 17 | ret |
deps/lld/test/ELF/Inputs/x86-64-cet2.s created+22| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | .section ".note.gnu.property", "a" | |
| 2 | .align 4 | |
| 3 | .long 4 | |
| 4 | .long 32 | |
| 5 | .long 5 | |
| 6 | .asciz "GNU" | |
| 7 | ||
| 8 | .long 0xc0000000 | |
| 9 | .long 4 | |
| 10 | .long 0 | |
| 11 | .long 0 | |
| 12 | ||
| 13 | .long 0xc0000002 | |
| 14 | .long 4 | |
| 15 | .long 3 | |
| 16 | .long 0 | |
| 17 | ||
| 18 | .text | |
| 19 | .globl func2 | |
| 20 | .type func2,@function | |
| 21 | func2: | |
| 22 | ret |
deps/lld/test/ELF/Inputs/x86-64-cet3.s created+5| ... | ... | @@ -0,0 +1,5 @@ |
| 1 | .text | |
| 2 | .globl func2 | |
| 3 | .type func2,@function | |
| 4 | func2: | |
| 5 | ret |
deps/lld/test/ELF/Inputs/x86-64-cet4.s created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | .section ".note.gnu.property", "a" | |
| 2 | .align 4 | |
| 3 | .long 4 | |
| 4 | .long 16 | |
| 5 | .long 5 | |
| 6 | .asciz "GNU" | |
| 7 | ||
| 8 | .long 0xc0000002 | |
| 9 | .long 4 | |
| 10 | .long 0xfffffffd | |
| 11 | .long 0 | |
| 12 | ||
| 13 | .text | |
| 14 | .globl func2 | |
| 15 | .type func2,@function | |
| 16 | func2: | |
| 17 | ret |
deps/lld/test/ELF/Inputs/x86-64-pcrel.s created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | .globl foo | |
| 2 | foo: | |
| 3 | ||
| 4 | .word _start - foo | |
| 5 | .fill 14,1,0xcc | |
| 6 | ||
| 7 | .byte _start - foo | |
| 8 | .fill 15,1,0xcc |
deps/lld/test/ELF/Inputs/x86-64-reloc-16-error.s deleted-3| ... | ... | @@ -1,3 +0,0 @@ |
| 1 | .globl foo | |
| 2 | .hidden foo | |
| 3 | foo = 65536 |
deps/lld/test/ELF/Inputs/x86-64-reloc-16.s deleted-3| ... | ... | @@ -1,3 +0,0 @@ |
| 1 | .globl foo | |
| 2 | .hidden foo | |
| 3 | foo = 0x42 |
deps/lld/test/ELF/Inputs/x86-64-reloc-8-error.s deleted-3| ... | ... | @@ -1,3 +0,0 @@ |
| 1 | .globl foo | |
| 2 | .hidden foo | |
| 3 | foo = 256 |
deps/lld/test/ELF/Inputs/x86-64-reloc-8.s deleted-3| ... | ... | @@ -1,3 +0,0 @@ |
| 1 | .globl foo | |
| 2 | .hidden foo | |
| 3 | foo = 0x42 |
deps/lld/test/ELF/aarch64-abs16.s+4-4| ... | ... | @@ -20,8 +20,8 @@ _start: |
| 20 | 20 | // S + A = 0x8000 |
| 21 | 21 | // CHECK-NEXT: 210000 ffff0080 |
| 22 | 22 | |
| 23 | // RUN: not ld.lld %t.o %t255.o -o %t2 2>&1 | FileCheck %s --check-prefix=OVERFLOW1 | |
| 24 | // OVERFLOW1: relocation R_AARCH64_ABS16 out of range: -32769 is not in [-32768, 32767] | |
| 23 | // RUN: not ld.lld %t.o %t255.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=OVERFLOW1 | |
| 24 | // OVERFLOW1: relocation R_AARCH64_ABS16 out of range: -32769 is not in [-32768, 65535] | |
| 25 | 25 | |
| 26 | // RUN: not ld.lld %t.o %t257.o -o %t2 2>&1 | FileCheck %s --check-prefix=OVERFLOW2 | |
| 27 | // OVERFLOW2: relocation R_AARCH64_ABS16 out of range: 65536 is not in [-32768, 32767] | |
| 26 | // RUN: not ld.lld %t.o %t257.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=OVERFLOW2 | |
| 27 | // OVERFLOW2: relocation R_AARCH64_ABS16 out of range: 65536 is not in [-32768, 65535] |
deps/lld/test/ELF/aarch64-abs32-dyn.s created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | # REQUIRES: aarch64 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o | |
| 3 | # RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s | |
| 4 | ||
| 5 | ## Test we don't create R_AARCH64_RELATIVE. | |
| 6 | ||
| 7 | # CHECK: error: relocation R_AARCH64_ABS32 cannot be used against symbol hidden; recompile with -fPIC | |
| 8 | ||
| 9 | .globl hidden | |
| 10 | .hidden hidden | |
| 11 | hidden: | |
| 12 | ||
| 13 | .data | |
| 14 | .long hidden |
deps/lld/test/ELF/aarch64-abs32.s+4-4| ... | ... | @@ -20,8 +20,8 @@ _start: |
| 20 | 20 | // S + A = 0x80000000 |
| 21 | 21 | // CHECK-NEXT: 210000 ffffffff 00000080 |
| 22 | 22 | |
| 23 | // RUN: not ld.lld %t.o %t255.o -o %t2 2>&1 | FileCheck %s --check-prefix=OVERFLOW1 | |
| 24 | // OVERFLOW1: relocation R_AARCH64_ABS32 out of range: -2147483649 is not in [-2147483648, 2147483647] | |
| 23 | // RUN: not ld.lld %t.o %t255.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=OVERFLOW1 | |
| 24 | // OVERFLOW1: relocation R_AARCH64_ABS32 out of range: -2147483649 is not in [-2147483648, 4294967295] | |
| 25 | 25 | |
| 26 | // RUN: not ld.lld %t.o %t257.o -o %t2 2>&1 | FileCheck %s --check-prefix=OVERFLOW2 | |
| 27 | // OVERFLOW2: relocation R_AARCH64_ABS32 out of range: 4294967296 is not in [-2147483648, 2147483647] | |
| 26 | // RUN: not ld.lld %t.o %t257.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=OVERFLOW2 | |
| 27 | // OVERFLOW2: relocation R_AARCH64_ABS32 out of range: 4294967296 is not in [-2147483648, 4294967295] |
deps/lld/test/ELF/aarch64-abs64-dyn.s+1-1| ... | ... | @@ -14,7 +14,7 @@ bar: |
| 14 | 14 | .xword bar |
| 15 | 15 | |
| 16 | 16 | // RUN: ld.lld -shared -o %t.so %t.o |
| 17 | // RUN: llvm-readobj -symbols -dyn-relocations %t.so | FileCheck %s | |
| 17 | // RUN: llvm-readobj --symbols --dyn-relocations %t.so | FileCheck %s | |
| 18 | 18 | |
| 19 | 19 | // CHECK: Dynamic Relocations { |
| 20 | 20 | // CHECK-NEXT: {{.*}} R_AARCH64_RELATIVE - [[BAR_ADDR:.*]] |
deps/lld/test/ELF/aarch64-bti-pac-cli-error.s created+12| ... | ... | @@ -0,0 +1,12 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc --triple=x86_64-pc-linux --filetype=obj -o %t.o %s | |
| 3 | # RUN: not ld.lld --pac-plt --force-bti %t.o -o %t 2>&1 | FileCheck %s | |
| 4 | # | |
| 5 | ## Check that we error if --pac-plt and --force-bti are used when target is not | |
| 6 | ## aarch64 | |
| 7 | ||
| 8 | # CHECK: error: --pac-plt only supported on AArch64 | |
| 9 | # CHECK-NEXT: error: --force-bti only supported on AArch64 | |
| 10 | ||
| 11 | .globl start | |
| 12 | start: ret |
deps/lld/test/ELF/aarch64-call26-thunk.s+1| ... | ... | @@ -10,6 +10,7 @@ _start: |
| 10 | 10 | bl big |
| 11 | 11 | |
| 12 | 12 | // CHECK: Disassembly of section .text: |
| 13 | // CHECK-EMPTY: | |
| 13 | 14 | // CHECK-NEXT: _start: |
| 14 | 15 | // CHECK-NEXT: 210000: 02 00 00 94 bl #8 |
| 15 | 16 | // CHECK: __AArch64AbsLongThunk_big: |
deps/lld/test/ELF/aarch64-condb-reloc.s+14-10| ... | ... | @@ -5,12 +5,13 @@ |
| 5 | 5 | # RUN: llvm-objdump -d %t | FileCheck %s |
| 6 | 6 | # RUN: ld.lld -shared %t1 %t2 -o %t3 |
| 7 | 7 | # RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=DSO %s |
| 8 | # RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s | |
| 8 | # RUN: llvm-readobj -S -r %t3 | FileCheck -check-prefix=DSOREL %s | |
| 9 | 9 | |
| 10 | 10 | # 0x11024 - 36 = 0x11000 |
| 11 | 11 | # 0x11028 - 24 = 0x11010 |
| 12 | 12 | # 0x1102c - 16 = 0x1101c |
| 13 | 13 | # CHECK: Disassembly of section .text: |
| 14 | # CHECK-EMPTY: | |
| 14 | 15 | # CHECK-NEXT: _foo: |
| 15 | 16 | # CHECK-NEXT: 210000: {{.*}} nop |
| 16 | 17 | # CHECK-NEXT: 210004: {{.*}} nop |
| ... | ... | @@ -36,8 +37,8 @@ |
| 36 | 37 | #DSOREL-NEXT: SHF_ALLOC |
| 37 | 38 | #DSOREL-NEXT: SHF_WRITE |
| 38 | 39 | #DSOREL-NEXT: ] |
| 39 | #DSOREL-NEXT: Address: 0x20000 | |
| 40 | #DSOREL-NEXT: Offset: 0x20000 | |
| 40 | #DSOREL-NEXT: Address: 0x30000 | |
| 41 | #DSOREL-NEXT: Offset: 0x30000 | |
| 41 | 42 | #DSOREL-NEXT: Size: 48 |
| 42 | 43 | #DSOREL-NEXT: Link: 0 |
| 43 | 44 | #DSOREL-NEXT: Info: 0 |
| ... | ... | @@ -46,13 +47,14 @@ |
| 46 | 47 | #DSOREL-NEXT: } |
| 47 | 48 | #DSOREL: Relocations [ |
| 48 | 49 | #DSOREL-NEXT: Section ({{.*}}) .rela.plt { |
| 49 | #DSOREL-NEXT: 0x20018 R_AARCH64_JUMP_SLOT _foo | |
| 50 | #DSOREL-NEXT: 0x20020 R_AARCH64_JUMP_SLOT _bar | |
| 51 | #DSOREL-NEXT: 0x20028 R_AARCH64_JUMP_SLOT _dah | |
| 50 | #DSOREL-NEXT: 0x30018 R_AARCH64_JUMP_SLOT _foo | |
| 51 | #DSOREL-NEXT: 0x30020 R_AARCH64_JUMP_SLOT _bar | |
| 52 | #DSOREL-NEXT: 0x30028 R_AARCH64_JUMP_SLOT _dah | |
| 52 | 53 | #DSOREL-NEXT: } |
| 53 | 54 | #DSOREL-NEXT:] |
| 54 | 55 | |
| 55 | 56 | #DSO: Disassembly of section .text: |
| 57 | #DSO-EMPTY: | |
| 56 | 58 | #DSO-NEXT: _foo: |
| 57 | 59 | #DSO-NEXT: 10000: {{.*}} nop |
| 58 | 60 | #DSO-NEXT: 10004: {{.*}} nop |
| ... | ... | @@ -69,10 +71,12 @@ |
| 69 | 71 | #DSO-NEXT: 10024: {{.*}} b.eq #44 |
| 70 | 72 | #DSO-NEXT: 10028: {{.*}} b.eq #56 |
| 71 | 73 | #DSO-NEXT: 1002c: {{.*}} b.eq #68 |
| 74 | #DSO-EMPTY: | |
| 72 | 75 | #DSO-NEXT: Disassembly of section .plt: |
| 76 | #DSO-EMPTY: | |
| 73 | 77 | #DSO-NEXT: .plt: |
| 74 | 78 | #DSO-NEXT: 10030: {{.*}} stp x16, x30, [sp, #-16]! |
| 75 | #DSO-NEXT: 10034: {{.*}} adrp x16, #65536 | |
| 79 | #DSO-NEXT: 10034: {{.*}} adrp x16, #131072 | |
| 76 | 80 | #DSO-NEXT: 10038: {{.*}} ldr x17, [x16, #16] |
| 77 | 81 | #DSO-NEXT: 1003c: {{.*}} add x16, x16, #16 |
| 78 | 82 | #DSO-NEXT: 10040: {{.*}} br x17 |
| ... | ... | @@ -81,19 +85,19 @@ |
| 81 | 85 | #DSO-NEXT: 1004c: {{.*}} nop |
| 82 | 86 | #DSO-EMPTY: |
| 83 | 87 | #DSO-NEXT: _foo@plt: |
| 84 | #DSO-NEXT: 10050: {{.*}} adrp x16, #65536 | |
| 88 | #DSO-NEXT: 10050: {{.*}} adrp x16, #131072 | |
| 85 | 89 | #DSO-NEXT: 10054: {{.*}} ldr x17, [x16, #24] |
| 86 | 90 | #DSO-NEXT: 10058: {{.*}} add x16, x16, #24 |
| 87 | 91 | #DSO-NEXT: 1005c: {{.*}} br x17 |
| 88 | 92 | #DSO-EMPTY: |
| 89 | 93 | #DSO-NEXT: _bar@plt: |
| 90 | #DSO-NEXT: 10060: {{.*}} adrp x16, #65536 | |
| 94 | #DSO-NEXT: 10060: {{.*}} adrp x16, #131072 | |
| 91 | 95 | #DSO-NEXT: 10064: {{.*}} ldr x17, [x16, #32] |
| 92 | 96 | #DSO-NEXT: 10068: {{.*}} add x16, x16, #32 |
| 93 | 97 | #DSO-NEXT: 1006c: {{.*}} br x17 |
| 94 | 98 | #DSO-EMPTY: |
| 95 | 99 | #DSO-NEXT: _dah@plt: |
| 96 | #DSO-NEXT: 10070: {{.*}} adrp x16, #65536 | |
| 100 | #DSO-NEXT: 10070: {{.*}} adrp x16, #131072 | |
| 97 | 101 | #DSO-NEXT: 10074: {{.*}} ldr x17, [x16, #40] |
| 98 | 102 | #DSO-NEXT: 10078: {{.*}} add x16, x16, #40 |
| 99 | 103 | #DSO-NEXT: 1007c: {{.*}} br x17 |
deps/lld/test/ELF/aarch64-copy.s+3-2| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %p/Inputs/relocation-copy.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld -shared %t2.o -soname fixed-length-string.so -o %t2.so |
| 5 | 5 | // RUN: ld.lld %t.o %t2.so -o %t3 |
| 6 | // RUN: llvm-readobj -s -r --expand-relocs -symbols %t3 | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S -r --expand-relocs --symbols %t3 | FileCheck %s | |
| 7 | 7 | // RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=CODE %s |
| 8 | 8 | // RUN: llvm-objdump -s -section=.rodata %t3 | FileCheck -check-prefix=RODATA %s |
| 9 | 9 | |
| ... | ... | @@ -77,6 +77,7 @@ _start: |
| 77 | 77 | // CHECK: ] |
| 78 | 78 | |
| 79 | 79 | // CODE: Disassembly of section .text: |
| 80 | // CODE-EMPTY: | |
| 80 | 81 | // CODE-NEXT: _start: |
| 81 | 82 | // S(x) = 0x230000, A = 0, P = 0x210000 |
| 82 | 83 | // S + A - P = 0x20000 = 131072 |
| ... | ... | @@ -90,4 +91,4 @@ _start: |
| 90 | 91 | |
| 91 | 92 | // RODATA: Contents of section .rodata: |
| 92 | 93 | // S(z) = 0x230014 |
| 93 | // RODATA-NEXT: 2002e0 14002300 | |
| 94 | // RODATA-NEXT: 200318 14002300 |
deps/lld/test/ELF/aarch64-copy2.s deleted-27| ... | ... | @@ -1,27 +0,0 @@ |
| 1 | // REQUIRES: aarch64 | |
| 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=aarch64-pc-linux | |
| 3 | // RUN: llvm-mc %p/Inputs/aarch64-copy2.s -o %t2.o -filetype=obj -triple=aarch64-pc-linux | |
| 4 | // RUN: ld.lld %t2.o -o %t2.so -shared | |
| 5 | // RUN: ld.lld %t.o %t2.so -o %t | |
| 6 | // RUN: llvm-readobj -t %t | FileCheck %s | |
| 7 | ||
| 8 | .global _start | |
| 9 | _start: | |
| 10 | adrp x8, foo | |
| 11 | bl bar | |
| 12 | ||
| 13 | // CHECK: Name: bar | |
| 14 | // CHECK-NEXT: Value: 0x0 | |
| 15 | // CHECK-NEXT: Size: 0 | |
| 16 | // CHECK-NEXT: Binding: Global | |
| 17 | // CHECK-NEXT: Type: None | |
| 18 | // CHECK-NEXT: Other: 0 | |
| 19 | // CHECK-NEXT: Section: Undefined | |
| 20 | ||
| 21 | // CHECK: Name: foo | |
| 22 | // CHECK-NEXT: Value: 0x210030 | |
| 23 | // CHECK-NEXT: Size: 0 | |
| 24 | // CHECK-NEXT: Binding: Global | |
| 25 | // CHECK-NEXT: Type: Function | |
| 26 | // CHECK-NEXT: Other: 0 | |
| 27 | // CHECK-NEXT: Section: Undefined |
deps/lld/test/ELF/aarch64-cortex-a53-843419-large.s+3-3| ... | ... | @@ -42,7 +42,7 @@ t3_ff8_ldr: |
| 42 | 42 | ret |
| 43 | 43 | |
| 44 | 44 | // CHECK3: t3_ff8_ldr: |
| 45 | // CHECK3-NEXT: 211ff8: 60 00 04 f0 adrp x0, #134279168 | |
| 45 | // CHECK3-NEXT: 211ff8: e0 00 04 f0 adrp x0, #134344704 | |
| 46 | 46 | // CHECK3-NEXT: 211ffc: 21 00 40 f9 ldr x1, [x1] |
| 47 | 47 | // CHECK3-NEXT: 212000: 02 08 80 15 b #100671496 |
| 48 | 48 | // CHECK3-NEXT: 212004: c0 03 5f d6 ret |
| ... | ... | @@ -63,7 +63,7 @@ t3_ff8_str: |
| 63 | 63 | ret |
| 64 | 64 | |
| 65 | 65 | // CHECK4: t3_ff8_str: |
| 66 | // CHECK4-NEXT: 4213ff8: 60 00 02 b0 adrp x0, #67162112 | |
| 66 | // CHECK4-NEXT: 4213ff8: e0 00 02 b0 adrp x0, #67227648 | |
| 67 | 67 | // CHECK4-NEXT: 4213ffc: 21 00 40 f9 ldr x1, [x1] |
| 68 | 68 | // CHECK4-NEXT: 4214000: 04 00 80 14 b #33554448 |
| 69 | 69 | // CHECK4-NEXT: 4214004: c0 03 5f d6 ret |
| ... | ... | @@ -102,7 +102,7 @@ t3_ffc_ldr: |
| 102 | 102 | ret |
| 103 | 103 | |
| 104 | 104 | // CHECK7: t3_ffc_ldr: |
| 105 | // CHECK7-NEXT: 8211ffc: 60 00 00 f0 adrp x0, #61440 | |
| 105 | // CHECK7-NEXT: 8211ffc: e0 00 00 f0 adrp x0, #126976 | |
| 106 | 106 | // CHECK7-NEXT: 8212000: 21 00 40 f9 ldr x1, [x1] |
| 107 | 107 | // CHECK7-NEXT: 8212004: 02 00 00 14 b #8 |
| 108 | 108 | // CHECK7-NEXT: 8212008: c0 03 5f d6 ret |
deps/lld/test/ELF/aarch64-cortex-a53-843419-recognize.s+26-26| ... | ... | @@ -28,7 +28,7 @@ |
| 28 | 28 | |
| 29 | 29 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 211FF8 in unpatched output. |
| 30 | 30 | // CHECK: t3_ff8_ldr: |
| 31 | // CHECK-NEXT: 211ff8: e0 01 00 f0 adrp x0, #258048 | |
| 31 | // CHECK-NEXT: 211ff8: 60 02 00 f0 adrp x0, #323584 | |
| 32 | 32 | // CHECK-NEXT: 211ffc: 21 00 40 f9 ldr x1, [x1] |
| 33 | 33 | // CHECK-FIX: 212000: 03 c8 00 14 b #204812 |
| 34 | 34 | // CHECK-NOFIX: 212000: 00 00 40 f9 ldr x0, [x0] |
| ... | ... | @@ -46,7 +46,7 @@ t3_ff8_ldr: |
| 46 | 46 | |
| 47 | 47 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 213FF8 in unpatched output. |
| 48 | 48 | // CHECK: t3_ff8_ldrsimd: |
| 49 | // CHECK-NEXT: 213ff8: e0 01 00 b0 adrp x0, #249856 | |
| 49 | // CHECK-NEXT: 213ff8: 60 02 00 b0 adrp x0, #315392 | |
| 50 | 50 | // CHECK-NEXT: 213ffc: 21 00 40 bd ldr s1, [x1] |
| 51 | 51 | // CHECK-FIX: 214000: 05 c0 00 14 b #196628 |
| 52 | 52 | // CHECK-NOFIX: 214000: 02 04 40 f9 ldr x2, [x0, #8] |
| ... | ... | @@ -64,7 +64,7 @@ t3_ff8_ldrsimd: |
| 64 | 64 | |
| 65 | 65 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 215FFC in unpatched output. |
| 66 | 66 | // CHECK: t3_ffc_ldrpost: |
| 67 | // CHECK-NEXT: 215ffc: c0 01 00 f0 adrp x0, #241664 | |
| 67 | // CHECK-NEXT: 215ffc: 40 02 00 f0 adrp x0, #307200 | |
| 68 | 68 | // CHECK-NEXT: 216000: 21 84 40 bc ldr s1, [x1], #8 |
| 69 | 69 | // CHECK-FIX: 216004: 06 b8 00 14 b #188440 |
| 70 | 70 | // CHECK-NOFIX: 216004: 03 08 40 f9 ldr x3, [x0, #16] |
| ... | ... | @@ -82,7 +82,7 @@ t3_ffc_ldrpost: |
| 82 | 82 | |
| 83 | 83 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 217FF8 in unpatched output. |
| 84 | 84 | // CHECK: t3_ff8_strpre: |
| 85 | // CHECK-NEXT: 217ff8: c0 01 00 b0 adrp x0, #233472 | |
| 85 | // CHECK-NEXT: 217ff8: 40 02 00 b0 adrp x0, #299008 | |
| 86 | 86 | // CHECK-NEXT: 217ffc: 21 8c 00 bc str s1, [x1, #8]! |
| 87 | 87 | // CHECK-FIX: 218000: 09 b0 00 14 b #180260 |
| 88 | 88 | // CHECK-NOFIX: 218000: 02 00 40 f9 ldr x2, [x0] |
| ... | ... | @@ -100,7 +100,7 @@ t3_ff8_strpre: |
| 100 | 100 | |
| 101 | 101 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 219FFC in unpatched output. |
| 102 | 102 | // CHECK: t3_ffc_str: |
| 103 | // CHECK-NEXT: 219ffc: bc 01 00 f0 adrp x28, #225280 | |
| 103 | // CHECK-NEXT: 219ffc: 3c 02 00 f0 adrp x28, #290816 | |
| 104 | 104 | // CHECK-NEXT: 21a000: 42 00 00 f9 str x2, [x2] |
| 105 | 105 | // CHECK-FIX: 21a004: 0a a8 00 14 b #172072 |
| 106 | 106 | // CHECK-NOFIX: 21a004: 9c 07 00 f9 str x28, [x28, #8] |
| ... | ... | @@ -118,7 +118,7 @@ t3_ffc_str: |
| 118 | 118 | |
| 119 | 119 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 21BFFC in unpatched output. |
| 120 | 120 | // CHECK: t3_ffc_strsimd: |
| 121 | // CHECK-NEXT: 21bffc: bc 01 00 b0 adrp x28, #217088 | |
| 121 | // CHECK-NEXT: 21bffc: 3c 02 00 b0 adrp x28, #282624 | |
| 122 | 122 | // CHECK-NEXT: 21c000: 44 00 00 b9 str w4, [x2] |
| 123 | 123 | // CHECK-FIX: 21c004: 0c a0 00 14 b #163888 |
| 124 | 124 | // CHECK-NOFIX: 21c004: 84 0b 00 f9 str x4, [x28, #16] |
| ... | ... | @@ -136,7 +136,7 @@ t3_ffc_strsimd: |
| 136 | 136 | |
| 137 | 137 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 21DFF8 in unpatched output. |
| 138 | 138 | // CHECK: t3_ff8_ldrunpriv: |
| 139 | // CHECK-NEXT: 21dff8: 9d 01 00 f0 adrp x29, #208896 | |
| 139 | // CHECK-NEXT: 21dff8: 1d 02 00 f0 adrp x29, #274432 | |
| 140 | 140 | // CHECK-NEXT: 21dffc: 41 08 40 38 ldtrb w1, [x2] |
| 141 | 141 | // CHECK-FIX: 21e000: 0f 98 00 14 b #155708 |
| 142 | 142 | // CHECK-NOFIX: 21e000: bd 03 40 f9 ldr x29, [x29] |
| ... | ... | @@ -154,7 +154,7 @@ t3_ff8_ldrunpriv: |
| 154 | 154 | |
| 155 | 155 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 21FFFC in unpatched output. |
| 156 | 156 | // CHECK: t3_ffc_ldur: |
| 157 | // CHECK-NEXT: 21fffc: 9d 01 00 b0 adrp x29, #200704 | |
| 157 | // CHECK-NEXT: 21fffc: 1d 02 00 b0 adrp x29, #266240 | |
| 158 | 158 | // CHECK-NEXT: 220000: 42 40 40 b8 ldur w2, [x2, #4] |
| 159 | 159 | // CHECK-FIX: 220004: 10 90 00 14 b #147520 |
| 160 | 160 | // CHECK-NOFIX: 220004: bd 07 40 f9 ldr x29, [x29, #8] |
| ... | ... | @@ -171,7 +171,7 @@ t3_ffc_ldur: |
| 171 | 171 | |
| 172 | 172 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 221FFC in unpatched output. |
| 173 | 173 | // CHECK: t3_ffc_sturh: |
| 174 | // CHECK-NEXT: 221ffc: 72 01 00 f0 adrp x18, #192512 | |
| 174 | // CHECK-NEXT: 221ffc: f2 01 00 f0 adrp x18, #258048 | |
| 175 | 175 | // CHECK-NEXT: 222000: 43 40 00 78 sturh w3, [x2, #4] |
| 176 | 176 | // CHECK-FIX: 222004: 12 88 00 14 b #139336 |
| 177 | 177 | // CHECK-NOFIX: 222004: 41 0a 40 f9 ldr x1, [x18, #16] |
| ... | ... | @@ -189,7 +189,7 @@ t3_ffc_sturh: |
| 189 | 189 | |
| 190 | 190 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 223FF8 in unpatched output. |
| 191 | 191 | // CHECK: t3_ff8_literal: |
| 192 | // CHECK-NEXT: 223ff8: 72 01 00 b0 adrp x18, #184320 | |
| 192 | // CHECK-NEXT: 223ff8: f2 01 00 b0 adrp x18, #249856 | |
| 193 | 193 | // CHECK-NEXT: 223ffc: e3 ff ff 58 ldr x3, #-4 |
| 194 | 194 | // CHECK-FIX: 224000: 15 80 00 14 b #131156 |
| 195 | 195 | // CHECK-NOFIX: 224000: 52 02 40 f9 ldr x18, [x18] |
| ... | ... | @@ -207,7 +207,7 @@ t3_ff8_literal: |
| 207 | 207 | |
| 208 | 208 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 225FFC in unpatched output. |
| 209 | 209 | // CHECK: t3_ffc_register: |
| 210 | // CHECK-NEXT: 225ffc: 4f 01 00 f0 adrp x15, #176128 | |
| 210 | // CHECK-NEXT: 225ffc: cf 01 00 f0 adrp x15, #241664 | |
| 211 | 211 | // CHECK-NEXT: 226000: 43 68 61 f8 ldr x3, [x2, x1] |
| 212 | 212 | // CHECK-FIX: 226004: 16 78 00 14 b #122968 |
| 213 | 213 | // CHECK-NOFIX: 226004: ea 05 40 f9 ldr x10, [x15, #8] |
| ... | ... | @@ -225,7 +225,7 @@ t3_ffc_register: |
| 225 | 225 | |
| 226 | 226 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 227FF8 in unpatched output. |
| 227 | 227 | // CHECK: t3_ff8_stp: |
| 228 | // CHECK-NEXT: 227ff8: 50 01 00 b0 adrp x16, #167936 | |
| 228 | // CHECK-NEXT: 227ff8: d0 01 00 b0 adrp x16, #233472 | |
| 229 | 229 | // CHECK-NEXT: 227ffc: 61 08 00 a9 stp x1, x2, [x3] |
| 230 | 230 | // CHECK-FIX: 228000: 19 70 00 14 b #114788 |
| 231 | 231 | // CHECK-NOFIX: 228000: 0d 0a 40 f9 ldr x13, [x16, #16] |
| ... | ... | @@ -243,7 +243,7 @@ t3_ff8_stp: |
| 243 | 243 | |
| 244 | 244 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 229FFC in unpatched output. |
| 245 | 245 | // CHECK: t3_ffc_stnp: |
| 246 | // CHECK-NEXT: 229ffc: 27 01 00 f0 adrp x7, #159744 | |
| 246 | // CHECK-NEXT: 229ffc: a7 01 00 f0 adrp x7, #225280 | |
| 247 | 247 | // CHECK-NEXT: 22a000: 61 08 00 a8 stnp x1, x2, [x3] |
| 248 | 248 | // CHECK-FIX: 22a004: 1a 68 00 14 b #106600 |
| 249 | 249 | // CHECK-NOFIX: 22a004: e9 00 40 f9 ldr x9, [x7] |
| ... | ... | @@ -261,7 +261,7 @@ t3_ffc_stnp: |
| 261 | 261 | |
| 262 | 262 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 22BFFC in unpatched output. |
| 263 | 263 | // CHECK: t3_ffc_st1singlepost: |
| 264 | // CHECK-NEXT: 22bffc: 37 01 00 b0 adrp x23, #151552 | |
| 264 | // CHECK-NEXT: 22bffc: b7 01 00 b0 adrp x23, #217088 | |
| 265 | 265 | // CHECK-NEXT: 22c000: 20 04 82 0d st1 { v0.b }[1], [x1], x2 |
| 266 | 266 | // CHECK-FIX: 22c004: 1c 60 00 14 b #98416 |
| 267 | 267 | // CHECK-NOFIX: 22c004: f6 06 40 f9 ldr x22, [x23, #8] |
| ... | ... | @@ -279,7 +279,7 @@ t3_ffc_st1singlepost: |
| 279 | 279 | |
| 280 | 280 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 22DFF8 in unpatched output. |
| 281 | 281 | // CHECK: t3_ff8_st1multiple: |
| 282 | // CHECK-NEXT: 22dff8: 17 01 00 f0 adrp x23, #143360 | |
| 282 | // CHECK-NEXT: 22dff8: 97 01 00 f0 adrp x23, #208896 | |
| 283 | 283 | // CHECK-NEXT: 22dffc: 20 a0 00 4c st1 { v0.16b, v1.16b }, [x1] |
| 284 | 284 | // CHECK-FIX: 22e000: 1f 58 00 14 b #90236 |
| 285 | 285 | // CHECK-NOFIX: 22e000: f8 0a 40 f9 ldr x24, [x23, #16] |
| ... | ... | @@ -297,7 +297,7 @@ t3_ff8_st1multiple: |
| 297 | 297 | |
| 298 | 298 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 22FFF8 in unpatched output. |
| 299 | 299 | // CHECK: t4_ff8_ldr: |
| 300 | // CHECK-NEXT: 22fff8: 00 01 00 b0 adrp x0, #135168 | |
| 300 | // CHECK-NEXT: 22fff8: 80 01 00 b0 adrp x0, #200704 | |
| 301 | 301 | // CHECK-NEXT: 22fffc: 21 00 40 f9 ldr x1, [x1] |
| 302 | 302 | // CHECK-NEXT: 230000: 42 00 00 8b add x2, x2, x0 |
| 303 | 303 | // CHECK-FIX: 230004: 20 50 00 14 b #82048 |
| ... | ... | @@ -317,7 +317,7 @@ t4_ff8_ldr: |
| 317 | 317 | |
| 318 | 318 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 231FFC in unpatched output. |
| 319 | 319 | // CHECK: t4_ffc_str: |
| 320 | // CHECK-NEXT: 231ffc: fc 00 00 f0 adrp x28, #126976 | |
| 320 | // CHECK-NEXT: 231ffc: 7c 01 00 f0 adrp x28, #192512 | |
| 321 | 321 | // CHECK-NEXT: 232000: 42 00 00 f9 str x2, [x2] |
| 322 | 322 | // CHECK-NEXT: 232004: 20 00 02 cb sub x0, x1, x2 |
| 323 | 323 | // CHECK-FIX: 232008: 21 48 00 14 b #73860 |
| ... | ... | @@ -337,7 +337,7 @@ t4_ffc_str: |
| 337 | 337 | |
| 338 | 338 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 233FF8 in unpatched output. |
| 339 | 339 | // CHECK: t4_ff8_stp: |
| 340 | // CHECK-NEXT: 233ff8: f0 00 00 b0 adrp x16, #118784 | |
| 340 | // CHECK-NEXT: 233ff8: 70 01 00 b0 adrp x16, #184320 | |
| 341 | 341 | // CHECK-NEXT: 233ffc: 61 08 00 a9 stp x1, x2, [x3] |
| 342 | 342 | // CHECK-NEXT: 234000: 03 7e 10 9b mul x3, x16, x16 |
| 343 | 343 | // CHECK-FIX: 234004: 24 40 00 14 b #65680 |
| ... | ... | @@ -357,7 +357,7 @@ t4_ff8_stp: |
| 357 | 357 | |
| 358 | 358 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 235FF8 in unpatched output. |
| 359 | 359 | // CHECK: t4_ff8_stppre: |
| 360 | // CHECK-NEXT: 235ff8: d0 00 00 f0 adrp x16, #110592 | |
| 360 | // CHECK-NEXT: 235ff8: 50 01 00 f0 adrp x16, #176128 | |
| 361 | 361 | // CHECK-NEXT: 235ffc: 61 08 81 a9 stp x1, x2, [x3, #16]! |
| 362 | 362 | // CHECK-NEXT: 236000: 03 7e 10 9b mul x3, x16, x16 |
| 363 | 363 | // CHECK-FIX: 236004: 26 38 00 14 b #57496 |
| ... | ... | @@ -377,7 +377,7 @@ t4_ff8_stppre: |
| 377 | 377 | |
| 378 | 378 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 237FF8 in unpatched output. |
| 379 | 379 | // CHECK: t4_ff8_stppost: |
| 380 | // CHECK-NEXT: 237ff8: d0 00 00 b0 adrp x16, #102400 | |
| 380 | // CHECK-NEXT: 237ff8: 50 01 00 b0 adrp x16, #167936 | |
| 381 | 381 | // CHECK-NEXT: 237ffc: 61 08 81 a8 stp x1, x2, [x3], #16 |
| 382 | 382 | // CHECK-NEXT: 238000: 03 7e 10 9b mul x3, x16, x16 |
| 383 | 383 | // CHECK-FIX: 238004: 28 30 00 14 b #49312 |
| ... | ... | @@ -397,7 +397,7 @@ t4_ff8_stppost: |
| 397 | 397 | |
| 398 | 398 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 239FFC in unpatched output. |
| 399 | 399 | // CHECK: t4_ffc_stpsimd: |
| 400 | // CHECK-NEXT: 239ffc: b0 00 00 f0 adrp x16, #94208 | |
| 400 | // CHECK-NEXT: 239ffc: 30 01 00 f0 adrp x16, #159744 | |
| 401 | 401 | // CHECK-NEXT: 23a000: 61 08 00 ad stp q1, q2, [x3] |
| 402 | 402 | // CHECK-NEXT: 23a004: 03 7e 10 9b mul x3, x16, x16 |
| 403 | 403 | // CHECK-FIX: 23a008: 29 28 00 14 b #41124 |
| ... | ... | @@ -417,7 +417,7 @@ t4_ffc_stpsimd: |
| 417 | 417 | |
| 418 | 418 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 23BFFC in unpatched output. |
| 419 | 419 | // CHECK: t4_ffc_stnp: |
| 420 | // CHECK-NEXT: 23bffc: a7 00 00 b0 adrp x7, #86016 | |
| 420 | // CHECK-NEXT: 23bffc: 27 01 00 b0 adrp x7, #151552 | |
| 421 | 421 | // CHECK-NEXT: 23c000: 61 08 00 a8 stnp x1, x2, [x3] |
| 422 | 422 | // CHECK-NEXT: 23c004: 1f 20 03 d5 nop |
| 423 | 423 | // CHECK-FIX: 23c008: 2b 20 00 14 b #32940 |
| ... | ... | @@ -437,7 +437,7 @@ t4_ffc_stnp: |
| 437 | 437 | |
| 438 | 438 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 23DFFC in unpatched output. |
| 439 | 439 | // CHECK: t4_ffc_st1: |
| 440 | // CHECK-NEXT: 23dffc: 98 00 00 f0 adrp x24, #77824 | |
| 440 | // CHECK-NEXT: 23dffc: 18 01 00 f0 adrp x24, #143360 | |
| 441 | 441 | // CHECK-NEXT: 23e000: 20 80 00 4d st1 { v0.s }[2], [x1] |
| 442 | 442 | // CHECK-NEXT: 23e004: f6 06 40 f9 ldr x22, [x23, #8] |
| 443 | 443 | // CHECK-FIX: 23e008: 2d 18 00 14 b #24756 |
| ... | ... | @@ -457,7 +457,7 @@ t4_ffc_st1: |
| 457 | 457 | |
| 458 | 458 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 23FFF8 in unpatched output. |
| 459 | 459 | // CHECK: t3_ff8_ldr_once: |
| 460 | // CHECK-NEXT: 23fff8: 80 00 00 b0 adrp x0, #69632 | |
| 460 | // CHECK-NEXT: 23fff8: 00 01 00 b0 adrp x0, #135168 | |
| 461 | 461 | // CHECK-NEXT: 23fffc: 20 70 82 4c st1 { v0.16b }, [x1], x2 |
| 462 | 462 | // CHECK-FIX: 240000: 31 10 00 14 b #16580 |
| 463 | 463 | // CHECK-NOFIX: 240000: 01 08 40 f9 ldr x1, [x0, #16] |
| ... | ... | @@ -477,7 +477,7 @@ t3_ff8_ldr_once: |
| 477 | 477 | |
| 478 | 478 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 241FF8 in unpatched output. |
| 479 | 479 | // CHECK: t3_ff8_ldxr: |
| 480 | // CHECK-NEXT: 241ff8: 60 00 00 f0 adrp x0, #61440 | |
| 480 | // CHECK-NEXT: 241ff8: e0 00 00 f0 adrp x0, #126976 | |
| 481 | 481 | // CHECK-NEXT: 241ffc: 03 7c 5f c8 ldxr x3, [x0] |
| 482 | 482 | // CHECK-FIX: 242000: 33 08 00 14 b #8396 |
| 483 | 483 | // CHECK-NOFIX: 242000: 01 08 40 f9 ldr x1, [x0, #16] |
| ... | ... | @@ -497,7 +497,7 @@ t3_ff8_ldxr: |
| 497 | 497 | |
| 498 | 498 | // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 243FF8 in unpatched output. |
| 499 | 499 | // CHECK: t3_ff8_stxr: |
| 500 | // CHECK-NEXT: 243ff8: 60 00 00 b0 adrp x0, #53248 | |
| 500 | // CHECK-NEXT: 243ff8: e0 00 00 b0 adrp x0, #118784 | |
| 501 | 501 | // CHECK-NEXT: 243ffc: 03 7c 04 c8 stxr w4, x3, [x0] |
| 502 | 502 | // CHECK-FIX: 244000: 35 00 00 14 b #212 |
| 503 | 503 | // CHECK-NOFIX: 244000: 01 08 40 f9 ldr x1, [x0, #16] |
deps/lld/test/ELF/aarch64-cortex-a53-843419-thunk.s+1-1| ... | ... | @@ -44,7 +44,7 @@ t3_ff8_ldr: |
| 44 | 44 | // CHECK-NEXT: 11004: 02 00 00 14 b #8 |
| 45 | 45 | // CHECK-NEXT: 11008: c0 03 5f d6 ret |
| 46 | 46 | // CHECK: __CortexA53843419_11004: |
| 47 | // CHECK-NEXT: 1100c: 00 08 40 f9 ldr x0, [x0, #16] | |
| 47 | // CHECK-NEXT: 1100c: 00 04 40 f9 ldr x0, [x0, #8] | |
| 48 | 48 | // CHECK-NEXT: 11010: fe ff ff 17 b #-8 |
| 49 | 49 | |
| 50 | 50 | .section .text.04, "ax", %progbits |
deps/lld/test/ELF/aarch64-cortex-a53-843419-tlsrelax.s+2-2| ... | ... | @@ -26,9 +26,9 @@ _start: |
| 26 | 26 | // CHECK: _start: |
| 27 | 27 | // CHECK-NEXT: 210ff8: 41 d0 3b d5 mrs x1, TPIDR_EL0 |
| 28 | 28 | // CHECK-NEXT: 210ffc: 00 00 a0 d2 movz x0, #0, lsl #16 |
| 29 | // CHECK-NEXT: 211000: 01 08 80 f2 movk x1, #64 | |
| 29 | // CHECK-NEXT: 211000: 01 02 80 f2 movk x1, #16 | |
| 30 | 30 | // CHECK-NEXT: 211004: 00 00 a0 d2 movz x0, #0, lsl #16 |
| 31 | // CHECK-NEXT: 211008: 01 08 80 f2 movk x1, #64 | |
| 31 | // CHECK-NEXT: 211008: 01 02 80 f2 movk x1, #16 | |
| 32 | 32 | // CHECK-NEXT: 21100c: c0 03 5f d6 ret |
| 33 | 33 | |
| 34 | 34 | .type v,@object |
deps/lld/test/ELF/aarch64-feature-bti.s created+218| ... | ... | @@ -0,0 +1,218 @@ |
| 1 | # REQUIRES: aarch64 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t.o | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-bti1.s -o %t1.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3.s -o %t2.o | |
| 5 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3-bti.s -o %t3.o | |
| 6 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func2.s -o %tno.o | |
| 7 | ||
| 8 | ## We do not add BTI support when the inputs don't have the .note.gnu.property | |
| 9 | ## field. | |
| 10 | ||
| 11 | # RUN: ld.lld %tno.o %t3.o --shared -o %tno.so | |
| 12 | # RUN: llvm-objdump -d -mattr=+bti --no-show-raw-insn %tno.so | FileCheck --check-prefix=NOBTI %s | |
| 13 | # RUN: llvm-readelf -x .got.plt %tno.so | FileCheck --check-prefix SOGOTPLT %s | |
| 14 | # RUN: llvm-readelf --dynamic-table %tno.so | FileCheck --check-prefix NOBTIDYN %s | |
| 15 | ||
| 16 | # NOBTIDYN-NOT: 0x0000000070000001 (AARCH64_BTI_PLT) | |
| 17 | # NOBTIDYN-NOT: 0x0000000070000003 (AARCH64_PAC_PLT) | |
| 18 | ||
| 19 | # NOBTI: 0000000000010000 func2: | |
| 20 | # NOBTI-NEXT: 10000: bl #48 <func3@plt> | |
| 21 | # NOBTI-NEXT: 10004: ret | |
| 22 | # NOBTI: Disassembly of section .plt: | |
| 23 | # NOBTI: 0000000000010010 .plt: | |
| 24 | # NOBTI-NEXT: 10010: stp x16, x30, [sp, #-16]! | |
| 25 | # NOBTI-NEXT: 10014: adrp x16, #131072 | |
| 26 | # NOBTI-NEXT: 10018: ldr x17, [x16, #16] | |
| 27 | # NOBTI-NEXT: 1001c: add x16, x16, #16 | |
| 28 | # NOBTI-NEXT: 10020: br x17 | |
| 29 | # NOBTI-NEXT: 10024: nop | |
| 30 | # NOBTI-NEXT: 10028: nop | |
| 31 | # NOBTI-NEXT: 1002c: nop | |
| 32 | # NOBTI: 0000000000010030 func3@plt: | |
| 33 | # NOBTI-NEXT: 10030: adrp x16, #131072 | |
| 34 | # NOBTI-NEXT: 10034: ldr x17, [x16, #24] | |
| 35 | # NOBTI-NEXT: 10038: add x16, x16, #24 | |
| 36 | # NOBTI-NEXT: 1003c: br x17 | |
| 37 | ||
| 38 | ## Expect a bti c at the start of plt[0], the plt entries do not need bti c as | |
| 39 | ## their address doesn't escape the shared object, so they can't be indirectly | |
| 40 | ## called. Expect no other difference. | |
| 41 | ||
| 42 | # RUN: ld.lld %t1.o %t3.o --shared -o %t.so | |
| 43 | # RUN: llvm-readelf -n %t.so | FileCheck --check-prefix BTIPROP %s | |
| 44 | # RUN: llvm-objdump -d -mattr=+bti --no-show-raw-insn %t.so | FileCheck --check-prefix BTISO %s | |
| 45 | # RUN: llvm-readelf -x .got.plt %t.so | FileCheck --check-prefix SOGOTPLT %s | |
| 46 | # RUN: llvm-readelf --dynamic-table %t.so | FileCheck --check-prefix BTIDYN %s | |
| 47 | ||
| 48 | # BTIPROP: Properties: aarch64 feature: BTI | |
| 49 | ||
| 50 | # BTIDYN: 0x0000000070000001 (AARCH64_BTI_PLT) | |
| 51 | # BTIDYN-NOT: 0x0000000070000003 (AARCH64_PAC_PLT) | |
| 52 | ||
| 53 | # BTISO: 0000000000010000 func2: | |
| 54 | # BTISO-NEXT: 10000: bl #48 <func3@plt> | |
| 55 | # BTISO-NEXT: 10004: ret | |
| 56 | # BTISO: Disassembly of section .plt: | |
| 57 | # BTISO: 0000000000010010 .plt: | |
| 58 | # BTISO-NEXT: 10010: bti c | |
| 59 | # BTISO-NEXT: 10014: stp x16, x30, [sp, #-16]! | |
| 60 | # BTISO-NEXT: 10018: adrp x16, #131072 | |
| 61 | # BTISO-NEXT: 1001c: ldr x17, [x16, #16] | |
| 62 | # BTISO-NEXT: 10020: add x16, x16, #16 | |
| 63 | # BTISO-NEXT: 10024: br x17 | |
| 64 | # BTISO-NEXT: 10028: nop | |
| 65 | # BTISO-NEXT: 1002c: nop | |
| 66 | # BTISO: 0000000000010030 func3@plt: | |
| 67 | # BTISO-NEXT: 10030: adrp x16, #131072 | |
| 68 | # BTISO-NEXT: 10034: ldr x17, [x16, #24] | |
| 69 | # BTISO-NEXT: 10038: add x16, x16, #24 | |
| 70 | # BTISO-NEXT: 1003c: br x17 | |
| 71 | ||
| 72 | ## The .got.plt should be identical between the BTI and no BTI DSO PLT. | |
| 73 | # SOGOTPLT: Hex dump of section '.got.plt' | |
| 74 | # SOGOTPLT-NEXT: 0x00030000 00000000 00000000 00000000 00000000 | |
| 75 | # SOGOTPLT-NEXT: 0x00030010 00000000 00000000 10000100 00000000 | |
| 76 | ||
| 77 | ## Build an executable with all relocatable inputs having the BTI | |
| 78 | ## .note.gnu.property. We expect a bti c in front of all PLT entries as the | |
| 79 | ## address of a PLT entry can escape an executable. | |
| 80 | ||
| 81 | # RUN: ld.lld %t2.o --shared -o %t2.so | |
| 82 | ||
| 83 | # RUN: ld.lld %t.o %t.so %t2.so -o %t.exe | |
| 84 | # RUN: llvm-readelf --dynamic-table -n %t.exe | FileCheck --check-prefix=BTIPROP %s | |
| 85 | # RUN: llvm-objdump -d -mattr=+bti --no-show-raw-insn %t.exe | FileCheck --check-prefix=EXECBTI %s | |
| 86 | ||
| 87 | # EXECBTI: Disassembly of section .text: | |
| 88 | # EXECBTI: 0000000000210000 func1: | |
| 89 | # EXECBTI-NEXT: 210000: bl #48 <func2@plt> | |
| 90 | # EXECBTI-NEXT: 210004: ret | |
| 91 | # EXECBTI: Disassembly of section .plt: | |
| 92 | # EXECBTI: 0000000000210010 .plt: | |
| 93 | # EXECBTI-NEXT: 210010: bti c | |
| 94 | # EXECBTI-NEXT: 210014: stp x16, x30, [sp, #-16]! | |
| 95 | # EXECBTI-NEXT: 210018: adrp x16, #131072 | |
| 96 | # EXECBTI-NEXT: 21001c: ldr x17, [x16, #16] | |
| 97 | # EXECBTI-NEXT: 210020: add x16, x16, #16 | |
| 98 | # EXECBTI-NEXT: 210024: br x17 | |
| 99 | # EXECBTI-NEXT: 210028: nop | |
| 100 | # EXECBTI-NEXT: 21002c: nop | |
| 101 | # EXECBTI: 0000000000210030 func2@plt: | |
| 102 | # EXECBTI-NEXT: 210030: bti c | |
| 103 | # EXECBTI-NEXT: 210034: adrp x16, #131072 | |
| 104 | # EXECBTI-NEXT: 210038: ldr x17, [x16, #24] | |
| 105 | # EXECBTI-NEXT: 21003c: add x16, x16, #24 | |
| 106 | # EXECBTI-NEXT: 210040: br x17 | |
| 107 | # EXECBTI-NEXT: 210044: nop | |
| 108 | ||
| 109 | ## We expect the same for PIE, as the address of an ifunc can escape | |
| 110 | # RUN: ld.lld --pie %t.o %t.so %t2.so -o %tpie.exe | |
| 111 | # RUN: llvm-readelf -n %tpie.exe | FileCheck --check-prefix=BTIPROP %s | |
| 112 | # RUN: llvm-readelf --dynamic-table -n %tpie.exe | FileCheck --check-prefix=BTIPROP %s | |
| 113 | # RUN: llvm-objdump -d -mattr=+bti --no-show-raw-insn %tpie.exe | FileCheck --check-prefix=PIE %s | |
| 114 | ||
| 115 | # PIE: Disassembly of section .text: | |
| 116 | # PIE: 0000000000010000 func1: | |
| 117 | # PIE-NEXT: 10000: bl #48 <func2@plt> | |
| 118 | # PIE-NEXT: 10004: ret | |
| 119 | # PIE: Disassembly of section .plt: | |
| 120 | # PIE: 0000000000010010 .plt: | |
| 121 | # PIE-NEXT: 10010: bti c | |
| 122 | # PIE-NEXT: 10014: stp x16, x30, [sp, #-16]! | |
| 123 | # PIE-NEXT: 10018: adrp x16, #131072 | |
| 124 | # PIE-NEXT: 1001c: ldr x17, [x16, #16] | |
| 125 | # PIE-NEXT: 10020: add x16, x16, #16 | |
| 126 | # PIE-NEXT: 10024: br x17 | |
| 127 | # PIE-NEXT: 10028: nop | |
| 128 | # PIE-NEXT: 1002c: nop | |
| 129 | # PIE: 0000000000010030 func2@plt: | |
| 130 | # PIE-NEXT: 10030: bti c | |
| 131 | # PIE-NEXT: 10034: adrp x16, #131072 | |
| 132 | # PIE-NEXT: 10038: ldr x17, [x16, #24] | |
| 133 | # PIE-NEXT: 1003c: add x16, x16, #24 | |
| 134 | # PIE-NEXT: 10040: br x17 | |
| 135 | # PIE-NEXT: 10044: nop | |
| 136 | ||
| 137 | ## Build and executable with not all relocatable inputs having the BTI | |
| 138 | ## .note.property, expect no bti c and no .note.gnu.property entry | |
| 139 | ||
| 140 | # RUN: ld.lld %t.o %t2.o %t.so -o %tnobti.exe | |
| 141 | # RUN: llvm-readelf --dynamic-table %tnobti.exe | FileCheck --check-prefix NOBTIDYN %s | |
| 142 | # RUN: llvm-objdump -d -mattr=+bti --no-show-raw-insn %tnobti.exe | FileCheck --check-prefix=NOEX %s | |
| 143 | ||
| 144 | # NOEX: Disassembly of section .text: | |
| 145 | # NOEX: 0000000000210000 func1: | |
| 146 | # NOEX-NEXT: 210000: bl #48 <func2@plt> | |
| 147 | # NOEX-NEXT: 210004: ret | |
| 148 | # NOEX: 0000000000210008 func3: | |
| 149 | # NOEX-NEXT: 210008: ret | |
| 150 | # NOEX: Disassembly of section .plt: | |
| 151 | # NOEX: 0000000000210010 .plt: | |
| 152 | # NOEX-NEXT: 210010: stp x16, x30, [sp, #-16]! | |
| 153 | # NOEX-NEXT: 210014: adrp x16, #131072 | |
| 154 | # NOEX-NEXT: 210018: ldr x17, [x16, #16] | |
| 155 | # NOEX-NEXT: 21001c: add x16, x16, #16 | |
| 156 | # NOEX-NEXT: 210020: br x17 | |
| 157 | # NOEX-NEXT: 210024: nop | |
| 158 | # NOEX-NEXT: 210028: nop | |
| 159 | # NOEX-NEXT: 21002c: nop | |
| 160 | # NOEX: 0000000000210030 func2@plt: | |
| 161 | # NOEX-NEXT: 210030: adrp x16, #131072 | |
| 162 | # NOEX-NEXT: 210034: ldr x17, [x16, #24] | |
| 163 | # NOEX-NEXT: 210038: add x16, x16, #24 | |
| 164 | # NOEX-NEXT: 21003c: br x17 | |
| 165 | ||
| 166 | ## Force BTI entries with the --force-bti command line option. Expect a warning | |
| 167 | ## from the file without the .note.gnu.property. | |
| 168 | ||
| 169 | # RUN: ld.lld %t.o %t2.o --force-bti %t.so -o %tforcebti.exe 2>&1 | FileCheck --check-prefix=FORCE-WARN %s | |
| 170 | ||
| 171 | # FORCE-WARN: aarch64-feature-bti.s.tmp2.o: --force-bti: file does not have BTI property | |
| 172 | ||
| 173 | ||
| 174 | # RUN: llvm-readelf -n %tforcebti.exe | FileCheck --check-prefix=BTIPROP %s | |
| 175 | # RUN: llvm-readelf --dynamic-table %tforcebti.exe | FileCheck --check-prefix BTIDYN %s | |
| 176 | # RUN: llvm-objdump -d -mattr=+bti --no-show-raw-insn %tforcebti.exe | FileCheck --check-prefix=FORCE %s | |
| 177 | ||
| 178 | # FORCE: Disassembly of section .text: | |
| 179 | # FORCE: 0000000000210000 func1: | |
| 180 | # FORCE-NEXT: 210000: bl #48 <func2@plt> | |
| 181 | # FORCE-NEXT: 210004: ret | |
| 182 | # FORCE: 0000000000210008 func3: | |
| 183 | # FORCE-NEXT: 210008: ret | |
| 184 | # FORCE: Disassembly of section .plt: | |
| 185 | # FORCE: 0000000000210010 .plt: | |
| 186 | # FORCE-NEXT: 210010: bti c | |
| 187 | # FORCE-NEXT: 210014: stp x16, x30, [sp, #-16]! | |
| 188 | # FORCE-NEXT: 210018: adrp x16, #131072 | |
| 189 | # FORCE-NEXT: 21001c: ldr x17, [x16, #16] | |
| 190 | # FORCE-NEXT: 210020: add x16, x16, #16 | |
| 191 | # FORCE-NEXT: 210024: br x17 | |
| 192 | # FORCE-NEXT: 210028: nop | |
| 193 | # FORCE-NEXT: 21002c: nop | |
| 194 | # FORCE: 0000000000210030 func2@plt: | |
| 195 | # FORCE-NEXT: 210030: bti c | |
| 196 | # FORCE-NEXT: 210034: adrp x16, #131072 | |
| 197 | # FORCE-NEXT: 210038: ldr x17, [x16, #24] | |
| 198 | # FORCE-NEXT: 21003c: add x16, x16, #24 | |
| 199 | # FORCE-NEXT: 210040: br x17 | |
| 200 | # FORCE-NEXT: 210044: nop | |
| 201 | ||
| 202 | .section ".note.gnu.property", "a" | |
| 203 | .long 4 | |
| 204 | .long 0x10 | |
| 205 | .long 0x5 | |
| 206 | .asciz "GNU" | |
| 207 | ||
| 208 | .long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND | |
| 209 | .long 4 | |
| 210 | .long 1 // GNU_PROPERTY_AARCH64_FEATURE_1_BTI | |
| 211 | .long 0 | |
| 212 | ||
| 213 | .text | |
| 214 | .globl _start | |
| 215 | .type func1,%function | |
| 216 | func1: | |
| 217 | bl func2 | |
| 218 | ret |
deps/lld/test/ELF/aarch64-feature-btipac.s created+142| ... | ... | @@ -0,0 +1,142 @@ |
| 1 | # REQUIRES: aarch64 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t.o | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-btipac1.s -o %t1.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3.s -o %t3.o | |
| 5 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3-btipac.s -o %t3btipac.o | |
| 6 | ||
| 7 | ## Build shared library with all inputs having BTI and PAC, expect PLT | |
| 8 | ## entries supporting both PAC and BTI. For a shared library this means: | |
| 9 | ## PLT[0] has bti c at start | |
| 10 | ## PLT[n] has autia1716 before br x17 | |
| 11 | ||
| 12 | # RUN: ld.lld %t1.o %t3btipac.o --shared -o %t.so | |
| 13 | # RUN: llvm-readelf -n %t.so | FileCheck --check-prefix BTIPACPROP %s | |
| 14 | # RUN: llvm-objdump -d -mattr=+v8.5a --no-show-raw-insn %t.so | FileCheck --check-prefix BTIPACSO %s | |
| 15 | # RUN: llvm-readelf --dynamic-table %t.so | FileCheck --check-prefix BTIPACDYN %s | |
| 16 | ||
| 17 | # BTIPACSO: Disassembly of section .text: | |
| 18 | # BTIPACSO: 0000000000010000 func2: | |
| 19 | # BTIPACSO-NEXT: 10000: bl #48 <func3@plt> | |
| 20 | # BTIPACSO-NEXT: 10004: ret | |
| 21 | # BTIPACSO: 0000000000010008 func3: | |
| 22 | # BTIPACSO-NEXT: 10008: ret | |
| 23 | # BTIPACSO: Disassembly of section .plt: | |
| 24 | # BTIPACSO: 0000000000010010 .plt: | |
| 25 | # BTIPACSO-NEXT: 10010: bti c | |
| 26 | # BTIPACSO-NEXT: 10014: stp x16, x30, [sp, #-16]! | |
| 27 | # BTIPACSO-NEXT: 10018: adrp x16, #131072 | |
| 28 | # BTIPACSO-NEXT: 1001c: ldr x17, [x16, #16] | |
| 29 | # BTIPACSO-NEXT: 10020: add x16, x16, #16 | |
| 30 | # BTIPACSO-NEXT: 10024: br x17 | |
| 31 | # BTIPACSO-NEXT: 10028: nop | |
| 32 | # BTIPACSO-NEXT: 1002c: nop | |
| 33 | # BTIPACSO: 0000000000010030 func3@plt: | |
| 34 | # BTIPACSO-NEXT: 10030: adrp x16, #131072 | |
| 35 | # BTIPACSO-NEXT: 10034: ldr x17, [x16, #24] | |
| 36 | # BTIPACSO-NEXT: 10038: add x16, x16, #24 | |
| 37 | # BTIPACSO-NEXT: 1003c: autia1716 | |
| 38 | # BTIPACSO-NEXT: 10040: br x17 | |
| 39 | # BTIPACSO-NEXT: 10044: nop | |
| 40 | ||
| 41 | # BTIPACPROP: Properties: aarch64 feature: BTI, PAC | |
| 42 | ||
| 43 | # BTIPACDYN: 0x0000000070000001 (AARCH64_BTI_PLT) | |
| 44 | # BTIPACDYN: 0x0000000070000003 (AARCH64_PAC_PLT) | |
| 45 | ||
| 46 | ## Make an executable with both BTI and PAC properties. Expect: | |
| 47 | ## PLT[0] bti c as first instruction | |
| 48 | ## PLT[n] bti n as first instruction, autia1716 before br x17 | |
| 49 | ||
| 50 | # RUN: ld.lld %t.o %t3btipac.o %t.so -o %t.exe | |
| 51 | # RUN: llvm-readelf -n %t.exe | FileCheck --check-prefix=BTIPACPROP %s | |
| 52 | # RUN: llvm-objdump -d -mattr=+v8.5a --no-show-raw-insn %t.exe | FileCheck --check-prefix BTIPACEX %s | |
| 53 | # RUN: llvm-readelf --dynamic-table %t.exe | FileCheck --check-prefix BTIPACDYN %s | |
| 54 | ||
| 55 | # BTIPACEX: Disassembly of section .text: | |
| 56 | # BTIPACEX: 0000000000210000 func1: | |
| 57 | # BTIPACEX-NEXT: 210000: bl #48 <func2@plt> | |
| 58 | # BTIPACEX-NEXT: 210004: ret | |
| 59 | # BTIPACEX-NEXT: 210008: ret | |
| 60 | # BTIPACEX: 000000000021000c func3: | |
| 61 | # BTIPACEX-NEXT: 21000c: ret | |
| 62 | # BTIPACEX: Disassembly of section .plt: | |
| 63 | # BTIPACEX: 0000000000210010 .plt: | |
| 64 | # BTIPACEX-NEXT: 210010: bti c | |
| 65 | # BTIPACEX-NEXT: 210014: stp x16, x30, [sp, #-16]! | |
| 66 | # BTIPACEX-NEXT: 210018: adrp x16, #131072 | |
| 67 | # BTIPACEX-NEXT: 21001c: ldr x17, [x16, #16] | |
| 68 | # BTIPACEX-NEXT: 210020: add x16, x16, #16 | |
| 69 | # BTIPACEX-NEXT: 210024: br x17 | |
| 70 | # BTIPACEX-NEXT: 210028: nop | |
| 71 | # BTIPACEX-NEXT: 21002c: nop | |
| 72 | # BTIPACEX: 0000000000210030 func2@plt: | |
| 73 | # BTIPACEX-NEXT: 210030: bti c | |
| 74 | # BTIPACEX-NEXT: 210034: adrp x16, #131072 | |
| 75 | # BTIPACEX-NEXT: 210038: ldr x17, [x16, #24] | |
| 76 | # BTIPACEX-NEXT: 21003c: add x16, x16, #24 | |
| 77 | # BTIPACEX-NEXT: 210040: autia1716 | |
| 78 | # BTIPACEX-NEXT: 210044: br x17 | |
| 79 | ||
| 80 | ## Check that combinations of BTI+PAC with 0 properties results in standard PLT | |
| 81 | ||
| 82 | # RUN: ld.lld %t.o %t3.o %t.so -o %t.exe | |
| 83 | # RUN: llvm-objdump -d -mattr=+v8.5a --no-show-raw-insn %t.exe | FileCheck --check-prefix EX %s | |
| 84 | # RUN: llvm-readelf --dynamic-table %t.exe | FileCheck --check-prefix=NODYN %s | |
| 85 | ||
| 86 | # EX: Disassembly of section .text: | |
| 87 | # EX: 0000000000210000 func1: | |
| 88 | # EX-NEXT: 210000: bl #48 <func2@plt> | |
| 89 | # EX-NEXT: 210004: ret | |
| 90 | # EX-NEXT: 210008: ret | |
| 91 | # EX: 000000000021000c func3: | |
| 92 | # EX-NEXT: 21000c: ret | |
| 93 | # EX: Disassembly of section .plt: | |
| 94 | # EX: 0000000000210010 .plt: | |
| 95 | # EX-NEXT: 210010: stp x16, x30, [sp, #-16]! | |
| 96 | # EX-NEXT: 210014: adrp x16, #131072 | |
| 97 | # EX-NEXT: 210018: ldr x17, [x16, #16] | |
| 98 | # EX-NEXT: 21001c: add x16, x16, #16 | |
| 99 | # EX-NEXT: 210020: br x17 | |
| 100 | # EX-NEXT: 210024: nop | |
| 101 | # EX-NEXT: 210028: nop | |
| 102 | # EX-NEXT: 21002c: nop | |
| 103 | # EX: 0000000000210030 func2@plt: | |
| 104 | # EX: 210030: adrp x16, #131072 | |
| 105 | # EX-NEXT: 210034: ldr x17, [x16, #24] | |
| 106 | # EX-NEXT: 210038: add x16, x16, #24 | |
| 107 | # EX-NEXT: 21003c: br x17 | |
| 108 | ||
| 109 | # NODYN-NOT: 0x0000000070000001 (AARCH64_BTI_PLT) | |
| 110 | # NODYN-NOT: 0x0000000070000003 (AARCH64_PAC_PLT) | |
| 111 | ||
| 112 | ## Check that combination of --pac-plt and --force-bti warns for the file that | |
| 113 | ## doesn't contain the BTI property, but generates PAC and BTI PLT sequences. | |
| 114 | ## The --pac-plt doesn't warn as it is not required for correctness. | |
| 115 | ||
| 116 | # RUN: ld.lld %t.o %t3.o %t.so --pac-plt --force-bti -o %t.exe 2>&1 | FileCheck --check-prefix=FORCE-WARN %s | |
| 117 | ||
| 118 | # FORCE-WARN: aarch64-feature-btipac.s.tmp3.o: --force-bti: file does not have BTI property | |
| 119 | ||
| 120 | # RUN: llvm-readelf -n %t.exe | FileCheck --check-prefix=BTIPACPROP %s | |
| 121 | # RUN: llvm-objdump -d -mattr=+v8.5a --no-show-raw-insn %t.exe | FileCheck --check-prefix BTIPACEX %s | |
| 122 | # RUN: llvm-readelf --dynamic-table %t.exe | FileCheck --check-prefix BTIPACDYN %s | |
| 123 | .section ".note.gnu.property", "a" | |
| 124 | .long 4 | |
| 125 | .long 0x10 | |
| 126 | .long 0x5 | |
| 127 | .asciz "GNU" | |
| 128 | ||
| 129 | .long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND | |
| 130 | .long 4 | |
| 131 | .long 3 // GNU_PROPERTY_AARCH64_FEATURE_1_BTI and PAC | |
| 132 | .long 0 | |
| 133 | ||
| 134 | .text | |
| 135 | .globl _start | |
| 136 | .type func1,%function | |
| 137 | func1: | |
| 138 | bl func2 | |
| 139 | ret | |
| 140 | .globl func3 | |
| 141 | .type func3,%function | |
| 142 | ret |
deps/lld/test/ELF/aarch64-feature-pac.s created+129| ... | ... | @@ -0,0 +1,129 @@ |
| 1 | # REQUIRES: aarch64 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t.o | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-pac1.s -o %t1.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3.s -o %t2.o | |
| 5 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3-pac.s -o %t3.o | |
| 6 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func2.s -o %tno.o | |
| 7 | ||
| 8 | ## We do not add PAC support when the inputs don't have the .note.gnu.property | |
| 9 | ## field. | |
| 10 | ||
| 11 | # RUN: ld.lld %tno.o %t3.o --shared -o %tno.so | |
| 12 | # RUN: llvm-objdump -d -mattr=+v8.3a --no-show-raw-insn %tno.so | FileCheck --check-prefix=NOPAC %s | |
| 13 | # RUN: llvm-readelf -x .got.plt %tno.so | FileCheck --check-prefix SOGOTPLT %s | |
| 14 | # RUN: llvm-readelf --dynamic-table %tno.so | FileCheck --check-prefix NOPACDYN %s | |
| 15 | ||
| 16 | # NOPAC: 0000000000010000 func2: | |
| 17 | # NOPAC-NEXT: 10000: bl #48 <func3@plt> | |
| 18 | # NOPAC-NEXT: 10004: ret | |
| 19 | # NOPAC: Disassembly of section .plt: | |
| 20 | # NOPAC: 0000000000010010 .plt: | |
| 21 | # NOPAC-NEXT: 10010: stp x16, x30, [sp, #-16]! | |
| 22 | # NOPAC-NEXT: 10014: adrp x16, #131072 | |
| 23 | # NOPAC-NEXT: 10018: ldr x17, [x16, #16] | |
| 24 | # NOPAC-NEXT: 1001c: add x16, x16, #16 | |
| 25 | # NOPAC-NEXT: 10020: br x17 | |
| 26 | # NOPAC-NEXT: 10024: nop | |
| 27 | # NOPAC-NEXT: 10028: nop | |
| 28 | # NOPAC-NEXT: 1002c: nop | |
| 29 | # NOPAC: 0000000000010030 func3@plt: | |
| 30 | # NOPAC-NEXT: 10030: adrp x16, #131072 | |
| 31 | # NOPAC-NEXT: 10034: ldr x17, [x16, #24] | |
| 32 | # NOPAC-NEXT: 10038: add x16, x16, #24 | |
| 33 | # NOPAC-NEXT: 1003c: br x17 | |
| 34 | ||
| 35 | # NOPACDYN-NOT: 0x0000000070000001 (AARCH64_BTI_PLT) | |
| 36 | # NOPACDYN-NOT: 0x0000000070000003 (AARCH64_PAC_PLT) | |
| 37 | ||
| 38 | # RUN: ld.lld %t1.o %t3.o --shared -o %t.so | |
| 39 | # RUN: llvm-readelf -n %t.so | FileCheck --check-prefix PACPROP %s | |
| 40 | # RUN: llvm-objdump -d -mattr=+v8.3a --no-show-raw-insn %t.so | FileCheck --check-prefix PACSO %s | |
| 41 | # RUN: llvm-readelf -x .got.plt %t.so | FileCheck --check-prefix SOGOTPLT %s | |
| 42 | # RUN: llvm-readelf --dynamic-table %t.so | FileCheck --check-prefix PACDYN %s | |
| 43 | ||
| 44 | ## PAC has no effect on PLT[0], for PLT[N] autia1716 is used to authenticate | |
| 45 | ## the address in x17 (context in x16) before branching to it. The dynamic | |
| 46 | ## loader is responsible for calling pacia1716 on the entry. | |
| 47 | # PACSO: 0000000000010000 func2: | |
| 48 | # PACSO-NEXT: 10000: bl #48 <func3@plt> | |
| 49 | # PACSO-NEXT: 10004: ret | |
| 50 | # PACSO: Disassembly of section .plt: | |
| 51 | # PACSO: 0000000000010010 .plt: | |
| 52 | # PACSO-NEXT: 10010: stp x16, x30, [sp, #-16]! | |
| 53 | # PACSO-NEXT: 10014: adrp x16, #131072 | |
| 54 | # PACSO-NEXT: 10018: ldr x17, [x16, #16] | |
| 55 | # PACSO-NEXT: 1001c: add x16, x16, #16 | |
| 56 | # PACSO-NEXT: 10020: br x17 | |
| 57 | # PACSO-NEXT: 10024: nop | |
| 58 | # PACSO-NEXT: 10028: nop | |
| 59 | # PACSO-NEXT: 1002c: nop | |
| 60 | # PACSO: 0000000000010030 func3@plt: | |
| 61 | # PACSO-NEXT: 10030: adrp x16, #131072 | |
| 62 | # PACSO-NEXT: 10034: ldr x17, [x16, #24] | |
| 63 | # PACSO-NEXT: 10038: add x16, x16, #24 | |
| 64 | # PACSO-NEXT: 1003c: autia1716 | |
| 65 | # PACSO-NEXT: 10040: br x17 | |
| 66 | # PACSO-NEXT: 10044: nop | |
| 67 | ||
| 68 | # The .got.plt should be identical between the PAC and no PAC DSO PLT. | |
| 69 | # SOGOTPLT: Hex dump of section '.got.plt': | |
| 70 | # SOGOTPLT-NEXT: 0x00030000 00000000 00000000 00000000 00000000 | |
| 71 | # SOGOTPLT-NEXT: 0x00030010 00000000 00000000 10000100 00000000 | |
| 72 | ||
| 73 | # PACPROP: Properties: aarch64 feature: PAC | |
| 74 | ||
| 75 | # PACDYN-NOT: 0x0000000070000001 (AARCH64_BTI_PLT) | |
| 76 | # PACDYN: 0x0000000070000003 (AARCH64_PAC_PLT) | |
| 77 | ||
| 78 | ## Turn on PAC entries with the --pac-plt command line option. There are no | |
| 79 | ## warnings in this case as the choice to use PAC in PLT entries is orthogonal | |
| 80 | ## to the choice of using PAC in relocatable objects. The presence of the PAC | |
| 81 | ## .note.gnu.property is an indication of preference by the relocatable object. | |
| 82 | ||
| 83 | # RUN: ld.lld %t.o %t2.o --pac-plt %t.so -o %tpacplt.exe | |
| 84 | # RUN: llvm-readelf -n %tpacplt.exe | FileCheck --check-prefix=PACPROP %s | |
| 85 | # RUN: llvm-readelf --dynamic-table %tpacplt.exe | FileCheck --check-prefix PACDYN %s | |
| 86 | # RUN: llvm-objdump -d -mattr=+v8.3a --no-show-raw-insn %tpacplt.exe | FileCheck --check-prefix PACPLT %s | |
| 87 | ||
| 88 | # PACPLT: Disassembly of section .text: | |
| 89 | # PACPLT: 0000000000210000 func1: | |
| 90 | # PACPLT-NEXT: 210000: bl #48 <func2@plt> | |
| 91 | # PACPLT-NEXT: 210004: ret | |
| 92 | # PACPLT: 0000000000210008 func3: | |
| 93 | # PACPLT-NEXT: 210008: ret | |
| 94 | # PACPLT: Disassembly of section .plt: | |
| 95 | # PACPLT: 0000000000210010 .plt: | |
| 96 | # PACPLT-NEXT: 210010: stp x16, x30, [sp, #-16]! | |
| 97 | # PACPLT-NEXT: 210014: adrp x16, #131072 | |
| 98 | # PACPLT-NEXT: 210018: ldr x17, [x16, #16] | |
| 99 | # PACPLT-NEXT: 21001c: add x16, x16, #16 | |
| 100 | # PACPLT-NEXT: 210020: br x17 | |
| 101 | # PACPLT-NEXT: 210024: nop | |
| 102 | # PACPLT-NEXT: 210028: nop | |
| 103 | # PACPLT-NEXT: 21002c: nop | |
| 104 | # PACPLT: 0000000000210030 func2@plt: | |
| 105 | # PACPLT-NEXT: 210030: adrp x16, #131072 | |
| 106 | # PACPLT-NEXT: 210034: ldr x17, [x16, #24] | |
| 107 | # PACPLT-NEXT: 210038: add x16, x16, #24 | |
| 108 | # PACPLT-NEXT: 21003c: autia1716 | |
| 109 | # PACPLT-NEXT: 210040: br x17 | |
| 110 | # PACPLT-NEXT: 210044: nop | |
| 111 | ||
| 112 | ||
| 113 | .section ".note.gnu.property", "a" | |
| 114 | .long 4 | |
| 115 | .long 0x10 | |
| 116 | .long 0x5 | |
| 117 | .asciz "GNU" | |
| 118 | ||
| 119 | .long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND | |
| 120 | .long 4 | |
| 121 | .long 2 // GNU_PROPERTY_AARCH64_FEATURE_1_PAC | |
| 122 | .long 0 | |
| 123 | ||
| 124 | .text | |
| 125 | .globl _start | |
| 126 | .type func1,%function | |
| 127 | func1: | |
| 128 | bl func2 | |
| 129 | ret |
deps/lld/test/ELF/aarch64-fpic-adr_prel_pg_hi21.s+2| ... | ... | @@ -4,8 +4,10 @@ |
| 4 | 4 | // CHECK: relocation R_AARCH64_ADR_PREL_PG_HI21 cannot be used against symbol dat; recompile with -fPIC |
| 5 | 5 | // CHECK: >>> defined in {{.*}}.o |
| 6 | 6 | // CHECK: >>> referenced by {{.*}}.o:(.text+0x0) |
| 7 | // CHECK: relocation R_AARCH64_ADR_PREL_PG_HI21_NC cannot be used against symbol dat; recompile with -fPIC | |
| 7 | 8 | |
| 8 | 9 | adrp x0, dat |
| 10 | adrp x0, :pg_hi21_nc:dat | |
| 9 | 11 | .data |
| 10 | 12 | .globl dat |
| 11 | 13 | dat: |
deps/lld/test/ELF/aarch64-fpic-got.s+12-4| ... | ... | @@ -3,14 +3,22 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t.o |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %p/Inputs/shared.s -o %t-lib.o |
| 5 | 5 | # RUN: ld.lld -shared %t-lib.o -o %t-lib.so |
| 6 | ||
| 6 | 7 | # RUN: ld.lld %t-lib.so %t.o -o %t.exe |
| 7 | # RUN: llvm-readobj -dyn-relocations %t.exe | FileCheck %s | |
| 8 | # RUN: llvm-readobj -r %t.exe | FileCheck --check-prefix=RELOC %s | |
| 9 | # RUN: llvm-objdump -d --no-show-raw-insn %t.exe | FileCheck --check-prefix=DIS %s | |
| 8 | 10 | |
| 9 | 11 | ## Checks if got access to dynamic objects is done through a got relative |
| 10 | 12 | ## dynamic relocation and not using plt relative (R_AARCH64_JUMP_SLOT). |
| 11 | # CHECK: Dynamic Relocations { | |
| 12 | # CHECK-NEXT: 0x{{[0-9A-F]+}} R_AARCH64_GLOB_DAT bar 0x0 | |
| 13 | # CHECK-NEXT: } | |
| 13 | # RELOC: .rela.dyn { | |
| 14 | # RELOC-NEXT: 0x2200C0 R_AARCH64_GLOB_DAT bar 0x0 | |
| 15 | # RELOC-NEXT: } | |
| 16 | ||
| 17 | ## page(0x2200C0) - page(0x210000) = 65536 | |
| 18 | ## page(0x2200C0) & 0xff8 = 192 | |
| 19 | # DIS: _start: | |
| 20 | # DIS-NEXT: 210000: adrp x0, #65536 | |
| 21 | # DIS-NEXT: 210004: ldr x0, [x0, #192] | |
| 14 | 22 | |
| 15 | 23 | .globl _start |
| 16 | 24 | _start: |
deps/lld/test/ELF/aarch64-gnu-ifunc-address-pie.s deleted-44| ... | ... | @@ -1,44 +0,0 @@ |
| 1 | # REQUIRES: aarch64 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o | |
| 3 | # RUN: ld.lld -pie %t.o -o %tout | |
| 4 | # RUN: llvm-objdump -D %tout | FileCheck %s | |
| 5 | # RUN: llvm-readobj -r %tout | FileCheck %s -check-prefix=CHECK-RELOCS | |
| 6 | ||
| 7 | # Test that when we take the address of a preemptible ifunc using -fpie, we can | |
| 8 | # handle the case when the ifunc is in the same translation unit as the address | |
| 9 | # taker. In this case the compiler knows that ifunc is not defined in a shared | |
| 10 | # library so it can use a non got generating relative reference. | |
| 11 | .text | |
| 12 | .globl myfunc | |
| 13 | .type myfunc,@gnu_indirect_function | |
| 14 | myfunc: | |
| 15 | ret | |
| 16 | ||
| 17 | .text | |
| 18 | .globl main | |
| 19 | .type main,@function | |
| 20 | main: | |
| 21 | adrp x8, myfunc | |
| 22 | add x8, x8, :lo12: myfunc | |
| 23 | ret | |
| 24 | ||
| 25 | # CHECK: 0000000000010000 myfunc: | |
| 26 | # CHECK-NEXT: 10000:	c0 03 5f d6 	ret | |
| 27 | # CHECK: 0000000000010004 main: | |
| 28 | # CHECK-NEXT: 10004:	08 00 00 90 	adrp	x8, #0 | |
| 29 | # x8 = 0x10000 | |
| 30 | # CHECK-NEXT: 10008:	08 41 00 91 	add	x8, x8, #16 | |
| 31 | # x8 = 0x10010 = .plt for myfunc | |
| 32 | # CHECK-NEXT: 1000c:	c0 03 5f d6 	ret | |
| 33 | # CHECK-NEXT: Disassembly of section .plt: | |
| 34 | # CHECK-NEXT: 0000000000010010 .plt: | |
| 35 | # CHECK-NEXT: 10010:	90 00 00 90 	adrp	x16, #65536 | |
| 36 | # CHECK-NEXT: 10014:	11 02 40 f9 	ldr	x17, [x16] | |
| 37 | # CHECK-NEXT: 10018:	10 02 00 91 	add	x16, x16, #0 | |
| 38 | # CHECK-NEXT: 1001c:	20 02 1f d6 	br	x17 | |
| 39 | ||
| 40 | # CHECK-RELOCS: Relocations [ | |
| 41 | # CHECK-RELOCS-NEXT: Section {{.*}} .rela.plt { | |
| 42 | # CHECK-RELOCS-NEXT: 0x20000 R_AARCH64_IRELATIVE - 0x10000 | |
| 43 | # CHECK-RELOCS-NEXT: } | |
| 44 | # CHECK-RELOCS-NEXT: ] |
deps/lld/test/ELF/aarch64-gnu-ifunc-address.s+9-11| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: aarch64 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o |
| 3 | 3 | # RUN: ld.lld -shared %t.o -o %tout |
| 4 | # RUN: llvm-objdump -D %tout | FileCheck %s | |
| 4 | # RUN: llvm-objdump -D --no-show-raw-insn %tout | FileCheck %s | |
| 5 | 5 | # RUN: llvm-readobj -r %tout | FileCheck %s --check-prefix=CHECK-RELOCS |
| 6 | 6 | |
| 7 | 7 | # Test that when we take the address of a preemptible ifunc in a shared object |
| ... | ... | @@ -21,20 +21,18 @@ main: |
| 21 | 21 | ldr x8, [x8, :got_lo12:myfunc] |
| 22 | 22 | ret |
| 23 | 23 | # CHECK: 0000000000010004 main: |
| 24 | # x8 = 0x30000 | |
| 25 | # CHECK-NEXT: 10004: 08 01 00 90 adrp x8, #131072 | |
| 26 | # x8 = 0x300e0 = .got entry for myfunc with R_AARCH64_GLOB_DAT | |
| 27 | # CHECK-NEXT: 10008: 08 71 40 f9 ldr x8, [x8, #224] | |
| 28 | # CHECK-NEXT: 1000c: c0 03 5f d6 ret | |
| 24 | # x8 = 0x20000 | |
| 25 | # CHECK-NEXT: 10004: adrp x8, #65536 | |
| 26 | # x8 = 0x200a0 = .got entry for myfunc with R_AARCH64_GLOB_DAT | |
| 27 | # CHECK-NEXT: 10008: ldr x8, [x8, #160] | |
| 28 | # CHECK-NEXT: 1000c: ret | |
| 29 | 29 | |
| 30 | 30 | # CHECK: Disassembly of section .got: |
| 31 | # CHECK-NEXT: 00000000000300e0 .got: | |
| 31 | # CHECK-EMPTY: | |
| 32 | # CHECK-NEXT: 00000000000200a0 .got: | |
| 32 | 33 | |
| 33 | 34 | # CHECK-RELOCS: Relocations [ |
| 34 | 35 | # CHECK-RELOCS-NEXT: Section {{.*}} .rela.dyn { |
| 35 | # CHECK-RELOCS-NEXT: 0x300E0 R_AARCH64_GLOB_DAT myfunc 0x0 | |
| 36 | # CHECK-RELOCS-NEXT: } | |
| 37 | # CHECK-RELOCS-NEXT: Section {{.*}} .rela.plt { | |
| 38 | # CHECK-RELOCS-NEXT: 0x20018 R_AARCH64_JUMP_SLOT myfunc 0x0 | |
| 36 | # CHECK-RELOCS-NEXT: 0x200A0 R_AARCH64_GLOB_DAT myfunc 0x0 | |
| 39 | 37 | # CHECK-RELOCS-NEXT: } |
| 40 | 38 | # CHECK-RELOCS-NEXT: ] |
deps/lld/test/ELF/aarch64-gnu-ifunc-nonpreemptable.s created+72| ... | ... | @@ -0,0 +1,72 @@ |
| 1 | # REQUIRES: aarch64 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o | |
| 3 | ||
| 4 | # RUN: ld.lld %t.o -o %t | |
| 5 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=PDE | |
| 6 | # RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=PDE-RELOC | |
| 7 | ||
| 8 | # RUN: ld.lld -pie %t.o -o %t | |
| 9 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s --check-prefix=PIE | |
| 10 | # RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=PIE-RELOC | |
| 11 | ||
| 12 | ## When compiling with -fno-PIE or -fPIE, if the ifunc is in the same | |
| 13 | ## translation unit as the address taker, the compiler knows that ifunc is not | |
| 14 | ## defined in a shared library so it can use a non GOT generating relative reference. | |
| 15 | .text | |
| 16 | .globl myfunc | |
| 17 | .type myfunc,@gnu_indirect_function | |
| 18 | myfunc: | |
| 19 | .globl myfunc_resolver | |
| 20 | .type myfunc_resolver,@function | |
| 21 | myfunc_resolver: | |
| 22 | ret | |
| 23 | ||
| 24 | .text | |
| 25 | .globl main | |
| 26 | .type main,@function | |
| 27 | main: | |
| 28 | adrp x8, myfunc | |
| 29 | add x8, x8, :lo12: myfunc | |
| 30 | ret | |
| 31 | ||
| 32 | ## The address of myfunc is the address of the PLT entry for myfunc. | |
| 33 | # PDE: myfunc_resolver: | |
| 34 | # PDE-NEXT: 210000: ret | |
| 35 | # PDE: main: | |
| 36 | # PDE-NEXT: 210004: adrp x8, #0 | |
| 37 | # PDE-NEXT: 210008: add x8, x8, #16 | |
| 38 | # PDE-NEXT: 21000c: ret | |
| 39 | # PDE-EMPTY: | |
| 40 | # PDE-NEXT: Disassembly of section .plt: | |
| 41 | # PDE-EMPTY: | |
| 42 | # PDE-NEXT: myfunc: | |
| 43 | ## page(.got.plt) - page(0x210010) = 65536 | |
| 44 | # PDE-NEXT: 210010: adrp x16, #65536 | |
| 45 | # PDE-NEXT: 210014: ldr x17, [x16] | |
| 46 | # PDE-NEXT: 210018: add x16, x16, #0 | |
| 47 | # PDE-NEXT: 21001c: br x17 | |
| 48 | ||
| 49 | ## The adrp to myfunc should generate a PLT entry and a GOT entry with an | |
| 50 | ## irelative relocation. | |
| 51 | # PDE-RELOC: .rela.plt { | |
| 52 | # PDE-RELOC-NEXT: 0x220000 R_AARCH64_IRELATIVE - 0x210000 | |
| 53 | # PDE-RELOC-NEXT: } | |
| 54 | ||
| 55 | # PIE: myfunc_resolver: | |
| 56 | # PIE-NEXT: 10000: ret | |
| 57 | # PIE: main: | |
| 58 | # PIE-NEXT: 10004: adrp x8, #0 | |
| 59 | # PIE-NEXT: 10008: add x8, x8, #16 | |
| 60 | # PIE-NEXT: 1000c: ret | |
| 61 | # PIE-EMPTY: | |
| 62 | # PIE-NEXT: Disassembly of section .plt: | |
| 63 | # PIE-EMPTY: | |
| 64 | # PIE-NEXT: myfunc: | |
| 65 | # PIE-NEXT: 10010: adrp x16, #131072 | |
| 66 | # PIE-NEXT: 10014: ldr x17, [x16] | |
| 67 | # PIE-NEXT: 10018: add x16, x16, #0 | |
| 68 | # PIE-NEXT: 1001c: br x17 | |
| 69 | ||
| 70 | # PIE-RELOC: .rela.plt { | |
| 71 | # PIE-RELOC-NEXT: 0x30000 R_AARCH64_IRELATIVE - 0x10000 | |
| 72 | # PIE-RELOC-NEXT: } |
deps/lld/test/ELF/aarch64-gnu-ifunc-nosym.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: aarch64 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o |
| 3 | 3 | // RUN: ld.lld -static %t.o -o %tout |
| 4 | // RUN: llvm-readobj -symbols %tout | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols %tout | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // Check that no __rela_iplt_end/__rela_iplt_start |
| 7 | 7 | // appear in symtab if there is no references to them. |
deps/lld/test/ELF/aarch64-gnu-ifunc-plt.s+17-14| ... | ... | @@ -5,24 +5,24 @@ |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv %t.so %t.o -o %tout |
| 6 | 6 | // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM |
| 7 | 7 | // RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT |
| 8 | // RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s | |
| 8 | // RUN: llvm-readobj -r --dynamic-table %tout | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | // Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt |
| 11 | 11 | // CHECK: Relocations [ |
| 12 | 12 | // CHECK-NEXT: Section (4) .rela.plt { |
| 13 | // CHECK: 0x220018 R_AARCH64_JUMP_SLOT bar2 0x0 | |
| 14 | // CHECK-NEXT: 0x220020 R_AARCH64_JUMP_SLOT zed2 0x0 | |
| 15 | // CHECK-NEXT: 0x220028 R_AARCH64_IRELATIVE - 0x210000 | |
| 16 | // CHECK-NEXT: 0x220030 R_AARCH64_IRELATIVE - 0x210004 | |
| 13 | // CHECK: 0x230018 R_AARCH64_JUMP_SLOT bar2 0x0 | |
| 14 | // CHECK-NEXT: 0x230020 R_AARCH64_JUMP_SLOT zed2 0x0 | |
| 15 | // CHECK-NEXT: 0x230028 R_AARCH64_IRELATIVE - 0x210000 | |
| 16 | // CHECK-NEXT: 0x230030 R_AARCH64_IRELATIVE - 0x210004 | |
| 17 | 17 | // CHECK-NEXT: } |
| 18 | 18 | // CHECK-NEXT: ] |
| 19 | 19 | |
| 20 | 20 | // Check that .got.plt entries point back to PLT header |
| 21 | 21 | // GOTPLT: Contents of section .got.plt: |
| 22 | // GOTPLT-NEXT: 220000 00000000 00000000 00000000 00000000 | |
| 23 | // GOTPLT-NEXT: 220010 00000000 00000000 20002100 00000000 | |
| 24 | // GOTPLT-NEXT: 220020 20002100 00000000 20002100 00000000 | |
| 25 | // GOTPLT-NEXT: 220030 20002100 00000000 | |
| 22 | // GOTPLT-NEXT: 230000 00000000 00000000 00000000 00000000 | |
| 23 | // GOTPLT-NEXT: 230010 00000000 00000000 20002100 00000000 | |
| 24 | // GOTPLT-NEXT: 230020 20002100 00000000 20002100 00000000 | |
| 25 | // GOTPLT-NEXT: 230030 20002100 00000000 | |
| 26 | 26 | |
| 27 | 27 | // Check that the PLTRELSZ tag includes the IRELATIVE relocations |
| 28 | 28 | // CHECK: DynamicSection [ |
| ... | ... | @@ -30,6 +30,7 @@ |
| 30 | 30 | |
| 31 | 31 | // Check that a PLT header is written and the ifunc entries appear last |
| 32 | 32 | // DISASM: Disassembly of section .text: |
| 33 | // DISASM-EMPTY: | |
| 33 | 34 | // DISASM-NEXT: foo: |
| 34 | 35 | // DISASM-NEXT: 210000: {{.*}} ret |
| 35 | 36 | // DISASM: bar: |
| ... | ... | @@ -39,10 +40,12 @@ |
| 39 | 40 | // DISASM-NEXT: 21000c: {{.*}} bl #100 |
| 40 | 41 | // DISASM-NEXT: 210010: {{.*}} bl #48 |
| 41 | 42 | // DISASM-NEXT: 210014: {{.*}} bl #60 |
| 43 | // DISASM-EMPTY: | |
| 42 | 44 | // DISASM-NEXT: Disassembly of section .plt: |
| 45 | // DISASM-EMPTY: | |
| 43 | 46 | // DISASM-NEXT: .plt: |
| 44 | 47 | // DISASM-NEXT: 210020: {{.*}} stp x16, x30, [sp, #-16]! |
| 45 | // DISASM-NEXT: 210024: {{.*}} adrp x16, #65536 | |
| 48 | // DISASM-NEXT: 210024: {{.*}} adrp x16, #131072 | |
| 46 | 49 | // DISASM-NEXT: 210028: {{.*}} ldr x17, [x16, #16] |
| 47 | 50 | // DISASM-NEXT: 21002c: {{.*}} add x16, x16, #16 |
| 48 | 51 | // DISASM-NEXT: 210030: {{.*}} br x17 |
| ... | ... | @@ -51,21 +54,21 @@ |
| 51 | 54 | // DISASM-NEXT: 21003c: {{.*}} nop |
| 52 | 55 | // DISASM-EMPTY: |
| 53 | 56 | // DISASM-NEXT: bar2@plt: |
| 54 | // DISASM-NEXT: 210040: {{.*}} adrp x16, #65536 | |
| 57 | // DISASM-NEXT: 210040: {{.*}} adrp x16, #131072 | |
| 55 | 58 | // DISASM-NEXT: 210044: {{.*}} ldr x17, [x16, #24] |
| 56 | 59 | // DISASM-NEXT: 210048: {{.*}} add x16, x16, #24 |
| 57 | 60 | // DISASM-NEXT: 21004c: {{.*}} br x17 |
| 58 | 61 | // DISASM-EMPTY: |
| 59 | 62 | // DISASM-NEXT: zed2@plt: |
| 60 | // DISASM-NEXT: 210050: {{.*}} adrp x16, #65536 | |
| 63 | // DISASM-NEXT: 210050: {{.*}} adrp x16, #131072 | |
| 61 | 64 | // DISASM-NEXT: 210054: {{.*}} ldr x17, [x16, #32] |
| 62 | 65 | // DISASM-NEXT: 210058: {{.*}} add x16, x16, #32 |
| 63 | 66 | // DISASM-NEXT: 21005c: {{.*}} br x17 |
| 64 | // DISASM-NEXT: 210060: {{.*}} adrp x16, #65536 | |
| 67 | // DISASM-NEXT: 210060: {{.*}} adrp x16, #131072 | |
| 65 | 68 | // DISASM-NEXT: 210064: {{.*}} ldr x17, [x16, #40] |
| 66 | 69 | // DISASM-NEXT: 210068: {{.*}} add x16, x16, #40 |
| 67 | 70 | // DISASM-NEXT: 21006c: {{.*}} br x17 |
| 68 | // DISASM-NEXT: 210070: {{.*}} adrp x16, #65536 | |
| 71 | // DISASM-NEXT: 210070: {{.*}} adrp x16, #131072 | |
| 69 | 72 | // DISASM-NEXT: 210074: {{.*}} ldr x17, [x16, #48] |
| 70 | 73 | // DISASM-NEXT: 210078: {{.*}} add x16, x16, #48 |
| 71 | 74 | // DISASM-NEXT: 21007c: {{.*}} br x17 |
deps/lld/test/ELF/aarch64-gnu-ifunc.s+4-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o |
| 3 | 3 | // RUN: ld.lld -static %t.o -o %tout |
| 4 | 4 | // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM |
| 5 | // RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s | |
| 5 | // RUN: llvm-readobj -r --symbols --sections %tout | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // CHECK: Sections [ |
| 8 | 8 | // CHECK: Section { |
| ... | ... | @@ -100,6 +100,7 @@ |
| 100 | 100 | // 392 = 0x188 |
| 101 | 101 | |
| 102 | 102 | // DISASM: Disassembly of section .text: |
| 103 | // DISASM-EMPTY: | |
| 103 | 104 | // DISASM-NEXT: foo: |
| 104 | 105 | // DISASM-NEXT: 210000: c0 03 5f d6 ret |
| 105 | 106 | // DISASM: bar: |
| ... | ... | @@ -109,7 +110,9 @@ |
| 109 | 110 | // DISASM-NEXT: 21000c: 09 00 00 94 bl #36 |
| 110 | 111 | // DISASM-NEXT: 210010: 42 60 05 91 add x2, x2, #344 |
| 111 | 112 | // DISASM-NEXT: 210014: 42 20 06 91 add x2, x2, #392 |
| 113 | // DISASM-EMPTY: | |
| 112 | 114 | // DISASM-NEXT: Disassembly of section .plt: |
| 115 | // DISASM-EMPTY: | |
| 113 | 116 | // DISASM-NEXT: .plt: |
| 114 | 117 | // DISASM-NEXT: 210020: 90 00 00 90 adrp x16, #65536 |
| 115 | 118 | // DISASM-NEXT: 210024: 11 02 40 f9 ldr x17, [x16] |
deps/lld/test/ELF/aarch64-gnu-ifunc2.s+5-7| ... | ... | @@ -5,16 +5,18 @@ |
| 5 | 5 | # RUN: llvm-readobj -r %tout | FileCheck %s --check-prefix=RELOC |
| 6 | 6 | |
| 7 | 7 | # CHECK: Disassembly of section .text: |
| 8 | # CHECK-EMPTY: | |
| 8 | 9 | # CHECK-NEXT: myfunc: |
| 9 | 10 | # CHECK-NEXT: 210000: |
| 10 | 11 | |
| 11 | 12 | # CHECK: main: |
| 12 | # adrp x8, 0x230000, 0x230000 == address in .got | |
| 13 | # CHECK-NEXT: 210004: {{.*}} adrp x8, #131072 | |
| 13 | # adrp x8, 0x220000, 0x220000 == address in .got.plt | |
| 14 | # CHECK-NEXT: 210004: {{.*}} adrp x8, #65536 | |
| 14 | 15 | # CHECK-NEXT: 210008: {{.*}} ldr x8, [x8] |
| 15 | 16 | # CHECK-NEXT: 21000c: {{.*}} ret |
| 16 | 17 | |
| 17 | 18 | # CHECK: Disassembly of section .plt: |
| 19 | # CHECK-EMPTY: | |
| 18 | 20 | # CHECK-NEXT: .plt: |
| 19 | 21 | # adrp x16, 0x220000, 0x220000 == address in .got.plt |
| 20 | 22 | # CHECK-NEXT: 210010: {{.*}} adrp x16, #65536 |
| ... | ... | @@ -23,14 +25,10 @@ |
| 23 | 25 | # CHECK-NEXT: 21001c: {{.*}} br x17 |
| 24 | 26 | |
| 25 | 27 | # CHECK: Disassembly of section .got.plt: |
| 28 | # CHECK-EMPTY: | |
| 26 | 29 | # CHECK-NEXT: .got.plt: |
| 27 | 30 | # CHECK-NEXT: 220000: |
| 28 | 31 | |
| 29 | # CHECK: Disassembly of section .got: | |
| 30 | # CHECK-NEXT: .got: | |
| 31 | # 0x210010 == address in .plt | |
| 32 | # CHECK-NEXT: 230000: 10 00 21 00 | |
| 33 | ||
| 34 | 32 | # RELOC: Relocations [ |
| 35 | 33 | # RELOC-NEXT: Section {{.*}} .rela.plt { |
| 36 | 34 | # RELOC-NEXT: 0x220000 R_AARCH64_IRELATIVE - 0x210000 |
deps/lld/test/ELF/aarch64-gnu-ifunc3.s deleted-49| ... | ... | @@ -1,49 +0,0 @@ |
| 1 | # REQUIRES: aarch64 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o | |
| 3 | # RUN: ld.lld -static %t.o -o %tout | |
| 4 | # RUN: llvm-objdump -D %tout | FileCheck %s | |
| 5 | # RUN: llvm-readobj -r %tout | FileCheck %s --check-prefix=RELOC | |
| 6 | ||
| 7 | # The address of myfunc is the address of the PLT entry for myfunc. | |
| 8 | # The adrp to myfunc should generate a PLT entry and a got entry with an | |
| 9 | # irelative relocation. | |
| 10 | .text | |
| 11 | .globl myfunc | |
| 12 | .type myfunc,@gnu_indirect_function | |
| 13 | myfunc: | |
| 14 | ret | |
| 15 | ||
| 16 | .text | |
| 17 | .globl _start | |
| 18 | .type _start,@function | |
| 19 | _start: | |
| 20 | adrp x8, myfunc | |
| 21 | add x8, x8, :lo12:myfunc | |
| 22 | ret | |
| 23 | ||
| 24 | # CHECK: Disassembly of section .text: | |
| 25 | # CHECK-NEXT: myfunc: | |
| 26 | # CHECK-NEXT: 210000:	c0 03 5f d6 	ret | |
| 27 | # CHECK: _start: | |
| 28 | # adrp x8, 0x210000 + 0x10 from add == .plt entry | |
| 29 | # CHECK-NEXT: 210004:	08 00 00 90 	adrp	x8, #0 | |
| 30 | # CHECK-NEXT: 210008:	08 41 00 91 	add	x8, x8, #16 | |
| 31 | # CHECK-NEXT: 21000c:	c0 03 5f d6 	ret | |
| 32 | # CHECK-NEXT: Disassembly of section .plt: | |
| 33 | # CHECK-NEXT: .plt: | |
| 34 | # adrp x16, 0x220000, 0x220000 == address in .got.plt | |
| 35 | # CHECK-NEXT: 210010:	90 00 00 90 	adrp	x16, #65536 | |
| 36 | # CHECK-NEXT: 210014:	11 02 40 f9 	ldr	x17, [x16] | |
| 37 | # CHECK-NEXT: 210018:	10 02 00 91 	add	x16, x16, #0 | |
| 38 | # CHECK-NEXT: 21001c:	20 02 1f d6 	br	x17 | |
| 39 | # CHECK-NEXT: Disassembly of section .got.plt: | |
| 40 | # CHECK-NEXT: .got.plt: | |
| 41 | # 0x210010 == address in .plt | |
| 42 | # CHECK-NEXT: 220000:	10 00 21 00 | |
| 43 | # CHECK-NEXT: 220004:	00 00 00 00 | |
| 44 | ||
| 45 | # RELOC: Relocations [ | |
| 46 | # RELOC-NEXT: Section (1) .rela.plt { | |
| 47 | # RELOC-NEXT: 0x220000 R_AARCH64_IRELATIVE - 0x210000 | |
| 48 | # RELOC-NEXT: } | |
| 49 | # RELOC-NEXT: ] |
deps/lld/test/ELF/aarch64-got-reloc.s deleted-30| ... | ... | @@ -1,30 +0,0 @@ |
| 1 | // REQUIRES: aarch64 | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o | |
| 3 | // RUN: ld.lld %t.o -o %t | |
| 4 | // RUN: llvm-readobj -s --section-data %t | FileCheck %s | |
| 5 | ||
| 6 | // CHECK: Name: .got | |
| 7 | // CHECK-NEXT: Type: SHT_PROGBITS | |
| 8 | // CHECK-NEXT: Flags [ | |
| 9 | // CHECK-NEXT: SHF_ALLOC | |
| 10 | // CHECK-NEXT: SHF_WRITE | |
| 11 | // CHECK-NEXT: ] | |
| 12 | // CHECK-NEXT: Address: | |
| 13 | // CHECK-NEXT: Offset: | |
| 14 | // CHECK-NEXT: Size: 8 | |
| 15 | // CHECK-NEXT: Link: 0 | |
| 16 | // CHECK-NEXT: Info: 0 | |
| 17 | // CHECK-NEXT: AddressAlignment: 8 | |
| 18 | // CHECK-NEXT: EntrySize: 0 | |
| 19 | // CHECK-NEXT: SectionData ( | |
| 20 | // CHECK-NEXT: 0000: 00000000 00000000 |........| | |
| 21 | // CHECK-NEXT: ) | |
| 22 | ||
| 23 | .globl _start | |
| 24 | _start: | |
| 25 | adrp x8, :got:foo | |
| 26 | ldr x8, [x8, :got_lo12:foo] | |
| 27 | ldr w0, [x8] | |
| 28 | ret | |
| 29 | ||
| 30 | .weak foo |
deps/lld/test/ELF/aarch64-got-weak-undef.s created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | // REQUIRES: aarch64 | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o | |
| 3 | // RUN: ld.lld %t.o -o %t | |
| 4 | // RUN: llvm-readelf -r %t | FileCheck --check-prefix=RELOC %s | |
| 5 | // RUN: llvm-readelf -x .got %t | FileCheck %s | |
| 6 | ||
| 7 | // RELOC: no relocations | |
| 8 | ||
| 9 | // CHECK: 0x00220000 00000000 00000000 | |
| 10 | ||
| 11 | .globl _start | |
| 12 | _start: | |
| 13 | adrp x8, :got:foo | |
| 14 | ldr x8, [x8, :got_lo12:foo] | |
| 15 | ldr w0, [x8] | |
| 16 | ret | |
| 17 | ||
| 18 | .weak foo |
deps/lld/test/ELF/aarch64-got.s deleted-18| ... | ... | @@ -1,18 +0,0 @@ |
| 1 | # REQUIRES: aarch64 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -o %t | |
| 4 | # RUN: llvm-readobj -s %t | FileCheck %s | |
| 5 | ||
| 6 | # CHECK-NOT: Name: .got | |
| 7 | ||
| 8 | .globl _start | |
| 9 | _start: | |
| 10 | adrp x0, :gottprel:foo | |
| 11 | ||
| 12 | 	.global foo | |
| 13 | .section .tdata,"awT",%progbits | |
| 14 | .align 2 | |
| 15 | .type foo, %object | |
| 16 | .size foo, 4 | |
| 17 | foo: | |
| 18 | .word 5 |
deps/lld/test/ELF/aarch64-hi21-nc.s created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | // REQUIRES: aarch64 | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %t.o | |
| 3 | // RUN: ld.lld %t.o -o %t | |
| 4 | // RUN: llvm-objdump -d %t | FileCheck %s | |
| 5 | ||
| 6 | foo = . + 0x1100000000000000 | |
| 7 | // CHECK: adrp x0, #0 | |
| 8 | adrp x0, :pg_hi21_nc:foo |
deps/lld/test/ELF/aarch64-ifunc-bti.s created+65| ... | ... | @@ -0,0 +1,65 @@ |
| 1 | # REQUIRES: aarch64 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %p/Inputs/aarch64-addrifunc.s -o %t1.o | |
| 4 | ||
| 5 | # RUN: ld.lld --shared %t1.o -o %t1.so | |
| 6 | # RUN: ld.lld --pie %t1.so %t.o -o %t | |
| 7 | # RUN: llvm-objdump -d -mattr=+bti -triple=aarch64-linux-gnu %t | FileCheck %s | |
| 8 | ||
| 9 | # When the address of an ifunc is taken using a non-got reference which clang | |
| 10 | # can do, LLD exports a canonical PLT entry that may have its address taken so | |
| 11 | # we must use bti c. | |
| 12 | ||
| 13 | # CHECK: Disassembly of section .plt: | |
| 14 | # CHECK: 0000000000010020 .plt: | |
| 15 | # CHECK-NEXT: 10020: 5f 24 03 d5 bti c | |
| 16 | # CHECK-NEXT: 10024: f0 7b bf a9 stp x16, x30, [sp, #-16]! | |
| 17 | # CHECK-NEXT: 10028: 10 01 00 90 adrp x16, #131072 | |
| 18 | # CHECK-NEXT: 1002c: 11 0a 40 f9 ldr x17, [x16, #16] | |
| 19 | # CHECK-NEXT: 10030: 10 42 00 91 add x16, x16, #16 | |
| 20 | # CHECK-NEXT: 10034: 20 02 1f d6 br x17 | |
| 21 | # CHECK-NEXT: 10038: 1f 20 03 d5 nop | |
| 22 | # CHECK-NEXT: 1003c: 1f 20 03 d5 nop | |
| 23 | # CHECK: 0000000000010040 func1@plt: | |
| 24 | # CHECK-NEXT: 10040: 5f 24 03 d5 bti c | |
| 25 | # CHECK-NEXT: 10044: 10 01 00 90 adrp x16, #131072 | |
| 26 | # CHECK-NEXT: 10048: 11 0e 40 f9 ldr x17, [x16, #24] | |
| 27 | # CHECK-NEXT: 1004c: 10 62 00 91 add x16, x16, #24 | |
| 28 | # CHECK-NEXT: 10050: 20 02 1f d6 br x17 | |
| 29 | # CHECK-NEXT: 10054: 1f 20 03 d5 nop | |
| 30 | # CHECK-NEXT: ... | |
| 31 | # CHECK: 0000000000010060 myfunc: | |
| 32 | # CHECK-NEXT: 10060: 5f 24 03 d5 bti c | |
| 33 | # CHECK-NEXT: 10064: 10 01 00 90 adrp x16, #131072 | |
| 34 | # CHECK-NEXT: 10068: 11 12 40 f9 ldr x17, [x16, #32] | |
| 35 | # CHECK-NEXT: 1006c: 10 82 00 91 add x16, x16, #32 | |
| 36 | # CHECK-NEXT: 10070: 20 02 1f d6 br x17 | |
| 37 | # CHECK-NEXT: 10074: 1f 20 03 d5 nop | |
| 38 | ||
| 39 | .section ".note.gnu.property", "a" | |
| 40 | .long 4 | |
| 41 | .long 0x10 | |
| 42 | .long 0x5 | |
| 43 | .asciz "GNU" | |
| 44 | ||
| 45 | .long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND | |
| 46 | .long 4 | |
| 47 | .long 1 // GNU_PROPERTY_AARCH64_FEATURE_1_BTI | |
| 48 | .long 0 | |
| 49 | ||
| 50 | .text | |
| 51 | .globl myfunc | |
| 52 | .type myfunc,@gnu_indirect_function | |
| 53 | myfunc: | |
| 54 | ret | |
| 55 | ||
| 56 | .globl func1 | |
| 57 | ||
| 58 | .text | |
| 59 | .globl _start | |
| 60 | .type _start, %function | |
| 61 | _start: | |
| 62 | bl func1 | |
| 63 | adrp x8, myfunc | |
| 64 | add x8, x8, :lo12:myfunc | |
| 65 | ret |
deps/lld/test/ELF/aarch64-jump26-thunk.s+1| ... | ... | @@ -10,6 +10,7 @@ _start: |
| 10 | 10 | b big |
| 11 | 11 | |
| 12 | 12 | // CHECK: Disassembly of section .text: |
| 13 | // CHECK-EMPTY: | |
| 13 | 14 | // CHECK-NEXT: _start: |
| 14 | 15 | // CHECK-NEXT: 210000: 02 00 00 14 b #8 |
| 15 | 16 | // CHECK: __AArch64AbsLongThunk_big: |
deps/lld/test/ELF/aarch64-ldprel-lo19-invalid.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-none %s -o %t.o |
| 4 | 4 | # RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s |
| 5 | 5 | |
| 6 | # CHECK: relocation R_AARCH64_LD_PREL_LO19 out of range: 2065536 is not in [-1048576, 1048575] | |
| 6 | # CHECK: relocation R_AARCH64_LD_PREL_LO19 out of range: 2131072 is not in [-1048576, 1048575] | |
| 7 | 7 | |
| 8 | 8 | ldr x8, patatino |
| 9 | 9 | .data |
deps/lld/test/ELF/aarch64-load-alignment.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-none %s -o %t.o |
| 4 | 4 | # RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s |
| 5 | 5 | |
| 6 | # CHECK: improper alignment for relocation R_AARCH64_LD_PREL_LO19: 0x10005 is not aligned to 4 bytes | |
| 6 | # CHECK: improper alignment for relocation R_AARCH64_LD_PREL_LO19: 0x20005 is not aligned to 4 bytes | |
| 7 | 7 | |
| 8 | 8 | ldr x8, patatino |
| 9 | 9 | .data |
deps/lld/test/ELF/aarch64-nopic-plt.s created+27| ... | ... | @@ -0,0 +1,27 @@ |
| 1 | // REQUIRES: aarch64 | |
| 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=aarch64-pc-linux | |
| 3 | // RUN: llvm-mc %p/Inputs/aarch64-copy2.s -o %t2.o -filetype=obj -triple=aarch64-pc-linux | |
| 4 | // RUN: ld.lld %t2.o -o %t2.so -shared | |
| 5 | // RUN: ld.lld %t.o %t2.so -o %t | |
| 6 | // RUN: llvm-readobj --symbols %t | FileCheck %s | |
| 7 | ||
| 8 | .global _start | |
| 9 | _start: | |
| 10 | adrp x8, foo | |
| 11 | bl bar | |
| 12 | ||
| 13 | // CHECK: Name: bar | |
| 14 | // CHECK-NEXT: Value: 0x0 | |
| 15 | // CHECK-NEXT: Size: 0 | |
| 16 | // CHECK-NEXT: Binding: Global | |
| 17 | // CHECK-NEXT: Type: None | |
| 18 | // CHECK-NEXT: Other: 0 | |
| 19 | // CHECK-NEXT: Section: Undefined | |
| 20 | ||
| 21 | // CHECK: Name: foo | |
| 22 | // CHECK-NEXT: Value: 0x210030 | |
| 23 | // CHECK-NEXT: Size: 0 | |
| 24 | // CHECK-NEXT: Binding: Global | |
| 25 | // CHECK-NEXT: Type: Function | |
| 26 | // CHECK-NEXT: Other: 0 | |
| 27 | // CHECK-NEXT: Section: Undefined |
deps/lld/test/ELF/aarch64-prel16.s+2-2| ... | ... | @@ -25,7 +25,7 @@ _start: |
| 25 | 25 | // CHECK-NEXT: 201000 ffff0080 |
| 26 | 26 | |
| 27 | 27 | // RUN: not ld.lld -z max-page-size=4096 %t.o %t255.o -o %t2 2>&1 | FileCheck %s --check-prefix=OVERFLOW1 |
| 28 | // OVERFLOW1: relocation R_AARCH64_PREL16 out of range: -32769 is not in [-32768, 32767] | |
| 28 | // OVERFLOW1: relocation R_AARCH64_PREL16 out of range: -32769 is not in [-32768, 65535] | |
| 29 | 29 | |
| 30 | 30 | // RUN: not ld.lld -z max-page-size=4096 %t.o %t257.o -o %t2 2>&1 | FileCheck %s --check-prefix=OVERFLOW2 |
| 31 | // OVERFLOW2: relocation R_AARCH64_PREL16 out of range: 65536 is not in [-32768, 32767] | |
| 31 | // OVERFLOW2: relocation R_AARCH64_PREL16 out of range: 65536 is not in [-32768, 65535] |
deps/lld/test/ELF/aarch64-prel32.s+2-2| ... | ... | @@ -25,7 +25,7 @@ _start: |
| 25 | 25 | // CHECK-NEXT: 201000 ffffffff 00000080 |
| 26 | 26 | |
| 27 | 27 | // RUN: not ld.lld -z max-page-size=4096 %t.o %t255.o -o %t2 2>&1 | FileCheck %s --check-prefix=OVERFLOW1 |
| 28 | // OVERFLOW1: relocation R_AARCH64_PREL32 out of range: -2147483649 is not in [-2147483648, 2147483647] | |
| 28 | // OVERFLOW1: relocation R_AARCH64_PREL32 out of range: -2147483649 is not in [-2147483648, 4294967295] | |
| 29 | 29 | |
| 30 | 30 | // RUN: not ld.lld -z max-page-size=4096 %t.o %t257.o -o %t2 2>&1 | FileCheck %s --check-prefix=OVERFLOW2 |
| 31 | // OVERFLOW2: relocation R_AARCH64_PREL32 out of range: 4294967296 is not in [-2147483648, 2147483647] | |
| 31 | // OVERFLOW2: relocation R_AARCH64_PREL32 out of range: 4294967296 is not in [-2147483648, 4294967295] |
deps/lld/test/ELF/aarch64-property-relocatable.s created+36| ... | ... | @@ -0,0 +1,36 @@ |
| 1 | # REQUIRES: aarch64 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t.o | |
| 3 | # RUN: ld.lld -r %t.o -o %t2.o | |
| 4 | # RUN: llvm-readelf -n %t2.o | FileCheck -match-full-lines %s | |
| 5 | ||
| 6 | ## Test that .note.gnu.property is passed through -r, and that we can handle | |
| 7 | ## more than one FEATURE_AND in the same object file. This is logically the | |
| 8 | ## same as if the features were combined in a single FEATURE_AND as the rule | |
| 9 | ## states that the bit in the output pr_data field if it is set in all | |
| 10 | .text | |
| 11 | ret | |
| 12 | ||
| 13 | .section ".note.gnu.property", "a" | |
| 14 | .p2align 3 | |
| 15 | .long 4 | |
| 16 | .long 0x10 | |
| 17 | .long 0x5 | |
| 18 | .asciz "GNU" | |
| 19 | ||
| 20 | .long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND | |
| 21 | .long 4 | |
| 22 | .long 1 // GNU_PROPERTY_AARCH64_FEATURE_1_BTI | |
| 23 | .long 0 | |
| 24 | ||
| 25 | .long 4 | |
| 26 | .long 0x10 | |
| 27 | .long 0x5 | |
| 28 | .asciz "GNU" | |
| 29 | .long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND | |
| 30 | .long 4 | |
| 31 | .long 2 // GNU_PROPERTY_AARCH64_FEATURE_1_PAC | |
| 32 | .long 0 | |
| 33 | ||
| 34 | # CHECK: Owner Data size	Description | |
| 35 | # CHECK-NEXT: GNU 0x00000010	NT_GNU_PROPERTY_TYPE_0 (property note) | |
| 36 | # CHECK-NEXT: Properties: aarch64 feature: BTI, PAC |
deps/lld/test/ELF/aarch64-relocs.s+12| ... | ... | @@ -12,6 +12,7 @@ msg: .asciz "Hello, world\n" |
| 12 | 12 | msgend: |
| 13 | 13 | |
| 14 | 14 | # CHECK: Disassembly of section .R_AARCH64_ADR_PREL_LO21: |
| 15 | # CHECK-EMPTY: | |
| 15 | 16 | # CHECK: _start: |
| 16 | 17 | # CHECK: 0: 21 00 00 10 adr x1, #4 |
| 17 | 18 | # CHECK: msg: |
| ... | ... | @@ -29,6 +30,7 @@ mystr: |
| 29 | 30 | # PAGE(P) = 0x210000 |
| 30 | 31 | # |
| 31 | 32 | # CHECK: Disassembly of section .R_AARCH64_ADR_PREL_PG_H121: |
| 33 | # CHECK-EMPTY: | |
| 32 | 34 | # CHECK-NEXT: $x.2: |
| 33 | 35 | # CHECK-NEXT: 210012: 01 00 00 90 adrp x1, #0 |
| 34 | 36 | |
| ... | ... | @@ -43,6 +45,7 @@ mystr: |
| 43 | 45 | # R << 10 = 0x7c00 |
| 44 | 46 | # |
| 45 | 47 | # CHECK: Disassembly of section .R_AARCH64_ADD_ABS_LO12_NC: |
| 48 | # CHECK-EMPTY: | |
| 46 | 49 | # CHECK-NEXT: $x.4: |
| 47 | 50 | # CHECK-NEXT: 21001b: 00 7c 00 91 add x0, x0, #31 |
| 48 | 51 | |
| ... | ... | @@ -56,6 +59,7 @@ foo: |
| 56 | 59 | # R = ((S + A) & 0xFFF) << 7 = 0x00001400 |
| 57 | 60 | # 0x00001400 | 0xf940177c = 0xf940177c |
| 58 | 61 | # CHECK: Disassembly of section .R_AARCH64_LDST64_ABS_LO12_NC: |
| 62 | # CHECK-EMPTY: | |
| 59 | 63 | # CHECK-NEXT: $x.6: |
| 60 | 64 | # CHECK-NEXT: 210024: 7c 17 40 f9 ldr x28, [x27, #40] |
| 61 | 65 | |
| ... | ... | @@ -65,6 +69,7 @@ sub: |
| 65 | 69 | nop |
| 66 | 70 | |
| 67 | 71 | # CHECK: Disassembly of section .SUB: |
| 72 | # CHECK-EMPTY: | |
| 68 | 73 | # CHECK-NEXT: $x.8: |
| 69 | 74 | # CHECK-NEXT: 21002c: 1f 20 03 d5 nop |
| 70 | 75 | # CHECK: sub: |
| ... | ... | @@ -79,6 +84,7 @@ call26: |
| 79 | 84 | # (R & 0x0ffffffc) >> 2 = 0x03ffffff |
| 80 | 85 | # 0x94000000 | 0x03ffffff = 0x97ffffff |
| 81 | 86 | # CHECK: Disassembly of section .R_AARCH64_CALL26: |
| 87 | # CHECK-EMPTY: | |
| 82 | 88 | # CHECK-NEXT: call26: |
| 83 | 89 | # CHECK-NEXT: 210034: ff ff ff 97 bl #-4 |
| 84 | 90 | |
| ... | ... | @@ -91,6 +97,7 @@ jump26: |
| 91 | 97 | # (R & 0x0ffffffc) >> 2 = 0x03fffffe |
| 92 | 98 | # 0x14000000 | 0x03fffffe = 0x17fffffe |
| 93 | 99 | # CHECK: Disassembly of section .R_AARCH64_JUMP26: |
| 100 | # CHECK-EMPTY: | |
| 94 | 101 | # CHECK-NEXT: jump26: |
| 95 | 102 | # CHECK-NEXT: 210038: fe ff ff 17 b #-8 |
| 96 | 103 | |
| ... | ... | @@ -105,6 +112,7 @@ foo32: |
| 105 | 112 | # R = ((S + A) & 0xFFC) << 8 = 0x00004000 |
| 106 | 113 | # 0x00004000 | 0xbd4000a4 = 0xbd4040a4 |
| 107 | 114 | # CHECK: Disassembly of section .R_AARCH64_LDST32_ABS_LO12_NC: |
| 115 | # CHECK-EMPTY: | |
| 108 | 116 | # CHECK-NEXT: ldst32: |
| 109 | 117 | # CHECK-NEXT: 21003c: a4 40 40 bd ldr s4, [x5, #64] |
| 110 | 118 | |
| ... | ... | @@ -119,6 +127,7 @@ foo8: |
| 119 | 127 | # R = ((S + A) & 0xFFF) << 10 = 0x00012000 |
| 120 | 128 | # 0x00012000 | 0x398001ab = 0x398121ab |
| 121 | 129 | # CHECK: Disassembly of section .R_AARCH64_LDST8_ABS_LO12_NC: |
| 130 | # CHECK-EMPTY: | |
| 122 | 131 | # CHECK-NEXT: ldst8: |
| 123 | 132 | # CHECK-NEXT: 210044: ab 21 81 39 ldrsb x11, [x13, #72] |
| 124 | 133 | |
| ... | ... | @@ -133,6 +142,7 @@ foo128: |
| 133 | 142 | # R = ((S + A) & 0xFF8) << 6 = 0x00001400 |
| 134 | 143 | # 0x00001400 | 0x3dc00274 = 0x3dc01674 |
| 135 | 144 | # CHECK: Disassembly of section .R_AARCH64_LDST128_ABS_LO12_NC: |
| 145 | # CHECK-EMPTY: | |
| 136 | 146 | # CHECK: ldst128: |
| 137 | 147 | # CHECK: 21004c: 74 16 c0 3d ldr q20, [x19, #80] |
| 138 | 148 | #foo128: |
| ... | ... | @@ -151,6 +161,7 @@ foo16: |
| 151 | 161 | # R = ((S + A) & 0x0FFC) << 9 = 0xb000 |
| 152 | 162 | # 0xb000 | 0x7d400271 = 0x7d40b271 |
| 153 | 163 | # CHECK: Disassembly of section .R_AARCH64_LDST16_ABS_LO12_NC: |
| 164 | # CHECK-EMPTY: | |
| 154 | 165 | # CHECK-NEXT: ldst16: |
| 155 | 166 | # CHECK-NEXT: 210054: 71 c2 40 7d ldr h17, [x19, #96] |
| 156 | 167 | # CHECK-NEXT: 210058: 61 c2 40 79 ldrh w1, [x19, #96] |
| ... | ... | @@ -166,6 +177,7 @@ movz1: |
| 166 | 177 | |
| 167 | 178 | ## 4222124650659840 == (0xF << 48) |
| 168 | 179 | # CHECK: Disassembly of section .R_AARCH64_MOVW_UABS: |
| 180 | # CHECK-EMPTY: | |
| 169 | 181 | # CHECK-NEXT: movz1: |
| 170 | 182 | # CHECK-NEXT: 8c 01 80 f2 movk x12, #12 |
| 171 | 183 | # CHECK-NEXT: ad 01 a0 f2 movk x13, #13, lsl #16 |
deps/lld/test/ELF/aarch64-relro.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: aarch64 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t |
| 3 | 3 | # RUN: ld.lld %t -o %t2 |
| 4 | # RUN: llvm-readobj -program-headers %t2 | FileCheck %s | |
| 4 | # RUN: llvm-readobj -l %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: Type: PT_GNU_RELRO |
| 7 | 7 | # CHECK-NEXT: Offset: |
deps/lld/test/ELF/aarch64-thunk-pi.s+7-6| ... | ... | @@ -72,11 +72,12 @@ high_target2: |
| 72 | 72 | // CHECK-NEXT: 10000018:	00 02 1f d6 	br	x16 |
| 73 | 73 | |
| 74 | 74 | // CHECK: Disassembly of section .plt: |
| 75 | // CHECK-EMPTY: | |
| 75 | 76 | // CHECK-NEXT: .plt: |
| 76 | 77 | // CHECK-NEXT: 10000020: f0 7b bf a9 stp x16, x30, [sp, #-16]! |
| 77 | 78 | // CHECK-NEXT: 10000024: 10 00 00 90 adrp x16, #0 |
| 78 | // CHECK-NEXT: 10000028: 11 3a 40 f9 ldr x17, [x16, #112] | |
| 79 | // CHECK-NEXT: 1000002c: 10 c2 01 91 add x16, x16, #112 | |
| 79 | // CHECK-NEXT: 10000028: 11 92 40 f9 ldr x17, [x16, #288] | |
| 80 | // CHECK-NEXT: 1000002c: 10 82 04 91 add x16, x16, #288 | |
| 80 | 81 | // CHECK-NEXT: 10000030: 20 02 1f d6 br x17 |
| 81 | 82 | // CHECK-NEXT: 10000034: 1f 20 03 d5 nop |
| 82 | 83 | // CHECK-NEXT: 10000038: 1f 20 03 d5 nop |
| ... | ... | @@ -84,12 +85,12 @@ high_target2: |
| 84 | 85 | // CHECK-EMPTY: |
| 85 | 86 | // CHECK-NEXT: high_target@plt: |
| 86 | 87 | // CHECK-NEXT: 10000040: 10 00 00 90 adrp x16, #0 |
| 87 | // CHECK-NEXT: 10000044: 11 3e 40 f9 ldr x17, [x16, #120] | |
| 88 | // CHECK-NEXT: 10000048: 10 e2 01 91 add x16, x16, #120 | |
| 88 | // CHECK-NEXT: 10000044: 11 96 40 f9 ldr x17, [x16, #296] | |
| 89 | // CHECK-NEXT: 10000048: 10 a2 04 91 add x16, x16, #296 | |
| 89 | 90 | // CHECK-NEXT: 1000004c: 20 02 1f d6 br x17 |
| 90 | 91 | // CHECK-EMPTY: |
| 91 | 92 | // CHECK-NEXT: low_target@plt: |
| 92 | 93 | // CHECK-NEXT: 10000050: 10 00 00 90 adrp x16, #0 |
| 93 | // CHECK-NEXT: 10000054: 11 42 40 f9 ldr x17, [x16, #128] | |
| 94 | // CHECK-NEXT: 10000058: 10 02 02 91 add x16, x16, #128 | |
| 94 | // CHECK-NEXT: 10000054: 11 9a 40 f9 ldr x17, [x16, #304] | |
| 95 | // CHECK-NEXT: 10000058: 10 c2 04 91 add x16, x16, #304 | |
| 95 | 96 | // CHECK-NEXT: 1000005c: 20 02 1f d6 br x17 |
deps/lld/test/ELF/aarch64-thunk-script.s+2| ... | ... | @@ -26,6 +26,7 @@ high_target: |
| 26 | 26 | ret |
| 27 | 27 | |
| 28 | 28 | // CHECK: Disassembly of section .text_low: |
| 29 | // CHECK-EMPTY: | |
| 29 | 30 | // CHECK-NEXT: _start: |
| 30 | 31 | // CHECK-NEXT: 2000: 02 00 00 94 bl #8 |
| 31 | 32 | // CHECK-NEXT: 2004: c0 03 5f d6 ret |
| ... | ... | @@ -36,6 +37,7 @@ high_target: |
| 36 | 37 | // CHECK-NEXT: 2010: 00 20 00 08 .word 0x08002000 |
| 37 | 38 | // CHECK-NEXT: 2014: 00 00 00 00 .word 0x00000000 |
| 38 | 39 | // CHECK: Disassembly of section .text_high: |
| 40 | // CHECK-EMPTY: | |
| 39 | 41 | // CHECK-NEXT: high_target: |
| 40 | 42 | // CHECK-NEXT: 8002000: 00 00 00 96 bl #-134217728 |
| 41 | 43 | // CHECK-NEXT: 8002004: c0 03 5f d6 ret |
deps/lld/test/ELF/aarch64-tls-gdie.s+7-7| ... | ... | @@ -3,8 +3,8 @@ |
| 3 | 3 | // RUN: llvm-mc %p/Inputs/aarch64-tls-gdie.s -o %t2.o -filetype=obj -triple=aarch64-pc-linux |
| 4 | 4 | // RUN: ld.lld %t2.o -o %t2.so -shared |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv %t.o %t2.so -o %t |
| 6 | // RUN: llvm-readobj -s %t | FileCheck --check-prefix=SEC %s | |
| 7 | // RUN: llvm-objdump -d %t | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S %t | FileCheck --check-prefix=SEC %s | |
| 7 | // RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | .globl _start |
| 10 | 10 | _start: |
| ... | ... | @@ -27,8 +27,8 @@ _start: |
| 27 | 27 | // 0x0B0 = 176 |
| 28 | 28 | |
| 29 | 29 | // CHECK: _start: |
| 30 | // CHECK-NEXT: 210000: {{.*}} nop | |
| 31 | // CHECK-NEXT: 210004: {{.*}} adrp x0, #65536 | |
| 32 | // CHECK-NEXT: 210008: {{.*}} ldr x0, [x0, #176] | |
| 33 | // CHECK-NEXT: 21000c: {{.*}} nop | |
| 34 | // CHECK-NEXT: 210010: {{.*}} nop | |
| 30 | // CHECK-NEXT: 210000: nop | |
| 31 | // CHECK-NEXT: 210004: adrp x0, #65536 | |
| 32 | // CHECK-NEXT: 210008: ldr x0, [x0, #176] | |
| 33 | // CHECK-NEXT: 21000c: nop | |
| 34 | // CHECK-NEXT: 210010: nop |
deps/lld/test/ELF/aarch64-tls-gdle.s+11-10| ... | ... | @@ -2,20 +2,21 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %p/Inputs/aarch64-tls-ie.s -o %ttlsie.o |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %tmain.o |
| 4 | 4 | # RUN: ld.lld %tmain.o %ttlsie.o -o %tout |
| 5 | # RUN: llvm-objdump -d %tout | FileCheck %s | |
| 6 | # RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s | |
| 5 | # RUN: llvm-objdump -d --no-show-raw-insn %tout | FileCheck %s | |
| 6 | # RUN: llvm-readobj -r %tout | FileCheck -check-prefix=RELOC %s | |
| 7 | 7 | |
| 8 | #Local-Dynamic to Local-Exec relax creates no | |
| 9 | #RELOC: Relocations [ | |
| 10 | #RELOC-NEXT: ] | |
| 8 | ## Local-Dynamic to Local-Exec relax creates no dynamic relocations. | |
| 9 | # RELOC: Relocations [ | |
| 10 | # RELOC-NEXT: ] | |
| 11 | 11 | |
| 12 | # TCB size = 64 and foo is first element from TLS register. | |
| 12 | # TCB size = 0x16 and foo is first element from TLS register. | |
| 13 | 13 | # CHECK: Disassembly of section .text: |
| 14 | # CHECK-EMPTY: | |
| 14 | 15 | # CHECK: _start: |
| 15 | # CHECK: 210000:	00 00 a0 d2	movz	x0, #0, lsl #16 | |
| 16 | # CHECK: 210004:	00 08 80 f2 	movk	x0, #64 | |
| 17 | # CHECK: 210008:	1f 20 03 d5 	nop | |
| 18 | # CHECK: 21000c:	1f 20 03 d5 	nop | |
| 16 | # CHECK: 210000: movz x0, #0, lsl #16 | |
| 17 | # CHECK: 210004: movk x0, #16 | |
| 18 | # CHECK: 210008: nop | |
| 19 | # CHECK: 21000c: nop | |
| 19 | 20 | |
| 20 | 21 | .globl _start |
| 21 | 22 | _start: |
deps/lld/test/ELF/aarch64-tls-ie.s+33-35| ... | ... | @@ -1,45 +1,43 @@ |
| 1 | // REQUIRES: aarch64 | |
| 2 | 1 | # REQUIRES: aarch64 |
| 3 | 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %p/Inputs/aarch64-tls-ie.s -o %tdso.o |
| 4 | 3 | # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %tmain.o |
| 5 | 4 | # RUN: ld.lld -shared %tdso.o -o %tdso.so |
| 6 | 5 | # RUN: ld.lld --hash-style=sysv %tmain.o %tdso.so -o %tout |
| 7 | # RUN: llvm-objdump -d %tout | FileCheck %s | |
| 8 | # RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s | |
| 6 | # RUN: llvm-objdump -d --no-show-raw-insn %tout | FileCheck %s | |
| 7 | # RUN: llvm-readobj -S -r %tout | FileCheck -check-prefix=RELOC %s | |
| 9 | 8 | |
| 10 | #RELOC: Section { | |
| 11 | #RELOC: Index: | |
| 12 | #RELOC: Name: .got | |
| 13 | #RELOC-NEXT: Type: SHT_PROGBITS | |
| 14 | #RELOC-NEXT: Flags [ | |
| 15 | #RELOC-NEXT: SHF_ALLOC | |
| 16 | #RELOC-NEXT: SHF_WRITE | |
| 17 | #RELOC-NEXT: ] | |
| 18 | #RELOC-NEXT: Address: 0x2200B0 | |
| 19 | #RELOC-NEXT: Offset: 0x200B0 | |
| 20 | #RELOC-NEXT: Size: 16 | |
| 21 | #RELOC-NEXT: Link: 0 | |
| 22 | #RELOC-NEXT: Info: 0 | |
| 23 | #RELOC-NEXT: AddressAlignment: 8 | |
| 24 | #RELOC-NEXT: EntrySize: 0 | |
| 25 | #RELOC-NEXT: } | |
| 26 | #RELOC: Relocations [ | |
| 27 | #RELOC-NEXT: Section ({{.*}}) .rela.dyn { | |
| 28 | #RELOC-NEXT: 0x2200B8 R_AARCH64_TLS_TPREL64 bar 0x0 | |
| 29 | #RELOC-NEXT: 0x2200B0 R_AARCH64_TLS_TPREL64 foo 0x0 | |
| 30 | #RELOC-NEXT: } | |
| 31 | #RELOC-NEXT:] | |
| 9 | # RELOC: Section { | |
| 10 | # RELOC: Index: | |
| 11 | # RELOC: Name: .got | |
| 12 | # RELOC-NEXT: Type: SHT_PROGBITS | |
| 13 | # RELOC-NEXT: Flags [ | |
| 14 | # RELOC-NEXT: SHF_ALLOC | |
| 15 | # RELOC-NEXT: SHF_WRITE | |
| 16 | # RELOC-NEXT: ] | |
| 17 | # RELOC-NEXT: Address: 0x2200B0 | |
| 18 | # RELOC-NEXT: Offset: 0x200B0 | |
| 19 | # RELOC-NEXT: Size: 16 | |
| 20 | # RELOC-NEXT: Link: 0 | |
| 21 | # RELOC-NEXT: Info: 0 | |
| 22 | # RELOC-NEXT: AddressAlignment: 8 | |
| 23 | # RELOC-NEXT: EntrySize: 0 | |
| 24 | # RELOC-NEXT: } | |
| 25 | # RELOC: Relocations [ | |
| 26 | # RELOC-NEXT: Section ({{.*}}) .rela.dyn { | |
| 27 | # RELOC-NEXT: 0x2200B8 R_AARCH64_TLS_TPREL64 bar 0x0 | |
| 28 | # RELOC-NEXT: 0x2200B0 R_AARCH64_TLS_TPREL64 foo 0x0 | |
| 29 | # RELOC-NEXT: } | |
| 30 | # RELOC-NEXT:] | |
| 32 | 31 | |
| 33 | # Page(0x2200B0) - Page(0x210000) = 0x10000 = 65536 | |
| 34 | # 0x2200B0 & 0xff8 = 0xB0 = 176 | |
| 35 | # Page(0x2200B8) - Page(0x210000) = 0x10000 = 65536 | |
| 36 | # 0x2200B8 & 0xff8 = 0xB8 = 184 | |
| 37 | #CHECK: Disassembly of section .text: | |
| 38 | #CHECK: _start: | |
| 39 | #CHECK: 210000: 80 00 00 90 adrp x0, #65536 | |
| 40 | #CHECK: 210004: 00 58 40 f9 ldr x0, [x0, #176] | |
| 41 | #CHECK: 210008: 80 00 00 90 adrp x0, #65536 | |
| 42 | #CHECK: 21000c: 00 5c 40 f9 ldr x0, [x0, #184] | |
| 32 | ## Page(0x2200B0) - Page(0x210000) = 0x10000 = 65536 | |
| 33 | ## 0x2200B0 & 0xff8 = 0xB0 = 176 | |
| 34 | ## Page(0x2200B8) - Page(0x210000) = 0x10000 = 65536 | |
| 35 | ## 0x2200B8 & 0xff8 = 0xB8 = 184 | |
| 36 | # CHECK: _start: | |
| 37 | # CHECK-NEXT: 210000: adrp x0, #65536 | |
| 38 | # CHECK-NEXT: 210004: ldr x0, [x0, #176] | |
| 39 | # CHECK-NEXT: 210008: adrp x0, #65536 | |
| 40 | # CHECK-NEXT: 21000c: ldr x0, [x0, #184] | |
| 43 | 41 | |
| 44 | 42 | .globl _start |
| 45 | 43 | _start: |
deps/lld/test/ELF/aarch64-tls-iele.s+12-7| ... | ... | @@ -2,20 +2,25 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %p/Inputs/aarch64-tls-ie.s -o %ttlsie.o |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %tmain.o |
| 4 | 4 | # RUN: ld.lld %tmain.o %ttlsie.o -o %tout |
| 5 | # RUN: llvm-objdump -d %tout | FileCheck %s | |
| 6 | # RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s | |
| 5 | # RUN: llvm-objdump -d --no-show-raw-insn %tout | FileCheck %s | |
| 6 | # RUN: llvm-readobj -r %tout | FileCheck -check-prefix=RELOC %s | |
| 7 | ||
| 8 | # RUN: ld.lld -pie %tmain.o %ttlsie.o -o %tout | |
| 9 | # RUN: llvm-objdump -d --no-show-raw-insn %tout | FileCheck %s | |
| 10 | # RUN: llvm-readobj -r %tout | FileCheck -check-prefix=RELOC %s | |
| 7 | 11 | |
| 8 | 12 | # Initial-Exec to Local-Exec relax creates no dynamic relocations. |
| 9 | 13 | # RELOC: Relocations [ |
| 10 | 14 | # RELOC-NEXT: ] |
| 11 | 15 | |
| 12 | # TCB size = 64 and foo is first element from TLS register. | |
| 16 | # TCB size = 0x16 and foo is first element from TLS register. | |
| 13 | 17 | # CHECK: Disassembly of section .text: |
| 18 | # CHECK-EMPTY: | |
| 14 | 19 | # CHECK: _start: |
| 15 | # CHECK-NEXT: 210000: 00 00 a0 d2 movz x0, #0, lsl #16 | |
| 16 | # CHECK-NEXT: 210004: 80 08 80 f2 movk x0, #68 | |
| 17 | # CHECK-NEXT: 210008: 00 00 a0 d2 movz x0, #0, lsl #16 | |
| 18 | # CHECK-NEXT: 21000c: 00 08 80 f2 movk x0, #64 | |
| 20 | # CHECK-NEXT: movz x0, #0, lsl #16 | |
| 21 | # CHECK-NEXT: movk x0, #20 | |
| 22 | # CHECK-NEXT: movz x0, #0, lsl #16 | |
| 23 | # CHECK-NEXT: movk x0, #16 | |
| 19 | 24 | |
| 20 | 25 | .section .tdata |
| 21 | 26 | .align 2 |
deps/lld/test/ELF/aarch64-tls-le.s+5-5| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %tmain.o |
| 3 | 3 | # RUN: ld.lld %tmain.o -o %tout |
| 4 | 4 | # RUN: llvm-objdump -d %tout | FileCheck %s |
| 5 | # RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s | |
| 5 | # RUN: llvm-readobj -S -r %tout | FileCheck -check-prefix=RELOC %s | |
| 6 | 6 | |
| 7 | 7 | #Local-Dynamic to Local-Exec relax creates no |
| 8 | 8 | #RELOC: Relocations [ |
| ... | ... | @@ -17,12 +17,12 @@ _start: |
| 17 | 17 | add x0, x0, :tprel_hi12:v2 |
| 18 | 18 | add x0, x0, :tprel_lo12_nc:v2 |
| 19 | 19 | |
| 20 | # TCB size = 64 and foo is first element from TLS register. | |
| 20 | # TCB size = 0x16 and foo is first element from TLS register. | |
| 21 | 21 | #CHECK: Disassembly of section .text: |
| 22 | 22 | #CHECK: _start: |
| 23 | 23 | #CHECK: 210000: 40 d0 3b d5 mrs x0, TPIDR_EL0 |
| 24 | 24 | #CHECK: 210004: 00 00 40 91 add x0, x0, #0, lsl #12 |
| 25 | #CHECK: 210008: 00 00 01 91 add x0, x0, #64 | |
| 25 | #CHECK: 210008: 00 40 00 91 add x0, x0, #16 | |
| 26 | 26 | #CHECK: 21000c: 40 d0 3b d5 mrs x0, TPIDR_EL0 |
| 27 | 27 | #CHECK: 210010: 00 fc 7f 91 add x0, x0, #4095, lsl #12 |
| 28 | 28 | #CHECK: 210014: 00 e0 3f 91 add x0, x0, #4088 |
| ... | ... | @@ -36,9 +36,9 @@ v1: |
| 36 | 36 | .word 0 |
| 37 | 37 | .size v1, 4 |
| 38 | 38 | |
| 39 | # The current offset from the thread pointer is 68. Raise it to just below the | |
| 39 | # The current offset from the thread pointer is 20. Raise it to just below the | |
| 40 | 40 | # 24-bit limit. |
| 41 | .space (0xfffff8 - 68) | |
| 41 | .space (0xfffff8 - 20) | |
| 42 | 42 | |
| 43 | 43 | .type v2,@object |
| 44 | 44 | .globl v2 |
deps/lld/test/ELF/aarch64-tls-pie.s deleted-28| ... | ... | @@ -1,28 +0,0 @@ |
| 1 | # REQUIRES: aarch64 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-cloudabi %s -o %t1.o | |
| 3 | # RUN: ld.lld -pie %t1.o -o %t | |
| 4 | # RUN: llvm-readobj -r %t | FileCheck %s | |
| 5 | ||
| 6 | # Similar to bug 27174: R_AARCH64_TLSLE_*TPREL* relocations should be | |
| 7 | # eliminated when building a PIE executable, as the static TLS layout is | |
| 8 | # fixed. | |
| 9 | # | |
| 10 | # CHECK: Relocations [ | |
| 11 | # CHECK-NEXT: ] | |
| 12 | ||
| 13 | 	.globl	_start | |
| 14 | _start: | |
| 15 | 	# Accessing the variable directly. | |
| 16 | 	add	x11, x8, :tprel_hi12:i | |
| 17 | 	add	x11, x11, :tprel_lo12_nc:i | |
| 18 | ||
| 19 | 	# Accessing the variable through the GOT. | |
| 20 | 	adrp	x10, :gottprel:i | |
| 21 | 	mrs	x8, TPIDR_EL0 | |
| 22 | 	ldr	x10, [x10, :gottprel_lo12:i] | |
| 23 | ||
| 24 | 	.section	.tbss.i,"awT",@nobits | |
| 25 | 	.globl	i | |
| 26 | i: | |
| 27 | 	.word	0 | |
| 28 | 	.size	i, 4 |
deps/lld/test/ELF/aarch64-tls-static.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: aarch64 |
| 2 | 2 | // RUN: llvm-mc %s -o %t.o -triple aarch64-pc-linux -filetype=obj |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -s %t.so | FileCheck --check-prefix=SEC %s | |
| 4 | // RUN: llvm-readobj -S %t.so | FileCheck --check-prefix=SEC %s | |
| 5 | 5 | // RUN: llvm-objdump -d %t.so | FileCheck %s |
| 6 | 6 | |
| 7 | 7 | foo: |
deps/lld/test/ELF/aarch64-tlsld-ldst.s+27-27| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: aarch64 |
| 2 | 2 | // RUN: llvm-mc -triple=aarch64-linux-gnu -filetype=obj %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t |
| 4 | // RUN: llvm-objdump -d %t | FileCheck %s | |
| 4 | // RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 5 | 5 | // RUN: llvm-readelf --symbols %t | FileCheck -check-prefix CHECK-SYMS %s |
| 6 | 6 | |
| 7 | 7 | .text |
| ... | ... | @@ -25,28 +25,28 @@ _start: mrs x8, TPIDR_EL0 |
| 25 | 25 | ldrb w0, [x8, :tprel_lo12_nc:var4] |
| 26 | 26 | |
| 27 | 27 | // CHECK: _start: |
| 28 | // CHECK-NEXT: 210000: 48 d0 3b d5 mrs x8, TPIDR_EL0 | |
| 29 | // 0x0 + c40 = 0xc40 = tcb (64-bytes) + var0 | |
| 30 | // CHECK-NEXT: 210004: 08 01 40 91 add x8, x8, #0, lsl #12 | |
| 31 | // CHECK-NEXT: 210008: 14 11 c3 3d ldr q20, [x8, #3136] | |
| 32 | // 0x1000 + 0x850 = 0x1850 = tcb + var1 | |
| 33 | // CHECK-NEXT: 21000c: 08 05 40 91 add x8, x8, #1, lsl #12 | |
| 34 | // CHECK-NEXT: 210010: 00 29 44 f9 ldr x0, [x8, #2128] | |
| 35 | // 0x2000 + 0x458 = 0x2458 = tcb + var2 | |
| 36 | // CHECK-NEXT: 210014: 08 09 40 91 add x8, x8, #2, lsl #12 | |
| 37 | // CHECK-NEXT: 210018: 00 59 44 b9 ldr w0, [x8, #1112] | |
| 38 | // 0x3000 + 0x5c = 0x305c = tcb + var3 | |
| 39 | // CHECK-NEXT: 21001c: 08 0d 40 91 add x8, x8, #3, lsl #12 | |
| 40 | // CHECK-NEXT: 210020: 00 b9 40 79 ldrh w0, [x8, #92] | |
| 41 | // 0x3000 + 0xc5e = 0x3c5e = tcb + var4 | |
| 42 | // CHECK-NEXT: 210024: 08 0d 40 91 add x8, x8, #3, lsl #12 | |
| 43 | // CHECK-NEXT: 210028: 00 79 71 39 ldrb w0, [x8, #3166] | |
| 28 | // CHECK-NEXT: 210000: mrs x8, TPIDR_EL0 | |
| 29 | // 0x0 + c10 = 0xc10 = tcb (16-bytes) + var0 | |
| 30 | // CHECK-NEXT: 210004: add x8, x8, #0, lsl #12 | |
| 31 | // CHECK-NEXT: 210008: ldr q20, [x8, #3088] | |
| 32 | // 0x1000 + 0x820 = 0x1820 = tcb + var1 | |
| 33 | // CHECK-NEXT: 21000c: add x8, x8, #1, lsl #12 | |
| 34 | // CHECK-NEXT: 210010: ldr x0, [x8, #2080] | |
| 35 | // 0x2000 + 0x428 = 0x2428 = tcb + var2 | |
| 36 | // CHECK-NEXT: 210014: add x8, x8, #2, lsl #12 | |
| 37 | // CHECK-NEXT: 210018: ldr w0, [x8, #1064] | |
| 38 | // 0x3000 + 0x2c = 0x302c = tcb + var3 | |
| 39 | // CHECK-NEXT: 21001c: add x8, x8, #3, lsl #12 | |
| 40 | // CHECK-NEXT: 210020: ldrh w0, [x8, #44] | |
| 41 | // 0x3000 + 0xc2e = 0x32ce = tcb + var4 | |
| 42 | // CHECK-NEXT: 210024: add x8, x8, #3, lsl #12 | |
| 43 | // CHECK-NEXT: 210028: ldrb w0, [x8, #3118] | |
| 44 | 44 | |
| 45 | // CHECK-SYMS: 0000000000000c00 16 TLS GLOBAL DEFAULT 2 var0 | |
| 46 | // CHECK-SYMS-NEXT: 0000000000001810 8 TLS GLOBAL DEFAULT 2 var1 | |
| 47 | // CHECK-SYMS-NEXT: 0000000000002418 4 TLS GLOBAL DEFAULT 2 var2 | |
| 48 | // CHECK-SYMS-NEXT: 000000000000301c 2 TLS GLOBAL DEFAULT 2 var3 | |
| 49 | // CHECK-SYMS-NEXT: 0000000000003c1e 1 TLS GLOBAL DEFAULT 2 var4 | |
| 45 | // CHECK-SYMS: 0000000000000c00 0 TLS GLOBAL DEFAULT 2 var0 | |
| 46 | // CHECK-SYMS-NEXT: 0000000000001810 4 TLS GLOBAL DEFAULT 2 var1 | |
| 47 | // CHECK-SYMS-NEXT: 0000000000002418 2 TLS GLOBAL DEFAULT 2 var2 | |
| 48 | // CHECK-SYMS-NEXT: 000000000000301c 1 TLS GLOBAL DEFAULT 2 var3 | |
| 49 | // CHECK-SYMS-NEXT: 0000000000003c1e 0 TLS GLOBAL DEFAULT 2 var4 | |
| 50 | 50 | |
| 51 | 51 | .globl var0 |
| 52 | 52 | .globl var1 |
| ... | ... | @@ -59,12 +59,12 @@ _start: mrs x8, TPIDR_EL0 |
| 59 | 59 | .type var3,@object |
| 60 | 60 | |
| 61 | 61 | .section .tbss,"awT",@nobits |
| 62 | .balign 64 | |
| 62 | .balign 16 | |
| 63 | 63 | .space 1024 * 3 |
| 64 | 64 | var0: |
| 65 | 65 | .quad 0 |
| 66 | 66 | .quad 0 |
| 67 | .size var0, 16 | |
| 67 | .size var1, 16 | |
| 68 | 68 | .space 1024 * 3 |
| 69 | 69 | var1: |
| 70 | 70 | .quad 0 |
| ... | ... | @@ -72,14 +72,14 @@ var1: |
| 72 | 72 | .space 1024 * 3 |
| 73 | 73 | var2: |
| 74 | 74 | .word 0 |
| 75 | .size var2, 4 | |
| 75 | .size var1, 4 | |
| 76 | 76 | |
| 77 | 77 | .space 1024 * 3 |
| 78 | 78 | var3: |
| 79 | 79 | .hword 0 |
| 80 | .size var3, 2 | |
| 80 | .size var2, 2 | |
| 81 | 81 | .space 1024 * 3 |
| 82 | 82 | var4: |
| 83 | 83 | .byte 0 |
| 84 | .size var4, 1 | |
| 84 | .size var3, 1 | |
| 85 | 85 | .space 1024 * 3 |
deps/lld/test/ELF/aarch64-tstbr14-reloc.s+12-8| ... | ... | @@ -5,13 +5,14 @@ |
| 5 | 5 | # RUN: llvm-objdump -d %t | FileCheck %s |
| 6 | 6 | # RUN: ld.lld -shared %t1 %t2 -o %t3 |
| 7 | 7 | # RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=DSO %s |
| 8 | # RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s | |
| 8 | # RUN: llvm-readobj -S -r %t3 | FileCheck -check-prefix=DSOREL %s | |
| 9 | 9 | |
| 10 | 10 | # 0x1101c - 28 = 0x20000 |
| 11 | 11 | # 0x11020 - 16 = 0x20010 |
| 12 | 12 | # 0x11024 - 36 = 0x20000 |
| 13 | 13 | # 0x11028 - 24 = 0x20010 |
| 14 | 14 | # CHECK: Disassembly of section .text: |
| 15 | # CHECK-EMPTY: | |
| 15 | 16 | # CHECK-NEXT: _foo: |
| 16 | 17 | # CHECK-NEXT: 210000: {{.*}} nop |
| 17 | 18 | # CHECK-NEXT: 210004: {{.*}} nop |
| ... | ... | @@ -35,8 +36,8 @@ |
| 35 | 36 | #DSOREL-NEXT: SHF_ALLOC |
| 36 | 37 | #DSOREL-NEXT: SHF_WRITE |
| 37 | 38 | #DSOREL-NEXT: ] |
| 38 | #DSOREL-NEXT: Address: 0x20000 | |
| 39 | #DSOREL-NEXT: Offset: 0x20000 | |
| 39 | #DSOREL-NEXT: Address: 0x30000 | |
| 40 | #DSOREL-NEXT: Offset: 0x30000 | |
| 40 | 41 | #DSOREL-NEXT: Size: 40 |
| 41 | 42 | #DSOREL-NEXT: Link: 0 |
| 42 | 43 | #DSOREL-NEXT: Info: 0 |
| ... | ... | @@ -45,12 +46,13 @@ |
| 45 | 46 | #DSOREL-NEXT: } |
| 46 | 47 | #DSOREL: Relocations [ |
| 47 | 48 | #DSOREL-NEXT: Section ({{.*}}) .rela.plt { |
| 48 | #DSOREL-NEXT: 0x20018 R_AARCH64_JUMP_SLOT _foo | |
| 49 | #DSOREL-NEXT: 0x20020 R_AARCH64_JUMP_SLOT _bar | |
| 49 | #DSOREL-NEXT: 0x30018 R_AARCH64_JUMP_SLOT _foo | |
| 50 | #DSOREL-NEXT: 0x30020 R_AARCH64_JUMP_SLOT _bar | |
| 50 | 51 | #DSOREL-NEXT: } |
| 51 | 52 | #DSOREL-NEXT:] |
| 52 | 53 | |
| 53 | 54 | #DSO: Disassembly of section .text: |
| 55 | #DSO-EMPTY: | |
| 54 | 56 | #DSO-NEXT: _foo: |
| 55 | 57 | #DSO-NEXT: 10000: {{.*}} nop |
| 56 | 58 | #DSO-NEXT: 10004: {{.*}} nop |
| ... | ... | @@ -69,10 +71,12 @@ |
| 69 | 71 | #DSO-NEXT: 10020: {{.*}} tbnz w3, #15, #64 |
| 70 | 72 | #DSO-NEXT: 10024: {{.*}} tbz x6, #45, #44 |
| 71 | 73 | #DSO-NEXT: 10028: {{.*}} tbz x6, #45, #56 |
| 74 | #DSO-EMPTY: | |
| 72 | 75 | #DSO-NEXT: Disassembly of section .plt: |
| 76 | #DSO-EMPTY: | |
| 73 | 77 | #DSO-NEXT: .plt: |
| 74 | 78 | #DSO-NEXT: 10030: {{.*}} stp x16, x30, [sp, #-16]! |
| 75 | #DSO-NEXT: 10034: {{.*}} adrp x16, #65536 | |
| 79 | #DSO-NEXT: 10034: {{.*}} adrp x16, #131072 | |
| 76 | 80 | #DSO-NEXT: 10038: {{.*}} ldr x17, [x16, #16] |
| 77 | 81 | #DSO-NEXT: 1003c: {{.*}} add x16, x16, #16 |
| 78 | 82 | #DSO-NEXT: 10040: {{.*}} br x17 |
| ... | ... | @@ -81,13 +85,13 @@ |
| 81 | 85 | #DSO-NEXT: 1004c: {{.*}} nop |
| 82 | 86 | #DSO-EMPTY: |
| 83 | 87 | #DSO-NEXT: _foo@plt: |
| 84 | #DSO-NEXT: 10050: {{.*}} adrp x16, #65536 | |
| 88 | #DSO-NEXT: 10050: {{.*}} adrp x16, #131072 | |
| 85 | 89 | #DSO-NEXT: 10054: {{.*}} ldr x17, [x16, #24] |
| 86 | 90 | #DSO-NEXT: 10058: {{.*}} add x16, x16, #24 |
| 87 | 91 | #DSO-NEXT: 1005c: {{.*}} br x17 |
| 88 | 92 | #DSO-EMPTY: |
| 89 | 93 | #DSO-NEXT: _bar@plt: |
| 90 | #DSO-NEXT: 10060: {{.*}} adrp x16, #65536 | |
| 94 | #DSO-NEXT: 10060: {{.*}} adrp x16, #131072 | |
| 91 | 95 | #DSO-NEXT: 10064: {{.*}} ldr x17, [x16, #32] |
| 92 | 96 | #DSO-NEXT: 10068: {{.*}} add x16, x16, #32 |
| 93 | 97 | #DSO-NEXT: 1006c: {{.*}} br x17 |
deps/lld/test/ELF/aarch64-undefined-weak.s+1| ... | ... | @@ -34,6 +34,7 @@ _start: |
| 34 | 34 | ldr x8, target |
| 35 | 35 | |
| 36 | 36 | // CHECK: Disassembly of section .text: |
| 37 | // CHECK-EMPTY: | |
| 37 | 38 | // 2162688 = 0x210000 |
| 38 | 39 | // CHECK: 210000: {{.*}} b #4 |
| 39 | 40 | // CHECK-NEXT: 210004: {{.*}} bl #4 |
deps/lld/test/ELF/abs-hidden.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/abs-hidden.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld --hash-style=sysv %t.o %t2.o -o %t.so -shared |
| 5 | // RUN: llvm-readobj -r -s -section-data %t.so | FileCheck %s | |
| 5 | // RUN: llvm-readobj -r -S --section-data %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | .quad foo |
| 8 | 8 | .long foo@gotpcrel |
deps/lld/test/ELF/allow-shlib-undefined.s+20-16| ... | ... | @@ -1,26 +1,30 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | # --allow-shlib-undefined and --no-allow-shlib-undefined are fully | |
| 3 | # ignored in linker implementation. | |
| 4 | # --allow-shlib-undefined is set by default | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 5 | 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ |
| 6 | # RUN: %p/Inputs/allow-shlib-undefined.s -o %t | |
| 7 | # RUN: ld.lld -shared %t -o %t.so | |
| 8 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 | |
| 5 | # RUN: %p/Inputs/allow-shlib-undefined.s -o %t1.o | |
| 6 | # RUN: ld.lld -shared %t1.o -o %t.so | |
| 7 | ||
| 8 | # RUN: ld.lld --allow-shlib-undefined %t.o %t.so -o /dev/null | |
| 9 | # RUN: not ld.lld --no-allow-shlib-undefined %t.o %t.so -o /dev/null 2>&1 | FileCheck %s | |
| 10 | # Executable defaults to --no-allow-shlib-undefined | |
| 11 | # RUN: not ld.lld %t.o %t.so -o /dev/null 2>&1 | FileCheck %s | |
| 12 | # -shared defaults to --allow-shlib-undefined | |
| 13 | # RUN: ld.lld -shared %t.o %t.so -o /dev/null | |
| 9 | 14 | |
| 10 | # Executable: should link with DSO containing undefined symbols in any case. | |
| 11 | # RUN: ld.lld %t1 %t.so -o %t2 | |
| 12 | # RUN: ld.lld --no-allow-shlib-undefined %t1 %t.so -o %t2 | |
| 13 | # RUN: ld.lld --allow-shlib-undefined %t1 %t.so -o %t2 | |
| 15 | # RUN: echo | llvm-mc -filetype=obj -triple=x86_64-unknown-linux -o %tempty.o | |
| 16 | # RUN: ld.lld -shared %tempty.o -o %tempty.so | |
| 17 | # RUN: ld.lld -shared %t1.o %tempty.so -o %t2.so | |
| 18 | # RUN: ld.lld --no-allow-shlib-undefined %t.o %t2.so -o /dev/null | |
| 14 | 19 | |
| 15 | 20 | # DSO with undefines: |
| 16 | 21 | # should link with or without any of these options. |
| 17 | # RUN: ld.lld -shared %t -o %t.so | |
| 18 | # RUN: ld.lld -shared --allow-shlib-undefined %t -o %t.so | |
| 19 | # RUN: ld.lld -shared --no-allow-shlib-undefined %t -o %t.so | |
| 20 | ||
| 21 | # Executable still should not link when have undefines inside. | |
| 22 | # RUN: not ld.lld %t -o %t.so | |
| 22 | # RUN: ld.lld -shared %t1.o -o /dev/null | |
| 23 | # RUN: ld.lld -shared --allow-shlib-undefined %t1.o -o /dev/null | |
| 24 | # RUN: ld.lld -shared --no-allow-shlib-undefined %t1.o -o /dev/null | |
| 23 | 25 | |
| 24 | 26 | .globl _start |
| 25 | 27 | _start: |
| 26 | 28 | callq _shared@PLT |
| 29 | ||
| 30 | # CHECK: undefined reference to _unresolved |
deps/lld/test/ELF/amdgpu-abi-version-err.s created+10| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | # REQUIRES: amdgpu | |
| 2 | # RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx900 -filetype=obj %s -o %t-0.o | |
| 3 | # RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx900 -mattr=-code-object-v3 -filetype=obj %s -o %t-1.o | |
| 4 | # RUN: not ld.lld -shared %t-0.o %t-1.o -o %t.so 2>&1 | FileCheck %s | |
| 5 | ||
| 6 | # CHECK: ld.lld: error: incompatible ABI version: {{.*}}-1.o | |
| 7 | ||
| 8 | .text | |
| 9 | s_nop 0x0 | |
| 10 | s_endpgm |
deps/lld/test/ELF/amdgpu-abi-version.s created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | # REQUIRES: amdgpu | |
| 2 | # RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx900 -filetype=obj %s -o %t.o | |
| 3 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 4 | # RUN: llvm-readobj --file-headers %t.so | FileCheck %s | |
| 5 | ||
| 6 | # CHECK: OS/ABI: AMDGPU_HSA (0x40) | |
| 7 | # CHECK: ABIVersion: 1 | |
| 8 | ||
| 9 | .text | |
| 10 | s_nop 0x0 | |
| 11 | s_endpgm |
deps/lld/test/ELF/amdgpu-elf-flags.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx803 -mattr=-code-object-v3 -filetype=obj %S/Inputs/amdgpu-kernel-0.s -o %t-0.o |
| 3 | 3 | # RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx803 -mattr=-code-object-v3 -filetype=obj %S/Inputs/amdgpu-kernel-1.s -o %t-1.o |
| 4 | 4 | # RUN: ld.lld -shared %t-0.o %t-1.o -o %t.so |
| 5 | # RUN: llvm-readobj -file-headers %t.so | FileCheck %s | |
| 5 | # RUN: llvm-readobj --file-headers %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: Flags [ |
| 8 | 8 | # CHECK: EF_AMDGPU_MACH_AMDGCN_GFX803 (0x2A) |
deps/lld/test/ELF/amdgpu-globals.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: amdgpu |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri %s -o %t.o |
| 3 | 3 | # RUN: ld.lld -shared %t.o -o %t |
| 4 | # RUN: llvm-readobj -sections -symbols -program-headers %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj --sections --symbols -l %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .type glob0, @object |
| 7 | 7 | .data |
deps/lld/test/ELF/amdgpu-kernels.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: amdgpu |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri -mattr=-code-object-v3 %s -o %t.o |
| 3 | 3 | # RUN: ld.lld -shared %t.o -o %t |
| 4 | # RUN: llvm-readobj -sections -symbols -program-headers %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj --sections --symbols -l %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .hsa_code_object_version 1,0 |
| 7 | 7 | .hsa_code_object_isa 7,0,0,"AMD","AMDGPU" |
deps/lld/test/ELF/amdgpu-relocs.s+19-7| ... | ... | @@ -2,7 +2,8 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=amdgcn--amdhsa -mcpu=fiji %s -o %t.o |
| 3 | 3 | # RUN: ld.lld --hash-style=sysv -shared %t.o -o %t.so |
| 4 | 4 | # RUN: llvm-readobj -r %t.so | FileCheck %s |
| 5 | # RUN: llvm-objdump -s %t.so | FileCheck %s --check-prefix=OBJDUMP | |
| 5 | # RUN: llvm-nm %t.so | FileCheck %s --check-prefix=NM | |
| 6 | # RUN: llvm-readelf -x .rodata -x nonalloc %t.so | FileCheck %s --check-prefix=HEX | |
| 6 | 7 | |
| 7 | 8 | .text |
| 8 | 9 | |
| ... | ... | @@ -48,6 +49,9 @@ kernel0: |
| 48 | 49 | .local local_var0 |
| 49 | 50 | .local local_var1 |
| 50 | 51 | .local local_var2 |
| 52 | local_var0: | |
| 53 | local_var1: | |
| 54 | local_var2: | |
| 51 | 55 | |
| 52 | 56 | # R_AMDGPU_ABS32: |
| 53 | 57 | .section nonalloc, "w", @progbits |
| ... | ... | @@ -68,6 +72,7 @@ ptr: |
| 68 | 72 | .type temp2, @object |
| 69 | 73 | .local temp2 |
| 70 | 74 | .size temp2, 4 |
| 75 | temp2: | |
| 71 | 76 | |
| 72 | 77 | .type ptr2, @object |
| 73 | 78 | .globl ptr2 |
| ... | ... | @@ -89,7 +94,7 @@ foo: |
| 89 | 94 | # linker. |
| 90 | 95 | # CHECK: Relocations [ |
| 91 | 96 | # CHECK: .rela.dyn { |
| 92 | # CHECK-NEXT: R_AMDGPU_RELATIVE64 - 0x0 | |
| 97 | # CHECK-NEXT: R_AMDGPU_RELATIVE64 - 0x3008 | |
| 93 | 98 | # CHECK-NEXT: R_AMDGPU_ABS64 common_var0 0x0 |
| 94 | 99 | # CHECK-NEXT: R_AMDGPU_ABS64 common_var1 0x0 |
| 95 | 100 | # CHECK-NEXT: R_AMDGPU_ABS64 common_var2 0x0 |
| ... | ... | @@ -109,9 +114,16 @@ foo: |
| 109 | 114 | # CHECK-NEXT: } |
| 110 | 115 | # CHECK-NEXT: ] |
| 111 | 116 | |
| 112 | # OBJDUMP: Contents of section .rodata: | |
| 113 | # OBJDUMP: d0f8ffff ffffffff | |
| 117 | # NM: 0000000000003010 B common_var0 | |
| 118 | # NM: 0000000000003410 B common_var1 | |
| 119 | # NM: 0000000000003810 B common_var2 | |
| 120 | # NM: 0000000000003008 d temp2 | |
| 114 | 121 | |
| 115 | # OBJDUMP: Contents of section nonalloc: | |
| 116 | # OBJDUMP-NEXT: 0000 00000000 04480000 00000000 08440000 | |
| 117 | # OBJDUMP-NEXT: 00000000 0c400000 | |
| 122 | # temp2 - foo = 0x3008-0x768 = 0x28a0 | |
| 123 | # HEX: section '.rodata': | |
| 124 | # HEX-NEXT: 0x00000768 a0280000 00000000 | |
| 125 | ||
| 126 | # common_var2+4, common_var1+8, and common_var0+12. | |
| 127 | # HEX: section 'nonalloc': | |
| 128 | # HEX-NEXT: 0x00000000 00000000 14380000 00000000 18340000 | |
| 129 | # HEX-NEXT: 0x00000010 00000000 1c300000 |
deps/lld/test/ELF/archive-fetch.s+8-1| ... | ... | @@ -9,7 +9,14 @@ |
| 9 | 9 | # RUN: llvm-ar rcs %t.a %tfoo.o %tbar.o |
| 10 | 10 | |
| 11 | 11 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 12 | # RUN: ld.lld %t.a %t.o -o /dev/null | |
| 12 | # RUN: ld.lld %t.a %t.o -o %t | |
| 13 | # RUN: llvm-nm %t | FileCheck %s | |
| 14 | ||
| 15 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 16 | # RUN: ld.lld %t.a %t.so -o %t | |
| 17 | # RUN: llvm-nm %t | FileCheck %s | |
| 18 | ||
| 19 | # CHECK: T foo | |
| 13 | 20 | |
| 14 | 21 | _start: |
| 15 | 22 | callq foo |
deps/lld/test/ELF/archive-no-index.s created+13| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # Tests error on archive file without a symbol table | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux -o %t.o %s | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux -o %t.archive.o %S/Inputs/archive.s | |
| 5 | # RUN: rm -f %t.a | |
| 6 | # RUN: llvm-ar crS %t.a %t.archive.o | |
| 7 | ||
| 8 | # RUN: not ld.lld -o /dev/null %t.o %t.a 2>&1 | FileCheck %s | |
| 9 | ||
| 10 | .globl _start | |
| 11 | _start: | |
| 12 | ||
| 13 | # CHECK: error: {{.*}}.a: archive has no index; run ranlib to add one |
deps/lld/test/ELF/archive-thin-missing-member.s created+24| ... | ... | @@ -0,0 +1,24 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: rm -f %t-no-syms.a | |
| 4 | # RUN: rm -f %t-syms.a | |
| 5 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o | |
| 6 | # RUN: llvm-ar rcTS %t-no-syms.a %t.o | |
| 7 | # RUN: llvm-ar rcT %t-syms.a %t.o | |
| 8 | # RUN: rm %t.o | |
| 9 | ||
| 10 | # Test error when loading symbols from missing thin archive member. | |
| 11 | # RUN: not ld.lld %t-no-syms.a -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR1 | |
| 12 | # ERR1: {{.*}}-no-syms.a: could not get the buffer for a child of the archive: '{{.*}}.o': {{[Nn]}}o such file or directory | |
| 13 | ||
| 14 | # Test error when thin archive has symbol table but member is missing. | |
| 15 | # RUN: not ld.lld -m elf_amd64_fbsd %t-syms.a -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR2 | |
| 16 | # ERR2: {{.*}}-syms.a: could not get the buffer for the member defining symbol _start: '{{.*}}.o': {{[Nn]}}o such file or directory | |
| 17 | ||
| 18 | # Test error when thin archive is linked using --whole-archive but member is missing. | |
| 19 | # RUN: not ld.lld --whole-archive %t-syms.a -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR3 | |
| 20 | # ERR3: {{.*}}-syms.a: could not get the buffer for a child of the archive: '{{.*}}.o': {{[Nn]}}o such file or directory | |
| 21 | ||
| 22 | .global _start | |
| 23 | _start: | |
| 24 | nop |
deps/lld/test/ELF/arm-abs32-dyn.s+12-3| ... | ... | @@ -14,12 +14,19 @@ bar: |
| 14 | 14 | .word foo |
| 15 | 15 | .word bar |
| 16 | 16 | |
| 17 | // In PIC mode, if R_ARM_TARGET1 represents R_ARM_ABS32 (the default), an | |
| 18 | // R_ARM_TARGET1 to a non-preemptable symbol also creates an R_ARM_RELATIVE in | |
| 19 | // a writable section. | |
| 20 | .word bar(target1) | |
| 21 | ||
| 17 | 22 | // RUN: ld.lld -shared -o %t.so %t.o |
| 18 | // RUN: llvm-readobj -symbols -dyn-relocations %t.so | FileCheck %s | |
| 23 | // RUN: llvm-readobj --symbols --dyn-relocations %t.so | FileCheck %s | |
| 24 | // RUN: llvm-readelf -x .data %t.so | FileCheck --check-prefix=HEX %s | |
| 19 | 25 | |
| 20 | 26 | // CHECK: Dynamic Relocations { |
| 21 | // CHECK-NEXT: 0x1004 R_ARM_RELATIVE | |
| 22 | // CHECK-NEXT: 0x1000 R_ARM_ABS32 foo 0x0 | |
| 27 | // CHECK-NEXT: 0x2004 R_ARM_RELATIVE | |
| 28 | // CHECK-NEXT: 0x2008 R_ARM_RELATIVE | |
| 29 | // CHECK-NEXT: 0x2000 R_ARM_ABS32 foo 0x0 | |
| 23 | 30 | // CHECK-NEXT: } |
| 24 | 31 | |
| 25 | 32 | // CHECK: Symbols [ |
| ... | ... | @@ -30,3 +37,5 @@ bar: |
| 30 | 37 | // CHECK: Symbol { |
| 31 | 38 | // CHECK: Name: foo |
| 32 | 39 | // CHECK-NEXT: Value: 0x1000 |
| 40 | ||
| 41 | // HEX: 0x00002000 00000000 00100000 00100000 |
deps/lld/test/ELF/arm-attributes.s+3-3| ... | ... | @@ -3,11 +3,11 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t2.o |
| 4 | 4 | |
| 5 | 5 | // RUN: ld.lld %t1.o %t2.o -o %t |
| 6 | // RUN: llvm-readobj -arm-attributes %t | FileCheck %s | |
| 6 | // RUN: llvm-readobj --arm-attributes %t | FileCheck %s | |
| 7 | 7 | // RUN: ld.lld %t1.o %t2.o -shared -o %t2 |
| 8 | // RUN: llvm-readobj -arm-attributes %t2 | FileCheck %s | |
| 8 | // RUN: llvm-readobj --arm-attributes %t2 | FileCheck %s | |
| 9 | 9 | // RUN: ld.lld %t1.o %t2.o -r -o %t3 |
| 10 | // RUN: llvm-readobj -arm-attributes %t3 | FileCheck %s | |
| 10 | // RUN: llvm-readobj --arm-attributes %t3 | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | // Check that we retain only 1 SHT_ARM_ATTRIBUTES section. At present we do not |
| 13 | 13 | // try and merge or use the contents of SHT_ARM_ATTRIBUTES sections. We just |
deps/lld/test/ELF/arm-bl-v6-inrange.s+4| ... | ... | @@ -28,9 +28,12 @@ _start: |
| 28 | 28 | thumbfunc: |
| 29 | 29 | bx lr |
| 30 | 30 | // CHECK-THUMB: Disassembly of section .callee1: |
| 31 | // CHECK-THUMB-EMPTY: | |
| 31 | 32 | // CHECK-THUMB-NEXT: thumbfunc: |
| 32 | 33 | // CHECK-THUMB-NEXT: 100004: 70 47 bx lr |
| 34 | // CHECK-THUMB-EMPTY: | |
| 33 | 35 | // CHECK-THUMB-NEXT: Disassembly of section .caller: |
| 36 | // CHECK-THUMB-EMPTY: | |
| 34 | 37 | // CHECK-THUMB-NEXT: _start: |
| 35 | 38 | // CHECK-THUMB-NEXT: 500000: 00 f4 00 f8 bl #-4194304 |
| 36 | 39 | // CHECK-THUMB-NEXT: 500004: ff f3 fe ef blx #4194300 |
| ... | ... | @@ -43,5 +46,6 @@ thumbfunc: |
| 43 | 46 | armfunc: |
| 44 | 47 | bx lr |
| 45 | 48 | // CHECK-ARM: Disassembly of section .callee2: |
| 49 | // CHECK-ARM-EMPTY: | |
| 46 | 50 | // CHECK-ARM-NEXT: armfunc: |
| 47 | 51 | // CHECK-ARM-NEXT: 900004: 1e ff 2f e1 bx lr |
deps/lld/test/ELF/arm-bl-v6.s+1| ... | ... | @@ -26,6 +26,7 @@ _start: |
| 26 | 26 | bx lr |
| 27 | 27 | |
| 28 | 28 | // CHECK-ARM1: Disassembly of section .text: |
| 29 | // CHECK-ARM1-EMPTY: | |
| 29 | 30 | // CHECK-ARM1-NEXT: _start: |
| 30 | 31 | // CHECK-ARM1-NEXT: 11000: 00 00 00 fa blx #0 <thumbfunc> |
| 31 | 32 | // CHECK-ARM1-NEXT: 11004: 1e ff 2f e1 bx lr |
deps/lld/test/ELF/arm-blx.s+5| ... | ... | @@ -74,16 +74,19 @@ callee_arm_high: |
| 74 | 74 | bx lr |
| 75 | 75 | |
| 76 | 76 | // CHECK-THUMB: Disassembly of section .callee1: |
| 77 | // CHECK-THUMB-EMPTY: | |
| 77 | 78 | // CHECK-THUMB-NEXT: callee_low: |
| 78 | 79 | // CHECK-THUMB-NEXT: b4: 70 47 bx lr |
| 79 | 80 | // CHECK-THUMB: callee_low2: |
| 80 | 81 | // CHECK-THUMB-NEXT: b6: 70 47 bx lr |
| 81 | 82 | |
| 82 | 83 | // CHECK-ARM: Disassembly of section .callee2: |
| 84 | // CHECK-ARM-EMPTY: | |
| 83 | 85 | // CHECK-ARM-NEXT: callee_arm_low: |
| 84 | 86 | // CHECK-ARM-NEXT: 100: 1e ff 2f e1 bx lr |
| 85 | 87 | |
| 86 | 88 | // CHECK-ARM: Disassembly of section .caller: |
| 89 | // CHECK-ARM-EMPTY: | |
| 87 | 90 | // CHECK-ARM-NEXT: _start: |
| 88 | 91 | // CHECK-ARM-NEXT: 10000: 2b c0 ff fa blx #-65364 <callee_low> |
| 89 | 92 | // CHECK-ARM-NEXT: 10004: 2a c0 ff fa blx #-65368 <callee_low> |
| ... | ... | @@ -104,11 +107,13 @@ callee_arm_high: |
| 104 | 107 | // CHECK-ARM-NEXT: 10038: 1e ff 2f e1 bx lr |
| 105 | 108 | |
| 106 | 109 | // CHECK-THUMB: Disassembly of section .callee3: |
| 110 | // CHECK-THUMB-EMPTY: | |
| 107 | 111 | // CHECK-THUMB: callee_high: |
| 108 | 112 | // CHECK-THUMB-NEXT: 10100: 70 47 bx lr |
| 109 | 113 | // CHECK-THUMB: callee_high2: |
| 110 | 114 | // CHECK-THUMB-NEXT: 10102: 70 47 bx lr |
| 111 | 115 | |
| 112 | 116 | // CHECK-ARM: Disassembly of section .callee4: |
| 117 | // CHECK-ARM-EMPTY: | |
| 113 | 118 | // CHECK-NEXT-ARM: callee_arm_high: |
| 114 | 119 | // CHECK-NEXT-ARM: 10200: 1e ff 2f e1 bx lr |
deps/lld/test/ELF/arm-branch-rangethunk.s+2| ... | ... | @@ -19,6 +19,7 @@ _start: |
| 19 | 19 | beq too_far3 |
| 20 | 20 | |
| 21 | 21 | // SHORT: Disassembly of section .text: |
| 22 | // SHORT-EMPTY: | |
| 22 | 23 | // SHORT-NEXT: _start: |
| 23 | 24 | // SHORT-NEXT: 20000: 01 00 00 eb bl #4 <__ARMv7ABSLongThunk_too_far1> |
| 24 | 25 | // SHORT-NEXT: 20004: 01 00 00 ea b #4 <__ARMv7ABSLongThunk_too_far2> |
| ... | ... | @@ -31,6 +32,7 @@ _start: |
| 31 | 32 | // SHORT-NEXT: 20014: fd ff 7f ea b #33554420 <__ARMv7ABSLongThunk_too_far3+0x1fffffc> |
| 32 | 33 | |
| 33 | 34 | // LONG: Disassembly of section .text: |
| 35 | // LONG-EMPTY: | |
| 34 | 36 | // LONG-NEXT: _start: |
| 35 | 37 | // LONG-NEXT: 20000: 01 00 00 eb bl #4 <__ARMv7ABSLongThunk_too_far1> |
| 36 | 38 | // LONG-NEXT: 20004: 03 00 00 ea b #12 <__ARMv7ABSLongThunk_too_far2> |
deps/lld/test/ELF/arm-branch-undef-weak-plt-thunk.s+1| ... | ... | @@ -22,6 +22,7 @@ _start: |
| 22 | 22 | .space 32 * 1024 * 1024 |
| 23 | 23 | |
| 24 | 24 | // CHECK: Disassembly of section .text: |
| 25 | // CHECK-EMPTY: | |
| 25 | 26 | // CHECK-NEXT: _start: |
| 26 | 27 | // CHECK-NEXT: 11000: 00 00 00 ea b #0 <__ARMv7ABSLongThunk_undefined_weak_we_expect_a_plt_entry_for> |
| 27 | 28 | // CHECK-NEXT: 11004: 02 00 00 eb bl #8 <__ARMv7ABSLongThunk_bar2> |
deps/lld/test/ELF/arm-branch.s+1| ... | ... | @@ -38,6 +38,7 @@ callee_high: |
| 38 | 38 | bx lr |
| 39 | 39 | |
| 40 | 40 | // CHECK: Disassembly of section .caller: |
| 41 | // CHECK-EMPTY: | |
| 41 | 42 | // CHECK-NEXT: _start: |
| 42 | 43 | // S(callee_low) = 0xb4 P = 0x10000 A = -8 = -0xff54 = -65364 |
| 43 | 44 | // CHECK-NEXT: 10000: 2b c0 ff eb bl #-65364 <callee_low> |
deps/lld/test/ELF/arm-copy.s+3-2| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/relocation-copy-arm.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld -shared %t2.o -soname fixed-length-string.so -o %t2.so |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv %t.o %t2.so -o %t3 |
| 6 | // RUN: llvm-readobj -s -r --expand-relocs -symbols %t3 | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S -r --expand-relocs --symbols %t3 | FileCheck %s | |
| 7 | 7 | // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CODE %s |
| 8 | 8 | // RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi -section=.rodata %t3 | FileCheck -check-prefix=RODATA %s |
| 9 | 9 | |
| ... | ... | @@ -65,6 +65,7 @@ _start: |
| 65 | 65 | // CHECK-NEXT: Section: .bss |
| 66 | 66 | |
| 67 | 67 | // CODE: Disassembly of section .text: |
| 68 | // CODE-EMPTY: | |
| 68 | 69 | // CODE-NEXT: _start: |
| 69 | 70 | // S(y) = 0x13000, A = 0 |
| 70 | 71 | // (S + A) & 0x0000ffff = 0x3000 = #12288 |
| ... | ... | @@ -78,4 +79,4 @@ _start: |
| 78 | 79 | |
| 79 | 80 | // RODATA: Contents of section .rodata: |
| 80 | 81 | // S(z) = 0x13004 |
| 81 | // RODATA-NEXT: 10190 04300100 | |
| 82 | // RODATA-NEXT: 101b0 04300100 |
deps/lld/test/ELF/arm-data-prel.s+9-13| ... | ... | @@ -1,12 +1,11 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | // RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o %t.o | |
| 2 | // RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj --arm-add-build-attributes -o %t.o | |
| 3 | 3 | // RUN: echo "SECTIONS { \ |
| 4 | 4 | // RUN: .text : { *(.text) } \ |
| 5 | 5 | // RUN: .prel.test : { *(.ARM.exidx) } \ |
| 6 | // RUN: .prel.test.TEST1 : { *(.ARM.exidx.TEST1) } \ | |
| 7 | 6 | // RUN: .TEST1 : { *(.TEST1) } } " > %t.script |
| 8 | 7 | // RUN: ld.lld --script %t.script %t.o -o %t |
| 9 | // RUN: llvm-readobj -s -sd %t | FileCheck --check-prefix=CHECK %s | |
| 8 | // RUN: llvm-readobj -S --section-data %t | FileCheck --check-prefix=CHECK %s | |
| 10 | 9 | |
| 11 | 10 | // The R_ARM_PREL31 relocation is used in by the .ARM.exidx exception tables |
| 12 | 11 | // bit31 of the place denotes whether the field is an inline table entry |
| ... | ... | @@ -47,17 +46,14 @@ __aeabi_unwind_cpp_pr0: |
| 47 | 46 | // The expected value of the exception table is |
| 48 | 47 | // Word0 0 in bit 31, -4 encoded in 31-bit signed offset |
| 49 | 48 | // Word1 Inline table entry EHT Inline Personality Routine #0 |
| 50 | // CHECK: Name: .prel.test | |
| 51 | // CHECK: SectionData ( | |
| 52 | // CHECK: 0000: FCFFFF7F B0B0B080 | |
| 53 | // CHECK: ) | |
| 54 | ||
| 55 | // The expected value of the exception table is | |
| 56 | // Word0 0 in bit 31, +8 encoded in 31-bit signed offset | |
| 57 | // Word1 Inline table entry EHT Inline Personality Routine #0 | |
| 49 | // Word3 0 in bit 31, +10 encoded in 31-bit signed offset | |
| 50 | // Word4 Inline table entry EHT Inline Personality Routine #0 | |
| 58 | 51 | // set vsp = r11 |
| 59 | 52 | // pop r11, r14 |
| 60 | // CHECK: Name: .prel.test.TEST1 | |
| 53 | // Word5 Sentinel +18 EXIDX_CANTUNWIND | |
| 54 | ||
| 55 | // CHECK: Name: .prel.test | |
| 61 | 56 | // CHECK: SectionData ( |
| 62 | // CHECK: 0000: 08000000 80849B80 | |
| 57 | // CHECK: 0000: FCFFFF7F B0B0B080 10000000 80849B80 | |
| 58 | // CHECK: 0010: 18000000 01000000 | |
| 63 | 59 | // CHECK: ) |
deps/lld/test/ELF/arm-data-relocs.s+2| ... | ... | @@ -12,9 +12,11 @@ _start: |
| 12 | 12 | // S = 0x100, A = 0x24 |
| 13 | 13 | // S + A = 0x124 |
| 14 | 14 | // CHECK: Disassembly of section .R_ARM_ABS32POS: |
| 15 | // CHECK-EMPTY: | |
| 15 | 16 | // CHECK: 11000: 24 01 00 00 |
| 16 | 17 | .section .R_ARM_ABS32NEG, "ax",%progbits |
| 17 | 18 | .word foo - 0x24 |
| 18 | 19 | // S = 0x100, A = -0x24 |
| 19 | 20 | // CHECK: Disassembly of section .R_ARM_ABS32NEG: |
| 21 | // CHECK-EMPTY: | |
| 20 | 22 | // CHECK: 11004: dc 00 00 00 |
deps/lld/test/ELF/arm-eabi-version.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o |
| 3 | 3 | // RUN: ld.lld -static %t.o -o %tout |
| 4 | // RUN: llvm-readobj -file-headers %tout | FileCheck %s | |
| 4 | // RUN: llvm-readobj --file-headers %tout | FileCheck %s | |
| 5 | 5 | .syntax unified |
| 6 | 6 | .text |
| 7 | 7 | .globl _start |
deps/lld/test/ELF/arm-exidx-add-missing.s created+66| ... | ... | @@ -0,0 +1,66 @@ |
| 1 | // REQUIRES: arm | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi --arm-add-build-attributes %s -o %t | |
| 3 | // RUN: ld.lld %t --no-merge-exidx-entries -o %t2 | |
| 4 | // RUN: llvm-objdump -s %t2 | FileCheck %s | |
| 5 | // RUN: ld.lld %t -o %t3 | |
| 6 | // RUN: llvm-objdump -s %t3 | FileCheck %s -check-prefix=CHECK-MERGE | |
| 7 | ||
| 8 | // The ARM.exidx section is a table of 8-byte entries of the form: | |
| 9 | // | PREL31 Relocation to start of function | Unwinding information | | |
| 10 | // The range of addresses covered by the table entry is terminated by the | |
| 11 | // next table entry. This means that an executable section without a .ARM.exidx | |
| 12 | // section does not terminate the range of addresses. To fix this the linker | |
| 13 | // synthesises an EXIDX_CANTUNWIND entry for each section wihout a .ARM.exidx | |
| 14 | // section. | |
| 15 | ||
| 16 | .syntax unified | |
| 17 | ||
| 18 | // Expect inline unwind instructions | |
| 19 | .section .text.01, "ax", %progbits | |
| 20 | .global f1 | |
| 21 | f1: | |
| 22 | .fnstart | |
| 23 | bx lr | |
| 24 | .save {r7, lr} | |
| 25 | .setfp r7, sp, #0 | |
| 26 | .fnend | |
| 27 | ||
| 28 | // Expect no unwind information from assembler. The linker must | |
| 29 | // synthesise an EXIDX_CANTUNWIND entry to prevent an exception | |
| 30 | // thrown through f2 from matching against the unwind instructions | |
| 31 | // for f1. | |
| 32 | .section .text.02, "ax", %progbits | |
| 33 | .global f2 | |
| 34 | f2: | |
| 35 | bx lr | |
| 36 | ||
| 37 | ||
| 38 | // Expect 1 EXIDX_CANTUNWIND entry that can be merged into the linker | |
| 39 | // generated EXIDX_CANTUNWIND as if the assembler had generated it. | |
| 40 | .section .text.03, "ax",%progbits | |
| 41 | .global f3 | |
| 42 | f3: | |
| 43 | .fnstart | |
| 44 | bx lr | |
| 45 | .cantunwind | |
| 46 | .fnend | |
| 47 | ||
| 48 | // Dummy implementation of personality routines to satisfy reference | |
| 49 | // from exception tables, linker will generate EXIDX_CANTUNWIND. | |
| 50 | .section .text.__aeabi_unwind_cpp_pr0, "ax", %progbits | |
| 51 | .global __aeabi_unwind_cpp_pr0 | |
| 52 | __aeabi_unwind_cpp_pr0: | |
| 53 | bx lr | |
| 54 | ||
| 55 | // f1, f2 | |
| 56 | // CHECK: 100d4 2c0f0000 08849780 280f0000 01000000 | |
| 57 | // f3, __aeabi_unwind_cpp_pr0 | |
| 58 | // CHECK-NEXT: 100e4 240f0000 01000000 200f0000 01000000 | |
| 59 | // sentinel | |
| 60 | // CHECK-NEXT: 100f4 1c0f0000 01000000 | |
| 61 | ||
| 62 | // f1, (f2, f3, __aeabi_unwind_cpp_pr0) | |
| 63 | // CHECK-MERGE: 100d4 2c0f0000 08849780 280f0000 01000000 | |
| 64 | // sentinel | |
| 65 | // CHECK-MERGE-NEXT: 100e4 2c0f0000 01000000 | |
| 66 |
deps/lld/test/ELF/arm-exidx-canunwind.s+14-14| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t | |
| 3 | // RUN: ld.lld %t -o %t2 2>&1 | |
| 2 | // RUN: llvm-mc -filetype=obj --arm-add-build-attributes -triple=armv7a-none-linux-gnueabi %s -o %t | |
| 3 | // RUN: ld.lld %t -o %t2 | |
| 4 | 4 | // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s |
| 5 | 5 | // RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXIDX %s |
| 6 | 6 | // RUN: llvm-readobj --program-headers --sections %t2 | FileCheck -check-prefix=CHECK-PT %s |
| ... | ... | @@ -53,6 +53,7 @@ _start: |
| 53 | 53 | bx lr |
| 54 | 54 | |
| 55 | 55 | // CHECK: Disassembly of section .text: |
| 56 | // CHECK-EMPTY: | |
| 56 | 57 | // CHECK-NEXT: _start: |
| 57 | 58 | // CHECK-NEXT: 11000: 01 00 00 eb bl #4 <func1> |
| 58 | 59 | // CHECK-NEXT: 11004: 01 00 00 eb bl #4 <func2> |
| ... | ... | @@ -66,15 +67,14 @@ _start: |
| 66 | 67 | // CHECK: __aeabi_unwind_cpp_pr0: |
| 67 | 68 | // CHECK-NEXT: 11018: 1e ff 2f e1 bx lr |
| 68 | 69 | |
| 69 | // CHECK-EXIDX: Contents of section .ARM.exidx: | |
| 70 | // 100d4 + f38 = 1100c = func1 (inline unwinding data) | |
| 71 | // 100dc + f34 = 11010 = func2 (100e0 + c = 100ec = .ARM.extab entry) | |
| 72 | // CHECK-EXIDX-NEXT: 100d4 380f0000 08849780 340f0000 0c000000 | |
| 73 | // 100e4 + f30 = 11014 = terminate = func2 + sizeof(func2) | |
| 74 | // CHECK-EXIDX-NEXT: 100e4 300f0000 01000000 | |
| 75 | // CHECK-EXIDX-NEXT: Contents of section .ARM.extab: | |
| 76 | // 100ec + f28 = 11014 = __gxx_personality_v0 | |
| 77 | // CHECK-EXIDX-NEXT: 100ec 280f0000 b0b0b000 00000000 | |
| 70 | // 100d4 + f2c = 11000 = main (linker generated cantunwind) | |
| 71 | // 100dc + f30 = 1100c = func1 (inline unwinding data) | |
| 72 | // CHECK-EXIDX: 100d4 2c0f0000 01000000 300f0000 08849780 | |
| 73 | // 100e4 + f2c = 11010 = func2 (100e8 + 14 = 100fc = .ARM.extab entry) | |
| 74 | // 100ec + f28 = 11014 = __gcc_personality_v0 (linker generated cantunwind) | |
| 75 | // CHECK-EXIDX-NEXT: 100e4 2c0f0000 14000000 280f0000 01000000 | |
| 76 | // 100f4 + f28 = 1101c = sentinel | |
| 77 | // CHECK-EXIDX-NEXT: 100f4 280f0000 01000000 | |
| 78 | 78 | |
| 79 | 79 | // CHECK-PT: Name: .ARM.exidx |
| 80 | 80 | // CHECK-PT-NEXT: Type: SHT_ARM_EXIDX (0x70000001) |
| ... | ... | @@ -84,14 +84,14 @@ _start: |
| 84 | 84 | // CHECK-PT-NEXT: ] |
| 85 | 85 | // CHECK-PT-NEXT: Address: 0x100D4 |
| 86 | 86 | // CHECK-PT-NEXT: Offset: 0xD4 |
| 87 | // CHECK-PT-NEXT: Size: 24 | |
| 87 | // CHECK-PT-NEXT: Size: 40 | |
| 88 | 88 | |
| 89 | 89 | // CHECK-PT: Type: PT_ARM_EXIDX (0x70000001) |
| 90 | 90 | // CHECK-PT-NEXT: Offset: 0xD4 |
| 91 | 91 | // CHECK-PT-NEXT: VirtualAddress: 0x100D4 |
| 92 | 92 | // CHECK-PT-NEXT: PhysicalAddress: 0x100D4 |
| 93 | // CHECK-PT-NEXT: FileSize: 24 | |
| 94 | // CHECK-PT-NEXT: MemSize: 24 | |
| 93 | // CHECK-PT-NEXT: FileSize: 40 | |
| 94 | // CHECK-PT-NEXT: MemSize: 40 | |
| 95 | 95 | // CHECK-PT-NEXT: Flags [ (0x4) |
| 96 | 96 | // CHECK-PT-NEXT: PF_R (0x4) |
| 97 | 97 | // CHECK-PT-NEXT: ] |
deps/lld/test/ELF/arm-exidx-dedup.s+14-11| ... | ... | @@ -1,27 +1,29 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t | |
| 2 | // RUN: llvm-mc -filetype=obj --arm-add-build-attributes -triple=armv7a-none-linux-gnueabi %s -o %t | |
| 3 | 3 | // RUN: ld.lld %t --no-merge-exidx-entries -o %t2 |
| 4 | 4 | // RUN: llvm-objdump -s %t2 | FileCheck --check-prefix CHECK-DUPS %s |
| 5 | 5 | // RUN: ld.lld %t -o %t3 |
| 6 | 6 | // RUN: llvm-objdump -s %t3 | FileCheck %s |
| 7 | ||
| 7 | 8 | // Test that lld can at least remove duplicate .ARM.exidx sections. A more |
| 8 | 9 | // fine grained implementation will be able to remove duplicate entries within |
| 9 | 10 | // a .ARM.exidx section. |
| 10 | 11 | |
| 11 | 12 | // With duplicate entries |
| 12 | 13 | // CHECK-DUPS: Contents of section .ARM.exidx: |
| 13 | // CHECK-DUPS-NEXT: 100d4 2c0f0000 01000000 280f0000 01000000 | |
| 14 | // CHECK-DUPS-NEXT: 100e4 240f0000 01000000 200f0000 01000000 | |
| 15 | // CHECK-DUPS-NEXT: 100f4 1c0f0000 08849780 180f0000 08849780 | |
| 16 | // CHECK-DUPS-NEXT: 10104 140f0000 08849780 100f0000 14000000 | |
| 17 | // CHECK-DUPS-NEXT: 10114 0c0f0000 18000000 080f0000 01000000 | |
| 14 | // CHECK-DUPS-NEXT: 100d4 2c0f0000 01000000 280f0000 01000000 | |
| 15 | // CHECK-DUPS-NEXT: 100e4 240f0000 01000000 200f0000 01000000 | |
| 16 | // CHECK-DUPS-NEXT: 100f4 1c0f0000 08849780 180f0000 08849780 | |
| 17 | // CHECK-DUPS-NEXT: 10104 140f0000 08849780 100f0000 24000000 | |
| 18 | // CHECK-DUPS-NEXT: 10114 0c0f0000 28000000 080f0000 01000000 | |
| 19 | // CHECK-DUPS-NEXT: 10124 040f0000 01000000 000f0000 01000000 | |
| 18 | 20 | // CHECK-DUPS-NEXT: Contents of section .ARM.extab: |
| 19 | 21 | |
| 20 | 22 | // After duplicate entry removal |
| 21 | 23 | // CHECK: Contents of section .ARM.exidx: |
| 22 | // CHECK-NEXT: 100d4 2c0f0000 01000000 340f0000 08849780 | |
| 23 | // CHECK-NEXT: 100e4 380f0000 14000000 340f0000 18000000 | |
| 24 | // CHECK-NEXT: 100f4 300f0000 01000000 | |
| 24 | // CHECK-NEXT: 100d4 2c0f0000 01000000 340f0000 08849780 | |
| 25 | // CHECK-NEXT: 100e4 380f0000 1c000000 340f0000 20000000 | |
| 26 | // CHECK-NEXT: 100f4 300f0000 01000000 300f0000 01000000 | |
| 25 | 27 | // CHECK-NEXT: Contents of section .ARM.extab: |
| 26 | 28 | .syntax unified |
| 27 | 29 | |
| ... | ... | @@ -113,8 +115,9 @@ f8: |
| 113 | 115 | .long 0 |
| 114 | 116 | .fnend |
| 115 | 117 | |
| 116 | // Dummy implementation of personality routines to satisfy reference from | |
| 117 | // exception tables | |
| 118 | // Dummy implementation of personality routines to satisfy reference from | |
| 119 | // exception tables | |
| 120 | // Expect Linker generated EXIDX_CANTUNWIND tables | |
| 118 | 121 | .section .text.__gcc_personality_v0, "ax", %progbits |
| 119 | 122 | .global __gxx_personality_v0 |
| 120 | 123 | __gxx_personality_v0: |
deps/lld/test/ELF/arm-exidx-discard.s+5-2| ... | ... | @@ -2,12 +2,15 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple arm-gnu-linux-eabi -mcpu cortex-a7 -arm-add-build-attributes %s -o %t.o |
| 3 | 3 | // RUN: echo "ENTRY(__entrypoint) SECTIONS { . = 0x10000; .text : { *(.text .text.*) } /DISCARD/ : { *(.ARM.exidx*) *(.gnu.linkonce.armexidx.*) } }" > %t.script |
| 4 | 4 | // RUN: ld.lld -T %t.script %t.o -o %t.elf 2>&1 |
| 5 | // RUN: llvm-readobj -sections %t.elf | FileCheck %s | |
| 5 | // RUN: llvm-readobj --sections %t.elf | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | .globl __entrypoint |
| 8 | 8 | __entrypoint: |
| 9 | .fnstart | |
| 9 | 10 | bx lr |
| 10 | ||
| 11 | .save {r7, lr} | |
| 12 | .setfp r7, sp, #0 | |
| 13 | .fnend | |
| 11 | 14 | // Check that .ARM.exidx/.gnu.linkonce.armexidx |
| 12 | 15 | // are correctly removed if they were added. |
| 13 | 16 | // CHECK-NOT: .ARM.exidx |
deps/lld/test/ELF/arm-exidx-emit-relocs.s created+71| ... | ... | @@ -0,0 +1,71 @@ |
| 1 | // REQUIRES: arm | |
| 2 | // RUN: llvm-mc -filetype=obj --arm-add-build-attributes -triple=armv7a-none-linux-gnueabi %s -o %t | |
| 3 | // RUN: ld.lld --emit-relocs %t -o %t2 | |
| 4 | // RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s | |
| 5 | // RUN: llvm-readelf --relocs %t2 | FileCheck -check-prefix=CHECK-RELOCS %s | |
| 6 | ||
| 7 | // LLD does not support --emit-relocs for .ARM.exidx sections as the relocations | |
| 8 | // from synthetic table entries won't be represented. Given the known use cases | |
| 9 | // of --emit-relocs, relocating kernels, and binary analysis, the former doesn't | |
| 10 | // use exceptions and the latter can derive the relocations from the table if | |
| 11 | // they need them. | |
| 12 | .syntax unified | |
| 13 | // Will produce an ARM.exidx entry with inline unwinding instructions | |
| 14 | .section .text.func1, "ax",%progbits | |
| 15 | .global func1 | |
| 16 | func1: | |
| 17 | .fnstart | |
| 18 | bx lr | |
| 19 | .save {r7, lr} | |
| 20 | .setfp r7, sp, #0 | |
| 21 | .fnend | |
| 22 | ||
| 23 | .syntax unified | |
| 24 | .section .text.func2, "ax",%progbits | |
| 25 | // A function with the same inline unwinding instructions, expect merge. | |
| 26 | .global func2 | |
| 27 | func2: | |
| 28 | .fnstart | |
| 29 | bx lr | |
| 30 | .save {r7, lr} | |
| 31 | .setfp r7, sp, #0 | |
| 32 | .fnend | |
| 33 | ||
| 34 | .section .text.25, "ax", %progbits | |
| 35 | .global func25 | |
| 36 | func25: | |
| 37 | .fnstart | |
| 38 | bx lr | |
| 39 | .cantunwind | |
| 40 | .fnend | |
| 41 | ||
| 42 | .section .text.26, "ax", %progbits | |
| 43 | .global func26 | |
| 44 | func26: | |
| 45 | .fnstart | |
| 46 | bx lr | |
| 47 | .cantunwind | |
| 48 | .fnend | |
| 49 | ||
| 50 | .syntax unified | |
| 51 | .section .text.func3, "ax",%progbits | |
| 52 | // A function with the same inline unwinding instructions, expect merge. | |
| 53 | .global func3 | |
| 54 | func3: | |
| 55 | .fnstart | |
| 56 | bx lr | |
| 57 | .save {r7, lr} | |
| 58 | .setfp r7, sp, #0 | |
| 59 | .fnend | |
| 60 | ||
| 61 | .section .text.__aeabi_unwind_cpp_pr0, "ax", %progbits | |
| 62 | .global __aeabi_unwind_cpp_pr0 | |
| 63 | __aeabi_unwind_cpp_pr0: | |
| 64 | bx lr | |
| 65 | ||
| 66 | // CHECK: Contents of section .ARM.exidx: | |
| 67 | // CHECK-NEXT: 100d4 2c0f0000 08849780 2c0f0000 01000000 | |
| 68 | // CHECK-NEXT: 100e4 2c0f0000 08849780 280f0000 01000000 | |
| 69 | // CHECK-NEXT: 100f4 240f0000 01000000 | |
| 70 | ||
| 71 | // CHECK-RELOCS-NOT: Relocation section '.rel.ARM.exidx' |
deps/lld/test/ELF/arm-exidx-gc.s+13-11| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t | |
| 2 | // RUN: llvm-mc -filetype=obj --arm-add-build-attributes -triple=armv7a-none-linux-gnueabi %s -o %t | |
| 3 | 3 | // RUN: ld.lld %t --no-merge-exidx-entries -o %t2 --gc-sections 2>&1 |
| 4 | 4 | // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s |
| 5 | 5 | // RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXIDX %s |
| ... | ... | @@ -91,6 +91,7 @@ _start: |
| 91 | 91 | // routines are kept alive by references from live .ARM.exidx and .ARM.extab |
| 92 | 92 | // sections |
| 93 | 93 | // CHECK: Disassembly of section .text: |
| 94 | // CHECK-EMPTY: | |
| 94 | 95 | // CHECK-NEXT: _start: |
| 95 | 96 | // CHECK-NEXT: 11000: 01 00 00 eb bl #4 <func1> |
| 96 | 97 | // CHECK-NEXT: 11004: 01 00 00 eb bl #4 <func2> |
| ... | ... | @@ -111,14 +112,15 @@ _start: |
| 111 | 112 | // CHECK-NOT: __gxx_personality_v1 |
| 112 | 113 | |
| 113 | 114 | // CHECK-EXIDX: Contents of section .ARM.exidx: |
| 114 | // 100d4 + f38 = 1100c = func1 | |
| 115 | // 100dc + f34 = 11010 = func2 (100e0 + 1c = 100fc = .ARM.extab) | |
| 116 | // CHECK-EXIDX-NEXT: 100d4 380f0000 08849780 340f0000 1c000000 | |
| 117 | // 100e4 + f30 = 11014 = __gxx_personality_v0 | |
| 118 | // 100ec + f2c = 11018 = __aeabi_unwind_cpp_pr0 | |
| 119 | // CHECK-EXIDX-NEXT: 100e4 300f0000 01000000 2c0f0000 01000000 | |
| 120 | // 100f4 + f28 = 1101c = __aeabi_unwind_cpp_pr0 + sizeof(__aeabi_unwind_cpp_pr0) | |
| 121 | // CHECK-EXIDX-NEXT: 100f4 280f0000 01000000 | |
| 115 | // 100d4 + f2c = 11000 | |
| 116 | // 100dc + f30 = 1100c = func1 | |
| 117 | // CHECK-EXIDX-NEXT: 100d4 2c0f0000 01000000 300f0000 08849780 | |
| 118 | // 100e4 + f2c = 11010 = func2 (100e8 + 1c = 10104 = .ARM.extab) | |
| 119 | // 100ec + f28 = 11014 = __gxx_personality_v0 | |
| 120 | // CHECK-EXIDX-NEXT: 100e4 2c0f0000 1c000000 280f0000 01000000 | |
| 121 | // 100f4 + f24 = 11018 = __aeabi_unwind_cpp_pr0 | |
| 122 | // 100fc + f20 = 1101c = __aeabi_unwind_cpp_pr0 + sizeof(__aeabi_unwind_cpp_pr0) | |
| 123 | // CHECK-EXIDX-NEXT: 100f4 240f0000 01000000 200f0000 01000000 | |
| 122 | 124 | // CHECK-EXIDX-NEXT: Contents of section .ARM.extab: |
| 123 | // 100fc + f18 = 11014 = __gxx_personality_v0 | |
| 124 | // CHECK-EXIDX-NEXT: 100fc 180f0000 b0b0b000 | |
| 125 | // 10104 + f10 = 11014 = __gxx_personality_v0 | |
| 126 | // CHECK-EXIDX-NEXT: 10104 100f0000 b0b0b000 |
deps/lld/test/ELF/arm-exidx-link.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -s %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // CHECK: Name: .ARM.exidx |
| 7 | 7 | // CHECK-NEXT: Type: SHT_ARM_EXIDX |
deps/lld/test/ELF/arm-exidx-order.s+11| ... | ... | @@ -54,6 +54,7 @@ f3: |
| 54 | 54 | // Check default no linker script order. |
| 55 | 55 | |
| 56 | 56 | // CHECK: Disassembly of section .text: |
| 57 | // CHECK-EMPTY: | |
| 57 | 58 | // CHECK: _start: |
| 58 | 59 | // CHECK-NEXT: 11000: 1e ff 2f e1 bx lr |
| 59 | 60 | // CHECK: f1: |
| ... | ... | @@ -67,12 +68,15 @@ f3: |
| 67 | 68 | // CHECK: func5: |
| 68 | 69 | // CHECK-NEXT: 11014: 1e ff 2f e1 bx lr |
| 69 | 70 | // CHECK: Disassembly of section .func1: |
| 71 | // CHECK-EMPTY: | |
| 70 | 72 | // CHECK-NEXT: func1: |
| 71 | 73 | // CHECK-NEXT: 11018: 1e ff 2f e1 bx lr |
| 72 | 74 | // CHECK: Disassembly of section .func2: |
| 75 | // CHECK-EMPTY: | |
| 73 | 76 | // CHECK-NEXT: func2: |
| 74 | 77 | // CHECK-NEXT: 1101c: 1e ff 2f e1 bx lr |
| 75 | 78 | // CHECK: Disassembly of section .func3: |
| 79 | // CHECK-EMPTY: | |
| 76 | 80 | // CHECK-NEXT: func3: |
| 77 | 81 | // CHECK-NEXT: 11020: 1e ff 2f e1 bx lr |
| 78 | 82 | |
| ... | ... | @@ -128,6 +132,7 @@ f3: |
| 128 | 132 | // the .text section but before the orphan sections |
| 129 | 133 | |
| 130 | 134 | // CHECK-SCRIPT: Disassembly of section .text: |
| 135 | // CHECK-SCRIPT-EMPTY: | |
| 131 | 136 | // CHECK-SCRIPT-NEXT: func4: |
| 132 | 137 | // CHECK-SCRIPT-NEXT: 11000: 1e ff 2f e1 bx lr |
| 133 | 138 | // CHECK-SCRIPT: func5: |
| ... | ... | @@ -140,13 +145,19 @@ f3: |
| 140 | 145 | // CHECK-SCRIPT-NEXT: 11010: 1e ff 2f e1 bx lr |
| 141 | 146 | // CHECK-SCRIPT: f3: |
| 142 | 147 | // CHECK-SCRIPT-NEXT: 11014: 1e ff 2f e1 bx lr |
| 148 | // CHECK-SCRIPT-EMPTY: | |
| 143 | 149 | // CHECK-SCRIPT-NEXT: Disassembly of section .func1: |
| 150 | // CHECK-SCRIPT-EMPTY: | |
| 144 | 151 | // CHECK-SCRIPT-NEXT: func1: |
| 145 | 152 | // CHECK-SCRIPT-NEXT: 11018: 1e ff 2f e1 bx lr |
| 153 | // CHECK-SCRIPT-EMPTY: | |
| 146 | 154 | // CHECK-SCRIPT-NEXT: Disassembly of section .func2: |
| 155 | // CHECK-SCRIPT-EMPTY: | |
| 147 | 156 | // CHECK-SCRIPT-NEXT: func2: |
| 148 | 157 | // CHECK-SCRIPT-NEXT: 1101c: 1e ff 2f e1 bx lr |
| 158 | // CHECK-SCRIPT-EMPTY: | |
| 149 | 159 | // CHECK-SCRIPT-NEXT: Disassembly of section .func3: |
| 160 | // CHECK-SCRIPT-EMPTY: | |
| 150 | 161 | // CHECK-SCRIPT-NEXT: func3: |
| 151 | 162 | // CHECK-SCRIPT-NEXT: 11020: 1e ff 2f e1 bx lr |
| 152 | 163 |
deps/lld/test/ELF/arm-exidx-output.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t |
| 3 | 3 | // RUN: ld.lld %t -o %t2 2>&1 |
| 4 | // RUN: llvm-readobj -sections %t2 | FileCheck %s | |
| 4 | // RUN: llvm-readobj --sections %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // Check that only a single .ARM.exidx output section is created when |
| 7 | 7 | // there are input sections of the form .ARM.exidx.<section-name>. The |
deps/lld/test/ELF/arm-exidx-relocatable.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-exidx-cantunwind.s -o %tcantunwind |
| 4 | 4 | // Check that relocatable link maintains SHF_LINK_ORDER |
| 5 | 5 | // RUN: ld.lld -r %t %tcantunwind -o %t4 2>&1 |
| 6 | // RUN: llvm-readobj -s %t4 | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S %t4 | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | // Each assembler created .ARM.exidx section has the SHF_LINK_ORDER flag set |
| 9 | 9 | // with the sh_link containing the section index of the executable section |
deps/lld/test/ELF/arm-exidx-sentinel-norelocatable.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | 2 | // RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o %t.o |
| 3 | 3 | // RUN: ld.lld -r %t.o -o %t |
| 4 | // RUN: llvm-readobj -s %t | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S %t | FileCheck %s | |
| 5 | 5 | // Check that when doing a relocatable link we don't add a terminating entry |
| 6 | 6 | // to the .ARM.exidx section |
| 7 | 7 | .syntax unified |
deps/lld/test/ELF/arm-exidx-shared.s+5-5| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t | |
| 2 | // RUN: llvm-mc -filetype=obj -arm-add-build-attributes -triple=armv7a-none-linux-gnueabi %s -o %t | |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv %t --shared -o %t2 2>&1 |
| 4 | 4 | // RUN: llvm-readobj --relocations %t2 | FileCheck %s |
| 5 | // RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXTAB %s | |
| 5 | // RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck --check-prefix=CHECK-EXTAB-NEXT %s | |
| 6 | 6 | |
| 7 | 7 | // Check that the relative R_ARM_PREL31 relocation can access a PLT entry |
| 8 | 8 | // for when the personality routine is referenced from a shared library. |
| ... | ... | @@ -38,8 +38,8 @@ __aeabi_unwind_cpp_pr0: |
| 38 | 38 | |
| 39 | 39 | // CHECK: Relocations [ |
| 40 | 40 | // CHECK-NEXT: Section {{.*}} .rel.plt { |
| 41 | // CHECK-NEXT: 0x200C R_ARM_JUMP_SLOT __gxx_personality_v0 | |
| 41 | // CHECK-NEXT: 0x300C R_ARM_JUMP_SLOT __gxx_personality_v0 | |
| 42 | 42 | |
| 43 | 43 | // CHECK-EXTAB: Contents of section .ARM.extab: |
| 44 | // 0x0210 + 0x0e20 = 0x1030 = __gxx_personality_v0(PLT) | |
| 45 | // CHECK-EXTAB-NEXT: 0210 200e0000 b0b0b000 00000000 | |
| 44 | // 0x0238 + 0xdf8 = 0x1030 = __gxx_personality_v0(PLT) | |
| 45 | // CHECK-EXTAB-NEXT: 0238 f80d0000 b0b0b000 00000000 |
deps/lld/test/ELF/arm-exidx-synthetic-link.s created+37| ... | ... | @@ -0,0 +1,37 @@ |
| 1 | // REQUIRES: arm | |
| 2 | // RUN: llvm-mc -filetype=obj -arm-add-build-attributes -triple=armv7a-none-linux-gnueabi %s -o %t.o | |
| 3 | // RUN: ld.lld %t.o -o %t.so -shared | |
| 4 | // RUN: llvm-readobj -S %t.so | FileCheck %s | |
| 5 | ||
| 6 | // Test that when all the .ARM.exidx sections are merged into a single | |
| 7 | // synthetic EXIDX_CANTUNWIND entry we can still set the SHF_LINK_ORDER | |
| 8 | // link. | |
| 9 | .syntax unified | |
| 10 | .section .text.1, "ax", %progbits | |
| 11 | .globl f1 | |
| 12 | .type f1, %function | |
| 13 | f1: | |
| 14 | bx lr | |
| 15 | ||
| 16 | .section .text.2, "ax", %progbits | |
| 17 | .globl f2 | |
| 18 | .type f2, %function | |
| 19 | f2: | |
| 20 | .fnstart | |
| 21 | bx lr | |
| 22 | .cantunwind | |
| 23 | .fnend | |
| 24 | ||
| 25 | // CHECK: Name: .ARM.exidx | |
| 26 | // CHECK-NEXT: Type: SHT_ARM_EXIDX | |
| 27 | // CHECK-NEXT: Flags [ | |
| 28 | // CHECK-NEXT: SHF_ALLOC | |
| 29 | // CHECK-NEXT: SHF_LINK_ORDER | |
| 30 | // CHECK-NEXT: ] | |
| 31 | // CHECK-NEXT: Address: | |
| 32 | // CHECK-NEXT: Offset: | |
| 33 | // CHECK-NEXT: Size: | |
| 34 | // CHECK-NEXT: Link: [[INDEX:.*]] | |
| 35 | ||
| 36 | // CHECK: Index: [[INDEX]] | |
| 37 | // CHECK-NEXT: Name: .text |
deps/lld/test/ELF/arm-extreme-range-pi-thunk.s+4| ... | ... | @@ -32,6 +32,7 @@ high: |
| 32 | 32 | // ARMv7a instructions and relocations. |
| 33 | 33 | |
| 34 | 34 | // CHECK: Disassembly of section .text_low: |
| 35 | // CHECK-EMPTY: | |
| 35 | 36 | // CHECK-NEXT: _start: |
| 36 | 37 | // CHECK-NEXT: 130: 00 00 00 eb bl #0 <__ARMV7PILongThunk_high> |
| 37 | 38 | // CHECK-NEXT: 134: 1e ff 2f e1 bx lr |
| ... | ... | @@ -44,6 +45,7 @@ high: |
| 44 | 45 | // CHECK-NEXT: 144: 1c ff 2f e1 bx r12 |
| 45 | 46 | |
| 46 | 47 | // CHECK: Disassembly of section .text_high: |
| 48 | // CHECK-EMPTY: | |
| 47 | 49 | // CHECK-NEXT: high: |
| 48 | 50 | // CHECK-NEXT: f0000000: 00 00 00 eb bl #0 <__ARMV7PILongThunk__start> |
| 49 | 51 | // CHECK-NEXT: f0000004: 1e ff 2f e1 bx lr |
| ... | ... | @@ -57,6 +59,7 @@ high: |
| 57 | 59 | |
| 58 | 60 | // Thumbv7a instructions and relocations |
| 59 | 61 | // CHECK-THUMB: Disassembly of section .text_low: |
| 62 | // CHECK-THUMB-EMPTY: | |
| 60 | 63 | // CHECK-THUMB-NEXT: _start: |
| 61 | 64 | // CHECK-THUMB-NEXT: 130: 00 f0 02 f8 bl #4 |
| 62 | 65 | // CHECK-THUMB-NEXT: 134: 70 47 bx lr |
| ... | ... | @@ -70,6 +73,7 @@ high: |
| 70 | 73 | // CHECK-THUMB-NEXT: 142: 60 47 bx r12 |
| 71 | 74 | |
| 72 | 75 | // CHECK-THUMB: Disassembly of section .text_high: |
| 76 | // CHECK-THUMB-EMPTY: | |
| 73 | 77 | // CHECK-THUMB-NEXT: high: |
| 74 | 78 | // CHECK-THUMB-NEXT: f0000000: 00 f0 02 f8 bl #4 |
| 75 | 79 | // CHECK-THUMB-NEXT: f0000004: 70 47 bx lr |
deps/lld/test/ELF/arm-force-pi-thunk.s+2| ... | ... | @@ -31,6 +31,7 @@ low_target2: |
| 31 | 31 | bl high_target2 |
| 32 | 32 | |
| 33 | 33 | // CHECK: Disassembly of section .text_low: |
| 34 | // CHECK-EMPTY: | |
| 34 | 35 | // CHECK-NEXT: _start: |
| 35 | 36 | // CHECK-NEXT: 94: 70 47 bx lr |
| 36 | 37 | // CHECK: low_target: |
| ... | ... | @@ -69,6 +70,7 @@ high_target2: |
| 69 | 70 | bl low_target2 |
| 70 | 71 | |
| 71 | 72 | // CHECK: Disassembly of section .text_high: |
| 73 | // CHECK-EMPTY: | |
| 72 | 74 | // CHECK-NEXT: high_target: |
| 73 | 75 | // CHECK-NEXT: 2000000: 00 f0 02 f8 bl #4 |
| 74 | 76 | // CHECK-NEXT: 2000004: 00 f0 06 f8 bl #12 |
deps/lld/test/ELF/arm-fpic-got.s+7-6| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t |
| 4 | // RUN: llvm-readobj -s %t | FileCheck %s | |
| 5 | // RUN: llvm-readobj -s -symbols %t | FileCheck -check-prefix=SYMBOLS %s | |
| 4 | // RUN: llvm-readobj -S %t | FileCheck %s | |
| 5 | // RUN: llvm-readobj -S --symbols %t | FileCheck -check-prefix=SYMBOLS %s | |
| 6 | 6 | // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t | FileCheck -check-prefix=CODE %s |
| 7 | 7 | |
| 8 | 8 | // Test the R_ARM_GOT_PREL relocation |
| ... | ... | @@ -36,7 +36,7 @@ val: |
| 36 | 36 | // CHECK-NEXT: SHF_ALLOC |
| 37 | 37 | // CHECK-NEXT: SHF_WRITE |
| 38 | 38 | // CHECK-NEXT: ] |
| 39 | // CHECK-NEXT: Address: 0x13000 | |
| 39 | // CHECK-NEXT: Address: 0x12000 | |
| 40 | 40 | // CHECK-NEXT: Offset: |
| 41 | 41 | // CHECK-NEXT: Size: 4 |
| 42 | 42 | // CHECK-NEXT: Link: |
| ... | ... | @@ -45,7 +45,7 @@ val: |
| 45 | 45 | // CHECK-NEXT: EntrySize: |
| 46 | 46 | |
| 47 | 47 | // SYMBOLS: Name: val |
| 48 | // SYMBOLS-NEXT: Value: 0x12000 | |
| 48 | // SYMBOLS-NEXT: Value: 0x13000 | |
| 49 | 49 | // SYMBOLS-NEXT: Size: 4 |
| 50 | 50 | // SYMBOLS-NEXT: Binding: Global |
| 51 | 51 | // SYMBOLS-NEXT: Type: Object |
| ... | ... | @@ -53,11 +53,12 @@ val: |
| 53 | 53 | // SYMBOLS-NEXT: Section: .data |
| 54 | 54 | |
| 55 | 55 | // CODE: Disassembly of section .text: |
| 56 | // CODE-EMPTY: | |
| 56 | 57 | // CODE-NEXT: _start: |
| 57 | 58 | // CODE-NEXT: 11000: 08 00 9f e5 ldr r0, [pc, #8] |
| 58 | 59 | // CODE-NEXT: 11004: 00 00 9f e7 ldr r0, [pc, r0] |
| 59 | 60 | // CODE-NEXT: 11008: 00 00 90 e5 ldr r0, [r0] |
| 60 | 61 | // CODE-NEXT: 1100c: 1e ff 2f e1 bx lr |
| 61 | 62 | // CODE: $d.1: |
| 62 | // 0x11004 + 0x1ff4 + 8 = 0x13000 = .got | |
| 63 | // CODE-NEXT: 11010: f4 1f 00 00 | |
| 63 | // 0x11004 + 0x0ff4 + 8 = 0x12000 = .got | |
| 64 | // CODE-NEXT: 11010: f4 0f 00 00 |
deps/lld/test/ELF/arm-gnu-ifunc-nosym.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o |
| 3 | 3 | // RUN: ld.lld -static %t.o -o %tout |
| 4 | // RUN: llvm-readobj -symbols %tout | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols %tout | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // Check that no __rel_iplt_end/__rel_iplt_start |
| 7 | 7 | // appear in symtab if there are no references to them. |
deps/lld/test/ELF/arm-gnu-ifunc-plt.s+19-16| ... | ... | @@ -5,30 +5,31 @@ |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv %t.so %t.o -o %tout |
| 6 | 6 | // RUN: llvm-objdump -triple=armv7a-linux-gnueabihf -d %tout | FileCheck %s --check-prefix=DISASM |
| 7 | 7 | // RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT |
| 8 | // RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s | |
| 8 | // RUN: llvm-readobj -r --dynamic-table %tout | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | // Check that the IRELATIVE relocations are last in the .got |
| 11 | 11 | // CHECK: Relocations [ |
| 12 | 12 | // CHECK-NEXT: Section (4) .rel.dyn { |
| 13 | // CHECK-NEXT: 0x13078 R_ARM_GLOB_DAT bar2 0x0 | |
| 14 | // CHECK-NEXT: 0x1307C R_ARM_GLOB_DAT zed2 0x0 | |
| 15 | // CHECK-NEXT: 0x13080 R_ARM_IRELATIVE - 0x0 | |
| 16 | // CHECK-NEXT: 0x13084 R_ARM_IRELATIVE - 0x0 | |
| 13 | // CHECK-NEXT: 0x12078 R_ARM_GLOB_DAT bar2 0x0 | |
| 14 | // CHECK-NEXT: 0x1207C R_ARM_GLOB_DAT zed2 0x0 | |
| 15 | // CHECK-NEXT: 0x12080 R_ARM_IRELATIVE - 0x0 | |
| 16 | // CHECK-NEXT: 0x12084 R_ARM_IRELATIVE - 0x0 | |
| 17 | 17 | // CHECK-NEXT: } |
| 18 | 18 | // CHECK-NEXT: Section (5) .rel.plt { |
| 19 | // CHECK-NEXT: 0x1200C R_ARM_JUMP_SLOT bar2 0x0 | |
| 20 | // CHECK-NEXT: 0x12010 R_ARM_JUMP_SLOT zed2 0x0 | |
| 19 | // CHECK-NEXT: 0x1300C R_ARM_JUMP_SLOT bar2 0x0 | |
| 20 | // CHECK-NEXT: 0x13010 R_ARM_JUMP_SLOT zed2 0x0 | |
| 21 | 21 | // CHECK-NEXT: } |
| 22 | 22 | // CHECK-NEXT: ] |
| 23 | 23 | |
| 24 | 24 | // Check that the GOT entries refer back to the ifunc resolver |
| 25 | // GOTPLT: Contents of section .got.plt: | |
| 26 | // GOTPLT-NEXT: 12000 00000000 00000000 00000000 20100100 | |
| 27 | // GOTPLT-NEXT: 12010 20100100 | |
| 28 | 25 | // GOTPLT: Contents of section .got: |
| 29 | // GOTPLT-NEXT: 13078 00000000 00000000 00100100 04100100 | |
| 26 | // GOTPLT-NEXT: 12078 00000000 00000000 00100100 04100100 | |
| 27 | // GOTPLT: Contents of section .got.plt: | |
| 28 | // GOTPLT-NEXT: 13000 00000000 00000000 00000000 20100100 | |
| 29 | // GOTPLT-NEXT: 13010 20100100 | |
| 30 | 30 | |
| 31 | 31 | // DISASM: Disassembly of section .text: |
| 32 | // DISASM-EMPTY: | |
| 32 | 33 | // DISASM-NEXT: foo: |
| 33 | 34 | // DISASM-NEXT: 11000: 1e ff 2f e1 bx lr |
| 34 | 35 | // DISASM: bar: |
| ... | ... | @@ -41,11 +42,13 @@ |
| 41 | 42 | // DISASM-NEXT: 11014: 04 00 00 00 .word 0x00000004 |
| 42 | 43 | // DISASM: 11018: 08 00 00 eb bl #32 |
| 43 | 44 | // DISASM-NEXT: 1101c: 0b 00 00 eb bl #44 |
| 45 | // DISASM-EMPTY: | |
| 44 | 46 | // DISASM-NEXT: Disassembly of section .plt: |
| 47 | // DISASM-EMPTY: | |
| 45 | 48 | // DISASM-NEXT: $a: |
| 46 | 49 | // DISASM-NEXT: 11020: 04 e0 2d e5 str lr, [sp, #-4]! |
| 47 | 50 | // DISASM-NEXT: 11024: 00 e6 8f e2 add lr, pc, #0, #12 |
| 48 | // DISASM-NEXT: 11028: 00 ea 8e e2 add lr, lr, #0, #20 | |
| 51 | // DISASM-NEXT: 11028: 01 ea 8e e2 add lr, lr, #4096 | |
| 49 | 52 | // DISASM-NEXT: 1102c: dc ff be e5 ldr pc, [lr, #4060]! |
| 50 | 53 | // DISASM: $d: |
| 51 | 54 | // DISASM-NEXT: 11030: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| ... | ... | @@ -54,25 +57,25 @@ |
| 54 | 57 | // DISASM-NEXT: 1103c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| 55 | 58 | // DISASM: $a: |
| 56 | 59 | // DISASM-NEXT: 11040: 00 c6 8f e2 add r12, pc, #0, #12 |
| 57 | // DISASM-NEXT: 11044: 00 ca 8c e2 add r12, r12, #0, #20 | |
| 60 | // DISASM-NEXT: 11044: 01 ca 8c e2 add r12, r12, #4096 | |
| 58 | 61 | // DISASM-NEXT: 11048: c4 ff bc e5 ldr pc, [r12, #4036]! |
| 59 | 62 | // DISASM: $d: |
| 60 | 63 | // DISASM-NEXT: 1104c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| 61 | 64 | // DISASM: $a: |
| 62 | 65 | // DISASM-NEXT: 11050: 00 c6 8f e2 add r12, pc, #0, #12 |
| 63 | // DISASM-NEXT: 11054: 00 ca 8c e2 add r12, r12, #0, #20 | |
| 66 | // DISASM-NEXT: 11054: 01 ca 8c e2 add r12, r12, #4096 | |
| 64 | 67 | // DISASM-NEXT: 11058: b8 ff bc e5 ldr pc, [r12, #4024]! |
| 65 | 68 | // DISASM: $d: |
| 66 | 69 | // DISASM-NEXT: 1105c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| 67 | 70 | // DISASM: $a: |
| 68 | 71 | // DISASM-NEXT: 11060: 00 c6 8f e2 add r12, pc, #0, #12 |
| 69 | // DISASM-NEXT: 11064: 02 ca 8c e2 add r12, r12, #8192 | |
| 72 | // DISASM-NEXT: 11064: 01 ca 8c e2 add r12, r12, #4096 | |
| 70 | 73 | // DISASM-NEXT: 11068: 18 f0 bc e5 ldr pc, [r12, #24]! |
| 71 | 74 | // DISASM: $d: |
| 72 | 75 | // DISASM-NEXT: 1106c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| 73 | 76 | // DISASM: $a: |
| 74 | 77 | // DISASM-NEXT: 11070: 00 c6 8f e2 add r12, pc, #0, #12 |
| 75 | // DISASM-NEXT: 11074: 02 ca 8c e2 add r12, r12, #8192 | |
| 78 | // DISASM-NEXT: 11074: 01 ca 8c e2 add r12, r12, #4096 | |
| 76 | 79 | // DISASM-NEXT: 11078: 0c f0 bc e5 ldr pc, [r12, #12]! |
| 77 | 80 | // DISASM: $d: |
| 78 | 81 | // DISASM-NEXT: 1107c:	d4 d4 d4 d4 	.word	0xd4d4d4d4 |
deps/lld/test/ELF/arm-gnu-ifunc.s+4-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o |
| 3 | 3 | // RUN: ld.lld -static %t.o -o %tout |
| 4 | 4 | // RUN: llvm-objdump -triple armv7a-none-linux-gnueabi -d %tout | FileCheck %s --check-prefix=DISASM |
| 5 | // RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s | |
| 5 | // RUN: llvm-readobj -r --symbols --sections %tout | FileCheck %s | |
| 6 | 6 | .syntax unified |
| 7 | 7 | .text |
| 8 | 8 | .type foo STT_GNU_IFUNC |
| ... | ... | @@ -113,6 +113,7 @@ _start: |
| 113 | 113 | // CHECK-NEXT: } |
| 114 | 114 | |
| 115 | 115 | // DISASM: Disassembly of section .text: |
| 116 | // DISASM-EMPTY: | |
| 116 | 117 | // DISASM-NEXT: foo: |
| 117 | 118 | // DISASM-NEXT: 11000: 1e ff 2f e1 bx lr |
| 118 | 119 | // DISASM: bar: |
| ... | ... | @@ -126,7 +127,9 @@ _start: |
| 126 | 127 | // 1 * 65536 + 260 = 0x10104 __rel_iplt_end |
| 127 | 128 | // DISASM-NEXT: 11018: 04 01 00 e3 movw r0, #260 |
| 128 | 129 | // DISASM-NEXT: 1101c: 01 00 40 e3 movt r0, #1 |
| 130 | // DISASM-EMPTY: | |
| 129 | 131 | // DISASM-NEXT: Disassembly of section .plt: |
| 132 | // DISASM-EMPTY: | |
| 130 | 133 | // DISASM-NEXT: $a: |
| 131 | 134 | // DISASM-NEXT: 11020: 00 c6 8f e2 add r12, pc, #0, #12 |
| 132 | 135 | // DISASM-NEXT: 11024: 00 ca 8c e2 add r12, r12, #0, #20 |
deps/lld/test/ELF/arm-got-relative.s+2-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | 2 | // RUN: llvm-mc -position-independent -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv %t.o -shared -o %t |
| 4 | // RUN: llvm-readobj -s -symbols -dyn-relocations %t | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S --symbols --dyn-relocations %t | FileCheck %s | |
| 5 | 5 | // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t | FileCheck -check-prefix=CODE %s |
| 6 | 6 | .syntax unified |
| 7 | 7 | .text |
| ... | ... | @@ -41,6 +41,7 @@ function: |
| 41 | 41 | // CHECK-NEXT: Section: .got |
| 42 | 42 | |
| 43 | 43 | // CODE: Disassembly of section .text: |
| 44 | // CODE-EMPTY: | |
| 44 | 45 | // CODE-NEXT: _start: |
| 45 | 46 | // CODE-NEXT: 1000: 08 30 9f e5 ldr r3, [pc, #8] |
| 46 | 47 | // CODE-NEXT: 1004: 08 20 9f e5 ldr r2, [pc, #8] |
deps/lld/test/ELF/arm-gotoff.s+2-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabi %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t |
| 4 | // RUN: llvm-readobj -s -r -t %t | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S -r --symbols %t | FileCheck %s | |
| 5 | 5 | // RUN: llvm-objdump -triple=armv7a-linux-gnueabi -d %t | FileCheck --check-prefix=DISASM %s |
| 6 | 6 | |
| 7 | 7 | // Test the R_ARM_GOTOFF32 relocation |
| ... | ... | @@ -53,6 +53,7 @@ |
| 53 | 53 | // CHECK-NEXT: Section: .bss |
| 54 | 54 | |
| 55 | 55 | // DISASM: Disassembly of section .text: |
| 56 | // DISASM-EMPTY: | |
| 56 | 57 | // DISASM-NEXT :_start: |
| 57 | 58 | // DISASM-NEXT 11000: 1e ff 2f e1 bx lr |
| 58 | 59 | // Offset 0 from .got = bar |
deps/lld/test/ELF/arm-icf-exidx.s+1| ... | ... | @@ -23,6 +23,7 @@ __aeabi_unwind_cpp_pr0: |
| 23 | 23 | bx lr |
| 24 | 24 | |
| 25 | 25 | // CHECK: Disassembly of section .text: |
| 26 | // CHECK-EMPTY: | |
| 26 | 27 | // CHECK-NEXT: g: |
| 27 | 28 | // CHECK-NEXT: 11000: 1e ff 2f e1 bx lr |
| 28 | 29 | // CHECK: __aeabi_unwind_cpp_pr0: |
deps/lld/test/ELF/arm-mov-relocs.s+2| ... | ... | @@ -18,6 +18,7 @@ _start: |
| 18 | 18 | movw r3, :lower16:label3 |
| 19 | 19 | movw r4, :lower16:label3 + 4 |
| 20 | 20 | // CHECK: Disassembly of section .R_ARM_MOVW_ABS_NC |
| 21 | // CHECK-EMPTY: | |
| 21 | 22 | // CHECK: movw	r0, #0 |
| 22 | 23 | // CHECK: movw	r1, #4 |
| 23 | 24 | // CHECK: movw	r2, #12 |
| ... | ... | @@ -30,6 +31,7 @@ _start: |
| 30 | 31 | movt r3, :upper16:label3 |
| 31 | 32 | movt r4, :upper16:label3 + 4 |
| 32 | 33 | // CHECK: Disassembly of section .R_ARM_MOVT_ABS |
| 34 | // CHECK-EMPTY: | |
| 33 | 35 | // CHECK: movt	r0, #2 |
| 34 | 36 | // CHECK: movt	r1, #2 |
| 35 | 37 | // CHECK: movt	r2, #2 |
deps/lld/test/ELF/arm-pie-relative.s+2-2| ... | ... | @@ -19,7 +19,7 @@ sym: |
| 19 | 19 | |
| 20 | 20 | // CHECK: Relocations [ |
| 21 | 21 | // CHECK-NEXT: Section (4) .rel.dyn { |
| 22 | // CHECK-NEXT: 0x3058 R_ARM_RELATIVE | |
| 22 | // CHECK-NEXT: 0x2058 R_ARM_RELATIVE | |
| 23 | 23 | |
| 24 | 24 | // GOT: Contents of section .got: |
| 25 | // GOT-NEXT: 3058 00200000 | |
| 25 | // GOT-NEXT: 2058 00300000 |
deps/lld/test/ELF/arm-plt-reloc.s+29-16| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | // RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t | FileCheck %s |
| 6 | 6 | // RUN: ld.lld --hash-style=sysv -shared %t1 %t2 -o %t3 |
| 7 | 7 | // RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSO %s |
| 8 | // RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s | |
| 8 | // RUN: llvm-readobj -S -r %t3 | FileCheck -check-prefix=DSOREL %s | |
| 9 | 9 | // |
| 10 | 10 | // Test PLT entry generation |
| 11 | 11 | .syntax unified |
| ... | ... | @@ -20,6 +20,7 @@ _start: |
| 20 | 20 | |
| 21 | 21 | // Executable, expect no PLT |
| 22 | 22 | // CHECK: Disassembly of section .text: |
| 23 | // CHECK-EMPTY: | |
| 23 | 24 | // CHECK-NEXT: func1: |
| 24 | 25 | // CHECK-NEXT: 11000: 1e ff 2f e1 bx lr |
| 25 | 26 | // CHECK: func2: |
| ... | ... | @@ -34,6 +35,7 @@ _start: |
| 34 | 35 | // Expect PLT entries as symbols can be preempted |
| 35 | 36 | // The .got.plt and .plt displacement is small so we can use small PLT entries. |
| 36 | 37 | // DSO: Disassembly of section .text: |
| 38 | // DSO-EMPTY: | |
| 37 | 39 | // DSO-NEXT: func1: |
| 38 | 40 | // DSO-NEXT: 1000: 1e ff 2f e1 bx lr |
| 39 | 41 | // DSO: func2: |
| ... | ... | @@ -47,12 +49,14 @@ _start: |
| 47 | 49 | // DSO-NEXT: 1010: 0e 00 00 eb bl #56 |
| 48 | 50 | // S(0x10160) - P(0x1014) + A(-8) = 0x44 = 68 |
| 49 | 51 | // DSO-NEXT: 1014: 11 00 00 0a beq #68 |
| 52 | // DSO-EMPTY: | |
| 50 | 53 | // DSO-NEXT: Disassembly of section .plt: |
| 54 | // DSO-EMPTY: | |
| 51 | 55 | // DSO-NEXT: $a: |
| 52 | 56 | // DSO-NEXT: 1020: 04 e0 2d e5 str lr, [sp, #-4]! |
| 53 | // (0x1024 + 8) + (0 RoR 12) + (0 RoR 20) + (0xfdc) = 0x2008 = .got.plt[3] | |
| 57 | // (0x1024 + 8) + (0 RoR 12) + 4096 + (0xfdc) = 0x3008 = .got.plt[3] | |
| 54 | 58 | // DSO-NEXT: 1024: 00 e6 8f e2 add lr, pc, #0, #12 |
| 55 | // DSO-NEXT: 1028: 00 ea 8e e2 add lr, lr, #0, #20 | |
| 59 | // DSO-NEXT: 1028: 01 ea 8e e2 add lr, lr, #4096 | |
| 56 | 60 | // DSO-NEXT: 102c: dc ff be e5 ldr pc, [lr, #4060]! |
| 57 | 61 | // DSO: $d: |
| 58 | 62 | // DSO-NEXT: 1030: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| ... | ... | @@ -60,23 +64,23 @@ _start: |
| 60 | 64 | // DSO-NEXT: 1038: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| 61 | 65 | // DSO-NEXT: 103c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| 62 | 66 | // DSO: $a: |
| 63 | // (0x1040 + 8) + (0 RoR 12) + (0 RoR 20) + (0xfc4) = 0x200c | |
| 67 | // (0x1040 + 8) + (0 RoR 12) + 4096 + (0xfc4) = 0x300c | |
| 64 | 68 | // DSO-NEXT: 1040: 00 c6 8f e2 add r12, pc, #0, #12 |
| 65 | // DSO-NEXT: 1044: 00 ca 8c e2 add r12, r12, #0, #20 | |
| 69 | // DSO-NEXT: 1044: 01 ca 8c e2 add r12, r12, #4096 | |
| 66 | 70 | // DSO-NEXT: 1048: c4 ff bc e5 ldr pc, [r12, #4036]! |
| 67 | 71 | // DSO: $d: |
| 68 | 72 | // DSO-NEXT: 104c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| 69 | 73 | // DSO: $a: |
| 70 | // (0x1050 + 8) + (0 RoR 12) + (0 RoR 20) + (0xfb8) = 0x2010 | |
| 74 | // (0x1050 + 8) + (0 RoR 12) + 4096 + (0xfb8) = 0x3010 | |
| 71 | 75 | // DSO-NEXT: 1050: 00 c6 8f e2 add r12, pc, #0, #12 |
| 72 | // DSO-NEXT: 1054: 00 ca 8c e2 add r12, r12, #0, #20 | |
| 76 | // DSO-NEXT: 1054: 01 ca 8c e2 add r12, r12, #4096 | |
| 73 | 77 | // DSO-NEXT: 1058: b8 ff bc e5 ldr pc, [r12, #4024]! |
| 74 | 78 | // DSO: $d: |
| 75 | 79 | // DSO-NEXT: 105c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| 76 | 80 | // DSO: $a: |
| 77 | // (0x1060 + 8) + (0 RoR 12) + (0 RoR 20) + (0xfac) = 0x2014 | |
| 81 | // (0x1060 + 8) + (0 RoR 12) + 4096 + (0xfac) = 0x3014 | |
| 78 | 82 | // DSO-NEXT: 1060: 00 c6 8f e2 add r12, pc, #0, #12 |
| 79 | // DSO-NEXT: 1064: 00 ca 8c e2 add r12, r12, #0, #20 | |
| 83 | // DSO-NEXT: 1064: 01 ca 8c e2 add r12, r12, #4096 | |
| 80 | 84 | // DSO-NEXT: 1068: ac ff bc e5 ldr pc, [r12, #4012]! |
| 81 | 85 | // DSO: $d: |
| 82 | 86 | // DSO-NEXT: 106c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| ... | ... | @@ -88,7 +92,7 @@ _start: |
| 88 | 92 | // DSOREL-NEXT: SHF_ALLOC |
| 89 | 93 | // DSOREL-NEXT: SHF_WRITE |
| 90 | 94 | // DSOREL-NEXT: ] |
| 91 | // DSOREL-NEXT: Address: 0x2000 | |
| 95 | // DSOREL-NEXT: Address: 0x3000 | |
| 92 | 96 | // DSOREL-NEXT: Offset: |
| 93 | 97 | // DSOREL-NEXT: Size: 24 |
| 94 | 98 | // DSOREL-NEXT: Link: |
| ... | ... | @@ -97,9 +101,9 @@ _start: |
| 97 | 101 | // DSOREL-NEXT: EntrySize: |
| 98 | 102 | // DSOREL: Relocations [ |
| 99 | 103 | // DSOREL-NEXT: Section {{.*}} .rel.plt { |
| 100 | // DSOREL-NEXT: 0x200C R_ARM_JUMP_SLOT func1 0x0 | |
| 101 | // DSOREL-NEXT: 0x2010 R_ARM_JUMP_SLOT func2 0x0 | |
| 102 | // DSOREL-NEXT: 0x2014 R_ARM_JUMP_SLOT func3 0x0 | |
| 104 | // DSOREL-NEXT: 0x300C R_ARM_JUMP_SLOT func1 0x0 | |
| 105 | // DSOREL-NEXT: 0x3010 R_ARM_JUMP_SLOT func2 0x0 | |
| 106 | // DSOREL-NEXT: 0x3014 R_ARM_JUMP_SLOT func3 0x0 | |
| 103 | 107 | |
| 104 | 108 | // Test a large separation between the .plt and .got.plt |
| 105 | 109 | // The .got.plt and .plt displacement is large but still within the range |
| ... | ... | @@ -111,9 +115,10 @@ _start: |
| 111 | 115 | // RUN: }" > %t.script |
| 112 | 116 | // RUN: ld.lld --hash-style=sysv --script %t.script -shared %t1 %t2 -o %t4 |
| 113 | 117 | // RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t4 | FileCheck --check-prefix=CHECKHIGH %s |
| 114 | // RUN: llvm-readobj -s -r %t4 | FileCheck --check-prefix=DSORELHIGH %s | |
| 118 | // RUN: llvm-readobj -S -r %t4 | FileCheck --check-prefix=DSORELHIGH %s | |
| 115 | 119 | |
| 116 | 120 | // CHECKHIGH: Disassembly of section .text: |
| 121 | // CHECKHIGH-EMPTY: | |
| 117 | 122 | // CHECKHIGH-NEXT: func1: |
| 118 | 123 | // CHECKHIGH-NEXT: 1000: 1e ff 2f e1 bx lr |
| 119 | 124 | // CHECKHIGH: func2: |
| ... | ... | @@ -124,7 +129,9 @@ _start: |
| 124 | 129 | // CHECKHIGH-NEXT: 100c: 03 04 00 ea b #4108 <$a> |
| 125 | 130 | // CHECKHIGH-NEXT: 1010: 06 04 00 eb bl #4120 <$a> |
| 126 | 131 | // CHECKHIGH-NEXT: 1014: 09 04 00 0a beq #4132 <$a> |
| 132 | // CHECKHIGH-EMPTY: | |
| 127 | 133 | // CHECKHIGH-NEXT: Disassembly of section .plt: |
| 134 | // CHECKHIGH-EMPTY: | |
| 128 | 135 | // CHECKHIGH-NEXT: $a: |
| 129 | 136 | // CHECKHIGH-NEXT: 2000: 04 e0 2d e5 str lr, [sp, #-4]! |
| 130 | 137 | // CHECKHIGH-NEXT: 2004: 10 e6 8f e2 add lr, pc, #16, #12 |
| ... | ... | @@ -176,9 +183,10 @@ _start: |
| 176 | 183 | // RUN: }" > %t2.script |
| 177 | 184 | // RUN: ld.lld --hash-style=sysv --script %t2.script -shared %t1 %t2 -o %t5 |
| 178 | 185 | // RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t5 | FileCheck --check-prefix=CHECKLONG %s |
| 179 | // RUN: llvm-readobj -s -r %t5 | FileCheck --check-prefix=DSORELLONG %s | |
| 186 | // RUN: llvm-readobj -S -r %t5 | FileCheck --check-prefix=DSORELLONG %s | |
| 180 | 187 | |
| 181 | 188 | // CHECKLONG: Disassembly of section .text: |
| 189 | // CHECKLONG-EMPTY: | |
| 182 | 190 | // CHECKLONG-NEXT: func1: |
| 183 | 191 | // CHECKLONG-NEXT: 1000: 1e ff 2f e1 bx lr |
| 184 | 192 | // CHECKLONG: func2: |
| ... | ... | @@ -189,7 +197,9 @@ _start: |
| 189 | 197 | // CHECKLONG-NEXT: 100c: 03 04 00 ea b #4108 <$a> |
| 190 | 198 | // CHECKLONG-NEXT: 1010: 06 04 00 eb bl #4120 <$a> |
| 191 | 199 | // CHECKLONG-NEXT: 1014: 09 04 00 0a beq #4132 <$a> |
| 200 | // CHECKLONG-EMPTY: | |
| 192 | 201 | // CHECKLONG-NEXT: Disassembly of section .plt: |
| 202 | // CHECKLONG-EMPTY: | |
| 193 | 203 | // CHECKLONG-NEXT: $a: |
| 194 | 204 | // CHECKLONG-NEXT: 2000: 04 e0 2d e5 str lr, [sp, #-4]! |
| 195 | 205 | // CHECKLONG-NEXT: 2004: 04 e0 9f e5 ldr lr, [pc, #4] |
| ... | ... | @@ -242,9 +252,10 @@ _start: |
| 242 | 252 | // RUN: }" > %t3.script |
| 243 | 253 | // RUN: ld.lld --hash-style=sysv --script %t3.script -shared %t1 %t2 -o %t6 |
| 244 | 254 | // RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t6 | FileCheck --check-prefix=CHECKMIX %s |
| 245 | // RUN: llvm-readobj -s -r %t6 | FileCheck --check-prefix=DSORELMIX %s | |
| 255 | // RUN: llvm-readobj -S -r %t6 | FileCheck --check-prefix=DSORELMIX %s | |
| 246 | 256 | |
| 247 | 257 | // CHECKMIX: Disassembly of section .text: |
| 258 | // CHECKMIX-EMPTY: | |
| 248 | 259 | // CHECKMIX-NEXT: func1: |
| 249 | 260 | // CHECKMIX-NEXT: 1000: 1e ff 2f e1 bx lr |
| 250 | 261 | // CHECKMIX: func2: |
| ... | ... | @@ -255,7 +266,9 @@ _start: |
| 255 | 266 | // CHECKMIX-NEXT: 100c: 03 04 00 ea b #4108 <$a> |
| 256 | 267 | // CHECKMIX-NEXT: 1010: 06 04 00 eb bl #4120 <$a> |
| 257 | 268 | // CHECKMIX-NEXT: 1014: 09 04 00 0a beq #4132 <$a> |
| 269 | // CHECKMIX-EMPTY: | |
| 258 | 270 | // CHECKMIX-NEXT: Disassembly of section .plt: |
| 271 | // CHECKMIX-EMPTY: | |
| 259 | 272 | // CHECKMIX-NEXT: $a: |
| 260 | 273 | // CHECKMIX-NEXT: 2000: 04 e0 2d e5 str lr, [sp, #-4]! |
| 261 | 274 | // CHECKMIX-NEXT: 2004: 04 e0 9f e5 ldr lr, [pc, #4] |
deps/lld/test/ELF/arm-sbrel32.s+1| ... | ... | @@ -31,6 +31,7 @@ foo3: .space 4 |
| 31 | 31 | foo4: .space 4 |
| 32 | 32 | |
| 33 | 33 | // CHECK: Disassembly of section .text: |
| 34 | // CHECK-EMPTY: | |
| 34 | 35 | // CHECK-NEXT: _start: |
| 35 | 36 | // CHECK-NEXT: 11000: 1e ff 2f e1 bx lr |
| 36 | 37 | // CHECK: 11004: 00 00 00 00 .word 0x00000000 |
deps/lld/test/ELF/arm-tag-vfp-args.s+7-7| ... | ... | @@ -7,15 +7,15 @@ |
| 7 | 7 | |
| 8 | 8 | // The default for this file is 0 (Base AAPCS) |
| 9 | 9 | // RUN: ld.lld %t.o -o %tdefault |
| 10 | // RUN: llvm-readobj -file-headers %tdefault | FileCheck -check-prefix=CHECK-BASE %s | |
| 10 | // RUN: llvm-readobj --file-headers %tdefault | FileCheck -check-prefix=CHECK-BASE %s | |
| 11 | 11 | |
| 12 | 12 | // Expect explicit Base AAPCS. |
| 13 | 13 | // RUN: ld.lld %t.o %tbase.o -o %tbase |
| 14 | // RUN: llvm-readobj -file-headers %tbase | FileCheck -check-prefix=CHECK-BASE %s | |
| 14 | // RUN: llvm-readobj --file-headers %tbase | FileCheck -check-prefix=CHECK-BASE %s | |
| 15 | 15 | |
| 16 | 16 | // Expect explicit Base AAPCS when linking Base and Compatible. |
| 17 | 17 | // RUN: ld.lld %t.o %tbase.o %tcompat.o -o %tbasecompat |
| 18 | // RUN: llvm-readobj -file-headers %tbasecompat | FileCheck -check-prefix=CHECK-BASE %s | |
| 18 | // RUN: llvm-readobj --file-headers %tbasecompat | FileCheck -check-prefix=CHECK-BASE %s | |
| 19 | 19 | |
| 20 | 20 | // CHECK-BASE: Flags [ (0x5000200) |
| 21 | 21 | // CHECK-BASE-NEXT: 0x200 |
| ... | ... | @@ -25,11 +25,11 @@ |
| 25 | 25 | |
| 26 | 26 | // Expect Hard float VFP AAPCS |
| 27 | 27 | // RUN: ld.lld %t.o %tvfp.o -o %tvfp |
| 28 | // RUN: llvm-readobj -file-headers %tvfp | FileCheck -check-prefix=CHECK-VFP %s | |
| 28 | // RUN: llvm-readobj --file-headers %tvfp | FileCheck -check-prefix=CHECK-VFP %s | |
| 29 | 29 | |
| 30 | 30 | // Expect Hard float VFP AAPCS when linking VFP and Compatible |
| 31 | 31 | // RUN: ld.lld %t.o %tvfp.o %tcompat.o -o %tvfpcompat |
| 32 | // RUN: llvm-readobj -file-headers %tvfpcompat | FileCheck -check-prefix=CHECK-VFP %s | |
| 32 | // RUN: llvm-readobj --file-headers %tvfpcompat | FileCheck -check-prefix=CHECK-VFP %s | |
| 33 | 33 | |
| 34 | 34 | // CHECK-VFP: Flags [ (0x5000400) |
| 35 | 35 | // CHECK-VFP-NEXT: 0x400 |
| ... | ... | @@ -39,11 +39,11 @@ |
| 39 | 39 | |
| 40 | 40 | // Expect Toolchain specifc to not use either Base or VFP AAPCS |
| 41 | 41 | // RUN: ld.lld %t.o %ttoolchain.o -o %ttoolchain |
| 42 | // RUN: llvm-readobj -file-headers %ttoolchain | FileCheck -check-prefix=CHECK-TOOLCHAIN %s | |
| 42 | // RUN: llvm-readobj --file-headers %ttoolchain | FileCheck -check-prefix=CHECK-TOOLCHAIN %s | |
| 43 | 43 | |
| 44 | 44 | // Expect Toolchain and Compatible to have same affect as Toolchain. |
| 45 | 45 | // RUN: ld.lld %t.o %ttoolchain.o %tcompat.o -o %ttoolchaincompat |
| 46 | // RUN: llvm-readobj -file-headers %ttoolchaincompat | FileCheck -check-prefix=CHECK-TOOLCHAIN %s | |
| 46 | // RUN: llvm-readobj --file-headers %ttoolchaincompat | FileCheck -check-prefix=CHECK-TOOLCHAIN %s | |
| 47 | 47 | |
| 48 | 48 | // CHECK-TOOLCHAIN: Flags [ (0x5000000) |
| 49 | 49 | // CHECK-TOOLCHAIN-NEXT: 0x1000000 |
deps/lld/test/ELF/arm-target1.s+1| ... | ... | @@ -26,6 +26,7 @@ |
| 26 | 26 | // Force generation of $d.0 as section is not all data |
| 27 | 27 | nop |
| 28 | 28 | // RELATIVE: Disassembly of section .text: |
| 29 | // RELATIVE-EMPTY: | |
| 29 | 30 | // RELATIVE: $d.0: |
| 30 | 31 | // RELATIVE: 1000: 04 00 00 00 .word 0x00000004 |
| 31 | 32 | // RELATIVE: SYMBOL TABLE: |
deps/lld/test/ELF/arm-thumb-blx.s+5| ... | ... | @@ -41,14 +41,17 @@ _start: |
| 41 | 41 | bx lr |
| 42 | 42 | |
| 43 | 43 | // CHECK-ARM: Disassembly of section .R_ARM_CALL24_callee1: |
| 44 | // CHECK-ARM-EMPTY: | |
| 44 | 45 | // CHECK-NEXT-ARM: callee_low: |
| 45 | 46 | // CHECK-NEXT-ARM: b4: 1e ff 2f e1 bx lr |
| 46 | 47 | |
| 47 | 48 | // CHECK-THUMB: Disassembly of section .R_ARM_CALL24_callee2: |
| 49 | // CHECK-THUMB-EMPTY: | |
| 48 | 50 | // CHECK-NEXT-THUMB: callee_thumb_low: |
| 49 | 51 | // CHECK-NEXT-THUMB: 100:	70 47 	bx	lr |
| 50 | 52 | |
| 51 | 53 | // CHECK-THUMB: Disassembly of section .caller: |
| 54 | // CHECK-THUMB-EMPTY: | |
| 52 | 55 | // CHECK-THUMB: _start: |
| 53 | 56 | // Align(0x10000,4) - 0xff50 (65360) + 4 = 0xb4 = callee_low |
| 54 | 57 | // CHECK-NEXT-THUMB: 10000: f0 f7 58 e8 blx #-65360 |
| ... | ... | @@ -77,9 +80,11 @@ _start: |
| 77 | 80 | |
| 78 | 81 | |
| 79 | 82 | // CHECK-ARM: Disassembly of section .R_ARM_CALL24_callee3: |
| 83 | // CHECK-ARM-EMPTY: | |
| 80 | 84 | // CHECK-NEXT-ARM: callee_high: |
| 81 | 85 | // CHECK-NEXT-ARM: 10100: 1e ff 2f e1 bx lr |
| 82 | 86 | |
| 83 | 87 | // CHECK: Disassembly of section .R_ARM_CALL24_callee4: |
| 88 | // CHECK-EMPTY: | |
| 84 | 89 | // CHECK-NEXT-THUMB:callee_thumb_high: |
| 85 | 90 | // CHECK-NEXT-THUMB: 10200: 70 47 bx lr |
deps/lld/test/ELF/arm-thumb-branch-rangethunk.s+1| ... | ... | @@ -17,6 +17,7 @@ _start: |
| 17 | 17 | beq.w too_far3 |
| 18 | 18 | |
| 19 | 19 | // CHECK: Disassembly of section .text: |
| 20 | // CHECK-EMPTY: | |
| 20 | 21 | // CHECK-NEXT: _start: |
| 21 | 22 | // CHECK-NEXT: 20000: 00 f0 04 f8 bl #8 |
| 22 | 23 | // CHECK-NEXT: 20004: 00 f0 07 b8 b.w #14 <__Thumbv7ABSLongThunk_too_far2> |
deps/lld/test/ELF/arm-thumb-branch.s+5| ... | ... | @@ -40,9 +40,12 @@ callee_high: |
| 40 | 40 | bx lr |
| 41 | 41 | |
| 42 | 42 | // CHECK: Disassembly of section .callee1: |
| 43 | // CHECK-EMPTY: | |
| 43 | 44 | // CHECK-NEXT: callee_low: |
| 44 | 45 | // CHECK-NEXT: b4: 70 47 bx lr |
| 46 | // CHECK-EMPTY: | |
| 45 | 47 | // CHECK-NEXT: Disassembly of section .caller: |
| 48 | // CHECK-EMPTY: | |
| 46 | 49 | // CHECK-NEXT: _start: |
| 47 | 50 | // CHECK-NEXT: 10000: f0 f7 58 f8 bl #-65360 |
| 48 | 51 | // CHECK-NEXT: 10004: f0 f7 56 b8 b.w #-65364 |
| ... | ... | @@ -55,6 +58,8 @@ callee_high: |
| 55 | 58 | // CHECK-NEXT: 10020: 3f f3 ff af bgt.w #1048574 |
| 56 | 59 | // CHECK-NEXT: 10024: 70 47 bx lr |
| 57 | 60 | // CHECK-NEXT: 10026: |
| 61 | // CHECK-EMPTY: | |
| 58 | 62 | // CHECK-NEXT: Disassembly of section .callee2: |
| 63 | // CHECK-EMPTY: | |
| 59 | 64 | // CHECK-NEXT: callee_high: |
| 60 | 65 | // CHECK-NEXT: 10028: 70 47 bx lr |
deps/lld/test/ELF/arm-thumb-condbranch-thunk.s+1| ... | ... | @@ -34,6 +34,7 @@ _start: |
| 34 | 34 | // Section |
| 35 | 35 | bl tfunc33 |
| 36 | 36 | // CHECK1: Disassembly of section .text: |
| 37 | // CHECK1-EMPTY: | |
| 37 | 38 | // CHECK1-NEXT: tfunc00: |
| 38 | 39 | // CHECK1-NEXT: 80000: 70 47 bx lr |
| 39 | 40 | // CHECK1-NEXT: 80002: 7f f3 ff d7 bl #16252926 |
deps/lld/test/ELF/arm-thumb-interwork-shared.s+5-3| ... | ... | @@ -15,6 +15,7 @@ sym1: |
| 15 | 15 | // entry. |
| 16 | 16 | |
| 17 | 17 | // CHECK: Disassembly of section .text: |
| 18 | // CHECK-EMPTY: | |
| 18 | 19 | // CHECK-NEXT: sym1: |
| 19 | 20 | // CHECK-NEXT: 1000: 00 f0 02 b8 b.w #4 <__ThumbV7PILongThunk_elsewhere> |
| 20 | 21 | // CHECK-NEXT: 1004: 00 f0 06 b8 b.w #12 <__ThumbV7PILongThunk_weakref> |
| ... | ... | @@ -30,10 +31,11 @@ sym1: |
| 30 | 31 | // CHECK-NEXT: 101e: 60 47 bx r12 |
| 31 | 32 | |
| 32 | 33 | // PLT: Disassembly of section .plt: |
| 34 | // PLT-EMPTY: | |
| 33 | 35 | // PLT-NEXT: $a: |
| 34 | 36 | // PLT-NEXT: 1020: 04 e0 2d e5 str lr, [sp, #-4]! |
| 35 | 37 | // PLT-NEXT: 1024: 00 e6 8f e2 add lr, pc, #0, #12 |
| 36 | // PLT-NEXT: 1028: 00 ea 8e e2 add lr, lr, #0, #20 | |
| 38 | // PLT-NEXT: 1028: 01 ea 8e e2 add lr, lr, #4096 | |
| 37 | 39 | // PLT-NEXT: 102c: dc ff be e5 ldr pc, [lr, #4060]! |
| 38 | 40 | // PLT: $d: |
| 39 | 41 | // PLT-NEXT: 1030: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| ... | ... | @@ -42,13 +44,13 @@ sym1: |
| 42 | 44 | // PLT-NEXT: 103c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| 43 | 45 | // PLT: $a: |
| 44 | 46 | // PLT-NEXT: 1040: 00 c6 8f e2 add r12, pc, #0, #12 |
| 45 | // PLT-NEXT: 1044: 00 ca 8c e2 add r12, r12, #0, #20 | |
| 47 | // PLT-NEXT: 1044: 01 ca 8c e2 add r12, r12, #4096 | |
| 46 | 48 | // PLT-NEXT: 1048: c4 ff bc e5 ldr pc, [r12, #4036]! |
| 47 | 49 | // PLT: $d: |
| 48 | 50 | // PLT-NEXT: 104c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| 49 | 51 | // PLT: $a: |
| 50 | 52 | // PLT-NEXT: 1050: 00 c6 8f e2 add r12, pc, #0, #12 |
| 51 | // PLT-NEXT: 1054: 00 ca 8c e2 add r12, r12, #0, #20 | |
| 53 | // PLT-NEXT: 1054: 01 ca 8c e2 add r12, r12, #4096 | |
| 52 | 54 | // PLT-NEXT: 1058: b8 ff bc e5 ldr pc, [r12, #4024]! |
| 53 | 55 | // PLT: $d: |
| 54 | 56 | // PLT-NEXT: 105c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
deps/lld/test/ELF/arm-thumb-interwork-thunk.s+11-1| ... | ... | @@ -19,7 +19,7 @@ |
| 19 | 19 | // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CHECK-ARM -check-prefix=CHECK-PI-ARM %s |
| 20 | 20 | // RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t4 | FileCheck -check-prefix=CHECK-THUMB -check-prefix=CHECK-PI-PLT-THUMB %s |
| 21 | 21 | // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t4 | FileCheck -check-prefix=CHECK-ARM -check-prefix=CHECK-PI-PLT-ARM %s |
| 22 | // RUN: llvm-readobj -s -r %t4 | FileCheck -check-prefix=CHECK-DSO-REL %s | |
| 22 | // RUN: llvm-readobj -S -r %t4 | FileCheck -check-prefix=CHECK-DSO-REL %s | |
| 23 | 23 | |
| 24 | 24 | // Test ARM Thumb Interworking |
| 25 | 25 | // The file is linked and checked 3 times to check the following contexts |
| ... | ... | @@ -39,6 +39,7 @@ thumb_callee1: |
| 39 | 39 | bx lr |
| 40 | 40 | |
| 41 | 41 | // CHECK-THUMB: Disassembly of section .R_ARM_JUMP24_callee_1: |
| 42 | // CHECK-THUMB-EMPTY: | |
| 42 | 43 | // CHECK-THUMB: thumb_callee1: |
| 43 | 44 | // CHECK-THUMB: 1000: 70 47 bx |
| 44 | 45 | .section .R_ARM_THM_JUMP_callee_low, "ax", %progbits |
| ... | ... | @@ -79,6 +80,7 @@ arm_caller: |
| 79 | 80 | bne arm_callee3 |
| 80 | 81 | bx lr |
| 81 | 82 | // CHECK-ARM-ABS-ARM: Disassembly of section .arm_caller: |
| 83 | // CHECK-ARM-ABS-ARM-EMPTY: | |
| 82 | 84 | // CHECK-ARM-ABS-ARM-NEXT: arm_caller: |
| 83 | 85 | // CHECK-ARM-ABS-ARM-NEXT: 1300: 3e ff ff fa blx #-776 <thumb_callee1> |
| 84 | 86 | // CHECK-ARM-ABS-ARM-NEXT: 1304: 3d ff ff fa blx #-780 <thumb_callee1> |
| ... | ... | @@ -107,6 +109,7 @@ arm_caller: |
| 107 | 109 | // CHECK-ARM-ABS-ARM-NEXT: 1348: 1c ff 2f e1 bx r12 |
| 108 | 110 | |
| 109 | 111 | // CHECK-PI-ARM: Disassembly of section .arm_caller: |
| 112 | // CHECK-PI-ARM-EMPTY: | |
| 110 | 113 | // CHECK-PI-ARM-NEXT: arm_caller: |
| 111 | 114 | // CHECK-PI-ARM-NEXT: 1300: 3e ff ff fa blx #-776 <thumb_callee1> |
| 112 | 115 | // CHECK-PI-ARM-NEXT: 1304: 3d ff ff fa blx #-780 <thumb_callee1> |
| ... | ... | @@ -140,6 +143,7 @@ arm_caller: |
| 140 | 143 | |
| 141 | 144 | // All PLT entries are ARM, no need for interworking thunks |
| 142 | 145 | // CHECK-PI-ARM-PLT: Disassembly of section .arm_caller: |
| 146 | // CHECK-PI-ARM-PLT-EMPTY: | |
| 143 | 147 | // CHECK-PI-ARM-PLT-NEXT: arm_caller: |
| 144 | 148 | // 0x17e4 PLT(thumb_callee1) |
| 145 | 149 | // CHECK-PI-ARM-PLT-NEXT: 1300: 37 01 00 eb bl #1244 |
| ... | ... | @@ -184,6 +188,7 @@ thumb_caller: |
| 184 | 188 | beq.w arm_callee2 |
| 185 | 189 | bne.w arm_callee3 |
| 186 | 190 | // CHECK-ABS-THUMB: Disassembly of section .thumb_caller: |
| 191 | // CHECK-ABS-THUMB-EMPTY: | |
| 187 | 192 | // CHECK-ABS-THUMB-NEXT: thumb_caller: |
| 188 | 193 | // CHECK-ABS-THUMB-NEXT: 1400: ff f7 7e ee blx #-772 |
| 189 | 194 | // CHECK-ABS-THUMB-NEXT: 1404: ff f7 7c ee blx #-776 |
| ... | ... | @@ -210,6 +215,7 @@ thumb_caller: |
| 210 | 215 | // CHECK-ABS-THUMB-NEXT: 143c: 60 47 bx r12 |
| 211 | 216 | |
| 212 | 217 | // CHECK-PI-THUMB: Disassembly of section .thumb_caller: |
| 218 | // CHECK-PI-THUMB-EMPTY: | |
| 213 | 219 | // CHECK-PI-THUMB-NEXT: thumb_caller: |
| 214 | 220 | // CHECK-PI-THUMB-NEXT: 1400: ff f7 7e ee blx #-772 |
| 215 | 221 | // CHECK-PI-THUMB-NEXT: 1404: ff f7 7c ee blx #-776 |
| ... | ... | @@ -239,6 +245,7 @@ thumb_caller: |
| 239 | 245 | // CHECK-PI-THUMB-NEXT: 1442: 60 47 bx r12 |
| 240 | 246 | |
| 241 | 247 | // CHECK-PI-THUMB-PLT: Disassembly of section .arm_caller: |
| 248 | // CHECK-PI-THUMB-PLT-EMPTY: | |
| 242 | 249 | // CHECK-PI-THUMB-PLT-NEXT: thumb_caller: |
| 243 | 250 | // 0x1400 + 4 + 0x410 = 0x1814 = PLT(arm_callee1) |
| 244 | 251 | // CHECK-PI-THUMB-PLT-NEXT: 1400: 00 f0 08 ea blx #1040 |
| ... | ... | @@ -286,6 +293,7 @@ thumb_callee2: |
| 286 | 293 | thumb_callee3: |
| 287 | 294 | bx lr |
| 288 | 295 | // CHECK-THUMB: Disassembly of section .R_ARM_JUMP24_callee_2: |
| 296 | // CHECK-THUMB-EMPTY: | |
| 289 | 297 | // CHECK-THUMB-NEXT: thumb_callee2: |
| 290 | 298 | // CHECK-THUMB-NEXT: 1500: 70 47 bx lr |
| 291 | 299 | // CHECK-THUMB: thumb_callee3: |
| ... | ... | @@ -303,6 +311,7 @@ arm_callee2: |
| 303 | 311 | arm_callee3: |
| 304 | 312 | bx lr |
| 305 | 313 | // CHECK-ARM: Disassembly of section .R_ARM_THM_JUMP_callee_2: |
| 314 | // CHECK-ARM-EMPTY: | |
| 306 | 315 | // CHECK-ARM-NEXT: arm_callee2: |
| 307 | 316 | // CHECK-ARM-NEXT: 1600: 1e ff 2f e1 bx lr |
| 308 | 317 | // CHECK-ARM: arm_callee3: |
| ... | ... | @@ -321,6 +330,7 @@ _start: |
| 321 | 330 | |
| 322 | 331 | |
| 323 | 332 | // CHECK-PI-ARM-PLT: Disassembly of section .plt: |
| 333 | // CHECK-PI-ARM-PLT-EMPTY: | |
| 324 | 334 | // CHECK-PI-ARM-PLT-NEXT: .plt: |
| 325 | 335 | // CHECK-PI-ARM-PLT-NEXT: 17b0: 04 e0 2d e5 str lr, [sp, #-4]! |
| 326 | 336 | // CHECK-PI-ARM-PLT-NEXT: 17b4: 04 e0 9f e5 ldr lr, [pc, #4] |
deps/lld/test/ELF/arm-thumb-narrow-branch-check.s+7| ... | ... | @@ -50,9 +50,12 @@ callee_high: |
| 50 | 50 | callee_high_far = 0x180d |
| 51 | 51 | |
| 52 | 52 | // CHECK: Disassembly of section .R_ARM_PC11_1: |
| 53 | // CHECK-EMPTY: | |
| 53 | 54 | // CHECK-NEXT: callee_low: |
| 54 | 55 | // CHECK-NEXT: 1000: 70 47 bx lr |
| 56 | // CHECK-EMPTY: | |
| 55 | 57 | // CHECK-NEXT: Disassembly of section .caller: |
| 58 | // CHECK-EMPTY: | |
| 56 | 59 | // CHECK-NEXT: callers: |
| 57 | 60 | // 1004 - 0x800 (2048) + 4 = 0x808 = callee_low_far |
| 58 | 61 | // CHECK-NEXT: 1004: 00 e4 b #-2048 |
| ... | ... | @@ -64,10 +67,14 @@ callee_high_far = 0x180d |
| 64 | 67 | // CHECK-NEXT: 100a: ff e3 b #2046 |
| 65 | 68 | // CHECK-NEXT: 100c: 70 47 bx lr |
| 66 | 69 | // CHECK-NEXT: 100e: 00 bf nop |
| 70 | // CHECK-EMPTY: | |
| 67 | 71 | // CHECK-NEXT: Disassembly of section .R_ARM_PC11_2: |
| 72 | // CHECK-EMPTY: | |
| 68 | 73 | // CHECK-NEXT: callee_high: |
| 69 | 74 | // CHECK-NEXT: 1010: 70 47 bx lr |
| 75 | // CHECK-EMPTY: | |
| 70 | 76 | // CHECK-NEXT: Disassembly of section .text: |
| 77 | // CHECK-EMPTY: | |
| 71 | 78 | // CHECK-NEXT: _start: |
| 72 | 79 | // CHECK-NEXT: 1014: ff f7 f6 ff bl #-20 |
| 73 | 80 | // CHECK-NEXT: 1018: 70 47 bx lr |
deps/lld/test/ELF/arm-thumb-no-undefined-thunk.s+1| ... | ... | @@ -17,6 +17,7 @@ _start: |
| 17 | 17 | b.w target |
| 18 | 18 | |
| 19 | 19 | // CHECK: Disassembly of section .text: |
| 20 | // CHECK-EMPTY: | |
| 20 | 21 | // CHECK-NEXT: _start: |
| 21 | 22 | // 69636 = 0x11004 = next instruction |
| 22 | 23 | // CHECK: 11000: {{.*}} bl #0 |
deps/lld/test/ELF/arm-thumb-plt-range-thunk-os.s+6-4| ... | ... | @@ -35,6 +35,7 @@ preemptible: |
| 35 | 35 | bl far_nonpreemptible_alias |
| 36 | 36 | bx lr |
| 37 | 37 | // CHECK1: Disassembly of section .text: |
| 38 | // CHECK1-EMPTY: | |
| 38 | 39 | // CHECK1-NEXT: sym1: |
| 39 | 40 | // CHECK1-NEXT: 2000000: 00 f0 00 d8 bl #8388608 |
| 40 | 41 | // CHECK1-NEXT: 2000004: 00 f0 04 d8 bl #8388616 |
| ... | ... | @@ -84,10 +85,11 @@ far_nonpreemptible_alias: |
| 84 | 85 | // CHECK3: 4000000: 00 f0 16 e8 blx #44 |
| 85 | 86 | |
| 86 | 87 | // CHECK4: Disassembly of section .plt: |
| 88 | // CHECK4-EMPTY: | |
| 87 | 89 | // CHECK4-NEXT: $a: |
| 88 | 90 | // CHECK4-NEXT: 4000010:	04 e0 2d e5 	str	lr, [sp, #-4]! |
| 89 | 91 | // CHECK4-NEXT: 4000014:	00 e6 8f e2 	add	lr, pc, #0, #12 |
| 90 | // CHECK4-NEXT: 4000018:	00 ea 8e e2 	add	lr, lr, #0, #20 | |
| 92 | // CHECK4-NEXT: 4000018:	01 ea 8e e2 	add	lr, lr, #4096 | |
| 91 | 93 | // CHECK4-NEXT: 400001c:	ec ff be e5 	ldr	pc, [lr, #4076]! |
| 92 | 94 | // CHECK4: $d: |
| 93 | 95 | // CHECK4-NEXT: 4000020:	d4 d4 d4 d4 	.word	0xd4d4d4d4 |
| ... | ... | @@ -96,19 +98,19 @@ far_nonpreemptible_alias: |
| 96 | 98 | // CHECK4-NEXT: 400002c:	d4 d4 d4 d4 	.word	0xd4d4d4d4 |
| 97 | 99 | // CHECK4: $a: |
| 98 | 100 | // CHECK4-NEXT: 4000030:	00 c6 8f e2 	add	r12, pc, #0, #12 |
| 99 | // CHECK4-NEXT: 4000034:	00 ca 8c e2 	add	r12, r12, #0, #20 | |
| 101 | // CHECK4-NEXT: 4000034:	01 ca 8c e2 	add	r12, r12, #4096 | |
| 100 | 102 | // CHECK4-NEXT: 4000038:	d4 ff bc e5 	ldr	pc, [r12, #4052]! |
| 101 | 103 | // CHECK4: $d: |
| 102 | 104 | // CHECK4-NEXT: 400003c:	d4 d4 d4 d4 	.word	0xd4d4d4d4 |
| 103 | 105 | // CHECK4: $a: |
| 104 | 106 | // CHECK4-NEXT: 4000040:	00 c6 8f e2 	add	r12, pc, #0, #12 |
| 105 | // CHECK4-NEXT: 4000044:	00 ca 8c e2 	add	r12, r12, #0, #20 | |
| 107 | // CHECK4-NEXT: 4000044:	01 ca 8c e2 	add	r12, r12, #4096 | |
| 106 | 108 | // CHECK4-NEXT: 4000048:	c8 ff bc e5 	ldr	pc, [r12, #4040]! |
| 107 | 109 | // CHECK4: $d: |
| 108 | 110 | // CHECK4-NEXT: 400004c:	d4 d4 d4 d4 	.word	0xd4d4d4d4 |
| 109 | 111 | // CHECK4: $a: |
| 110 | 112 | // CHECK4-NEXT: 4000050:	00 c6 8f e2 	add	r12, pc, #0, #12 |
| 111 | // CHECK4-NEXT: 4000054:	00 ca 8c e2 	add	r12, r12, #0, #20 | |
| 113 | // CHECK4-NEXT: 4000054:	01 ca 8c e2 	add	r12, r12, #4096 | |
| 112 | 114 | // CHECK4-NEXT: 4000058:	bc ff bc e5 	ldr	pc, [r12, #4028]! |
| 113 | 115 | // CHECK4: $d: |
| 114 | 116 | // CHECK4-NEXT: 400005c:	d4 d4 d4 d4 	.word	0xd4d4d4d4 |
deps/lld/test/ELF/arm-thumb-plt-reloc.s+16-13| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | // RUN: ld.lld --hash-style=sysv -shared %t1 %t2 -o %t3 |
| 7 | 7 | // RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSOTHUMB %s |
| 8 | 8 | // RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSOARM %s |
| 9 | // RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s | |
| 9 | // RUN: llvm-readobj -S -r %t3 | FileCheck -check-prefix=DSOREL %s | |
| 10 | 10 | // |
| 11 | 11 | // Test PLT entry generation |
| 12 | 12 | .syntax unified |
| ... | ... | @@ -24,6 +24,7 @@ _start: |
| 24 | 24 | |
| 25 | 25 | // Executable, expect no PLT |
| 26 | 26 | // CHECK: Disassembly of section .text: |
| 27 | // CHECK-EMPTY: | |
| 27 | 28 | // CHECK-NEXT: func1: |
| 28 | 29 | // CHECK-NEXT: 11000: 70 47 bx lr |
| 29 | 30 | // CHECK: func2: |
| ... | ... | @@ -43,6 +44,7 @@ _start: |
| 43 | 44 | // .text is Thumb and .plt is ARM, llvm-objdump can currently only disassemble |
| 44 | 45 | // as ARM or Thumb. Work around by disassembling twice. |
| 45 | 46 | // DSOTHUMB: Disassembly of section .text: |
| 47 | // DSOTHUMB-EMPTY: | |
| 46 | 48 | // DSOTHUMB-NEXT: func1: |
| 47 | 49 | // DSOTHUMB-NEXT: 1000: 70 47 bx lr |
| 48 | 50 | // DSOTHUMB: func2: |
| ... | ... | @@ -58,11 +60,12 @@ _start: |
| 58 | 60 | // 0x1010 + 0x4C + 4 = 0x1060 = PLT func3 |
| 59 | 61 | // DSOTHUMB-NEXT: 1010: 00 f0 26 e8 blx #76 |
| 60 | 62 | // DSOARM: Disassembly of section .plt: |
| 63 | // DSOARM-EMPTY: | |
| 61 | 64 | // DSOARM-NEXT: $a: |
| 62 | 65 | // DSOARM-NEXT: 1020: 04 e0 2d e5 str lr, [sp, #-4]! |
| 63 | // (0x1024 + 8) + (0 RoR 12) + (0 RoR 20) + (0xfdc) = 0x2008 = .got.plt[3] | |
| 66 | // (0x1024 + 8) + (0 RoR 12) + 4096 + (0xfdc) = 0x3008 = .got.plt[3] | |
| 64 | 67 | // DSOARM-NEXT: 1024: 00 e6 8f e2 add lr, pc, #0, #12 |
| 65 | // DSOARM-NEXT: 1028: 00 ea 8e e2 add lr, lr, #0, #20 | |
| 68 | // DSOARM-NEXT: 1028: 01 ea 8e e2 add lr, lr, #4096 | |
| 66 | 69 | // DSOARM-NEXT: 102c: dc ff be e5 ldr pc, [lr, #4060]! |
| 67 | 70 | // DSOARM: $d: |
| 68 | 71 | |
| ... | ... | @@ -71,23 +74,23 @@ _start: |
| 71 | 74 | // DSOARM-NEXT: 1038: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| 72 | 75 | // DSOARM-NEXT: 103c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| 73 | 76 | // DSOARM: $a: |
| 74 | // (0x1040 + 8) + (0 RoR 12) + (0 RoR 20) + (0xfc4) = 0x200c | |
| 77 | // (0x1040 + 8) + (0 RoR 12) + 4096 + (0xfc4) = 0x300c | |
| 75 | 78 | // DSOARM-NEXT: 1040: 00 c6 8f e2 add r12, pc, #0, #12 |
| 76 | // DSOARM-NEXT: 1044: 00 ca 8c e2 add r12, r12, #0, #20 | |
| 79 | // DSOARM-NEXT: 1044: 01 ca 8c e2 add r12, r12, #4096 | |
| 77 | 80 | // DSOARM-NEXT: 1048: c4 ff bc e5 ldr pc, [r12, #4036]! |
| 78 | 81 | // DSOARM: $d: |
| 79 | 82 | // DSOARM-NEXT: 104c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| 80 | 83 | // DSOARM: $a: |
| 81 | // (0x1050 + 8) + (0 RoR 12) + (0 RoR 20) + (0xfb8) = 0x2010 | |
| 84 | // (0x1050 + 8) + (0 RoR 12) + 4096 + (0xfb8) = 0x3010 | |
| 82 | 85 | // DSOARM-NEXT: 1050: 00 c6 8f e2 add r12, pc, #0, #12 |
| 83 | // DSOARM-NEXT: 1054: 00 ca 8c e2 add r12, r12, #0, #20 | |
| 86 | // DSOARM-NEXT: 1054: 01 ca 8c e2 add r12, r12, #4096 | |
| 84 | 87 | // DSOARM-NEXT: 1058: b8 ff bc e5 ldr pc, [r12, #4024]! |
| 85 | 88 | // DSOARM: $d: |
| 86 | 89 | // DSOARM-NEXT: 105c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| 87 | 90 | // DSOARM: $a: |
| 88 | // (0x1060 + 8) + (0 RoR 12) + (0 RoR 20) + (0xfac) = 0x2014 | |
| 91 | // (0x1060 + 8) + (0 RoR 12) + 4096 + (0xfac) = 0x3014 | |
| 89 | 92 | // DSOARM-NEXT: 1060: 00 c6 8f e2 add r12, pc, #0, #12 |
| 90 | // DSOARM-NEXT: 1064: 00 ca 8c e2 add r12, r12, #0, #20 | |
| 93 | // DSOARM-NEXT: 1064: 01 ca 8c e2 add r12, r12, #4096 | |
| 91 | 94 | // DSOARM-NEXT: 1068: ac ff bc e5 ldr pc, [r12, #4012]! |
| 92 | 95 | // DSOARM: $d: |
| 93 | 96 | // DSOARM-NEXT: 106c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| ... | ... | @@ -98,7 +101,7 @@ _start: |
| 98 | 101 | // DSOREL-NEXT: SHF_ALLOC |
| 99 | 102 | // DSOREL-NEXT: SHF_WRITE |
| 100 | 103 | // DSOREL-NEXT: ] |
| 101 | // DSOREL-NEXT: Address: 0x2000 | |
| 104 | // DSOREL-NEXT: Address: 0x3000 | |
| 102 | 105 | // DSOREL-NEXT: Offset: |
| 103 | 106 | // DSOREL-NEXT: Size: 24 |
| 104 | 107 | // DSOREL-NEXT: Link: |
| ... | ... | @@ -107,6 +110,6 @@ _start: |
| 107 | 110 | // DSOREL-NEXT: EntrySize: |
| 108 | 111 | // DSOREL: Relocations [ |
| 109 | 112 | // DSOREL-NEXT: Section (4) .rel.plt { |
| 110 | // DSOREL-NEXT: 0x200C R_ARM_JUMP_SLOT func1 0x0 | |
| 111 | // DSOREL-NEXT: 0x2010 R_ARM_JUMP_SLOT func2 0x0 | |
| 112 | // DSOREL-NEXT: 0x2014 R_ARM_JUMP_SLOT func3 0x0 | |
| 113 | // DSOREL-NEXT: 0x300C R_ARM_JUMP_SLOT func1 0x0 | |
| 114 | // DSOREL-NEXT: 0x3010 R_ARM_JUMP_SLOT func2 0x0 | |
| 115 | // DSOREL-NEXT: 0x3014 R_ARM_JUMP_SLOT func3 0x0 |
deps/lld/test/ELF/arm-thumb-range-thunk-os.s+1| ... | ... | @@ -43,6 +43,7 @@ _start: |
| 43 | 43 | // the first of the pre-created ThunkSections. |
| 44 | 44 | bl tfunc16 |
| 45 | 45 | // CHECK1: Disassembly of section .text: |
| 46 | // CHECK1-EMPTY: | |
| 46 | 47 | // CHECK1-NEXT: _start: |
| 47 | 48 | // CHECK1-NEXT: 100000: ff f0 fe ff bl #1048572 |
| 48 | 49 | // CHECK1-NEXT: 100004: ff f3 fc d7 bl #16777208 |
deps/lld/test/ELF/arm-thumb-thunk-empty-pass.s+1| ... | ... | @@ -17,6 +17,7 @@ foo: |
| 17 | 17 | bl _start |
| 18 | 18 | |
| 19 | 19 | // CHECK1: Disassembly of section .text: |
| 20 | // CHECK1-EMPTY: | |
| 20 | 21 | // CHECK1-NEXT: _start: |
| 21 | 22 | // CHECK1-NEXT: 11000: ff f7 fe ff bl #-4 |
| 22 | 23 | // CHECK1: __Thumbv7ABSLongThunk__start: |
deps/lld/test/ELF/arm-thumb-thunk-v6m.s+4| ... | ... | @@ -31,6 +31,7 @@ far: |
| 31 | 31 | bx lr |
| 32 | 32 | |
| 33 | 33 | // CHECK: Disassembly of section .text_low: |
| 34 | // CHECK-EMPTY: | |
| 34 | 35 | // CHECK-NEXT: _start: |
| 35 | 36 | // CHECK-NEXT: 94: 00 f0 00 f8 bl #0 |
| 36 | 37 | // CHECK: __Thumbv6MABSLongThunk_far: |
| ... | ... | @@ -40,10 +41,12 @@ far: |
| 40 | 41 | // CHECK-NEXT: 9e: 01 bd pop {r0, pc} |
| 41 | 42 | // CHECK: a0: 01 00 00 02 .word 0x02000001 |
| 42 | 43 | // CHECK: Disassembly of section .text_high: |
| 44 | // CHECK-EMPTY: | |
| 43 | 45 | // CHECK-NEXT: far: |
| 44 | 46 | // CHECK-NEXT: 2000000: 70 47 bx lr |
| 45 | 47 | |
| 46 | 48 | // CHECK-PI: Disassembly of section .text_low: |
| 49 | // CHECK-PI-EMPTY: | |
| 47 | 50 | // CHECK-PI-NEXT: _start: |
| 48 | 51 | // CHECK-PI-NEXT: 130: 00 f0 00 f8 bl #0 |
| 49 | 52 | // CHECK-PI: __Thumbv6MPILongThunk_far: |
| ... | ... | @@ -57,5 +60,6 @@ far: |
| 57 | 60 | // CHECK-PI: 140: c1 fe ff 01 .word 0x01fffec1 |
| 58 | 61 | |
| 59 | 62 | // CHECK-PI: Disassembly of section .text_high: |
| 63 | // CHECK-PI-EMPTY: | |
| 60 | 64 | // CHECK-PI-NEXT: far: |
| 61 | 65 | // CHECK-PI-NEXT: 2000000: 70 47 bx lr |
deps/lld/test/ELF/arm-thumb-undefined-weak-narrow.test+14-15| ... | ... | @@ -4,6 +4,7 @@ |
| 4 | 4 | # RUN: llvm-objdump -triple=thumbv7a-linux-gnueabi -d %t | FileCheck %s |
| 5 | 5 | |
| 6 | 6 | # CHECK: Disassembly of section .text: |
| 7 | # CHECK-EMPTY: | |
| 7 | 8 | # CHECK-NEXT:_start: |
| 8 | 9 | # CHECK-NEXT: 11000: ff e7 b #-2 |
| 9 | 10 | |
| ... | ... | @@ -33,18 +34,16 @@ Sections: |
| 33 | 34 | Type: R_ARM_THM_JUMP11 |
| 34 | 35 | |
| 35 | 36 | Symbols: |
| 36 | Global: | |
| 37 | - Type: STT_FUNC | |
| 38 | Name: _start | |
| 39 | Value: 1 | |
| 40 | Section: .text | |
| 41 | Local: | |
| 42 | - Type: STT_NOTYPE | |
| 43 | Name: "$t" | |
| 44 | Section: .text | |
| 45 | Value: 0 | |
| 46 | Weak: | |
| 47 | - Type: STT_NOTYPE | |
| 48 | Name: undefined_weak | |
| 49 | Value: 0 | |
| 50 | ||
| 37 | - Type: STT_NOTYPE | |
| 38 | Name: "$t" | |
| 39 | Section: .text | |
| 40 | Value: 0 | |
| 41 | - Type: STT_FUNC | |
| 42 | Name: _start | |
| 43 | Value: 1 | |
| 44 | Section: .text | |
| 45 | Binding: STB_GLOBAL | |
| 46 | - Type: STT_NOTYPE | |
| 47 | Name: undefined_weak | |
| 48 | Value: 0 | |
| 49 | Binding: STB_WEAK |
deps/lld/test/ELF/arm-thumb-undefined-weak.s+1| ... | ... | @@ -28,6 +28,7 @@ _start: |
| 28 | 28 | movw r0, :lower16:target - . |
| 29 | 29 | |
| 30 | 30 | // CHECK: Disassembly of section .text: |
| 31 | // CHECK-EMPTY: | |
| 31 | 32 | // 69636 = 0x11004 |
| 32 | 33 | // CHECK: 11000: {{.*}} beq.w #0 <_start+0x4> |
| 33 | 34 | // CHECK-NEXT: 11004: {{.*}} b.w #0 <_start+0x8> |
deps/lld/test/ELF/arm-thunk-largesection.s+1| ... | ... | @@ -16,6 +16,7 @@ _start: |
| 16 | 16 | bx lr |
| 17 | 17 | .space 0x1000 |
| 18 | 18 | // CHECK1: Disassembly of section .text: |
| 19 | // CHECK1-EMPTY: | |
| 19 | 20 | // CHECK1-NEXT:_start: |
| 20 | 21 | // CHECK1-NEXT: 11000: 70 47 bx lr |
| 21 | 22 | // CHECK1-EMPTY: |
deps/lld/test/ELF/arm-thunk-linkerscript-dotexpr.s+1| ... | ... | @@ -28,6 +28,7 @@ low_target2: |
| 28 | 28 | bl high_target |
| 29 | 29 | bl high_target2 |
| 30 | 30 | // CHECK1: Disassembly of section .text_low: |
| 31 | // CHECK1-EMPTY: | |
| 31 | 32 | // CHECK1-NEXT: _start: |
| 32 | 33 | // CHECK1-NEXT: 94: 70 47 bx lr |
| 33 | 34 | // CHECK1: low_target: |
deps/lld/test/ELF/arm-thunk-linkerscript-large.s+3| ... | ... | @@ -53,6 +53,7 @@ _start: |
| 53 | 53 | // Expect a range extension thunk in .text OutputSection |
| 54 | 54 | bl tfunch31 |
| 55 | 55 | // CHECK1: Disassembly of section .text: |
| 56 | // CHECK1-EMPTY: | |
| 56 | 57 | // CHECK1-NEXT: _start: |
| 57 | 58 | // CHECK1-NEXT: 100000: ff f0 fe ff bl #1048572 |
| 58 | 59 | // CHECK1-NEXT: 100004: 00 f0 00 f8 bl #0 |
| ... | ... | @@ -66,6 +67,7 @@ _start: |
| 66 | 67 | // We can reuse existing thunk in .text |
| 67 | 68 | bl tfunch31 |
| 68 | 69 | // CHECK2: Disassembly of section .textl: |
| 70 | // CHECK2-EMPTY: | |
| 69 | 71 | // CHECK2-NEXT: tfuncl00: |
| 70 | 72 | // CHECK2-NEXT: 200000:	70 47 	bx	lr |
| 71 | 73 | // CHECK2-NEXT: 200002:	ff f0 ff df 	bl	#9437182 |
| ... | ... | @@ -122,6 +124,7 @@ _start: |
| 122 | 124 | // Shouldn't need a thunk |
| 123 | 125 | bl tfuncl31 |
| 124 | 126 | // CHECK5: Disassembly of section .texth: |
| 127 | // CHECK5-EMPTY: | |
| 125 | 128 | // CHECK5-NEXT: tfunch00: |
| 126 | 129 | // CHECK5-NEXT: 2200000: 70 47 bx lr |
| 127 | 130 | // CHECK5-NEXT: 2200002: 00 f7 05 f8 bl #-1048566 |
deps/lld/test/ELF/arm-thunk-linkerscript-orphan.s+3| ... | ... | @@ -18,6 +18,7 @@ low_target: |
| 18 | 18 | bl high_target |
| 19 | 19 | bl orphan_target |
| 20 | 20 | // CHECK: Disassembly of section .text_low: |
| 21 | // CHECK-EMPTY: | |
| 21 | 22 | // CHECK-NEXT: _start: |
| 22 | 23 | // CHECK-NEXT: 100000: 70 47 bx lr |
| 23 | 24 | // CHECK: low_target: |
| ... | ... | @@ -39,6 +40,7 @@ high_target: |
| 39 | 40 | bl low_target |
| 40 | 41 | bl orphan_target |
| 41 | 42 | // CHECK: Disassembly of section .text_high: |
| 43 | // CHECK-EMPTY: | |
| 42 | 44 | // CHECK-NEXT: high_target: |
| 43 | 45 | // CHECK-NEXT: 2000000: 00 f0 02 f8 bl #4 |
| 44 | 46 | // CHECK-NEXT: 2000004: 00 f0 06 f8 bl #12 |
| ... | ... | @@ -55,6 +57,7 @@ orphan_target: |
| 55 | 57 | bl low_target |
| 56 | 58 | bl high_target |
| 57 | 59 | // CHECK: Disassembly of section orphan: |
| 60 | // CHECK-EMPTY: | |
| 58 | 61 | // CHECK-NEXT: orphan_target: |
| 59 | 62 | // CHECK-NEXT: 2000014: ff f7 f8 ff bl #-16 |
| 60 | 63 | // CHECK-NEXT: 2000018: ff f7 f2 ff bl #-28 |
deps/lld/test/ELF/arm-thunk-linkerscript.s+2| ... | ... | @@ -28,6 +28,7 @@ low_target2: |
| 28 | 28 | bl high_target2 |
| 29 | 29 | |
| 30 | 30 | // CHECK: Disassembly of section .text_low: |
| 31 | // CHECK-EMPTY: | |
| 31 | 32 | // CHECK-NEXT: _start: |
| 32 | 33 | // CHECK-NEXT: 94: 70 47 bx lr |
| 33 | 34 | // CHECK: low_target: |
| ... | ... | @@ -62,6 +63,7 @@ high_target2: |
| 62 | 63 | bl low_target2 |
| 63 | 64 | |
| 64 | 65 | // CHECK: Disassembly of section .text_high: |
| 66 | // CHECK-EMPTY: | |
| 65 | 67 | // CHECK-NEXT: high_target: |
| 66 | 68 | // CHECK-NEXT: 2000000: 00 f0 02 f8 bl #4 |
| 67 | 69 | // CHECK-NEXT: 2000004: 00 f0 05 f8 bl #10 |
deps/lld/test/ELF/arm-thunk-multipass-plt.s created+95| ... | ... | @@ -0,0 +1,95 @@ |
| 1 | // REQUIRES: arm | |
| 2 | // RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv5-none-linux-gnueabi %s -o %t | |
| 3 | // RUN: ld.lld %t -o %t2 --shared 2>&1 | |
| 4 | // RUN: llvm-objdump --start-address=7340044 --stop-address=7340048 --triple=armv5-none-linux-gnueabi -d %t2 | FileCheck %s | |
| 5 | // RUN: llvm-objdump --start-address=8388620 --stop-address=8388624 --triple=thumbv5-none-linux-gnueabi -d %t2 | FileCheck %s -check-prefix=CHECK-CALL | |
| 6 | // RUN: llvm-objdump --start-address=13631520 --stop-address=13631584 --triple=armv5-none-linux-gnueabi -d %t2 | FileCheck %s -check-prefix=CHECK-PLT | |
| 7 | // When we create a thunk to a PLT entry the relocation is redirected to the | |
| 8 | // Thunk, changing its expression to a non-PLT equivalent. If the thunk | |
| 9 | // becomes unusable we need to restore the relocation expression to the PLT | |
| 10 | // form so that when we create a new thunk it targets the PLT. | |
| 11 | ||
| 12 | // Test case that checks the case: | |
| 13 | // - Thunk is created on pass 1 to a PLT entry for preemptible | |
| 14 | // - Some other Thunk added in the same pass moves the thunk to | |
| 15 | // preemptible out of range of its caller. | |
| 16 | // - New Thunk is created on pass 2 to PLT entry for preemptible | |
| 17 | ||
| 18 | .globl preemptible | |
| 19 | .globl preemptible2 | |
| 20 | .section .text.01, "ax", %progbits | |
| 21 | .balign 0x100000 | |
| 22 | .thumb | |
| 23 | .globl needsplt | |
| 24 | .type needsplt, %function | |
| 25 | needsplt: | |
| 26 | bl preemptible | |
| 27 | .section .text.02, "ax", %progbits | |
| 28 | .space (1024 * 1024) | |
| 29 | ||
| 30 | .section .text.03, "ax", %progbits | |
| 31 | .space (1024 * 1024) | |
| 32 | ||
| 33 | .section .text.04, "ax", %progbits | |
| 34 | .space (1024 * 1024) | |
| 35 | ||
| 36 | .section .text.05, "ax", %progbits | |
| 37 | .space (1024 * 1024) | |
| 38 | ||
| 39 | .section .text.06, "ax", %progbits | |
| 40 | .space (1024 * 1024) | |
| 41 | ||
| 42 | .section .text.07, "ax", %progbits | |
| 43 | .space (1024 * 1024) | |
| 44 | // 0x70000c + 8 + 0x60002c = 0xd00040 = preemptible@plt | |
| 45 | // CHECK: 0070000c __ARMV5PILongThunk_preemptible: | |
| 46 | // CHECK-NEXT: 70000c: 0b 00 18 ea b #6291500 | |
| 47 | ||
| 48 | .section .text.08, "ax", %progbits | |
| 49 | .space (1024 * 1024) - 4 | |
| 50 | ||
| 51 | .section .text.10, "ax", %progbits | |
| 52 | .balign 2 | |
| 53 | bl preemptible | |
| 54 | bl preemptible2 | |
| 55 | // 0x80000c + 4 - 100004 = 0x70000c = __ARMv5PILongThunk_preemptible | |
| 56 | // CHECK-CALL: 80000c: ff f6 fe ef blx #-1048580 | |
| 57 | .balign 2 | |
| 58 | .globl preemptible | |
| 59 | .type preemptible, %function | |
| 60 | preemptible: | |
| 61 | bx lr | |
| 62 | .globl preemptible2 | |
| 63 | .type preemptible2, %function | |
| 64 | preemptible2: | |
| 65 | bx lr | |
| 66 | ||
| 67 | ||
| 68 | .section .text.11, "ax", %progbits | |
| 69 | .space (5 * 1024 * 1024) | |
| 70 | ||
| 71 | ||
| 72 | // CHECK-PLT: Disassembly of section .plt: | |
| 73 | // CHECK-PLT-EMPTY: | |
| 74 | // CHECK-PLT-NEXT: 00d00020 $a: | |
| 75 | // CHECK-PLT-NEXT: d00020: 04 e0 2d e5 str lr, [sp, #-4]! | |
| 76 | // CHECK-PLT-NEXT: d00024: 00 e6 8f e2 add lr, pc, #0, #12 | |
| 77 | // CHECK-PLT-NEXT: d00028: 01 ea 8e e2 add lr, lr, #4096 | |
| 78 | // CHECK-PLT-NEXT: d0002c: dc ff be e5 ldr pc, [lr, #4060]! | |
| 79 | // CHECK-PLT: 00d00030 $d: | |
| 80 | // CHECK-PLT-NEXT: d00030: d4 d4 d4 d4 .word 0xd4d4d4d4 | |
| 81 | // CHECK-PLT-NEXT: d00034: d4 d4 d4 d4 .word 0xd4d4d4d4 | |
| 82 | // CHECK-PLT-NEXT: d00038: d4 d4 d4 d4 .word 0xd4d4d4d4 | |
| 83 | // CHECK-PLT-NEXT: d0003c: d4 d4 d4 d4 .word 0xd4d4d4d4 | |
| 84 | // CHECK-PLT: 00d00040 $a: | |
| 85 | // CHECK-PLT-NEXT: d00040: 00 c6 8f e2 add r12, pc, #0, #12 | |
| 86 | // CHECK-PLT-NEXT: d00044: 01 ca 8c e2 add r12, r12, #4096 | |
| 87 | // CHECK-PLT-NEXT: d00048: c4 ff bc e5 ldr pc, [r12, #4036]! | |
| 88 | // CHECK-PLT: 00d0004c $d: | |
| 89 | // CHECK-PLT-NEXT: d0004c: d4 d4 d4 d4 .word 0xd4d4d4d4 | |
| 90 | // CHECK-PLT: 00d00050 $a: | |
| 91 | // CHECK-PLT-NEXT: d00050: 00 c6 8f e2 add r12, pc, #0, #12 | |
| 92 | // CHECK-PLT-NEXT: d00054: 01 ca 8c e2 add r12, r12, #4096 | |
| 93 | // CHECK-PLT-NEXT: d00058: b8 ff bc e5 ldr pc, [r12, #4024]! | |
| 94 | // CHECK-PLT: 00d0005c $d: | |
| 95 | // CHECK-PLT-NEXT: d0005c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
deps/lld/test/ELF/arm-thunk-re-add.s+4-3| ... | ... | @@ -99,10 +99,11 @@ callers: |
| 99 | 99 | // CHECK2-NEXT: 110001c: ff f6 f8 bf b.w #-1048592 <__ThumbV7PILongThunk_imported2> |
| 100 | 100 | |
| 101 | 101 | // CHECK3: Disassembly of section .plt: |
| 102 | // CHECK3-EMPTY: | |
| 102 | 103 | // CHECK3-NEXT: $a: |
| 103 | 104 | // CHECK3-NEXT: 1100020: 04 e0 2d e5 str lr, [sp, #-4]! |
| 104 | 105 | // CHECK3-NEXT: 1100024: 00 e6 8f e2 add lr, pc, #0, #12 |
| 105 | // CHECK3-NEXT: 1100028: 00 ea 8e e2 add lr, lr, #0, #20 | |
| 106 | // CHECK3-NEXT: 1100028: 01 ea 8e e2 add lr, lr, #4096 | |
| 106 | 107 | // CHECK3-NEXT: 110002c: dc ff be e5 ldr pc, [lr, #4060]! |
| 107 | 108 | // CHECK3: $d: |
| 108 | 109 | // CHECK3-NEXT: 1100030: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| ... | ... | @@ -111,13 +112,13 @@ callers: |
| 111 | 112 | // CHECK3-NEXT: 110003c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| 112 | 113 | // CHECK3: $a: |
| 113 | 114 | // CHECK3-NEXT: 1100040: 00 c6 8f e2 add r12, pc, #0, #12 |
| 114 | // CHECK3-NEXT: 1100044: 00 ca 8c e2 add r12, r12, #0, #20 | |
| 115 | // CHECK3-NEXT: 1100044: 01 ca 8c e2 add r12, r12, #4096 | |
| 115 | 116 | // CHECK3-NEXT: 1100048: c4 ff bc e5 ldr pc, [r12, #4036]! |
| 116 | 117 | // CHECK3: $d: |
| 117 | 118 | // CHECK3-NEXT: 110004c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
| 118 | 119 | // CHECK3: $a: |
| 119 | 120 | // CHECK3-NEXT: 1100050: 00 c6 8f e2 add r12, pc, #0, #12 |
| 120 | // CHECK3-NEXT: 1100054: 00 ca 8c e2 add r12, r12, #0, #20 | |
| 121 | // CHECK3-NEXT: 1100054: 01 ca 8c e2 add r12, r12, #4096 | |
| 121 | 122 | // CHECK3-NEXT: 1100058: b8 ff bc e5 ldr pc, [r12, #4024]! |
| 122 | 123 | // CHECK3: $d: |
| 123 | 124 | // CHECK3-NEXT: 110005c: d4 d4 d4 d4 .word 0xd4d4d4d4 |
deps/lld/test/ELF/arm-tls-gd32.s+2-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -s -dyn-relocations %t.so | FileCheck --check-prefix=SEC %s | |
| 4 | // RUN: llvm-readobj -S --dyn-relocations %t.so | FileCheck --check-prefix=SEC %s | |
| 5 | 5 | // RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t.so | FileCheck %s |
| 6 | 6 | |
| 7 | 7 | // Test the handling of the global-dynamic TLS model. Dynamic Loader finds |
| ... | ... | @@ -91,8 +91,7 @@ x: |
| 91 | 91 | // SEC-NEXT: 0x2058 R_ARM_TLS_DTPOFF32 y |
| 92 | 92 | |
| 93 | 93 | |
| 94 | // CHECK: Disassembly | |
| 95 | // CHECK-NEXT: func: | |
| 94 | // CHECK-LABEL: 00001000 func: | |
| 96 | 95 | // CHECK-NEXT: 1000: 00 f0 20 e3 nop |
| 97 | 96 | // CHECK-NEXT: 1004: 00 f0 20 e3 nop |
| 98 | 97 | // CHECK-NEXT: 1008: 00 f0 20 e3 nop |
deps/lld/test/ELF/arm-tls-ie32.s+2-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -s -dyn-relocations %t.so | FileCheck --check-prefix=SEC %s | |
| 4 | // RUN: llvm-readobj -S --dyn-relocations %t.so | FileCheck --check-prefix=SEC %s | |
| 5 | 5 | // RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t.so | FileCheck %s |
| 6 | 6 | |
| 7 | 7 | // Test the handling of the initial-exec TLS model. Relative location within |
| ... | ... | @@ -83,6 +83,7 @@ x: |
| 83 | 83 | // SEC: 0x2050 R_ARM_TLS_TPOFF32 y |
| 84 | 84 | |
| 85 | 85 | // CHECK: Disassembly of section .text: |
| 86 | // CHECK-EMPTY: | |
| 86 | 87 | // CHECK-NEXT: func: |
| 87 | 88 | // CHECK-NEXT: 1000: 00 f0 20 e3 nop |
| 88 | 89 | // CHECK-NEXT: 1004: 00 f0 20 e3 nop |
deps/lld/test/ELF/arm-tls-ldm32.s+3-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -s -dyn-relocations %t.so | FileCheck --check-prefix=SEC %s | |
| 4 | // RUN: llvm-readobj -S --dyn-relocations %t.so | FileCheck --check-prefix=SEC %s | |
| 5 | 5 | // RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t.so | FileCheck %s |
| 6 | 6 | |
| 7 | 7 | // Test the handling of the local-dynamic TLS model. Dynamic loader finds |
| ... | ... | @@ -56,6 +56,7 @@ x: |
| 56 | 56 | // SEC-NEXT: 0x204C R_ARM_TLS_DTPMOD32 - 0x0 |
| 57 | 57 | |
| 58 | 58 | // CHECK: Disassembly of section .text: |
| 59 | // CHECK-EMPTY: | |
| 59 | 60 | // CHECK-NEXT: _start: |
| 60 | 61 | // CHECK-NEXT: 1000: 00 f0 20 e3 nop |
| 61 | 62 | |
| ... | ... | @@ -65,6 +66,7 @@ x: |
| 65 | 66 | // CHECK-NEXT: 100c: 04 00 00 00 |
| 66 | 67 | |
| 67 | 68 | // CHECK-EXE: Disassembly of section .text: |
| 69 | // CHECK-EXE-EMPTY: | |
| 68 | 70 | // CHECK-NEXT-EXE: _start: |
| 69 | 71 | // CHECK-NEXT-EXE: 11000: 00 f0 20 e3 nop |
| 70 | 72 |
deps/lld/test/ELF/arm-tls-le32.s+8-7| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi |
| 3 | 3 | // RUN: ld.lld %t.o -o %t |
| 4 | // RUN: llvm-readobj -s -dyn-relocations %t | FileCheck --check-prefix=SEC %s | |
| 4 | // RUN: llvm-readobj -S --dyn-relocations %t | FileCheck --check-prefix=SEC %s | |
| 5 | 5 | // RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t | FileCheck %s |
| 6 | 6 | |
| 7 | 7 | // Test the handling of the local exec TLS model. TLS can be resolved |
| ... | ... | @@ -68,10 +68,11 @@ x: |
| 68 | 68 | // SEC-NEXT: } |
| 69 | 69 | |
| 70 | 70 | // CHECK: Disassembly of section .text: |
| 71 | // CHECK-EMPTY: | |
| 71 | 72 | // CHECK-NEXT: _start: |
| 72 | // offset of x from Thread pointer = (TcbSize + 0x0 = 0x20) | |
| 73 | // CHECK-NEXT: 11000: 20 00 00 00 | |
| 74 | // offset of z from Thread pointer = (TcbSize + 0x8 = 0x28) | |
| 75 | // CHECK-NEXT: 11004: 28 00 00 00 | |
| 76 | // offset of y from Thread pointer = (TcbSize + 0x4 = 0x24) | |
| 77 | // CHECK-NEXT: 11008: 24 00 00 00 | |
| 73 | // offset of x from Thread pointer = (TcbSize + 0x0 = 0x8) | |
| 74 | // CHECK-NEXT: 11000: 08 00 00 00 | |
| 75 | // offset of z from Thread pointer = (TcbSize + 0x8 = 0x10) | |
| 76 | // CHECK-NEXT: 11004: 10 00 00 00 | |
| 77 | // offset of y from Thread pointer = (TcbSize + 0x4 = 0xc) | |
| 78 | // CHECK-NEXT: 11008: 0c 00 00 00 |
deps/lld/test/ELF/arm-tls-norelax-gd-ie.s+4-4| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: ld.lld %t1 --shared -o %t1.so |
| 4 | 4 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv %t1.so %t.o -o %t |
| 6 | // RUN: llvm-readobj -s -dyn-relocations %t | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S --dyn-relocations %t | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | // This tls global-dynamic sequence is with respect to a preemptible symbol but |
| 9 | 9 | // is in an application so a relaxation to Initial Exec would normally be |
| ... | ... | @@ -25,6 +25,6 @@ func: |
| 25 | 25 | .Lt0: .word y(TLSGD) + (. - .L0 - 8) |
| 26 | 26 | |
| 27 | 27 | // CHECK: Dynamic Relocations { |
| 28 | // CHECK-NEXT: 0x13078 R_ARM_TLS_DTPMOD32 y | |
| 29 | // CHECK-NEXT: 0x1307C R_ARM_TLS_DTPOFF32 y | |
| 30 | // CHECK-NEXT: 0x1200C R_ARM_JUMP_SLOT __tls_get_addr | |
| 28 | // CHECK-NEXT: 0x12078 R_ARM_TLS_DTPMOD32 y | |
| 29 | // CHECK-NEXT: 0x1207C R_ARM_TLS_DTPOFF32 y | |
| 30 | // CHECK-NEXT: 0x1300C R_ARM_JUMP_SLOT __tls_get_addr |
deps/lld/test/ELF/arm-tls-norelax-gd-le.s+1-1| ... | ... | @@ -33,7 +33,7 @@ x: |
| 33 | 33 | |
| 34 | 34 | // CHECK: Contents of section .got: |
| 35 | 35 | // Module index is always 1 for executable |
| 36 | // CHECK-NEXT: 13060 01000000 00000000 | |
| 36 | // CHECK-NEXT: 12060 01000000 00000000 | |
| 37 | 37 | |
| 38 | 38 | |
| 39 | 39 | // Without any definition of __tls_get_addr we get an error |
deps/lld/test/ELF/arm-tls-norelax-ie-le.s+2-2| ... | ... | @@ -37,5 +37,5 @@ x2: |
| 37 | 37 | .type x2, %object |
| 38 | 38 | |
| 39 | 39 | // CHECK: Contents of section .got: |
| 40 | // x1 at offset 0x20 from TP, x2 at offset 0x24 from TP. Offsets include TCB size of 0x20 | |
| 41 | // CHECK-NEXT: 13064 20000000 24000000 | |
| 40 | // x1 at offset 8 from TP, x2 at offset 0xc from TP. Offsets include TCB size of 8 | |
| 41 | // CHECK-NEXT: 12064 08000000 0c000000 |
deps/lld/test/ELF/arm-tls-norelax-ld-le.s+1-1| ... | ... | @@ -32,4 +32,4 @@ x: |
| 32 | 32 | .word 10 |
| 33 | 33 | |
| 34 | 34 | // CHECK: Contents of section .got: |
| 35 | // CHECK-NEXT: 13064 01000000 00000000 | |
| 35 | // CHECK-NEXT: 12064 01000000 00000000 |
deps/lld/test/ELF/arm-undefined-weak.s+1| ... | ... | @@ -28,6 +28,7 @@ _start: |
| 28 | 28 | .word target - . |
| 29 | 29 | |
| 30 | 30 | // CHECK: Disassembly of section .text: |
| 31 | // CHECK-EMPTY: | |
| 31 | 32 | // 69636 = 0x11004 |
| 32 | 33 | // CHECK: 11000: {{.*}} b #-4 <_start+0x4> |
| 33 | 34 | // CHECK-NEXT: 11004: {{.*}} bl #-4 <_start+0x8> |
deps/lld/test/ELF/arm-v4bx.test+6-9| ... | ... | @@ -27,14 +27,11 @@ Sections: |
| 27 | 27 | Info: .text |
| 28 | 28 | Relocations: |
| 29 | 29 | - Offset: 0x0000000000000000 |
| 30 | Symbol: '' | |
| 31 | 30 | Type: R_ARM_V4BX |
| 32 | 31 | Symbols: |
| 33 | Global: | |
| 34 | - Name: _start | |
| 35 | Section: .text | |
| 36 | Local: | |
| 37 | - Name: .text | |
| 38 | Type: STT_SECTION | |
| 39 | Section: .text | |
| 40 | DynamicSymbols: | |
| 32 | - Name: .text | |
| 33 | Type: STT_SECTION | |
| 34 | Section: .text | |
| 35 | - Name: _start | |
| 36 | Section: .text | |
| 37 | Binding: STB_GLOBAL |
deps/lld/test/ELF/as-needed-weak.s+4-3| ... | ... | @@ -10,9 +10,10 @@ |
| 10 | 10 | |
| 11 | 11 | # CHECK-NOT: libfoo |
| 12 | 12 | |
| 13 | # CHECK: Symbol table of .hash for image: | |
| 14 | # CHECK-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name | |
| 15 | # CHECK-NEXT: 1 1: 0000000000000000 0 FUNC WEAK DEFAULT UND foo | |
| 13 | # CHECK: Symbol table '.dynsym' contains 2 entries: | |
| 14 | # CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name | |
| 15 | # CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND | |
| 16 | # CHECK-NEXT: 1: 0000000000000000 0 FUNC WEAK DEFAULT UND foo | |
| 16 | 17 | |
| 17 | 18 | .globl _start |
| 18 | 19 | .weak foo |
deps/lld/test/ELF/as-needed.s+6-6| ... | ... | @@ -10,27 +10,27 @@ |
| 10 | 10 | /// Check if --as-needed actually works. |
| 11 | 11 | |
| 12 | 12 | // RUN: ld.lld %t.o %t2.so %t3.so %t4.so -o %t2 |
| 13 | // RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s | |
| 13 | // RUN: llvm-readobj --dynamic-table %t2 | FileCheck %s | |
| 14 | 14 | |
| 15 | 15 | // RUN: ld.lld --as-needed %t.o %t2.so %t3.so %t4.so -o %t2 |
| 16 | // RUN: llvm-readobj -dynamic-table %t2 | FileCheck -check-prefix=CHECK2 %s | |
| 16 | // RUN: llvm-readobj --dynamic-table %t2 | FileCheck -check-prefix=CHECK2 %s | |
| 17 | 17 | |
| 18 | 18 | // Test with the .o last |
| 19 | 19 | // RUN: ld.lld --as-needed %t2.so %t3.so %t4.so %t.o -o %t2 |
| 20 | // RUN: llvm-readobj -dynamic-table %t2 | FileCheck -check-prefix=CHECK2 %s | |
| 20 | // RUN: llvm-readobj --dynamic-table %t2 | FileCheck -check-prefix=CHECK2 %s | |
| 21 | 21 | |
| 22 | 22 | // RUN: ld.lld --as-needed %t.o %t2.so --no-as-needed %t3.so %t4.so -o %t2 |
| 23 | // RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s | |
| 23 | // RUN: llvm-readobj --dynamic-table %t2 | FileCheck %s | |
| 24 | 24 | |
| 25 | 25 | /// GROUP command is the same as listing the files on the command line. |
| 26 | 26 | |
| 27 | 27 | // RUN: echo "GROUP(\"%t2.so\" \"%t3.so\" \"%t4.so\")" > %t.script |
| 28 | 28 | // RUN: ld.lld %t.o %t.script -o %t2 |
| 29 | // RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s | |
| 29 | // RUN: llvm-readobj --dynamic-table %t2 | FileCheck %s | |
| 30 | 30 | |
| 31 | 31 | // RUN: echo "GROUP(AS_NEEDED(\"%t2.so\" \"%t3.so\" \"%t4.so\"))" > %t.script |
| 32 | 32 | // RUN: ld.lld %t.o %t.script -o %t2 |
| 33 | // RUN: llvm-readobj -dynamic-table %t2 | FileCheck -check-prefix=CHECK2 %s | |
| 33 | // RUN: llvm-readobj --dynamic-table %t2 | FileCheck -check-prefix=CHECK2 %s | |
| 34 | 34 | |
| 35 | 35 | // CHECK: NEEDED Shared library: [shared1] |
| 36 | 36 | // CHECK: NEEDED Shared library: [shared2] |
deps/lld/test/ELF/assignment-archive.s+2-2| ... | ... | @@ -6,14 +6,14 @@ |
| 6 | 6 | |
| 7 | 7 | # RUN: echo "SECTIONS { foo = 1; }" > %t1.script |
| 8 | 8 | # RUN: ld.lld -o %t1.exe --script %t1.script %tar.a %t.o |
| 9 | # RUN: llvm-readobj -symbols %t1.exe | FileCheck %s | |
| 9 | # RUN: llvm-readobj --symbols %t1.exe | FileCheck %s | |
| 10 | 10 | # CHECK-NOT: bar |
| 11 | 11 | # CHECK: foo |
| 12 | 12 | # CHECK-NOT: bar |
| 13 | 13 | |
| 14 | 14 | # RUN: echo "SECTIONS { zed = foo; }" > %t2.script |
| 15 | 15 | # RUN: ld.lld -o %t2.exe --script %t2.script %tar.a %t.o |
| 16 | # RUN: llvm-readobj -symbols %t2.exe | FileCheck %s --check-prefix=SYMS | |
| 16 | # RUN: llvm-readobj --symbols %t2.exe | FileCheck %s --check-prefix=SYMS | |
| 17 | 17 | # SYMS: bar |
| 18 | 18 | # SYMS: foo |
| 19 | 19 |
deps/lld/test/ELF/avoid-empty-program-headers.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld %t -o %tout |
| 4 | // RUN: llvm-readobj -program-headers %tout | FileCheck %s | |
| 4 | // RUN: llvm-readobj -l %tout | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .global _start |
| 7 | 7 | _start: |
deps/lld/test/ELF/bad-reloc-target.test deleted-29| ... | ... | @@ -1,29 +0,0 @@ |
| 1 | # RUN: yaml2obj %s -o %t1.o | |
| 2 | # RUN: not ld.lld %t1.o -o %t1 2>&1 | FileCheck %s | |
| 3 | # CHECK: error: {{.*}}.o: unsupported relocation reference | |
| 4 | ||
| 5 | # RUN: yaml2obj %S/Inputs/bad-reloc-target.test -o %t2.o | |
| 6 | # RUN: not ld.lld %t2.o -o %t2 2>&1 | FileCheck %s --check-prefix=ERR2 | |
| 7 | # ERR2: error: {{.*}}.o: invalid relocated section index: 99 | |
| 8 | ||
| 9 | --- !ELF | |
| 10 | FileHeader: | |
| 11 | Class: ELFCLASS64 | |
| 12 | Data: ELFDATA2LSB | |
| 13 | Type: ET_REL | |
| 14 | Machine: EM_X86_64 | |
| 15 | Sections: | |
| 16 | - Name: .text | |
| 17 | Type: SHT_PROGBITS | |
| 18 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 19 | - Name: .rela.text | |
| 20 | Type: SHT_RELA | |
| 21 | Link: .symtab | |
| 22 | Info: 0 | |
| 23 | Relocations: | |
| 24 | - Offset: 0x0000000000000000 | |
| 25 | Symbol: foo | |
| 26 | Type: R_X86_64_64 | |
| 27 | Symbols: | |
| 28 | Global: | |
| 29 | - Name: foo | |
| \ No newline at end of file |
deps/lld/test/ELF/basic-aarch64.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: aarch64 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t |
| 3 | 3 | # RUN: ld.lld %t -o %t2 |
| 4 | # RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t2 \ | |
| 4 | # RUN: llvm-readobj --file-headers --sections -l --symbols %t2 \ | |
| 5 | 5 | # RUN: | FileCheck %s |
| 6 | 6 | |
| 7 | 7 | # exits with return code 42 on FreeBSD/AArch64 |
deps/lld/test/ELF/basic-freebsd.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t |
| 5 | 5 | # RUN: ld.lld %t -o %t2 |
| 6 | # RUN: llvm-readobj -file-headers %t2 | FileCheck %s | |
| 6 | # RUN: llvm-readobj --file-headers %t2 | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | .globl _start |
| 9 | 9 | _start: |
deps/lld/test/ELF/basic-i386.s created+179| ... | ... | @@ -0,0 +1,179 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -o %t | |
| 4 | # RUN: llvm-readobj --file-headers --sections -l %t | FileCheck %s | |
| 5 | ||
| 6 | # exits with return code 42 on linux | |
| 7 | .globl _start | |
| 8 | _start: | |
| 9 | mov $1, %eax | |
| 10 | mov $42, %ebx | |
| 11 | int $0x80 | |
| 12 | ||
| 13 | # CHECK: ElfHeader { | |
| 14 | # CHECK-NEXT: Ident { | |
| 15 | # CHECK-NEXT: Magic: (7F 45 4C 46) | |
| 16 | # CHECK-NEXT: Class: 32-bit (0x1) | |
| 17 | # CHECK-NEXT: DataEncoding: LittleEndian (0x1) | |
| 18 | # CHECK-NEXT: FileVersion: 1 | |
| 19 | # CHECK-NEXT: OS/ABI: SystemV (0x0) | |
| 20 | # CHECK-NEXT: ABIVersion: 0 | |
| 21 | # CHECK-NEXT: Unused: (00 00 00 00 00 00 00) | |
| 22 | # CHECK-NEXT: } | |
| 23 | # CHECK-NEXT: Type: Executable (0x2) | |
| 24 | # CHECK-NEXT: Machine: EM_386 (0x3) | |
| 25 | # CHECK-NEXT: Version: 1 | |
| 26 | # CHECK-NEXT: Entry: 0x401000 | |
| 27 | # CHECK-NEXT: ProgramHeaderOffset: 0x34 | |
| 28 | # CHECK-NEXT: SectionHeaderOffset: 0x205C | |
| 29 | # CHECK-NEXT: Flags [ (0x0) | |
| 30 | # CHECK-NEXT: ] | |
| 31 | # CHECK-NEXT: HeaderSize: 52 | |
| 32 | # CHECK-NEXT: ProgramHeaderEntrySize: 32 | |
| 33 | # CHECK-NEXT: ProgramHeaderCount: 4 | |
| 34 | # CHECK-NEXT: SectionHeaderEntrySize: 40 | |
| 35 | # CHECK-NEXT: SectionHeaderCount: 6 | |
| 36 | # CHECK-NEXT: StringTableSectionIndex: 4 | |
| 37 | # CHECK-NEXT: } | |
| 38 | # CHECK-NEXT: Sections [ | |
| 39 | # CHECK-NEXT: Section { | |
| 40 | # CHECK-NEXT: Index: 0 | |
| 41 | # CHECK-NEXT: Name: (0) | |
| 42 | # CHECK-NEXT: Type: SHT_NULL (0x0) | |
| 43 | # CHECK-NEXT: Flags [ (0x0) | |
| 44 | # CHECK-NEXT: ] | |
| 45 | # CHECK-NEXT: Address: 0x0 | |
| 46 | # CHECK-NEXT: Offset: 0x0 | |
| 47 | # CHECK-NEXT: Size: 0 | |
| 48 | # CHECK-NEXT: Link: 0 | |
| 49 | # CHECK-NEXT: Info: 0 | |
| 50 | # CHECK-NEXT: AddressAlignment: 0 | |
| 51 | # CHECK-NEXT: EntrySize: 0 | |
| 52 | # CHECK-NEXT: } | |
| 53 | # CHECK-NEXT: Section { | |
| 54 | # CHECK-NEXT: Index: 1 | |
| 55 | # CHECK-NEXT: Name: .text | |
| 56 | # CHECK-NEXT: Type: SHT_PROGBITS (0x1) | |
| 57 | # CHECK-NEXT: Flags [ (0x6) | |
| 58 | # CHECK-NEXT: SHF_ALLOC (0x2) | |
| 59 | # CHECK-NEXT: SHF_EXECINSTR (0x4) | |
| 60 | # CHECK-NEXT: ] | |
| 61 | # CHECK-NEXT: Address: 0x401000 | |
| 62 | # CHECK-NEXT: Offset: 0x1000 | |
| 63 | # CHECK-NEXT: Size: 12 | |
| 64 | # CHECK-NEXT: Link: 0 | |
| 65 | # CHECK-NEXT: Info: 0 | |
| 66 | # CHECK-NEXT: AddressAlignment: 4 | |
| 67 | # CHECK-NEXT: EntrySize: 0 | |
| 68 | # CHECK-NEXT: } | |
| 69 | # CHECK-NEXT: Section { | |
| 70 | # CHECK-NEXT: Index: 2 | |
| 71 | # CHECK-NEXT: Name: .comment | |
| 72 | # CHECK-NEXT: Type: SHT_PROGBITS (0x1) | |
| 73 | # CHECK-NEXT: Flags [ (0x30) | |
| 74 | # CHECK-NEXT: SHF_MERGE (0x10) | |
| 75 | # CHECK-NEXT: SHF_STRINGS (0x20) | |
| 76 | # CHECK-NEXT: ] | |
| 77 | # CHECK-NEXT: Address: 0x0 | |
| 78 | # CHECK-NEXT: Offset: 0x2000 | |
| 79 | # CHECK-NEXT: Size: 8 | |
| 80 | # CHECK-NEXT: Link: 0 | |
| 81 | # CHECK-NEXT: Info: 0 | |
| 82 | # CHECK-NEXT: AddressAlignment: 1 | |
| 83 | # CHECK-NEXT: EntrySize: 1 | |
| 84 | # CHECK-NEXT: } | |
| 85 | # CHECK-NEXT: Section { | |
| 86 | # CHECK-NEXT: Index: 3 | |
| 87 | # CHECK-NEXT: Name: .symtab | |
| 88 | # CHECK-NEXT: Type: SHT_SYMTAB | |
| 89 | # CHECK-NEXT: Flags [ | |
| 90 | # CHECK-NEXT: ] | |
| 91 | # CHECK-NEXT: Address: 0x0 | |
| 92 | # CHECK-NEXT: Offset: 0x2008 | |
| 93 | # CHECK-NEXT: Size: 32 | |
| 94 | # CHECK-NEXT: Link: 5 | |
| 95 | # CHECK-NEXT: Info: 1 | |
| 96 | # CHECK-NEXT: AddressAlignment: 4 | |
| 97 | # CHECK-NEXT: EntrySize: 16 | |
| 98 | # CHECK-NEXT: } | |
| 99 | # CHECK-NEXT: Section { | |
| 100 | # CHECK-NEXT: Index: 4 | |
| 101 | # CHECK-NEXT: Name: .shstrtab | |
| 102 | # CHECK-NEXT: Type: SHT_STRTAB (0x3) | |
| 103 | # CHECK-NEXT: Flags [ (0x0) | |
| 104 | # CHECK-NEXT: ] | |
| 105 | # CHECK-NEXT: Address: 0x0 | |
| 106 | # CHECK-NEXT: Offset: 0x2028 | |
| 107 | # CHECK-NEXT: Size: 42 | |
| 108 | # CHECK-NEXT: Link: 0 | |
| 109 | # CHECK-NEXT: Info: 0 | |
| 110 | # CHECK-NEXT: AddressAlignment: 1 | |
| 111 | # CHECK-NEXT: EntrySize: 0 | |
| 112 | # CHECK-NEXT: } | |
| 113 | # CHECK-NEXT: Section { | |
| 114 | # CHECK-NEXT: Index: 5 | |
| 115 | # CHECK-NEXT: Name: .strtab | |
| 116 | # CHECK-NEXT: Type: SHT_STRTAB (0x3) | |
| 117 | # CHECK-NEXT: Flags [ (0x0) | |
| 118 | # CHECK-NEXT: ] | |
| 119 | # CHECK-NEXT: Address: 0x0 | |
| 120 | # CHECK-NEXT: Offset: 0x2052 | |
| 121 | # CHECK-NEXT: Size: 8 | |
| 122 | # CHECK-NEXT: Link: 0 | |
| 123 | # CHECK-NEXT: Info: 0 | |
| 124 | # CHECK-NEXT: AddressAlignment: 1 | |
| 125 | # CHECK-NEXT: EntrySize: 0 | |
| 126 | # CHECK-NEXT: } | |
| 127 | # CHECK-NEXT: ] | |
| 128 | # CHECK-NEXT: ProgramHeaders [ | |
| 129 | # CHECK-NEXT: ProgramHeader { | |
| 130 | # CHECK-NEXT: Type: PT_PHDR (0x6) | |
| 131 | # CHECK-NEXT: Offset: 0x34 | |
| 132 | # CHECK-NEXT: VirtualAddress: 0x400034 | |
| 133 | # CHECK-NEXT: PhysicalAddress: 0x400034 | |
| 134 | # CHECK-NEXT: FileSize: 128 | |
| 135 | # CHECK-NEXT: MemSize: 128 | |
| 136 | # CHECK-NEXT: Flags [ (0x4) | |
| 137 | # CHECK-NEXT: PF_R (0x4) | |
| 138 | # CHECK-NEXT: ] | |
| 139 | # CHECK-NEXT: Alignment: 4 | |
| 140 | # CHECK-NEXT: } | |
| 141 | # CHECK-NEXT: ProgramHeader { | |
| 142 | # CHECK-NEXT: Type: PT_LOAD (0x1) | |
| 143 | # CHECK-NEXT: Offset: 0x0 | |
| 144 | # CHECK-NEXT: VirtualAddress: 0x400000 | |
| 145 | # CHECK-NEXT: PhysicalAddress: 0x400000 | |
| 146 | # CHECK-NEXT: FileSize: 180 | |
| 147 | # CHECK-NEXT: MemSize: 180 | |
| 148 | # CHECK-NEXT: Flags [ | |
| 149 | # CHECK-NEXT: PF_R | |
| 150 | # CHECK-NEXT: ] | |
| 151 | # CHECK-NEXT: Alignment: 4096 | |
| 152 | # CHECK-NEXT: } | |
| 153 | # CHECK-NEXT: ProgramHeader { | |
| 154 | # CHECK-NEXT: Type: PT_LOAD (0x1) | |
| 155 | # CHECK-NEXT: Offset: 0x1000 | |
| 156 | # CHECK-NEXT: VirtualAddress: 0x401000 | |
| 157 | # CHECK-NEXT: PhysicalAddress: 0x401000 | |
| 158 | # CHECK-NEXT: FileSize: 4096 | |
| 159 | # CHECK-NEXT: MemSize: 4096 | |
| 160 | # CHECK-NEXT: Flags [ (0x5) | |
| 161 | # CHECK-NEXT: PF_R (0x4) | |
| 162 | # CHECK-NEXT: PF_X (0x1) | |
| 163 | # CHECK-NEXT: ] | |
| 164 | # CHECK-NEXT: Alignment: 4096 | |
| 165 | # CHECK-NEXT: } | |
| 166 | # CHECK-NEXT: ProgramHeader { | |
| 167 | # CHECK-NEXT: Type: PT_GNU_STACK | |
| 168 | # CHECK-NEXT: Offset: 0x0 | |
| 169 | # CHECK-NEXT: VirtualAddress: 0x0 | |
| 170 | # CHECK-NEXT: PhysicalAddress: 0x0 | |
| 171 | # CHECK-NEXT: FileSize: 0 | |
| 172 | # CHECK-NEXT: MemSize: 0 | |
| 173 | # CHECK-NEXT: Flags [ | |
| 174 | # CHECK-NEXT: PF_R | |
| 175 | # CHECK-NEXT: PF_W | |
| 176 | # CHECK-NEXT: ] | |
| 177 | # CHECK-NEXT: Alignment: 0 | |
| 178 | # CHECK-NEXT: } | |
| 179 | # CHECK-NEXT: ] |
deps/lld/test/ELF/basic-mips.s+47-23| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: mips |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld %t.o -o %t.exe |
| 4 | # RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t.exe \ | |
| 4 | # RUN: llvm-readobj --file-headers --sections -l --symbols %t.exe \ | |
| 5 | 5 | # RUN: | FileCheck %s |
| 6 | 6 | |
| 7 | 7 | # Exits with return code 1 on Linux. |
| ... | ... | @@ -34,7 +34,7 @@ __start: |
| 34 | 34 | # CHECK-NEXT: ] |
| 35 | 35 | # CHECK-NEXT: HeaderSize: 52 |
| 36 | 36 | # CHECK-NEXT: ProgramHeaderEntrySize: 32 |
| 37 | # CHECK-NEXT: ProgramHeaderCount: 5 | |
| 37 | # CHECK-NEXT: ProgramHeaderCount: 7 | |
| 38 | 38 | # CHECK-NEXT: SectionHeaderEntrySize: 40 |
| 39 | 39 | # CHECK-NEXT: SectionHeaderCount: 11 |
| 40 | 40 | # CHECK-NEXT: StringTableSectionIndex: 9 |
| ... | ... | @@ -61,8 +61,8 @@ __start: |
| 61 | 61 | # CHECK-NEXT: Flags [ (0x2) |
| 62 | 62 | # CHECK-NEXT: SHF_ALLOC (0x2) |
| 63 | 63 | # CHECK-NEXT: ] |
| 64 | # CHECK-NEXT: Address: 0x100D8 | |
| 65 | # CHECK-NEXT: Offset: 0xD8 | |
| 64 | # CHECK-NEXT: Address: 0x10118 | |
| 65 | # CHECK-NEXT: Offset: 0x118 | |
| 66 | 66 | # CHECK-NEXT: Size: 24 |
| 67 | 67 | # CHECK-NEXT: Link: 0 |
| 68 | 68 | # CHECK-NEXT: Info: 0 |
| ... | ... | @@ -76,8 +76,8 @@ __start: |
| 76 | 76 | # CHECK-NEXT: Flags [ (0x2) |
| 77 | 77 | # CHECK-NEXT: SHF_ALLOC (0x2) |
| 78 | 78 | # CHECK-NEXT: ] |
| 79 | # CHECK-NEXT: Address: 0x100F0 | |
| 80 | # CHECK-NEXT: Offset: 0xF0 | |
| 79 | # CHECK-NEXT: Address: 0x10130 | |
| 80 | # CHECK-NEXT: Offset: 0x130 | |
| 81 | 81 | # CHECK-NEXT: Size: 24 |
| 82 | 82 | # CHECK-NEXT: Link: 0 |
| 83 | 83 | # CHECK-NEXT: Info: 0 |
| ... | ... | @@ -245,8 +245,8 @@ __start: |
| 245 | 245 | # CHECK-NEXT: Offset: 0x34 |
| 246 | 246 | # CHECK-NEXT: VirtualAddress: 0x10034 |
| 247 | 247 | # CHECK-NEXT: PhysicalAddress: 0x10034 |
| 248 | # CHECK-NEXT: FileSize: 160 | |
| 249 | # CHECK-NEXT: MemSize: 160 | |
| 248 | # CHECK-NEXT: FileSize: 224 | |
| 249 | # CHECK-NEXT: MemSize: 224 | |
| 250 | 250 | # CHECK-NEXT: Flags [ (0x4) |
| 251 | 251 | # CHECK-NEXT: PF_R (0x4) |
| 252 | 252 | # CHECK-NEXT: ] |
| ... | ... | @@ -257,8 +257,8 @@ __start: |
| 257 | 257 | # CHECK-NEXT: Offset: 0x0 |
| 258 | 258 | # CHECK-NEXT: VirtualAddress: 0x10000 |
| 259 | 259 | # CHECK-NEXT: PhysicalAddress: 0x10000 |
| 260 | # CHECK-NEXT: FileSize: 264 | |
| 261 | # CHECK-NEXT: MemSize: 264 | |
| 260 | # CHECK-NEXT: FileSize: 328 | |
| 261 | # CHECK-NEXT: MemSize: 328 | |
| 262 | 262 | # CHECK-NEXT: Flags [ (0x4) |
| 263 | 263 | # CHECK-NEXT: PF_R (0x4) |
| 264 | 264 | # CHECK-NEXT: ] |
| ... | ... | @@ -291,16 +291,40 @@ __start: |
| 291 | 291 | # CHECK-NEXT: Alignment: 65536 |
| 292 | 292 | # CHECK-NEXT: } |
| 293 | 293 | # CHECK-NEXT: ProgramHeader { |
| 294 | # CHECK-NEXT: Type: PT_GNU_STACK | |
| 295 | # CHECK-NEXT: Offset: 0x0 | |
| 296 | # CHECK-NEXT: VirtualAddress: 0x0 | |
| 297 | # CHECK-NEXT: PhysicalAddress: 0x0 | |
| 298 | # CHECK-NEXT: FileSize: 0 | |
| 299 | # CHECK-NEXT: MemSize: 0 | |
| 300 | # CHECK-NEXT: Flags [ | |
| 301 | # CHECK-NEXT: PF_R | |
| 302 | # CHECK-NEXT: PF_W | |
| 303 | # CHECK-NEXT: ] | |
| 304 | # CHECK-NEXT: Alignment: 0 | |
| 305 | # CHECK-NEXT: } | |
| 306 | # CHECK-NEXT:] | |
| 294 | # CHECK-NEXT: Type: PT_GNU_STACK | |
| 295 | # CHECK-NEXT: Offset: 0x0 | |
| 296 | # CHECK-NEXT: VirtualAddress: 0x0 | |
| 297 | # CHECK-NEXT: PhysicalAddress: 0x0 | |
| 298 | # CHECK-NEXT: FileSize: 0 | |
| 299 | # CHECK-NEXT: MemSize: 0 | |
| 300 | # CHECK-NEXT: Flags [ | |
| 301 | # CHECK-NEXT: PF_R | |
| 302 | # CHECK-NEXT: PF_W | |
| 303 | # CHECK-NEXT: ] | |
| 304 | # CHECK-NEXT: Alignment: 0 | |
| 305 | # CHECK-NEXT: } | |
| 306 | # CHECK-NEXT: ProgramHeader { | |
| 307 | # CHECK-NEXT: Type: PT_MIPS_REGINFO | |
| 308 | # CHECK-NEXT: Offset: 0x130 | |
| 309 | # CHECK-NEXT: VirtualAddress: 0x10130 | |
| 310 | # CHECK-NEXT: PhysicalAddress: 0x10130 | |
| 311 | # CHECK-NEXT: FileSize: 24 | |
| 312 | # CHECK-NEXT: MemSize: 24 | |
| 313 | # CHECK-NEXT: Flags [ (0x4) | |
| 314 | # CHECK-NEXT: PF_R (0x4) | |
| 315 | # CHECK-NEXT: ] | |
| 316 | # CHECK-NEXT: Alignment: 4 | |
| 317 | # CHECK-NEXT: } | |
| 318 | # CHECK-NEXT: ProgramHeader { | |
| 319 | # CHECK-NEXT: Type: PT_MIPS_ABIFLAGS | |
| 320 | # CHECK-NEXT: Offset: 0x118 | |
| 321 | # CHECK-NEXT: VirtualAddress: 0x10118 | |
| 322 | # CHECK-NEXT: PhysicalAddress: 0x10118 | |
| 323 | # CHECK-NEXT: FileSize: 24 | |
| 324 | # CHECK-NEXT: MemSize: 24 | |
| 325 | # CHECK-NEXT: Flags [ (0x4) | |
| 326 | # CHECK-NEXT: PF_R (0x4) | |
| 327 | # CHECK-NEXT: ] | |
| 328 | # CHECK-NEXT: Alignment: 8 | |
| 329 | # CHECK-NEXT: } | |
| 330 | # CHECK-NEXT: ] |
deps/lld/test/ELF/basic-ppc.s+41-165| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: ppc |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t | |
| 3 | # RUN: ld.lld --hash-style=sysv -discard-all -shared %t -o %t2 | |
| 4 | # RUN: llvm-readobj -file-headers -sections -section-data -program-headers %t2 | FileCheck %s | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -o %t | |
| 4 | # RUN: llvm-readobj --file-headers --sections --section-data -l %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # exits with return code 42 on FreeBSD |
| 7 | 7 | .text |
| ... | ... | @@ -23,20 +23,20 @@ |
| 23 | 23 | // CHECK-NEXT: ABIVersion: 0 |
| 24 | 24 | // CHECK-NEXT: Unused: (00 00 00 00 00 00 00) |
| 25 | 25 | // CHECK-NEXT: } |
| 26 | // CHECK-NEXT: Type: SharedObject (0x3) | |
| 26 | // CHECK-NEXT: Type: Executable (0x2) | |
| 27 | 27 | // CHECK-NEXT: Machine: EM_PPC (0x14) |
| 28 | 28 | // CHECK-NEXT: Version: 1 |
| 29 | // CHECK-NEXT: Entry: 0x1000 | |
| 29 | // CHECK-NEXT: Entry: 0x10010000 | |
| 30 | 30 | // CHECK-NEXT: ProgramHeaderOffset: 0x34 |
| 31 | // CHECK-NEXT: SectionHeaderOffset: 0x20AC | |
| 31 | // CHECK-NEXT: SectionHeaderOffset: 0x11044 | |
| 32 | 32 | // CHECK-NEXT: Flags [ (0x0) |
| 33 | 33 | // CHECK-NEXT: ] |
| 34 | 34 | // CHECK-NEXT: HeaderSize: 52 |
| 35 | 35 | // CHECK-NEXT: ProgramHeaderEntrySize: 32 |
| 36 | // CHECK-NEXT: ProgramHeaderCount: 7 | |
| 36 | // CHECK-NEXT: ProgramHeaderCount: 4 | |
| 37 | 37 | // CHECK-NEXT: SectionHeaderEntrySize: 40 |
| 38 | // CHECK-NEXT: SectionHeaderCount: 10 | |
| 39 | // CHECK-NEXT: StringTableSectionIndex: 8 | |
| 38 | // CHECK-NEXT: SectionHeaderCount: 6 | |
| 39 | // CHECK-NEXT: StringTableSectionIndex: 4 | |
| 40 | 40 | // CHECK-NEXT: } |
| 41 | 41 | // CHECK-NEXT: Sections [ |
| 42 | 42 | // CHECK-NEXT: Section { |
| ... | ... | @@ -57,68 +57,14 @@ |
| 57 | 57 | // CHECK-NEXT: } |
| 58 | 58 | // CHECK-NEXT: Section { |
| 59 | 59 | // CHECK-NEXT: Index: 1 |
| 60 | // CHECK-NEXT: Name: .dynsym | |
| 61 | // CHECK-NEXT: Type: SHT_DYNSYM (0xB) | |
| 62 | // CHECK-NEXT: Flags [ (0x2) | |
| 63 | // CHECK-NEXT: SHF_ALLOC (0x2) | |
| 64 | // CHECK-NEXT: ] | |
| 65 | // CHECK-NEXT: Address: 0x114 | |
| 66 | // CHECK-NEXT: Offset: 0x114 | |
| 67 | // CHECK-NEXT: Size: 16 | |
| 68 | // CHECK-NEXT: Link: 3 | |
| 69 | // CHECK-NEXT: Info: 1 | |
| 70 | // CHECK-NEXT: AddressAlignment: 4 | |
| 71 | // CHECK-NEXT: EntrySize: 16 | |
| 72 | // CHECK-NEXT: SectionData ( | |
| 73 | // CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000 |................| | |
| 74 | // CHECK-NEXT: ) | |
| 75 | // CHECK-NEXT: } | |
| 76 | // CHECK-NEXT: Section { | |
| 77 | // CHECK-NEXT: Index: 2 | |
| 78 | // CHECK-NEXT: Name: .hash | |
| 79 | // CHECK-NEXT: Type: SHT_HASH (0x5) | |
| 80 | // CHECK-NEXT: Flags [ (0x2) | |
| 81 | // CHECK-NEXT: SHF_ALLOC (0x2) | |
| 82 | // CHECK-NEXT: ] | |
| 83 | // CHECK-NEXT: Address: 0x124 | |
| 84 | // CHECK-NEXT: Offset: 0x124 | |
| 85 | // CHECK-NEXT: Size: 16 | |
| 86 | // CHECK-NEXT: Link: 1 | |
| 87 | // CHECK-NEXT: Info: 0 | |
| 88 | // CHECK-NEXT: AddressAlignment: 4 | |
| 89 | // CHECK-NEXT: EntrySize: 4 | |
| 90 | // CHECK-NEXT: SectionData ( | |
| 91 | // CHECK-NEXT: 0000: 00000001 00000001 00000000 00000000 |................| | |
| 92 | // CHECK-NEXT: ) | |
| 93 | // CHECK-NEXT: } | |
| 94 | // CHECK-NEXT: Section { | |
| 95 | // CHECK-NEXT: Index: 3 | |
| 96 | // CHECK-NEXT: Name: .dynstr | |
| 97 | // CHECK-NEXT: Type: SHT_STRTAB (0x3) | |
| 98 | // CHECK-NEXT: Flags [ (0x2) | |
| 99 | // CHECK-NEXT: SHF_ALLOC (0x2) | |
| 100 | // CHECK-NEXT: ] | |
| 101 | // CHECK-NEXT: Address: 0x134 | |
| 102 | // CHECK-NEXT: Offset: 0x134 | |
| 103 | // CHECK-NEXT: Size: 1 | |
| 104 | // CHECK-NEXT: Link: 0 | |
| 105 | // CHECK-NEXT: Info: 0 | |
| 106 | // CHECK-NEXT: AddressAlignment: 1 | |
| 107 | // CHECK-NEXT: EntrySize: 0 | |
| 108 | // CHECK-NEXT: SectionData ( | |
| 109 | // CHECK-NEXT: 0000: 00 |.| | |
| 110 | // CHECK-NEXT: ) | |
| 111 | // CHECK-NEXT: } | |
| 112 | // CHECK-NEXT: Section { | |
| 113 | // CHECK-NEXT: Index: 4 | |
| 114 | 60 | // CHECK-NEXT: Name: .text |
| 115 | 61 | // CHECK-NEXT: Type: SHT_PROGBITS (0x1) |
| 116 | 62 | // CHECK-NEXT: Flags [ (0x6) |
| 117 | 63 | // CHECK-NEXT: SHF_ALLOC (0x2) |
| 118 | 64 | // CHECK-NEXT: SHF_EXECINSTR (0x4) |
| 119 | 65 | // CHECK-NEXT: ] |
| 120 | // CHECK-NEXT: Address: 0x1000 | |
| 121 | // CHECK-NEXT: Offset: 0x1000 | |
| 66 | // CHECK-NEXT: Address: 0x10010000 | |
| 67 | // CHECK-NEXT: Offset: 0x10000 | |
| 122 | 68 | // CHECK-NEXT: Size: 12 |
| 123 | 69 | // CHECK-NEXT: Link: 0 |
| 124 | 70 | // CHECK-NEXT: Info: 0 |
| ... | ... | @@ -129,28 +75,7 @@ |
| 129 | 75 | // CHECK-NEXT: ) |
| 130 | 76 | // CHECK-NEXT: } |
| 131 | 77 | // CHECK-NEXT: Section { |
| 132 | // CHECK-NEXT: Index: 5 | |
| 133 | // CHECK-NEXT: Name: .dynamic | |
| 134 | // CHECK-NEXT: Type: SHT_DYNAMIC (0x6) | |
| 135 | // CHECK-NEXT: Flags [ (0x3) | |
| 136 | // CHECK-NEXT: SHF_ALLOC (0x2) | |
| 137 | // CHECK-NEXT: SHF_WRITE (0x1) | |
| 138 | // CHECK-NEXT: ] | |
| 139 | // CHECK-NEXT: Address: 0x2000 | |
| 140 | // CHECK-NEXT: Offset: 0x2000 | |
| 141 | // CHECK-NEXT: Size: 48 | |
| 142 | // CHECK-NEXT: Link: 3 | |
| 143 | // CHECK-NEXT: Info: 0 | |
| 144 | // CHECK-NEXT: AddressAlignment: 4 | |
| 145 | // CHECK-NEXT: EntrySize: 8 | |
| 146 | // CHECK-NEXT: SectionData ( | |
| 147 | // CHECK-NEXT: 0000: 00000006 00000114 0000000B 00000010 | |
| 148 | // CHECK-NEXT: 0010: 00000005 00000134 0000000A 00000001 | |
| 149 | // CHECK-NEXT: 0020: 00000004 00000124 00000000 00000000 | |
| 150 | // CHECK-NEXT: ) | |
| 151 | // CHECK-NEXT: } | |
| 152 | // CHECK-NEXT: Section { | |
| 153 | // CHECK-NEXT: Index: 6 | |
| 78 | // CHECK-NEXT: Index: 2 | |
| 154 | 79 | // CHECK-NEXT: Name: .comment |
| 155 | 80 | // CHECK-NEXT: Type: SHT_PROGBITS (0x1) |
| 156 | 81 | // CHECK-NEXT: Flags [ (0x30) |
| ... | ... | @@ -158,70 +83,59 @@ |
| 158 | 83 | // CHECK-NEXT: SHF_STRINGS (0x20) |
| 159 | 84 | // CHECK-NEXT: ] |
| 160 | 85 | // CHECK-NEXT: Address: 0x0 |
| 161 | // CHECK-NEXT: Offset: 0x2030 | |
| 86 | // CHECK-NEXT: Offset: 0x11000 | |
| 162 | 87 | // CHECK-NEXT: Size: 8 |
| 163 | 88 | // CHECK-NEXT: Link: 0 |
| 164 | 89 | // CHECK-NEXT: Info: 0 |
| 165 | 90 | // CHECK-NEXT: AddressAlignment: 1 |
| 166 | 91 | // CHECK-NEXT: EntrySize: 1 |
| 167 | // CHECK-NEXT: SectionData ( | |
| 168 | // CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.| | |
| 169 | // CHECK-NEXT: ) | |
| 170 | // CHECK-NEXT: } | |
| 92 | // CHECK: } | |
| 171 | 93 | // CHECK-NEXT: Section { |
| 172 | // CHECK-NEXT: Index: 7 | |
| 94 | // CHECK-NEXT: Index: 3 | |
| 173 | 95 | // CHECK-NEXT: Name: .symtab |
| 174 | 96 | // CHECK-NEXT: Type: SHT_SYMTAB (0x2) |
| 175 | 97 | // CHECK-NEXT: Flags [ (0x0) |
| 176 | 98 | // CHECK-NEXT: ] |
| 177 | 99 | // CHECK-NEXT: Address: 0x0 |
| 178 | // CHECK-NEXT: Offset: 0x2038 | |
| 179 | // CHECK-NEXT: Size: 32 | |
| 180 | // CHECK-NEXT: Link: 9 | |
| 181 | // CHECK-NEXT: Info: 2 | |
| 100 | // CHECK-NEXT: Offset: 0x11008 | |
| 101 | // CHECK-NEXT: Size: 16 | |
| 102 | // CHECK-NEXT: Link: 5 | |
| 103 | // CHECK-NEXT: Info: 1 | |
| 182 | 104 | // CHECK-NEXT: AddressAlignment: 4 |
| 183 | 105 | // CHECK-NEXT: EntrySize: 16 |
| 184 | 106 | // CHECK-NEXT: SectionData ( |
| 185 | 107 | // CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000 |................| |
| 186 | // CHECK-NEXT: 0010: 00000001 00002000 00000000 00020005 |...... .........| | |
| 187 | 108 | // CHECK-NEXT: ) |
| 188 | 109 | // CHECK-NEXT: } |
| 189 | 110 | // CHECK-NEXT: Section { |
| 190 | // CHECK-NEXT: Index: 8 | |
| 111 | // CHECK-NEXT: Index: 4 | |
| 191 | 112 | // CHECK-NEXT: Name: .shstrtab |
| 192 | 113 | // CHECK-NEXT: Type: SHT_STRTAB (0x3) |
| 193 | 114 | // CHECK-NEXT: Flags [ (0x0) |
| 194 | 115 | // CHECK-NEXT: ] |
| 195 | 116 | // CHECK-NEXT: Address: 0x0 |
| 196 | // CHECK-NEXT: Offset: 0x2058 | |
| 197 | // CHECK-NEXT: Size: 73 | |
| 117 | // CHECK-NEXT: Offset: 0x11018 | |
| 118 | // CHECK-NEXT: Size: 42 | |
| 198 | 119 | // CHECK-NEXT: Link: 0 |
| 199 | 120 | // CHECK-NEXT: Info: 0 |
| 200 | 121 | // CHECK-NEXT: AddressAlignment: 1 |
| 201 | 122 | // CHECK-NEXT: EntrySize: 0 |
| 202 | // CHECK-NEXT: SectionData ( | |
| 203 | // CHECK-NEXT: 0000: 002E6479 6E73796D 002E6861 7368002E |..dynsym..hash..| | |
| 204 | // CHECK-NEXT: 0010: 64796E73 7472002E 74657874 002E6479 |dynstr..text..dy| | |
| 205 | // CHECK-NEXT: 0020: 6E616D69 63002E63 6F6D6D65 6E74002E |namic..comment..| | |
| 206 | // CHECK-NEXT: 0030: 73796D74 6162002E 73687374 72746162 |symtab..shstrtab| | |
| 207 | // CHECK-NEXT: 0040: 002E7374 72746162 00 |..strtab.| | |
| 208 | // CHECK-NEXT: ) | |
| 209 | // CHECK-NEXT: } | |
| 123 | // CHECK: } | |
| 210 | 124 | // CHECK-NEXT: Section { |
| 211 | // CHECK-NEXT: Index: 9 | |
| 125 | // CHECK-NEXT: Index: 5 | |
| 212 | 126 | // CHECK-NEXT: Name: .strtab |
| 213 | 127 | // CHECK-NEXT: Type: SHT_STRTAB (0x3) |
| 214 | 128 | // CHECK-NEXT: Flags [ (0x0) |
| 215 | 129 | // CHECK-NEXT: ] |
| 216 | 130 | // CHECK-NEXT: Address: 0x0 |
| 217 | // CHECK-NEXT: Offset: 0x20A1 | |
| 218 | // CHECK-NEXT: Size: 10 | |
| 131 | // CHECK-NEXT: Offset: 0x11042 | |
| 132 | // CHECK-NEXT: Size: 1 | |
| 219 | 133 | // CHECK-NEXT: Link: 0 |
| 220 | 134 | // CHECK-NEXT: Info: 0 |
| 221 | 135 | // CHECK-NEXT: AddressAlignment: 1 |
| 222 | 136 | // CHECK-NEXT: EntrySize: 0 |
| 223 | 137 | // CHECK-NEXT: SectionData ( |
| 224 | // CHECK-NEXT: 0000: 005F4459 4E414D49 4300 |._DYNAMIC.| | |
| 138 | // CHECK-NEXT: 0000: 00 | |
| 225 | 139 | // CHECK-NEXT: ) |
| 226 | 140 | // CHECK-NEXT: } |
| 227 | 141 | // CHECK-NEXT: ] |
| ... | ... | @@ -229,10 +143,10 @@ |
| 229 | 143 | // CHECK-NEXT: ProgramHeader { |
| 230 | 144 | // CHECK-NEXT: Type: PT_PHDR (0x6) |
| 231 | 145 | // CHECK-NEXT: Offset: 0x34 |
| 232 | // CHECK-NEXT: VirtualAddress: 0x34 | |
| 233 | // CHECK-NEXT: PhysicalAddress: 0x34 | |
| 234 | // CHECK-NEXT: FileSize: 224 | |
| 235 | // CHECK-NEXT: MemSize: 224 | |
| 146 | // CHECK-NEXT: VirtualAddress: 0x10000034 | |
| 147 | // CHECK-NEXT: PhysicalAddress: 0x10000034 | |
| 148 | // CHECK-NEXT: FileSize: 128 | |
| 149 | // CHECK-NEXT: MemSize: 128 | |
| 236 | 150 | // CHECK-NEXT: Flags [ (0x4) |
| 237 | 151 | // CHECK-NEXT: PF_R (0x4) |
| 238 | 152 | // CHECK-NEXT: ] |
| ... | ... | @@ -241,65 +155,27 @@ |
| 241 | 155 | // CHECK-NEXT: ProgramHeader { |
| 242 | 156 | // CHECK-NEXT: Type: PT_LOAD (0x1) |
| 243 | 157 | // CHECK-NEXT: Offset: 0x0 |
| 244 | // CHECK-NEXT: VirtualAddress: 0x0 | |
| 245 | // CHECK-NEXT: PhysicalAddress: 0x0 | |
| 246 | // CHECK-NEXT: FileSize: 309 | |
| 247 | // CHECK-NEXT: MemSize: 309 | |
| 158 | // CHECK-NEXT: VirtualAddress: 0x10000000 | |
| 159 | // CHECK-NEXT: PhysicalAddress: 0x10000000 | |
| 160 | // CHECK-NEXT: FileSize: 180 | |
| 161 | // CHECK-NEXT: MemSize: 180 | |
| 248 | 162 | // CHECK-NEXT: Flags [ (0x4) |
| 249 | 163 | // CHECK-NEXT: PF_R (0x4) |
| 250 | 164 | // CHECK-NEXT: ] |
| 251 | // CHECK-NEXT: Alignment: 4096 | |
| 165 | // CHECK-NEXT: Alignment: 65536 | |
| 252 | 166 | // CHECK-NEXT: } |
| 253 | 167 | // CHECK-NEXT: ProgramHeader { |
| 254 | 168 | // CHECK-NEXT: Type: PT_LOAD (0x1) |
| 255 | 169 | // CHECK-NEXT: Offset: 0x1000 |
| 256 | // CHECK-NEXT: VirtualAddress: 0x1000 | |
| 257 | // CHECK-NEXT: PhysicalAddress: 0x1000 | |
| 258 | // CHECK-NEXT: FileSize: 12 | |
| 259 | // CHECK-NEXT: MemSize: 12 | |
| 170 | // CHECK-NEXT: VirtualAddress: 0x10010000 | |
| 171 | // CHECK-NEXT: PhysicalAddress: 0x10010000 | |
| 172 | // CHECK-NEXT: FileSize: 4096 | |
| 173 | // CHECK-NEXT: MemSize: 4096 | |
| 260 | 174 | // CHECK-NEXT: Flags [ (0x5) |
| 261 | 175 | // CHECK-NEXT: PF_R (0x4) |
| 262 | 176 | // CHECK-NEXT: PF_X (0x1) |
| 263 | 177 | // CHECK-NEXT: ] |
| 264 | // CHECK-NEXT: Alignment: 4096 | |
| 265 | // CHECK-NEXT: } | |
| 266 | // CHECK-NEXT: ProgramHeader { | |
| 267 | // CHECK-NEXT: Type: PT_LOAD (0x1) | |
| 268 | // CHECK-NEXT: Offset: 0x2000 | |
| 269 | // CHECK-NEXT: VirtualAddress: 0x2000 | |
| 270 | // CHECK-NEXT: PhysicalAddress: 0x2000 | |
| 271 | // CHECK-NEXT: FileSize: 48 | |
| 272 | // CHECK-NEXT: MemSize: 48 | |
| 273 | // CHECK-NEXT: Flags [ (0x6) | |
| 274 | // CHECK-NEXT: PF_R (0x4) | |
| 275 | // CHECK-NEXT: PF_W (0x2) | |
| 276 | // CHECK-NEXT: ] | |
| 277 | // CHECK-NEXT: Alignment: 4096 | |
| 278 | // CHECK-NEXT: } | |
| 279 | // CHECK-NEXT: ProgramHeader { | |
| 280 | // CHECK-NEXT: Type: PT_DYNAMIC (0x2) | |
| 281 | // CHECK-NEXT: Offset: 0x2000 | |
| 282 | // CHECK-NEXT: VirtualAddress: 0x2000 | |
| 283 | // CHECK-NEXT: PhysicalAddress: 0x2000 | |
| 284 | // CHECK-NEXT: FileSize: 48 | |
| 285 | // CHECK-NEXT: MemSize: 48 | |
| 286 | // CHECK-NEXT: Flags [ (0x6) | |
| 287 | // CHECK-NEXT: PF_R (0x4) | |
| 288 | // CHECK-NEXT: PF_W (0x2) | |
| 289 | // CHECK-NEXT: ] | |
| 290 | // CHECK-NEXT: Alignment: 4 | |
| 291 | // CHECK-NEXT: } | |
| 292 | // CHECK-NEXT: ProgramHeader { | |
| 293 | // CHECK-NEXT: Type: PT_GNU_RELRO (0x6474E552) | |
| 294 | // CHECK-NEXT: Offset: 0x2000 | |
| 295 | // CHECK-NEXT: VirtualAddress: 0x2000 | |
| 296 | // CHECK-NEXT: PhysicalAddress: 0x2000 | |
| 297 | // CHECK-NEXT: FileSize: 48 | |
| 298 | // CHECK-NEXT: MemSize: 4096 | |
| 299 | // CHECK-NEXT: Flags [ (0x4) | |
| 300 | // CHECK-NEXT: PF_R (0x4) | |
| 301 | // CHECK-NEXT: ] | |
| 302 | // CHECK-NEXT: Alignment: 1 | |
| 178 | // CHECK-NEXT: Alignment: 65536 | |
| 303 | 179 | // CHECK-NEXT: } |
| 304 | 180 | // CHECK-NEXT: ProgramHeader { |
| 305 | 181 | // CHECK-NEXT: Type: PT_GNU_STACK (0x6474E551) |
deps/lld/test/ELF/basic-ppc64.s+48-30| ... | ... | @@ -1,7 +1,12 @@ |
| 1 | 1 | # REQUIRES: ppc |
| 2 | # # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t | |
| 3 | # RUN: ld.lld --hash-style=sysv -discard-all -shared %t -o %t2 | |
| 4 | # RUN: llvm-readobj -file-headers -sections -section-data -program-headers %t2 | FileCheck %s | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 3 | # RUN: ld.lld --hash-style=sysv -discard-all -shared %t.o -o %t.so | |
| 4 | # RUN: llvm-readobj --file-headers --sections --section-data -l %t.so | FileCheck --check-prefixes=CHECK,LE %s | |
| 5 | ||
| 6 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o | |
| 7 | # RUN: ld.lld --hash-style=sysv -discard-all -shared %t.o -o %t.so | |
| 8 | # RUN: llvm-readobj --file-headers --sections --section-data -l %t.so | FileCheck --check-prefixes=CHECK,BE %s | |
| 9 | ||
| 5 | 10 | .abiversion 2 |
| 6 | 11 | # Exits with return code 55 on linux. |
| 7 | 12 | .text |
| ... | ... | @@ -10,14 +15,16 @@ |
| 10 | 15 | sc |
| 11 | 16 | |
| 12 | 17 | // CHECK:Format: ELF64-ppc64 |
| 13 | // CHECK-NEXT:Arch: powerpc64le | |
| 14 | // CHECK-NEXT:AddressSize: 64bit | |
| 15 | // CHECK-NEXT:LoadName: | |
| 16 | // CHECK-NEXT:ElfHeader { | |
| 18 | // LE-NEXT: Arch: powerpc64le | |
| 19 | // BE-NEXT: Arch: powerpc64{{$}} | |
| 20 | // CHECK-NEXT: AddressSize: 64bit | |
| 21 | // CHECK-NEXT: LoadName: | |
| 22 | // CHECK-NEXT: ElfHeader { | |
| 17 | 23 | // CHECK-NEXT: Ident { |
| 18 | 24 | // CHECK-NEXT: Magic: (7F 45 4C 46) |
| 19 | 25 | // CHECK-NEXT: Class: 64-bit (0x2) |
| 20 | // CHECK-NEXT: DataEncoding: LittleEndian (0x1) | |
| 26 | // LE-NEXT: DataEncoding: LittleEndian (0x1) | |
| 27 | // BE-NEXT: DataEncoding: BigEndian (0x2) | |
| 21 | 28 | // CHECK-NEXT: FileVersion: 1 |
| 22 | 29 | // CHECK-NEXT: OS/ABI: SystemV (0x0) |
| 23 | 30 | // CHECK-NEXT: ABIVersion: 0 |
| ... | ... | @@ -63,8 +70,8 @@ |
| 63 | 70 | // CHECK-NEXT: Flags [ (0x2) |
| 64 | 71 | // CHECK-NEXT: SHF_ALLOC (0x2) |
| 65 | 72 | // CHECK-NEXT: ] |
| 66 | // CHECK-NEXT: Address: 0x1C8 | |
| 67 | // CHECK-NEXT: Offset: 0x1C8 | |
| 73 | // CHECK-NEXT: Address: 0x200 | |
| 74 | // CHECK-NEXT: Offset: 0x200 | |
| 68 | 75 | // CHECK-NEXT: Size: 24 |
| 69 | 76 | // CHECK-NEXT: Link: 3 |
| 70 | 77 | // CHECK-NEXT: Info: 1 |
| ... | ... | @@ -82,15 +89,16 @@ |
| 82 | 89 | // CHECK-NEXT: Flags [ (0x2) |
| 83 | 90 | // CHECK-NEXT: SHF_ALLOC (0x2) |
| 84 | 91 | // CHECK-NEXT: ] |
| 85 | // CHECK-NEXT: Address: 0x1E0 | |
| 86 | // CHECK-NEXT: Offset: 0x1E0 | |
| 92 | // CHECK-NEXT: Address: 0x218 | |
| 93 | // CHECK-NEXT: Offset: 0x218 | |
| 87 | 94 | // CHECK-NEXT: Size: 16 |
| 88 | 95 | // CHECK-NEXT: Link: 1 |
| 89 | 96 | // CHECK-NEXT: Info: 0 |
| 90 | 97 | // CHECK-NEXT: AddressAlignment: 4 |
| 91 | 98 | // CHECK-NEXT: EntrySize: 4 |
| 92 | 99 | // CHECK-NEXT: SectionData ( |
| 93 | // CHECK-NEXT: 0000: 01000000 01000000 00000000 00000000 |................| | |
| 100 | // LE-NEXT: 0000: 01000000 01000000 00000000 00000000 | |
| 101 | // BE-NEXT: 0000: 00000001 00000001 00000000 00000000 | |
| 94 | 102 | // CHECK-NEXT: ) |
| 95 | 103 | // CHECK-NEXT: } |
| 96 | 104 | // CHECK-NEXT: Section { |
| ... | ... | @@ -100,8 +108,8 @@ |
| 100 | 108 | // CHECK-NEXT: Flags [ (0x2) |
| 101 | 109 | // CHECK-NEXT: SHF_ALLOC (0x2) |
| 102 | 110 | // CHECK-NEXT: ] |
| 103 | // CHECK-NEXT: Address: 0x1F0 | |
| 104 | // CHECK-NEXT: Offset: 0x1F0 | |
| 111 | // CHECK-NEXT: Address: 0x228 | |
| 112 | // CHECK-NEXT: Offset: 0x228 | |
| 105 | 113 | // CHECK-NEXT: Size: 1 |
| 106 | 114 | // CHECK-NEXT: Link: 0 |
| 107 | 115 | // CHECK-NEXT: Info: 0 |
| ... | ... | @@ -127,7 +135,8 @@ |
| 127 | 135 | // CHECK-NEXT: AddressAlignment: 4 |
| 128 | 136 | // CHECK-NEXT: EntrySize: 0 |
| 129 | 137 | // CHECK-NEXT: SectionData ( |
| 130 | // CHECK-NEXT: 0000: 01000038 37006038 02000044 |...87.`8...D| | |
| 138 | // LE-NEXT: 0000: 01000038 37006038 02000044 | |
| 139 | // BE-NEXT: 0000: 38000001 38600037 44000002 | |
| 131 | 140 | // CHECK-NEXT: ) |
| 132 | 141 | // CHECK-NEXT: } |
| 133 | 142 | // CHECK-NEXT: Section { |
| ... | ... | @@ -146,12 +155,18 @@ |
| 146 | 155 | // CHECK-NEXT: AddressAlignment: 8 |
| 147 | 156 | // CHECK-NEXT: EntrySize: 16 |
| 148 | 157 | // CHECK-NEXT: SectionData ( |
| 149 | // CHECK-NEXT: 0000: 06000000 00000000 C8010000 00000000 |................| | |
| 150 | // CHECK-NEXT: 0010: 0B000000 00000000 18000000 00000000 |................| | |
| 151 | // CHECK-NEXT: 0020: 05000000 00000000 F0010000 00000000 |................| | |
| 152 | // CHECK-NEXT: 0030: 0A000000 00000000 01000000 00000000 |................| | |
| 153 | // CHECK-NEXT: 0040: 04000000 00000000 E0010000 00000000 |................| | |
| 154 | // CHECK-NEXT: 0050: 00000000 00000000 00000000 00000000 |................| | |
| 158 | // LE-NEXT: 0000: 06000000 00000000 00020000 00000000 | | |
| 159 | // LE-NEXT: 0010: 0B000000 00000000 18000000 00000000 | | |
| 160 | // LE-NEXT: 0020: 05000000 00000000 28020000 00000000 | | |
| 161 | // LE-NEXT: 0030: 0A000000 00000000 01000000 00000000 | | |
| 162 | // LE-NEXT: 0040: 04000000 00000000 18020000 00000000 | | |
| 163 | // LE-NEXT: 0050: 00000000 00000000 00000000 00000000 | | |
| 164 | // BE-NEXT: 0000: 00000000 00000006 00000000 00000200 | | |
| 165 | // BE-NEXT: 0010: 00000000 0000000B 00000000 00000018 | | |
| 166 | // BE-NEXT: 0020: 00000000 00000005 00000000 00000228 | | |
| 167 | // BE-NEXT: 0030: 00000000 0000000A 00000000 00000001 | | |
| 168 | // BE-NEXT: 0040: 00000000 00000004 00000000 00000218 | | |
| 169 | // BE-NEXT: 0050: 00000000 00000000 00000000 00000000 | | |
| 155 | 170 | // CHECK-NEXT: ) |
| 156 | 171 | // CHECK-NEXT: } |
| 157 | 172 | // CHECK-NEXT: Section { |
| ... | ... | @@ -203,9 +218,12 @@ |
| 203 | 218 | // CHECK-NEXT: AddressAlignment: 8 |
| 204 | 219 | // CHECK-NEXT: EntrySize: 24 |
| 205 | 220 | // CHECK-NEXT: SectionData ( |
| 206 | // CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000 |................| | |
| 207 | // CHECK-NEXT: 0010: 00000000 00000000 01000000 00020500 |................| | |
| 208 | // CHECK-NEXT: 0020: 00000200 00000000 00000000 00000000 |................| | |
| 221 | // LE-NEXT: 0000: 00000000 00000000 00000000 00000000 |................| | |
| 222 | // LE-NEXT: 0010: 00000000 00000000 01000000 00020500 |................| | |
| 223 | // LE-NEXT: 0020: 00000200 00000000 00000000 00000000 |................| | |
| 224 | // BE-NEXT: 0000: 00000000 00000000 00000000 00000000 |................| | |
| 225 | // BE-NEXT: 0010: 00000000 00000000 00000001 00020005 |................| | |
| 226 | // BE-NEXT: 0020: 00000000 00020000 00000000 00000000 |................| | |
| 209 | 227 | // CHECK-NEXT: ) |
| 210 | 228 | // CHECK-NEXT: } |
| 211 | 229 | // CHECK-NEXT: Section { |
| ... | ... | @@ -254,8 +272,8 @@ |
| 254 | 272 | // CHECK-NEXT: Offset: 0x40 |
| 255 | 273 | // CHECK-NEXT: VirtualAddress: 0x40 |
| 256 | 274 | // CHECK-NEXT: PhysicalAddress: 0x40 |
| 257 | // CHECK-NEXT: FileSize: 392 | |
| 258 | // CHECK-NEXT: MemSize: 392 | |
| 275 | // CHECK-NEXT: FileSize: 448 | |
| 276 | // CHECK-NEXT: MemSize: 448 | |
| 259 | 277 | // CHECK-NEXT: Flags [ (0x4) |
| 260 | 278 | // CHECK-NEXT: PF_R (0x4) |
| 261 | 279 | // CHECK-NEXT: ] |
| ... | ... | @@ -266,8 +284,8 @@ |
| 266 | 284 | // CHECK-NEXT: Offset: 0x0 |
| 267 | 285 | // CHECK-NEXT: VirtualAddress: 0x0 |
| 268 | 286 | // CHECK-NEXT: PhysicalAddress: 0x0 |
| 269 | // CHECK-NEXT: FileSize: 497 | |
| 270 | // CHECK-NEXT: MemSize: 497 | |
| 287 | // CHECK-NEXT: FileSize: 553 | |
| 288 | // CHECK-NEXT: MemSize: 553 | |
| 271 | 289 | // CHECK-NEXT: Flags [ (0x4) |
| 272 | 290 | // CHECK-NEXT: PF_R (0x4) |
| 273 | 291 | // CHECK-NEXT: ] |
| ... | ... | @@ -292,7 +310,7 @@ |
| 292 | 310 | // CHECK-NEXT: VirtualAddress: 0x20000 |
| 293 | 311 | // CHECK-NEXT: PhysicalAddress: 0x20000 |
| 294 | 312 | // CHECK-NEXT: FileSize: 96 |
| 295 | // CHECK-NEXT: MemSize: 65536 | |
| 313 | // CHECK-NEXT: MemSize: 96 | |
| 296 | 314 | // CHECK-NEXT: Flags [ (0x6) |
| 297 | 315 | // CHECK-NEXT: PF_R (0x4) |
| 298 | 316 | // CHECK-NEXT: PF_W (0x2) |
deps/lld/test/ELF/basic-sparcv9.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: sparc |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=sparc64-unknown-openbsd %s -o %t |
| 3 | 3 | # RUN: ld.lld %t -o %t2 |
| 4 | # RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t2 \ | |
| 4 | # RUN: llvm-readobj --file-headers --sections -l --symbols %t2 \ | |
| 5 | 5 | # RUN: | FileCheck %s |
| 6 | 6 | |
| 7 | 7 | # exits with return code 42 on OpenBSD/sparc64 |
deps/lld/test/ELF/basic.s+6-3| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 4 | 4 | # RUN: ld.lld %t -o %t2 |
| 5 | # RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t2 \ | |
| 5 | # RUN: llvm-readobj --file-headers --sections -l --symbols %t2 \ | |
| 6 | 6 | # RUN: | FileCheck %s |
| 7 | 7 | # RUN: ld.lld %t -o /dev/null |
| 8 | 8 | |
| ... | ... | @@ -204,7 +204,7 @@ _start: |
| 204 | 204 | # Test for the response file (POSIX quoting style) |
| 205 | 205 | # RUN: echo " -o %t2" > %t.responsefile |
| 206 | 206 | # RUN: ld.lld %t --rsp-quoting=posix @%t.responsefile |
| 207 | # RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t2 \ | |
| 207 | # RUN: llvm-readobj --file-headers --sections -l --symbols %t2 \ | |
| 208 | 208 | # RUN: | FileCheck %s |
| 209 | 209 | |
| 210 | 210 | # Test for the response file (Windows quoting style) |
| ... | ... | @@ -234,7 +234,7 @@ _start: |
| 234 | 234 | # NO_O_VAL: -o: missing argument |
| 235 | 235 | |
| 236 | 236 | # RUN: not ld.lld --foo 2>&1 | FileCheck --check-prefix=UNKNOWN %s |
| 237 | # UNKNOWN: unknown argument: --foo | |
| 237 | # UNKNOWN: unknown argument '--foo' | |
| 238 | 238 | |
| 239 | 239 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 240 | 240 | # RUN: not ld.lld %t %t -o %t2 2>&1 | FileCheck --check-prefix=DUP %s |
| ... | ... | @@ -252,3 +252,6 @@ _start: |
| 252 | 252 | # RUN: not ld.lld %t --thinlto-jobs=0 2>&1 | FileCheck --check-prefix=NOTHREADSTHIN %s |
| 253 | 253 | # RUN: not ld.lld %t --plugin-opt=jobs=0 2>&1 | FileCheck --check-prefix=NOTHREADSTHIN %s |
| 254 | 254 | # NOTHREADSTHIN: --thinlto-jobs: number of threads must be > 0 |
| 255 | ||
| 256 | # RUN: not ld.lld %t -z ifunc-noplt -z text 2>&1 | FileCheck --check-prefix=NOIFUNCPLTNOTEXTREL %s | |
| 257 | # NOIFUNCPLTNOTEXTREL: -z text and -z ifunc-noplt may not be used together |
deps/lld/test/ELF/basic32.s deleted-179| ... | ... | @@ -1,179 +0,0 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t | |
| 3 | # RUN: ld.lld %t -o %t2 | |
| 4 | # RUN: llvm-readobj -file-headers -sections -program-headers %t2 | FileCheck %s | |
| 5 | ||
| 6 | # exits with return code 42 on linux | |
| 7 | .globl _start | |
| 8 | _start: | |
| 9 | mov $1, %eax | |
| 10 | mov $42, %ebx | |
| 11 | int $0x80 | |
| 12 | ||
| 13 | # CHECK: ElfHeader { | |
| 14 | # CHECK-NEXT: Ident { | |
| 15 | # CHECK-NEXT: Magic: (7F 45 4C 46) | |
| 16 | # CHECK-NEXT: Class: 32-bit (0x1) | |
| 17 | # CHECK-NEXT: DataEncoding: LittleEndian (0x1) | |
| 18 | # CHECK-NEXT: FileVersion: 1 | |
| 19 | # CHECK-NEXT: OS/ABI: SystemV (0x0) | |
| 20 | # CHECK-NEXT: ABIVersion: 0 | |
| 21 | # CHECK-NEXT: Unused: (00 00 00 00 00 00 00) | |
| 22 | # CHECK-NEXT: } | |
| 23 | # CHECK-NEXT: Type: Executable (0x2) | |
| 24 | # CHECK-NEXT: Machine: EM_386 (0x3) | |
| 25 | # CHECK-NEXT: Version: 1 | |
| 26 | # CHECK-NEXT: Entry: 0x401000 | |
| 27 | # CHECK-NEXT: ProgramHeaderOffset: 0x34 | |
| 28 | # CHECK-NEXT: SectionHeaderOffset: 0x205C | |
| 29 | # CHECK-NEXT: Flags [ (0x0) | |
| 30 | # CHECK-NEXT: ] | |
| 31 | # CHECK-NEXT: HeaderSize: 52 | |
| 32 | # CHECK-NEXT: ProgramHeaderEntrySize: 32 | |
| 33 | # CHECK-NEXT: ProgramHeaderCount: 4 | |
| 34 | # CHECK-NEXT: SectionHeaderEntrySize: 40 | |
| 35 | # CHECK-NEXT: SectionHeaderCount: 6 | |
| 36 | # CHECK-NEXT: StringTableSectionIndex: 4 | |
| 37 | # CHECK-NEXT: } | |
| 38 | # CHECK-NEXT: Sections [ | |
| 39 | # CHECK-NEXT: Section { | |
| 40 | # CHECK-NEXT: Index: 0 | |
| 41 | # CHECK-NEXT: Name: (0) | |
| 42 | # CHECK-NEXT: Type: SHT_NULL (0x0) | |
| 43 | # CHECK-NEXT: Flags [ (0x0) | |
| 44 | # CHECK-NEXT: ] | |
| 45 | # CHECK-NEXT: Address: 0x0 | |
| 46 | # CHECK-NEXT: Offset: 0x0 | |
| 47 | # CHECK-NEXT: Size: 0 | |
| 48 | # CHECK-NEXT: Link: 0 | |
| 49 | # CHECK-NEXT: Info: 0 | |
| 50 | # CHECK-NEXT: AddressAlignment: 0 | |
| 51 | # CHECK-NEXT: EntrySize: 0 | |
| 52 | # CHECK-NEXT: } | |
| 53 | # CHECK-NEXT: Section { | |
| 54 | # CHECK-NEXT: Index: 1 | |
| 55 | # CHECK-NEXT: Name: .text | |
| 56 | # CHECK-NEXT: Type: SHT_PROGBITS (0x1) | |
| 57 | # CHECK-NEXT: Flags [ (0x6) | |
| 58 | # CHECK-NEXT: SHF_ALLOC (0x2) | |
| 59 | # CHECK-NEXT: SHF_EXECINSTR (0x4) | |
| 60 | # CHECK-NEXT: ] | |
| 61 | # CHECK-NEXT: Address: 0x401000 | |
| 62 | # CHECK-NEXT: Offset: 0x1000 | |
| 63 | # CHECK-NEXT: Size: 12 | |
| 64 | # CHECK-NEXT: Link: 0 | |
| 65 | # CHECK-NEXT: Info: 0 | |
| 66 | # CHECK-NEXT: AddressAlignment: 4 | |
| 67 | # CHECK-NEXT: EntrySize: 0 | |
| 68 | # CHECK-NEXT: } | |
| 69 | # CHECK-NEXT: Section { | |
| 70 | # CHECK-NEXT: Index: 2 | |
| 71 | # CHECK-NEXT: Name: .comment | |
| 72 | # CHECK-NEXT: Type: SHT_PROGBITS (0x1) | |
| 73 | # CHECK-NEXT: Flags [ (0x30) | |
| 74 | # CHECK-NEXT: SHF_MERGE (0x10) | |
| 75 | # CHECK-NEXT: SHF_STRINGS (0x20) | |
| 76 | # CHECK-NEXT: ] | |
| 77 | # CHECK-NEXT: Address: 0x0 | |
| 78 | # CHECK-NEXT: Offset: 0x2000 | |
| 79 | # CHECK-NEXT: Size: 8 | |
| 80 | # CHECK-NEXT: Link: 0 | |
| 81 | # CHECK-NEXT: Info: 0 | |
| 82 | # CHECK-NEXT: AddressAlignment: 1 | |
| 83 | # CHECK-NEXT: EntrySize: 1 | |
| 84 | # CHECK-NEXT: } | |
| 85 | # CHECK-NEXT: Section { | |
| 86 | # CHECK-NEXT: Index: 3 | |
| 87 | # CHECK-NEXT: Name: .symtab | |
| 88 | # CHECK-NEXT: Type: SHT_SYMTAB | |
| 89 | # CHECK-NEXT: Flags [ | |
| 90 | # CHECK-NEXT: ] | |
| 91 | # CHECK-NEXT: Address: 0x0 | |
| 92 | # CHECK-NEXT: Offset: 0x2008 | |
| 93 | # CHECK-NEXT: Size: 32 | |
| 94 | # CHECK-NEXT: Link: 5 | |
| 95 | # CHECK-NEXT: Info: 1 | |
| 96 | # CHECK-NEXT: AddressAlignment: 4 | |
| 97 | # CHECK-NEXT: EntrySize: 16 | |
| 98 | # CHECK-NEXT: } | |
| 99 | # CHECK-NEXT: Section { | |
| 100 | # CHECK-NEXT: Index: 4 | |
| 101 | # CHECK-NEXT: Name: .shstrtab | |
| 102 | # CHECK-NEXT: Type: SHT_STRTAB (0x3) | |
| 103 | # CHECK-NEXT: Flags [ (0x0) | |
| 104 | # CHECK-NEXT: ] | |
| 105 | # CHECK-NEXT: Address: 0x0 | |
| 106 | # CHECK-NEXT: Offset: 0x2028 | |
| 107 | # CHECK-NEXT: Size: 42 | |
| 108 | # CHECK-NEXT: Link: 0 | |
| 109 | # CHECK-NEXT: Info: 0 | |
| 110 | # CHECK-NEXT: AddressAlignment: 1 | |
| 111 | # CHECK-NEXT: EntrySize: 0 | |
| 112 | # CHECK-NEXT: } | |
| 113 | # CHECK-NEXT: Section { | |
| 114 | # CHECK-NEXT: Index: 5 | |
| 115 | # CHECK-NEXT: Name: .strtab | |
| 116 | # CHECK-NEXT: Type: SHT_STRTAB (0x3) | |
| 117 | # CHECK-NEXT: Flags [ (0x0) | |
| 118 | # CHECK-NEXT: ] | |
| 119 | # CHECK-NEXT: Address: 0x0 | |
| 120 | # CHECK-NEXT: Offset: 0x2052 | |
| 121 | # CHECK-NEXT: Size: 8 | |
| 122 | # CHECK-NEXT: Link: 0 | |
| 123 | # CHECK-NEXT: Info: 0 | |
| 124 | # CHECK-NEXT: AddressAlignment: 1 | |
| 125 | # CHECK-NEXT: EntrySize: 0 | |
| 126 | # CHECK-NEXT: } | |
| 127 | # CHECK-NEXT: ] | |
| 128 | # CHECK-NEXT: ProgramHeaders [ | |
| 129 | # CHECK-NEXT: ProgramHeader { | |
| 130 | # CHECK-NEXT: Type: PT_PHDR (0x6) | |
| 131 | # CHECK-NEXT: Offset: 0x34 | |
| 132 | # CHECK-NEXT: VirtualAddress: 0x400034 | |
| 133 | # CHECK-NEXT: PhysicalAddress: 0x400034 | |
| 134 | # CHECK-NEXT: FileSize: 128 | |
| 135 | # CHECK-NEXT: MemSize: 128 | |
| 136 | # CHECK-NEXT: Flags [ (0x4) | |
| 137 | # CHECK-NEXT: PF_R (0x4) | |
| 138 | # CHECK-NEXT: ] | |
| 139 | # CHECK-NEXT: Alignment: 4 | |
| 140 | # CHECK-NEXT: } | |
| 141 | # CHECK-NEXT: ProgramHeader { | |
| 142 | # CHECK-NEXT: Type: PT_LOAD (0x1) | |
| 143 | # CHECK-NEXT: Offset: 0x0 | |
| 144 | # CHECK-NEXT: VirtualAddress: 0x400000 | |
| 145 | # CHECK-NEXT: PhysicalAddress: 0x400000 | |
| 146 | # CHECK-NEXT: FileSize: 180 | |
| 147 | # CHECK-NEXT: MemSize: 180 | |
| 148 | # CHECK-NEXT: Flags [ | |
| 149 | # CHECK-NEXT: PF_R | |
| 150 | # CHECK-NEXT: ] | |
| 151 | # CHECK-NEXT: Alignment: 4096 | |
| 152 | # CHECK-NEXT: } | |
| 153 | # CHECK-NEXT: ProgramHeader { | |
| 154 | # CHECK-NEXT: Type: PT_LOAD (0x1) | |
| 155 | # CHECK-NEXT: Offset: 0x1000 | |
| 156 | # CHECK-NEXT: VirtualAddress: 0x401000 | |
| 157 | # CHECK-NEXT: PhysicalAddress: 0x401000 | |
| 158 | # CHECK-NEXT: FileSize: 4096 | |
| 159 | # CHECK-NEXT: MemSize: 4096 | |
| 160 | # CHECK-NEXT: Flags [ (0x5) | |
| 161 | # CHECK-NEXT: PF_R (0x4) | |
| 162 | # CHECK-NEXT: PF_X (0x1) | |
| 163 | # CHECK-NEXT: ] | |
| 164 | # CHECK-NEXT: Alignment: 4096 | |
| 165 | # CHECK-NEXT: } | |
| 166 | # CHECK-NEXT: ProgramHeader { | |
| 167 | # CHECK-NEXT: Type: PT_GNU_STACK | |
| 168 | # CHECK-NEXT: Offset: 0x0 | |
| 169 | # CHECK-NEXT: VirtualAddress: 0x0 | |
| 170 | # CHECK-NEXT: PhysicalAddress: 0x0 | |
| 171 | # CHECK-NEXT: FileSize: 0 | |
| 172 | # CHECK-NEXT: MemSize: 0 | |
| 173 | # CHECK-NEXT: Flags [ | |
| 174 | # CHECK-NEXT: PF_R | |
| 175 | # CHECK-NEXT: PF_W | |
| 176 | # CHECK-NEXT: ] | |
| 177 | # CHECK-NEXT: Alignment: 0 | |
| 178 | # CHECK-NEXT: } | |
| 179 | # CHECK-NEXT: ] |
deps/lld/test/ELF/basic64be.s deleted-217| ... | ... | @@ -1,217 +0,0 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t | |
| 3 | # RUN: ld.lld -discard-all %t -o %t2 | |
| 4 | # RUN: llvm-readobj -file-headers -sections -section-data -program-headers %t2 | FileCheck %s | |
| 5 | ||
| 6 | # exits with return code 42 on linux | |
| 7 | .text | |
| 8 | 	li 0,1 | |
| 9 | 	li 3,42 | |
| 10 | 	sc | |
| 11 | # CHECK: ElfHeader { | |
| 12 | # CHECK-NEXT: Ident { | |
| 13 | # CHECK-NEXT: Magic: (7F 45 4C 46) | |
| 14 | # CHECK-NEXT: Class: 64-bit (0x2) | |
| 15 | # CHECK-NEXT: DataEncoding: BigEndian (0x2) | |
| 16 | # CHECK-NEXT: FileVersion: 1 | |
| 17 | # CHECK-NEXT: OS/ABI: SystemV (0x0) | |
| 18 | # CHECK-NEXT: ABIVersion: 0 | |
| 19 | # CHECK-NEXT: Unused: (00 00 00 00 00 00 00) | |
| 20 | # CHECK-NEXT: } | |
| 21 | # CHECK-NEXT: Type: Executable (0x2) | |
| 22 | # CHECK-NEXT: Machine: EM_PPC64 (0x15) | |
| 23 | # CHECK-NEXT: Version: 1 | |
| 24 | # CHECK-NEXT: Entry: 0x10010000 | |
| 25 | # CHECK-NEXT: ProgramHeaderOffset: 0x40 | |
| 26 | # CHECK-NEXT: SectionHeaderOffset: 0x20058 | |
| 27 | # CHECK-NEXT: Flags [ (0x2) | |
| 28 | # CHECK-NEXT: 0x2 | |
| 29 | # CHECK-NEXT: ] | |
| 30 | # CHECK-NEXT: HeaderSize: 64 | |
| 31 | # CHECK-NEXT: ProgramHeaderEntrySize: 56 | |
| 32 | # CHECK-NEXT: ProgramHeaderCount: 4 | |
| 33 | # CHECK-NEXT: SectionHeaderEntrySize: 64 | |
| 34 | # CHECK-NEXT: SectionHeaderCount: 7 | |
| 35 | # CHECK-NEXT: StringTableSectionIndex: 5 | |
| 36 | # CHECK-NEXT: } | |
| 37 | # CHECK-NEXT: Sections [ | |
| 38 | # CHECK-NEXT: Section { | |
| 39 | # CHECK-NEXT: Index: 0 | |
| 40 | # CHECK-NEXT: Name: (0) | |
| 41 | # CHECK-NEXT: Type: SHT_NULL (0x0) | |
| 42 | # CHECK-NEXT: Flags [ (0x0) | |
| 43 | # CHECK-NEXT: ] | |
| 44 | # CHECK-NEXT: Address: 0x0 | |
| 45 | # CHECK-NEXT: Offset: 0x0 | |
| 46 | # CHECK-NEXT: Size: 0 | |
| 47 | # CHECK-NEXT: Link: 0 | |
| 48 | # CHECK-NEXT: Info: 0 | |
| 49 | # CHECK-NEXT: AddressAlignment: 0 | |
| 50 | # CHECK-NEXT: EntrySize: 0 | |
| 51 | # CHECK-NEXT: SectionData ( | |
| 52 | # CHECK-NEXT: ) | |
| 53 | # CHECK-NEXT: } | |
| 54 | # CHECK-NEXT: Section { | |
| 55 | # CHECK-NEXT: Index: 1 | |
| 56 | # CHECK-NEXT: Name: .text (1) | |
| 57 | # CHECK-NEXT: Type: SHT_PROGBITS (0x1) | |
| 58 | # CHECK-NEXT: Flags [ (0x6) | |
| 59 | # CHECK-NEXT: SHF_ALLOC (0x2) | |
| 60 | # CHECK-NEXT: SHF_EXECINSTR (0x4) | |
| 61 | # CHECK-NEXT: ] | |
| 62 | # CHECK-NEXT: Address: 0x10010000 | |
| 63 | # CHECK-NEXT: Offset: 0x10000 | |
| 64 | # CHECK-NEXT: Size: 12 | |
| 65 | # CHECK-NEXT: Link: 0 | |
| 66 | # CHECK-NEXT: Info: 0 | |
| 67 | # CHECK-NEXT: AddressAlignment: 4 | |
| 68 | # CHECK-NEXT: EntrySize: 0 | |
| 69 | # CHECK-NEXT: SectionData ( | |
| 70 | # CHECK-NEXT: 0000: 38000001 3860002A 44000002 |8...8`.*D...| | |
| 71 | # CHECK-NEXT: ) | |
| 72 | # CHECK-NEXT: } | |
| 73 | # CHECK-NEXT: Section { | |
| 74 | # CHECK-NEXT: Index: 2 | |
| 75 | # CHECK-NEXT: Name: .branch_lt (7) | |
| 76 | # CHECK-NEXT: Type: SHT_PROGBITS (0x1) | |
| 77 | # CHECK-NEXT: Flags [ (0x3) | |
| 78 | # CHECK-NEXT: SHF_ALLOC (0x2) | |
| 79 | # CHECK-NEXT: SHF_WRITE (0x1) | |
| 80 | # CHECK-NEXT: ] | |
| 81 | # CHECK-NEXT: Address: 0x10020000 | |
| 82 | # CHECK-NEXT: Offset: 0x20000 | |
| 83 | # CHECK-NEXT: Size: 0 | |
| 84 | # CHECK-NEXT: Link: 0 | |
| 85 | # CHECK-NEXT: Info: 0 | |
| 86 | # CHECK-NEXT: AddressAlignment: 8 | |
| 87 | # CHECK-NEXT: EntrySize: 0 | |
| 88 | # CHECK-NEXT: SectionData ( | |
| 89 | # CHECK-NEXT: ) | |
| 90 | # CHECK-NEXT: } | |
| 91 | # CHECK-NEXT: Section { | |
| 92 | # CHECK-NEXT: Index: 3 | |
| 93 | # CHECK-NEXT: Name: .comment (18) | |
| 94 | # CHECK-NEXT: Type: SHT_PROGBITS (0x1) | |
| 95 | # CHECK-NEXT: Flags [ (0x30) | |
| 96 | # CHECK-NEXT: SHF_MERGE (0x10) | |
| 97 | # CHECK-NEXT: SHF_STRINGS (0x20) | |
| 98 | # CHECK-NEXT: ] | |
| 99 | # CHECK-NEXT: Address: 0x0 | |
| 100 | # CHECK-NEXT: Offset: 0x20000 | |
| 101 | # CHECK-NEXT: Size: 8 | |
| 102 | # CHECK-NEXT: Link: 0 | |
| 103 | # CHECK-NEXT: Info: 0 | |
| 104 | # CHECK-NEXT: AddressAlignment: 1 | |
| 105 | # CHECK-NEXT: EntrySize: 1 | |
| 106 | # CHECK-NEXT: SectionData ( | |
| 107 | # CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.| | |
| 108 | # CHECK-NEXT: ) | |
| 109 | # CHECK-NEXT: } | |
| 110 | # CHECK-NEXT: Section { | |
| 111 | # CHECK-NEXT: Index: 4 | |
| 112 | # CHECK-NEXT: Name: .symtab (27) | |
| 113 | # CHECK-NEXT: Type: SHT_SYMTAB (0x2) | |
| 114 | # CHECK-NEXT: Flags [ (0x0) | |
| 115 | # CHECK-NEXT: ] | |
| 116 | # CHECK-NEXT: Address: 0x0 | |
| 117 | # CHECK-NEXT: Offset: 0x20008 | |
| 118 | # CHECK-NEXT: Size: 24 | |
| 119 | # CHECK-NEXT: Link: 6 | |
| 120 | # CHECK-NEXT: Info: 1 | |
| 121 | # CHECK-NEXT: AddressAlignment: 8 | |
| 122 | # CHECK-NEXT: EntrySize: 24 | |
| 123 | # CHECK-NEXT: SectionData ( | |
| 124 | # CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000 |................| | |
| 125 | # CHECK-NEXT: 0010: 00000000 00000000 |........| | |
| 126 | # CHECK-NEXT: ) | |
| 127 | # CHECK-NEXT: } | |
| 128 | # CHECK-NEXT: Section { | |
| 129 | # CHECK-NEXT: Index: 5 | |
| 130 | # CHECK-NEXT: Name: .shstrtab (35) | |
| 131 | # CHECK-NEXT: Type: SHT_STRTAB (0x3) | |
| 132 | # CHECK-NEXT: Flags [ (0x0) | |
| 133 | # CHECK-NEXT: ] | |
| 134 | # CHECK-NEXT: Address: 0x0 | |
| 135 | # CHECK-NEXT: Offset: 0x20020 | |
| 136 | # CHECK-NEXT: Size: 53 | |
| 137 | # CHECK-NEXT: Link: 0 | |
| 138 | # CHECK-NEXT: Info: 0 | |
| 139 | # CHECK-NEXT: AddressAlignment: 1 | |
| 140 | # CHECK-NEXT: EntrySize: 0 | |
| 141 | # CHECK-NEXT: SectionData ( | |
| 142 | # CHECK-NEXT: 0000: 002E7465 7874002E 6272616E 63685F6C |..text..branch_l| | |
| 143 | # CHECK-NEXT: 0010: 74002E63 6F6D6D65 6E74002E 73796D74 |t..comment..symt| | |
| 144 | # CHECK-NEXT: 0020: 6162002E 73687374 72746162 002E7374 |ab..shstrtab..st| | |
| 145 | # CHECK-NEXT: 0030: 72746162 00 |rtab.| | |
| 146 | # CHECK-NEXT: ) | |
| 147 | # CHECK-NEXT: } | |
| 148 | # CHECK-NEXT: Section { | |
| 149 | # CHECK-NEXT: Index: 6 | |
| 150 | # CHECK-NEXT: Name: .strtab (45) | |
| 151 | # CHECK-NEXT: Type: SHT_STRTAB (0x3) | |
| 152 | # CHECK-NEXT: Flags [ (0x0) | |
| 153 | # CHECK-NEXT: ] | |
| 154 | # CHECK-NEXT: Address: 0x0 | |
| 155 | # CHECK-NEXT: Offset: 0x20055 | |
| 156 | # CHECK-NEXT: Size: 1 | |
| 157 | # CHECK-NEXT: Link: 0 | |
| 158 | # CHECK-NEXT: Info: 0 | |
| 159 | # CHECK-NEXT: AddressAlignment: 1 | |
| 160 | # CHECK-NEXT: EntrySize: 0 | |
| 161 | # CHECK-NEXT: SectionData ( | |
| 162 | # CHECK-NEXT: 0000: 00 |.| | |
| 163 | # CHECK-NEXT: ) | |
| 164 | # CHECK-NEXT: } | |
| 165 | # CHECK-NEXT: ] | |
| 166 | # CHECK-NEXT: ProgramHeaders [ | |
| 167 | # CHECK-NEXT: ProgramHeader { | |
| 168 | # CHECK-NEXT: Type: PT_PHDR (0x6) | |
| 169 | # CHECK-NEXT: Offset: 0x40 | |
| 170 | # CHECK-NEXT: VirtualAddress: 0x10000040 | |
| 171 | # CHECK-NEXT: PhysicalAddress: 0x10000040 | |
| 172 | # CHECK-NEXT: FileSize: 280 | |
| 173 | # CHECK-NEXT: MemSize: 280 | |
| 174 | # CHECK-NEXT: Flags [ (0x4) | |
| 175 | # CHECK-NEXT: PF_R (0x4) | |
| 176 | # CHECK-NEXT: ] | |
| 177 | # CHECK-NEXT: Alignment: 8 | |
| 178 | # CHECK-NEXT: } | |
| 179 | # CHECK-NEXT: ProgramHeader { | |
| 180 | # CHECK-NEXT: Type: PT_LOAD (0x1) | |
| 181 | # CHECK-NEXT: Offset: 0x0 | |
| 182 | # CHECK-NEXT: VirtualAddress: 0x10000000 | |
| 183 | # CHECK-NEXT: PhysicalAddress: 0x10000000 | |
| 184 | # CHECK-NEXT: FileSize: 344 | |
| 185 | # CHECK-NEXT: MemSize: 344 | |
| 186 | # CHECK-NEXT: Flags [ (0x4) | |
| 187 | # CHECK-NEXT: PF_R (0x4) | |
| 188 | # CHECK-NEXT: ] | |
| 189 | # CHECK-NEXT: Alignment: 65536 | |
| 190 | # CHECK-NEXT: } | |
| 191 | # CHECK-NEXT: ProgramHeader { | |
| 192 | # CHECK-NEXT: Type: PT_LOAD (0x1) | |
| 193 | # CHECK-NEXT: Offset: 0x10000 | |
| 194 | # CHECK-NEXT: VirtualAddress: 0x10010000 | |
| 195 | # CHECK-NEXT: PhysicalAddress: 0x10010000 | |
| 196 | # CHECK-NEXT: FileSize: 4096 | |
| 197 | # CHECK-NEXT: MemSize: 4096 | |
| 198 | # CHECK-NEXT: Flags [ (0x5) | |
| 199 | # CHECK-NEXT: PF_R (0x4) | |
| 200 | # CHECK-NEXT: PF_X (0x1) | |
| 201 | # CHECK-NEXT: ] | |
| 202 | # CHECK-NEXT: Alignment: 65536 | |
| 203 | # CHECK-NEXT: } | |
| 204 | # CHECK-NEXT: ProgramHeader { | |
| 205 | # CHECK-NEXT: Type: PT_GNU_STACK (0x6474E551) | |
| 206 | # CHECK-NEXT: Offset: 0x0 | |
| 207 | # CHECK-NEXT: VirtualAddress: 0x0 | |
| 208 | # CHECK-NEXT: PhysicalAddress: 0x0 | |
| 209 | # CHECK-NEXT: FileSize: 0 | |
| 210 | # CHECK-NEXT: MemSize: 0 | |
| 211 | # CHECK-NEXT: Flags [ (0x6) | |
| 212 | # CHECK-NEXT: PF_R (0x4) | |
| 213 | # CHECK-NEXT: PF_W (0x2) | |
| 214 | # CHECK-NEXT: ] | |
| 215 | # CHECK-NEXT: Alignment: 0 | |
| 216 | # CHECK-NEXT: } | |
| 217 | # CHECK-NEXT: ] |
deps/lld/test/ELF/bss-start-common.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: llvm-objdump -t -section-headers %t2 | FileCheck %s |
| 5 | 5 | |
| 6 | 6 | # CHECK: Sections: |
| 7 | # CHECK: Idx Name Size Address Type | |
| 7 | # CHECK: Idx Name Size VMA Type | |
| 8 | 8 | # CHECK: 2 .bss 00000004 0000000000201000 BSS |
| 9 | 9 | # CHECK: SYMBOL TABLE: |
| 10 | 10 | # CHECK: 0000000000201000 .bss 00000000 __bss_start |
deps/lld/test/ELF/bss.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld %t -o %t2 |
| 4 | // RUN: llvm-readobj -sections %t2 | FileCheck %s | |
| 4 | // RUN: llvm-readobj --sections %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // Test that bss takes no space on disk. |
| 7 | 7 |
deps/lld/test/ELF/bsymbolic-undef.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld -shared -Bsymbolic %t.o -o %t.so |
| 4 | # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s | |
| 4 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: DynamicSymbols [ |
| 7 | 7 | # CHECK-NEXT: Symbol { |
deps/lld/test/ELF/bsymbolic.s+3-3| ... | ... | @@ -3,9 +3,9 @@ |
| 3 | 3 | // RUN: ld.lld -shared %t.o -o %t0.so |
| 4 | 4 | // RUN: ld.lld -shared -Bsymbolic %t.o -o %t1.so |
| 5 | 5 | // RUN: ld.lld -shared -Bsymbolic-functions %t.o -o %t2.so |
| 6 | // RUN: llvm-readobj -s %t0.so | FileCheck -check-prefix=NOOPTION %s | |
| 7 | // RUN: llvm-readobj -s %t1.so | FileCheck -check-prefix=SYMBOLIC %s | |
| 8 | // RUN: llvm-readobj -s %t2.so | FileCheck -check-prefix=SYMBOLIC %s | |
| 6 | // RUN: llvm-readobj -S %t0.so | FileCheck -check-prefix=NOOPTION %s | |
| 7 | // RUN: llvm-readobj -S %t1.so | FileCheck -check-prefix=SYMBOLIC %s | |
| 8 | // RUN: llvm-readobj -S %t2.so | FileCheck -check-prefix=SYMBOLIC %s | |
| 9 | 9 | |
| 10 | 10 | // NOOPTION: Section { |
| 11 | 11 | // NOOPTION: Name: .plt |
deps/lld/test/ELF/build-id.s+4-4| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 4 | 4 | |
| 5 | 5 | # RUN: ld.lld --build-id %t -o %t2 |
| 6 | # RUN: llvm-readobj -s %t2 | FileCheck -check-prefix=ALIGN %s | |
| 6 | # RUN: llvm-readobj -S %t2 | FileCheck -check-prefix=ALIGN %s | |
| 7 | 7 | |
| 8 | 8 | # RUN: ld.lld --build-id %t -o %t2 -threads |
| 9 | 9 | # RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=DEFAULT %s |
| ... | ... | @@ -65,15 +65,15 @@ _start: |
| 65 | 65 | # DEFAULT: Contents of section .note.test: |
| 66 | 66 | # DEFAULT: Contents of section .note.gnu.build-id: |
| 67 | 67 | # DEFAULT-NEXT: 04000000 08000000 03000000 474e5500 ............GNU. |
| 68 | # DEFAULT-NEXT: 894c04e8 fbf5556b | |
| 68 | # DEFAULT-NEXT: 95849665 2621c734 | |
| 69 | 69 | |
| 70 | 70 | # MD5: Contents of section .note.gnu.build-id: |
| 71 | 71 | # MD5-NEXT: 04000000 10000000 03000000 474e5500 ............GNU. |
| 72 | # MD5-NEXT: 6a51bbd7 9e8ee3f9 2e02d213 711cfec9 | |
| 72 | # MD5-NEXT: 1882c01f 71698eed 229b3994 eb554c80 | |
| 73 | 73 | |
| 74 | 74 | # SHA1: Contents of section .note.gnu.build-id: |
| 75 | 75 | # SHA1-NEXT: 04000000 14000000 03000000 474e5500 ............GNU. |
| 76 | # SHA1-NEXT: 9a8618b1 d6fd0e5c eda73dd8 76de5596 | |
| 76 | # SHA1-NEXT: 96820adf d90d5470 0a0c32ff a88c4017 | |
| 77 | 77 | |
| 78 | 78 | # UUID: Contents of section .note.gnu.build-id: |
| 79 | 79 | # UUID-NEXT: 04000000 10000000 03000000 474e5500 ............GNU. |
deps/lld/test/ELF/cgprofile-bad-clusters.s+1-1| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | # RUN: echo "G H 5" >> %t.call_graph |
| 12 | 12 | # RUN: echo "H I 4" >> %t.call_graph |
| 13 | 13 | # RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2 |
| 14 | # RUN: llvm-readobj -symbols %t2 | FileCheck %s | |
| 14 | # RUN: llvm-readobj --symbols %t2 | FileCheck %s | |
| 15 | 15 | |
| 16 | 16 | .section .text.A,"ax",@progbits |
| 17 | 17 | .globl A |
deps/lld/test/ELF/cgprofile-icf.s+2-2| ... | ... | @@ -6,9 +6,9 @@ |
| 6 | 6 | # RUN: echo "A C 40" >> %t.call_graph |
| 7 | 7 | # RUN: echo "C D 61" >> %t.call_graph |
| 8 | 8 | # RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t.out -icf=all |
| 9 | # RUN: llvm-readobj -symbols %t.out | FileCheck %s | |
| 9 | # RUN: llvm-readobj --symbols %t.out | FileCheck %s | |
| 10 | 10 | # RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2.out |
| 11 | # RUN: llvm-readobj -symbols %t2.out | FileCheck %s --check-prefix=NOICF | |
| 11 | # RUN: llvm-readobj --symbols %t2.out | FileCheck %s --check-prefix=NOICF | |
| 12 | 12 | |
| 13 | 13 | .section .text.D,"ax",@progbits |
| 14 | 14 | .globl D |
deps/lld/test/ELF/cgprofile-print.s created+37| ... | ... | @@ -0,0 +1,37 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t | |
| 4 | # RUN: echo "A B 5" > %t.call_graph | |
| 5 | # RUN: echo "B C 50" >> %t.call_graph | |
| 6 | # RUN: echo "C D 40" >> %t.call_graph | |
| 7 | # RUN: echo "D B 10" >> %t.call_graph | |
| 8 | # RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2 --print-symbol-order=%t3 | |
| 9 | # RUN: FileCheck %s --input-file %t3 | |
| 10 | ||
| 11 | # CHECK: B | |
| 12 | # CHECK-NEXT: C | |
| 13 | # CHECK-NEXT: D | |
| 14 | # CHECK-NEXT: A | |
| 15 | ||
| 16 | .section .text.A,"ax",@progbits | |
| 17 | .globl A | |
| 18 | A: | |
| 19 | nop | |
| 20 | ||
| 21 | .section .text.B,"ax",@progbits | |
| 22 | .globl B | |
| 23 | B: | |
| 24 | nop | |
| 25 | ||
| 26 | .section .text.C,"ax",@progbits | |
| 27 | .globl C | |
| 28 | C: | |
| 29 | nop | |
| 30 | ||
| 31 | .section .text.D,"ax",@progbits | |
| 32 | .globl D | |
| 33 | D: | |
| 34 | nop | |
| 35 | ||
| 36 | ||
| 37 |
deps/lld/test/ELF/cgprofile-reproduce.s created+42| ... | ... | @@ -0,0 +1,42 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t | |
| 4 | # RUN: echo "A B 5" > %t.call_graph | |
| 5 | # RUN: echo "B C 50" >> %t.call_graph | |
| 6 | # RUN: echo "C D 40" >> %t.call_graph | |
| 7 | # RUN: echo "D B 10" >> %t.call_graph | |
| 8 | # RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2 --print-symbol-order=%t3 | |
| 9 | # RUN: ld.lld -e A %t --symbol-ordering-file %t3 -o %t2 | |
| 10 | # RUN: llvm-readobj --symbols %t2 | FileCheck %s | |
| 11 | ||
| 12 | # CHECK: Name: A | |
| 13 | # CHECK-NEXT: Value: 0x201003 | |
| 14 | # CHECK: Name: B | |
| 15 | # CHECK-NEXT: Value: 0x201000 | |
| 16 | # CHECK: Name: C | |
| 17 | # CHECK-NEXT: Value: 0x201001 | |
| 18 | # CHECK: Name: D | |
| 19 | # CHECK-NEXT: Value: 0x201002 | |
| 20 | ||
| 21 | .section .text.A,"ax",@progbits | |
| 22 | .globl A | |
| 23 | A: | |
| 24 | nop | |
| 25 | ||
| 26 | .section .text.B,"ax",@progbits | |
| 27 | .globl B | |
| 28 | B: | |
| 29 | nop | |
| 30 | ||
| 31 | .section .text.C,"ax",@progbits | |
| 32 | .globl C | |
| 33 | C: | |
| 34 | nop | |
| 35 | ||
| 36 | .section .text.D,"ax",@progbits | |
| 37 | .globl D | |
| 38 | D: | |
| 39 | nop | |
| 40 | ||
| 41 | ||
| 42 |
deps/lld/test/ELF/cgprofile-txt.s+2-2| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 4 | 4 | # RUN: ld.lld -e A %t -o %t2 |
| 5 | # RUN: llvm-readobj -symbols %t2 | FileCheck %s --check-prefix=NOSORT | |
| 5 | # RUN: llvm-readobj --symbols %t2 | FileCheck %s --check-prefix=NOSORT | |
| 6 | 6 | |
| 7 | 7 | # RUN: echo "A B 10" > %t.call_graph |
| 8 | 8 | # RUN: echo "A B 10" >> %t.call_graph |
| ... | ... | @@ -25,7 +25,7 @@ |
| 25 | 25 | # RUN: echo "TooManyPreds9 TooManyPreds 10" >> %t.call_graph |
| 26 | 26 | # RUN: echo "TooManyPreds10 TooManyPreds 11" >> %t.call_graph |
| 27 | 27 | # RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2 |
| 28 | # RUN: llvm-readobj -symbols %t2 | FileCheck %s | |
| 28 | # RUN: llvm-readobj --symbols %t2 | FileCheck %s | |
| 29 | 29 | |
| 30 | 30 | .section .text.D,"ax",@progbits |
| 31 | 31 | D: |
deps/lld/test/ELF/cgprofile-txt2.s+1-1| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | # RUN: echo "C D 40" >> %t.call_graph |
| 7 | 7 | # RUN: echo "D B 10" >> %t.call_graph |
| 8 | 8 | # RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2 |
| 9 | # RUN: llvm-readobj -symbols %t2 | FileCheck %s | |
| 9 | # RUN: llvm-readobj --symbols %t2 | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | # CHECK: Name: A |
| 12 | 12 | # CHECK-NEXT: Value: 0x201003 |
deps/lld/test/ELF/color-diagnostics.test+1-1| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | # RUN: not ld.lld -xyz -color-diagnostics=always /nosuchfile 2>&1 \ |
| 7 | 7 | # RUN: | FileCheck -check-prefix=COLOR %s |
| 8 | 8 | |
| 9 | # COLOR: {{ld.lld: .\[0;1;31merror: .\[0munknown argument: -xyz}} | |
| 9 | # COLOR: {{ld.lld: .\[0;1;31merror: .\[0munknown argument '-xyz'}} | |
| 10 | 10 | # COLOR: {{ld.lld: .\[0;1;31merror: .\[0mcannot open /nosuchfile}} |
| 11 | 11 | |
| 12 | 12 | # RUN: not ld.lld -color-diagnostics=foobar 2>&1 | FileCheck -check-prefix=ERR %s |
deps/lld/test/ELF/combreloc.s created+48| ... | ... | @@ -0,0 +1,48 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 4 | # RUN: echo 'mov aaa@gotpcrel(%rip), %rax' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o | |
| 5 | ||
| 6 | # RUN: ld.lld -shared %t.o %t1.o -o %t.so | |
| 7 | # RUN: llvm-readobj -r --dynamic-table %t.so | FileCheck %s | |
| 8 | # RUN: ld.lld -shared %t.o %t1.o -o %t.so -z combreloc | |
| 9 | # RUN: llvm-readobj -r --dynamic-table %t.so | FileCheck %s | |
| 10 | ||
| 11 | # -z combreloc is the default: sort relocations by (!IsRelative,SymIndex,r_offset), | |
| 12 | # and emit DT_RELACOUNT (except on MIPS) to indicate the number of relative | |
| 13 | # relocations. | |
| 14 | ||
| 15 | # CHECK: Relocations [ | |
| 16 | # CHECK-NEXT: Section ({{.*}}) .rela.dyn { | |
| 17 | # CHECK-NEXT: 0x3020 R_X86_64_RELATIVE - 0x3028 | |
| 18 | # CHECK-NEXT: 0x20B0 R_X86_64_GLOB_DAT aaa 0x0 | |
| 19 | # CHECK-NEXT: 0x3000 R_X86_64_64 aaa 0x0 | |
| 20 | # CHECK-NEXT: 0x3018 R_X86_64_64 aaa 0x0 | |
| 21 | # CHECK-NEXT: 0x3010 R_X86_64_64 bbb 0x0 | |
| 22 | # CHECK-NEXT: 0x3008 R_X86_64_64 ccc 0x0 | |
| 23 | # CHECK-NEXT: } | |
| 24 | # CHECK: DynamicSection [ | |
| 25 | # CHECK: RELACOUNT 1 | |
| 26 | ||
| 27 | # RUN: ld.lld -z nocombreloc -shared %t.o %t1.o -o %t.so | |
| 28 | # RUN: llvm-readobj -r --dynamic-table %t.so | FileCheck --check-prefix=NOCOMB %s | |
| 29 | ||
| 30 | # NOCOMB: Relocations [ | |
| 31 | # NOCOMB-NEXT: Section ({{.*}}) .rela.dyn { | |
| 32 | # NOCOMB-NEXT: 0x3000 R_X86_64_64 aaa 0x0 | |
| 33 | # NOCOMB-NEXT: 0x3008 R_X86_64_64 ccc 0x0 | |
| 34 | # NOCOMB-NEXT: 0x3010 R_X86_64_64 bbb 0x0 | |
| 35 | # NOCOMB-NEXT: 0x3018 R_X86_64_64 aaa 0x0 | |
| 36 | # NOCOMB-NEXT: 0x3020 R_X86_64_RELATIVE - 0x3028 | |
| 37 | # NOCOMB-NEXT: 0x20A0 R_X86_64_GLOB_DAT aaa 0x0 | |
| 38 | # NOCOMB-NEXT: } | |
| 39 | # NOCOMB: DynamicSection [ | |
| 40 | # NOCOMB-NOT: RELACOUNT | |
| 41 | ||
| 42 | .data | |
| 43 | .quad aaa | |
| 44 | .quad ccc | |
| 45 | .quad bbb | |
| 46 | .quad aaa | |
| 47 | .quad relative | |
| 48 | relative: |
deps/lld/test/ELF/combrelocs.s deleted-95| ... | ... | @@ -1,95 +0,0 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 4 | # RUN: ld.lld -shared %t.o -o %t.out | |
| 5 | # RUN: llvm-readobj -r --expand-relocs --dynamic-table %t.out | FileCheck %s | |
| 6 | ||
| 7 | # RUN: ld.lld -shared %t.o -o %t.out -z combreloc | |
| 8 | # RUN: llvm-readobj -r --expand-relocs --dynamic-table %t.out | FileCheck %s | |
| 9 | ||
| 10 | # CHECK: Relocations [ | |
| 11 | # CHECK-NEXT: Section ({{.*}}) .rela.dyn { | |
| 12 | # CHECK-NEXT: Relocation { | |
| 13 | # CHECK-NEXT: Offset: 0x1000 | |
| 14 | # CHECK-NEXT: Type: R_X86_64_64 | |
| 15 | # CHECK-NEXT: Symbol: aaa (1) | |
| 16 | # CHECK-NEXT: Addend: 0x0 | |
| 17 | # CHECK-NEXT: } | |
| 18 | # CHECK-NEXT: Relocation { | |
| 19 | # CHECK-NEXT: Offset: 0x1018 | |
| 20 | # CHECK-NEXT: Type: R_X86_64_64 | |
| 21 | # CHECK-NEXT: Symbol: aaa (1) | |
| 22 | # CHECK-NEXT: Addend: 0x0 | |
| 23 | # CHECK-NEXT: } | |
| 24 | # CHECK-NEXT: Relocation { | |
| 25 | # CHECK-NEXT: Offset: 0x1010 | |
| 26 | # CHECK-NEXT: Type: R_X86_64_64 | |
| 27 | # CHECK-NEXT: Symbol: bbb (2) | |
| 28 | # CHECK-NEXT: Addend: 0x0 | |
| 29 | # CHECK-NEXT: } | |
| 30 | # CHECK-NEXT: Relocation { | |
| 31 | # CHECK-NEXT: Offset: 0x1008 | |
| 32 | # CHECK-NEXT: Type: R_X86_64_64 | |
| 33 | # CHECK-NEXT: Symbol: ccc (3) | |
| 34 | # CHECK-NEXT: Addend: 0x0 | |
| 35 | # CHECK-NEXT: } | |
| 36 | # CHECK-NEXT: Relocation { | |
| 37 | # CHECK-NEXT: Offset: 0x1020 | |
| 38 | # CHECK-NEXT: Type: R_X86_64_64 | |
| 39 | # CHECK-NEXT: Symbol: ddd (4) | |
| 40 | # CHECK-NEXT: Addend: 0x0 | |
| 41 | # CHECK-NEXT: } | |
| 42 | # CHECK-NEXT: } | |
| 43 | # CHECK-NEXT: ] | |
| 44 | # CHECK: DynamicSection [ | |
| 45 | # CHECK-NEXT: Tag | |
| 46 | # CHECK-NOT: RELACOUNT | |
| 47 | ||
| 48 | # RUN: ld.lld -z nocombreloc -shared %t.o -o %t.out | |
| 49 | # RUN: llvm-readobj -r --expand-relocs --dynamic-table %t.out | \ | |
| 50 | # RUN: FileCheck --check-prefix=NOCOMB %s | |
| 51 | ||
| 52 | # NOCOMB: Relocations [ | |
| 53 | # NOCOMB-NEXT: Section ({{.*}}) .rela.dyn { | |
| 54 | # NOCOMB-NEXT: Relocation { | |
| 55 | # NOCOMB-NEXT: Offset: 0x1000 | |
| 56 | # NOCOMB-NEXT: Type: R_X86_64_64 | |
| 57 | # NOCOMB-NEXT: Symbol: aaa (1) | |
| 58 | # NOCOMB-NEXT: Addend: 0x0 | |
| 59 | # NOCOMB-NEXT: } | |
| 60 | # NOCOMB-NEXT: Relocation { | |
| 61 | # NOCOMB-NEXT: Offset: 0x1008 | |
| 62 | # NOCOMB-NEXT: Type: R_X86_64_64 | |
| 63 | # NOCOMB-NEXT: Symbol: ccc (3) | |
| 64 | # NOCOMB-NEXT: Addend: 0x0 | |
| 65 | # NOCOMB-NEXT: } | |
| 66 | # NOCOMB-NEXT: Relocation { | |
| 67 | # NOCOMB-NEXT: Offset: 0x1010 | |
| 68 | # NOCOMB-NEXT: Type: R_X86_64_64 | |
| 69 | # NOCOMB-NEXT: Symbol: bbb (2) | |
| 70 | # NOCOMB-NEXT: Addend: 0x0 | |
| 71 | # NOCOMB-NEXT: } | |
| 72 | # NOCOMB-NEXT: Relocation { | |
| 73 | # NOCOMB-NEXT: Offset: 0x1018 | |
| 74 | # NOCOMB-NEXT: Type: R_X86_64_64 | |
| 75 | # NOCOMB-NEXT: Symbol: aaa (1) | |
| 76 | # NOCOMB-NEXT: Addend: 0x0 | |
| 77 | # NOCOMB-NEXT: } | |
| 78 | # NOCOMB-NEXT: Relocation { | |
| 79 | # NOCOMB-NEXT: Offset: 0x1020 | |
| 80 | # NOCOMB-NEXT: Type: R_X86_64_64 | |
| 81 | # NOCOMB-NEXT: Symbol: ddd (4) | |
| 82 | # NOCOMB-NEXT: Addend: 0x0 | |
| 83 | # NOCOMB-NEXT: } | |
| 84 | # NOCOMB-NEXT: } | |
| 85 | # NOCOMB-NEXT: ] | |
| 86 | # NOCOMB: DynamicSection [ | |
| 87 | # NOCOMB-NEXT: Tag | |
| 88 | # NOCOMB-NOT: RELACOUNT | |
| 89 | ||
| 90 | .data | |
| 91 | .quad aaa | |
| 92 | .quad ccc | |
| 93 | .quad bbb | |
| 94 | .quad aaa | |
| 95 | .quad ddd |
deps/lld/test/ELF/comdat-discarded-error.s created+28| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o | |
| 3 | # RUN: echo '.section .text.foo,"axG",@progbits,foo,comdat; .globl foo; foo:' |\ | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64 - -o %t2.o | |
| 5 | # RUN: echo '.section .text.foo,"axG",@progbits,foo,comdat; .globl bar; bar:' |\ | |
| 6 | # RUN: llvm-mc -filetype=obj -triple=x86_64 - -o %t3.o | |
| 7 | ||
| 8 | # RUN: not ld.lld %t2.o %t3.o %t1.o -o /dev/null 2>&1 | FileCheck %s | |
| 9 | ||
| 10 | # CHECK: error: relocation refers to a symbol in a discarded section: bar | |
| 11 | # CHECK-NEXT: >>> defined in {{.*}}3.o | |
| 12 | # CHECK-NEXT: >>> section group signature: foo | |
| 13 | # CHECK-NEXT: >>> prevailing definition is in {{.*}}2.o | |
| 14 | # CHECK-NEXT: >>> referenced by {{.*}}1.o:(.text+0x1) | |
| 15 | ||
| 16 | # CHECK: error: relocation refers to a discarded section: .text.foo | |
| 17 | # CHECK-NEXT: >>> defined in {{.*}}1.o | |
| 18 | # CHECK-NEXT: >>> section group signature: foo | |
| 19 | # CHECK-NEXT: >>> prevailing definition is in {{.*}}2.o | |
| 20 | # CHECK-NEXT: >>> referenced by {{.*}}1.o:(.data+0x0) | |
| 21 | ||
| 22 | .globl _start | |
| 23 | _start: | |
| 24 | jmp bar | |
| 25 | ||
| 26 | .section .text.foo,"axG",@progbits,foo,comdat | |
| 27 | .data | |
| 28 | .quad .text.foo |
deps/lld/test/ELF/comdat-discarded-gdb-index.s created+63| ... | ... | @@ -0,0 +1,63 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | # RUN: ld.lld --gdb-index %t.o %t.o -o %t | |
| 4 | ||
| 5 | ## .debug_info has a relocation to .text.foo . The second %t.o is discarded. | |
| 6 | ## Check we don't error on the relocation. | |
| 7 | # CHECK: .rela.debug_info { | |
| 8 | # CHECK-NEXT: 0xC R_X86_64_64 .text.foo 0x0 | |
| 9 | ||
| 10 | .section .text.foo,"axG",@progbits,foo,comdat | |
| 11 | .globl foo | |
| 12 | .Lfunc_begin0: | |
| 13 | foo: | |
| 14 | ret | |
| 15 | .Lfunc_end0: | |
| 16 | ||
| 17 | .section .debug_abbrev,"",@progbits | |
| 18 | .byte 1 # Abbreviation Code | |
| 19 | .byte 17 # DW_TAG_compile_unit | |
| 20 | .byte 1 # DW_CHILDREN_yes | |
| 21 | .byte 17 # DW_AT_low_pc | |
| 22 | .byte 1 # DW_FORM_addr | |
| 23 | .byte 18 # DW_AT_high_pc | |
| 24 | .byte 6 # DW_FORM_data4 | |
| 25 | .ascii "\264B" # DW_AT_GNU_pubnames | |
| 26 | .byte 25 # DW_FORM_flag_present | |
| 27 | .byte 0 # EOM(1) | |
| 28 | .byte 0 # EOM(2) | |
| 29 | .byte 2 # Abbreviation Code | |
| 30 | .byte 46 # DW_TAG_subprogram | |
| 31 | .byte 0 # DW_CHILDREN_no | |
| 32 | .byte 3 # DW_AT_name | |
| 33 | .byte 8 # DW_FORM_string | |
| 34 | .byte 0 # EOM(1) | |
| 35 | .byte 0 # EOM(2) | |
| 36 | .byte 0 | |
| 37 | ||
| 38 | .section .debug_info,"",@progbits | |
| 39 | .Lcu_begin0: | |
| 40 | .long .Lcu_end0 - .Lcu_begin0 - 4 | |
| 41 | .short 4 # DWARF version number | |
| 42 | .long 0 # Offset Into Abbrev. Section | |
| 43 | .byte 4 # Address Size | |
| 44 | .Ldie0: | |
| 45 | .byte 1 # Abbrev [1] DW_TAG_compile_unit | |
| 46 | .quad .Lfunc_begin0 # DW_AT_low_pc | |
| 47 | .long .Lfunc_end0 - .Lfunc_begin0 # DW_AT_high_pc | |
| 48 | .byte 2 # Abbrev [2] DW_TAG_subprogram | |
| 49 | .asciz "foo" # DW_AT_name | |
| 50 | .byte 0 | |
| 51 | .Lcu_end0: | |
| 52 | ||
| 53 | .section .debug_gnu_pubnames,"",@progbits | |
| 54 | .long .LpubNames_end0 - .LpubNames_begin0 | |
| 55 | .LpubNames_begin0: | |
| 56 | .short 2 # Version | |
| 57 | .long .Lcu_begin0 # CU Offset | |
| 58 | .long .Lcu_end0 - .Lcu_begin0 | |
| 59 | .long .Ldie0 - .Lcu_begin0 | |
| 60 | .byte 48 # Attributes: FUNCTION, EXTERNAL | |
| 61 | .asciz "foo" # External Name | |
| 62 | .long 0 | |
| 63 | .LpubNames_end0: |
deps/lld/test/ELF/comdat-discarded-ppc64.s created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o %t.o -o /dev/null | |
| 4 | # RUN: ld.lld -r --fatal-warnings %t.o %t.o -o /dev/null | |
| 5 | ||
| 6 | ## clang/gcc PPC64 may emit a .rela.toc which references a switch table in a | |
| 7 | ## discarded .rodata/.text section. The .toc and the .rela.toc are incorrectly | |
| 8 | ## not placed in the comdat. | |
| 9 | ## Don't error "relocation refers to a discarded section". | |
| 10 | ||
| 11 | .section .text.foo,"axG",@progbits,foo,comdat | |
| 12 | .globl foo | |
| 13 | foo: | |
| 14 | .L0: | |
| 15 | ||
| 16 | .section .toc,"aw" | |
| 17 | .quad .L0 |
deps/lld/test/ELF/comdat-discarded-reloc.s+32-7| ... | ... | @@ -1,17 +1,42 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/comdat-discarded-reloc.s -o %t2.o |
| 4 | # RUN: ld.lld -gc-sections %t.o %t2.o -o %t | |
| 4 | # RUN: ld.lld -gc-sections --noinhibit-exec %t2.o %t.o -o /dev/null | |
| 5 | # RUN: ld.lld -r %t2.o %t.o -o %t 2>&1 | FileCheck --check-prefix=WARN %s | |
| 6 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s | |
| 5 | 7 | |
| 6 | 8 | ## ELF spec doesn't allow a relocation to point to a deduplicated |
| 7 | 9 | ## COMDAT section. Unfortunately this happens in practice (e.g. .eh_frame) |
| 8 | 10 | ## Test case checks we do not crash. |
| 9 | 11 | |
| 10 | .global bar, _start | |
| 12 | # WARN: warning: relocation refers to a discarded section: .text.bar1 | |
| 13 | # WARN-NEXT: >>> referenced by {{.*}}.o:(.rela.text.bar2+0x0) | |
| 14 | # WARN-NOT: warning | |
| 11 | 15 | |
| 12 | .section .text.foo,"aG",@progbits,group,comdat | |
| 16 | # RELOC: .rela.eh_frame { | |
| 17 | # RELOC-NEXT: R_X86_64_NONE | |
| 18 | # RELOC-NEXT: } | |
| 19 | # RELOC-NEXT: .rela.debug_foo { | |
| 20 | # RELOC-NEXT: R_X86_64_NONE | |
| 21 | # RELOC-NEXT: } | |
| 22 | # RELOC-NEXT: .rela.gcc_except_table { | |
| 23 | # RELOC-NEXT: R_X86_64_NONE | |
| 24 | # RELOC-NEXT: } | |
| 13 | 25 | |
| 14 | .section .text | |
| 15 | _start: | |
| 16 | .quad .text.foo | |
| 17 | .quad bar | |
| 26 | .section .text.bar1,"aG",@progbits,group,comdat | |
| 27 | ||
| 28 | ## .text.bar1 in this file is discarded. Warn on the relocation. | |
| 29 | .section .text.bar2,"ax" | |
| 30 | .globl bar | |
| 31 | bar: | |
| 32 | .quad .text.bar1 | |
| 33 | ||
| 34 | ## Don't warn on .eh_frame, .debug*, .zdebug*, or .gcc_except_table | |
| 35 | .section .eh_frame,"a" | |
| 36 | .quad .text.bar1 | |
| 37 | ||
| 38 | .section .debug_foo | |
| 39 | .quad .text.bar1 | |
| 40 | ||
| 41 | .section .gcc_except_table,"a" | |
| 42 | .quad .text.bar1 |
deps/lld/test/ELF/comdat.s+4-4| ... | ... | @@ -1,9 +1,9 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/comdat.s -o %t2.o |
| 4 | // RUN: ld.lld -shared %t.o %t.o %t2.o -o %t | |
| 4 | // RUN: ld.lld -shared %t.o %t2.o -o %t | |
| 5 | 5 | // RUN: llvm-objdump -d %t | FileCheck %s |
| 6 | // RUN: llvm-readobj -s -t %t | FileCheck --check-prefix=READ %s | |
| 6 | // RUN: llvm-readobj -S --symbols %t | FileCheck --check-prefix=READ %s | |
| 7 | 7 | |
| 8 | 8 | // Check that we don't crash with --gc-section and that we print a list of |
| 9 | 9 | // reclaimed sections on stderr. |
| ... | ... | @@ -19,6 +19,7 @@ foo: |
| 19 | 19 | nop |
| 20 | 20 | |
| 21 | 21 | // CHECK: Disassembly of section .text2: |
| 22 | // CHECK-EMPTY: | |
| 22 | 23 | // CHECK-NEXT: foo: |
| 23 | 24 | // CHECK-NEXT: 1000: {{.*}} nop |
| 24 | 25 | // CHECK-NOT: nop |
| ... | ... | @@ -27,11 +28,10 @@ foo: |
| 27 | 28 | call foo |
| 28 | 29 | |
| 29 | 30 | // CHECK: Disassembly of section bar: |
| 31 | // CHECK-EMPTY: | |
| 30 | 32 | // CHECK-NEXT: bar: |
| 31 | 33 | // 0x1000 - 0x1001 - 5 = -6 |
| 32 | // 0 - 0x1006 - 5 = -4107 | |
| 33 | 34 | // CHECK-NEXT: 1001:	{{.*}} callq -6 |
| 34 | // CHECK-NEXT: 1006:	{{.*}} callq -4107 | |
| 35 | 35 | |
| 36 | 36 | .section .text3,"axG",@progbits,zed,comdat,unique,0 |
| 37 | 37 |
deps/lld/test/ELF/common-gc.s+2-2| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t |
| 3 | 3 | |
| 4 | 4 | # RUN: ld.lld %t -o %t2 |
| 5 | # RUN: llvm-readobj -sections -symbols %t2 | FileCheck %s --check-prefix=NOGC | |
| 5 | # RUN: llvm-readobj --sections --symbols %t2 | FileCheck %s --check-prefix=NOGC | |
| 6 | 6 | |
| 7 | 7 | # NOGC: Name: .bss |
| 8 | 8 | # NOGC-NEXT: Type: |
| ... | ... | @@ -18,7 +18,7 @@ |
| 18 | 18 | # NOGC: Name: foo |
| 19 | 19 | |
| 20 | 20 | # RUN: ld.lld -gc-sections %t -o %t1 |
| 21 | # RUN: llvm-readobj -sections -symbols %t1 | FileCheck %s --check-prefix=GC | |
| 21 | # RUN: llvm-readobj --sections --symbols %t1 | FileCheck %s --check-prefix=GC | |
| 22 | 22 | |
| 23 | 23 | # GC: Name: .bss |
| 24 | 24 | # GC-NEXT: Type: |
deps/lld/test/ELF/common-page.s created+223| ... | ... | @@ -0,0 +1,223 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t | |
| 4 | ||
| 5 | # exits with return code 42 on linux | |
| 6 | .globl _start | |
| 7 | _start: | |
| 8 | nop | |
| 9 | ||
| 10 | # Increase max-page-size to 64k while using the default x86_64 common page size | |
| 11 | # of 4k. If the last loadable segment is executable then lld aligns the next | |
| 12 | # section using the common page size. | |
| 13 | ||
| 14 | # RUN: ld.lld -z max-page-size=0x10000 -z common-page-size=0x1000 %t -o %t2 | |
| 15 | # RUN: llvm-readobj --sections -l %t2 | FileCheck --check-prefix=CHECK-MAX %s | |
| 16 | ||
| 17 | # CHECK-MAX: Sections [ | |
| 18 | # CHECK-MAX-NEXT: Section { | |
| 19 | # CHECK-MAX-NEXT: Index: 0 | |
| 20 | # CHECK-MAX-NEXT: Name: (0) | |
| 21 | # CHECK-MAX-NEXT: Type: SHT_NULL (0x0) | |
| 22 | # CHECK-MAX-NEXT: Flags [ (0x0) | |
| 23 | # CHECK-MAX-NEXT: ] | |
| 24 | # CHECK-MAX-NEXT: Address: 0x0 | |
| 25 | # CHECK-MAX-NEXT: Offset: 0x0 | |
| 26 | # CHECK-MAX-NEXT: Size: 0 | |
| 27 | # CHECK-MAX-NEXT: Link: 0 | |
| 28 | # CHECK-MAX-NEXT: Info: 0 | |
| 29 | # CHECK-MAX-NEXT: AddressAlignment: 0 | |
| 30 | # CHECK-MAX-NEXT: EntrySize: 0 | |
| 31 | # CHECK-MAX-NEXT: } | |
| 32 | # CHECK-MAX-NEXT: Section { | |
| 33 | # CHECK-MAX-NEXT: Index: 1 | |
| 34 | # CHECK-MAX-NEXT: Name: .text (1) | |
| 35 | # CHECK-MAX-NEXT: Type: SHT_PROGBITS (0x1) | |
| 36 | # CHECK-MAX-NEXT: Flags [ (0x6) | |
| 37 | # CHECK-MAX-NEXT: SHF_ALLOC (0x2) | |
| 38 | # CHECK-MAX-NEXT: SHF_EXECINSTR (0x4) | |
| 39 | # CHECK-MAX-NEXT: ] | |
| 40 | # CHECK-MAX-NEXT: Address: 0x210000 | |
| 41 | # CHECK-MAX-NEXT: Offset: 0x10000 | |
| 42 | # CHECK-MAX-NEXT: Size: 1 | |
| 43 | # CHECK-MAX-NEXT: Link: 0 | |
| 44 | # CHECK-MAX-NEXT: Info: 0 | |
| 45 | # CHECK-MAX-NEXT: AddressAlignment: 4 | |
| 46 | # CHECK-MAX-NEXT: EntrySize: 0 | |
| 47 | # CHECK-MAX-NEXT: } | |
| 48 | # CHECK-MAX-NEXT: Section { | |
| 49 | # CHECK-MAX-NEXT: Index: 2 | |
| 50 | # CHECK-MAX-NEXT: Name: .comment (7) | |
| 51 | # CHECK-MAX-NEXT: Type: SHT_PROGBITS (0x1) | |
| 52 | # CHECK-MAX-NEXT: Flags [ (0x30) | |
| 53 | # CHECK-MAX-NEXT: SHF_MERGE (0x10) | |
| 54 | # CHECK-MAX-NEXT: SHF_STRINGS (0x20) | |
| 55 | # CHECK-MAX-NEXT: ] | |
| 56 | # CHECK-MAX-NEXT: Address: 0x0 | |
| 57 | # CHECK-MAX-NEXT: Offset: 0x11000 | |
| 58 | # CHECK-MAX-NEXT: Size: 8 | |
| 59 | # CHECK-MAX-NEXT: Link: 0 | |
| 60 | # CHECK-MAX-NEXT: Info: 0 | |
| 61 | # CHECK-MAX-NEXT: AddressAlignment: 1 | |
| 62 | # CHECK-MAX-NEXT: EntrySize: 1 | |
| 63 | ||
| 64 | # CHECK-MAX: ProgramHeaders [ | |
| 65 | # CHECK-MAX-NEXT: ProgramHeader { | |
| 66 | # CHECK-MAX-NEXT: Type: PT_PHDR (0x6) | |
| 67 | # CHECK-MAX-NEXT: Offset: 0x40 | |
| 68 | # CHECK-MAX-NEXT: VirtualAddress: 0x200040 | |
| 69 | # CHECK-MAX-NEXT: PhysicalAddress: 0x200040 | |
| 70 | # CHECK-MAX-NEXT: FileSize: 224 | |
| 71 | # CHECK-MAX-NEXT: MemSize: 224 | |
| 72 | # CHECK-MAX-NEXT: Flags [ (0x4) | |
| 73 | # CHECK-MAX-NEXT: PF_R (0x4) | |
| 74 | # CHECK-MAX-NEXT: ] | |
| 75 | # CHECK-MAX-NEXT: Alignment: 8 | |
| 76 | # CHECK-MAX-NEXT: } | |
| 77 | # CHECK-MAX-NEXT: ProgramHeader { | |
| 78 | # CHECK-MAX-NEXT: Type: PT_LOAD (0x1) | |
| 79 | # CHECK-MAX-NEXT: Offset: 0x0 | |
| 80 | # CHECK-MAX-NEXT: VirtualAddress: 0x200000 | |
| 81 | # CHECK-MAX-NEXT: PhysicalAddress: 0x200000 | |
| 82 | # CHECK-MAX-NEXT: FileSize: 288 | |
| 83 | # CHECK-MAX-NEXT: MemSize: 288 | |
| 84 | # CHECK-MAX-NEXT: Flags [ (0x4) | |
| 85 | # CHECK-MAX-NEXT: PF_R (0x4) | |
| 86 | # CHECK-MAX-NEXT: ] | |
| 87 | # CHECK-MAX-NEXT: Alignment: 65536 | |
| 88 | # CHECK-MAX-NEXT: } | |
| 89 | # CHECK-MAX-NEXT: ProgramHeader { | |
| 90 | # CHECK-MAX-NEXT: Type: PT_LOAD (0x1) | |
| 91 | # CHECK-MAX-NEXT: Offset: 0x10000 | |
| 92 | # CHECK-MAX-NEXT: VirtualAddress: 0x210000 | |
| 93 | # CHECK-MAX-NEXT: PhysicalAddress: 0x210000 | |
| 94 | # CHECK-MAX-NEXT: FileSize: 4096 | |
| 95 | # CHECK-MAX-NEXT: MemSize: 4096 | |
| 96 | # CHECK-MAX-NEXT: Flags [ (0x5) | |
| 97 | # CHECK-MAX-NEXT: PF_R (0x4) | |
| 98 | # CHECK-MAX-NEXT: PF_X (0x1) | |
| 99 | # CHECK-MAX-NEXT: ] | |
| 100 | # CHECK-MAX-NEXT: Alignment: 65536 | |
| 101 | # CHECK-MAX-NEXT: } | |
| 102 | # CHECK-MAX-NEXT: ProgramHeader { | |
| 103 | # CHECK-MAX-NEXT: Type: PT_GNU_STACK (0x6474E551) | |
| 104 | # CHECK-MAX-NEXT: Offset: 0x0 | |
| 105 | # CHECK-MAX-NEXT: VirtualAddress: 0x0 | |
| 106 | # CHECK-MAX-NEXT: PhysicalAddress: 0x0 | |
| 107 | # CHECK-MAX-NEXT: FileSize: 0 | |
| 108 | # CHECK-MAX-NEXT: MemSize: 0 | |
| 109 | # CHECK-MAX-NEXT: Flags [ (0x6) | |
| 110 | # CHECK-MAX-NEXT: PF_R (0x4) | |
| 111 | # CHECK-MAX-NEXT: PF_W (0x2) | |
| 112 | # CHECK-MAX-NEXT: ] | |
| 113 | # CHECK-MAX-NEXT: Alignment: 0 | |
| 114 | ||
| 115 | # Increase common-page-size to max-page-size. Expect to see a larger offset | |
| 116 | # of the first Section after the executable loadable segment due to the higher | |
| 117 | # alignment requirement. | |
| 118 | ||
| 119 | # RUN: ld.lld -z max-page-size=0x10000 -z common-page-size=0x10000 %t -o %t3 | |
| 120 | # RUN: llvm-readobj --sections -l %t3 | FileCheck --check-prefix=CHECK-COMMON %s | |
| 121 | ||
| 122 | # Check that we truncate common-page-size to max-page-size | |
| 123 | ||
| 124 | # RUN: ld.lld -z max-page-size=0x10000 -z common-page-size=0x100000 %t -o %t4 | |
| 125 | # RUN: llvm-readobj --sections -l %t4 | FileCheck --check-prefix=CHECK-COMMON %s | |
| 126 | ||
| 127 | # CHECK-COMMON: Sections [ | |
| 128 | # CHECK-COMMON-NEXT: Section { | |
| 129 | # CHECK-COMMON-NEXT: Index: 0 | |
| 130 | # CHECK-COMMON-NEXT: Name: (0) | |
| 131 | # CHECK-COMMON-NEXT: Type: SHT_NULL (0x0) | |
| 132 | # CHECK-COMMON-NEXT: Flags [ (0x0) | |
| 133 | # CHECK-COMMON-NEXT: ] | |
| 134 | # CHECK-COMMON-NEXT: Address: 0x0 | |
| 135 | # CHECK-COMMON-NEXT: Offset: 0x0 | |
| 136 | # CHECK-COMMON-NEXT: Size: 0 | |
| 137 | # CHECK-COMMON-NEXT: Link: 0 | |
| 138 | # CHECK-COMMON-NEXT: Info: 0 | |
| 139 | # CHECK-COMMON-NEXT: AddressAlignment: 0 | |
| 140 | # CHECK-COMMON-NEXT: EntrySize: 0 | |
| 141 | # CHECK-COMMON-NEXT: } | |
| 142 | # CHECK-COMMON-NEXT: Section { | |
| 143 | # CHECK-COMMON-NEXT: Index: 1 | |
| 144 | # CHECK-COMMON-NEXT: Name: .text (1) | |
| 145 | # CHECK-COMMON-NEXT: Type: SHT_PROGBITS (0x1) | |
| 146 | # CHECK-COMMON-NEXT: Flags [ (0x6) | |
| 147 | # CHECK-COMMON-NEXT: SHF_ALLOC (0x2) | |
| 148 | # CHECK-COMMON-NEXT: SHF_EXECINSTR (0x4) | |
| 149 | # CHECK-COMMON-NEXT: ] | |
| 150 | # CHECK-COMMON-NEXT: Address: 0x210000 | |
| 151 | # CHECK-COMMON-NEXT: Offset: 0x10000 | |
| 152 | # CHECK-COMMON-NEXT: Size: 1 | |
| 153 | # CHECK-COMMON-NEXT: Link: 0 | |
| 154 | # CHECK-COMMON-NEXT: Info: 0 | |
| 155 | # CHECK-COMMON-NEXT: AddressAlignment: 4 | |
| 156 | # CHECK-COMMON-NEXT: EntrySize: 0 | |
| 157 | # CHECK-COMMON-NEXT: } | |
| 158 | # CHECK-COMMON-NEXT: Section { | |
| 159 | # CHECK-COMMON-NEXT: Index: 2 | |
| 160 | # CHECK-COMMON-NEXT: Name: .comment (7) | |
| 161 | # CHECK-COMMON-NEXT: Type: SHT_PROGBITS (0x1) | |
| 162 | # CHECK-COMMON-NEXT: Flags [ (0x30) | |
| 163 | # CHECK-COMMON-NEXT: SHF_MERGE (0x10) | |
| 164 | # CHECK-COMMON-NEXT: SHF_STRINGS (0x20) | |
| 165 | # CHECK-COMMON-NEXT: ] | |
| 166 | # CHECK-COMMON-NEXT: Address: 0x0 | |
| 167 | # CHECK-COMMON-NEXT: Offset: 0x20000 | |
| 168 | # CHECK-COMMON-NEXT: Size: 8 | |
| 169 | # CHECK-COMMON-NEXT: Link: 0 | |
| 170 | # CHECK-COMMON-NEXT: Info: 0 | |
| 171 | # CHECK-COMMON-NEXT: AddressAlignment: 1 | |
| 172 | # CHECK-COMMON-NEXT: EntrySize: 1 | |
| 173 | ||
| 174 | # CHECK-COMMON: ProgramHeaders [ | |
| 175 | # CHECK-COMMON-NEXT: ProgramHeader { | |
| 176 | # CHECK-COMMON-NEXT: Type: PT_PHDR (0x6) | |
| 177 | # CHECK-COMMON-NEXT: Offset: 0x40 | |
| 178 | # CHECK-COMMON-NEXT: VirtualAddress: 0x200040 | |
| 179 | # CHECK-COMMON-NEXT: PhysicalAddress: 0x200040 | |
| 180 | # CHECK-COMMON-NEXT: FileSize: 224 | |
| 181 | # CHECK-COMMON-NEXT: MemSize: 224 | |
| 182 | # CHECK-COMMON-NEXT: Flags [ (0x4) | |
| 183 | # CHECK-COMMON-NEXT: PF_R (0x4) | |
| 184 | # CHECK-COMMON-NEXT: ] | |
| 185 | # CHECK-COMMON-NEXT: Alignment: 8 | |
| 186 | # CHECK-COMMON-NEXT: } | |
| 187 | # CHECK-COMMON-NEXT: ProgramHeader { | |
| 188 | # CHECK-COMMON-NEXT: Type: PT_LOAD (0x1) | |
| 189 | # CHECK-COMMON-NEXT: Offset: 0x0 | |
| 190 | # CHECK-COMMON-NEXT: VirtualAddress: 0x200000 | |
| 191 | # CHECK-COMMON-NEXT: PhysicalAddress: 0x200000 | |
| 192 | # CHECK-COMMON-NEXT: FileSize: 288 | |
| 193 | # CHECK-COMMON-NEXT: MemSize: 288 | |
| 194 | # CHECK-COMMON-NEXT: Flags [ (0x4) | |
| 195 | # CHECK-COMMON-NEXT: PF_R (0x4) | |
| 196 | # CHECK-COMMON-NEXT: ] | |
| 197 | # CHECK-COMMON-NEXT: Alignment: 65536 | |
| 198 | # CHECK-COMMON-NEXT: } | |
| 199 | # CHECK-COMMON-NEXT: ProgramHeader { | |
| 200 | # CHECK-COMMON-NEXT: Type: PT_LOAD (0x1) | |
| 201 | # CHECK-COMMON-NEXT: Offset: 0x10000 | |
| 202 | # CHECK-COMMON-NEXT: VirtualAddress: 0x210000 | |
| 203 | # CHECK-COMMON-NEXT: PhysicalAddress: 0x210000 | |
| 204 | # CHECK-COMMON-NEXT: FileSize: 65536 | |
| 205 | # CHECK-COMMON-NEXT: MemSize: 65536 | |
| 206 | # CHECK-COMMON-NEXT: Flags [ (0x5) | |
| 207 | # CHECK-COMMON-NEXT: PF_R (0x4) | |
| 208 | # CHECK-COMMON-NEXT: PF_X (0x1) | |
| 209 | # CHECK-COMMON-NEXT: ] | |
| 210 | # CHECK-COMMON-NEXT: Alignment: 65536 | |
| 211 | # CHECK-COMMON-NEXT: } | |
| 212 | # CHECK-COMMON-NEXT: ProgramHeader { | |
| 213 | # CHECK-COMMON-NEXT: Type: PT_GNU_STACK (0x6474E551) | |
| 214 | # CHECK-COMMON-NEXT: Offset: 0x0 | |
| 215 | # CHECK-COMMON-NEXT: VirtualAddress: 0x0 | |
| 216 | # CHECK-COMMON-NEXT: PhysicalAddress: 0x0 | |
| 217 | # CHECK-COMMON-NEXT: FileSize: 0 | |
| 218 | # CHECK-COMMON-NEXT: MemSize: 0 | |
| 219 | # CHECK-COMMON-NEXT: Flags [ (0x6) | |
| 220 | # CHECK-COMMON-NEXT: PF_R (0x4) | |
| 221 | # CHECK-COMMON-NEXT: PF_W (0x2) | |
| 222 | # CHECK-COMMON-NEXT: ] | |
| 223 | # CHECK-COMMON-NEXT: Alignment: 0 |
deps/lld/test/ELF/common.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/common.s -o %t2 |
| 4 | 4 | // RUN: ld.lld %t %t2 -o %t3 |
| 5 | // RUN: llvm-readobj -t -s %t3 | FileCheck %s | |
| 5 | // RUN: llvm-readobj --symbols -S %t3 | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // CHECK: Name: .bss |
| 8 | 8 | // CHECK-NEXT: Type: SHT_NOBITS |
deps/lld/test/ELF/compress-debug-sections.s+2-2| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # ZLIBCONTENT: Contents of section .debug_str: |
| 8 | 8 | # ZLIBCONTENT-NOT: AAAAAAAAA |
| 9 | 9 | |
| 10 | # RUN: llvm-readobj -s %t1 | FileCheck %s --check-prefix=ZLIBFLAGS | |
| 10 | # RUN: llvm-readobj -S %t1 | FileCheck %s --check-prefix=ZLIBFLAGS | |
| 11 | 11 | # ZLIBFLAGS: Section { |
| 12 | 12 | # ZLIBFLAGS: Index: |
| 13 | 13 | # ZLIBFLAGS: Name: .debug_str |
| ... | ... | @@ -24,7 +24,7 @@ |
| 24 | 24 | ## Test alias. |
| 25 | 25 | # RUN: ld.lld %t.o -o %t2 --compress-debug-sections zlib |
| 26 | 26 | # RUN: llvm-objdump -s %t2 | FileCheck %s --check-prefix=ZLIBCONTENT |
| 27 | # RUN: llvm-readobj -s %t2 | FileCheck %s --check-prefix=ZLIBFLAGS | |
| 27 | # RUN: llvm-readobj -S %t2 | FileCheck %s --check-prefix=ZLIBFLAGS | |
| 28 | 28 | |
| 29 | 29 | # RUN: not ld.lld %t.o -o %t1 --compress-debug-sections=zlib-gabi 2>&1 | \ |
| 30 | 30 | # RUN: FileCheck -check-prefix=ERR %s |
deps/lld/test/ELF/compressed-debug-conflict.s+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # REQUIRES: x86, zlib |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple i686-linux-gnu -compress-debug-sections=zlib %s -o %t.o |
| 3 | # RUN: llvm-readobj -sections %t.o | FileCheck -check-prefix=OBJ %s | |
| 3 | # RUN: llvm-readobj --sections %t.o | FileCheck -check-prefix=OBJ %s | |
| 4 | 4 | # RUN: not ld.lld %t.o %t.o -o /dev/null 2>&1 | FileCheck -check-prefix=ERROR %s |
| 5 | 5 | |
| 6 | 6 | # OBJ: Sections [ |
deps/lld/test/ELF/compressed-debug-input.s+5-5| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: zlib, x86 |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -compress-debug-sections=zlib -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 4 | # RUN: llvm-readobj -sections %t | FileCheck -check-prefix=ZLIB %s | |
| 4 | # RUN: llvm-readobj --sections %t | FileCheck -check-prefix=ZLIB %s | |
| 5 | 5 | # ZLIB: Section { |
| 6 | 6 | # ZLIB: Index: 2 |
| 7 | 7 | # ZLIB: Name: .debug_str |
| ... | ... | @@ -16,12 +16,12 @@ |
| 16 | 16 | # ZLIB-NEXT: Size: |
| 17 | 17 | # ZLIB-NEXT: Link: |
| 18 | 18 | # ZLIB-NEXT: Info: |
| 19 | # ZLIB-NEXT: AddressAlignment: 1 | |
| 19 | # ZLIB-NEXT: AddressAlignment: 8 | |
| 20 | 20 | # ZLIB-NEXT: EntrySize: 1 |
| 21 | 21 | # ZLIB-NEXT: } |
| 22 | 22 | |
| 23 | 23 | # RUN: llvm-mc -compress-debug-sections=zlib-gnu -filetype=obj -triple=x86_64-unknown-linux %s -o %t2 |
| 24 | # RUN: llvm-readobj -sections %t2 | FileCheck -check-prefix=GNU %s | |
| 24 | # RUN: llvm-readobj --sections %t2 | FileCheck -check-prefix=GNU %s | |
| 25 | 25 | # GNU: Section { |
| 26 | 26 | # GNU: Index: 2 |
| 27 | 27 | # GNU: Name: .zdebug_str |
| ... | ... | @@ -40,10 +40,10 @@ |
| 40 | 40 | # GNU-NEXT: } |
| 41 | 41 | |
| 42 | 42 | # RUN: ld.lld --hash-style=sysv %t -o %t.so -shared |
| 43 | # RUN: llvm-readobj -sections -section-data %t.so | FileCheck -check-prefix=DATA %s | |
| 43 | # RUN: llvm-readobj --sections --section-data %t.so | FileCheck -check-prefix=DATA %s | |
| 44 | 44 | |
| 45 | 45 | # RUN: ld.lld --hash-style=sysv %t2 -o %t2.so -shared |
| 46 | # RUN: llvm-readobj -sections -section-data %t2.so | FileCheck -check-prefix=DATA %s | |
| 46 | # RUN: llvm-readobj --sections --section-data %t2.so | FileCheck -check-prefix=DATA %s | |
| 47 | 47 | |
| 48 | 48 | # DATA: Section { |
| 49 | 49 | # DATA: Index: 6 |
deps/lld/test/ELF/compressed-input-alignment.test created+67| ... | ... | @@ -0,0 +1,67 @@ |
| 1 | # REQUIRES: zlib, x86 | |
| 2 | ||
| 3 | # RUN: yaml2obj -docnum=1 %s -o %t.o | |
| 4 | # RUN: ld.lld %t.o %t.o -o %t2 | |
| 5 | # RUN: llvm-readobj --sections --section-data %t2 | FileCheck %s | |
| 6 | ||
| 7 | # RUN: yaml2obj -docnum=2 %s -o %t.o | |
| 8 | # RUN: ld.lld %t.o %t.o -o %t2 | |
| 9 | # RUN: llvm-readobj --sections --section-data %t2 | FileCheck %s | |
| 10 | ||
| 11 | # CHECK: Name: .debug_info | |
| 12 | # CHECK-NEXT: Type: SHT_PROGBITS | |
| 13 | # CHECK-NEXT: Flags [ | |
| 14 | # CHECK-NEXT: ] | |
| 15 | # CHECK-NEXT: Address: 0x0 | |
| 16 | # CHECK-NEXT: Offset: 0xE8 | |
| 17 | # CHECK-NEXT: Size: 108 | |
| 18 | # CHECK-NEXT: Link: 0 | |
| 19 | # CHECK-NEXT: Info: 0 | |
| 20 | # CHECK-NEXT: AddressAlignment: 1 | |
| 21 | # CHECK-NEXT: EntrySize: 0 | |
| 22 | # CHECK-NEXT: SectionData ( | |
| 23 | # CHECK-NEXT: 0000: {{.*}} |ABCDEFGHIJKLMNOP| | |
| 24 | # CHECK-NEXT: 0010: {{.*}} |QRSTUVWXYZ.ABCDE| | |
| 25 | # CHECK-NEXT: 0020: {{.*}} |FGHIJKLMNOPQRSTU| | |
| 26 | # CHECK-NEXT: 0030: {{.*}} |VWXYZ.ABCDEFGHIJ| | |
| 27 | # CHECK-NEXT: 0040: {{.*}} |KLMNOPQRSTUVWXYZ| | |
| 28 | # CHECK-NEXT: 0050: {{.*}} |.ABCDEFGHIJKLMNO| | |
| 29 | # CHECK-NEXT: 0060: {{.*}} |PQRSTUVWXYZ.| | |
| 30 | # CHECK-NEXT: ) | |
| 31 | # CHECK-NEXT: } | |
| 32 | ||
| 33 | ## YAML below is produced from the following code. AddressAlign of .debug_info is 8, | |
| 34 | ## while compressed header has ch_addralign = 1. LLD had a bug and did not use the | |
| 35 | ## value of ch_addralign at all. We produced broken section content. | |
| 36 | ## | |
| 37 | ## .section .debug_info,"",@progbits | |
| 38 | ## .string "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
| 39 | ## .string "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
| 40 | ||
| 41 | --- !ELF | |
| 42 | FileHeader: | |
| 43 | Class: ELFCLASS64 | |
| 44 | Data: ELFDATA2LSB | |
| 45 | Type: ET_REL | |
| 46 | Machine: EM_X86_64 | |
| 47 | Sections: | |
| 48 | - Name: .debug_info | |
| 49 | Type: SHT_PROGBITS | |
| 50 | Flags: [ SHF_COMPRESSED ] | |
| 51 | AddressAlign: 0x0000000000000008 | |
| 52 | Content: 010000000000000036000000000000000100000000000000789C73747276717573F7F0F4F2F6F1F5F30F080C0A0E090D0B8F888C6270C42D0500ADA00FBF | |
| 53 | ||
| 54 | ## YAML below is the same as above, with a single change: ch_addralign field of the compressed | |
| 55 | ## header was set to 0. This is allowed by the standard, we have to support it. | |
| 56 | --- !ELF | |
| 57 | FileHeader: | |
| 58 | Class: ELFCLASS64 | |
| 59 | Data: ELFDATA2LSB | |
| 60 | Type: ET_REL | |
| 61 | Machine: EM_X86_64 | |
| 62 | Sections: | |
| 63 | - Name: .debug_info | |
| 64 | Type: SHT_PROGBITS | |
| 65 | Flags: [ SHF_COMPRESSED ] | |
| 66 | AddressAlign: 0x0000000000000008 | |
| 67 | Content: 010000000000000036000000000000000000000000000000789C73747276717573F7F0F4F2F6F1F5F30F080C0A0E090D0B8F888C6270C42D0500ADA00FBF |
deps/lld/test/ELF/copy-rel-pie.s+7-6| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc %p/Inputs/copy-rel-pie.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux |
| 4 | 4 | // RUN: ld.lld %t2.o -o %t2.so -shared |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv %t.o %t2.so -o %t.exe -pie |
| 6 | // RUN: llvm-readobj -s -r %t.exe | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S -r %t.exe | FileCheck %s | |
| 7 | 7 | // RUN: llvm-objdump -d %t.exe | FileCheck --check-prefix=DISASM %s |
| 8 | 8 | |
| 9 | 9 | .global _start |
| ... | ... | @@ -27,21 +27,22 @@ _start: |
| 27 | 27 | // CHECK-NEXT: SHF_ALLOC |
| 28 | 28 | // CHECK-NEXT: SHF_WRITE |
| 29 | 29 | // CHECK-NEXT: ] |
| 30 | // CHECK-NEXT: Address: 0x4000 | |
| 30 | // CHECK-NEXT: Address: 0x3020 | |
| 31 | 31 | |
| 32 | 32 | // CHECK: Relocations [ |
| 33 | 33 | // CHECK-NEXT: Section (4) .rela.dyn { |
| 34 | // CHECK-NEXT: 0x4000 R_X86_64_COPY foo 0x0 | |
| 34 | // CHECK-NEXT: 0x3020 R_X86_64_COPY foo 0x0 | |
| 35 | 35 | // CHECK-NEXT: } |
| 36 | 36 | // CHECK-NEXT: Section (5) .rela.plt { |
| 37 | // CHECK-NEXT: 0x2018 R_X86_64_JUMP_SLOT bar 0x0 | |
| 37 | // CHECK-NEXT: 0x3018 R_X86_64_JUMP_SLOT bar 0x0 | |
| 38 | 38 | // CHECK-NEXT: } |
| 39 | 39 | // CHECK-NEXT: ] |
| 40 | 40 | |
| 41 | 41 | // (0x1010 + 0x10) - 0x1005 = 27 |
| 42 | // 0x4000 - 0x100a = 12278 | |
| 42 | // 0x3020 - 0x100a = 8214 | |
| 43 | 43 | |
| 44 | 44 | // DISASM: Disassembly of section .text: |
| 45 | // DISASM-EMPTY: | |
| 45 | 46 | // DISASM-NEXT: _start: |
| 46 | 47 | // DISASM-NEXT: 1000: e8 1b 00 00 00 callq 27 |
| 47 | // DISASM-NEXT: 1005: e8 f6 2f 00 00 callq 12278 <foo> | |
| 48 | // DISASM-NEXT: 1005: e8 16 20 00 00 callq 8214 <foo> |
deps/lld/test/ELF/copy-rel-version.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | // RUN: echo "v1 {}; v2 {};" > %t.ver |
| 5 | 5 | // RUN: ld.lld %t1.o -shared -soname t1.so --version-script=%t.ver -o %t1.so |
| 6 | 6 | // RUN: ld.lld %t.o %t1.so -o %t |
| 7 | // RUN: llvm-readobj -t %t | FileCheck %s | |
| 7 | // RUN: llvm-readobj --symbols %t | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | .global _start |
| 10 | 10 | _start: |
deps/lld/test/ELF/copy-relocation-zero-abs-addr.s+2-2| ... | ... | @@ -3,8 +3,8 @@ |
| 3 | 3 | // RUN: ld.lld -shared -o %t2.so %t.o |
| 4 | 4 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t3.o |
| 5 | 5 | // RUN: ld.lld %t2.so %t3.o -o %t4 |
| 6 | // RUN: llvm-readobj -symbols %t2.so | FileCheck -check-prefix=ABSADDR %s | |
| 7 | // RUN: llvm-readobj -s -r --expand-relocs %t4 | FileCheck %s | |
| 6 | // RUN: llvm-readobj --symbols %t2.so | FileCheck -check-prefix=ABSADDR %s | |
| 7 | // RUN: llvm-readobj -S -r --expand-relocs %t4 | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | // This tests that symbols with absolute addresses are properly |
| 10 | 10 | // handled. Normal DSO symbols are handled as usual. |
deps/lld/test/ELF/debug-gnu-pubnames.s+2-2| ... | ... | @@ -2,12 +2,12 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | |
| 4 | 4 | # RUN: ld.lld %t.o -o %t1.exe |
| 5 | # RUN: llvm-readobj -sections %t1.exe | FileCheck %s | |
| 5 | # RUN: llvm-readobj --sections %t1.exe | FileCheck %s | |
| 6 | 6 | # CHECK: .debug_gnu_pubnames |
| 7 | 7 | # CHECK: .debug_gnu_pubtypes |
| 8 | 8 | |
| 9 | 9 | # RUN: ld.lld -gdb-index %t.o -o %t2.exe |
| 10 | # RUN: llvm-readobj -sections %t2.exe | FileCheck %s --check-prefix=GDB | |
| 10 | # RUN: llvm-readobj --sections %t2.exe | FileCheck %s --check-prefix=GDB | |
| 11 | 11 | # GDB-NOT: .debug_gnu_pubnames |
| 12 | 12 | # GDB-NOT: .debug_gnu_pubtypes |
| 13 | 13 |
deps/lld/test/ELF/debug-line-obj.s created+175| ... | ... | @@ -0,0 +1,175 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux -dwarf-version=5 %s -o %t.o | |
| 3 | # RUN: not ld.lld %t.o -o %t1 2>&1 | FileCheck %s | |
| 4 | ||
| 5 | # When compiling with -ffunction-sections, .debug_line may contain descriptions | |
| 6 | # of locations from the different text sections. Until relocated such | |
| 7 | # descriptions might contain overlapping offsets. Check LLD is able to report | |
| 8 | # the error locations correctly in this case. | |
| 9 | ||
| 10 | # CHECK: error: undefined symbol: foo() | |
| 11 | # CHECK-NEXT: >>> referenced by test.cpp:2 | |
| 12 | # CHECK-NEXT: >>> {{.*}}.o:(bar()) | |
| 13 | # CHECK-NEXT: >>> referenced by test.cpp:3 | |
| 14 | # CHECK-NEXT: >>> {{.*}}.o:(baz()) | |
| 15 | ||
| 16 | # The code below is the reduced version of the output | |
| 17 | # from the following invocation and source: | |
| 18 | # | |
| 19 | # // test.cpp: | |
| 20 | # int foo(); | |
| 21 | # int bar() { return foo(); } | |
| 22 | # int baz() { return foo(); } | |
| 23 | # | |
| 24 | # clang -gdwarf-5 -ffunction-sections test.cpp -o test.s -S | |
| 25 | ||
| 26 | .text | |
| 27 | .file "test.cpp" | |
| 28 | .section .text._Z3barv,"ax",@progbits | |
| 29 | .globl _Z3barv | |
| 30 | .type _Z3barv,@function | |
| 31 | _Z3barv: | |
| 32 | .Lfunc_begin0: | |
| 33 | .file 0 "/path" "test.cpp" md5 0x9ff11a8404ab4d032ee2dd4f5f8c4140 | |
| 34 | .loc 0 2 0 # test.cpp:2:0 | |
| 35 | .loc 0 2 20 prologue_end # test.cpp:2:20 | |
| 36 | callq _Z3foov | |
| 37 | .loc 0 2 13 is_stmt 0 # test.cpp:2:13 | |
| 38 | .Lfunc_end0: | |
| 39 | .size _Z3barv, .Lfunc_end0-_Z3barv | |
| 40 | # -- End function | |
| 41 | .section .text._Z3bazv,"ax",@progbits | |
| 42 | .globl _Z3bazv # -- Begin function _Z3bazv | |
| 43 | .type _Z3bazv,@function | |
| 44 | _Z3bazv: # @_Z3bazv | |
| 45 | .Lfunc_begin1: | |
| 46 | .loc 0 3 0 is_stmt 1 # test.cpp:3:0 | |
| 47 | .loc 0 3 20 prologue_end # test.cpp:3:20 | |
| 48 | callq _Z3foov | |
| 49 | .loc 0 3 13 is_stmt 0 # test.cpp:3:13 | |
| 50 | .Lfunc_end1: | |
| 51 | .size _Z3bazv, .Lfunc_end1-_Z3bazv | |
| 52 | ||
| 53 | .section .debug_str,"MS",@progbits,1 | |
| 54 | .Linfo_string0: | |
| 55 | .asciz "stub" | |
| 56 | ||
| 57 | .section .debug_str_offsets,"",@progbits | |
| 58 | .long 8 | |
| 59 | .short 5 | |
| 60 | .short 0 | |
| 61 | .Lstr_offsets_base0: | |
| 62 | .long .Linfo_string0 | |
| 63 | ||
| 64 | .section .debug_abbrev,"",@progbits | |
| 65 | .byte 1 # Abbreviation Code | |
| 66 | .byte 17 # DW_TAG_compile_unit | |
| 67 | .byte 1 # DW_CHILDREN_yes | |
| 68 | .byte 37 # DW_AT_producer | |
| 69 | .byte 37 # DW_FORM_strx1 | |
| 70 | .byte 19 # DW_AT_language | |
| 71 | .byte 5 # DW_FORM_data2 | |
| 72 | .byte 3 # DW_AT_name | |
| 73 | .byte 37 # DW_FORM_strx1 | |
| 74 | .byte 114 # DW_AT_str_offsets_base | |
| 75 | .byte 23 # DW_FORM_sec_offset | |
| 76 | .byte 16 # DW_AT_stmt_list | |
| 77 | .byte 23 # DW_FORM_sec_offset | |
| 78 | .byte 27 # DW_AT_comp_dir | |
| 79 | .byte 37 # DW_FORM_strx1 | |
| 80 | .byte 115 # DW_AT_addr_base | |
| 81 | .byte 23 # DW_FORM_sec_offset | |
| 82 | .byte 17 # DW_AT_low_pc | |
| 83 | .byte 1 # DW_FORM_addr | |
| 84 | .byte 85 # DW_AT_ranges | |
| 85 | .byte 35 # DW_FORM_rnglistx | |
| 86 | .byte 116 # DW_AT_rnglists_base | |
| 87 | .byte 23 # DW_FORM_sec_offset | |
| 88 | .byte 0 # EOM(1) | |
| 89 | .byte 0 # EOM(2) | |
| 90 | .byte 2 # Abbreviation Code | |
| 91 | .byte 46 # DW_TAG_subprogram | |
| 92 | .byte 0 # DW_CHILDREN_no | |
| 93 | .byte 17 # DW_AT_low_pc | |
| 94 | .byte 27 # DW_FORM_addrx | |
| 95 | .byte 18 # DW_AT_high_pc | |
| 96 | .byte 6 # DW_FORM_data4 | |
| 97 | .byte 64 # DW_AT_frame_base | |
| 98 | .byte 24 # DW_FORM_exprloc | |
| 99 | .byte 110 # DW_AT_linkage_name | |
| 100 | .byte 37 # DW_FORM_strx1 | |
| 101 | .byte 3 # DW_AT_name | |
| 102 | .byte 37 # DW_FORM_strx1 | |
| 103 | .byte 58 # DW_AT_decl_file | |
| 104 | .byte 11 # DW_FORM_data1 | |
| 105 | .byte 59 # DW_AT_decl_line | |
| 106 | .byte 11 # DW_FORM_data1 | |
| 107 | .byte 73 # DW_AT_type | |
| 108 | .byte 19 # DW_FORM_ref4 | |
| 109 | .byte 63 # DW_AT_external | |
| 110 | .byte 25 # DW_FORM_flag_present | |
| 111 | .byte 0 # EOM(1) | |
| 112 | .byte 0 # EOM(2) | |
| 113 | .byte 3 # Abbreviation Code | |
| 114 | .byte 36 # DW_TAG_base_type | |
| 115 | .byte 0 # DW_CHILDREN_no | |
| 116 | .byte 3 # DW_AT_name | |
| 117 | .byte 37 # DW_FORM_strx1 | |
| 118 | .byte 62 # DW_AT_encoding | |
| 119 | .byte 11 # DW_FORM_data1 | |
| 120 | .byte 11 # DW_AT_byte_size | |
| 121 | .byte 11 # DW_FORM_data1 | |
| 122 | .byte 0 # EOM(1) | |
| 123 | .byte 0 # EOM(2) | |
| 124 | .byte 0 # EOM(3) | |
| 125 | ||
| 126 | .section .debug_info,"",@progbits | |
| 127 | .Lcu_begin0: | |
| 128 | .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit | |
| 129 | .Ldebug_info_start0: | |
| 130 | .short 5 # DWARF version number | |
| 131 | .byte 1 # DWARF Unit Type | |
| 132 | .byte 8 # Address Size (in bytes) | |
| 133 | .long .debug_abbrev # Offset Into Abbrev. Section | |
| 134 | .byte 1 # Abbrev [1] 0xc:0x44 DW_TAG_compile_unit | |
| 135 | .byte 0 # DW_AT_producer | |
| 136 | .short 4 # DW_AT_language | |
| 137 | .byte 0 # DW_AT_name | |
| 138 | .long .Lstr_offsets_base0 # DW_AT_str_offsets_base | |
| 139 | .long .Lline_table_start0 # DW_AT_stmt_list | |
| 140 | .byte 2 # DW_AT_comp_dir | |
| 141 | .long 0 # DW_AT_addr_base | |
| 142 | .quad 0 # DW_AT_low_pc | |
| 143 | .byte 0 # DW_AT_ranges | |
| 144 | .long 0 # DW_AT_rnglists_base | |
| 145 | .byte 2 # Abbrev [2] 0x2b:0x10 DW_TAG_subprogram | |
| 146 | .byte 0 # DW_AT_low_pc | |
| 147 | .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc | |
| 148 | .byte 1 # DW_AT_frame_base | |
| 149 | .byte 86 | |
| 150 | .byte 3 # DW_AT_linkage_name | |
| 151 | .byte 0 # DW_AT_name | |
| 152 | .byte 1 # DW_AT_decl_file | |
| 153 | .byte 2 # DW_AT_decl_line | |
| 154 | .long 75 # DW_AT_type | |
| 155 | # DW_AT_external | |
| 156 | .byte 2 # Abbrev [2] 0x3b:0x10 DW_TAG_subprogram | |
| 157 | .byte 1 # DW_AT_low_pc | |
| 158 | .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc | |
| 159 | .byte 1 # DW_AT_frame_base | |
| 160 | .byte 86 | |
| 161 | .byte 6 # DW_AT_linkage_name | |
| 162 | .byte 0 # DW_AT_name | |
| 163 | .byte 1 # DW_AT_decl_file | |
| 164 | .byte 3 # DW_AT_decl_line | |
| 165 | .long 75 # DW_AT_type | |
| 166 | # DW_AT_external | |
| 167 | .byte 3 # Abbrev [3] 0x4b:0x4 DW_TAG_base_type | |
| 168 | .byte 0 # DW_AT_name | |
| 169 | .byte 5 # DW_AT_encoding | |
| 170 | .byte 4 # DW_AT_byte_size | |
| 171 | .byte 0 # End Of Children Mark | |
| 172 | .Ldebug_info_end0: | |
| 173 | ||
| 174 | .section .debug_line,"",@progbits | |
| 175 | .Lline_table_start0: |
deps/lld/test/ELF/debug-line-str.s+1-2| ... | ... | @@ -27,8 +27,7 @@ |
| 27 | 27 | main: |
| 28 | 28 | .Lfunc_begin0: |
| 29 | 29 | .file 0 "/home/path" "test.cpp" md5 0x8ed32099ab837bd13543fd3e8102739f |
| 30 | .file 1 "test.cpp" md5 0x8ed32099ab837bd13543fd3e8102739f | |
| 31 | .loc 1 3 10 prologue_end | |
| 30 | .loc 0 3 10 prologue_end | |
| 32 | 31 | jmp _Z3foov |
| 33 | 32 | .Lfunc_end0: |
| 34 | 33 |
deps/lld/test/ELF/debug-relocation-none.test+5-4| ... | ... | @@ -52,7 +52,8 @@ Sections: |
| 52 | 52 | Content: '0111001017000000' |
| 53 | 53 | |
| 54 | 54 | Symbols: |
| 55 | Global: | |
| 56 | - Name: _start | |
| 57 | Section: .text | |
| 58 | - Name: bar | |
| 55 | - Name: _start | |
| 56 | Section: .text | |
| 57 | Binding: STB_GLOBAL | |
| 58 | - Name: bar | |
| 59 | Binding: STB_GLOBAL |
deps/lld/test/ELF/defsym-reserved-syms.s+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld -o %t %t.o --defsym=foo2=etext |
| 4 | # RUN: llvm-readobj -t -s %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj --symbols -S %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | ## Check 'foo2' value is equal to value of 'etext'. |
| 7 | 7 | # CHECK: Symbol { |
| ... | ... | @@ -14,7 +14,7 @@ |
| 14 | 14 | ## Check 'foo2' value set correctly when using |
| 15 | 15 | ## reserved symbol 'etext' in expression. |
| 16 | 16 | # RUN: ld.lld -o %t %t.o --defsym=foo2=etext+2 |
| 17 | # RUN: llvm-readobj -t -s %t | FileCheck %s --check-prefix=EXPR | |
| 17 | # RUN: llvm-readobj --symbols -S %t | FileCheck %s --check-prefix=EXPR | |
| 18 | 18 | # EXPR: Symbol { |
| 19 | 19 | # EXPR: Name: foo2 |
| 20 | 20 | # EXPR-NEXT: Value: 0x201007 |
deps/lld/test/ELF/defsym.s+5-4| ... | ... | @@ -1,12 +1,12 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld -o %t %t.o --defsym=foo2=foo1 |
| 4 | # RUN: llvm-readobj -t -s %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj --symbols -S %t | FileCheck %s | |
| 5 | 5 | # RUN: llvm-objdump -d -print-imm-hex %t | FileCheck %s --check-prefix=USE |
| 6 | 6 | |
| 7 | 7 | ## Check that we accept --defsym foo2=foo1 form. |
| 8 | 8 | # RUN: ld.lld -o %t2 %t.o --defsym foo2=foo1 |
| 9 | # RUN: llvm-readobj -t -s %t2 | FileCheck %s | |
| 9 | # RUN: llvm-readobj --symbols -S %t2 | FileCheck %s | |
| 10 | 10 | # RUN: llvm-objdump -d -print-imm-hex %t2 | FileCheck %s --check-prefix=USE |
| 11 | 11 | |
| 12 | 12 | ## Check we are reporting the error correctly and don't crash |
| ... | ... | @@ -36,11 +36,12 @@ |
| 36 | 36 | |
| 37 | 37 | ## Check we can use foo2 and it that it is an alias for foo1. |
| 38 | 38 | # USE: Disassembly of section .text: |
| 39 | # USE-EMPTY: | |
| 39 | 40 | # USE-NEXT: _start: |
| 40 | 41 | # USE-NEXT: movl $0x123, %edx |
| 41 | 42 | |
| 42 | 43 | # RUN: ld.lld -o %t %t.o --defsym=foo2=1 |
| 43 | # RUN: llvm-readobj -t -s %t | FileCheck %s --check-prefix=ABS | |
| 44 | # RUN: llvm-readobj --symbols -S %t | FileCheck %s --check-prefix=ABS | |
| 44 | 45 | |
| 45 | 46 | # ABS: Symbol { |
| 46 | 47 | # ABS: Name: foo2 |
| ... | ... | @@ -53,7 +54,7 @@ |
| 53 | 54 | # ABS-NEXT: } |
| 54 | 55 | |
| 55 | 56 | # RUN: ld.lld -o %t %t.o --defsym=foo2=foo1+5 |
| 56 | # RUN: llvm-readobj -t -s %t | FileCheck %s --check-prefix=EXPR | |
| 57 | # RUN: llvm-readobj --symbols -S %t | FileCheck %s --check-prefix=EXPR | |
| 57 | 58 | |
| 58 | 59 | # EXPR: Symbol { |
| 59 | 60 | # EXPR: Name: foo1 |
deps/lld/test/ELF/deplibs-colon-prefix.s created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/deplibs-lib_foo.s -o %tfoo.o | |
| 5 | # RUN: rm -rf %t.dir | |
| 6 | # RUN: mkdir -p %t.dir | |
| 7 | # RUN: llvm-ar rc %t.dir/foo.a %tfoo.o | |
| 8 | # RUN: not ld.lld %t.o -o /dev/null -L %t.dir 2>&1 | FileCheck %s -DOBJ=%t.o | |
| 9 | # CHECK: error: [[OBJ]]: unable to find library from dependent library specifier: :foo.a | |
| 10 | ||
| 11 | .global _start | |
| 12 | _start: | |
| 13 | call foo | |
| 14 | .section ".deplibs","MS",@llvm_dependent_libraries,1 | |
| 15 | .asciz ":foo.a" |
deps/lld/test/ELF/deplibs-corrupt.s created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 4 | # RUN: not ld.lld %t.o -o /dev/null -L %t.dir 2>&1 | FileCheck %s -DOBJ=%t.o | |
| 5 | # CHECK: error: [[OBJ]]: corrupted dependent libraries section (unterminated string): .deplibs | |
| 6 | ||
| 7 | .section ".deplibs","MS",@llvm_dependent_libraries,1 | |
| 8 | .ascii ":foo.a" |
deps/lld/test/ELF/deplibs.s created+56| ... | ... | @@ -0,0 +1,56 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/deplibs-lib_foo.s -o %tfoo.o | |
| 5 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/deplibs-lib_bar.s -o %tbar.o | |
| 6 | # RUN: rm -rf %t.dir %t.cwd | |
| 7 | # RUN: mkdir -p %t.dir | |
| 8 | ||
| 9 | # error if dependent libraries cannot be found | |
| 10 | # RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s -DOBJ=%t.o --check-prefix MISSING | |
| 11 | # MISSING: error: [[OBJ]]: unable to find library from dependent library specifier: foo.a | |
| 12 | # MISSING-NEXT: error: [[OBJ]]: unable to find library from dependent library specifier: bar | |
| 13 | ||
| 14 | # can ignore dependent libraries | |
| 15 | # RUN: not ld.lld %t.o -o /dev/null --no-dependent-libraries 2>&1 | FileCheck %s --check-prefix IGNORE | |
| 16 | # IGNORE: error: undefined symbol: foo | |
| 17 | # IGNORE: error: undefined symbol: bar | |
| 18 | ||
| 19 | # -r links preserve dependent libraries | |
| 20 | # RUN: ld.lld %t.o %t.o -r -o %t-r.o | |
| 21 | # RUN: not ld.lld %t-r.o -o /dev/null 2>&1 | sort | FileCheck %s -DOBJ=%t-r.o --check-prefixes MINUSR | |
| 22 | # MINUSR: error: [[OBJ]]: unable to find library from dependent library specifier: bar | |
| 23 | # MINUSR-NEXT: error: [[OBJ]]: unable to find library from dependent library specifier: foo.a | |
| 24 | # MINUSR-NOT: unable to find library from dependent library specifier | |
| 25 | ||
| 26 | # static archives located relative to library search paths | |
| 27 | # RUN: llvm-ar rc %t.dir/foo.a %tfoo.o | |
| 28 | # RUN: llvm-ar rc %t.dir/libbar.a %tbar.o | |
| 29 | # RUN: ld.lld %t.o -o /dev/null -L %t.dir | |
| 30 | ||
| 31 | # shared objects located relative to library search paths | |
| 32 | # RUN: rm %t.dir/libbar.a | |
| 33 | # RUN: ld.lld -shared -o %t.dir/libbar.so %tbar.o | |
| 34 | # RUN: ld.lld -Bdynamic %t.o -o /dev/null -L %t.dir | |
| 35 | ||
| 36 | # dependent libraries searched for symbols after libraries on the command line | |
| 37 | # RUN: mkdir -p %t.cwd | |
| 38 | # RUN: cd %t.cwd | |
| 39 | # RUN: cp %t.dir/foo.a %t.cwd/libcmdline.a | |
| 40 | # RUN: ld.lld %t.o libcmdline.a -o /dev/null -L %t.dir --trace 2>&1 | FileCheck %s -DOBJ=%t.o -DSO=%t.dir --check-prefix CMDLINE --implicit-check-not foo.a | |
| 41 | # CMDLINE: [[OBJ]] | |
| 42 | # CMDLINE-NEXT: {{^libcmdline\.a}} | |
| 43 | # CMDLINE-NEXT: [[SO]]{{[\\/]}}libbar.so | |
| 44 | ||
| 45 | # libraries can be found from specifiers as if the specifiers were listed on on the command-line. | |
| 46 | # RUN: cp %t.dir/foo.a %t.cwd/foo.a | |
| 47 | # RUN: ld.lld %t.o -o /dev/null -L %t.dir --trace 2>&1 | FileCheck %s -DOBJ=%t.o -DSO=%t.dir --check-prefix ASIFCMDLINE --implicit-check-not foo.a | |
| 48 | # ASIFCMDLINE: [[OBJ]] | |
| 49 | # ASIFCMDLINE-NEXT: {{^foo\.a}} | |
| 50 | # ASIFCMDLINE-NEXT: [[SO]]{{[\\/]}}libbar.so | |
| 51 | ||
| 52 | call foo | |
| 53 | call bar | |
| 54 | .section ".deplibs","MS",@llvm_dependent_libraries,1 | |
| 55 | .asciz "foo.a" | |
| 56 | .asciz "bar" |
deps/lld/test/ELF/discard-locals.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux -save-temp-labels %s -o %t |
| 3 | 3 | // RUN: ld.lld -discard-locals %t -o %t2 |
| 4 | // RUN: llvm-readobj -s -sd -t %t2 | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S --section-data --symbols %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .global _start |
| 7 | 7 | _start: |
deps/lld/test/ELF/discard-merge-locals.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld %t -o %t2 -shared |
| 4 | // RUN: llvm-readobj -t %t2 | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | 	leaq	.L.str(%rip), %rdi |
| 7 | 7 |
deps/lld/test/ELF/discard-merge-unnamed.s+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | // RUN: ld.lld %p/Inputs/discard-merge-unnamed.o -o %t2 -shared |
| 2 | // RUN: llvm-readobj -t %t2 | FileCheck %s | |
| 2 | // RUN: llvm-readobj --symbols %t2 | FileCheck %s | |
| 3 | 3 | |
| 4 | 4 | // Test that the unnamed symbol is SHF_MERGE is omitted. |
| 5 | 5 |
deps/lld/test/ELF/discard-none.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux -save-temp-labels %s -o %t |
| 3 | 3 | // RUN: ld.lld -discard-none -shared %t -o %t2 |
| 4 | // RUN: llvm-readobj -s -sd -t %t2 | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S --section-data --symbols %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .text |
| 7 | 7 | .Lmyvar: |
deps/lld/test/ELF/driver.test+7-3| ... | ... | @@ -1,10 +1,10 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | |
| 3 | # RUN: not ld.lld --unknown1 --unknown2 -m foo /no/such/file -lnosuchlib \ | |
| 3 | # RUN: not ld.lld --unknown1 --unkn=own2 -m foo /no/such/file -lnosuchlib \ | |
| 4 | 4 | # RUN: 2>&1 | FileCheck -check-prefix=UNKNOWN %s |
| 5 | 5 | |
| 6 | # UNKNOWN: unknown argument: --unknown1 | |
| 7 | # UNKNOWN: unknown argument: --unknown2 | |
| 6 | # UNKNOWN: unknown argument '--unknown1' | |
| 7 | # UNKNOWN: unknown argument '--unkn=own2' | |
| 8 | 8 | # UNKNOWN: unknown emulation: foo |
| 9 | 9 | # UNKNOWN: cannot open /no/such/file |
| 10 | 10 | # UNKNOWN: unable to find library -lnosuchlib |
| ... | ... | @@ -22,6 +22,9 @@ |
| 22 | 22 | # RUN: not ld.lld -v xyz 2>&1 | FileCheck -check-prefix=VERSION %s |
| 23 | 23 | # VERSION: LLD {{.*}} (compatible with GNU linkers) |
| 24 | 24 | |
| 25 | # RUN: not ld.lld --versin 2>&1 | FileCheck -check-prefix=SPELLVERSION %s | |
| 26 | # SPELLVERSION: unknown argument '--versin', did you mean '--version' | |
| 27 | ||
| 25 | 28 | ## Attempt to link DSO with -r |
| 26 | 29 | # RUN: ld.lld -shared %t -o %t.so |
| 27 | 30 | # RUN: not ld.lld -r %t.so %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR %s |
| ... | ... | @@ -60,6 +63,7 @@ |
| 60 | 63 | # ERR9: cannot open output file utput=/no/such/file |
| 61 | 64 | |
| 62 | 65 | # RUN: not ld.lld %t -z foo 2>&1 | FileCheck -check-prefix=ERR10 %s |
| 66 | # RUN: not ld.lld %t -z foo --version 2>&1 | FileCheck -check-prefix=ERR10 %s | |
| 63 | 67 | # ERR10: unknown -z value: foo |
| 64 | 68 | |
| 65 | 69 | ## Check we report "unknown -z value" error even with -v. |
deps/lld/test/ELF/dso-undef-size.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: ld.lld -shared %t1.o -o %t1.so |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o |
| 5 | 5 | # RUN: ld.lld -shared %t2.o %t1.so -o %t2.so |
| 6 | # RUN: llvm-readobj -symbols -dyn-symbols %t2.so | |
| 6 | # RUN: llvm-readobj --symbols --dyn-syms %t2.so | |
| 7 | 7 | |
| 8 | 8 | # CHECK: Symbols [ |
| 9 | 9 | # CHECK-NEXT: Symbol { |
deps/lld/test/ELF/dso_handle.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 4 | 4 | # RUN: ld.lld -shared %t.o -o %t |
| 5 | # RUN: llvm-readobj -symbols %t | FileCheck %s | |
| 5 | # RUN: llvm-readobj --symbols %t | FileCheck %s | |
| 6 | 6 | # CHECK: Name: __dso_handle |
| 7 | 7 | # CHECK-NEXT: Value: 0x0 |
| 8 | 8 | # CHECK-NEXT: Size: 0 |
deps/lld/test/ELF/dt_flags.s+3-3| ... | ... | @@ -5,13 +5,13 @@ |
| 5 | 5 | |
| 6 | 6 | # RUN: ld.lld -z global -z initfirst -z interpose -z now -z nodefaultlib \ |
| 7 | 7 | # RUN: -z nodelete -z nodlopen -z origin -Bsymbolic %t %t.so -o %t1 |
| 8 | # RUN: llvm-readobj -dynamic-table %t1 | FileCheck -check-prefix=FLAGS %s | |
| 8 | # RUN: llvm-readobj --dynamic-table %t1 | FileCheck -check-prefix=FLAGS %s | |
| 9 | 9 | |
| 10 | 10 | # RUN: ld.lld %t %t.so -o %t2 |
| 11 | # RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s | |
| 11 | # RUN: llvm-readobj --dynamic-table %t2 | FileCheck %s | |
| 12 | 12 | |
| 13 | 13 | # RUN: ld.lld -z lazy %t %t.so -o %t2 |
| 14 | # RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s | |
| 14 | # RUN: llvm-readobj --dynamic-table %t2 | FileCheck %s | |
| 15 | 15 | |
| 16 | 16 | # FLAGS: DynamicSection [ |
| 17 | 17 | # FLAGS: 0x000000000000001E FLAGS ORIGIN SYMBOLIC BIND_NOW |
deps/lld/test/ELF/dt_tags.s+2-2| ... | ... | @@ -3,8 +3,8 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t |
| 4 | 4 | # RUN: ld.lld -shared %t -o %t.so |
| 5 | 5 | # RUN: ld.lld %t %t.so -o %t.exe |
| 6 | # RUN: llvm-readobj -dynamic-table %t.so | FileCheck -check-prefix=DSO %s | |
| 7 | # RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=EXE %s | |
| 6 | # RUN: llvm-readobj --dynamic-table %t.so | FileCheck -check-prefix=DSO %s | |
| 7 | # RUN: llvm-readobj --dynamic-table %t.exe | FileCheck -check-prefix=EXE %s | |
| 8 | 8 | |
| 9 | 9 | # EXE: DynamicSection [ |
| 10 | 10 | # EXE: 0x0000000000000015 DEBUG 0x0 |
deps/lld/test/ELF/dtrace-r.test deleted-8| ... | ... | @@ -1,8 +0,0 @@ |
| 1 | RUN: ld.lld -r -o %t.o %p/Inputs/dtrace-r.o | |
| 2 | RUN: llvm-readobj -r %t.o | FileCheck %s | |
| 3 | ||
| 4 | CHECK: Relocations [ | |
| 5 | CHECK-NEXT: Section ({{.*}}) .rela.text { | |
| 6 | CHECK-NEXT: 0x0 R_X86_64_NONE - 0x0 | |
| 7 | CHECK-NEXT: } | |
| 8 | CHECK-NEXT: ] |
deps/lld/test/ELF/dynamic-got-rela.s+3-3| ... | ... | @@ -1,11 +1,11 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared --apply-dynamic-relocs |
| 4 | // RUN: llvm-readobj -r -s -l -section-data %t.so | FileCheck -check-prefix CHECK -check-prefix APPLYDYNREL %s | |
| 4 | // RUN: llvm-readobj -r -S -l --section-data %t.so | FileCheck -check-prefix CHECK -check-prefix APPLYDYNREL %s | |
| 5 | 5 | // RUN: ld.lld %t.o -o %t2.so -shared |
| 6 | // RUN: llvm-readobj -r -s -l -section-data %t2.so | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s | |
| 6 | // RUN: llvm-readobj -r -S -l --section-data %t2.so | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s | |
| 7 | 7 | // RUN: ld.lld %t.o -o %t2.so -shared --no-apply-dynamic-relocs |
| 8 | // RUN: llvm-readobj -r -s -l -section-data %t2.so | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s | |
| 8 | // RUN: llvm-readobj -r -S -l --section-data %t2.so | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s | |
| 9 | 9 | |
| 10 | 10 | // APPLYDYNREL: Name: .got |
| 11 | 11 | // APPLYDYNREL-NEXT: Type: SHT_PROGBITS |
deps/lld/test/ELF/dynamic-got.s+23-23| ... | ... | @@ -1,24 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -s -l -section-data -r %t.so | FileCheck %s | |
| 5 | ||
| 6 | // CHECK: Name: .got.plt | |
| 7 | // CHECK-NEXT: Type: SHT_PROGBITS | |
| 8 | // CHECK-NEXT: Flags [ | |
| 9 | // CHECK-NEXT: SHF_ALLOC | |
| 10 | // CHECK-NEXT: SHF_WRITE | |
| 11 | // CHECK-NEXT: ] | |
| 12 | // CHECK-NEXT: Address: | |
| 13 | // CHECK-NEXT: Offset: | |
| 14 | // CHECK-NEXT: Size: | |
| 15 | // CHECK-NEXT: Link: | |
| 16 | // CHECK-NEXT: Info: | |
| 17 | // CHECK-NEXT: AddressAlignment: | |
| 18 | // CHECK-NEXT: EntrySize: | |
| 19 | // CHECK-NEXT: SectionData ( | |
| 20 | // CHECK-NEXT: 0000: 00300000 00000000 00000000 | |
| 21 | // CHECK-NEXT: ) | |
| 4 | // RUN: llvm-readobj -S -l --section-data -r %t.so | FileCheck %s | |
| 22 | 5 | |
| 23 | 6 | // CHECK: Name: .got |
| 24 | 7 | // CHECK-NEXT: Type: SHT_PROGBITS |
| ... | ... | @@ -34,19 +17,36 @@ |
| 34 | 17 | // CHECK-NEXT: AddressAlignment: |
| 35 | 18 | // CHECK-NEXT: EntrySize: |
| 36 | 19 | // CHECK-NEXT: SectionData ( |
| 37 | // CHECK-NEXT: 0000: 00300000 | |
| 20 | // CHECK-NEXT: 0000: 00200000 | |
| 38 | 21 | // CHECK-NEXT: ) |
| 39 | 22 | |
| 23 | // CHECK: Name: .got.plt | |
| 24 | // CHECK-NEXT: Type: SHT_PROGBITS | |
| 25 | // CHECK-NEXT: Flags [ | |
| 26 | // CHECK-NEXT: SHF_ALLOC | |
| 27 | // CHECK-NEXT: SHF_WRITE | |
| 28 | // CHECK-NEXT: ] | |
| 29 | // CHECK-NEXT: Address: | |
| 30 | // CHECK-NEXT: Offset: | |
| 31 | // CHECK-NEXT: Size: | |
| 32 | // CHECK-NEXT: Link: | |
| 33 | // CHECK-NEXT: Info: | |
| 34 | // CHECK-NEXT: AddressAlignment: | |
| 35 | // CHECK-NEXT: EntrySize: | |
| 36 | // CHECK-NEXT: SectionData ( | |
| 37 | // CHECK-NEXT: 0000: 00200000 00000000 00000000 | |
| 38 | // CHECK-NEXT: ) | |
| 39 | ||
| 40 | 40 | // CHECK: Relocations [ |
| 41 | 41 | // CHECK-NEXT: Section ({{.*}}) .rel.dyn { |
| 42 | // CHECK-NEXT: 0x3050 R_386_RELATIVE - 0x0 | |
| 42 | // CHECK-NEXT: 0x2050 R_386_RELATIVE - 0x0 | |
| 43 | 43 | // CHECK-NEXT: } |
| 44 | 44 | // CHECK-NEXT: ] |
| 45 | 45 | |
| 46 | 46 | // CHECK: Type: PT_DYNAMIC |
| 47 | // CHECK-NEXT: Offset: 0x3000 | |
| 48 | // CHECK-NEXT: VirtualAddress: 0x3000 | |
| 49 | // CHECK-NEXT: PhysicalAddress: 0x3000 | |
| 47 | // CHECK-NEXT: Offset: 0x2000 | |
| 48 | // CHECK-NEXT: VirtualAddress: 0x2000 | |
| 49 | // CHECK-NEXT: PhysicalAddress: 0x2000 | |
| 50 | 50 | |
| 51 | 51 | calll .L0$pb |
| 52 | 52 | .L0$pb: |
deps/lld/test/ELF/dynamic-list-preempt-replace-symbol.s created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 4 | # RUN: echo '{ common; };' > %t.list | |
| 5 | # RUN: ld.lld --dynamic-list %t.list -shared %t.o -o %t.so | |
| 6 | ||
| 7 | # RUN: llvm-readobj -r %t.so | FileCheck %s | |
| 8 | ||
| 9 | # CHECK: R_X86_64_GLOB_DAT common 0x0 | |
| 10 | ||
| 11 | movq common@gotpcrel(%rip), %rax | |
| 12 | ||
| 13 | .type common,@object | |
| 14 | .comm common,4,4 |
deps/lld/test/ELF/dynamic-list-preempt.s+7-2| ... | ... | @@ -5,11 +5,16 @@ |
| 5 | 5 | # RUN: echo "{ global: foo; bar; local: *; };" > %t.vers |
| 6 | 6 | # RUN: ld.lld --hash-style=sysv -fatal-warnings -dynamic-list %t.list -version-script %t.vers -shared %t.o -o %t.so |
| 7 | 7 | # RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=RELOCS %s |
| 8 | # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=DYNSYMS %s | |
| 8 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck --check-prefix=DYNSYMS %s | |
| 9 | ||
| 10 | # RUN: echo "V1 { global: foo; bar; local: *; };" > %t.vers | |
| 11 | # RUN: ld.lld --hash-style=sysv -fatal-warnings -dynamic-list %t.list -version-script %t.vers -shared %t.o -o %t.so | |
| 12 | # RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=RELOCS %s | |
| 13 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck --check-prefix=DYNSYMS %s | |
| 9 | 14 | |
| 10 | 15 | # RELOCS: Relocations [ |
| 11 | 16 | # RELOCS-NEXT: Section ({{.*}}) .rela.plt { |
| 12 | # RELOCS-NEXT: R_X86_64_JUMP_SLOT foo 0x0 | |
| 17 | # RELOCS-NEXT: R_X86_64_JUMP_SLOT foo{{.*}} 0x0 | |
| 13 | 18 | # RELOCS-NEXT: R_X86_64_JUMP_SLOT ext 0x0 |
| 14 | 19 | # RELOCS-NEXT: } |
| 15 | 20 | # RELOCS-NEXT: ] |
deps/lld/test/ELF/dynamic-list-weak-archive.s+1-1| ... | ... | @@ -10,7 +10,7 @@ |
| 10 | 10 | |
| 11 | 11 | # CHECK: Relocations [ |
| 12 | 12 | # CHECK-NEXT: Section ({{.*}}) .rela.plt { |
| 13 | # CHECK-NEXT: 0x2018 R_X86_64_JUMP_SLOT foo | |
| 13 | # CHECK-NEXT: 0x3018 R_X86_64_JUMP_SLOT foo | |
| 14 | 14 | # CHECK-NEXT: } |
| 15 | 15 | # CHECK-NEXT: ] |
| 16 | 16 |
deps/lld/test/ELF/dynamic-list-wildcard.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | |
| 5 | 5 | # RUN: echo "{ foo1*; };" > %t.list |
| 6 | 6 | # RUN: ld.lld --hash-style=sysv -pie --dynamic-list %t.list %t -o %t.exe |
| 7 | # RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck %s | |
| 7 | # RUN: llvm-readobj --dyn-syms %t.exe | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | # CHECK: DynamicSymbols [ |
| 10 | 10 | # CHECK-NEXT: Symbol { |
deps/lld/test/ELF/dynamic-list.s+8-8| ... | ... | @@ -7,19 +7,19 @@ |
| 7 | 7 | ## Check exporting only one symbol. |
| 8 | 8 | # RUN: echo "{ foo1; };" > %t.list |
| 9 | 9 | # RUN: ld.lld --hash-style=sysv --dynamic-list %t.list %t %t2.so -o %t.exe |
| 10 | # RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck %s | |
| 10 | # RUN: llvm-readobj --dyn-syms %t.exe | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | ## And now using quoted strings (the output is the same since it does |
| 13 | 13 | ## use any wildcard character). |
| 14 | 14 | # RUN: echo "{ \"foo1\"; };" > %t.list |
| 15 | 15 | # RUN: ld.lld --hash-style=sysv --dynamic-list %t.list %t %t2.so -o %t.exe |
| 16 | # RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck %s | |
| 16 | # RUN: llvm-readobj --dyn-syms %t.exe | FileCheck %s | |
| 17 | 17 | |
| 18 | 18 | ## And now using --export-dynamic-symbol. |
| 19 | 19 | # RUN: ld.lld --hash-style=sysv --export-dynamic-symbol foo1 %t %t2.so -o %t.exe |
| 20 | # RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck %s | |
| 20 | # RUN: llvm-readobj --dyn-syms %t.exe | FileCheck %s | |
| 21 | 21 | # RUN: ld.lld --hash-style=sysv --export-dynamic-symbol=foo1 %t %t2.so -o %t.exe |
| 22 | # RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck %s | |
| 22 | # RUN: llvm-readobj --dyn-syms %t.exe | FileCheck %s | |
| 23 | 23 | |
| 24 | 24 | # CHECK: DynamicSymbols [ |
| 25 | 25 | # CHECK-NEXT: Symbol { |
| ... | ... | @@ -46,11 +46,11 @@ |
| 46 | 46 | ## Now export all the foo1, foo2, and foo31 symbols |
| 47 | 47 | # RUN: echo "{ foo1; foo2; foo31; };" > %t.list |
| 48 | 48 | # RUN: ld.lld --hash-style=sysv --dynamic-list %t.list %t %t2.so -o %t.exe |
| 49 | # RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=CHECK2 %s | |
| 49 | # RUN: llvm-readobj --dyn-syms %t.exe | FileCheck -check-prefix=CHECK2 %s | |
| 50 | 50 | # RUN: echo "{ foo1; foo2; };" > %t1.list |
| 51 | 51 | # RUN: echo "{ foo31; };" > %t2.list |
| 52 | 52 | # RUN: ld.lld --hash-style=sysv --dynamic-list %t1.list --dynamic-list %t2.list %t %t2.so -o %t.exe |
| 53 | # RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=CHECK2 %s | |
| 53 | # RUN: llvm-readobj --dyn-syms %t.exe | FileCheck -check-prefix=CHECK2 %s | |
| 54 | 54 | |
| 55 | 55 | # CHECK2: DynamicSymbols [ |
| 56 | 56 | # CHECK2-NEXT: Symbol { |
| ... | ... | @@ -96,11 +96,11 @@ |
| 96 | 96 | ## incomplete dynamic-list still exports everything. |
| 97 | 97 | # RUN: echo "{ foo2; };" > %t.list |
| 98 | 98 | # RUN: ld.lld --hash-style=sysv --dynamic-list %t.list --export-dynamic %t %t2.so -o %t.exe |
| 99 | # RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=CHECK3 %s | |
| 99 | # RUN: llvm-readobj --dyn-syms %t.exe | FileCheck -check-prefix=CHECK3 %s | |
| 100 | 100 | |
| 101 | 101 | ## The same with --export-dynamic-symbol. |
| 102 | 102 | # RUN: ld.lld --hash-style=sysv --export-dynamic-symbol=foo2 --export-dynamic %t %t2.so -o %t.exe |
| 103 | # RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=CHECK3 %s | |
| 103 | # RUN: llvm-readobj --dyn-syms %t.exe | FileCheck -check-prefix=CHECK3 %s | |
| 104 | 104 | |
| 105 | 105 | # CHECK3: DynamicSymbols [ |
| 106 | 106 | # CHECK3-NEXT: Symbol { |
deps/lld/test/ELF/dynamic-no-rosegment.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld -shared --no-rosegment -z rodynamic -o %t %t.o |
| 4 | # RUN: llvm-readobj -dynamic-table -s %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj --dynamic-table -S %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: DynamicSection [ (7 entries) |
| 7 | 7 | # CHECK-NEXT: Tag Type Name/Value |
deps/lld/test/ELF/dynamic-reloc-index.s+1-1| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | |
| 10 | 10 | // CHECK: Relocations [ |
| 11 | 11 | // CHECK-NEXT: Section ({{.*}}) .rela.plt { |
| 12 | // CHECK-NEXT: 0x202018 R_X86_64_JUMP_SLOT bar 0x0 | |
| 12 | // CHECK-NEXT: 0x203018 R_X86_64_JUMP_SLOT bar 0x0 | |
| 13 | 13 | // CHECK-NEXT: } |
| 14 | 14 | // CHECK-NEXT: ] |
| 15 | 15 |
deps/lld/test/ELF/dynamic-reloc.s+3-3| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/dynamic-reloc.s -o %t3.o |
| 5 | 5 | // RUN: ld.lld -shared %t2.o -o %t2.so |
| 6 | 6 | // RUN: ld.lld --hash-style=sysv %t.o %t3.o %t2.so -o %t |
| 7 | // RUN: llvm-readobj -dynamic-table -r --expand-relocs -s %t | FileCheck %s | |
| 7 | // RUN: llvm-readobj --dynamic-table -r --expand-relocs -S %t | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | // CHECK: Index: 1 |
| 10 | 10 | // CHECK-NEXT: Name: .dynsym |
| ... | ... | @@ -18,7 +18,7 @@ |
| 18 | 18 | // CHECK-NEXT: Offset: |
| 19 | 19 | // CHECK-NEXT: Size: [[RELASIZE:.*]] |
| 20 | 20 | // CHECK-NEXT: Link: 1 |
| 21 | // CHECK-NEXT: Info: 7 | |
| 21 | // CHECK-NEXT: Info: 8 | |
| 22 | 22 | // CHECK-NEXT: AddressAlignment: 8 |
| 23 | 23 | // CHECK-NEXT: EntrySize: 24 |
| 24 | 24 | |
| ... | ... | @@ -33,7 +33,7 @@ |
| 33 | 33 | // CHECK: Relocations [ |
| 34 | 34 | // CHECK-NEXT: Section ({{.*}}) .rela.plt { |
| 35 | 35 | // CHECK-NEXT: Relocation { |
| 36 | // CHECK-NEXT: Offset: 0x202018 | |
| 36 | // CHECK-NEXT: Offset: 0x203018 | |
| 37 | 37 | // CHECK-NEXT: Type: R_X86_64_JUMP_SLOT |
| 38 | 38 | // CHECK-NEXT: Symbol: bar |
| 39 | 39 | // CHECK-NEXT: Addend: 0x0 |
deps/lld/test/ELF/dynamic.s+2-2| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | ## Check that _DYNAMIC symbol is created when creating dynamic output, |
| 5 | 5 | ## and has hidden visibility and address equal to .dynamic section. |
| 6 | 6 | # RUN: ld.lld -shared %t.o -o %t.so |
| 7 | # RUN: llvm-readobj -sections -symbols %t.so | FileCheck %s | |
| 7 | # RUN: llvm-readobj --sections --symbols %t.so | FileCheck %s | |
| 8 | 8 | # CHECK: Section { |
| 9 | 9 | # CHECK: Index: 5 |
| 10 | 10 | # CHECK: Name: .dynamic |
| ... | ... | @@ -35,7 +35,7 @@ |
| 35 | 35 | # CHECK-NEXT: } |
| 36 | 36 | |
| 37 | 37 | # RUN: ld.lld %t.o -o %t2 |
| 38 | # RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=NODYN %s | |
| 38 | # RUN: llvm-readobj --sections --symbols %t2 | FileCheck -check-prefix=NODYN %s | |
| 39 | 39 | # NODYN: Symbols [ |
| 40 | 40 | # NODYN-NOT: Name: _DYNAMIC |
| 41 | 41 | # NODYN: ] |
deps/lld/test/ELF/dynsym-no-rosegment.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld -shared --no-rosegment -o %t %t.o |
| 4 | # RUN: llvm-readobj -dyn-symbols -s %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj --dyn-syms -S %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: DynamicSymbols [ |
| 7 | 7 | # CHECK-NEXT: Symbol { |
deps/lld/test/ELF/dynsym-pie.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t |
| 3 | 3 | # RUN: ld.lld -pie %t -o %t.out |
| 4 | # RUN: llvm-readobj -t -dyn-symbols %t.out | FileCheck %s | |
| 4 | # RUN: llvm-readobj --symbols --dyn-syms %t.out | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: Symbols [ |
| 7 | 7 | # CHECK: Symbol { |
deps/lld/test/ELF/edata-etext.s+1-1| ... | ... | @@ -12,7 +12,7 @@ |
| 12 | 12 | ## 3) Address of _end is different from _edata because of 2. |
| 13 | 13 | ## 4) Addresses of _edata == edata, _end == end and _etext == etext. |
| 14 | 14 | # CHECK: Sections: |
| 15 | # CHECK-NEXT: Idx Name Size Address Type | |
| 15 | # CHECK-NEXT: Idx Name Size VMA Type | |
| 16 | 16 | # CHECK-NEXT: 0 00000000 0000000000000000 |
| 17 | 17 | # CHECK-NEXT: 1 .text 00000001 0000000000201000 TEXT |
| 18 | 18 | # CHECK-NEXT: 2 .data 00000002 0000000000202000 DATA |
deps/lld/test/ELF/eh-align-cie.s+2-2| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | bar: |
| 10 | 10 | |
| 11 | 11 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 12 | // RUN: llvm-readobj -s -section-data %t.o | FileCheck --check-prefix=OBJ %s | |
| 12 | // RUN: llvm-readobj -S --section-data %t.o | FileCheck --check-prefix=OBJ %s | |
| 13 | 13 | |
| 14 | 14 | // Check the size of the CIE (0x18 + 4) an FDE (0x10 + 4) |
| 15 | 15 | // OBJ: Name: .eh_frame |
| ... | ... | @@ -32,7 +32,7 @@ bar: |
| 32 | 32 | |
| 33 | 33 | |
| 34 | 34 | // RUN: ld.lld --hash-style=sysv %t.o -o %t -shared |
| 35 | // RUN: llvm-readobj -s -section-data %t | FileCheck %s | |
| 35 | // RUN: llvm-readobj -S --section-data %t | FileCheck %s | |
| 36 | 36 | |
| 37 | 37 | // Check that the size of the CIE was changed to (0x1C + 4) and the FDE one was |
| 38 | 38 | // changed to (0x14 + 4) |
deps/lld/test/ELF/eh-frame-begin-end.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=amd64-unknown-openbsd %s -o %t.o |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=amd64-unknown-openbsd %p/Inputs/eh-frame-end.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld %t.o %t2.o -o %t |
| 5 | // RUN: llvm-readobj -sections %t | FileCheck %s | |
| 5 | // RUN: llvm-readobj --sections %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // CHECK: Name: .eh_frame |
| 8 | 8 | // CHECK-NEXT: Type: SHT_PROGBITS |
deps/lld/test/ELF/eh-frame-gc.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld -shared --gc-sections %t.o -o %t |
| 4 | # RUN: llvm-readobj -s %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj -S %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | ## Check that section containing personality is |
| 7 | 7 | ## not garbage collected. |
deps/lld/test/ELF/eh-frame-gc2.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld --gc-sections %t.o -o %t |
| 4 | // RUN: llvm-readobj -s %t | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // Test that the we don't gc the personality function. |
| 7 | 7 | // CHECK: Name: .foobar |
deps/lld/test/ELF/eh-frame-hdr-abs-fde.s+9-9| ... | ... | @@ -1,23 +1,23 @@ |
| 1 | # REQUIRES: mips | |
| 1 | # REQUIRES: x86 | |
| 2 | 2 | # Check reading PC values of FDEs and writing lookup table in the .eh_frame_hdr |
| 3 | 3 | # if CIE augmentation string has 'L' token and PC values are encoded using |
| 4 | 4 | # absolute (not relative) format. |
| 5 | 5 | |
| 6 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o | |
| 6 | # RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux %s -o %t.o | |
| 7 | 7 | # RUN: ld.lld --eh-frame-hdr %t.o -o %t |
| 8 | 8 | # RUN: llvm-objdump -s -dwarf=frames %t | FileCheck %s |
| 9 | 9 | |
| 10 | 10 | # CHECK: Contents of section .eh_frame_hdr: |
| 11 | # CHECK-NEXT: 10128 011b033b 00000010 00000001 0000fed8 | |
| 12 | # ^-- 0x20000 - 0x10138 | |
| 13 | # .text - .eh_frame_hdr | |
| 14 | # CHECK-NEXT: 10138 0000002c | |
| 11 | # CHECK-NEXT: 200190 011b033b 14000000 01000000 700e0000 | |
| 12 | # ^-- 0x201000 - 0x200190 | |
| 13 | # .text - .eh_frame_hdr | |
| 14 | # CHECK-NEXT: 2001a0 30000000 | |
| 15 | 15 | # CHECK: Contents of section .text: |
| 16 | # CHECK-NEXT: 20000 00000000 | |
| 16 | # CHECK-NEXT: 201000 90 | |
| 17 | 17 | |
| 18 | 18 | # CHECK: Augmentation: "zLR" |
| 19 | # CHECK: Augmentation data: 00 0B | |
| 20 | # ^-- DW_EH_PE_udata4 | DW_EH_PE_signed | |
| 19 | # CHECK: Augmentation data: 00 1B | |
| 20 | # ^-- DW_EH_PE_pcrel | DW_EH_PE_udata4 | DW_EH_PE_signed | |
| 21 | 21 | |
| 22 | 22 | 	.text |
| 23 | 23 | .globl __start |
deps/lld/test/ELF/eh-frame-hdr-augmentation.s+2-2| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | // CHECK-NEXT: Code alignment factor: 1 |
| 12 | 12 | // CHECK-NEXT: Data alignment factor: -8 |
| 13 | 13 | // CHECK-NEXT: Return address column: 16 |
| 14 | // CHECK-NEXT: Personality Address: 00000dad | |
| 14 | // CHECK-NEXT: Personality Address: 0000000000000dad | |
| 15 | 15 | // CHECK-NEXT: Augmentation data: |
| 16 | 16 | |
| 17 | 17 | // CHECK: DW_CFA_def_cfa: reg7 +8 |
| ... | ... | @@ -20,7 +20,7 @@ |
| 20 | 20 | // CHECK-NEXT: DW_CFA_nop: |
| 21 | 21 | |
| 22 | 22 | // CHECK: 00000020 00000014 00000024 FDE cie=00000024 pc=00000d98...00000d98 |
| 23 | // CHECK-NEXT: LSDA Address: 00000d8f | |
| 23 | // CHECK-NEXT: LSDA Address: 0000000000000d8f | |
| 24 | 24 | // CHECK-NEXT: DW_CFA_nop: |
| 25 | 25 | // CHECK-NEXT: DW_CFA_nop: |
| 26 | 26 | // CHECK-NEXT: DW_CFA_nop: |
deps/lld/test/ELF/eh-frame-hdr-icf-fde.s+1-1| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 7 | 7 | # RUN: ld.lld %t -o %t2 --icf=all --eh-frame-hdr |
| 8 | 8 | # RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=OBJ |
| 9 | # RUN: llvm-readobj -s -section-data %t2 | FileCheck %s | |
| 9 | # RUN: llvm-readobj -S --section-data %t2 | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | # OBJ: Relocations [ |
| 12 | 12 | # OBJ-NEXT: Section {{.*}} .rela.eh_frame { |
deps/lld/test/ELF/eh-frame-hdr-no-out2.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld --eh-frame-hdr %t.o -o %t |
| 4 | // RUN: llvm-readobj -s -program-headers %t | FileCheck %s --check-prefix=NOHDR | |
| 4 | // RUN: llvm-readobj -S -l %t | FileCheck %s --check-prefix=NOHDR | |
| 5 | 5 | |
| 6 | 6 | .section foo,"ax",@progbits |
| 7 | 7 | nop |
deps/lld/test/ELF/eh-frame-hdr.s+17-12| ... | ... | @@ -2,15 +2,15 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | |
| 4 | 4 | // RUN: ld.lld %t.o -o %t |
| 5 | // RUN: llvm-readobj -file-headers -s -section-data -program-headers -symbols %t \ | |
| 5 | // RUN: llvm-readobj --file-headers -S --section-data -l --symbols %t \ | |
| 6 | 6 | // RUN: | FileCheck %s --check-prefix=NOHDR |
| 7 | 7 | |
| 8 | 8 | // RUN: ld.lld -eh-frame-hdr -no-eh-frame-hdr %t.o -o %t |
| 9 | // RUN: llvm-readobj -file-headers -s -section-data -program-headers -symbols %t \ | |
| 9 | // RUN: llvm-readobj --file-headers -S --section-data -l --symbols %t \ | |
| 10 | 10 | // RUN: | FileCheck %s --check-prefix=NOHDR |
| 11 | 11 | |
| 12 | 12 | // RUN: ld.lld --eh-frame-hdr %t.o -o %t |
| 13 | // RUN: llvm-readobj -file-headers -s -section-data -program-headers -symbols %t \ | |
| 13 | // RUN: llvm-readobj --file-headers -S --section-data -l --symbols %t \ | |
| 14 | 14 | // RUN: | FileCheck %s --check-prefix=HDR |
| 15 | 15 | // RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=HDRDISASM |
| 16 | 16 | |
| ... | ... | @@ -38,15 +38,20 @@ _start: |
| 38 | 38 | // NOHDR: ProgramHeaders [ |
| 39 | 39 | // NOHDR-NOT: PT_GNU_EH_FRAME |
| 40 | 40 | |
| 41 | //HDRDISASM: Disassembly of section foo: | |
| 42 | //HDRDISASM-NEXT: foo: | |
| 43 | //HDRDISASM-NEXT: 201000: 90 nop | |
| 44 | //HDRDISASM-NEXT: Disassembly of section bar: | |
| 45 | //HDRDISASM-NEXT: bar: | |
| 46 | //HDRDISASM-NEXT: 201001: 90 nop | |
| 47 | //HDRDISASM-NEXT: Disassembly of section dah: | |
| 48 | //HDRDISASM-NEXT: dah: | |
| 49 | //HDRDISASM-NEXT: 201002: 90 nop | |
| 41 | // HDRDISASM: Disassembly of section foo: | |
| 42 | // HDRDISASM-EMPTY: | |
| 43 | // HDRDISASM-NEXT: foo: | |
| 44 | // HDRDISASM-NEXT: 201000: 90 nop | |
| 45 | // HDRDISASM-EMPTY: | |
| 46 | // HDRDISASM-NEXT: Disassembly of section bar: | |
| 47 | // HDRDISASM-EMPTY: | |
| 48 | // HDRDISASM-NEXT: bar: | |
| 49 | // HDRDISASM-NEXT: 201001: 90 nop | |
| 50 | // HDRDISASM-EMPTY: | |
| 51 | // HDRDISASM-NEXT: Disassembly of section dah: | |
| 52 | // HDRDISASM-EMPTY: | |
| 53 | // HDRDISASM-NEXT: dah: | |
| 54 | // HDRDISASM-NEXT: 201002: 90 nop | |
| 50 | 55 | |
| 51 | 56 | // HDR: Section { |
| 52 | 57 | // HDR: Index: |
deps/lld/test/ELF/eh-frame-marker.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux |
| 3 | 3 | // RUN: ld.lld --eh-frame-hdr %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -t -s %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols -S %t.so | FileCheck %s | |
| 5 | 5 | // We used to crash on this. |
| 6 | 6 | |
| 7 | 7 | // CHECK: Name: .eh_frame_hdr |
deps/lld/test/ELF/eh-frame-merge.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv %t.o %t.o -o %t -shared |
| 4 | // RUN: llvm-readobj -s -section-data %t | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S --section-data %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .section	foo,"ax",@progbits |
| 7 | 7 | 	.cfi_startproc |
deps/lld/test/ELF/eh-frame-negative-pcrel-sdata2.s+1-1| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 7 | 7 | # RUN: echo "SECTIONS { .text : { *(.text) } .eh_frame : { *(.eh_frame) } }" > %t.script |
| 8 | 8 | # RUN: ld.lld --eh-frame-hdr --script %t.script --section-start .text=0x1000 %t.o -o %t |
| 9 | # RUN: llvm-readobj -s -section-data %t | FileCheck %s | |
| 9 | # RUN: llvm-readobj -S --section-data %t | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | # CHECK: Section { |
| 12 | 12 | # CHECK: Index: |
deps/lld/test/ELF/eh-frame-negative-pcrel-sdata4.s+1-1| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 7 | 7 | # RUN: echo "SECTIONS { .text : { *(.text) } .eh_frame : { *(.eh_frame) } }" > %t.script |
| 8 | 8 | # RUN: ld.lld --eh-frame-hdr --script %t.script --section-start .text=0x1000 %t.o -o %t |
| 9 | # RUN: llvm-readobj -s -section-data %t | FileCheck %s | |
| 9 | # RUN: llvm-readobj -S --section-data %t | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | # CHECK: Section { |
| 12 | 12 | # CHECK: Index: |
deps/lld/test/ELF/eh-frame-negative-pcrel-sdata8.s+1-1| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 7 | 7 | # RUN: echo "SECTIONS { .text : { *(.text) } .eh_frame : { *(.eh_frame) } }" > %t.script |
| 8 | 8 | # RUN: ld.lld --eh-frame-hdr --script %t.script --section-start .text=0x1000 %t.o -o %t |
| 9 | # RUN: llvm-readobj -s -section-data %t | FileCheck %s | |
| 9 | # RUN: llvm-readobj -S --section-data %t | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | # CHECK: Section { |
| 12 | 12 | # CHECK: Index: |
deps/lld/test/ELF/eh-frame-padding-no-rosegment.s+3-3| ... | ... | @@ -12,7 +12,7 @@ bar: |
| 12 | 12 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 13 | 13 | |
| 14 | 14 | // Check the size of the CIE (0x18 + 4) and FDE (0x10 + 4) |
| 15 | // RUN: llvm-readobj -s -section-data %t.o | FileCheck --check-prefix=OBJ %s | |
| 15 | // RUN: llvm-readobj -S --section-data %t.o | FileCheck --check-prefix=OBJ %s | |
| 16 | 16 | |
| 17 | 17 | // OBJ: Name: .eh_frame |
| 18 | 18 | // OBJ-NEXT: Type: |
| ... | ... | @@ -35,14 +35,14 @@ bar: |
| 35 | 35 | // RUN: ld.lld --hash-style=sysv %t.o -no-rosegment -o %t -shared |
| 36 | 36 | |
| 37 | 37 | // Check that .eh_frame is in the same segment as .text |
| 38 | // RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=PHDR %s | |
| 38 | // RUN: llvm-readelf -l %t | FileCheck --check-prefix=PHDR %s | |
| 39 | 39 | |
| 40 | 40 | // PHDR: Segment Sections |
| 41 | 41 | // PHDR: .eh_frame {{.*}}.text |
| 42 | 42 | |
| 43 | 43 | // Check that the CIE and FDE are padded with 0x00 and not 0xCC when the |
| 44 | 44 | // .eh_frame section is placed in the executable segment |
| 45 | // RUN: llvm-readobj -s -section-data %t | FileCheck %s | |
| 45 | // RUN: llvm-readobj -S --section-data %t | FileCheck %s | |
| 46 | 46 | |
| 47 | 47 | // CHECK: Name: .eh_frame |
| 48 | 48 | // CHECK-NEXT: Type: |
deps/lld/test/ELF/eh-frame-type.test+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: yaml2obj %s -o %t.o |
| 2 | 2 | # RUN: ld.lld %t.o -o %t -shared |
| 3 | # RUN: llvm-readobj -s %t | FileCheck %s | |
| 3 | # RUN: llvm-readobj -S %t | FileCheck %s | |
| 4 | 4 | |
| 5 | 5 | # CHECK: Name: .eh_frame |
| 6 | 6 | # CHECK-NEXT: Type: SHT_PROGBITS |
deps/lld/test/ELF/eh-frame-value-format7.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 4 | 4 | # RUN: ld.lld --eh-frame-hdr --section-start .text=0x1000 %t.o -o %t |
| 5 | # RUN: llvm-readobj -s -section-data %t | FileCheck %s | |
| 5 | # RUN: llvm-readobj -S --section-data %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | ## Check we are able to handle DW_EH_PE_udata2 encoding. |
| 8 | 8 |
deps/lld/test/ELF/eh-frame-value-format8.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 4 | 4 | # RUN: ld.lld --eh-frame-hdr --section-start .text=0x1000 %t.o -o %t |
| 5 | # RUN: llvm-readobj -s -section-data %t | FileCheck %s | |
| 5 | # RUN: llvm-readobj -S --section-data %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | ## Check we are able to handle DW_EH_PE_absptr encoding. |
| 8 | 8 |
deps/lld/test/ELF/ehdr_start.s+2-2| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 4 | 4 | # RUN: ld.lld %t.o -o %t |
| 5 | # RUN: llvm-readobj -symbols %t | FileCheck %s | |
| 5 | # RUN: llvm-readobj --symbols %t | FileCheck %s | |
| 6 | 6 | # CHECK: Name: __ehdr_start (1) |
| 7 | 7 | # CHECK-NEXT: Value: 0x200000 |
| 8 | 8 | # CHECK-NEXT: Size: 0 |
| ... | ... | @@ -30,7 +30,7 @@ _start: |
| 30 | 30 | .quad __executable_start |
| 31 | 31 | |
| 32 | 32 | # RUN: ld.lld -r %t.o -o %t.r |
| 33 | # RUN: llvm-readobj -symbols %t.r | FileCheck %s --check-prefix=RELOCATABLE | |
| 33 | # RUN: llvm-readobj --symbols %t.r | FileCheck %s --check-prefix=RELOCATABLE | |
| 34 | 34 | |
| 35 | 35 | # RELOCATABLE: Name: __ehdr_start (1) |
| 36 | 36 | # RELOCATABLE-NEXT: Value: 0x0 |
deps/lld/test/ELF/ehframe-relocation.s+2-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/ehframe-relocation.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld %t.o %t2.o -o %t |
| 5 | // RUN: llvm-readobj -s %t | FileCheck %s | |
| 5 | // RUN: llvm-readobj -S %t | FileCheck %s | |
| 6 | 6 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s |
| 7 | 7 | |
| 8 | 8 | // CHECK: Name: .eh_frame |
| ... | ... | @@ -18,6 +18,7 @@ |
| 18 | 18 | // 0x200120 = 2097440 |
| 19 | 19 | // 0x200120 + 5 = 2097445 |
| 20 | 20 | // DISASM: Disassembly of section .text: |
| 21 | // DISASM-EMPTY: | |
| 21 | 22 | // DISASM-NEXT: _start: |
| 22 | 23 | // DISASM-NEXT: 201000: {{.*}} movq 2097440, %rax |
| 23 | 24 | // DISASM-NEXT: 201008: {{.*}} movq 2097445, %rax |
deps/lld/test/ELF/elf-header.s+2-2| ... | ... | @@ -1,10 +1,10 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld %t.o -o %t1 |
| 4 | # RUN: llvm-readobj -file-headers %t1 | FileCheck %s | |
| 4 | # RUN: llvm-readobj --file-headers %t1 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # RUN: ld.lld %t.o -no-rosegment -o %t2 |
| 7 | # RUN: llvm-readobj -file-headers %t2 | FileCheck %s | |
| 7 | # RUN: llvm-readobj --file-headers %t2 | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | # CHECK: ElfHeader { |
| 10 | 10 | # CHECK-NEXT: Ident { |
deps/lld/test/ELF/emit-relocs-merge.s+4-4| ... | ... | @@ -5,12 +5,12 @@ |
| 5 | 5 | |
| 6 | 6 | # CHECK: Relocations [ |
| 7 | 7 | # CHECK-NEXT: Section ({{.*}}) .rela.dyn { |
| 8 | # CHECK-NEXT: 0x1000 R_X86_64_64 zed 0x0 | |
| 9 | # CHECK-NEXT: 0x1008 R_X86_64_64 zed 0x0 | |
| 8 | # CHECK-NEXT: 0x2000 R_X86_64_64 zed 0x0 | |
| 9 | # CHECK-NEXT: 0x2008 R_X86_64_64 zed 0x0 | |
| 10 | 10 | # CHECK-NEXT: } |
| 11 | 11 | # CHECK-NEXT: Section ({{.*}}) .rela.data { |
| 12 | # CHECK-NEXT: 0x1000 R_X86_64_64 zed 0x0 | |
| 13 | # CHECK-NEXT: 0x1008 R_X86_64_64 zed 0x0 | |
| 12 | # CHECK-NEXT: 0x2000 R_X86_64_64 zed 0x0 | |
| 13 | # CHECK-NEXT: 0x2008 R_X86_64_64 zed 0x0 | |
| 14 | 14 | # CHECK-NEXT: } |
| 15 | 15 | # CHECK-NEXT: ] |
| 16 | 16 |
deps/lld/test/ELF/emit-relocs-mergeable-i386.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t1 |
| 3 | 3 | # RUN: ld.lld --emit-relocs %t1 -o %t2 |
| 4 | # RUN: llvm-readobj -sections -section-data %t2 | FileCheck %s | |
| 4 | # RUN: llvm-readobj --sections --section-data %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | ## Check lf we produce proper relocations when doing merging of SHF_MERGE sections. |
| 7 | 7 |
deps/lld/test/ELF/emit-relocs-mergeable.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 |
| 3 | 3 | # RUN: ld.lld --emit-relocs %t1 -o %t2 |
| 4 | # RUN: llvm-readobj -sections -section-data -r %t2 | FileCheck %s | |
| 4 | # RUN: llvm-readobj --sections --section-data -r %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | ## Check if we produce proper relocations when doing merging of SHF_MERGE sections. |
| 7 | 7 |
deps/lld/test/ELF/emit-relocs-mergeable2.s created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 3 | # RUN: ld.lld --emit-relocs %t.o -o %t.exe | |
| 4 | # RUN: llvm-readelf --relocations %t.exe | FileCheck %s | |
| 5 | ||
| 6 | # CHECK: 0000000000201004 000000010000000b R_X86_64_32S 0000000000200120 .Lfoo + 8 | |
| 7 | ||
| 8 | .globl _start | |
| 9 | _start: | |
| 10 | movq .Lfoo+8, %rax | |
| 11 | .section .rodata.cst16,"aM",@progbits,16 | |
| 12 | .Lfoo: | |
| 13 | .quad 0 | |
| 14 | .quad 0 |
deps/lld/test/ELF/emit-relocs-shared.s+2-2| ... | ... | @@ -8,9 +8,9 @@ |
| 8 | 8 | |
| 9 | 9 | # CHECK: Relocations [ |
| 10 | 10 | # CHECK-NEXT: Section {{.*}} .rela.dyn { |
| 11 | # CHECK-NEXT: 0x1000 R_X86_64_64 foo 0x0 | |
| 11 | # CHECK-NEXT: 0x2000 R_X86_64_64 foo 0x0 | |
| 12 | 12 | # CHECK-NEXT: } |
| 13 | 13 | # CHECK-NEXT: Section {{.*}} .rela.data { |
| 14 | # CHECK-NEXT: 0x1000 R_X86_64_64 foo 0x0 | |
| 14 | # CHECK-NEXT: 0x2000 R_X86_64_64 foo 0x0 | |
| 15 | 15 | # CHECK-NEXT: } |
| 16 | 16 | # CHECK-NEXT: ] |
deps/lld/test/ELF/emit-relocs.s+3-3| ... | ... | @@ -1,15 +1,15 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o |
| 3 | 3 | # RUN: ld.lld --emit-relocs %t1.o -o %t |
| 4 | # RUN: llvm-readobj -t -r -s %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj --symbols -r -S %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | ## Check single dash form. |
| 7 | 7 | # RUN: ld.lld -emit-relocs %t1.o -o %t1 |
| 8 | # RUN: llvm-readobj -t -r -s %t1 | FileCheck %s | |
| 8 | # RUN: llvm-readobj --symbols -r -S %t1 | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | ## Check alias. |
| 11 | 11 | # RUN: ld.lld -q %t1.o -o %t2 |
| 12 | # RUN: llvm-readobj -t -r -s %t2 | FileCheck %s | |
| 12 | # RUN: llvm-readobj --symbols -r -S %t2 | FileCheck %s | |
| 13 | 13 | |
| 14 | 14 | # CHECK: Section { |
| 15 | 15 | # CHECK: Index: 2 |
deps/lld/test/ELF/empty-pack-dyn-relocs.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 4 | 4 | // RUN: ld.lld -pie --pack-dyn-relocs=relr %t.o -o %t |
| 5 | // RUN: llvm-readobj -sections %t | FileCheck %s | |
| 5 | // RUN: llvm-readobj --sections %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | .global _start |
| 8 | 8 | _start: |
deps/lld/test/ELF/empty-pt-load.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -l --elf-output-style=GNU %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readelf -l %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // Test that we don't create an empty executable PT_LOAD. |
| 7 | 7 |
deps/lld/test/ELF/empty-ver.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: cd %t.dir |
| 4 | 4 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux |
| 5 | 5 | // RUN: ld.lld %t.o -o t.so -shared -version-script %p/Inputs/empty-ver.ver |
| 6 | // RUN: llvm-readobj -s -section-data -version-info t.so | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S --section-data --version-info t.so | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | // CHECK: Name: .dynstr |
| 9 | 9 | // CHECK-NEXT: Type: SHT_STRTAB |
deps/lld/test/ELF/empty-ver2.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: cd %t.dir |
| 4 | 4 | # RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux |
| 5 | 5 | # RUN: ld.lld %t.o -o t.so -shared -version-script %p/Inputs/empty-ver.ver |
| 6 | # RUN: llvm-readobj -version-info t.so | FileCheck %s | |
| 6 | # RUN: llvm-readobj --version-info t.so | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | # CHECK: Symbols [ |
| 9 | 9 | # CHECK-NEXT: Symbol { |
deps/lld/test/ELF/emulation-aarch64.s+6-6| ... | ... | @@ -1,16 +1,16 @@ |
| 1 | 1 | # REQUIRES: aarch64 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %taarch64 |
| 3 | 3 | # RUN: ld.lld -m aarch64linux %taarch64 -o %t2aarch64 |
| 4 | # RUN: llvm-readobj -file-headers %t2aarch64 | FileCheck --check-prefix=AARCH64 %s | |
| 4 | # RUN: llvm-readobj --file-headers %t2aarch64 | FileCheck --check-prefix=AARCH64 %s | |
| 5 | 5 | # RUN: ld.lld -m aarch64elf %taarch64 -o %t3aarch64 |
| 6 | # RUN: llvm-readobj -file-headers %t3aarch64 | FileCheck --check-prefix=AARCH64 %s | |
| 6 | # RUN: llvm-readobj --file-headers %t3aarch64 | FileCheck --check-prefix=AARCH64 %s | |
| 7 | 7 | # RUN: ld.lld -m aarch64_elf64_le_vec %taarch64 -o %t4aarch64 |
| 8 | # RUN: llvm-readobj -file-headers %t4aarch64 | FileCheck --check-prefix=AARCH64 %s | |
| 8 | # RUN: llvm-readobj --file-headers %t4aarch64 | FileCheck --check-prefix=AARCH64 %s | |
| 9 | 9 | # RUN: ld.lld %taarch64 -o %t5aarch64 |
| 10 | # RUN: llvm-readobj -file-headers %t5aarch64 | FileCheck --check-prefix=AARCH64 %s | |
| 10 | # RUN: llvm-readobj --file-headers %t5aarch64 | FileCheck --check-prefix=AARCH64 %s | |
| 11 | 11 | # RUN: echo 'OUTPUT_FORMAT(elf64-littleaarch64)' > %t4aarch64.script |
| 12 | 12 | # RUN: ld.lld %t4aarch64.script %taarch64 -o %t4aarch64 |
| 13 | # RUN: llvm-readobj -file-headers %t4aarch64 | FileCheck --check-prefix=AARCH64 %s | |
| 13 | # RUN: llvm-readobj --file-headers %t4aarch64 | FileCheck --check-prefix=AARCH64 %s | |
| 14 | 14 | # AARCH64: ElfHeader { |
| 15 | 15 | # AARCH64-NEXT: Ident { |
| 16 | 16 | # AARCH64-NEXT: Magic: (7F 45 4C 46) |
| ... | ... | @@ -33,7 +33,7 @@ |
| 33 | 33 | # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %taarch64fbsd |
| 34 | 34 | # RUN: echo 'OUTPUT_FORMAT(elf64-aarch64-freebsd)' > %taarch64fbsd.script |
| 35 | 35 | # RUN: ld.lld %taarch64fbsd.script %taarch64fbsd -o %t2aarch64fbsd |
| 36 | # RUN: llvm-readobj -file-headers %t2aarch64fbsd | FileCheck --check-prefix=AARCH64-FBSD %s | |
| 36 | # RUN: llvm-readobj --file-headers %t2aarch64fbsd | FileCheck --check-prefix=AARCH64-FBSD %s | |
| 37 | 37 | # AARCH64-FBSD: ElfHeader { |
| 38 | 38 | # AARCH64-FBSD-NEXT: Ident { |
| 39 | 39 | # AARCH64-FBSD-NEXT: Magic: (7F 45 4C 46) |
deps/lld/test/ELF/emulation-arm.s+4-4| ... | ... | @@ -1,14 +1,14 @@ |
| 1 | 1 | # REQUIRES: arm |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=armv7-unknown-linux %s -o %tarm |
| 3 | 3 | # RUN: ld.lld -m armelf %tarm -o %t2arm |
| 4 | # RUN: llvm-readobj -file-headers %t2arm | FileCheck --check-prefix=ARM %s | |
| 4 | # RUN: llvm-readobj --file-headers %t2arm | FileCheck --check-prefix=ARM %s | |
| 5 | 5 | # RUN: ld.lld -m armelf_linux_eabi %tarm -o %t3arm |
| 6 | # RUN: llvm-readobj -file-headers %t3arm | FileCheck --check-prefix=ARM %s | |
| 6 | # RUN: llvm-readobj --file-headers %t3arm | FileCheck --check-prefix=ARM %s | |
| 7 | 7 | # RUN: ld.lld %tarm -o %t4arm |
| 8 | # RUN: llvm-readobj -file-headers %t4arm | FileCheck --check-prefix=ARM %s | |
| 8 | # RUN: llvm-readobj --file-headers %t4arm | FileCheck --check-prefix=ARM %s | |
| 9 | 9 | # RUN: echo 'OUTPUT_FORMAT(elf32-littlearm)' > %t5arm.script |
| 10 | 10 | # RUN: ld.lld %t5arm.script %tarm -o %t5arm |
| 11 | # RUN: llvm-readobj -file-headers %t5arm | FileCheck --check-prefix=ARM %s | |
| 11 | # RUN: llvm-readobj --file-headers %t5arm | FileCheck --check-prefix=ARM %s | |
| 12 | 12 | # ARM: ElfHeader { |
| 13 | 13 | # ARM-NEXT: Ident { |
| 14 | 14 | # ARM-NEXT: Magic: (7F 45 4C 46) |
deps/lld/test/ELF/emulation-mips.s+21-21| ... | ... | @@ -1,15 +1,15 @@ |
| 1 | 1 | # REQUIRES: mips |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %tmips |
| 3 | 3 | # RUN: ld.lld -m elf32btsmip -e _start %tmips -o %t2mips |
| 4 | # RUN: llvm-readobj -file-headers %t2mips | FileCheck --check-prefix=MIPS %s | |
| 4 | # RUN: llvm-readobj --file-headers %t2mips | FileCheck --check-prefix=MIPS %s | |
| 5 | 5 | # RUN: ld.lld %tmips -e _start -o %t3mips |
| 6 | # RUN: llvm-readobj -file-headers %t3mips | FileCheck --check-prefix=MIPS %s | |
| 6 | # RUN: llvm-readobj --file-headers %t3mips | FileCheck --check-prefix=MIPS %s | |
| 7 | 7 | # RUN: echo 'OUTPUT_FORMAT(elf32-tradbigmips)' > %tmips.script |
| 8 | 8 | # RUN: ld.lld %tmips.script -e _start %tmips -o %t4mips |
| 9 | # RUN: llvm-readobj -file-headers %t4mips | FileCheck --check-prefix=MIPS %s | |
| 9 | # RUN: llvm-readobj --file-headers %t4mips | FileCheck --check-prefix=MIPS %s | |
| 10 | 10 | # RUN: echo 'OUTPUT_FORMAT(elf32-bigmips)' > %tmips2.script |
| 11 | 11 | # RUN: ld.lld %tmips2.script -e _start %tmips -o %t5mips |
| 12 | # RUN: llvm-readobj -file-headers %t5mips | FileCheck --check-prefix=MIPS %s | |
| 12 | # RUN: llvm-readobj --file-headers %t5mips | FileCheck --check-prefix=MIPS %s | |
| 13 | 13 | # MIPS: ElfHeader { |
| 14 | 14 | # MIPS-NEXT: Ident { |
| 15 | 15 | # MIPS-NEXT: Magic: (7F 45 4C 46) |
| ... | ... | @@ -34,14 +34,14 @@ |
| 34 | 34 | |
| 35 | 35 | # RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %tmipsel |
| 36 | 36 | # RUN: ld.lld -m elf32ltsmip -e _start %tmipsel -o %t2mipsel |
| 37 | # RUN: llvm-readobj -file-headers %t2mipsel | FileCheck --check-prefix=MIPSEL %s | |
| 37 | # RUN: llvm-readobj --file-headers %t2mipsel | FileCheck --check-prefix=MIPSEL %s | |
| 38 | 38 | # RUN: ld.lld -melf32ltsmip -e _start %tmipsel -o %t2mipsel |
| 39 | # RUN: llvm-readobj -file-headers %t2mipsel | FileCheck --check-prefix=MIPSEL %s | |
| 39 | # RUN: llvm-readobj --file-headers %t2mipsel | FileCheck --check-prefix=MIPSEL %s | |
| 40 | 40 | # RUN: ld.lld %tmipsel -e _start -o %t3mipsel |
| 41 | # RUN: llvm-readobj -file-headers %t3mipsel | FileCheck --check-prefix=MIPSEL %s | |
| 41 | # RUN: llvm-readobj --file-headers %t3mipsel | FileCheck --check-prefix=MIPSEL %s | |
| 42 | 42 | # RUN: echo 'OUTPUT_FORMAT(elf32-tradlittlemips)' > %tmipsel.script |
| 43 | 43 | # RUN: ld.lld %tmipsel.script -e _start %tmipsel -o %t4mipsel |
| 44 | # RUN: llvm-readobj -file-headers %t4mipsel | FileCheck --check-prefix=MIPSEL %s | |
| 44 | # RUN: llvm-readobj --file-headers %t4mipsel | FileCheck --check-prefix=MIPSEL %s | |
| 45 | 45 | # MIPSEL: ElfHeader { |
| 46 | 46 | # MIPSEL-NEXT: Ident { |
| 47 | 47 | # MIPSEL-NEXT: Magic: (7F 45 4C 46) |
| ... | ... | @@ -66,12 +66,12 @@ |
| 66 | 66 | |
| 67 | 67 | # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux-gnuabin32 %s -o %tmipsn32 |
| 68 | 68 | # RUN: ld.lld -m elf32btsmipn32 -e _start %tmipsn32 -o %t2mipsn32 |
| 69 | # RUN: llvm-readobj -file-headers %t2mipsn32 | FileCheck --check-prefix=MIPSN32 %s | |
| 69 | # RUN: llvm-readobj --file-headers %t2mipsn32 | FileCheck --check-prefix=MIPSN32 %s | |
| 70 | 70 | # RUN: ld.lld %tmipsn32 -e _start -o %t3mipsn32 |
| 71 | # RUN: llvm-readobj -file-headers %t3mipsn32 | FileCheck --check-prefix=MIPSN32 %s | |
| 71 | # RUN: llvm-readobj --file-headers %t3mipsn32 | FileCheck --check-prefix=MIPSN32 %s | |
| 72 | 72 | # RUN: echo 'OUTPUT_FORMAT(elf32-ntradbigmips)' > %tmipsn32.script |
| 73 | 73 | # RUN: ld.lld %tmipsn32.script -e _start %tmipsn32 -o %t4mipsn32 |
| 74 | # RUN: llvm-readobj -file-headers %t4mipsn32 | FileCheck --check-prefix=MIPSN32 %s | |
| 74 | # RUN: llvm-readobj --file-headers %t4mipsn32 | FileCheck --check-prefix=MIPSN32 %s | |
| 75 | 75 | # MIPSN32: ElfHeader { |
| 76 | 76 | # MIPSN32-NEXT: Ident { |
| 77 | 77 | # MIPSN32-NEXT: Magic: (7F 45 4C 46) |
| ... | ... | @@ -96,14 +96,14 @@ |
| 96 | 96 | |
| 97 | 97 | # RUN: llvm-mc -filetype=obj -triple=mips64el-unknown-linux-gnuabin32 %s -o %tmipsn32el |
| 98 | 98 | # RUN: ld.lld -m elf32ltsmipn32 -e _start %tmipsn32el -o %t2mipsn32el |
| 99 | # RUN: llvm-readobj -file-headers %t2mipsn32el | FileCheck --check-prefix=MIPSN32EL %s | |
| 99 | # RUN: llvm-readobj --file-headers %t2mipsn32el | FileCheck --check-prefix=MIPSN32EL %s | |
| 100 | 100 | # RUN: ld.lld -melf32ltsmipn32 -e _start %tmipsn32el -o %t2mipsn32el |
| 101 | # RUN: llvm-readobj -file-headers %t2mipsn32el | FileCheck --check-prefix=MIPSN32EL %s | |
| 101 | # RUN: llvm-readobj --file-headers %t2mipsn32el | FileCheck --check-prefix=MIPSN32EL %s | |
| 102 | 102 | # RUN: ld.lld %tmipsn32el -e _start -o %t3mipsn32el |
| 103 | # RUN: llvm-readobj -file-headers %t3mipsn32el | FileCheck --check-prefix=MIPSN32EL %s | |
| 103 | # RUN: llvm-readobj --file-headers %t3mipsn32el | FileCheck --check-prefix=MIPSN32EL %s | |
| 104 | 104 | # RUN: echo 'OUTPUT_FORMAT(elf32-ntradlittlemips)' > %tmipsn32el.script |
| 105 | 105 | # RUN: ld.lld %tmipsn32el.script -e _start %tmipsn32el -o %t4mipsn32el |
| 106 | # RUN: llvm-readobj -file-headers %t4mipsn32el | FileCheck --check-prefix=MIPSN32EL %s | |
| 106 | # RUN: llvm-readobj --file-headers %t4mipsn32el | FileCheck --check-prefix=MIPSN32EL %s | |
| 107 | 107 | # MIPSN32EL: ElfHeader { |
| 108 | 108 | # MIPSN32EL-NEXT: Ident { |
| 109 | 109 | # MIPSN32EL-NEXT: Magic: (7F 45 4C 46) |
| ... | ... | @@ -129,12 +129,12 @@ |
| 129 | 129 | # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -position-independent \ |
| 130 | 130 | # RUN: %s -o %tmips64 |
| 131 | 131 | # RUN: ld.lld -m elf64btsmip -e _start %tmips64 -o %t2mips64 |
| 132 | # RUN: llvm-readobj -file-headers %t2mips64 | FileCheck --check-prefix=MIPS64 %s | |
| 132 | # RUN: llvm-readobj --file-headers %t2mips64 | FileCheck --check-prefix=MIPS64 %s | |
| 133 | 133 | # RUN: ld.lld %tmips64 -e _start -o %t3mips64 |
| 134 | # RUN: llvm-readobj -file-headers %t3mips64 | FileCheck --check-prefix=MIPS64 %s | |
| 134 | # RUN: llvm-readobj --file-headers %t3mips64 | FileCheck --check-prefix=MIPS64 %s | |
| 135 | 135 | # RUN: echo 'OUTPUT_FORMAT(elf64-tradbigmips)' > %tmips64.script |
| 136 | 136 | # RUN: ld.lld %tmips64.script -e _start %tmips64 -o %t4mips64 |
| 137 | # RUN: llvm-readobj -file-headers %t4mips64 | FileCheck --check-prefix=MIPS64 %s | |
| 137 | # RUN: llvm-readobj --file-headers %t4mips64 | FileCheck --check-prefix=MIPS64 %s | |
| 138 | 138 | # MIPS64: ElfHeader { |
| 139 | 139 | # MIPS64-NEXT: Ident { |
| 140 | 140 | # MIPS64-NEXT: Magic: (7F 45 4C 46) |
| ... | ... | @@ -160,12 +160,12 @@ |
| 160 | 160 | # RUN: llvm-mc -filetype=obj -triple=mips64el-unknown-linux \ |
| 161 | 161 | # RUN: -position-independent %s -o %tmips64el |
| 162 | 162 | # RUN: ld.lld -m elf64ltsmip -e _start %tmips64el -o %t2mips64el |
| 163 | # RUN: llvm-readobj -file-headers %t2mips64el | FileCheck --check-prefix=MIPS64EL %s | |
| 163 | # RUN: llvm-readobj --file-headers %t2mips64el | FileCheck --check-prefix=MIPS64EL %s | |
| 164 | 164 | # RUN: ld.lld %tmips64el -e _start -o %t3mips64el |
| 165 | # RUN: llvm-readobj -file-headers %t3mips64el | FileCheck --check-prefix=MIPS64EL %s | |
| 165 | # RUN: llvm-readobj --file-headers %t3mips64el | FileCheck --check-prefix=MIPS64EL %s | |
| 166 | 166 | # RUN: echo 'OUTPUT_FORMAT(elf64-tradlittlemips)' > %tmips64el.script |
| 167 | 167 | # RUN: ld.lld %tmips64el.script -e _start %tmips64el -o %t4mips64el |
| 168 | # RUN: llvm-readobj -file-headers %t4mips64el | FileCheck --check-prefix=MIPS64EL %s | |
| 168 | # RUN: llvm-readobj --file-headers %t4mips64el | FileCheck --check-prefix=MIPS64EL %s | |
| 169 | 169 | # MIPS64EL: ElfHeader { |
| 170 | 170 | # MIPS64EL-NEXT: Ident { |
| 171 | 171 | # MIPS64EL-NEXT: Magic: (7F 45 4C 46) |
deps/lld/test/ELF/emulation-ppc.s+11-11| ... | ... | @@ -1,12 +1,12 @@ |
| 1 | 1 | # REQUIRES: ppc |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %tppc64 |
| 3 | 3 | # RUN: ld.lld -m elf64ppc %tppc64 -o %t2ppc64 |
| 4 | # RUN: llvm-readobj -file-headers %t2ppc64 | FileCheck --check-prefix=PPC64 %s | |
| 4 | # RUN: llvm-readobj --file-headers %t2ppc64 | FileCheck --check-prefix=PPC64 %s | |
| 5 | 5 | # RUN: ld.lld %tppc64 -o %t3ppc64 |
| 6 | # RUN: llvm-readobj -file-headers %t3ppc64 | FileCheck --check-prefix=PPC64 %s | |
| 6 | # RUN: llvm-readobj --file-headers %t3ppc64 | FileCheck --check-prefix=PPC64 %s | |
| 7 | 7 | # RUN: echo 'OUTPUT_FORMAT(elf64-powerpc)' > %tppc64.script |
| 8 | 8 | # RUN: ld.lld %tppc64.script %tppc64 -o %t4ppc64 |
| 9 | # RUN: llvm-readobj -file-headers %t4ppc64 | FileCheck --check-prefix=PPC64 %s | |
| 9 | # RUN: llvm-readobj --file-headers %t4ppc64 | FileCheck --check-prefix=PPC64 %s | |
| 10 | 10 | |
| 11 | 11 | # PPC64: ElfHeader { |
| 12 | 12 | # PPC64-NEXT: Ident { |
| ... | ... | @@ -38,7 +38,7 @@ |
| 38 | 38 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-freebsd %s -o %tppc64fbsd |
| 39 | 39 | # RUN: echo 'OUTPUT_FORMAT(elf64-powerpc-freebsd)' > %tppc64fbsd.script |
| 40 | 40 | # RUN: ld.lld %tppc64fbsd.script %tppc64fbsd -o %t2ppc64fbsd |
| 41 | # RUN: llvm-readobj -file-headers %t2ppc64fbsd | FileCheck --check-prefix=PPC64-FBSD %s | |
| 41 | # RUN: llvm-readobj --file-headers %t2ppc64fbsd | FileCheck --check-prefix=PPC64-FBSD %s | |
| 42 | 42 | |
| 43 | 43 | # PPC64-FBSD: ElfHeader { |
| 44 | 44 | # PPC64-FBSD-NEXT: Ident { |
| ... | ... | @@ -69,12 +69,12 @@ |
| 69 | 69 | |
| 70 | 70 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %tppc64le |
| 71 | 71 | # RUN: ld.lld -m elf64lppc %tppc64le -o %t2ppc64le |
| 72 | # RUN: llvm-readobj -file-headers %t2ppc64le | FileCheck --check-prefix=PPC64LE %s | |
| 72 | # RUN: llvm-readobj --file-headers %t2ppc64le | FileCheck --check-prefix=PPC64LE %s | |
| 73 | 73 | # RUN: ld.lld %tppc64le -o %t3ppc64le |
| 74 | # RUN: llvm-readobj -file-headers %t3ppc64le | FileCheck --check-prefix=PPC64LE %s | |
| 74 | # RUN: llvm-readobj --file-headers %t3ppc64le | FileCheck --check-prefix=PPC64LE %s | |
| 75 | 75 | # RUN: echo 'OUTPUT_FORMAT(elf64-powerpcle)' > %tppc64le.script |
| 76 | 76 | # RUN: ld.lld %tppc64le.script %tppc64le -o %t4ppc64le |
| 77 | # RUN: llvm-readobj -file-headers %t4ppc64le | FileCheck --check-prefix=PPC64LE %s | |
| 77 | # RUN: llvm-readobj --file-headers %t4ppc64le | FileCheck --check-prefix=PPC64LE %s | |
| 78 | 78 | |
| 79 | 79 | # PPC64LE: ElfHeader { |
| 80 | 80 | # PPC64LE-NEXT: Ident { |
| ... | ... | @@ -105,14 +105,14 @@ |
| 105 | 105 | |
| 106 | 106 | # RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-linux %s -o %tppc32 |
| 107 | 107 | # RUN: ld.lld -m elf32ppc %tppc32 -o %t2ppc32 |
| 108 | # RUN: llvm-readobj -file-headers %t2ppc32 | FileCheck --check-prefix=PPC32 %s | |
| 108 | # RUN: llvm-readobj --file-headers %t2ppc32 | FileCheck --check-prefix=PPC32 %s | |
| 109 | 109 | # RUN: ld.lld %tppc32 -o %t3ppc32 |
| 110 | # RUN: llvm-readobj -file-headers %t3ppc32 | FileCheck --check-prefix=PPC32 %s | |
| 110 | # RUN: llvm-readobj --file-headers %t3ppc32 | FileCheck --check-prefix=PPC32 %s | |
| 111 | 111 | # RUN: echo 'OUTPUT_FORMAT(elf32-powerpc)' > %tppc32.script |
| 112 | 112 | # RUN: ld.lld %tppc32.script %tppc32 -o %t4ppc32 |
| 113 | # RUN: llvm-readobj -file-headers %t4ppc32 | FileCheck --check-prefix=PPC32 %s | |
| 113 | # RUN: llvm-readobj --file-headers %t4ppc32 | FileCheck --check-prefix=PPC32 %s | |
| 114 | 114 | # RUN: ld.lld -m elf32ppclinux %tppc32 -o %t5ppc32 |
| 115 | # RUN: llvm-readobj -file-headers %t5ppc32 | FileCheck --check-prefix=PPC32 %s | |
| 115 | # RUN: llvm-readobj --file-headers %t5ppc32 | FileCheck --check-prefix=PPC32 %s | |
| 116 | 116 | |
| 117 | 117 | # PPC32: ElfHeader { |
| 118 | 118 | # PPC32-NEXT: Ident { |
deps/lld/test/ELF/emulation-riscv.s created+74| ... | ... | @@ -0,0 +1,74 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.o | |
| 4 | # RUN: ld.lld %t.o -o %t | |
| 5 | # RUN: llvm-readobj --file-headers %t | FileCheck --check-prefix=RV32 %s | |
| 6 | # RUN: ld.lld -m elf32lriscv %t.o -o %t | |
| 7 | # RUN: llvm-readobj --file-headers %t | FileCheck --check-prefix=RV32 %s | |
| 8 | # RUN: echo 'OUTPUT_FORMAT(elf32-littleriscv)' > %t.script | |
| 9 | # RUN: ld.lld %t.script %t.o -o %t | |
| 10 | # RUN: llvm-readobj --file-headers %t | FileCheck --check-prefix=RV32 %s | |
| 11 | ||
| 12 | # RV32: ElfHeader { | |
| 13 | # RV32-NEXT: Ident { | |
| 14 | # RV32-NEXT: Magic: (7F 45 4C 46) | |
| 15 | # RV32-NEXT: Class: 32-bit (0x1) | |
| 16 | # RV32-NEXT: DataEncoding: LittleEndian (0x1) | |
| 17 | # RV32-NEXT: FileVersion: 1 | |
| 18 | # RV32-NEXT: OS/ABI: SystemV (0x0) | |
| 19 | # RV32-NEXT: ABIVersion: 0 | |
| 20 | # RV32-NEXT: Unused: (00 00 00 00 00 00 00) | |
| 21 | # RV32-NEXT: } | |
| 22 | # RV32-NEXT: Type: Executable (0x2) | |
| 23 | # RV32-NEXT: Machine: EM_RISCV (0xF3) | |
| 24 | # RV32-NEXT: Version: 1 | |
| 25 | # RV32-NEXT: Entry: | |
| 26 | # RV32-NEXT: ProgramHeaderOffset: 0x34 | |
| 27 | # RV32-NEXT: SectionHeaderOffset: | |
| 28 | # RV32-NEXT: Flags [ (0x0) | |
| 29 | # RV32-NEXT: ] | |
| 30 | # RV32-NEXT: HeaderSize: 52 | |
| 31 | # RV32-NEXT: ProgramHeaderEntrySize: 32 | |
| 32 | # RV32-NEXT: ProgramHeaderCount: | |
| 33 | # RV32-NEXT: SectionHeaderEntrySize: 40 | |
| 34 | # RV32-NEXT: SectionHeaderCount: | |
| 35 | # RV32-NEXT: StringTableSectionIndex: | |
| 36 | # RV32-NEXT: } | |
| 37 | ||
| 38 | # RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.o | |
| 39 | # RUN: ld.lld %t.o -o %t | |
| 40 | # RUN: llvm-readobj --file-headers %t | FileCheck --check-prefix=RV64 %s | |
| 41 | # RUN: ld.lld -m elf64lriscv %t.o -o %t | |
| 42 | # RUN: llvm-readobj --file-headers %t | FileCheck --check-prefix=RV64 %s | |
| 43 | # RUN: echo 'OUTPUT_FORMAT(elf64-littleriscv)' > %t.script | |
| 44 | # RUN: ld.lld %t.script %t.o -o %t | |
| 45 | # RUN: llvm-readobj --file-headers %t | FileCheck --check-prefix=RV64 %s | |
| 46 | ||
| 47 | # RV64: ElfHeader { | |
| 48 | # RV64-NEXT: Ident { | |
| 49 | # RV64-NEXT: Magic: (7F 45 4C 46) | |
| 50 | # RV64-NEXT: Class: 64-bit (0x2) | |
| 51 | # RV64-NEXT: DataEncoding: LittleEndian (0x1) | |
| 52 | # RV64-NEXT: FileVersion: 1 | |
| 53 | # RV64-NEXT: OS/ABI: SystemV (0x0) | |
| 54 | # RV64-NEXT: ABIVersion: 0 | |
| 55 | # RV64-NEXT: Unused: (00 00 00 00 00 00 00) | |
| 56 | # RV64-NEXT: } | |
| 57 | # RV64-NEXT: Type: Executable (0x2) | |
| 58 | # RV64-NEXT: Machine: EM_RISCV (0xF3) | |
| 59 | # RV64-NEXT: Version: 1 | |
| 60 | # RV64-NEXT: Entry: | |
| 61 | # RV64-NEXT: ProgramHeaderOffset: 0x40 | |
| 62 | # RV64-NEXT: SectionHeaderOffset: | |
| 63 | # RV64-NEXT: Flags [ (0x0) | |
| 64 | # RV64-NEXT: ] | |
| 65 | # RV64-NEXT: HeaderSize: 64 | |
| 66 | # RV64-NEXT: ProgramHeaderEntrySize: 56 | |
| 67 | # RV64-NEXT: ProgramHeaderCount: | |
| 68 | # RV64-NEXT: SectionHeaderEntrySize: 64 | |
| 69 | # RV64-NEXT: SectionHeaderCount: | |
| 70 | # RV64-NEXT: StringTableSectionIndex: | |
| 71 | # RV64-NEXT: } | |
| 72 | ||
| 73 | .globl _start | |
| 74 | _start: |
deps/lld/test/ELF/emulation-x86.s+19-19| ... | ... | @@ -1,15 +1,15 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %tx64 |
| 3 | 3 | # RUN: ld.lld -m elf_amd64_fbsd %tx64 -o %t2x64 |
| 4 | # RUN: llvm-readobj -file-headers %t2x64 | FileCheck --check-prefix=AMD64 %s | |
| 4 | # RUN: llvm-readobj --file-headers %t2x64 | FileCheck --check-prefix=AMD64 %s | |
| 5 | 5 | # RUN: ld.lld %tx64 -o %t3x64 |
| 6 | # RUN: llvm-readobj -file-headers %t3x64 | FileCheck --check-prefix=AMD64 %s | |
| 6 | # RUN: llvm-readobj --file-headers %t3x64 | FileCheck --check-prefix=AMD64 %s | |
| 7 | 7 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.sysv |
| 8 | 8 | # RUN: ld.lld -m elf_amd64_fbsd %t.sysv -o %t.freebsd |
| 9 | # RUN: llvm-readobj -file-headers %t.freebsd | FileCheck --check-prefix=AMD64 %s | |
| 9 | # RUN: llvm-readobj --file-headers %t.freebsd | FileCheck --check-prefix=AMD64 %s | |
| 10 | 10 | # RUN: echo 'OUTPUT_FORMAT(elf64-x86-64-freebsd)' > %t4x64.script |
| 11 | 11 | # RUN: ld.lld %t4x64.script %tx64 -o %t4x64 |
| 12 | # RUN: llvm-readobj -file-headers %t4x64 | FileCheck --check-prefix=AMD64 %s | |
| 12 | # RUN: llvm-readobj --file-headers %t4x64 | FileCheck --check-prefix=AMD64 %s | |
| 13 | 13 | # AMD64: ElfHeader { |
| 14 | 14 | # AMD64-NEXT: Ident { |
| 15 | 15 | # AMD64-NEXT: Magic: (7F 45 4C 46) |
| ... | ... | @@ -38,13 +38,13 @@ |
| 38 | 38 | |
| 39 | 39 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tx64 |
| 40 | 40 | # RUN: ld.lld -m elf_x86_64 %tx64 -o %t2x64 |
| 41 | # RUN: llvm-readobj -file-headers %t2x64 | FileCheck --check-prefix=X86-64 %s | |
| 41 | # RUN: llvm-readobj --file-headers %t2x64 | FileCheck --check-prefix=X86-64 %s | |
| 42 | 42 | # RUN: ld.lld %tx64 -o %t3x64 |
| 43 | # RUN: llvm-readobj -file-headers %t3x64 | FileCheck --check-prefix=X86-64 %s | |
| 43 | # RUN: llvm-readobj --file-headers %t3x64 | FileCheck --check-prefix=X86-64 %s | |
| 44 | 44 | # RUN: echo 'OUTPUT_FORMAT(elf64-x86-64)' > %t4x64.script |
| 45 | 45 | # RUN: ld.lld %t4x64.script %tx64 -o %t4x64 |
| 46 | 46 | # RUN: ld.lld %tx64 -o %t4x64 %t4x64.script |
| 47 | # RUN: llvm-readobj -file-headers %t4x64 | FileCheck --check-prefix=X86-64 %s | |
| 47 | # RUN: llvm-readobj --file-headers %t4x64 | FileCheck --check-prefix=X86-64 %s | |
| 48 | 48 | # X86-64: ElfHeader { |
| 49 | 49 | # X86-64-NEXT: Ident { |
| 50 | 50 | # X86-64-NEXT: Magic: (7F 45 4C 46) |
| ... | ... | @@ -73,12 +73,12 @@ |
| 73 | 73 | |
| 74 | 74 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux-gnux32 %s -o %tx32 |
| 75 | 75 | # RUN: ld.lld -m elf32_x86_64 %tx32 -o %t2x32 |
| 76 | # RUN: llvm-readobj -file-headers %t2x32 | FileCheck --check-prefix=X32 %s | |
| 76 | # RUN: llvm-readobj --file-headers %t2x32 | FileCheck --check-prefix=X32 %s | |
| 77 | 77 | # RUN: ld.lld %tx32 -o %t3x32 |
| 78 | # RUN: llvm-readobj -file-headers %t3x32 | FileCheck --check-prefix=X32 %s | |
| 78 | # RUN: llvm-readobj --file-headers %t3x32 | FileCheck --check-prefix=X32 %s | |
| 79 | 79 | # RUN: echo 'OUTPUT_FORMAT(elf32-x86-64)' > %t4x32.script |
| 80 | 80 | # RUN: ld.lld %t4x32.script %tx32 -o %t4x32 |
| 81 | # RUN: llvm-readobj -file-headers %t4x32 | FileCheck --check-prefix=X32 %s | |
| 81 | # RUN: llvm-readobj --file-headers %t4x32 | FileCheck --check-prefix=X32 %s | |
| 82 | 82 | # X32: ElfHeader { |
| 83 | 83 | # X32-NEXT: Ident { |
| 84 | 84 | # X32-NEXT: Magic: (7F 45 4C 46) |
| ... | ... | @@ -107,12 +107,12 @@ |
| 107 | 107 | |
| 108 | 108 | # RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %tx86 |
| 109 | 109 | # RUN: ld.lld -m elf_i386 %tx86 -o %t2x86 |
| 110 | # RUN: llvm-readobj -file-headers %t2x86 | FileCheck --check-prefix=X86 %s | |
| 110 | # RUN: llvm-readobj --file-headers %t2x86 | FileCheck --check-prefix=X86 %s | |
| 111 | 111 | # RUN: ld.lld %tx86 -o %t3x86 |
| 112 | # RUN: llvm-readobj -file-headers %t3x86 | FileCheck --check-prefix=X86 %s | |
| 112 | # RUN: llvm-readobj --file-headers %t3x86 | FileCheck --check-prefix=X86 %s | |
| 113 | 113 | # RUN: echo 'OUTPUT_FORMAT(elf32-i386)' > %t4x86.script |
| 114 | 114 | # RUN: ld.lld %t4x86.script %tx86 -o %t4x86 |
| 115 | # RUN: llvm-readobj -file-headers %t4x86 | FileCheck --check-prefix=X86 %s | |
| 115 | # RUN: llvm-readobj --file-headers %t4x86 | FileCheck --check-prefix=X86 %s | |
| 116 | 116 | # X86: ElfHeader { |
| 117 | 117 | # X86-NEXT: Ident { |
| 118 | 118 | # X86-NEXT: Magic: (7F 45 4C 46) |
| ... | ... | @@ -141,12 +141,12 @@ |
| 141 | 141 | |
| 142 | 142 | # RUN: llvm-mc -filetype=obj -triple=i686-unknown-freebsd %s -o %tx86fbsd |
| 143 | 143 | # RUN: ld.lld -m elf_i386_fbsd %tx86fbsd -o %t2x86fbsd |
| 144 | # RUN: llvm-readobj -file-headers %t2x86fbsd | FileCheck --check-prefix=X86FBSD %s | |
| 144 | # RUN: llvm-readobj --file-headers %t2x86fbsd | FileCheck --check-prefix=X86FBSD %s | |
| 145 | 145 | # RUN: ld.lld %tx86fbsd -o %t3x86fbsd |
| 146 | # RUN: llvm-readobj -file-headers %t3x86fbsd | FileCheck --check-prefix=X86FBSD %s | |
| 146 | # RUN: llvm-readobj --file-headers %t3x86fbsd | FileCheck --check-prefix=X86FBSD %s | |
| 147 | 147 | # RUN: echo 'OUTPUT_FORMAT(elf32-i386-freebsd)' > %t4x86fbsd.script |
| 148 | 148 | # RUN: ld.lld %t4x86fbsd.script %tx86fbsd -o %t4x86fbsd |
| 149 | # RUN: llvm-readobj -file-headers %t4x86fbsd | FileCheck --check-prefix=X86FBSD %s | |
| 149 | # RUN: llvm-readobj --file-headers %t4x86fbsd | FileCheck --check-prefix=X86FBSD %s | |
| 150 | 150 | # X86FBSD: ElfHeader { |
| 151 | 151 | # X86FBSD-NEXT: Ident { |
| 152 | 152 | # X86FBSD-NEXT: Magic: (7F 45 4C 46) |
| ... | ... | @@ -175,12 +175,12 @@ |
| 175 | 175 | |
| 176 | 176 | # RUN: llvm-mc -filetype=obj -triple=i586-intel-elfiamcu %s -o %tiamcu |
| 177 | 177 | # RUN: ld.lld -m elf_iamcu %tiamcu -o %t2iamcu |
| 178 | # RUN: llvm-readobj -file-headers %t2iamcu | FileCheck --check-prefix=IAMCU %s | |
| 178 | # RUN: llvm-readobj --file-headers %t2iamcu | FileCheck --check-prefix=IAMCU %s | |
| 179 | 179 | # RUN: ld.lld %tiamcu -o %t3iamcu |
| 180 | # RUN: llvm-readobj -file-headers %t3iamcu | FileCheck --check-prefix=IAMCU %s | |
| 180 | # RUN: llvm-readobj --file-headers %t3iamcu | FileCheck --check-prefix=IAMCU %s | |
| 181 | 181 | # RUN: echo 'OUTPUT_FORMAT(elf32-iamcu)' > %t4iamcu.script |
| 182 | 182 | # RUN: ld.lld %t4iamcu.script %tiamcu -o %t4iamcu |
| 183 | # RUN: llvm-readobj -file-headers %t4iamcu | FileCheck --check-prefix=IAMCU %s | |
| 183 | # RUN: llvm-readobj --file-headers %t4iamcu | FileCheck --check-prefix=IAMCU %s | |
| 184 | 184 | # IAMCU: ElfHeader { |
| 185 | 185 | # IAMCU-NEXT: Ident { |
| 186 | 186 | # IAMCU-NEXT: Magic: (7F 45 4C 46) |
deps/lld/test/ELF/end-update.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | |
| 4 | 4 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 5 | 5 | // RUN: ld.lld %t.o -o %t |
| 6 | // RUN: llvm-readobj -sections -symbols %t | FileCheck %s | |
| 6 | // RUN: llvm-readobj --sections --symbols %t | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | // CHECK: Sections [ |
| 9 | 9 | // CHECK: Name: .bss |
deps/lld/test/ELF/end.s+1-1| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | |
| 6 | 6 | // By default, the .bss section is the latest section of the data segment. |
| 7 | 7 | // RUN: ld.lld %t.o -o %t |
| 8 | // RUN: llvm-readobj -sections -symbols %t | FileCheck %s --check-prefix=DEFAULT | |
| 8 | // RUN: llvm-readobj --sections --symbols %t | FileCheck %s --check-prefix=DEFAULT | |
| 9 | 9 | |
| 10 | 10 | // DEFAULT: Sections [ |
| 11 | 11 | // DEFAULT: Name: .bss |
deps/lld/test/ELF/entry.s+7-7| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 |
| 3 | 3 | |
| 4 | 4 | # RUN: ld.lld -e foobar %t1 -o %t2 2>&1 | FileCheck -check-prefix=WARN1 %s |
| 5 | # RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=TEXT %s | |
| 5 | # RUN: llvm-readobj --file-headers %t2 | FileCheck -check-prefix=TEXT %s | |
| 6 | 6 | |
| 7 | 7 | # WARN1: warning: cannot find entry symbol foobar; defaulting to 0x201000 |
| 8 | 8 | # TEXT: Entry: 0x201000 |
| ... | ... | @@ -19,7 +19,7 @@ |
| 19 | 19 | # RUN: echo .data > %t.s |
| 20 | 20 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux -n %t.s -o %t3 |
| 21 | 21 | # RUN: ld.lld %t3 -o %t4 2>&1 | FileCheck -check-prefix=WARN4 %s |
| 22 | # RUN: llvm-readobj -file-headers %t4 | FileCheck -check-prefix=NOENTRY %s | |
| 22 | # RUN: llvm-readobj --file-headers %t4 | FileCheck -check-prefix=NOENTRY %s | |
| 23 | 23 | |
| 24 | 24 | # WARN4: cannot find entry symbol _start; not setting start address |
| 25 | 25 | # NOENTRY: Entry: 0x0 |
| ... | ... | @@ -28,23 +28,23 @@ |
| 28 | 28 | # WARN5-NOT: warning: cannot find entry symbol |
| 29 | 29 | |
| 30 | 30 | # RUN: ld.lld %t1 -o %t2 -e entry |
| 31 | # RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=SYM %s | |
| 31 | # RUN: llvm-readobj --file-headers %t2 | FileCheck -check-prefix=SYM %s | |
| 32 | 32 | # SYM: Entry: 0x201008 |
| 33 | 33 | |
| 34 | 34 | # RUN: ld.lld %t1 --fatal-warnings -shared -o %t2 -e entry |
| 35 | # RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=DSO %s | |
| 35 | # RUN: llvm-readobj --file-headers %t2 | FileCheck -check-prefix=DSO %s | |
| 36 | 36 | # DSO: Entry: 0x1008 |
| 37 | 37 | |
| 38 | 38 | # RUN: ld.lld %t1 -o %t2 --entry=4096 |
| 39 | # RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=DEC %s | |
| 39 | # RUN: llvm-readobj --file-headers %t2 | FileCheck -check-prefix=DEC %s | |
| 40 | 40 | # DEC: Entry: 0x1000 |
| 41 | 41 | |
| 42 | 42 | # RUN: ld.lld %t1 -o %t2 --entry 0xcafe |
| 43 | # RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=HEX %s | |
| 43 | # RUN: llvm-readobj --file-headers %t2 | FileCheck -check-prefix=HEX %s | |
| 44 | 44 | # HEX: Entry: 0xCAFE |
| 45 | 45 | |
| 46 | 46 | # RUN: ld.lld %t1 -o %t2 -e 0777 |
| 47 | # RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=OCT %s | |
| 47 | # RUN: llvm-readobj --file-headers %t2 | FileCheck -check-prefix=OCT %s | |
| 48 | 48 | # OCT: Entry: 0x1FF |
| 49 | 49 | |
| 50 | 50 | .globl entry |
deps/lld/test/ELF/exclude-discarded-error.s created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | # RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s | |
| 4 | ||
| 5 | # CHECK: error: relocation refers to a symbol in a discarded section: foo | |
| 6 | # CHECK-NEXT: >>> defined in {{.*}}.o | |
| 7 | # CHECK-NEXT: >>> referenced by {{.*}}.o:(.text+0x1) | |
| 8 | ||
| 9 | .globl _start | |
| 10 | _start: | |
| 11 | jmp foo | |
| 12 | ||
| 13 | .section .foo,"ae" | |
| 14 | .globl foo | |
| 15 | foo: |
deps/lld/test/ELF/exclude-discarded-error2.s created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | # RUN: echo '.section .foo,"ae"; .weak foo; foo:' | \ | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o | |
| 5 | # RUN: not ld.lld %t.o %t1.o -o /dev/null 2>&1 | FileCheck %s | |
| 6 | ||
| 7 | # Because foo defined in %t1.o is weak, it does not override global undefined | |
| 8 | # in %t.o | |
| 9 | # CHECK-NOT: discarded section | |
| 10 | # CHECK: undefined symbol: foo | |
| 11 | ||
| 12 | .globl _start | |
| 13 | _start: | |
| 14 | jmp foo |
deps/lld/test/ELF/exclude-libs.s+8-8| ... | ... | @@ -9,28 +9,28 @@ |
| 9 | 9 | // RUN: llvm-ar rcs %t.dir/exc.a %t2.o %t3.o |
| 10 | 10 | |
| 11 | 11 | // RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe |
| 12 | // RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=DEFAULT %s | |
| 12 | // RUN: llvm-readobj --dyn-syms %t.exe | FileCheck --check-prefix=DEFAULT %s | |
| 13 | 13 | |
| 14 | 14 | // RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs=foo,bar |
| 15 | // RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=DEFAULT %s | |
| 15 | // RUN: llvm-readobj --dyn-syms %t.exe | FileCheck --check-prefix=DEFAULT %s | |
| 16 | 16 | |
| 17 | 17 | // RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs foo,bar,exc.a |
| 18 | // RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s | |
| 18 | // RUN: llvm-readobj --dyn-syms %t.exe | FileCheck --check-prefix=EXCLUDE %s | |
| 19 | 19 | |
| 20 | 20 | // RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs foo:bar:exc.a |
| 21 | // RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s | |
| 21 | // RUN: llvm-readobj --dyn-syms %t.exe | FileCheck --check-prefix=EXCLUDE %s | |
| 22 | 22 | |
| 23 | 23 | // RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs=ALL |
| 24 | // RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s | |
| 24 | // RUN: llvm-readobj --dyn-syms %t.exe | FileCheck --check-prefix=EXCLUDE %s | |
| 25 | 25 | |
| 26 | 26 | // RUN: ld.lld -shared %t.o %t2.o %t3.o %t.dir/exc.a -o %t.exe --exclude-libs=ALL |
| 27 | // RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=DEFAULT %s | |
| 27 | // RUN: llvm-readobj --dyn-syms %t.exe | FileCheck --check-prefix=DEFAULT %s | |
| 28 | 28 | |
| 29 | 29 | // RUN: ld.lld -shared --whole-archive %t.o %t.dir/exc.a -o %t.exe --exclude-libs foo,bar,exc.a |
| 30 | // RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s | |
| 30 | // RUN: llvm-readobj --dyn-syms %t.exe | FileCheck --check-prefix=EXCLUDE %s | |
| 31 | 31 | |
| 32 | 32 | // RUN: ld.lld -shared --whole-archive %t.o %t.dir/exc.a -o %t.exe --exclude-libs=ALL |
| 33 | // RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s | |
| 33 | // RUN: llvm-readobj --dyn-syms %t.exe | FileCheck --check-prefix=EXCLUDE %s | |
| 34 | 34 | |
| 35 | 35 | // DEFAULT: Name: fn |
| 36 | 36 | // DEFAULT: Name: fn2 |
deps/lld/test/ELF/executable-undefined-ignoreall.s+1-1| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | |
| 6 | 6 | # CHECK: Relocations [ |
| 7 | 7 | # CHECK-NEXT: Section ({{.*}}) .rela.plt { |
| 8 | # CHECK-NEXT: 0x2018 R_X86_64_JUMP_SLOT foo 0x0 | |
| 8 | # CHECK-NEXT: 0x3018 R_X86_64_JUMP_SLOT foo 0x0 | |
| 9 | 9 | # CHECK-NEXT: } |
| 10 | 10 | # CHECK-NEXT: ] |
| 11 | 11 |
deps/lld/test/ELF/executable-undefined-protected-ignoreall.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | # RUN: not ld.lld %t -o /dev/null --unresolved-symbols=ignore-all -pie 2>&1 | FileCheck %s |
| 4 | # CHECK: error: undefined symbol: foo | |
| 4 | # CHECK: error: undefined protected symbol: foo | |
| 5 | 5 | |
| 6 | 6 | .protected foo |
| 7 | 7 | _start: |
deps/lld/test/ELF/fill-trap-ppc.s+2-2| ... | ... | @@ -2,12 +2,12 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-linux %s -o %t.o |
| 4 | 4 | # RUN: ld.lld %t.o -o %t.ppc64le |
| 5 | # RUN: llvm-readobj -program-headers %t.ppc64le | FileCheck %s | |
| 5 | # RUN: llvm-readobj -l %t.ppc64le | FileCheck %s | |
| 6 | 6 | # RUN: od -Ax -t x1 -N16 -j0x10ff0 %t.ppc64le | FileCheck %s -check-prefix=LE |
| 7 | 7 | |
| 8 | 8 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-linux %s -o %t.o |
| 9 | 9 | # RUN: ld.lld %t.o -o %t.ppc64 |
| 10 | # RUN: llvm-readobj -program-headers %t.ppc64 | FileCheck %s | |
| 10 | # RUN: llvm-readobj -l %t.ppc64 | FileCheck %s | |
| 11 | 11 | # RUN: od -Ax -t x1 -N16 -j0x10ff0 %t.ppc64 | FileCheck %s -check-prefix=BE |
| 12 | 12 | |
| 13 | 13 | # CHECK: ProgramHeader { |
deps/lld/test/ELF/fill-trap.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 4 | 4 | # RUN: ld.lld %t -o %t2 |
| 5 | # RUN: llvm-readobj -program-headers %t2 | FileCheck %s | |
| 5 | # RUN: llvm-readobj -l %t2 | FileCheck %s | |
| 6 | 6 | # RUN: od -Ax -x -N16 -j0x1ff0 %t2 | FileCheck %s -check-prefix=FILL |
| 7 | 7 | |
| 8 | 8 | # CHECK: ProgramHeader { |
deps/lld/test/ELF/format-binary-non-ascii.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t£.o |
| 3 | 3 | |
| 4 | 4 | # RUN: ld.lld -o %t.elf %t£.o --format=binary %t£.o |
| 5 | # RUN: llvm-readobj -symbols %t.elf | FileCheck %s | |
| 5 | # RUN: llvm-readobj --symbols %t.elf | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp_{{[_]+}}o_start |
| 8 | 8 | # CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp_{{[_]+}}o_end |
deps/lld/test/ELF/gc-debuginfo-tls.s+2-2| ... | ... | @@ -2,8 +2,8 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld %t.o --gc-sections -shared -o %t1 |
| 4 | 4 | # RUN: ld.lld %t.o -shared -o %t2 |
| 5 | # RUN: llvm-readobj -symbols %t1 | FileCheck %s --check-prefix=GC | |
| 6 | # RUN: llvm-readobj -symbols %t2 | FileCheck %s --check-prefix=NOGC | |
| 5 | # RUN: llvm-readobj --symbols %t1 | FileCheck %s --check-prefix=GC | |
| 6 | # RUN: llvm-readobj --symbols %t2 | FileCheck %s --check-prefix=NOGC | |
| 7 | 7 | |
| 8 | 8 | # NOGC: Symbol { |
| 9 | 9 | # NOGC: Name: patatino |
deps/lld/test/ELF/gc-merge-local-sym.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared -O3 --gc-sections |
| 4 | // RUN: llvm-readobj -s -section-data -t %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S --section-data --symbols %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // CHECK: Name: .rodata |
| 7 | 7 | // CHECK-NEXT: Type: SHT_PROGBITS |
deps/lld/test/ELF/gc-sections-alloc.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 4 | 4 | # RUN: ld.lld %t -o %t2 --gc-sections -shared |
| 5 | # RUN: llvm-readobj -sections -section-data %t2 | FileCheck %s | |
| 5 | # RUN: llvm-readobj --sections --section-data %t2 | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # Non alloca section .bar should not keep section .foo alive. |
| 8 | 8 |
deps/lld/test/ELF/gc-sections-eh.s+2-2| ... | ... | @@ -3,11 +3,11 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 4 | 4 | |
| 5 | 5 | # RUN: ld.lld %t -o %t2 --gc-sections |
| 6 | # RUN: llvm-readobj -t %t2 | FileCheck %s | |
| 6 | # RUN: llvm-readobj --symbols %t2 | FileCheck %s | |
| 7 | 7 | # RUN: llvm-objdump --dwarf=frames %t2 | FileCheck --check-prefix=EH %s |
| 8 | 8 | |
| 9 | 9 | # RUN: ld.lld %t -o %t3 |
| 10 | # RUN: llvm-readobj -t %t3 | FileCheck --check-prefix=NOGC %s | |
| 10 | # RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=NOGC %s | |
| 11 | 11 | # RUN: llvm-objdump --dwarf=frames %t3 | FileCheck --check-prefix=EHNOGC %s |
| 12 | 12 | |
| 13 | 13 | # CHECK-NOT: foo |
deps/lld/test/ELF/gc-sections-implicit-addend.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %s -o %t.o |
| 4 | 4 | # RUN: ld.lld %t.o -o %t --gc-sections |
| 5 | # RUN: llvm-readobj -s %t | FileCheck %s | |
| 5 | # RUN: llvm-readobj -S %t | FileCheck %s | |
| 6 | 6 | # RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s |
| 7 | 7 | |
| 8 | 8 | # CHECK: Name: .foo |
deps/lld/test/ELF/gc-sections-keep-shared-start.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 4 | 4 | # RUN: ld.lld -shared --gc-sections -o %t1 %t |
| 5 | # RUN: llvm-readobj --elf-output-style=GNU --file-headers --symbols %t1 | |
| 5 | # RUN: llvm-readelf --file-headers --symbols %t1 | |
| 6 | 6 | # | FileCheck %s |
| 7 | 7 | # CHECK: Entry point address: 0x1000 |
| 8 | 8 | # CHECK: 0000000000001000 0 FUNC LOCAL HIDDEN 4 _start |
deps/lld/test/ELF/gc-sections-linker-defined-symbol.s+1-1| ... | ... | @@ -10,7 +10,7 @@ |
| 10 | 10 | # CHECK-NEXT: Binding: Global |
| 11 | 11 | # CHECK-NEXT: Type: None |
| 12 | 12 | # CHECK-NEXT: Other: |
| 13 | # CHECK-NEXT: Section: .dynamic | |
| 13 | # CHECK-NEXT: Section: .data | |
| 14 | 14 | |
| 15 | 15 | .data |
| 16 | 16 | .globl g |
deps/lld/test/ELF/gc-sections-local-sym.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld %t -o %t2 -shared --gc-sections |
| 4 | // RUN: llvm-readobj -t -s -section-data %t2 | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols -S --section-data %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .global foo |
| 7 | 7 | foo: |
deps/lld/test/ELF/gc-sections-lsda.s+1-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | // precise and gc the entire contents of this file, but test that at least |
| 8 | 8 | // we are consistent: if we keep .abc, we have to keep .foo |
| 9 | 9 | |
| 10 | // RUN: llvm-readobj -s %t | FileCheck %s | |
| 10 | // RUN: llvm-readobj -S %t | FileCheck %s | |
| 11 | 11 | // CHECK: Name: .abc |
| 12 | 12 | // CHECK: Name: .foo |
| 13 | 13 |
deps/lld/test/ELF/gc-sections-merge-addend.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared --gc-sections |
| 4 | // RUN: llvm-readobj -s -section-data %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S --section-data %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | |
| 7 | 7 | // CHECK: Name: .rodata |
deps/lld/test/ELF/gc-sections-merge-implicit-addend.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=i386-pc-linux |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared --gc-sections |
| 4 | // RUN: llvm-readobj -s -section-data %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S --section-data %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | |
| 7 | 7 | // CHECK: Name: .rodata |
deps/lld/test/ELF/gc-sections-merge.s+2-2| ... | ... | @@ -2,8 +2,8 @@ |
| 2 | 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared |
| 4 | 4 | // RUN: ld.lld %t.o -o %t.gc.so -shared --gc-sections |
| 5 | // RUN: llvm-readobj -s -section-data %t.so | FileCheck %s | |
| 6 | // RUN: llvm-readobj -s -section-data %t.gc.so | FileCheck --check-prefix=GC %s | |
| 5 | // RUN: llvm-readobj -S --section-data %t.so | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S --section-data %t.gc.so | FileCheck --check-prefix=GC %s | |
| 7 | 7 | |
| 8 | 8 | |
| 9 | 9 | // CHECK: Name: .rodata |
deps/lld/test/ELF/gc-sections-metadata-startstop.s+1-1| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | # CHECK-NOT: yy |
| 12 | 12 | |
| 13 | 13 | # CHECK: SYMBOL TABLE: |
| 14 | # CHECK: xx 00000000 __start_xx | |
| 14 | # CHECK: xx 00000000 .protected __start_xx | |
| 15 | 15 | # CHECK: w *UND* 00000000 __start_yy |
| 16 | 16 | |
| 17 | 17 | .weak __start_xx |
deps/lld/test/ELF/gc-sections-non-alloc-to-merge.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 4 | 4 | # RUN: ld.lld %t.o -o %t --gc-sections |
| 5 | # RUN: llvm-readobj -s --elf-output-style=GNU %t | FileCheck %s | |
| 5 | # RUN: llvm-readelf -S %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: .merge1 PROGBITS {{[0-9a-z]*}} {{[0-9a-z]*}} 000004 |
| 8 | 8 |
deps/lld/test/ELF/gc-sections-protected.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared --gc-sections |
| 4 | // RUN: llvm-readobj -s %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // CHECK: Name: .text |
| 7 | 7 | // CHECK-NEXT: Type: SHT_PROGBITS |
deps/lld/test/ELF/gc-sections-synthetic.s+1-1| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | # RUN: ld.lld %t1 -shared -o %t.so |
| 7 | 7 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2 |
| 8 | 8 | # RUN: ld.lld %t2 %t.so -build-id -dynamic-linker /foo/bar -o %t.out |
| 9 | # RUN: llvm-readobj -sections %t.out | FileCheck %s | |
| 9 | # RUN: llvm-readobj --sections %t.out | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | # CHECK: Name: .interp |
| 12 | 12 | # CHECK: Name: .note.gnu.build-id |
deps/lld/test/ELF/gc-sections-undefined.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | # RUN: ld.lld %t -o %t1 --gc-sections --undefined=foo |
| 4 | # RUN: llvm-readobj -t %t1 | FileCheck %s | |
| 4 | # RUN: llvm-readobj --symbols %t1 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: foo |
| 7 | 7 |
deps/lld/test/ELF/gc-sections-weak.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/gc-sections-weak.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld %t.o %t2.o -o %t.so -shared --gc-sections |
| 5 | // RUN: llvm-readobj -s %t.so | FileCheck %s | |
| 5 | // RUN: llvm-readobj -S %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | .global foo |
| 8 | 8 | foo: |
deps/lld/test/ELF/gc-sections.s+3-3| ... | ... | @@ -2,11 +2,11 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 4 | 4 | # RUN: ld.lld %t -o %t2 |
| 5 | # RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=NOGC %s | |
| 5 | # RUN: llvm-readobj --sections --symbols %t2 | FileCheck -check-prefix=NOGC %s | |
| 6 | 6 | # RUN: ld.lld --gc-sections %t -o %t2 |
| 7 | # RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=GC1 %s | |
| 7 | # RUN: llvm-readobj --sections --symbols %t2 | FileCheck -check-prefix=GC1 %s | |
| 8 | 8 | # RUN: ld.lld --export-dynamic --gc-sections %t -o %t2 |
| 9 | # RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=GC2 %s | |
| 9 | # RUN: llvm-readobj --sections --symbols %t2 | FileCheck -check-prefix=GC2 %s | |
| 10 | 10 | |
| 11 | 11 | # NOGC: Name: .eh_frame |
| 12 | 12 | # NOGC: Name: .text |
deps/lld/test/ELF/gdb-index-invalid-section-index.yaml created+140| ... | ... | @@ -0,0 +1,140 @@ |
| 1 | # RUN: yaml2obj %s -o %t.o | |
| 2 | # RUN: ld.lld --gdb-index %t.o -o /dev/null | |
| 3 | ||
| 4 | ## We used to crash if a DWARFAddressRange has invalid SectionIndex (-1). | |
| 5 | ## Such DWARFAddressRange can be produced by clang -c -gdwarf-5 -gmlt before r360678. | |
| 6 | ||
| 7 | --- !ELF | |
| 8 | FileHeader: | |
| 9 | Class: ELFCLASS64 | |
| 10 | Data: ELFDATA2LSB | |
| 11 | Type: ET_REL | |
| 12 | Machine: EM_X86_64 | |
| 13 | Sections: | |
| 14 | - Name: .text | |
| 15 | Type: SHT_PROGBITS | |
| 16 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 17 | AddressAlign: 0x0000000000000010 | |
| 18 | Content: 31C0C3 | |
| 19 | - Name: .debug_str_offsets | |
| 20 | Type: SHT_PROGBITS | |
| 21 | AddressAlign: 0x0000000000000001 | |
| 22 | Content: '1000000005000000000000000000000000000000' | |
| 23 | - Name: .rela.debug_str_offsets | |
| 24 | Type: SHT_RELA | |
| 25 | Link: .symtab | |
| 26 | AddressAlign: 0x0000000000000008 | |
| 27 | EntSize: 0x0000000000000018 | |
| 28 | Info: .debug_str_offsets | |
| 29 | Relocations: | |
| 30 | - Offset: 0x0000000000000008 | |
| 31 | Symbol: .debug_str | |
| 32 | Type: R_X86_64_32 | |
| 33 | - Offset: 0x000000000000000C | |
| 34 | Symbol: .debug_str | |
| 35 | Type: R_X86_64_32 | |
| 36 | Addend: 1 | |
| 37 | - Offset: 0x0000000000000010 | |
| 38 | Symbol: .debug_str | |
| 39 | Type: R_X86_64_32 | |
| 40 | Addend: 6 | |
| 41 | - Name: .debug_str | |
| 42 | Type: SHT_PROGBITS | |
| 43 | Flags: [ SHF_MERGE, SHF_STRINGS ] | |
| 44 | AddressAlign: 0x0000000000000001 | |
| 45 | EntSize: 0x0000000000000001 | |
| 46 | Content: 00612E6363002F746D7000 | |
| 47 | - Name: .debug_abbrev | |
| 48 | Type: SHT_PROGBITS | |
| 49 | AddressAlign: 0x0000000000000001 | |
| 50 | Content: 011100252513050325721710171B25111B1206000000 | |
| 51 | - Name: .debug_info | |
| 52 | Type: SHT_PROGBITS | |
| 53 | AddressAlign: 0x0000000000000001 | |
| 54 | Content: 1B000000050001080000000001000400010000000000000000020003000000 | |
| 55 | - Name: .rela.debug_info | |
| 56 | Type: SHT_RELA | |
| 57 | Link: .symtab | |
| 58 | AddressAlign: 0x0000000000000008 | |
| 59 | EntSize: 0x0000000000000018 | |
| 60 | Info: .debug_info | |
| 61 | Relocations: | |
| 62 | - Offset: 0x0000000000000008 | |
| 63 | Symbol: .debug_abbrev | |
| 64 | Type: R_X86_64_32 | |
| 65 | - Offset: 0x0000000000000011 | |
| 66 | Symbol: .debug_str_offsets | |
| 67 | Type: R_X86_64_32 | |
| 68 | Addend: 8 | |
| 69 | - Offset: 0x0000000000000015 | |
| 70 | Symbol: .debug_line | |
| 71 | Type: R_X86_64_32 | |
| 72 | - Name: .debug_addr | |
| 73 | Type: SHT_PROGBITS | |
| 74 | AddressAlign: 0x0000000000000001 | |
| 75 | Content: 0C000000050008000000000000000000 | |
| 76 | - Name: .rela.debug_addr | |
| 77 | Type: SHT_RELA | |
| 78 | Link: .symtab | |
| 79 | AddressAlign: 0x0000000000000008 | |
| 80 | EntSize: 0x0000000000000018 | |
| 81 | Info: .debug_addr | |
| 82 | Relocations: | |
| 83 | - Offset: 0x0000000000000008 | |
| 84 | Symbol: .text | |
| 85 | Type: R_X86_64_64 | |
| 86 | - Name: .debug_line | |
| 87 | Type: SHT_PROGBITS | |
| 88 | AddressAlign: 0x0000000000000001 | |
| 89 | Content: 2D0000000500080025000000010101FB0E0D00010101010000000100000101011F010000000002011F020F010000000000 | |
| 90 | - Name: .rela.debug_line | |
| 91 | Type: SHT_RELA | |
| 92 | Link: .symtab | |
| 93 | AddressAlign: 0x0000000000000008 | |
| 94 | EntSize: 0x0000000000000018 | |
| 95 | Info: .debug_line | |
| 96 | Relocations: | |
| 97 | - Offset: 0x0000000000000022 | |
| 98 | Symbol: .debug_line_str | |
| 99 | Type: R_X86_64_32 | |
| 100 | - Offset: 0x000000000000002C | |
| 101 | Symbol: .debug_line_str | |
| 102 | Type: R_X86_64_32 | |
| 103 | Addend: 5 | |
| 104 | - Name: .debug_line_str | |
| 105 | Type: SHT_PROGBITS | |
| 106 | Flags: [ SHF_MERGE, SHF_STRINGS ] | |
| 107 | AddressAlign: 0x0000000000000001 | |
| 108 | EntSize: 0x0000000000000001 | |
| 109 | Content: 2F746D7000612E636300 | |
| 110 | Symbols: | |
| 111 | - Name: a.ll | |
| 112 | Type: STT_FILE | |
| 113 | Index: SHN_ABS | |
| 114 | - Name: .text | |
| 115 | Type: STT_SECTION | |
| 116 | Section: .text | |
| 117 | - Name: .debug_str_offsets | |
| 118 | Type: STT_SECTION | |
| 119 | Section: .debug_str_offsets | |
| 120 | - Name: .debug_str | |
| 121 | Type: STT_SECTION | |
| 122 | Section: .debug_str | |
| 123 | - Name: .debug_abbrev | |
| 124 | Type: STT_SECTION | |
| 125 | Section: .debug_abbrev | |
| 126 | - Name: .debug_info | |
| 127 | Type: STT_SECTION | |
| 128 | Section: .debug_info | |
| 129 | - Name: .debug_line | |
| 130 | Type: STT_SECTION | |
| 131 | Section: .debug_line | |
| 132 | - Name: .debug_line_str | |
| 133 | Type: STT_SECTION | |
| 134 | Section: .debug_line_str | |
| 135 | - Name: foo | |
| 136 | Type: STT_FUNC | |
| 137 | Section: .text | |
| 138 | Binding: STB_GLOBAL | |
| 139 | Size: 0x0000000000000003 | |
| 140 | ... |
deps/lld/test/ELF/gdb-index-multiple-cu-2.s+2-2| ... | ... | @@ -4,8 +4,8 @@ |
| 4 | 4 | # RUN: ld.lld --gdb-index %t.o %t1.o -o %t |
| 5 | 5 | # RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s |
| 6 | 6 | |
| 7 | # %t.o has 2 CUs while %t1 has 1, thus _start in %t1.o should have CuIndex 2. | |
| 8 | # Attributes << 24 | CuIndex = 48 << 24 | 2 = 0x30000002 | |
| 7 | # %t.o has 2 CUs while %t1 has 1, thus _start in %t1.o should have cuIndex 2. | |
| 8 | # attributes << 24 | cuIndex = 48 << 24 | 2 = 0x30000002 | |
| 9 | 9 | # CHECK: Constant pool |
| 10 | 10 | # CHECK-NEXT: 0(0x0): 0x30000002 |
| 11 | 11 |
deps/lld/test/ELF/gdb-index-multiple-cu.s+6-6| ... | ... | @@ -3,10 +3,10 @@ |
| 3 | 3 | # RUN: ld.lld --gdb-index %t.o -o %t |
| 4 | 4 | # RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s |
| 5 | 5 | |
| 6 | # CuIndexAndAttrs of _start: | |
| 7 | # Attributes << 24 | CuIndex = 48 << 24 | 0 = 0x30000000 | |
| 8 | # CuIndexAndAttrs of foo: | |
| 9 | # Attributes << 24 | CuIndex = 48 << 24 | 1 = 0x30000001 | |
| 6 | # cuIndexAndAttrs of _start: | |
| 7 | # attributes << 24 | cuIndex = 48 << 24 | 0 = 0x30000000 | |
| 8 | # cuIndexAndAttrs of foo: | |
| 9 | # attributes << 24 | cuIndex = 48 << 24 | 1 = 0x30000001 | |
| 10 | 10 | # CHECK: Symbol table |
| 11 | 11 | # CHECK-DAG: String name: _start, CU vector index: 0 |
| 12 | 12 | # CHECK-DAG: String name: foo, CU vector index: 1 |
| ... | ... | @@ -63,7 +63,7 @@ foo: |
| 63 | 63 | # Swap sets to test the case where pubnames are in a |
| 64 | 64 | # different order than the CUs they refer to. |
| 65 | 65 | .section .debug_gnu_pubnames,"",@progbits |
| 66 | 	# CuIndex: 1 | |
| 66 | 	# cuIndex: 1 | |
| 67 | 67 | 	.long	.LpubNames_end1 - .LpubNames_begin1 |
| 68 | 68 | .LpubNames_begin1: |
| 69 | 69 | 	.short	2 # Version |
| ... | ... | @@ -75,7 +75,7 @@ foo: |
| 75 | 75 | 	.long	0 |
| 76 | 76 | .LpubNames_end1: |
| 77 | 77 | |
| 78 | 	# CuIndex: 0 | |
| 78 | 	# cuIndex: 0 | |
| 79 | 79 | 	.long	.LpubNames_end0 - .LpubNames_begin0 |
| 80 | 80 | .LpubNames_begin0: |
| 81 | 81 | 	.short	2 # Version |
deps/lld/test/ELF/gdb-index-ranges-discarded.s created+51| ... | ... | @@ -0,0 +1,51 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | # RUN: ld.lld --gdb-index -e main %t.o -o %t | |
| 4 | # RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s | |
| 5 | ||
| 6 | # CHECK: .gdb_index contents: | |
| 7 | # CHECK: Address area offset = 0x28, has 1 entries: | |
| 8 | # CHECK-NEXT: Low/High address = [0x201000, 0x201001) (Size: 0x1), CU id = 0 | |
| 9 | ||
| 10 | ## .debug_ranges contains 2 entries. .Lfunc_end0 is defined in the discarded | |
| 11 | ## .text.foo. Test we resolve it to a non-zero value, otherwise the address area | |
| 12 | ## of .gdb_index will not included [.Lfunc_begin1, .Lfunc_end1). | |
| 13 | ||
| 14 | .section .text.foo,"aex",@progbits | |
| 15 | .Lfunc_begin0: | |
| 16 | ret | |
| 17 | .Lfunc_end0: | |
| 18 | ||
| 19 | .section .text.bar,"ax",@progbits | |
| 20 | .Lfunc_begin1: | |
| 21 | ret | |
| 22 | .Lfunc_end1: | |
| 23 | ||
| 24 | .section .debug_abbrev,"",@progbits | |
| 25 | .byte 1 # Abbreviation Code | |
| 26 | .byte 17 # DW_TAG_compile_unit | |
| 27 | .byte 0 # DW_CHILDREN_no | |
| 28 | .byte 85 # DW_AT_ranges | |
| 29 | .byte 23 # DW_FORM_sec_offset | |
| 30 | .byte 0 # EOM(1) | |
| 31 | .byte 0 # EOM(2) | |
| 32 | .byte 0 | |
| 33 | ||
| 34 | .section .debug_info,"",@progbits | |
| 35 | .Lcu_begin0: | |
| 36 | .long .Lcu_end0 - .Lcu_begin0 - 4 | |
| 37 | .short 4 # DWARF version number | |
| 38 | .long 0 # Offset Into Abbrev. Section | |
| 39 | .byte 8 # Address Size | |
| 40 | .Ldie0: | |
| 41 | .byte 1 # Abbrev [1] DW_TAG_compile_unit | |
| 42 | .long 0 # DW_AT_ranges | |
| 43 | .Lcu_end0: | |
| 44 | ||
| 45 | .section .debug_ranges,"",@progbits | |
| 46 | .quad .Lfunc_begin0 | |
| 47 | .quad .Lfunc_end0 | |
| 48 | .quad .Lfunc_begin1 | |
| 49 | .quad .Lfunc_end1 | |
| 50 | .quad 0 | |
| 51 | .quad 0 |
deps/lld/test/ELF/gdb-index.s+2-1| ... | ... | @@ -16,6 +16,7 @@ |
| 16 | 16 | # RUN: llvm-readelf -sections %t | FileCheck %s --check-prefix=SECTION |
| 17 | 17 | |
| 18 | 18 | # DISASM: Disassembly of section .text: |
| 19 | # DISASM-EMPTY: | |
| 19 | 20 | # DISASM: entrypoint: |
| 20 | 21 | # DISASM-CHECK: 201000: 90 nop |
| 21 | 22 | # DISASM-CHECK: 201001: cc int3 |
| ... | ... | @@ -48,7 +49,7 @@ |
| 48 | 49 | # SECTION-NOT: debug_gnu_pubnames |
| 49 | 50 | |
| 50 | 51 | # RUN: ld.lld --gdb-index --no-gdb-index %t1.o %t2.o -o %t2 |
| 51 | # RUN: llvm-readobj -sections %t2 | FileCheck -check-prefix=NOGDB %s | |
| 52 | # RUN: llvm-readobj --sections %t2 | FileCheck -check-prefix=NOGDB %s | |
| 52 | 53 | # NOGDB-NOT: Name: .gdb_index |
| 53 | 54 | |
| 54 | 55 | ## The following section contents are created by this using gcc 7.1.0: |
deps/lld/test/ELF/global-offset-table-position-aarch64.s+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: aarch64 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv -shared %t -o %t2 |
| 4 | // RUN: llvm-readobj -t %t2 | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols %t2 | FileCheck %s | |
| 5 | 5 | .globl a |
| 6 | 6 | .type a,@object |
| 7 | 7 | .comm a,4,4 |
| ... | ... | @@ -20,7 +20,7 @@ _start: |
| 20 | 20 | .long _GLOBAL_OFFSET_TABLE_ - . |
| 21 | 21 | |
| 22 | 22 | // CHECK: Name: _GLOBAL_OFFSET_TABLE_ (11) |
| 23 | // CHECK-NEXT: Value: 0x20008 | |
| 23 | // CHECK-NEXT: Value: 0x30008 | |
| 24 | 24 | // CHECK-NEXT: Size: 0 |
| 25 | 25 | // CHECK-NEXT: Binding: Local (0x0) |
| 26 | 26 | // CHECK-NEXT: Type: None (0x0) |
deps/lld/test/ELF/global-offset-table-position-arm.s+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: arm |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %s -o %t |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv -shared %t -o %t2 |
| 4 | // RUN: llvm-readobj -t %t2 | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // The ARM _GLOBAL_OFFSET_TABLE_ should be defined at the start of the .got |
| 7 | 7 | .globl a |
| ... | ... | @@ -25,7 +25,7 @@ _start: |
| 25 | 25 | .data |
| 26 | 26 | |
| 27 | 27 | // CHECK: Name: _GLOBAL_OFFSET_TABLE_ |
| 28 | // CHECK-NEXT: Value: 0x3068 | |
| 28 | // CHECK-NEXT: Value: 0x2068 | |
| 29 | 29 | // CHECK-NEXT: Size: 0 |
| 30 | 30 | // CHECK-NEXT: Binding: Local |
| 31 | 31 | // CHECK-NEXT: Type: None |
deps/lld/test/ELF/global-offset-table-position-i386.s+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv -shared %t -o %t2 |
| 4 | // RUN: llvm-readobj -t %t2 | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // The X86 _GLOBAL_OFFSET_TABLE_ is defined at the start of the .got.plt |
| 7 | 7 | // section. |
| ... | ... | @@ -22,7 +22,7 @@ addl $_GLOBAL_OFFSET_TABLE_, %eax |
| 22 | 22 | calll f@PLT |
| 23 | 23 | |
| 24 | 24 | // CHECK: Name: _GLOBAL_OFFSET_TABLE_ (1) |
| 25 | // CHECK-NEXT: Value: 0x2000 | |
| 25 | // CHECK-NEXT: Value: 0x3000 | |
| 26 | 26 | // CHECK-NEXT: Size: 0 |
| 27 | 27 | // CHECK-NEXT: Binding: Local (0x0) |
| 28 | 28 | // CHECK-NEXT: Type: None (0x0) |
deps/lld/test/ELF/global-offset-table-position-mips.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: mips |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld -shared %t -o %t2 |
| 4 | // RUN: llvm-readobj -t %t2 | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // The Mips _GLOBAL_OFFSET_TABLE_ should be defined at the start of the .got |
| 7 | 7 |
deps/lld/test/ELF/global-offset-table-position.s+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv -shared %t -o %t2 |
| 4 | // RUN: llvm-readobj -t %t2 | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // The X86_64 _GLOBAL_OFFSET_TABLE_ is defined at the start of the .got.plt |
| 7 | 7 | // section. |
| ... | ... | @@ -22,7 +22,7 @@ callq	f@PLT |
| 22 | 22 | .long _GLOBAL_OFFSET_TABLE_ - . |
| 23 | 23 | |
| 24 | 24 | // CHECK: Name: _GLOBAL_OFFSET_TABLE_ |
| 25 | // CHECK-NEXT: Value: 0x2008 | |
| 25 | // CHECK-NEXT: Value: 0x3008 | |
| 26 | 26 | // CHECK-NEXT: Size: 0 |
| 27 | 27 | // CHECK-NEXT: Binding: Local |
| 28 | 28 | // CHECK-NEXT: Type: None (0x0) |
deps/lld/test/ELF/global_offset_table_shared.s+2-2| ... | ... | @@ -1,11 +1,11 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv -shared %t -o %t2 |
| 4 | // RUN: llvm-readobj -t %t2 | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols %t2 | FileCheck %s | |
| 5 | 5 | .long _GLOBAL_OFFSET_TABLE_ - . |
| 6 | 6 | |
| 7 | 7 | // CHECK: Name: _GLOBAL_OFFSET_TABLE_ |
| 8 | // CHECK-NEXT: Value: 0x2000 | |
| 8 | // CHECK-NEXT: Value: 0x3000 | |
| 9 | 9 | // CHECK-NEXT: Size: 0 |
| 10 | 10 | // CHECK-NEXT: Binding: Local |
| 11 | 11 | // CHECK-NEXT: Type: None |
deps/lld/test/ELF/gnu-hash-table-rwsegment.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 4 | 4 | # RUN: ld.lld -shared -hash-style=gnu --no-rosegment -o %t.so %t.o |
| 5 | # RUN: llvm-readobj -gnu-hash-table %t.so | FileCheck %s | |
| 5 | # RUN: llvm-readobj --gnu-hash-table %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: GnuHashTable { |
| 8 | 8 | # CHECK-NEXT: Num Buckets: 1 |
deps/lld/test/ELF/gnu-hash-table.s+5-5| ... | ... | @@ -36,15 +36,15 @@ |
| 36 | 36 | # RUN: ld.lld -shared --hash-style both -o %t-ppc64le.so %t-ppc64le.o %t2-ppc64le.a %t3-ppc64le.so |
| 37 | 37 | # RUN: ld.lld -shared --hash-style both -o %t-ppc64.so %t-ppc64.o %t2-ppc64.a %t3-ppc64.so |
| 38 | 38 | |
| 39 | # RUN: llvm-readobj -dyn-symbols -gnu-hash-table %te-i386.so \ | |
| 39 | # RUN: llvm-readobj --dyn-syms --gnu-hash-table %te-i386.so \ | |
| 40 | 40 | # RUN: | FileCheck %s -check-prefix=EMPTY |
| 41 | # RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-i386.so \ | |
| 41 | # RUN: llvm-readobj --sections --dyn-syms --gnu-hash-table %t-i386.so \ | |
| 42 | 42 | # RUN: | FileCheck %s -check-prefix=I386 |
| 43 | # RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-x86_64.so \ | |
| 43 | # RUN: llvm-readobj --sections --dyn-syms --gnu-hash-table %t-x86_64.so \ | |
| 44 | 44 | # RUN: | FileCheck %s -check-prefix=X86_64 |
| 45 | # RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-ppc64le.so \ | |
| 45 | # RUN: llvm-readobj --sections --dyn-syms --gnu-hash-table %t-ppc64le.so \ | |
| 46 | 46 | # RUN: | FileCheck %s -check-prefix=PPC64 |
| 47 | # RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-ppc64.so \ | |
| 47 | # RUN: llvm-readobj --sections --dyn-syms --gnu-hash-table %t-ppc64.so \ | |
| 48 | 48 | # RUN: | FileCheck %s -check-prefix=PPC64 |
| 49 | 49 | |
| 50 | 50 | # EMPTY: DynamicSymbols [ |
deps/lld/test/ELF/gnu-ifunc-canon.s created+92| ... | ... | @@ -0,0 +1,92 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o | |
| 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gnu-ifunc-canon-ro-pcrel.s -o %t-ro-pcrel.o | |
| 4 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gnu-ifunc-canon-ro-abs.s -o %t-ro-abs.o | |
| 5 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gnu-ifunc-canon-rw-addend.s -o %t-rw-addend.o | |
| 6 | // RUN: ld.lld %t.o -o %t1 | |
| 7 | // RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=IREL2 %s | |
| 8 | // RUN: ld.lld %t.o %t-ro-pcrel.o -o %t2 | |
| 9 | // RUN: llvm-readobj -r %t2 | FileCheck --check-prefix=IREL1 %s | |
| 10 | // RUN: ld.lld %t.o %t-ro-abs.o -o %t3 | |
| 11 | // RUN: llvm-readobj -r %t3 | FileCheck --check-prefix=IREL1 %s | |
| 12 | // RUN: ld.lld %t.o %t-rw-addend.o -o %t4 | |
| 13 | // RUN: llvm-readobj -r %t4 | FileCheck --check-prefix=IREL1 %s | |
| 14 | // RUN: llvm-objdump -s %t4 | FileCheck --check-prefix=DUMP %s | |
| 15 | // RUN: ld.lld %t.o %t-rw-addend.o -o %t4a -z retpolineplt | |
| 16 | // RUN: llvm-readobj -r %t4a | FileCheck --check-prefix=IREL1 %s | |
| 17 | // RUN: llvm-objdump -s %t4a | FileCheck --check-prefix=DUMP2 %s | |
| 18 | // RUN: ld.lld %t-ro-pcrel.o %t.o -o %t5 | |
| 19 | // RUN: llvm-readobj -r %t5 | FileCheck --check-prefix=IREL1 %s | |
| 20 | // RUN: ld.lld %t-ro-abs.o %t.o -o %t6 | |
| 21 | // RUN: llvm-readobj -r %t6 | FileCheck --check-prefix=IREL1 %s | |
| 22 | // RUN: ld.lld %t-rw-addend.o %t.o -o %t7 | |
| 23 | // RUN: llvm-readobj -r %t7 | FileCheck --check-prefix=IREL1 %s | |
| 24 | // RUN: ld.lld %t.o -o %t8 -pie | |
| 25 | // RUN: llvm-readobj -r %t8 | FileCheck --check-prefix=IREL2 %s | |
| 26 | // RUN: ld.lld %t.o %t-ro-pcrel.o -o %t9 -pie | |
| 27 | // RUN: llvm-readobj -r %t9 | FileCheck --check-prefix=IREL1-REL2 %s | |
| 28 | // RUN: ld.lld %t.o %t-rw-addend.o -o %t10 -pie | |
| 29 | // RUN: llvm-readobj -r %t10 | FileCheck --check-prefix=IREL1-REL3 %s | |
| 30 | // RUN: ld.lld %t-ro-pcrel.o %t.o -o %t11 -pie | |
| 31 | // RUN: llvm-readobj -r %t11 | FileCheck --check-prefix=IREL1-REL2 %s | |
| 32 | // RUN: ld.lld %t-rw-addend.o %t.o -o %t12 -pie | |
| 33 | // RUN: llvm-readobj -r %t12 | FileCheck --check-prefix=IREL1-REL3 %s | |
| 34 | ||
| 35 | // Two relocs, one for the GOT and the other for .data. | |
| 36 | // IREL2-NOT: R_X86_64_ | |
| 37 | // IREL2: .rela.plt | |
| 38 | // IREL2-NEXT: R_X86_64_IRELATIVE | |
| 39 | // IREL2-NEXT: R_X86_64_IRELATIVE | |
| 40 | // IREL2-NOT: R_X86_64_ | |
| 41 | ||
| 42 | // One reloc for the canonical PLT. | |
| 43 | // IREL1-NOT: R_X86_64_ | |
| 44 | // IREL1: .rela.plt | |
| 45 | // IREL1-NEXT: R_X86_64_IRELATIVE | |
| 46 | // IREL1-NOT: R_X86_64_ | |
| 47 | ||
| 48 | // One reloc for the canonical PLT and two RELATIVE relocations pointing to it, | |
| 49 | // one in the GOT and one in .data. | |
| 50 | // IREL1-REL2-NOT: R_X86_64_ | |
| 51 | // IREL1-REL2: .rela.dyn | |
| 52 | // IREL1-REL2-NEXT: R_X86_64_RELATIVE | |
| 53 | // IREL1-REL2-NEXT: R_X86_64_RELATIVE | |
| 54 | // IREL1-REL2: .rela.plt | |
| 55 | // IREL1-REL2-NEXT: R_X86_64_IRELATIVE | |
| 56 | // IREL1-REL2-NOT: R_X86_64_ | |
| 57 | ||
| 58 | // One reloc for the canonical PLT and three RELATIVE relocations pointing to it, | |
| 59 | // one in the GOT and two in .data. | |
| 60 | // IREL1-REL3-NOT: R_X86_64_ | |
| 61 | // IREL1-REL3: .rela.dyn | |
| 62 | // IREL1-REL3-NEXT: R_X86_64_RELATIVE | |
| 63 | // IREL1-REL3-NEXT: R_X86_64_RELATIVE | |
| 64 | // IREL1-REL3-NEXT: R_X86_64_RELATIVE | |
| 65 | // IREL1-REL3: .rela.plt | |
| 66 | // IREL1-REL3-NEXT: R_X86_64_IRELATIVE | |
| 67 | // IREL1-REL3-NOT: R_X86_64_ | |
| 68 | ||
| 69 | // Make sure the static relocations look right, both with and without headers. | |
| 70 | // DUMP: Contents of section .plt: | |
| 71 | // DUMP-NEXT: 201010 | |
| 72 | // DUMP: Contents of section .got: | |
| 73 | // DUMP-NEXT: 202000 10102000 00000000 | |
| 74 | // DUMP: Contents of section .data: | |
| 75 | // DUMP-NEXT: 203000 10102000 00000000 11102000 00000000 | |
| 76 | ||
| 77 | // DUMP2: Contents of section .plt: | |
| 78 | // DUMP2-NEXT: 201010 | |
| 79 | // DUMP2: Contents of section .got: | |
| 80 | // DUMP2-NEXT: 202000 40102000 00000000 | |
| 81 | // DUMP2: Contents of section .data: | |
| 82 | // DUMP2-NEXT: 203000 40102000 00000000 41102000 00000000 | |
| 83 | ||
| 84 | lea ifunc@gotpcrel(%rip), %rbx | |
| 85 | ||
| 86 | .type ifunc STT_GNU_IFUNC | |
| 87 | .globl ifunc | |
| 88 | ifunc: | |
| 89 | ret | |
| 90 | ||
| 91 | .data | |
| 92 | .8byte ifunc |
deps/lld/test/ELF/gnu-ifunc-dso.s+2-2| ... | ... | @@ -3,10 +3,10 @@ |
| 3 | 3 | # RUN: ld.lld -shared %t1.o -o %t.so |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o |
| 5 | 5 | # RUN: ld.lld -shared %t2.o %t.so -o %t |
| 6 | # RUN: llvm-readobj -dyn-relocations %t | FileCheck %s | |
| 6 | # RUN: llvm-readobj --dyn-relocations %t | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | # CHECK: Dynamic Relocations { |
| 9 | # CHECK-NEXT: 0x1000 R_X86_64_64 foo 0x0 | |
| 9 | # CHECK-NEXT: 0x2000 R_X86_64_64 foo 0x0 | |
| 10 | 10 | # CHECK-NEXT: } |
| 11 | 11 | |
| 12 | 12 | .data |
deps/lld/test/ELF/gnu-ifunc-dyntags.s+6-6| ... | ... | @@ -2,14 +2,14 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld -pie %t.o -o %tout |
| 4 | 4 | # RUN: llvm-objdump -section-headers %tout | FileCheck %s |
| 5 | # RUN: llvm-readobj -dynamic-table -r %tout | FileCheck %s --check-prefix=TAGS | |
| 5 | # RUN: llvm-readobj --dynamic-table -r %tout | FileCheck %s --check-prefix=TAGS | |
| 6 | 6 | |
| 7 | 7 | ## Check we produce DT_PLTREL/DT_JMPREL/DT_PLTGOT and DT_PLTRELSZ tags |
| 8 | 8 | ## when there are no other relocations except R_*_IRELATIVE. |
| 9 | 9 | |
| 10 | # CHECK: Name Size Address | |
| 11 | # CHECK: .rela.plt 00000030 0000000000000210 | |
| 12 | # CHECK: .got.plt 00000010 0000000000002000 | |
| 10 | # CHECK: Name Size VMA | |
| 11 | # CHECK: .rela.plt 00000030 0000000000000248 | |
| 12 | # CHECK: .got.plt 00000010 0000000000003000 | |
| 13 | 13 | |
| 14 | 14 | # TAGS: Relocations [ |
| 15 | 15 | # TAGS-NEXT: Section {{.*}} .rela.plt { |
| ... | ... | @@ -19,9 +19,9 @@ |
| 19 | 19 | # TAGS-NEXT: ] |
| 20 | 20 | |
| 21 | 21 | # TAGS: Tag Type Name/Value |
| 22 | # TAGS: 0x0000000000000017 JMPREL 0x210 | |
| 22 | # TAGS: 0x0000000000000017 JMPREL 0x248 | |
| 23 | 23 | # TAGS: 0x0000000000000002 PLTRELSZ 48 |
| 24 | # TAGS: 0x0000000000000003 PLTGOT 0x2000 | |
| 24 | # TAGS: 0x0000000000000003 PLTGOT 0x3000 | |
| 25 | 25 | # TAGS: 0x0000000000000014 PLTREL RELA |
| 26 | 26 | |
| 27 | 27 | .text |
deps/lld/test/ELF/gnu-ifunc-gotpcrel.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: ld.lld -shared %t2.o -o %t2.so |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 5 | 5 | # RUN: ld.lld --hash-style=sysv %t.o %t2.so -o %t |
| 6 | # RUN: llvm-readobj -dyn-relocations %t | FileCheck %s | |
| 6 | # RUN: llvm-readobj --dyn-relocations %t | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | # CHECK: Dynamic Relocations { |
| 9 | 9 | # CHECK-NEXT: 0x2020B0 R_X86_64_GLOB_DAT foo 0x0 |
deps/lld/test/ELF/gnu-ifunc-i386.s+34-6| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld -static %t.o -o %tout |
| 4 | 4 | // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM |
| 5 | // RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s | |
| 5 | // RUN: llvm-readobj -r --symbols --sections %tout | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // CHECK: Sections [ |
| 8 | 8 | // CHECK: Section { |
| ... | ... | @@ -70,39 +70,61 @@ |
| 70 | 70 | // CHECK-NEXT: } |
| 71 | 71 | // CHECK-NEXT: Symbol { |
| 72 | 72 | // CHECK-NEXT: Name: bar |
| 73 | // CHECK-NEXT: Value: 0x401030 | |
| 74 | // CHECK-NEXT: Size: 0 | |
| 75 | // CHECK-NEXT: Binding: Global | |
| 76 | // CHECK-NEXT: Type: Function | |
| 77 | // CHECK-NEXT: Other: 0 | |
| 78 | // CHECK-NEXT: Section: .plt | |
| 79 | // CHECK-NEXT: } | |
| 80 | // CHECK-NEXT: Symbol { | |
| 81 | // CHECK-NEXT: Name: bar_resolver | |
| 73 | 82 | // CHECK-NEXT: Value: 0x401001 |
| 74 | 83 | // CHECK-NEXT: Size: 0 |
| 75 | 84 | // CHECK-NEXT: Binding: Global |
| 76 | // CHECK-NEXT: Type: GNU_IFunc | |
| 85 | // CHECK-NEXT: Type: Function | |
| 77 | 86 | // CHECK-NEXT: Other: 0 |
| 78 | 87 | // CHECK-NEXT: Section: .text |
| 79 | 88 | // CHECK-NEXT: } |
| 80 | 89 | // CHECK-NEXT: Symbol { |
| 81 | 90 | // CHECK-NEXT: Name: foo |
| 91 | // CHECK-NEXT: Value: 0x401020 | |
| 92 | // CHECK-NEXT: Size: 0 | |
| 93 | // CHECK-NEXT: Binding: Global | |
| 94 | // CHECK-NEXT: Type: Function | |
| 95 | // CHECK-NEXT: Other: 0 | |
| 96 | // CHECK-NEXT: Section: .plt | |
| 97 | // CHECK-NEXT: } | |
| 98 | // CHECK-NEXT: Symbol { | |
| 99 | // CHECK-NEXT: Name: foo_resolver | |
| 82 | 100 | // CHECK-NEXT: Value: 0x401000 |
| 83 | 101 | // CHECK-NEXT: Size: 0 |
| 84 | 102 | // CHECK-NEXT: Binding: Global |
| 85 | // CHECK-NEXT: Type: GNU_IFunc | |
| 103 | // CHECK-NEXT: Type: Function | |
| 86 | 104 | // CHECK-NEXT: Other: 0 |
| 87 | 105 | // CHECK-NEXT: Section: .text |
| 88 | 106 | // CHECK-NEXT: } |
| 89 | 107 | // CHECK-NEXT:] |
| 90 | 108 | |
| 91 | 109 | // DISASM: Disassembly of section .text: |
| 92 | // DISASM-NEXT: foo: | |
| 110 | // DISASM-EMPTY: | |
| 111 | // DISASM-NEXT: foo_resolver: | |
| 93 | 112 | // DISASM-NEXT: 401000: c3 retl |
| 94 | // DISASM: bar: | |
| 113 | // DISASM: bar_resolver: | |
| 95 | 114 | // DISASM-NEXT: 401001: c3 retl |
| 96 | 115 | // DISASM: _start: |
| 97 | 116 | // DISASM-NEXT: 401002: e8 19 00 00 00 calll 25 |
| 98 | 117 | // DISASM-NEXT: 401007: e8 24 00 00 00 calll 36 |
| 99 | 118 | // DISASM-NEXT: 40100c: ba d4 00 40 00 movl $4194516, %edx |
| 100 | 119 | // DISASM-NEXT: 401011: ba e4 00 40 00 movl $4194532, %edx |
| 120 | // DISASM-EMPTY: | |
| 101 | 121 | // DISASM-NEXT: Disassembly of section .plt: |
| 102 | // DISASM-NEXT: .plt: | |
| 122 | // DISASM-EMPTY: | |
| 123 | // DISASM-NEXT: foo: | |
| 103 | 124 | // DISASM-NEXT: 401020: ff 25 00 20 40 00 jmpl *4202496 |
| 104 | 125 | // DISASM-NEXT: 401026: 68 10 00 00 00 pushl $16 |
| 105 | 126 | // DISASM-NEXT: 40102b: e9 e0 ff ff ff jmp -32 <_start+0xe> |
| 127 | // DISASM: bar: | |
| 106 | 128 | // DISASM-NEXT: 401030: ff 25 04 20 40 00 jmpl *4202500 |
| 107 | 129 | // DISASM-NEXT: 401036: 68 18 00 00 00 pushl $24 |
| 108 | 130 | // DISASM-NEXT: 40103b: e9 d0 ff ff ff jmp -48 <_start+0xe> |
| ... | ... | @@ -111,11 +133,17 @@ |
| 111 | 133 | .type foo STT_GNU_IFUNC |
| 112 | 134 | .globl foo |
| 113 | 135 | foo: |
| 136 | .type foo_resolver STT_FUNC | |
| 137 | .globl foo_resolver | |
| 138 | foo_resolver: | |
| 114 | 139 | ret |
| 115 | 140 | |
| 116 | 141 | .type bar STT_GNU_IFUNC |
| 117 | 142 | .globl bar |
| 118 | 143 | bar: |
| 144 | .type bar_resolver STT_FUNC | |
| 145 | .globl bar_resolver | |
| 146 | bar_resolver: | |
| 119 | 147 | ret |
| 120 | 148 | |
| 121 | 149 | .globl _start |
deps/lld/test/ELF/gnu-ifunc-noplt-i386.s created+71| ... | ... | @@ -0,0 +1,71 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=i686-pc-freebsd %S/Inputs/shared2-x86-64.s -o %t1.o | |
| 3 | // RUN: ld.lld %t1.o --shared -o %t.so | |
| 4 | // RUN: llvm-mc -filetype=obj -triple=i686-pc-freebsd %s -o %t.o | |
| 5 | // RUN: ld.lld -z ifunc-noplt -z notext --hash-style=sysv %t.so %t.o -o %tout | |
| 6 | // RUN: llvm-objdump -d --no-show-raw-insn %tout | FileCheck %s --check-prefix=DISASM | |
| 7 | // RUN: llvm-readobj -r --dynamic-table %tout | FileCheck %s | |
| 8 | ||
| 9 | // Check that we emitted relocations for the ifunc calls | |
| 10 | // CHECK: Relocations [ | |
| 11 | // CHECK-NEXT: Section (4) .rel.dyn { | |
| 12 | // CHECK-NEXT: 0x401008 R_386_PLT32 bar | |
| 13 | // CHECK-NEXT: 0x401003 R_386_PLT32 foo | |
| 14 | // CHECK-NEXT: } | |
| 15 | // CHECK-NEXT: Section (5) .rel.plt { | |
| 16 | // CHECK-NEXT: 0x40300C R_386_JUMP_SLOT bar2 | |
| 17 | // CHECK-NEXT: 0x403010 R_386_JUMP_SLOT zed2 | |
| 18 | // CHECK-NEXT: } | |
| 19 | ||
| 20 | // Check that ifunc call sites still require relocation | |
| 21 | // DISASM: Disassembly of section .text: | |
| 22 | // DISASM-EMPTY: | |
| 23 | // DISASM-NEXT: 00401000 foo: | |
| 24 | // DISASM-NEXT: 401000: 	retl | |
| 25 | // DISASM-EMPTY: | |
| 26 | // DISASM-NEXT: 00401001 bar: | |
| 27 | // DISASM-NEXT: 401001: 	retl | |
| 28 | // DISASM-EMPTY: | |
| 29 | // DISASM-NEXT: 00401002 _start: | |
| 30 | // DISASM-NEXT: 401002: 	calll	-4 <_start+0x1> | |
| 31 | // DISASM-NEXT: 401007: 	calll	-4 <_start+0x6> | |
| 32 | // DISASM-NEXT: 40100c: 	calll	31 <bar2@plt> | |
| 33 | // DISASM-NEXT: 401011: 	calll	42 <zed2@plt> | |
| 34 | // DISASM-EMPTY: | |
| 35 | // DISASM-NEXT: Disassembly of section .plt: | |
| 36 | // DISASM-EMPTY: | |
| 37 | // DISASM-NEXT: 00401020 .plt: | |
| 38 | // DISASM-NEXT: 401020: 	pushl	4206596 | |
| 39 | // DISASM-NEXT: 401026: 	jmpl	*4206600 | |
| 40 | // DISASM-NEXT: 40102c: 	nop | |
| 41 | // DISASM-NEXT: 40102d: 	nop | |
| 42 | // DISASM-NEXT: 40102e: 	nop | |
| 43 | // DISASM-NEXT: 40102f: 	nop | |
| 44 | // DISASM-EMPTY: | |
| 45 | // DISASM-NEXT: 00401030 bar2@plt: | |
| 46 | // DISASM-NEXT: 401030: 	jmpl	*4206604 | |
| 47 | // DISASM-NEXT: 401036: 	pushl	$0 | |
| 48 | // DISASM-NEXT: 40103b: 	jmp	-32 <.plt> | |
| 49 | // DISASM-EMPTY: | |
| 50 | // DISASM-NEXT: 00401040 zed2@plt: | |
| 51 | // DISASM-NEXT: 401040: 	jmpl	*4206608 | |
| 52 | // DISASM-NEXT: 401046: 	pushl	$8 | |
| 53 | // DISASM-NEXT: 40104b: 	jmp	-48 <.plt> | |
| 54 | ||
| 55 | .text | |
| 56 | .type foo STT_GNU_IFUNC | |
| 57 | .globl foo | |
| 58 | foo: | |
| 59 | ret | |
| 60 | ||
| 61 | .type bar STT_GNU_IFUNC | |
| 62 | .globl bar | |
| 63 | bar: | |
| 64 | ret | |
| 65 | ||
| 66 | .globl _start | |
| 67 | _start: | |
| 68 | call foo@plt | |
| 69 | call bar@plt | |
| 70 | call bar2@plt | |
| 71 | call zed2@plt |
deps/lld/test/ELF/gnu-ifunc-noplt.s created+68| ... | ... | @@ -0,0 +1,68 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-freebsd %S/Inputs/shared2-x86-64.s -o %t1.o | |
| 3 | // RUN: ld.lld %t1.o --shared -o %t.so | |
| 4 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-freebsd %s -o %t.o | |
| 5 | // RUN: ld.lld -z ifunc-noplt -z notext --hash-style=sysv %t.so %t.o -o %tout | |
| 6 | // RUN: llvm-objdump -d --no-show-raw-insn %tout | FileCheck %s --check-prefix=DISASM | |
| 7 | // RUN: llvm-readobj -r --dynamic-table %tout | FileCheck %s | |
| 8 | ||
| 9 | // Check that we emitted relocations for the ifunc calls | |
| 10 | // CHECK: Relocations [ | |
| 11 | // CHECK-NEXT: Section (4) .rela.dyn { | |
| 12 | // CHECK-NEXT: 0x201008 R_X86_64_PLT32 bar 0xFFFFFFFFFFFFFFFC | |
| 13 | // CHECK-NEXT: 0x201003 R_X86_64_PLT32 foo 0xFFFFFFFFFFFFFFFC | |
| 14 | // CHECK-NEXT: } | |
| 15 | // CHECK-NEXT: Section (5) .rela.plt { | |
| 16 | // CHECK-NEXT: 0x203018 R_X86_64_JUMP_SLOT bar2 0x0 | |
| 17 | // CHECK-NEXT: 0x203020 R_X86_64_JUMP_SLOT zed2 0x0 | |
| 18 | // CHECK-NEXT: } | |
| 19 | ||
| 20 | // Check that ifunc call sites still require relocation | |
| 21 | // DISASM: Disassembly of section .text: | |
| 22 | // DISASM-EMPTY: | |
| 23 | // DISASM-NEXT: 0000000000201000 foo: | |
| 24 | // DISASM-NEXT: 201000: 	retq | |
| 25 | // DISASM-EMPTY: | |
| 26 | // DISASM-NEXT: 0000000000201001 bar: | |
| 27 | // DISASM-NEXT: 201001: 	retq | |
| 28 | // DISASM-EMPTY: | |
| 29 | // DISASM-NEXT: 0000000000201002 _start: | |
| 30 | // DISASM-NEXT: 201002: 	callq	0 <_start+0x5> | |
| 31 | // DISASM-NEXT: 201007: 	callq	0 <_start+0xa> | |
| 32 | // DISASM-NEXT: 20100c: 	callq	31 <bar2@plt> | |
| 33 | // DISASM-NEXT: 201011: 	callq	42 <zed2@plt> | |
| 34 | // DISASM-EMPTY: | |
| 35 | // DISASM-NEXT: Disassembly of section .plt: | |
| 36 | // DISASM-EMPTY: | |
| 37 | // DISASM-NEXT: 0000000000201020 .plt: | |
| 38 | // DISASM-NEXT: 201020: 	pushq	8162(%rip) | |
| 39 | // DISASM-NEXT: 201026: 	jmpq	*8164(%rip) | |
| 40 | // DISASM-NEXT: 20102c: 	nopl	(%rax) | |
| 41 | // DISASM-EMPTY: | |
| 42 | // DISASM-NEXT: 0000000000201030 bar2@plt: | |
| 43 | // DISASM-NEXT: 201030: 	jmpq	*8162(%rip) | |
| 44 | // DISASM-NEXT: 201036: 	pushq	$0 | |
| 45 | // DISASM-NEXT: 20103b: 	jmp	-32 <.plt> | |
| 46 | // DISASM-EMPTY: | |
| 47 | // DISASM-NEXT: 0000000000201040 zed2@plt: | |
| 48 | // DISASM-NEXT: 201040: 	jmpq	*8154(%rip) | |
| 49 | // DISASM-NEXT: 201046: 	pushq	$1 | |
| 50 | // DISASM-NEXT: 20104b: 	jmp	-48 <.plt> | |
| 51 | ||
| 52 | .text | |
| 53 | .type foo STT_GNU_IFUNC | |
| 54 | .globl foo | |
| 55 | foo: | |
| 56 | ret | |
| 57 | ||
| 58 | .type bar STT_GNU_IFUNC | |
| 59 | .globl bar | |
| 60 | bar: | |
| 61 | ret | |
| 62 | ||
| 63 | .globl _start | |
| 64 | _start: | |
| 65 | call foo | |
| 66 | call bar | |
| 67 | call bar2 | |
| 68 | call zed2 |
deps/lld/test/ELF/gnu-ifunc-nosym-i386.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld -static %t.o -o %tout |
| 4 | // RUN: llvm-readobj -symbols %tout | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols %tout | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // Check that no __rel_iplt_end/__rel_iplt_start |
| 7 | 7 | // appear in symtab if there is no references to them. |
deps/lld/test/ELF/gnu-ifunc-nosym.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld -static %t.o -o %tout |
| 4 | // RUN: llvm-readobj -symbols %tout | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols %tout | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // Check that no __rela_iplt_end/__rela_iplt_start |
| 7 | 7 | // appear in symtab if there is no references to them. |
deps/lld/test/ELF/gnu-ifunc-plt-i386.s+16-13| ... | ... | @@ -5,21 +5,21 @@ |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv %t.so %t.o -o %tout |
| 6 | 6 | // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM |
| 7 | 7 | // RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT |
| 8 | // RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s | |
| 8 | // RUN: llvm-readobj -r --dynamic-table %tout | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | // Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt |
| 11 | 11 | // CHECK: Relocations [ |
| 12 | 12 | // CHECK-NEXT: Section (4) .rel.plt { |
| 13 | // CHECK-NEXT: 0x40200C R_386_JUMP_SLOT bar2 | |
| 14 | // CHECK-NEXT: 0x402010 R_386_JUMP_SLOT zed2 | |
| 15 | // CHECK-NEXT: 0x402014 R_386_IRELATIVE | |
| 16 | // CHECK-NEXT: 0x402018 R_386_IRELATIVE | |
| 13 | // CHECK-NEXT: 0x40300C R_386_JUMP_SLOT bar2 | |
| 14 | // CHECK-NEXT: 0x403010 R_386_JUMP_SLOT zed2 | |
| 15 | // CHECK-NEXT: 0x403014 R_386_IRELATIVE | |
| 16 | // CHECK-NEXT: 0x403018 R_386_IRELATIVE | |
| 17 | 17 | |
| 18 | 18 | // Check that IRELATIVE .got.plt entries point to ifunc resolver and not |
| 19 | 19 | // back to the plt entry + 6. |
| 20 | 20 | // GOTPLT: Contents of section .got.plt: |
| 21 | // GOTPLT: 402000 00304000 00000000 00000000 36104000 | |
| 22 | // GOTPLT-NEXT: 402010 46104000 00104000 01104000 | |
| 21 | // GOTPLT: 403000 00204000 00000000 00000000 36104000 | |
| 22 | // GOTPLT-NEXT: 403010 46104000 00104000 01104000 | |
| 23 | 23 | |
| 24 | 24 | // Check that the PLTRELSZ tag includes the IRELATIVE relocations |
| 25 | 25 | // CHECK: DynamicSection [ |
| ... | ... | @@ -27,6 +27,7 @@ |
| 27 | 27 | |
| 28 | 28 | // Check that a PLT header is written and the ifunc entries appear last |
| 29 | 29 | // DISASM: Disassembly of section .text: |
| 30 | // DISASM-EMPTY: | |
| 30 | 31 | // DISASM-NEXT: foo: |
| 31 | 32 | // DISASM-NEXT: 401000: c3 retl |
| 32 | 33 | // DISASM: bar: |
| ... | ... | @@ -36,28 +37,30 @@ |
| 36 | 37 | // DISASM-NEXT: 401007: e8 54 00 00 00 calll 84 |
| 37 | 38 | // DISASM-NEXT: 40100c: e8 1f 00 00 00 calll 31 |
| 38 | 39 | // DISASM-NEXT: 401011: e8 2a 00 00 00 calll 42 |
| 40 | // DISASM-EMPTY: | |
| 39 | 41 | // DISASM-NEXT: Disassembly of section .plt: |
| 42 | // DISASM-EMPTY: | |
| 40 | 43 | // DISASM-NEXT: .plt: |
| 41 | // DISASM-NEXT: 401020: ff 35 04 20 40 00 pushl 4202500 | |
| 42 | // DISASM-NEXT: 401026: ff 25 08 20 40 00 jmpl *4202504 | |
| 44 | // DISASM-NEXT: 401020: ff 35 04 30 40 00 pushl 4206596 | |
| 45 | // DISASM-NEXT: 401026: ff 25 08 30 40 00 jmpl *4206600 | |
| 43 | 46 | // DISASM-NEXT: 40102c: 90 nop |
| 44 | 47 | // DISASM-NEXT: 40102d: 90 nop |
| 45 | 48 | // DISASM-NEXT: 40102e: 90 nop |
| 46 | 49 | // DISASM-NEXT: 40102f: 90 nop |
| 47 | 50 | // DISASM-EMPTY: |
| 48 | 51 | // DISASM-NEXT: bar2@plt: |
| 49 | // DISASM-NEXT: 401030: ff 25 0c 20 40 00 jmpl *4202508 | |
| 52 | // DISASM-NEXT: 401030: ff 25 0c 30 40 00 jmpl *4206604 | |
| 50 | 53 | // DISASM-NEXT: 401036: 68 00 00 00 00 pushl $0 |
| 51 | 54 | // DISASM-NEXT: 40103b: e9 e0 ff ff ff jmp -32 <.plt> |
| 52 | 55 | // DISASM-EMPTY: |
| 53 | 56 | // DISASM-NEXT: zed2@plt: |
| 54 | // DISASM-NEXT: 401040: ff 25 10 20 40 00 jmpl *4202512 | |
| 57 | // DISASM-NEXT: 401040: ff 25 10 30 40 00 jmpl *4206608 | |
| 55 | 58 | // DISASM-NEXT: 401046: 68 08 00 00 00 pushl $8 |
| 56 | 59 | // DISASM-NEXT: 40104b: e9 d0 ff ff ff jmp -48 <.plt> |
| 57 | // DISASM-NEXT: 401050: ff 25 14 20 40 00 jmpl *4202516 | |
| 60 | // DISASM-NEXT: 401050: ff 25 14 30 40 00 jmpl *4206612 | |
| 58 | 61 | // DISASM-NEXT: 401056: 68 30 00 00 00 pushl $48 |
| 59 | 62 | // DISASM-NEXT: 40105b: e9 e0 ff ff ff jmp -32 <zed2@plt> |
| 60 | // DISASM-NEXT: 401060: ff 25 18 20 40 00 jmpl *4202520 | |
| 63 | // DISASM-NEXT: 401060: ff 25 18 30 40 00 jmpl *4206616 | |
| 61 | 64 | // DISASM-NEXT: 401066: 68 38 00 00 00 pushl $56 |
| 62 | 65 | // DISASM-NEXT: 40106b: e9 d0 ff ff ff jmp -48 <zed2@plt> |
| 63 | 66 |
deps/lld/test/ELF/gnu-ifunc-plt.s+18-15| ... | ... | @@ -5,22 +5,22 @@ |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv %t.so %t.o -o %tout |
| 6 | 6 | // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM |
| 7 | 7 | // RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT |
| 8 | // RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s | |
| 8 | // RUN: llvm-readobj -r --dynamic-table %tout | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | // Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt |
| 11 | 11 | // CHECK: Relocations [ |
| 12 | 12 | // CHECK-NEXT: Section (4) .rela.plt { |
| 13 | // CHECK-NEXT: 0x202018 R_X86_64_JUMP_SLOT bar2 0x0 | |
| 14 | // CHECK-NEXT: 0x202020 R_X86_64_JUMP_SLOT zed2 0x0 | |
| 15 | // CHECK-NEXT: 0x202028 R_X86_64_IRELATIVE - 0x201000 | |
| 16 | // CHECK-NEXT: 0x202030 R_X86_64_IRELATIVE - 0x201001 | |
| 13 | // CHECK-NEXT: 0x203018 R_X86_64_JUMP_SLOT bar2 0x0 | |
| 14 | // CHECK-NEXT: 0x203020 R_X86_64_JUMP_SLOT zed2 0x0 | |
| 15 | // CHECK-NEXT: 0x203028 R_X86_64_IRELATIVE - 0x201000 | |
| 16 | // CHECK-NEXT: 0x203030 R_X86_64_IRELATIVE - 0x201001 | |
| 17 | 17 | |
| 18 | 18 | // Check that .got.plt entries point back to PLT header |
| 19 | 19 | // GOTPLT: Contents of section .got.plt: |
| 20 | // GOTPLT-NEXT: 202000 00302000 00000000 00000000 00000000 | |
| 21 | // GOTPLT-NEXT: 202010 00000000 00000000 36102000 00000000 | |
| 22 | // GOTPLT-NEXT: 202020 46102000 00000000 56102000 00000000 | |
| 23 | // GOTPLT-NEXT: 202030 66102000 00000000 | |
| 20 | // GOTPLT-NEXT: 203000 00202000 00000000 00000000 00000000 | |
| 21 | // GOTPLT-NEXT: 203010 00000000 00000000 36102000 00000000 | |
| 22 | // GOTPLT-NEXT: 203020 46102000 00000000 56102000 00000000 | |
| 23 | // GOTPLT-NEXT: 203030 66102000 00000000 | |
| 24 | 24 | |
| 25 | 25 | // Check that the PLTRELSZ tag includes the IRELATIVE relocations |
| 26 | 26 | // CHECK: DynamicSection [ |
| ... | ... | @@ -28,6 +28,7 @@ |
| 28 | 28 | |
| 29 | 29 | // Check that a PLT header is written and the ifunc entries appear last |
| 30 | 30 | // DISASM: Disassembly of section .text: |
| 31 | // DISASM-EMPTY: | |
| 31 | 32 | // DISASM-NEXT: foo: |
| 32 | 33 | // DISASM-NEXT: 201000: c3 retq |
| 33 | 34 | // DISASM: bar: |
| ... | ... | @@ -37,25 +38,27 @@ |
| 37 | 38 | // DISASM-NEXT: 201007: e8 54 00 00 00 callq 84 |
| 38 | 39 | // DISASM-NEXT: 20100c: e8 1f 00 00 00 callq 31 |
| 39 | 40 | // DISASM-NEXT: 201011: e8 2a 00 00 00 callq 42 |
| 41 | // DISASM-EMPTY: | |
| 40 | 42 | // DISASM-NEXT: Disassembly of section .plt: |
| 43 | // DISASM-EMPTY: | |
| 41 | 44 | // DISASM-NEXT: .plt: |
| 42 | // DISASM-NEXT: 201020: ff 35 e2 0f 00 00 pushq 4066(%rip) | |
| 43 | // DISASM-NEXT: 201026: ff 25 e4 0f 00 00 jmpq *4068(%rip) | |
| 45 | // DISASM-NEXT: 201020: ff 35 e2 1f 00 00 pushq 8162(%rip) | |
| 46 | // DISASM-NEXT: 201026: ff 25 e4 1f 00 00 jmpq *8164(%rip) | |
| 44 | 47 | // DISASM-NEXT: 20102c: 0f 1f 40 00 nopl (%rax) |
| 45 | 48 | // DISASM-EMPTY: |
| 46 | 49 | // DISASM-NEXT: bar2@plt: |
| 47 | // DISASM-NEXT: 201030: ff 25 e2 0f 00 00 jmpq *4066(%rip) | |
| 50 | // DISASM-NEXT: 201030: ff 25 e2 1f 00 00 jmpq *8162(%rip) | |
| 48 | 51 | // DISASM-NEXT: 201036: 68 00 00 00 00 pushq $0 |
| 49 | 52 | // DISASM-NEXT: 20103b: e9 e0 ff ff ff jmp -32 <.plt> |
| 50 | 53 | // DISASM-EMPTY: |
| 51 | 54 | // DISASM-NEXT: zed2@plt: |
| 52 | // DISASM-NEXT: 201040: ff 25 da 0f 00 00 jmpq *4058(%rip) | |
| 55 | // DISASM-NEXT: 201040: ff 25 da 1f 00 00 jmpq *8154(%rip) | |
| 53 | 56 | // DISASM-NEXT: 201046: 68 01 00 00 00 pushq $1 |
| 54 | 57 | // DISASM-NEXT: 20104b: e9 d0 ff ff ff jmp -48 <.plt> |
| 55 | // DISASM-NEXT: 201050: ff 25 d2 0f 00 00 jmpq *4050(%rip) | |
| 58 | // DISASM-NEXT: 201050: ff 25 d2 1f 00 00 jmpq *8146(%rip) | |
| 56 | 59 | // DISASM-NEXT: 201056: 68 00 00 00 00 pushq $0 |
| 57 | 60 | // DISASM-NEXT: 20105b: e9 e0 ff ff ff jmp -32 <zed2@plt> |
| 58 | // DISASM-NEXT: 201060: ff 25 ca 0f 00 00 jmpq *4042(%rip) | |
| 61 | // DISASM-NEXT: 201060: ff 25 ca 1f 00 00 jmpq *8138(%rip) | |
| 59 | 62 | // DISASM-NEXT: 201066: 68 01 00 00 00 pushq $1 |
| 60 | 63 | // DISASM-NEXT: 20106b: e9 d0 ff ff ff jmp -48 <zed2@plt> |
| 61 | 64 |
deps/lld/test/ELF/gnu-ifunc-relative.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: ld.lld --strip-all %t.o -o %t |
| 4 | 4 | // RUN: llvm-readobj -r %t | FileCheck %s |
| 5 | 5 | // RUN: ld.lld %t.o -o %t |
| 6 | // RUN: llvm-readobj -r -t %t | FileCheck %s --check-prefixes=CHECK,SYM | |
| 6 | // RUN: llvm-readobj -r --symbols %t | FileCheck %s --check-prefixes=CHECK,SYM | |
| 7 | 7 | |
| 8 | 8 | .type foo STT_GNU_IFUNC |
| 9 | 9 | .globl foo |
deps/lld/test/ELF/gnu-ifunc-shared.s+11-8| ... | ... | @@ -7,6 +7,7 @@ |
| 7 | 7 | // Check that an IRELATIVE relocation is used for a non-preemptible ifunc |
| 8 | 8 | // handler and a JUMP_SLOT is used for a preemptible ifunc |
| 9 | 9 | // DISASM: Disassembly of section .text: |
| 10 | // DISASM-EMPTY: | |
| 10 | 11 | // DISASM-NEXT: fct: |
| 11 | 12 | // DISASM-NEXT: 1000: c3 retq |
| 12 | 13 | // DISASM: fct2: |
| ... | ... | @@ -18,30 +19,32 @@ |
| 18 | 19 | // DISASM-NEXT: 1011: c3 retq |
| 19 | 20 | // DISASM: f2: |
| 20 | 21 | // DISASM-NEXT: 1012: c3 retq |
| 22 | // DISASM-EMPTY: | |
| 21 | 23 | // DISASM-NEXT: Disassembly of section .plt: |
| 24 | // DISASM-EMPTY: | |
| 22 | 25 | // DISASM-NEXT: .plt: |
| 23 | // DISASM-NEXT: 1020: ff 35 e2 0f 00 00 pushq 4066(%rip) | |
| 24 | // DISASM-NEXT: 1026: ff 25 e4 0f 00 00 jmpq *4068(%rip) | |
| 26 | // DISASM-NEXT: 1020: ff 35 e2 1f 00 00 pushq 8162(%rip) | |
| 27 | // DISASM-NEXT: 1026: ff 25 e4 1f 00 00 jmpq *8164(%rip) | |
| 25 | 28 | // DISASM-NEXT: 102c: 0f 1f 40 00 nopl (%rax) |
| 26 | 29 | // DISASM-EMPTY: |
| 27 | 30 | // DISASM-NEXT: fct2@plt: |
| 28 | // DISASM-NEXT: 1030: ff 25 e2 0f 00 00 jmpq *4066(%rip) | |
| 31 | // DISASM-NEXT: 1030: ff 25 e2 1f 00 00 jmpq *8162(%rip) | |
| 29 | 32 | // DISASM-NEXT: 1036: 68 00 00 00 00 pushq $0 |
| 30 | 33 | // DISASM-NEXT: 103b: e9 e0 ff ff ff jmp -32 <.plt> |
| 31 | 34 | // DISASM-EMPTY: |
| 32 | 35 | // DISASM-NEXT: f2@plt: |
| 33 | // DISASM-NEXT: 1040: ff 25 da 0f 00 00 jmpq *4058(%rip) | |
| 36 | // DISASM-NEXT: 1040: ff 25 da 1f 00 00 jmpq *8154(%rip) | |
| 34 | 37 | // DISASM-NEXT: 1046: 68 01 00 00 00 pushq $1 |
| 35 | 38 | // DISASM-NEXT: 104b: e9 d0 ff ff ff jmp -48 <.plt> |
| 36 | // DISASM-NEXT: 1050: ff 25 d2 0f 00 00 jmpq *4050(%rip) | |
| 39 | // DISASM-NEXT: 1050: ff 25 d2 1f 00 00 jmpq *8146(%rip) | |
| 37 | 40 | // DISASM-NEXT: 1056: 68 00 00 00 00 pushq $0 |
| 38 | 41 | // DISASM-NEXT: 105b: e9 e0 ff ff ff jmp -32 <f2@plt> |
| 39 | 42 | |
| 40 | 43 | // CHECK: Relocations [ |
| 41 | 44 | // CHECK-NEXT: Section (4) .rela.plt { |
| 42 | // CHECK-NEXT: 0x2018 R_X86_64_JUMP_SLOT fct2 0x0 | |
| 43 | // CHECK-NEXT: 0x2020 R_X86_64_JUMP_SLOT f2 0x0 | |
| 44 | // CHECK-NEXT: 0x2028 R_X86_64_IRELATIVE - 0x1000 | |
| 45 | // CHECK-NEXT: 0x3018 R_X86_64_JUMP_SLOT fct2 0x0 | |
| 46 | // CHECK-NEXT: 0x3020 R_X86_64_JUMP_SLOT f2 0x0 | |
| 47 | // CHECK-NEXT: 0x3028 R_X86_64_IRELATIVE - 0x1000 | |
| 45 | 48 | |
| 46 | 49 | // Hidden expect IRELATIVE |
| 47 | 50 | .globl fct |
deps/lld/test/ELF/gnu-ifunc.s+4-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld -static %t.o -o %tout |
| 4 | 4 | // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM |
| 5 | // RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s | |
| 5 | // RUN: llvm-readobj -r --symbols --sections %tout | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // CHECK: Sections [ |
| 8 | 8 | // CHECK: Section { |
| ... | ... | @@ -90,6 +90,7 @@ |
| 90 | 90 | // CHECK-NEXT: ] |
| 91 | 91 | |
| 92 | 92 | // DISASM: Disassembly of section .text: |
| 93 | // DISASM-EMPTY: | |
| 93 | 94 | // DISASM-NEXT: foo: |
| 94 | 95 | // DISASM-NEXT: 201000: {{.*}} retq |
| 95 | 96 | // DISASM: bar: |
| ... | ... | @@ -100,7 +101,9 @@ |
| 100 | 101 | // DISASM-NEXT: 20100c: {{.*}} movl $2097496, %edx |
| 101 | 102 | // DISASM-NEXT: 201011: {{.*}} movl $2097544, %edx |
| 102 | 103 | // DISASM-NEXT: 201016: {{.*}} movl $2097545, %edx |
| 104 | // DISASM-EMPTY: | |
| 103 | 105 | // DISASM-NEXT: Disassembly of section .plt: |
| 106 | // DISASM-EMPTY: | |
| 104 | 107 | // DISASM-NEXT: .plt: |
| 105 | 108 | // DISASM-NEXT: 201020: {{.*}} jmpq *4058(%rip) |
| 106 | 109 | // DISASM-NEXT: 201026: {{.*}} pushq $0 |
deps/lld/test/ELF/gnu-unique.s+3-3| ... | ... | @@ -2,12 +2,12 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t |
| 3 | 3 | // |
| 4 | 4 | // RUN: ld.lld %t -shared -o %tout.so |
| 5 | // RUN: llvm-readobj -dyn-symbols %tout.so | FileCheck -check-prefix=GNU %s | |
| 5 | // RUN: llvm-readobj --dyn-syms %tout.so | FileCheck -check-prefix=GNU %s | |
| 6 | 6 | // RUN: ld.lld %t -shared -o %tout.so --gnu-unique |
| 7 | // RUN: llvm-readobj -dyn-symbols %tout.so | FileCheck -check-prefix=GNU %s | |
| 7 | // RUN: llvm-readobj --dyn-syms %tout.so | FileCheck -check-prefix=GNU %s | |
| 8 | 8 | // |
| 9 | 9 | // RUN: ld.lld %t -shared -o %tout.so --no-gnu-unique |
| 10 | // RUN: llvm-readobj -dyn-symbols %tout.so | FileCheck -check-prefix=NO %s | |
| 10 | // RUN: llvm-readobj --dyn-syms %tout.so | FileCheck -check-prefix=NO %s | |
| 11 | 11 | |
| 12 | 12 | // Check that STB_GNU_UNIQUE is treated as a global and ends up in the dynamic |
| 13 | 13 | // symbol table as STB_GNU_UNIQUE. |
deps/lld/test/ELF/gnustack.s+3-3| ... | ... | @@ -2,13 +2,13 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 |
| 3 | 3 | |
| 4 | 4 | # RUN: ld.lld %t1 -z execstack -o %t |
| 5 | # RUN: llvm-readobj --program-headers -s %t | FileCheck --check-prefix=RWX %s | |
| 5 | # RUN: llvm-readobj --program-headers -S %t | FileCheck --check-prefix=RWX %s | |
| 6 | 6 | |
| 7 | 7 | # RUN: ld.lld %t1 -o %t |
| 8 | # RUN: llvm-readobj --program-headers -s %t | FileCheck --check-prefix=RW %s | |
| 8 | # RUN: llvm-readobj --program-headers -S %t | FileCheck --check-prefix=RW %s | |
| 9 | 9 | |
| 10 | 10 | # RUN: ld.lld %t1 -o %t -z noexecstack |
| 11 | # RUN: llvm-readobj --program-headers -s %t | FileCheck --check-prefix=RW %s | |
| 11 | # RUN: llvm-readobj --program-headers -S %t | FileCheck --check-prefix=RW %s | |
| 12 | 12 | |
| 13 | 13 | # RW: Type: PT_GNU_STACK |
| 14 | 14 | # RW-NEXT: Offset: 0x0 |
deps/lld/test/ELF/got-aarch64.s deleted-40| ... | ... | @@ -1,40 +0,0 @@ |
| 1 | // REQUIRES: aarch64 | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %t.o | |
| 3 | // RUN: ld.lld --hash-style=sysv -shared %t.o -o %t.so | |
| 4 | // RUN: llvm-readobj -s -r %t.so | FileCheck %s | |
| 5 | // RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASM %s | |
| 6 | ||
| 7 | // CHECK: Name: .got | |
| 8 | // CHECK-NEXT: Type: SHT_PROGBITS | |
| 9 | // CHECK-NEXT: Flags [ | |
| 10 | // CHECK-NEXT: SHF_ALLOC | |
| 11 | // CHECK-NEXT: SHF_WRITE | |
| 12 | // CHECK-NEXT: ] | |
| 13 | // CHECK-NEXT: Address: 0x30090 | |
| 14 | // CHECK-NEXT: Offset: | |
| 15 | // CHECK-NEXT: Size: 8 | |
| 16 | // CHECK-NEXT: Link: 0 | |
| 17 | // CHECK-NEXT: Info: 0 | |
| 18 | // CHECK-NEXT: AddressAlignment: 8 | |
| 19 | ||
| 20 | // CHECK: Relocations [ | |
| 21 | // CHECK-NEXT: Section ({{.*}}) .rela.dyn { | |
| 22 | // CHECK-NEXT: 0x30090 R_AARCH64_GLOB_DAT dat 0x0 | |
| 23 | // CHECK-NEXT: } | |
| 24 | // CHECK-NEXT: ] | |
| 25 | ||
| 26 | // Page(0x20098) - Page(0x10000) = 0x10000 = 65536 | |
| 27 | // 0x20098 & 0xff8 = 0x98 = 152 | |
| 28 | ||
| 29 | // DISASM: main: | |
| 30 | // DISASM-NEXT: 10000: 00 01 00 90 adrp x0, #131072 | |
| 31 | // DISASM-NEXT: 10004: 00 48 40 f9 ldr x0, [x0, #144] | |
| 32 | ||
| 33 | .global main,foo,dat | |
| 34 | .text | |
| 35 | main: | |
| 36 | adrp x0, :got:dat | |
| 37 | ldr x0, [x0, :got_lo12:dat] | |
| 38 | .data | |
| 39 | dat: | |
| 40 | .word 42 |
deps/lld/test/ELF/got-i386.s+9-8| ... | ... | @@ -1,10 +1,10 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t |
| 4 | // RUN: llvm-readobj -s -r -t %t | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S -r --symbols %t | FileCheck %s | |
| 5 | 5 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s |
| 6 | 6 | |
| 7 | // CHECK: Name: .got | |
| 7 | // CHECK: Name: .got.plt | |
| 8 | 8 | // CHECK-NEXT: Type: SHT_PROGBITS |
| 9 | 9 | // CHECK-NEXT: Flags [ |
| 10 | 10 | // CHECK-NEXT: SHF_ALLOC |
| ... | ... | @@ -12,14 +12,14 @@ |
| 12 | 12 | // CHECK-NEXT: ] |
| 13 | 13 | // CHECK-NEXT: Address: 0x402000 |
| 14 | 14 | // CHECK-NEXT: Offset: |
| 15 | // CHECK-NEXT: Size: 0 | |
| 15 | // CHECK-NEXT: Size: | |
| 16 | 16 | // CHECK-NEXT: Link: |
| 17 | 17 | // CHECK-NEXT: Info: |
| 18 | 18 | // CHECK-NEXT: AddressAlignment: |
| 19 | 19 | |
| 20 | 20 | // CHECK: Symbol { |
| 21 | 21 | // CHECK: Name: bar |
| 22 | // CHECK-NEXT: Value: 0x402000 | |
| 22 | // CHECK-NEXT: Value: 0x40200C | |
| 23 | 23 | // CHECK-NEXT: Size: 10 |
| 24 | 24 | // CHECK-NEXT: Binding: Global |
| 25 | 25 | // CHECK-NEXT: Type: Object |
| ... | ... | @@ -28,7 +28,7 @@ |
| 28 | 28 | // CHECK-NEXT: } |
| 29 | 29 | // CHECK-NEXT: Symbol { |
| 30 | 30 | // CHECK-NEXT: Name: obj |
| 31 | // CHECK-NEXT: Value: 0x40200A | |
| 31 | // CHECK-NEXT: Value: 0x402016 | |
| 32 | 32 | // CHECK-NEXT: Size: 10 |
| 33 | 33 | // CHECK-NEXT: Binding: Global |
| 34 | 34 | // CHECK-NEXT: Type: Object |
| ... | ... | @@ -40,10 +40,11 @@ |
| 40 | 40 | // 0x40200A - 10 = addr(.got) = 0x402000 |
| 41 | 41 | // 0x40200A + 5 - 15 = addr(.got) = 0x402000 |
| 42 | 42 | // DISASM: Disassembly of section .text: |
| 43 | // DISASM-EMPTY: | |
| 43 | 44 | // DISASM-NEXT: _start: |
| 44 | // DISASM-NEXT: 401000: c7 81 00 00 00 00 01 00 00 00 movl $1, (%ecx) | |
| 45 | // DISASM-NEXT: 40100a: c7 81 0a 00 00 00 02 00 00 00 movl $2, 10(%ecx) | |
| 46 | // DISASM-NEXT: 401014: c7 81 0f 00 00 00 03 00 00 00 movl $3, 15(%ecx) | |
| 45 | // DISASM-NEXT: 401000: c7 81 0c 00 00 00 01 00 00 00 movl $1, 12(%ecx) | |
| 46 | // DISASM-NEXT: 40100a: c7 81 16 00 00 00 02 00 00 00 movl $2, 22(%ecx) | |
| 47 | // DISASM-NEXT: 401014: c7 81 1b 00 00 00 03 00 00 00 movl $3, 27(%ecx) | |
| 47 | 48 | |
| 48 | 49 | .global _start |
| 49 | 50 | _start: |
deps/lld/test/ELF/got-plt-header.s+11-11| ... | ... | @@ -1,31 +1,31 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -s -section-data %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S --section-data %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | call foo@plt |
| 7 | 7 | |
| 8 | 8 | // Check that the first .got.plt entry has the address of the dynamic table. |
| 9 | 9 | |
| 10 | // CHECK: Type: SHT_DYNAMIC | |
| 11 | // CHECK-NEXT: Flags [ | |
| 12 | // CHECK-NEXT: SHF_ALLOC | |
| 13 | // CHECK-NEXT: SHF_WRITE | |
| 14 | // CHECK-NEXT: ] | |
| 15 | // CHECK-NEXT: Address: 0x2000 | |
| 16 | ||
| 10 | 17 | // CHECK: Name: .got.plt |
| 11 | 18 | // CHECK-NEXT: Type: SHT_PROGBITS |
| 12 | 19 | // CHECK-NEXT: Flags [ |
| 13 | 20 | // CHECK-NEXT: SHF_ALLOC |
| 14 | 21 | // CHECK-NEXT: SHF_WRITE |
| 15 | 22 | // CHECK-NEXT: ] |
| 16 | // CHECK-NEXT: Address: 0x2000 | |
| 17 | // CHECK-NEXT: Offset: 0x2000 | |
| 23 | // CHECK-NEXT: Address: 0x3000 | |
| 24 | // CHECK-NEXT: Offset: 0x3000 | |
| 18 | 25 | // CHECK-NEXT: Size: 32 |
| 19 | 26 | // CHECK-NEXT: Link: 0 |
| 20 | 27 | // CHECK-NEXT: Info: 0 |
| 21 | 28 | // CHECK-NEXT: AddressAlignment: 8 |
| 22 | 29 | // CHECK-NEXT: EntrySize: 0 |
| 23 | 30 | // CHECK-NEXT: SectionData ( |
| 24 | // CHECK-NEXT: 0000: 00300000 00000000 00000000 00000000 | |
| 25 | ||
| 26 | // CHECK: Type: SHT_DYNAMIC | |
| 27 | // CHECK-NEXT: Flags [ | |
| 28 | // CHECK-NEXT: SHF_ALLOC | |
| 29 | // CHECK-NEXT: SHF_WRITE | |
| 30 | // CHECK-NEXT: ] | |
| 31 | // CHECK-NEXT: Address: 0x3000 | |
| 31 | // CHECK-NEXT: 0000: 00200000 00000000 00000000 00000000 |
deps/lld/test/ELF/got.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld -shared %t2.o -o %t2.so |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv %t.o %t2.so -o %t |
| 6 | // RUN: llvm-readobj -s -r %t | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S -r %t | FileCheck %s | |
| 7 | 7 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s |
| 8 | 8 | |
| 9 | 9 | // CHECK: Name: .got |
deps/lld/test/ELF/got32-i386.s+1-1| ... | ... | @@ -16,7 +16,7 @@ _start: |
| 16 | 16 | # CHECK: _start: |
| 17 | 17 | # CHECK-NEXT: 401001: 8b 1d {{.*}} movl 4202496, %ebx |
| 18 | 18 | # CHECK: Sections: |
| 19 | # CHECK: Name Size Address | |
| 19 | # CHECK: Name Size VMA | |
| 20 | 20 | # CHECK: .got 00000004 0000000000402000 |
| 21 | 21 | |
| 22 | 22 | # RUN: not ld.lld %t.o -o %t -pie 2>&1 | FileCheck %s --check-prefix=ERR |
deps/lld/test/ELF/got32x-i386.s+6-6| ... | ... | @@ -33,13 +33,13 @@ |
| 33 | 33 | |
| 34 | 34 | ## 73728 == 0x12000 == ADDR(.got) |
| 35 | 35 | # CHECK: _start: |
| 36 | # CHECK-NEXT: 401001: 8b 05 {{.*}} movl 4206592, %eax | |
| 37 | # CHECK-NEXT: 401007: 8b 1d {{.*}} movl 4206592, %ebx | |
| 38 | # CHECK-NEXT: 40100d: 8b 80 {{.*}} movl -4(%eax), %eax | |
| 39 | # CHECK-NEXT: 401013: 8b 83 {{.*}} movl -4(%ebx), %eax | |
| 36 | # CHECK-NEXT: 401001: 8b 05 {{.*}} movl 4202496, %eax | |
| 37 | # CHECK-NEXT: 401007: 8b 1d {{.*}} movl 4202496, %ebx | |
| 38 | # CHECK-NEXT: 40100d: 8b 80 {{.*}} movl -4096(%eax), %eax | |
| 39 | # CHECK-NEXT: 401013: 8b 83 {{.*}} movl -4096(%ebx), %eax | |
| 40 | 40 | # CHECK: Sections: |
| 41 | # CHECK: Name Size Address | |
| 42 | # CHECK: .got 00000004 0000000000403000 | |
| 41 | # CHECK: Name Size VMA | |
| 42 | # CHECK: .got.plt 0000000c 0000000000403000 | |
| 43 | 43 | |
| 44 | 44 | # RUN: not ld.lld %S/Inputs/i386-got32x-baseless.elf -o %t1 -pie 2>&1 | \ |
| 45 | 45 | # RUN: FileCheck %s --check-prefix=ERR |
deps/lld/test/ELF/gotpc-relax-nopic.s+16-14| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-unknown-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld --hash-style=sysv %t.o -o %t1 |
| 4 | # RUN: llvm-readobj -symbols -r %t1 | FileCheck --check-prefix=SYMRELOC %s | |
| 4 | # RUN: llvm-readobj --symbols -r %t1 | FileCheck --check-prefix=SYMRELOC %s | |
| 5 | 5 | # RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s |
| 6 | 6 | |
| 7 | 7 | ## There is no relocations. |
| ... | ... | @@ -14,6 +14,7 @@ |
| 14 | 14 | |
| 15 | 15 | ## 2105344 = 0x202000 (bar) |
| 16 | 16 | # DISASM: Disassembly of section .text: |
| 17 | # DISASM-EMPTY: | |
| 17 | 18 | # DISASM-NEXT: _start: |
| 18 | 19 | # DISASM-NEXT: 201000: {{.*}} adcq $2105344, %rax |
| 19 | 20 | # DISASM-NEXT: 201007: {{.*}} addq $2105344, %rbx |
| ... | ... | @@ -26,7 +27,7 @@ |
| 26 | 27 | # DISASM-NEXT: 201038: {{.*}} testq $2105344, %r15 |
| 27 | 28 | |
| 28 | 29 | # RUN: ld.lld --hash-style=sysv -shared %t.o -o %t2 |
| 29 | # RUN: llvm-readobj -s -r -d %t2 | FileCheck --check-prefix=SEC-PIC %s | |
| 30 | # RUN: llvm-readobj -S -r -d %t2 | FileCheck --check-prefix=SEC-PIC %s | |
| 30 | 31 | # RUN: llvm-objdump -d %t2 | FileCheck --check-prefix=DISASM-PIC %s |
| 31 | 32 | # SEC-PIC: Section { |
| 32 | 33 | # SEC-PIC: Index: |
| ... | ... | @@ -36,8 +37,8 @@ |
| 36 | 37 | # SEC-PIC-NEXT: SHF_ALLOC |
| 37 | 38 | # SEC-PIC-NEXT: SHF_WRITE |
| 38 | 39 | # SEC-PIC-NEXT: ] |
| 39 | # SEC-PIC-NEXT: Address: 0x30A0 | |
| 40 | # SEC-PIC-NEXT: Offset: 0x30A0 | |
| 40 | # SEC-PIC-NEXT: Address: 0x20A0 | |
| 41 | # SEC-PIC-NEXT: Offset: 0x20A0 | |
| 41 | 42 | # SEC-PIC-NEXT: Size: 8 |
| 42 | 43 | # SEC-PIC-NEXT: Link: |
| 43 | 44 | # SEC-PIC-NEXT: Info: |
| ... | ... | @@ -46,7 +47,7 @@ |
| 46 | 47 | # SEC-PIC-NEXT: } |
| 47 | 48 | # SEC-PIC: Relocations [ |
| 48 | 49 | # SEC-PIC-NEXT: Section ({{.*}}) .rela.dyn { |
| 49 | # SEC-PIC-NEXT: 0x30A0 R_X86_64_RELATIVE - 0x2000 | |
| 50 | # SEC-PIC-NEXT: 0x20A0 R_X86_64_RELATIVE - 0x3000 | |
| 50 | 51 | # SEC-PIC-NEXT: } |
| 51 | 52 | # SEC-PIC-NEXT: ] |
| 52 | 53 | # SEC-PIC: 0x000000006FFFFFF9 RELACOUNT 1 |
| ... | ... | @@ -55,16 +56,17 @@ |
| 55 | 56 | ## Ex: 0x1000 + 4249 + 7 = 0x20A0 |
| 56 | 57 | ## 0x102a + 4207 + 7 = 0x20A0 |
| 57 | 58 | # DISASM-PIC: Disassembly of section .text: |
| 59 | # DISASM-PIC-EMPTY: | |
| 58 | 60 | # DISASM-PIC-NEXT: _start: |
| 59 | # DISASM-PIC-NEXT: 1000: {{.*}} adcq 8345(%rip), %rax | |
| 60 | # DISASM-PIC-NEXT: 1007: {{.*}} addq 8338(%rip), %rbx | |
| 61 | # DISASM-PIC-NEXT: 100e: {{.*}} andq 8331(%rip), %rcx | |
| 62 | # DISASM-PIC-NEXT: 1015: {{.*}} cmpq 8324(%rip), %rdx | |
| 63 | # DISASM-PIC-NEXT: 101c: {{.*}} orq 8317(%rip), %rdi | |
| 64 | # DISASM-PIC-NEXT: 1023: {{.*}} sbbq 8310(%rip), %rsi | |
| 65 | # DISASM-PIC-NEXT: 102a: {{.*}} subq 8303(%rip), %rbp | |
| 66 | # DISASM-PIC-NEXT: 1031: {{.*}} xorq 8296(%rip), %r8 | |
| 67 | # DISASM-PIC-NEXT: 1038: {{.*}} testq %r15, 8289(%rip) | |
| 61 | # DISASM-PIC-NEXT: 1000: {{.*}} adcq 4249(%rip), %rax | |
| 62 | # DISASM-PIC-NEXT: 1007: {{.*}} addq 4242(%rip), %rbx | |
| 63 | # DISASM-PIC-NEXT: 100e: {{.*}} andq 4235(%rip), %rcx | |
| 64 | # DISASM-PIC-NEXT: 1015: {{.*}} cmpq 4228(%rip), %rdx | |
| 65 | # DISASM-PIC-NEXT: 101c: {{.*}} orq 4221(%rip), %rdi | |
| 66 | # DISASM-PIC-NEXT: 1023: {{.*}} sbbq 4214(%rip), %rsi | |
| 67 | # DISASM-PIC-NEXT: 102a: {{.*}} subq 4207(%rip), %rbp | |
| 68 | # DISASM-PIC-NEXT: 1031: {{.*}} xorq 4200(%rip), %r8 | |
| 69 | # DISASM-PIC-NEXT: 1038: {{.*}} testq %r15, 4193(%rip) | |
| 68 | 70 | |
| 69 | 71 | .data |
| 70 | 72 | .type bar, @object |
deps/lld/test/ELF/gotpc-relax-und-dso.s+2-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -relax-relocations -triple=x86_64-pc-linux %S/Inputs/gotpc-relax-und-dso.s -o %tdso.o |
| 4 | 4 | # RUN: ld.lld -shared %tdso.o -o %t.so |
| 5 | 5 | # RUN: ld.lld --hash-style=sysv -shared %t.o %t.so -o %tout |
| 6 | # RUN: llvm-readobj -r -s %tout | FileCheck --check-prefix=RELOC %s | |
| 6 | # RUN: llvm-readobj -r -S %tout | FileCheck --check-prefix=RELOC %s | |
| 7 | 7 | # RUN: llvm-objdump -d %tout | FileCheck --check-prefix=DISASM %s |
| 8 | 8 | |
| 9 | 9 | # RELOC: Relocations [ |
| ... | ... | @@ -17,6 +17,7 @@ |
| 17 | 17 | # 0x101e + 7 - 36 = 0x1001 |
| 18 | 18 | # 0x1025 + 7 - 43 = 0x1001 |
| 19 | 19 | # DISASM: Disassembly of section .text: |
| 20 | # DISASM-EMPTY: | |
| 20 | 21 | # DISASM-NEXT: foo: |
| 21 | 22 | # DISASM-NEXT: nop |
| 22 | 23 | # DISASM: hid: |
deps/lld/test/ELF/gotpc-relax.s+1| ... | ... | @@ -13,6 +13,7 @@ |
| 13 | 13 | # 0x201011 + 7 - 23 = 0x201001 |
| 14 | 14 | # 0x201018 + 7 - 30 = 0x201001 |
| 15 | 15 | # DISASM: Disassembly of section .text: |
| 16 | # DISASM-EMPTY: | |
| 16 | 17 | # DISASM-NEXT: foo: |
| 17 | 18 | # DISASM-NEXT: 201000: 90 nop |
| 18 | 19 | # DISASM: hid: |
deps/lld/test/ELF/gotpcrelx.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: %s -o %t.o |
| 4 | 4 | // RUN: llvm-readobj -r %t.o | FileCheck --check-prefix=RELS %s |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared |
| 6 | // RUN: llvm-readobj -s -r %t.so | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S -r %t.so | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | movq foo@GOTPCREL(%rip), %rax |
| 9 | 9 | movq bar@GOTPCREL(%rip), %rax |
deps/lld/test/ELF/hexagon-shared.s+7-7| ... | ... | @@ -25,22 +25,22 @@ jumpr r0 |
| 25 | 25 | # R_HEX_GOT_16_X |
| 26 | 26 | r0 = add(r1,##bar@GOT) |
| 27 | 27 | |
| 28 | # PLT: { immext(#65472 | |
| 29 | # PLT: r28 = add(pc,##65488) } | |
| 28 | # PLT: { immext(#131008 | |
| 29 | # PLT: r28 = add(pc,##131024) } | |
| 30 | 30 | # PLT: { r14 -= add(r28,#16) |
| 31 | 31 | # PLT: r15 = memw(r28+#8) |
| 32 | 32 | # PLT: r28 = memw(r28+#4) } |
| 33 | 33 | # PLT: { r14 = asr(r14,#2) |
| 34 | 34 | # PLT: jumpr r28 } |
| 35 | 35 | # PLT: { trap0(#219) } |
| 36 | # PLT: immext(#65472) | |
| 37 | # PLT: r14 = add(pc,##65472) } | |
| 36 | # PLT: immext(#131008) | |
| 37 | # PLT: r14 = add(pc,##131008) } | |
| 38 | 38 | # PLT: r28 = memw(r14+#0) } |
| 39 | 39 | # PLT: jumpr r28 } |
| 40 | 40 | |
| 41 | # TEXT: 10000: 00 00 02 00 00020000 | |
| 41 | # TEXT: 10000: 00 00 01 00 00010000 | |
| 42 | 42 | # TEXT: { 	call 0x10050 } |
| 43 | # TEXT: r0 = add(r1,##65664) } | |
| 43 | # TEXT: r0 = add(r1,##-65408) } | |
| 44 | 44 | |
| 45 | 45 | # GOT: .got: |
| 46 | # GOT: 30080:	00 00 00 00 00000000 <unknown> | |
| 46 | # GOT: 20080:	00 00 00 00 00000000 <unknown> |
deps/lld/test/ELF/hidden-shared-err.s+1-1| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | # RUN: not ld.lld %t.o %t3.o %t2.so -o %t 2>&1 | FileCheck %s |
| 12 | 12 | # RUN: not ld.lld %t3.o %t.o %t2.so -o %t 2>&1 | FileCheck %s |
| 13 | 13 | |
| 14 | # CHECK: undefined symbol: foo | |
| 14 | # CHECK: undefined hidden symbol: foo | |
| 15 | 15 | |
| 16 | 16 | .global _start |
| 17 | 17 | _start: |
deps/lld/test/ELF/i386-cet.s created+47| ... | ... | @@ -0,0 +1,47 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %s -o %t.o | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %p/Inputs/i386-cet1.s -o %t1.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %p/Inputs/i386-cet2.s -o %t2.o | |
| 5 | # RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %p/Inputs/i386-cet3.s -o %t3.o | |
| 6 | # RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %p/Inputs/i386-cet4.s -o %t4.o | |
| 7 | ||
| 8 | # RUN: ld.lld -e func1 %t.o %t1.o -o %t | |
| 9 | # RUN: llvm-readelf -n %t | FileCheck -check-prefix=CET -match-full-lines %s | |
| 10 | ||
| 11 | # RUN: ld.lld -e func1 %t.o %t2.o -o %t | |
| 12 | # RUN: llvm-readelf -n %t | FileCheck -check-prefix=CET -match-full-lines %s | |
| 13 | ||
| 14 | # CET: Properties: x86 feature: IBT, SHSTK | |
| 15 | ||
| 16 | # RUN: ld.lld -e func1 %t.o %t3.o -o %t | |
| 17 | # RUN: llvm-readelf -S %t | FileCheck -check-prefix=NOCET %s | |
| 18 | ||
| 19 | # NOCET: Section Headers | |
| 20 | # NOCET-NOT: .note.gnu.property | |
| 21 | ||
| 22 | # RUN: not ld.lld -e func1 %t.o %t3.o -o %t --require-cet 2>&1 \ | |
| 23 | # RUN: | FileCheck -check-prefix=ERROR %s | |
| 24 | # ERROR: i386-cet.s.tmp3.o: --require-cet: file is not compatible with CET | |
| 25 | ||
| 26 | # RUN: ld.lld -e func1 %t.o %t4.o -o %t | |
| 27 | # RUN: llvm-readelf -n %t | FileCheck -check-prefix=NOSHSTK -match-full-lines %s | |
| 28 | ||
| 29 | # Check .note.gnu.protery without property SHSTK. | |
| 30 | # NOSHSTK: Properties: x86 feature: IBT | |
| 31 | ||
| 32 | .section ".note.gnu.property", "a" | |
| 33 | .long 4 | |
| 34 | .long 0xc | |
| 35 | .long 0x5 | |
| 36 | .asciz "GNU" | |
| 37 | ||
| 38 | .long 0xc0000002 | |
| 39 | .long 4 | |
| 40 | .long 3 | |
| 41 | ||
| 42 | .text | |
| 43 | .globl func1 | |
| 44 | .type func1,@function | |
| 45 | func1: | |
| 46 | call func2 | |
| 47 | ret |
deps/lld/test/ELF/i386-debug-noabs.test+2-2| ... | ... | @@ -29,5 +29,5 @@ Sections: |
| 29 | 29 | Symbol: _GLOBAL_OFFSET_TABLE_ |
| 30 | 30 | Type: R_386_GOTPC |
| 31 | 31 | Symbols: |
| 32 | Global: | |
| 33 | - Name: _GLOBAL_OFFSET_TABLE_ | |
| 32 | - Name: _GLOBAL_OFFSET_TABLE_ | |
| 33 | Binding: STB_GLOBAL |
deps/lld/test/ELF/i386-got-and-copy.s+1-1| ... | ... | @@ -14,8 +14,8 @@ |
| 14 | 14 | |
| 15 | 15 | # CHECK: Relocations [ |
| 16 | 16 | # CHECK-NEXT: Section (4) .rel.dyn { |
| 17 | # CHECK-NEXT: 0x{{[0-9A-F]+}} R_386_COPY foo | |
| 18 | 17 | # CHECK-NEXT: 0x{{[0-9A-F]+}} R_386_GLOB_DAT foo |
| 18 | # CHECK-NEXT: 0x{{[0-9A-F]+}} R_386_COPY foo | |
| 19 | 19 | # CHECK-NEXT: } |
| 20 | 20 | # CHECK-NEXT: ] |
| 21 | 21 |
deps/lld/test/ELF/i386-gotoff-shared.s+4-12| ... | ... | @@ -1,23 +1,15 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -s %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readelf -S %t.so | FileCheck %s | |
| 5 | 5 | // RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASM %s |
| 6 | 6 | |
| 7 | 7 | bar: |
| 8 | 8 | movl bar@GOTOFF(%ebx), %eax |
| 9 | 9 | mov bar@GOT, %eax |
| 10 | 10 | |
| 11 | // CHECK: Name: .got | |
| 12 | // CHECK-NEXT: Type: SHT_PROGBITS | |
| 13 | // CHECK-NEXT: Flags [ | |
| 14 | // CHECK-NEXT: SHF_ALLOC | |
| 15 | // CHECK-NEXT: SHF_WRITE | |
| 16 | // CHECK-NEXT: ] | |
| 17 | // CHECK-NEXT: Address: 0x2050 | |
| 18 | // CHECK-NEXT: Offset: 0x2050 | |
| 19 | // CHECK-NEXT: Size: 4 | |
| 11 | // CHECK: .got.plt PROGBITS 00003000 | |
| 20 | 12 | |
| 21 | // 0x1000 - (0x2050 + 4) = -4180 | |
| 13 | // 0x1000 - 0x3000 (.got.plt) = -8192 | |
| 22 | 14 | |
| 23 | // DISASM: 1000: {{.*}} movl -4180(%ebx), %eax | |
| 15 | // DISASM: 1000: {{.*}} movl -8192(%ebx), %eax |
deps/lld/test/ELF/i386-gotpc-dynamic.s+4-19| ... | ... | @@ -1,28 +1,13 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared |
| 4 | # RUN: llvm-readobj -s %t.so | FileCheck %s | |
| 4 | # RUN: llvm-readelf -S %t.so | FileCheck %s | |
| 5 | 5 | # RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASM %s |
| 6 | 6 | |
| 7 | # CHECK: Section { | |
| 8 | # CHECK: Index: 7 | |
| 9 | # CHECK-NEXT: Name: .got | |
| 10 | # CHECK-NEXT: Type: SHT_PROGBITS | |
| 11 | # CHECK-NEXT: Flags [ | |
| 12 | # CHECK-NEXT: SHF_ALLOC | |
| 13 | # CHECK-NEXT: SHF_WRITE | |
| 14 | # CHECK-NEXT: ] | |
| 15 | # CHECK-NEXT: Address: 0x2030 | |
| 16 | # CHECK-NEXT: Offset: | |
| 17 | # CHECK-NEXT: Size: | |
| 18 | # CHECK-NEXT: Link: | |
| 19 | # CHECK-NEXT: Info: | |
| 20 | # CHECK-NEXT: AddressAlignment: | |
| 21 | # CHECK-NEXT: EntrySize: | |
| 22 | # CHECK-NEXT: } | |
| 7 | # CHECK: .got.plt PROGBITS 00003000 | |
| 23 | 8 | |
| 24 | ## 0x1000 + 4144 = 0x2030 | |
| 25 | # DISASM: 1000: {{.*}} movl $4144, %eax | |
| 9 | ## 0x3000 - 0x1000 = 8192 | |
| 10 | # DISASM: 1000: {{.*}} movl $8192, %eax | |
| 26 | 11 | |
| 27 | 12 | .section .foo,"ax",@progbits |
| 28 | 13 | foo: |
deps/lld/test/ELF/i386-gotpc.s+5-18| ... | ... | @@ -1,28 +1,15 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -s %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readelf -S %t.so | FileCheck %s | |
| 5 | 5 | // RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASM %s |
| 6 | 6 | |
| 7 | 7 | movl $_GLOBAL_OFFSET_TABLE_, %eax |
| 8 | 8 | |
| 9 | // CHECK: Name: .got.plt | |
| 10 | // CHECK-NEXT: Type: SHT_PROGBITS | |
| 11 | // CHECK-NEXT: Flags [ | |
| 12 | // CHECK-NEXT: SHF_ALLOC | |
| 13 | // CHECK-NEXT: SHF_WRITE | |
| 14 | // CHECK-NEXT: ] | |
| 15 | // CHECK-NEXT: Address: 0x2000 | |
| 16 | ||
| 17 | // CHECK: Name: .got | |
| 18 | // CHECK-NEXT: Type: SHT_PROGBITS | |
| 19 | // CHECK-NEXT: Flags [ | |
| 20 | // CHECK-NEXT: SHF_ALLOC | |
| 21 | // CHECK-NEXT: SHF_WRITE | |
| 22 | // CHECK-NEXT: ] | |
| 23 | // CHECK-NEXT: Address: 0x3030 | |
| 9 | // CHECK: .got.plt PROGBITS 00003000 | |
| 24 | 10 | |
| 25 | 11 | // DISASM: Disassembly of section .text: |
| 12 | // DISASM-EMPTY: | |
| 26 | 13 | // DISASM-NEXT: .text: |
| 27 | // DISASM-NEXT: 1000: {{.*}} movl $8240, %eax | |
| 28 | // 0x3030 - 0x1000 = 0x2030 | |
| 14 | // DISASM-NEXT: 1000: {{.*}} movl $8192, %eax | |
| 15 | // 0x3000 (.got.plt) - 0x1000 = 8192 |
deps/lld/test/ELF/i386-merge.s+5-5| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t -shared |
| 4 | // RUN: llvm-readobj -s -section-data %t | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S --section-data %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // CHECK: Name: .mysec |
| 7 | 7 | // CHECK-NEXT: Type: |
| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | // CHECK-NEXT: SHF_ALLOC |
| 10 | 10 | // CHECK-NEXT: SHF_MERGE |
| 11 | 11 | // CHECK-NEXT: ] |
| 12 | // CHECK-NEXT: Address: 0x158 | |
| 12 | // CHECK-NEXT: Address: 0x178 | |
| 13 | 13 | // CHECK-NEXT: Offset: |
| 14 | 14 | // CHECK-NEXT: Size: |
| 15 | 15 | // CHECK-NEXT: Link: |
| ... | ... | @@ -27,15 +27,15 @@ |
| 27 | 27 | // CHECK-NEXT: SHF_ALLOC |
| 28 | 28 | // CHECK-NEXT: SHF_WRITE |
| 29 | 29 | // CHECK-NEXT: ] |
| 30 | // CHECK-NEXT: Address: 0x1000 | |
| 31 | // CHECK-NEXT: Offset: 0x1000 | |
| 30 | // CHECK-NEXT: Address: 0x2000 | |
| 31 | // CHECK-NEXT: Offset: 0x2000 | |
| 32 | 32 | // CHECK-NEXT: Size: 4 |
| 33 | 33 | // CHECK-NEXT: Link: 0 |
| 34 | 34 | // CHECK-NEXT: Info: 0 |
| 35 | 35 | // CHECK-NEXT: AddressAlignment: 1 |
| 36 | 36 | // CHECK-NEXT: EntrySize: 0 |
| 37 | 37 | // CHECK-NEXT: SectionData ( |
| 38 | // CHECK-NEXT: 0000: 58010000 | | |
| 38 | // CHECK-NEXT: 0000: 78010000 | | |
| 39 | 39 | // CHECK-NEXT: ) |
| 40 | 40 | |
| 41 | 41 | // The content of .data should be the address of .mysec. |
deps/lld/test/ELF/i386-pc16.test+6-6| ... | ... | @@ -32,9 +32,9 @@ Sections: |
| 32 | 32 | Symbol: _start |
| 33 | 33 | Type: R_386_PC16 |
| 34 | 34 | Symbols: |
| 35 | Global: | |
| 36 | - Name: _start | |
| 37 | Type: STT_FUNC | |
| 38 | Section: .text | |
| 39 | Value: 0x1234 | |
| 40 | Size: 4 | |
| 35 | - Name: _start | |
| 36 | Type: STT_FUNC | |
| 37 | Section: .text | |
| 38 | Value: 0x1234 | |
| 39 | Size: 4 | |
| 40 | Binding: STB_GLOBAL |
deps/lld/test/ELF/i386-relax-reloc.s+9-4| ... | ... | @@ -1,12 +1,17 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o -relax-relocations |
| 3 | 3 | // RUN: ld.lld -shared %t.o -o %t.so |
| 4 | // RUN: llvm-readelf -S %t.so | FileCheck --check-prefix=SEC %s | |
| 4 | 5 | // RUN: llvm-objdump -d %t.so | FileCheck %s |
| 5 | 6 | |
| 7 | // SEC: .got PROGBITS 00002050 | |
| 8 | // SEC-NEXT: .got.plt PROGBITS 00003000 | |
| 9 | ||
| 10 | // 0x2050 - 0x3000 = -4016 | |
| 11 | // CHECK: foo: | |
| 12 | // CHECK-NEXT: movl -4016(%ebx), %eax | |
| 13 | // CHECK-NEXT: movl -4008(%ebx), %eax | |
| 14 | ||
| 6 | 15 | foo: |
| 7 | 16 | movl bar@GOT(%ebx), %eax |
| 8 | 17 | movl bar+8@GOT(%ebx), %eax |
| 9 | ||
| 10 | // CHECK: foo: | |
| 11 | // CHECK-NEXT: movl -4(%ebx), %eax | |
| 12 | // CHECK-NEXT: movl 4(%ebx), %eax |
deps/lld/test/ELF/i386-reloc-16.s+16-11| ... | ... | @@ -1,15 +1,20 @@ |
| 1 | // REQUIRES: x86 | |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=i386 %s -o %t.o | |
| 2 | 3 | |
| 3 | // RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %S/Inputs/x86-64-reloc-16.s -o %t1 | |
| 4 | // RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %S/Inputs/x86-64-reloc-16-error.s -o %t2 | |
| 5 | // RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t | |
| 6 | // RUN: ld.lld -shared %t %t1 -o %t3 | |
| 7 | // RUN: llvm-objdump -s %t3 | FileCheck %s | |
| 4 | # RUN: ld.lld %t.o --defsym=a=0 --defsym=b=32768 -o %t | |
| 5 | # RUN: llvm-readelf -x .text %t | FileCheck %s | |
| 6 | # CHECK: b80080bb ffff | |
| 8 | 7 | |
| 9 | // CHECK: Contents of section .text: | |
| 10 | // CHECK-NEXT: 1000 42 | |
| 8 | # RUN: not ld.lld %t.o --defsym=a=-1 --defsym=b=0 -o /dev/null 2>&1 | \ | |
| 9 | # RUN: FileCheck --check-prefix=OVERFLOW1 %s | |
| 10 | # OVERFLOW1: relocation R_386_16 out of range: -32769 is not in [-32768, 65535] | |
| 11 | 11 | |
| 12 | // RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck --check-prefix=ERROR %s | |
| 13 | // ERROR: relocation R_386_16 out of range: 65536 is not in [-32768, 32767] | |
| 12 | # RUN: not ld.lld %t.o --defsym=a=0 --defsym=b=32769 -o /dev/null 2>&1 | \ | |
| 13 | # RUN: FileCheck --check-prefix=OVERFLOW2 %s | |
| 14 | # OVERFLOW2: relocation R_386_16 out of range: 65536 is not in [-32768, 65535] | |
| 14 | 15 | |
| 15 | .short foo | |
| 16 | .code16 | |
| 17 | .global _start | |
| 18 | _start: | |
| 19 | movw $a-32768, %ax | |
| 20 | movw $b+32767, %bx |
deps/lld/test/ELF/i386-reloc-8.s+16-11| ... | ... | @@ -1,15 +1,20 @@ |
| 1 | // REQUIRES: x86 | |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=i386 %s -o %t.o | |
| 2 | 3 | |
| 3 | // RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %S/Inputs/i386-reloc-8.s -o %t1 | |
| 4 | // RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %S/Inputs/i386-reloc-8-error.s -o %t2 | |
| 5 | // RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t | |
| 6 | // RUN: ld.lld -shared %t %t1 -o %t3 | |
| 7 | // RUN: llvm-objdump -s %t3 | FileCheck %s | |
| 4 | # RUN: ld.lld %t.o --defsym=a=0 --defsym=b=128 -o %t | |
| 5 | # RUN: llvm-readelf -x .text %t | FileCheck %s | |
| 6 | # CHECK: b480b7ff | |
| 8 | 7 | |
| 9 | // CHECK: Contents of section .text: | |
| 10 | // CHECK-NEXT: 1000 ff | |
| 8 | # RUN: not ld.lld %t.o --defsym=a=-1 --defsym=b=0 -o /dev/null 2>&1 | \ | |
| 9 | # RUN: FileCheck --check-prefix=OVERFLOW1 %s | |
| 10 | # OVERFLOW1: relocation R_386_8 out of range: -129 is not in [-128, 255] | |
| 11 | 11 | |
| 12 | // RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck --check-prefix=ERROR %s | |
| 13 | // ERROR: relocation R_386_8 out of range: 256 is not in [-128, 127] | |
| 12 | # RUN: not ld.lld %t.o --defsym=a=0 --defsym=b=129 -o /dev/null 2>&1 | \ | |
| 13 | # RUN: FileCheck --check-prefix=OVERFLOW2 %s | |
| 14 | # OVERFLOW2: relocation R_386_8 out of range: 256 is not in [-128, 255] | |
| 14 | 15 | |
| 15 | .byte foo | |
| 16 | .code16 | |
| 17 | .globl _start | |
| 18 | _start: | |
| 19 | movb $a-128, %ah | |
| 20 | movb $b+127, %bh |
deps/lld/test/ELF/i386-reloc-large-addend.s+1| ... | ... | @@ -8,6 +8,7 @@ |
| 8 | 8 | // RUN: llvm-objdump -d -triple=i386-pc-linux-code16 %t | FileCheck %s |
| 9 | 9 | |
| 10 | 10 | // CHECK: Disassembly of section .text: |
| 11 | // CHECK-EMPTY: | |
| 11 | 12 | // CHECK-NEXT: _start: |
| 12 | 13 | // CHECK-NEXT: 7000: e9 fe 1f jmp 8190 |
| 13 | 14 | // 0x1 + 0x9000 - 0x7003 == 8190 |
deps/lld/test/ELF/i386-reloc-range.s+1| ... | ... | @@ -10,6 +10,7 @@ |
| 10 | 10 | // RUN: llvm-objdump -d -triple=i386-pc-linux-code16 %t1 | FileCheck %s |
| 11 | 11 | |
| 12 | 12 | // CHECK: Disassembly of section .text: |
| 13 | // CHECK-EMPTY: | |
| 13 | 14 | // CHECK-NEXT: _start: |
| 14 | 15 | // CHECK-NEXT: 200: {{.*}} jmp -1 |
| 15 | 16 | // 0x10202 - 0x203 == 0xffff |
deps/lld/test/ELF/i386-retpoline-nopic-linkerscript.s+5-4| ... | ... | @@ -13,10 +13,11 @@ |
| 13 | 13 | // RUN: llvm-objdump -d -s %t.exe | FileCheck %s |
| 14 | 14 | |
| 15 | 15 | // CHECK: Disassembly of section .plt: |
| 16 | // CHECK-EMPTY: | |
| 16 | 17 | // CHECK-NEXT: .plt: |
| 17 | // CHECK-NEXT: 10: ff 35 84 00 00 00 pushl 132 | |
| 18 | // CHECK-NEXT: 10: ff 35 ec 00 00 00 pushl 236 | |
| 18 | 19 | // CHECK-NEXT: 16: 50 pushl %eax |
| 19 | // CHECK-NEXT: 17: a1 88 00 00 00 movl 136, %eax | |
| 20 | // CHECK-NEXT: 17: a1 f0 00 00 00 movl 240, %eax | |
| 20 | 21 | // CHECK-NEXT: 1c: e8 0f 00 00 00 calll 15 <.plt+0x20> |
| 21 | 22 | // CHECK-NEXT: 21: f3 90 pause |
| 22 | 23 | // CHECK-NEXT: 23: 0f ae e8 lfence |
| ... | ... | @@ -37,7 +38,7 @@ |
| 37 | 38 | // CHECK-NEXT: 3e: c3 retl |
| 38 | 39 | // CHECK-NEXT: 3f: cc int3 |
| 39 | 40 | // CHECK-NEXT: 40: 50 pushl %eax |
| 40 | // CHECK-NEXT: 41: a1 8c 00 00 00 movl 140, %eax | |
| 41 | // CHECK-NEXT: 41: a1 f4 00 00 00 movl 244, %eax | |
| 41 | 42 | // CHECK-NEXT: 46: e8 e5 ff ff ff calll -27 <.plt+0x20> |
| 42 | 43 | // CHECK-NEXT: 4b: e9 d1 ff ff ff jmp -47 <.plt+0x11> |
| 43 | 44 | // CHECK-NEXT: 50: 68 00 00 00 00 pushl $0 |
| ... | ... | @@ -49,7 +50,7 @@ |
| 49 | 50 | // CHECK-NEXT: 5e: cc int3 |
| 50 | 51 | // CHECK-NEXT: 5f: cc int3 |
| 51 | 52 | // CHECK-NEXT: 60: 50 pushl %eax |
| 52 | // CHECK-NEXT: 61: a1 90 00 00 00 movl 144, %eax | |
| 53 | // CHECK-NEXT: 61: a1 f8 00 00 00 movl 248, %eax | |
| 53 | 54 | // CHECK-NEXT: 66: e8 c5 ff ff ff calll -59 <.plt+0x20> |
| 54 | 55 | // CHECK-NEXT: 6b: e9 b1 ff ff ff jmp -79 <.plt+0x11> |
| 55 | 56 | // CHECK-NEXT: 70: 68 08 00 00 00 pushl $8 |
deps/lld/test/ELF/i386-retpoline-nopic.s+6-5| ... | ... | @@ -7,10 +7,11 @@ |
| 7 | 7 | // RUN: llvm-objdump -d -s %t.exe | FileCheck %s |
| 8 | 8 | |
| 9 | 9 | // CHECK: Disassembly of section .plt: |
| 10 | // CHECK-EMPTY: | |
| 10 | 11 | // CHECK-NEXT: .plt: |
| 11 | // CHECK-NEXT: 401010: ff 35 04 20 40 00 pushl 4202500 | |
| 12 | // CHECK-NEXT: 401010: ff 35 04 30 40 00 pushl 4206596 | |
| 12 | 13 | // CHECK-NEXT: 401016: 50 pushl %eax |
| 13 | // CHECK-NEXT: 401017: a1 08 20 40 00 movl 4202504, %eax | |
| 14 | // CHECK-NEXT: 401017: a1 08 30 40 00 movl 4206600, %eax | |
| 14 | 15 | // CHECK-NEXT: 40101c: e8 0f 00 00 00 calll 15 <.plt+0x20> |
| 15 | 16 | // CHECK-NEXT: 401021: f3 90 pause |
| 16 | 17 | // CHECK-NEXT: 401023: 0f ae e8 lfence |
| ... | ... | @@ -31,7 +32,7 @@ |
| 31 | 32 | // CHECK-NEXT: 40103e: c3 retl |
| 32 | 33 | // CHECK-NEXT: 40103f: cc int3 |
| 33 | 34 | // CHECK-NEXT: 401040: 50 pushl %eax |
| 34 | // CHECK-NEXT: 401041: a1 0c 20 40 00 movl 4202508, %eax | |
| 35 | // CHECK-NEXT: 401041: a1 0c 30 40 00 movl 4206604, %eax | |
| 35 | 36 | // CHECK-NEXT: 401046: e8 e5 ff ff ff calll -27 <.plt+0x20> |
| 36 | 37 | // CHECK-NEXT: 40104b: e9 d1 ff ff ff jmp -47 <.plt+0x11> |
| 37 | 38 | // CHECK-NEXT: 401050: 68 00 00 00 00 pushl $0 |
| ... | ... | @@ -43,7 +44,7 @@ |
| 43 | 44 | // CHECK-NEXT: 40105e: cc int3 |
| 44 | 45 | // CHECK-NEXT: 40105f: cc int3 |
| 45 | 46 | // CHECK-NEXT: 401060: 50 pushl %eax |
| 46 | // CHECK-NEXT: 401061: a1 10 20 40 00 movl 4202512, %eax | |
| 47 | // CHECK-NEXT: 401061: a1 10 30 40 00 movl 4206608, %eax | |
| 47 | 48 | // CHECK-NEXT: 401066: e8 c5 ff ff ff calll -59 <.plt+0x20> |
| 48 | 49 | // CHECK-NEXT: 40106b: e9 b1 ff ff ff jmp -79 <.plt+0x11> |
| 49 | 50 | // CHECK-NEXT: 401070: 68 08 00 00 00 pushl $8 |
| ... | ... | @@ -56,7 +57,7 @@ |
| 56 | 57 | // CHECK-NEXT: 40107f: cc int3 |
| 57 | 58 | |
| 58 | 59 | // CHECK: Contents of section .got.plt: |
| 59 | // CHECK-NEXT: 00304000 00000000 00000000 50104000 | |
| 60 | // CHECK-NEXT: 00204000 00000000 00000000 50104000 | |
| 60 | 61 | // CHECK-NEXT: 70104000 |
| 61 | 62 | |
| 62 | 63 | .global _start |
deps/lld/test/ELF/i386-retpoline-pic-linkerscript.s+5-4| ... | ... | @@ -13,10 +13,11 @@ |
| 13 | 13 | // RUN: llvm-objdump -d -s %t.exe | FileCheck %s |
| 14 | 14 | |
| 15 | 15 | // CHECK: Disassembly of section .plt: |
| 16 | // CHECK-EMPTY: | |
| 16 | 17 | // CHECK-NEXT: .plt: |
| 17 | // CHECK-NEXT: 10: ff b3 84 00 00 00 pushl 132(%ebx) | |
| 18 | // CHECK-NEXT: 10: ff b3 04 00 00 00 pushl 4(%ebx) | |
| 18 | 19 | // CHECK-NEXT: 16: 50 pushl %eax |
| 19 | // CHECK-NEXT: 17: 8b 83 88 00 00 00 movl 136(%ebx), %eax | |
| 20 | // CHECK-NEXT: 17: 8b 83 08 00 00 00 movl 8(%ebx), %eax | |
| 20 | 21 | // CHECK-NEXT: 1d: e8 0e 00 00 00 calll 14 <.plt+0x20> |
| 21 | 22 | // CHECK-NEXT: 22: f3 90 pause |
| 22 | 23 | // CHECK-NEXT: 24: 0f ae e8 lfence |
| ... | ... | @@ -36,7 +37,7 @@ |
| 36 | 37 | // CHECK-NEXT: 3e: c3 retl |
| 37 | 38 | // CHECK-NEXT: 3f: cc int3 |
| 38 | 39 | // CHECK-NEXT: 40: 50 pushl %eax |
| 39 | // CHECK-NEXT: 41: 8b 83 8c 00 00 00 movl 140(%ebx), %eax | |
| 40 | // CHECK-NEXT: 41: 8b 83 0c 00 00 00 movl 12(%ebx), %eax | |
| 40 | 41 | // CHECK-NEXT: 47: e8 e4 ff ff ff calll -28 <.plt+0x20> |
| 41 | 42 | // CHECK-NEXT: 4c: e9 d1 ff ff ff jmp -47 <.plt+0x12> |
| 42 | 43 | // CHECK-NEXT: 51: 68 00 00 00 00 pushl $0 |
| ... | ... | @@ -47,7 +48,7 @@ |
| 47 | 48 | // CHECK-NEXT: 5e: cc int3 |
| 48 | 49 | // CHECK-NEXT: 5f: cc int3 |
| 49 | 50 | // CHECK-NEXT: 60: 50 pushl %eax |
| 50 | // CHECK-NEXT: 61: 8b 83 90 00 00 00 movl 144(%ebx), %eax | |
| 51 | // CHECK-NEXT: 61: 8b 83 10 00 00 00 movl 16(%ebx), %eax | |
| 51 | 52 | // CHECK-NEXT: 67: e8 c4 ff ff ff calll -60 <.plt+0x20> |
| 52 | 53 | // CHECK-NEXT: 6c: e9 b1 ff ff ff jmp -79 <.plt+0x12> |
| 53 | 54 | // CHECK-NEXT: 71: 68 08 00 00 00 pushl $8 |
deps/lld/test/ELF/i386-retpoline-pic.s+7-6| ... | ... | @@ -7,10 +7,11 @@ |
| 7 | 7 | // RUN: llvm-objdump -d -s %t.exe | FileCheck %s |
| 8 | 8 | |
| 9 | 9 | // CHECK: Disassembly of section .plt: |
| 10 | // CHECK-EMPTY: | |
| 10 | 11 | // CHECK-NEXT: .plt: |
| 11 | // CHECK-NEXT: 1010: ff b3 04 20 00 00 pushl 8196(%ebx) | |
| 12 | // CHECK-NEXT: 1010: ff b3 04 00 00 00 pushl 4(%ebx) | |
| 12 | 13 | // CHECK-NEXT: 1016: 50 pushl %eax |
| 13 | // CHECK-NEXT: 1017: 8b 83 08 20 00 00 movl 8200(%ebx), %eax | |
| 14 | // CHECK-NEXT: 1017: 8b 83 08 00 00 00 movl 8(%ebx), %eax | |
| 14 | 15 | // CHECK-NEXT: 101d: e8 0e 00 00 00 calll 14 <.plt+0x20> |
| 15 | 16 | // CHECK-NEXT: 1022: f3 90 pause |
| 16 | 17 | // CHECK-NEXT: 1024: 0f ae e8 lfence |
| ... | ... | @@ -30,7 +31,7 @@ |
| 30 | 31 | // CHECK-NEXT: 103e: c3 retl |
| 31 | 32 | // CHECK-NEXT: 103f: cc int3 |
| 32 | 33 | // CHECK-NEXT: 1040: 50 pushl %eax |
| 33 | // CHECK-NEXT: 1041: 8b 83 0c 20 00 00 movl 8204(%ebx), %eax | |
| 34 | // CHECK-NEXT: 1041: 8b 83 0c 00 00 00 movl 12(%ebx), %eax | |
| 34 | 35 | // CHECK-NEXT: 1047: e8 e4 ff ff ff calll -28 <.plt+0x20> |
| 35 | 36 | // CHECK-NEXT: 104c: e9 d1 ff ff ff jmp -47 <.plt+0x12> |
| 36 | 37 | // CHECK-NEXT: 1051: 68 00 00 00 00 pushl $0 |
| ... | ... | @@ -41,7 +42,7 @@ |
| 41 | 42 | // CHECK-NEXT: 105e: cc int3 |
| 42 | 43 | // CHECK-NEXT: 105f: cc int3 |
| 43 | 44 | // CHECK-NEXT: 1060: 50 pushl %eax |
| 44 | // CHECK-NEXT: 1061: 8b 83 10 20 00 00 movl 8208(%ebx), %eax | |
| 45 | // CHECK-NEXT: 1061: 8b 83 10 00 00 00 movl 16(%ebx), %eax | |
| 45 | 46 | // CHECK-NEXT: 1067: e8 c4 ff ff ff calll -60 <.plt+0x20> |
| 46 | 47 | // CHECK-NEXT: 106c: e9 b1 ff ff ff jmp -79 <.plt+0x12> |
| 47 | 48 | // CHECK-NEXT: 1071: 68 08 00 00 00 pushl $8 |
| ... | ... | @@ -53,8 +54,8 @@ |
| 53 | 54 | // CHECK-NEXT: 107f: cc int3 |
| 54 | 55 | |
| 55 | 56 | // CHECK: Contents of section .got.plt: |
| 56 | // CHECK-NEXT: 2000 00300000 00000000 00000000 51100000 | |
| 57 | // CHECK-NEXT: 2010 71100000 | |
| 57 | // CHECK-NEXT: 3000 00200000 00000000 00000000 51100000 | |
| 58 | // CHECK-NEXT: 3010 71100000 | |
| 58 | 59 | |
| 59 | 60 | .global _start |
| 60 | 61 | _start: |
deps/lld/test/ELF/i386-static-tls-model.s created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %S/Inputs/i386-static-tls-model1.s -o %t.o | |
| 4 | # RUN: ld.lld %t.o -o %t1 -shared | |
| 5 | # RUN: llvm-readobj --dynamic-table %t1 | FileCheck %s | |
| 6 | ||
| 7 | # RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %S/Inputs/i386-static-tls-model2.s -o %t.o | |
| 8 | # RUN: ld.lld %t.o -o %t2 -shared | |
| 9 | # RUN: llvm-readobj --dynamic-table %t2 | FileCheck %s | |
| 10 | ||
| 11 | # RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %S/Inputs/i386-static-tls-model3.s -o %t.o | |
| 12 | # RUN: ld.lld %t.o -o %t3 -shared | |
| 13 | # RUN: llvm-readobj --dynamic-table %t3 | FileCheck %s | |
| 14 | ||
| 15 | # RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %S/Inputs/i386-static-tls-model4.s -o %t.o | |
| 16 | # RUN: ld.lld %t.o -o %t4 -shared | |
| 17 | # RUN: llvm-readobj --dynamic-table %t4 | FileCheck %s | |
| 18 | ||
| 19 | # CHECK: DynamicSection [ | |
| 20 | # CHECK: FLAGS STATIC_TLS |
deps/lld/test/ELF/i386-tls-ie-shared.s+28-27| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %p/Inputs/tls-opt-iele-i686-nopic.s -o %tso.o |
| 4 | 4 | // RUN: ld.lld -shared %tso.o -o %tso |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv -shared %t.o %tso -o %t1 |
| 6 | // RUN: llvm-readobj -s -r -d %t1 | FileCheck --check-prefix=GOTRELSHARED %s | |
| 6 | // RUN: llvm-readobj -S -r -d %t1 | FileCheck --check-prefix=GOTRELSHARED %s | |
| 7 | 7 | // RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASMSHARED %s |
| 8 | 8 | |
| 9 | 9 | // GOTRELSHARED: Section { |
| ... | ... | @@ -14,8 +14,8 @@ |
| 14 | 14 | // GOTRELSHARED-NEXT: SHF_ALLOC |
| 15 | 15 | // GOTRELSHARED-NEXT: SHF_WRITE |
| 16 | 16 | // GOTRELSHARED-NEXT: ] |
| 17 | // GOTRELSHARED-NEXT: Address: 0x2058 | |
| 18 | // GOTRELSHARED-NEXT: Offset: 0x2058 | |
| 17 | // GOTRELSHARED-NEXT: Address: 0x2060 | |
| 18 | // GOTRELSHARED-NEXT: Offset: 0x2060 | |
| 19 | 19 | // GOTRELSHARED-NEXT: Size: 16 |
| 20 | 20 | // GOTRELSHARED-NEXT: Link: 0 |
| 21 | 21 | // GOTRELSHARED-NEXT: Info: 0 |
| ... | ... | @@ -32,36 +32,37 @@ |
| 32 | 32 | // GOTRELSHARED-NEXT: 0x102D R_386_RELATIVE - 0x0 |
| 33 | 33 | // GOTRELSHARED-NEXT: 0x1036 R_386_RELATIVE - 0x0 |
| 34 | 34 | // GOTRELSHARED-NEXT: 0x103F R_386_RELATIVE - 0x0 |
| 35 | // GOTRELSHARED-NEXT: 0x2058 R_386_TLS_TPOFF tlslocal0 0x0 | |
| 36 | // GOTRELSHARED-NEXT: 0x205C R_386_TLS_TPOFF tlslocal1 0x0 | |
| 37 | // GOTRELSHARED-NEXT: 0x2060 R_386_TLS_TPOFF tlsshared0 0x0 | |
| 38 | // GOTRELSHARED-NEXT: 0x2064 R_386_TLS_TPOFF tlsshared1 0x0 | |
| 35 | // GOTRELSHARED-NEXT: 0x2060 R_386_TLS_TPOFF tlslocal0 0x0 | |
| 36 | // GOTRELSHARED-NEXT: 0x2064 R_386_TLS_TPOFF tlslocal1 0x0 | |
| 37 | // GOTRELSHARED-NEXT: 0x2068 R_386_TLS_TPOFF tlsshared0 0x0 | |
| 38 | // GOTRELSHARED-NEXT: 0x206C R_386_TLS_TPOFF tlsshared1 0x0 | |
| 39 | 39 | // GOTRELSHARED-NEXT: } |
| 40 | 40 | // GOTRELSHARED-NEXT: ] |
| 41 | 41 | // GOTRELSHARED: 0x6FFFFFFA RELCOUNT 8 |
| 42 | 42 | |
| 43 | 43 | // DISASMSHARED: Disassembly of section test: |
| 44 | // DISASMSHARED-EMPTY: | |
| 44 | 45 | // DISASMSHARED-NEXT: _start: |
| 45 | // (.got)[0] = 0x2058 = 8280 | |
| 46 | // (.got)[1] = 0x205C = 8284 | |
| 47 | // (.got)[2] = 0x2060 = 8288 | |
| 48 | // (.got)[3] = 0x2064 = 8292 | |
| 49 | // DISASMSHARED-NEXT: 1000: 8b 0d 58 20 00 00 movl 8280, %ecx | |
| 50 | // DISASMSHARED-NEXT: 1006: 65 8b 01 movl %gs:(%ecx), %eax | |
| 51 | // DISASMSHARED-NEXT: 1009: a1 58 20 00 00 movl 8280, %eax | |
| 52 | // DISASMSHARED-NEXT: 100e: 65 8b 00 movl %gs:(%eax), %eax | |
| 53 | // DISASMSHARED-NEXT: 1011: 03 0d 58 20 00 00 addl 8280, %ecx | |
| 54 | // DISASMSHARED-NEXT: 1017: 65 8b 01 movl %gs:(%ecx), %eax | |
| 55 | // DISASMSHARED-NEXT: 101a: 8b 0d 5c 20 00 00 movl 8284, %ecx | |
| 56 | // DISASMSHARED-NEXT: 1020: 65 8b 01 movl %gs:(%ecx), %eax | |
| 57 | // DISASMSHARED-NEXT: 1023: a1 5c 20 00 00 movl 8284, %eax | |
| 58 | // DISASMSHARED-NEXT: 1028: 65 8b 00 movl %gs:(%eax), %eax | |
| 59 | // DISASMSHARED-NEXT: 102b: 03 0d 5c 20 00 00 addl 8284, %ecx | |
| 60 | // DISASMSHARED-NEXT: 1031: 65 8b 01 movl %gs:(%ecx), %eax | |
| 61 | // DISASMSHARED-NEXT: 1034: 8b 0d 60 20 00 00 movl 8288, %ecx | |
| 62 | // DISASMSHARED-NEXT: 103a: 65 8b 01 movl %gs:(%ecx), %eax | |
| 63 | // DISASMSHARED-NEXT: 103d: 03 0d 64 20 00 00 addl 8292, %ecx | |
| 64 | // DISASMSHARED-NEXT: 1043: 65 8b 01 movl %gs:(%ecx), %eax | |
| 46 | // (.got)[0] = 0x2060 = 8288 | |
| 47 | // (.got)[1] = 0x2064 = 8292 | |
| 48 | // (.got)[2] = 0x2068 = 8296 | |
| 49 | // (.got)[3] = 0x206C = 8300 | |
| 50 | // DISASMSHARED-NEXT: 1000: {{.*}} movl 8288, %ecx | |
| 51 | // DISASMSHARED-NEXT: 1006: {{.*}} movl %gs:(%ecx), %eax | |
| 52 | // DISASMSHARED-NEXT: 1009: {{.*}} movl 8288, %eax | |
| 53 | // DISASMSHARED-NEXT: 100e: {{.*}} movl %gs:(%eax), %eax | |
| 54 | // DISASMSHARED-NEXT: 1011: {{.*}} addl 8288, %ecx | |
| 55 | // DISASMSHARED-NEXT: 1017: {{.*}} movl %gs:(%ecx), %eax | |
| 56 | // DISASMSHARED-NEXT: 101a: {{.*}} movl 8292, %ecx | |
| 57 | // DISASMSHARED-NEXT: 1020: {{.*}} movl %gs:(%ecx), %eax | |
| 58 | // DISASMSHARED-NEXT: 1023: {{.*}} movl 8292, %eax | |
| 59 | // DISASMSHARED-NEXT: 1028: {{.*}} movl %gs:(%eax), %eax | |
| 60 | // DISASMSHARED-NEXT: 102b: {{.*}} addl 8292, %ecx | |
| 61 | // DISASMSHARED-NEXT: 1031: {{.*}} movl %gs:(%ecx), %eax | |
| 62 | // DISASMSHARED-NEXT: 1034: {{.*}} movl 8296, %ecx | |
| 63 | // DISASMSHARED-NEXT: 103a: {{.*}} movl %gs:(%ecx), %eax | |
| 64 | // DISASMSHARED-NEXT: 103d: {{.*}} addl 8300, %ecx | |
| 65 | // DISASMSHARED-NEXT: 1043: {{.*}} movl %gs:(%ecx), %eax | |
| 65 | 66 | |
| 66 | 67 | .type tlslocal0,@object |
| 67 | 68 | .section .tbss,"awT",@nobits |
deps/lld/test/ELF/i386-tls-ld-preemptable.s created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=i386 %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -shared -o %t.so | |
| 4 | # RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck %s | |
| 5 | ||
| 6 | # CHECK: 100b: movl (%eax), %eax | |
| 7 | ||
| 8 | # We used to error on R_386_TLS_LDO_32 to preemptable symbols. | |
| 9 | # i is STB_GLOBAL and preemptable. | |
| 10 | leal i@TLSLDM(%ebx), %eax | |
| 11 | calll __tls_get_addr@PLT | |
| 12 | movl i@DTPOFF(%eax), %eax # R_386_TLS_LDO_32 | |
| 13 | ||
| 14 | .section .tbss,"awT",@nobits | |
| 15 | .globl i | |
| 16 | i: | |
| 17 | .long 0 | |
| 18 | .size i, 4 |
deps/lld/test/ELF/i386-tls-le-align.s created+29| ... | ... | @@ -0,0 +1,29 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=i386 %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -o %t | |
| 4 | # RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex %t | FileCheck %s | |
| 5 | ||
| 6 | # -alignTo(p_memsz, p_align) = -alignTo(4, 64) = -64 | |
| 7 | ||
| 8 | # CHECK: movl %gs:0xffffffc0, %eax | |
| 9 | movl %gs:a@NTPOFF, %eax | |
| 10 | ||
| 11 | # CHECK-NEXT: subl $0x40, %edx | |
| 12 | subl $a@tpoff, %edx | |
| 13 | ||
| 14 | # GD to LE relaxation. | |
| 15 | # CHECK-NEXT: movl %gs:0x0, %eax | |
| 16 | # CHECK-NEXT: subl $0x40, %eax | |
| 17 | leal a@tlsgd(,%ebx,1), %eax | |
| 18 | call ___tls_get_addr@plt | |
| 19 | ret | |
| 20 | ||
| 21 | .globl ___tls_get_addr | |
| 22 | .type ___tls_get_addr,@function | |
| 23 | ___tls_get_addr: | |
| 24 | ||
| 25 | .section .tbss,"awT" | |
| 26 | .align 64 | |
| 27 | a: | |
| 28 | .long 0 | |
| 29 | .size a, 4 |
deps/lld/test/ELF/i386-tls-le-undef.s created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=i386 %s -o %t.o | |
| 3 | # RUN: ld.lld --noinhibit-exec %t.o -o %t 2>&1 | |
| 4 | # RUN: llvm-objdump -d %t | FileCheck %s | |
| 5 | ||
| 6 | ## Undefined TLS symbols resolve to 0. | |
| 7 | ## In --noinhibit-exec mode, a non-weak undefined symbol is not an error. | |
| 8 | ||
| 9 | # CHECK: subl $0, %eax | |
| 10 | # CHECK: subl $0, %eax | |
| 11 | ||
| 12 | .weak weak_undef | |
| 13 | movl %gs:0, %eax | |
| 14 | subl $weak_undef@tpoff,%eax | |
| 15 | movl %gs:0, %eax | |
| 16 | subl $undef@tpoff,%eax |
deps/lld/test/ELF/icf-merged-sections.s+2-2| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 4 | 4 | # RUN: ld.lld %t.o -o %t --icf=all --ignore-data-address-equality --print-icf-sections | FileCheck -allow-empty --check-prefix=NOICF %s |
| 5 | # RUN: llvm-readobj -s -section-data %t | FileCheck %s | |
| 5 | # RUN: llvm-readobj -S --section-data %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # Check that merge synthetic sections are not merged by ICF. |
| 8 | 8 | |
| ... | ... | @@ -19,7 +19,7 @@ |
| 19 | 19 | # CHECK-NEXT: Size: 16 |
| 20 | 20 | # CHECK-NEXT: Link: |
| 21 | 21 | # CHECK-NEXT: Info: |
| 22 | # CHECK-NEXT: AddressAlignment: 8 | |
| 22 | # CHECK-NEXT: AddressAlignment: 1 | |
| 23 | 23 | # CHECK-NEXT: EntrySize: 0 |
| 24 | 24 | # CHECK-NEXT: SectionData ( |
| 25 | 25 | # CHECK-NEXT: 0000: 67452301 10325476 67452301 10325476 |
deps/lld/test/ELF/icf-symbol-type.s+1-1| ... | ... | @@ -7,8 +7,8 @@ |
| 7 | 7 | # We used to mark bar as absolute. |
| 8 | 8 | |
| 9 | 9 | # CHECK: .text PROGBITS 0000000000001000 |
| 10 | # CHECK: 0000000000001001 0 NOTYPE GLOBAL DEFAULT 4 foo | |
| 11 | 10 | # CHECK: 0000000000001001 0 NOTYPE GLOBAL DEFAULT 4 bar |
| 11 | # CHECK: 0000000000001001 0 NOTYPE GLOBAL DEFAULT 4 foo | |
| 12 | 12 | |
| 13 | 13 | # The nop makes the test more interesting by making the offset of |
| 14 | 14 | # text.f non zero. |
deps/lld/test/ELF/icf10.s created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-freebsd %s -o %t.o | |
| 4 | # RUN: ld.lld --icf=all %t.o -o /dev/null --print-icf-sections 2>&1 | FileCheck %s | |
| 5 | ||
| 6 | # Checks that ICF does not merge 2 sections the offset of | |
| 7 | # the relocations of which differ. | |
| 8 | ||
| 9 | # CHECK-NOT: selected | |
| 10 | ||
| 11 | .section .text.foo,"ax" | |
| 12 | .quad -1 | |
| 13 | .reloc 0, R_X86_64_NONE, 0 | |
| 14 | ||
| 15 | .section .text.bar,"ax" | |
| 16 | .quad -1 | |
| 17 | .reloc 1, R_X86_64_NONE, 0 |
deps/lld/test/ELF/icf10.test deleted-40| ... | ... | @@ -1,40 +0,0 @@ |
| 1 | # RUN: yaml2obj %s -o %t.o | |
| 2 | # RUN: ld.lld --icf=all %t.o -o /dev/null --print-icf-sections 2>&1 | FileCheck %s | |
| 3 | ||
| 4 | # Checks that ICF does not merge 2 sections the offset of | |
| 5 | # the relocations of which differ. | |
| 6 | ||
| 7 | # CHECK-NOT: selected | |
| 8 | ||
| 9 | !ELF | |
| 10 | FileHeader: | |
| 11 | Class: ELFCLASS64 | |
| 12 | Data: ELFDATA2LSB | |
| 13 | OSABI: ELFOSABI_FREEBSD | |
| 14 | Type: ET_REL | |
| 15 | Machine: EM_X86_64 | |
| 16 | Sections: | |
| 17 | - Name: .text.foo | |
| 18 | Type: SHT_PROGBITS | |
| 19 | Flags: [ SHF_ALLOC, SHF_EXECINSTR] | |
| 20 | Content: "FFFFFFFFFFFFFFFF" | |
| 21 | - Name: .text.bar | |
| 22 | Type: SHT_PROGBITS | |
| 23 | Flags: [ SHF_ALLOC, SHF_EXECINSTR] | |
| 24 | Content: "FFFFFFFFFFFFFFFF" | |
| 25 | - Name: .rela.text.foo | |
| 26 | Type: SHT_RELA | |
| 27 | Link: .symtab | |
| 28 | Info: .text.foo | |
| 29 | Relocations: | |
| 30 | - Offset: 0x0000000000000000 | |
| 31 | Symbol: '' | |
| 32 | Type: R_X86_64_NONE | |
| 33 | - Name: .rela.text.bar | |
| 34 | Type: SHT_RELA | |
| 35 | Link: .symtab | |
| 36 | Info: .text.bar | |
| 37 | Relocations: | |
| 38 | - Offset: 0x0000000000000001 | |
| 39 | Symbol: '' | |
| 40 | Type: R_X86_64_NONE |
deps/lld/test/ELF/icf11.test+6-7| ... | ... | @@ -33,7 +33,6 @@ Sections: |
| 33 | 33 | Info: .text.foo |
| 34 | 34 | Relocations: |
| 35 | 35 | - Offset: 0x0000000000000000 |
| 36 | Symbol: '' | |
| 37 | 36 | Type: R_X86_64_NONE |
| 38 | 37 | - Name: .rela.text.bar |
| 39 | 38 | Type: SHT_RELA |
| ... | ... | @@ -44,9 +43,9 @@ Sections: |
| 44 | 43 | Symbol: zed |
| 45 | 44 | Type: R_X86_64_64 |
| 46 | 45 | Symbols: |
| 47 | Global: | |
| 48 | - Name: zed | |
| 49 | Type: STT_FUNC | |
| 50 | Section: .text | |
| 51 | Value: 0x0 | |
| 52 | Size: 8 | |
| 46 | - Name: zed | |
| 47 | Type: STT_FUNC | |
| 48 | Section: .text | |
| 49 | Value: 0x0 | |
| 50 | Size: 8 | |
| 51 | Binding: STB_GLOBAL |
deps/lld/test/ELF/image-base.s+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | # RUN: ld.lld -image-base=0x1000000 %t -o %t1 |
| 4 | # RUN: llvm-readobj -program-headers %t1 | FileCheck %s | |
| 4 | # RUN: llvm-readobj -l %t1 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # RUN: not ld.lld -image-base=ABC %t -o %t1 2>&1 | FileCheck --check-prefix=ERR %s |
| 7 | 7 | # ERR: error: -image-base: number expected, but got ABC |
| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | |
| 12 | 12 | # Check alias. |
| 13 | 13 | # RUN: ld.lld -image-base 0x1000000 %t -o %t1 |
| 14 | # RUN: llvm-readobj -program-headers %t1 | FileCheck %s | |
| 14 | # RUN: llvm-readobj -l %t1 | FileCheck %s | |
| 15 | 15 | |
| 16 | 16 | .global _start |
| 17 | 17 | _start: |
deps/lld/test/ELF/init-fini-progbits.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 4 | 4 | // RUN: ld.lld %t -o %t.exe |
| 5 | // RUN: llvm-readobj -sections %t.exe | FileCheck %s | |
| 5 | // RUN: llvm-readobj --sections %t.exe | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // CHECK: Name: .init_array |
| 8 | 8 | // CHECK-NEXT: Type: SHT_INIT_ARRAY |
deps/lld/test/ELF/init-fini.s+6-6| ... | ... | @@ -3,25 +3,25 @@ |
| 3 | 3 | |
| 4 | 4 | // Should use "_init" and "_fini" by default when fills dynamic table |
| 5 | 5 | // RUN: ld.lld -shared %t -o %t2 |
| 6 | // RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=BYDEF %s | |
| 6 | // RUN: llvm-readobj --dynamic-table %t2 | FileCheck --check-prefix=BYDEF %s | |
| 7 | 7 | // BYDEF: INIT 0x11010 |
| 8 | 8 | // BYDEF: FINI 0x11020 |
| 9 | 9 | |
| 10 | 10 | // -init and -fini override symbols to use |
| 11 | 11 | // RUN: ld.lld -shared %t -o %t2 -init _foo -fini _bar |
| 12 | // RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=OVR %s | |
| 12 | // RUN: llvm-readobj --dynamic-table %t2 | FileCheck --check-prefix=OVR %s | |
| 13 | 13 | // OVR: INIT 0x11030 |
| 14 | 14 | // OVR: FINI 0x11040 |
| 15 | 15 | |
| 16 | 16 | // Check aliases as well |
| 17 | 17 | // RUN: ld.lld -shared %t -o %t2 -init=_foo -fini=_bar |
| 18 | // RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=OVR %s | |
| 18 | // RUN: llvm-readobj --dynamic-table %t2 | FileCheck --check-prefix=OVR %s | |
| 19 | 19 | |
| 20 | 20 | // Don't add an entry for undef. The freebsd dynamic linker doesn't |
| 21 | 21 | // check if the value is null. If it is, it will just call the |
| 22 | 22 | // load address. |
| 23 | 23 | // RUN: ld.lld -shared %t -o %t2 -init=_undef -fini=_undef |
| 24 | // RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=UNDEF %s | |
| 24 | // RUN: llvm-readobj --dynamic-table %t2 | FileCheck --check-prefix=UNDEF %s | |
| 25 | 25 | // UNDEF-NOT: INIT |
| 26 | 26 | // UNDEF-NOT: FINI |
| 27 | 27 | |
| ... | ... | @@ -30,14 +30,14 @@ |
| 30 | 30 | // RUN: echo > %t.s |
| 31 | 31 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t2.o |
| 32 | 32 | // RUN: ld.lld -shared %t2.o %t.so -o %t2 |
| 33 | // RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=SHARED %s | |
| 33 | // RUN: llvm-readobj --dynamic-table %t2 | FileCheck --check-prefix=SHARED %s | |
| 34 | 34 | // SHARED-NOT: INIT |
| 35 | 35 | // SHARED-NOT: FINI |
| 36 | 36 | |
| 37 | 37 | // Should not add new entries to the symbol table |
| 38 | 38 | // and should not require given symbols to be resolved |
| 39 | 39 | // RUN: ld.lld -shared %t -o %t2 -init=_unknown -fini=_unknown |
| 40 | // RUN: llvm-readobj -symbols -dynamic-table %t2 | FileCheck --check-prefix=NOENTRY %s | |
| 40 | // RUN: llvm-readobj --symbols --dynamic-table %t2 | FileCheck --check-prefix=NOENTRY %s | |
| 41 | 41 | // NOENTRY: Symbols [ |
| 42 | 42 | // NOENTRY-NOT: Name: _unknown |
| 43 | 43 | // NOENTRY: ] |
deps/lld/test/ELF/invalid-relocations.test+2-2| ... | ... | @@ -17,7 +17,7 @@ Sections: |
| 17 | 17 | Symbol: lulz |
| 18 | 18 | Type: R_X86_64_PC32 |
| 19 | 19 | Symbols: |
| 20 | Global: | |
| 21 | - Name: lulz | |
| 20 | - Name: lulz | |
| 21 | Binding: STB_GLOBAL | |
| 22 | 22 | |
| 23 | 23 | # CHECK: invalid relocated section index |
deps/lld/test/ELF/invalid-undef-section-symbol.test deleted-27| ... | ... | @@ -1,27 +0,0 @@ |
| 1 | # RUN: yaml2obj %s -o %t.o | |
| 2 | # RUN: not ld.lld -r %t.o -o /dev/null 2>&1 | FileCheck %s | |
| 3 | ||
| 4 | # We used to crash at this. | |
| 5 | # CHECK: STT_SECTION symbol should be defined | |
| 6 | ||
| 7 | --- !ELF | |
| 8 | FileHeader: | |
| 9 | Class: ELFCLASS64 | |
| 10 | Data: ELFDATA2LSB | |
| 11 | Type: ET_REL | |
| 12 | Machine: EM_X86_64 | |
| 13 | Sections: | |
| 14 | - Name: .text | |
| 15 | Type: SHT_PROGBITS | |
| 16 | - Name: .rela.text | |
| 17 | Type: SHT_RELA | |
| 18 | AddressAlign: 0x0000000000000008 | |
| 19 | Info: .text | |
| 20 | Relocations: | |
| 21 | - Offset: 0x0000000000000000 | |
| 22 | Symbol: .text | |
| 23 | Type: R_X86_64_NONE | |
| 24 | Symbols: | |
| 25 | Local: | |
| 26 | - Name: .text | |
| 27 | Type: STT_SECTION |
deps/lld/test/ELF/invalid/Inputs/binding.elf deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/binding.elf and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/broken-relaxation-x64.elf deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/broken-relaxation-x64.elf and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/common-symbol-alignment.elf deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/common-symbol-alignment.elf and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/common-symbol-alignment2.elf deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/common-symbol-alignment2.elf and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/data-encoding.a deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/data-encoding.a and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/dynamic-section-sh_size.elf deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/dynamic-section-sh_size.elf and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/file-class.a deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/file-class.a and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/invalid-e_shnum.elf deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/invalid-e_shnum.elf and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/mips-invalid-options-descriptor.elf deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/mips-invalid-options-descriptor.elf and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/multiple-eh-relocs.elf deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/multiple-eh-relocs.elf and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/section-alignment-notpow2.elf deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/section-alignment-notpow2.elf and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/section-index.elf deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/section-index.elf and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/symbol-index.elf deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/symbol-index.elf and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/symbol-name-offset.elf deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/symbol-name-offset.elf and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/symtab-sh_info.elf deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/symtab-sh_info.elf and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/symtab-sh_info2.elf deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/symtab-sh_info2.elf and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/symtab-sh_info3.elf deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/symtab-sh_info3.elf and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/tls-symbol.elf deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/tls-symbol.elf and /dev/null differ |
deps/lld/test/ELF/invalid/Inputs/undefined-local-symbol-in-dso.so deleted| Binary files a/deps/lld/test/ELF/invalid/Inputs/undefined-local-symbol-in-dso.so and /dev/null differ |
deps/lld/test/ELF/invalid/bad-arm-attributes.s created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | # REQUIRES: arm | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=arm-unknown-linux %s -o %t | |
| 3 | # RUN: ld.lld %t -o /dev/null 2>&1 | FileCheck %s | |
| 4 | ||
| 5 | # CHECK: invalid subsection length 0 at offset 1 | |
| 6 | ||
| 7 | .section .ARM.attributes,"a",%0x70000003 | |
| 8 | .quad 0 |
deps/lld/test/ELF/invalid/bad-arm-attributes2.s created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | # REQUIRES: arm | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=arm-unknown-linux %s -o %t | |
| 3 | # RUN: ld.lld %t -o /dev/null 2>&1 | FileCheck %s | |
| 4 | ||
| 5 | # CHECK: invalid subsection length 4294967295 at offset 1 | |
| 6 | ||
| 7 | .section .ARM.attributes,"a",%0x70000003 | |
| 8 | .byte 0, 0xFF, 0xFF, 0xFF, 0xFF |
deps/lld/test/ELF/invalid/bad-reloc-target.test created+76| ... | ... | @@ -0,0 +1,76 @@ |
| 1 | # RUN: yaml2obj -docnum=1 %s -o %t1.o | |
| 2 | # RUN: not ld.lld %t1.o -o %t1 2>&1 | FileCheck %s | |
| 3 | # CHECK: error: {{.*}}.o: unsupported relocation reference | |
| 4 | ||
| 5 | --- !ELF | |
| 6 | FileHeader: | |
| 7 | Class: ELFCLASS64 | |
| 8 | Data: ELFDATA2LSB | |
| 9 | Type: ET_REL | |
| 10 | Machine: EM_X86_64 | |
| 11 | Sections: | |
| 12 | - Name: .text | |
| 13 | Type: SHT_PROGBITS | |
| 14 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 15 | - Name: .rela.text | |
| 16 | Type: SHT_RELA | |
| 17 | Link: .symtab | |
| 18 | Info: 0 | |
| 19 | Relocations: | |
| 20 | - Offset: 0x0000000000000000 | |
| 21 | Symbol: foo | |
| 22 | Type: R_X86_64_64 | |
| 23 | Symbols: | |
| 24 | - Name: foo | |
| 25 | Binding: STB_GLOBAL | |
| 26 | ||
| 27 | # RUN: yaml2obj -docnum=2 %s -o %t2.o | |
| 28 | # RUN: not ld.lld %t2.o -o %t2 2>&1 | FileCheck %s --check-prefix=ERR2 | |
| 29 | # ERR2: error: {{.*}}.o: invalid relocated section index: 99 | |
| 30 | ||
| 31 | --- !ELF | |
| 32 | FileHeader: | |
| 33 | Class: ELFCLASS64 | |
| 34 | Data: ELFDATA2LSB | |
| 35 | Type: ET_REL | |
| 36 | Machine: EM_X86_64 | |
| 37 | Sections: | |
| 38 | - Name: .text | |
| 39 | Type: SHT_PROGBITS | |
| 40 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 41 | - Name: .rela.text | |
| 42 | Type: SHT_RELA | |
| 43 | Link: .symtab | |
| 44 | Info: 99 | |
| 45 | Relocations: | |
| 46 | - Offset: 0x0000000000000000 | |
| 47 | Symbol: foo | |
| 48 | Type: R_X86_64_64 | |
| 49 | Symbols: | |
| 50 | - Name: foo | |
| 51 | Binding: STB_GLOBAL | |
| 52 | ||
| 53 | ## Relocation refers to a symbol with index larger than | |
| 54 | ## symbol table size. Check we report it. | |
| 55 | # RUN: yaml2obj -docnum=3 %s -o %t2.o | |
| 56 | # RUN: not ld.lld %t2.o -o %t2 2>&1 | FileCheck %s --check-prefix=ERR3 | |
| 57 | # ERR3: error: {{.*}}.o: invalid symbol index | |
| 58 | ||
| 59 | --- !ELF | |
| 60 | FileHeader: | |
| 61 | Class: ELFCLASS64 | |
| 62 | Data: ELFDATA2LSB | |
| 63 | Type: ET_REL | |
| 64 | Machine: EM_X86_64 | |
| 65 | Sections: | |
| 66 | - Name: .text | |
| 67 | Type: SHT_PROGBITS | |
| 68 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 69 | - Name: .rela.text | |
| 70 | Type: SHT_RELA | |
| 71 | Link: .symtab | |
| 72 | Info: .text | |
| 73 | Relocations: | |
| 74 | - Offset: 0x0000000000000000 | |
| 75 | Symbol: 255 | |
| 76 | Type: R_X86_64_64 |
deps/lld/test/ELF/invalid/broken-relaxation-x64.test+7-6| ... | ... | @@ -38,9 +38,10 @@ Sections: |
| 38 | 38 | Symbol: foo |
| 39 | 39 | Type: R_X86_64_GOTTPOFF |
| 40 | 40 | Symbols: |
| 41 | Global: | |
| 42 | - Name: foo | |
| 43 | Type: STT_TLS | |
| 44 | Section: .text | |
| 45 | Value: 0x12345 | |
| 46 | Size: 4 | |
| 41 | - Name: foo | |
| 42 | Type: STT_TLS | |
| 43 | Section: .text | |
| 44 | Value: 0x12345 | |
| 45 | Size: 4 | |
| 46 | Binding: STB_GLOBAL | |
| 47 | ||
| \ No newline at end of file |
deps/lld/test/ELF/invalid/comdat-broken.test+2-2| ... | ... | @@ -21,5 +21,5 @@ Sections: |
| 21 | 21 | - SectionOrType: 0xFF |
| 22 | 22 | - SectionOrType: 3 |
| 23 | 23 | Symbols: |
| 24 | Global: | |
| 25 | - Name: foo | |
| 24 | - Name: foo | |
| 25 | Binding: STB_GLOBAL |
deps/lld/test/ELF/invalid/common-symbol-alignment.s deleted-12| ... | ... | @@ -1,12 +0,0 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | ## common-symbol-alignment.elf contains common symbol with zero alignment. | |
| 4 | # RUN: not ld.lld %S/Inputs/common-symbol-alignment.elf \ | |
| 5 | # RUN: -o %t 2>&1 | FileCheck %s | |
| 6 | # CHECK: common symbol 'bar' has invalid alignment: 0 | |
| 7 | ||
| 8 | ## common-symbol-alignment2.elf contains common symbol alignment greater | |
| 9 | ## than UINT32_MAX. | |
| 10 | # RUN: not ld.lld %S/Inputs/common-symbol-alignment2.elf \ | |
| 11 | # RUN: -o %t 2>&1 | FileCheck %s --check-prefix=BIG | |
| 12 | # BIG: common symbol 'bar' has invalid alignment: 271644049215 |
deps/lld/test/ELF/invalid/common-symbol-alignment.test created+36| ... | ... | @@ -0,0 +1,36 @@ |
| 1 | ## If an object contains a common symbol with zero alignment, | |
| 2 | ## check we report it. | |
| 3 | # RUN: yaml2obj -docnum=1 %s -o %t1.o | |
| 4 | # RUN: not ld.lld %t1.o -o %t 2>&1 | FileCheck %s | |
| 5 | # CHECK: common symbol 'bar' has invalid alignment: 0 | |
| 6 | ||
| 7 | --- !ELF | |
| 8 | FileHeader: | |
| 9 | Class: ELFCLASS64 | |
| 10 | Data: ELFDATA2LSB | |
| 11 | Type: ET_REL | |
| 12 | Machine: EM_X86_64 | |
| 13 | Symbols: | |
| 14 | - Name: bar | |
| 15 | Type: STT_FUNC | |
| 16 | Index: SHN_COMMON | |
| 17 | Binding: STB_GLOBAL | |
| 18 | ||
| 19 | ## If an object contains a common symbol with alignment greater | |
| 20 | ## than UINT32_MAX, check we report it. | |
| 21 | # RUN: yaml2obj -docnum=2 %s -o %t2.o | |
| 22 | # RUN: not ld.lld %t2.o -o %t 2>&1 | FileCheck %s --check-prefix=BIG | |
| 23 | # BIG: common symbol 'bar' has invalid alignment: 271644049215 | |
| 24 | ||
| 25 | --- !ELF | |
| 26 | FileHeader: | |
| 27 | Class: ELFCLASS64 | |
| 28 | Data: ELFDATA2LSB | |
| 29 | Type: ET_REL | |
| 30 | Machine: EM_X86_64 | |
| 31 | Symbols: | |
| 32 | - Name: bar | |
| 33 | Type: STT_FUNC | |
| 34 | Index: SHN_COMMON | |
| 35 | Value: 0x0000003F3F3F3F3F | |
| 36 | Binding: STB_GLOBAL |
deps/lld/test/ELF/invalid/data-encoding.test created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # The object in the archive has invalid data encoding. | |
| 4 | # Check we report this. | |
| 5 | ||
| 6 | # RUN: yaml2obj %s -o %t.o | |
| 7 | # RUN: llvm-ar rcs %t.a %t.o | |
| 8 | ||
| 9 | # RUN: not ld.lld --whole-archive %t.a -o /dev/null 2>&1 | FileCheck %s | |
| 10 | # CHECK: {{.*}}.a({{.*}}.o): corrupted ELF file: invalid data encoding | |
| 11 | ||
| 12 | --- !ELF | |
| 13 | FileHeader: | |
| 14 | Class: ELFCLASS64 | |
| 15 | Data: ELFDATANONE | |
| 16 | Type: ET_REL | |
| 17 | Machine: EM_X86_64 |
deps/lld/test/ELF/invalid/dynamic-section-broken.test created+36| ... | ... | @@ -0,0 +1,36 @@ |
| 1 | ## .dynamic section has invalid sh_entsize, check we report it. | |
| 2 | # RUN: yaml2obj -docnum=1 %s -o %t.so | |
| 3 | # RUN: not ld.lld %t.so -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR1 | |
| 4 | # ERR1: error: {{.*}}.so: section [index 1] has an invalid sh_entsize: 291 | |
| 5 | ||
| 6 | --- !ELF | |
| 7 | FileHeader: | |
| 8 | Class: ELFCLASS64 | |
| 9 | Data: ELFDATA2LSB | |
| 10 | Type: ET_DYN | |
| 11 | Machine: EM_X86_64 | |
| 12 | Sections: | |
| 13 | - Name: .dynamic | |
| 14 | Type: SHT_DYNAMIC | |
| 15 | Flags: [ SHF_ALLOC ] | |
| 16 | Link: .strtab | |
| 17 | EntSize: 0x123 | |
| 18 | ||
| 19 | ## The .dynamic section has invalid sh_size, which is too short and | |
| 20 | ## even less than entry size. Check we report it. | |
| 21 | # RUN: yaml2obj -docnum=2 %s -o %t.so | |
| 22 | # RUN: not ld.lld %t.so -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR2 | |
| 23 | # ERR2: error: {{.*}}.so: section [index 1] has an invalid sh_size (1) which is not a multiple of its sh_entsize (16) | |
| 24 | ||
| 25 | --- !ELF | |
| 26 | FileHeader: | |
| 27 | Class: ELFCLASS64 | |
| 28 | Data: ELFDATA2LSB | |
| 29 | Type: ET_DYN | |
| 30 | Machine: EM_X86_64 | |
| 31 | Sections: | |
| 32 | - Name: .dynamic | |
| 33 | Type: SHT_DYNAMIC | |
| 34 | Flags: [ SHF_ALLOC ] | |
| 35 | Link: .strtab | |
| 36 | Content: "00" |
deps/lld/test/ELF/invalid/dynamic-section-size.s deleted-4| ... | ... | @@ -1,4 +0,0 @@ |
| 1 | ## dynamic-section-sh_size.elf has incorrect sh_size of dynamic section. | |
| 2 | # RUN: not ld.lld %p/Inputs/dynamic-section-sh_size.elf -o /dev/null 2>&1 | \ | |
| 3 | # RUN: FileCheck %s | |
| 4 | # CHECK: error: {{.*}}: invalid sh_entsize |
deps/lld/test/ELF/invalid/ehframe-broken-relocation.test+6-6| ... | ... | @@ -23,9 +23,9 @@ Sections: |
| 23 | 23 | Symbol: zed |
| 24 | 24 | Type: R_X86_64_64 |
| 25 | 25 | Symbols: |
| 26 | Global: | |
| 27 | - Name: zed | |
| 28 | Type: STT_FUNC | |
| 29 | Section: .eh_frame | |
| 30 | Value: 0x0 | |
| 31 | Size: 8 | |
| 26 | - Name: zed | |
| 27 | Type: STT_FUNC | |
| 28 | Section: .eh_frame | |
| 29 | Value: 0x0 | |
| 30 | Size: 8 | |
| 31 | Binding: STB_GLOBAL |
deps/lld/test/ELF/invalid/invalid-binding.test created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | # RUN: yaml2obj %s -o %t.o | |
| 2 | # RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s | |
| 3 | # CHECK: error: {{.*}}.o: unexpected binding: 9 | |
| 4 | ||
| 5 | --- !ELF | |
| 6 | FileHeader: | |
| 7 | Class: ELFCLASS64 | |
| 8 | Data: ELFDATA2LSB | |
| 9 | OSABI: ELFOSABI_GNU | |
| 10 | Type: ET_REL | |
| 11 | Machine: EM_X86_64 | |
| 12 | Sections: | |
| 13 | - Name: .text | |
| 14 | Type: SHT_PROGBITS | |
| 15 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 16 | Symbols: | |
| 17 | - Name: foo | |
| 18 | Section: .text | |
| 19 | Binding: 0x9 |
deps/lld/test/ELF/invalid/invalid-debug-relocations.test+6-6| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: yaml2obj %s -o %t.o |
| 3 | 3 | # RUN: not ld.lld -gdb-index %t.o -o %t.exe 2>&1 | FileCheck %s |
| 4 | 4 | |
| 5 | # CHECK: error: {{.*}}invalid-debug-relocations.test.tmp.o:(.debug_info+0x0): has non-ABS relocation Unknown (255) against symbol '_start' | |
| 5 | # CHECK: error: {{.*}}invalid-debug-relocations.test.tmp.o:(.debug_info+0x0): unknown relocation (255) against symbol _start | |
| 6 | 6 | |
| 7 | 7 | !ELF |
| 8 | 8 | FileHeader: |
| ... | ... | @@ -33,8 +33,8 @@ Sections: |
| 33 | 33 | Symbol: _start |
| 34 | 34 | Type: 0xFF |
| 35 | 35 | Symbols: |
| 36 | Global: | |
| 37 | - Name: _start | |
| 38 | Type: STT_FUNC | |
| 39 | Section: .text | |
| 40 | Value: 0x0 | |
| 36 | - Name: _start | |
| 37 | Type: STT_FUNC | |
| 38 | Section: .text | |
| 39 | Value: 0x0 | |
| 40 | Binding: STB_GLOBAL |
deps/lld/test/ELF/invalid/invalid-e_shnum.s deleted-3| ... | ... | @@ -1,3 +0,0 @@ |
| 1 | ## Spec says that "If a file has no section header table, e_shnum holds the value zero.", though | |
| 2 | ## in this test case it holds non-zero and lld used to crash. | |
| 3 | # RUN: ld.lld %p/Inputs/invalid-e_shnum.elf -o /dev/null |
deps/lld/test/ELF/invalid/invalid-e_shnum.test created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | ## Spec says that "If a file has no section header table, e_shnum holds the value zero.", though | |
| 2 | ## in this test case it holds non-zero and lld used to crash. | |
| 3 | ||
| 4 | # RUN: yaml2obj %s -o %t | |
| 5 | # RUN: ld.lld %t -o /dev/null | |
| 6 | ||
| 7 | --- !ELF | |
| 8 | FileHeader: | |
| 9 | Class: ELFCLASS64 | |
| 10 | Data: ELFDATA2LSB | |
| 11 | Type: ET_REL | |
| 12 | Machine: EM_X86_64 | |
| 13 | SHOffset: 0 | |
| 14 | SHNum: 0x1 | |
| 15 | SHStrNdx: 0 |
deps/lld/test/ELF/invalid/invalid-elf.test+5-28| ... | ... | @@ -1,28 +1,5 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc %s -o %t -filetype=obj -triple x86_64-pc-linux | |
| 3 | ||
| 4 | # RUN: not ld.lld %t %p/Inputs/data-encoding.a -o %t2 2>&1 | \ | |
| 5 | # RUN: FileCheck --check-prefix=INVALID-DATA-ENC %s | |
| 6 | # INVALID-DATA-ENC: test.o: invalid data encoding | |
| 7 | ||
| 8 | # RUN: not ld.lld %t %p/Inputs/file-class.a -o %t2 2>&1 | \ | |
| 9 | # RUN: FileCheck --check-prefix=INVALID-FILE-CLASS %s | |
| 10 | # INVALID-FILE-CLASS: test.o: invalid file class | |
| 11 | ||
| 12 | # RUN: not ld.lld %p/Inputs/symtab-sh_info.elf -o %t2 2>&1 | \ | |
| 13 | # RUN: FileCheck --check-prefix=INVALID-SYMTAB-SHINFO %s | |
| 14 | # INVALID-SYMTAB-SHINFO: invalid sh_info in symbol table | |
| 15 | ||
| 16 | # RUN: not ld.lld %p/Inputs/binding.elf -o %t2 2>&1 | \ | |
| 17 | # RUN: FileCheck --check-prefix=INVALID-BINDING %s | |
| 18 | # INVALID-BINDING: unexpected binding | |
| 19 | ||
| 20 | # RUN: not ld.lld %p/Inputs/section-index.elf -o %t2 2>&1 | \ | |
| 21 | # RUN: FileCheck --check-prefix=INVALID-SECTION-INDEX-LLD %s | |
| 22 | # INVALID-SECTION-INDEX-LLD: invalid section index | |
| 23 | ||
| 24 | # RUN: not ld.lld %p/Inputs/multiple-eh-relocs.elf -o %t2 2>&1 | \ | |
| 25 | # RUN: FileCheck --check-prefix=INVALID-EH-RELOCS %s | |
| 26 | # INVALID-EH-RELOCS: multiple relocation sections to one section are not supported | |
| 27 | ||
| 28 | .long foo | |
| 1 | # RUN: rm -rf %t && mkdir -p %t | |
| 2 | # RUN: echo > %t/empty.o | |
| 3 | # RUN: llvm-ar --format=gnu cr %t/not-elf.a %t/empty.o | |
| 4 | # RUN: not ld.lld --whole-archive %t/not-elf.a -o %t2 2>&1 | FileCheck %s | |
| 5 | # CHECK: not-elf.a(empty.o): not an ELF file |
deps/lld/test/ELF/invalid/invalid-file-class.test created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: rm -rf %t && mkdir -p %t | |
| 3 | ||
| 4 | ## In this test, we check that able to report objects with | |
| 5 | ## invalid ELF class type. There are 2 cases we want to check: | |
| 6 | ## when the object is a regular input and when it is fetched from the archive. | |
| 7 | ||
| 8 | ## Create a broken ELF object with ELFCLASSNONE class using echo. We need to fill | |
| 9 | ## first 18 bytes which are used by LLD to check the object. | |
| 10 | ## 0x7f, 'E', 'L', 'F', ELFCLASSNONE(0), ELFDATA2LSB(1), | |
| 11 | ## EV_CURRENT(1), ELFOSABI_LINUX(3), <padding zero bytes>, ET_REL(1), EM_NONE(0) | |
| 12 | # RUN: echo -e -n "\x7f\x45\x4c\x46\x00\x01\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00" > %t/invalid.o | |
| 13 | ||
| 14 | # RUN: llvm-ar --format=gnu cr %t/invalid-class.a %t/invalid.o | |
| 15 | # RUN: not ld.lld -whole-archive %t/invalid-class.a -o %t2 2>&1 | FileCheck %s | |
| 16 | # CHECK: invalid-class.a(invalid.o): corrupted ELF file: invalid file class | |
| 17 | ||
| 18 | # RUN: not ld.lld %t/invalid.o -o %t2 2>&1 | FileCheck %s --check-prefix=OBJ | |
| 19 | # OBJ: invalid.o: corrupted ELF file: invalid file class |
deps/lld/test/ELF/invalid/invalid-relocation-x64.test+4-4| ... | ... | @@ -3,8 +3,8 @@ |
| 3 | 3 | # RUN: echo ".global foo; foo:" > %t2.s |
| 4 | 4 | # RUN: llvm-mc %t2.s -o %t2.o -filetype=obj -triple x86_64-pc-linux |
| 5 | 5 | # RUN: not ld.lld %t1.o %t2.o -o /dev/null 2>&1 | FileCheck %s |
| 6 | # CHECK: error: unrecognized reloc 152 | |
| 7 | # CHECK: error: unrecognized reloc 153 | |
| 6 | # CHECK: error: unknown relocation (152) against symbol foo | |
| 7 | # CHECK: error: unknown relocation (153) against symbol foo | |
| 8 | 8 | |
| 9 | 9 | !ELF |
| 10 | 10 | FileHeader: |
| ... | ... | @@ -29,5 +29,5 @@ Sections: |
| 29 | 29 | Symbol: foo |
| 30 | 30 | Type: 0x99 |
| 31 | 31 | Symbols: |
| 32 | Global: | |
| 33 | - Name: foo | |
| 32 | - Name: foo | |
| 33 | Binding: STB_GLOBAL |
deps/lld/test/ELF/invalid/invalid-soname.test+4-1| ... | ... | @@ -14,5 +14,8 @@ Sections: |
| 14 | 14 | - Name: .test |
| 15 | 15 | Type: SHT_DYNAMIC |
| 16 | 16 | Flags: [ SHF_ALLOC ] |
| 17 | Content: "0e000000000000000000000000000001" | |
| 18 | 17 | Link: .strtab |
| 18 | EntSize: 0x0000000000000010 | |
| 19 | Entries: | |
| 20 | - Tag: DT_SONAME | |
| 21 | Value: 0x0100000000000000 |
deps/lld/test/ELF/invalid/mips-invalid-options-descriptor.s deleted-5| ... | ... | @@ -1,5 +0,0 @@ |
| 1 | ## mips-invalid-options-descriptor.elf has option descriptor in | |
| 2 | ## .MIPS.options with size of zero. | |
| 3 | # RUN: not ld.lld %p/Inputs/mips-invalid-options-descriptor.elf -o /dev/null 2>&1 | \ | |
| 4 | # RUN: FileCheck %s | |
| 5 | # CHECK: error: {{.*}}: invalid section offset |
deps/lld/test/ELF/invalid/mips-invalid-options-descriptor.test created+21| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | # RUN: yaml2obj %s -o %t1.o | |
| 2 | # RUN: not ld.lld %t1.o -o %t 2>&1 | FileCheck %s | |
| 3 | # CHECK: error: {{.*}}1.o: zero option descriptor size | |
| 4 | ||
| 5 | ## YAML has a description of ODK_NULL (Undefined) MIPS option, | |
| 6 | ## with a size of zero. We do not allow options with a zero size. | |
| 7 | ## Check we report it. | |
| 8 | ||
| 9 | --- !ELF | |
| 10 | FileHeader: | |
| 11 | Class: ELFCLASS64 | |
| 12 | Data: ELFDATA2MSB | |
| 13 | Type: ET_REL | |
| 14 | Machine: EM_MIPS | |
| 15 | Flags: [ EF_MIPS_CPIC, EF_MIPS_ARCH_64 ] | |
| 16 | Sections: | |
| 17 | - Name: .MIPS.options | |
| 18 | Type: SHT_MIPS_OPTIONS | |
| 19 | Flags: [ SHF_ALLOC, SHF_MIPS_NOSTRIP ] | |
| 20 | AddressAlign: 0x0000000000000008 | |
| 21 | Content: '0000000000000000' |
deps/lld/test/ELF/invalid/multiple-relocations-sections.test created+29| ... | ... | @@ -0,0 +1,29 @@ |
| 1 | # RUN: yaml2obj %s -o %t1.o | |
| 2 | # RUN: not ld.lld %t1.o -o %t 2>&1 | FileCheck %s | |
| 3 | # CHECK: error: {{.*}}1.o: multiple relocation sections to one section are not supported | |
| 4 | ||
| 5 | ## The file has two relocation sections referring to a single target section. | |
| 6 | ## Multiple relocation sections to one section are not supported, check we report this case. | |
| 7 | ||
| 8 | --- !ELF | |
| 9 | FileHeader: | |
| 10 | Class: ELFCLASS64 | |
| 11 | Data: ELFDATA2LSB | |
| 12 | Type: ET_REL | |
| 13 | Machine: EM_X86_64 | |
| 14 | Sections: | |
| 15 | - Name: .text | |
| 16 | Type: SHT_PROGBITS | |
| 17 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 18 | - Name: .rela.text1 | |
| 19 | Type: SHT_RELA | |
| 20 | Link: .symtab | |
| 21 | Info: .text | |
| 22 | - Name: .rela.text2 | |
| 23 | Type: SHT_RELA | |
| 24 | Link: .symtab | |
| 25 | Info: .text | |
| 26 | Symbols: | |
| 27 | - Name: .text | |
| 28 | Type: STT_SECTION | |
| 29 | Section: .text |
deps/lld/test/ELF/invalid/reloc-section-reordered.test+4| ... | ... | @@ -28,3 +28,7 @@ Sections: |
| 28 | 28 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] |
| 29 | 29 | AddressAlign: 0x04 |
| 30 | 30 | Content: "FFFFFFFFFFFFFFFF" |
| 31 | Symbols: | |
| 32 | - Name: .text | |
| 33 | Type: STT_SECTION | |
| 34 | Section: .text |
deps/lld/test/ELF/invalid/section-alignment2.s+16-5| ... | ... | @@ -1,5 +1,16 @@ |
| 1 | ## section-alignment-notpow2.elf has section alignment | |
| 2 | ## 0xFFFFFFFF which is not a power of 2. | |
| 3 | # RUN: not ld.lld %p/Inputs/section-alignment-notpow2.elf -o /dev/null 2>&1 | \ | |
| 4 | # RUN: FileCheck %s | |
| 5 | # CHECK: section sh_addralign is not a power of 2 | |
| 1 | # RUN: yaml2obj %s -o %t.o | |
| 2 | # RUN: not ld.lld %t.o -o %tout 2>&1 | FileCheck %s | |
| 3 | ||
| 4 | # CHECK: error: {{.*}}.o:(.text): sh_addralign is not a power of 2 | |
| 5 | ||
| 6 | !ELF | |
| 7 | FileHeader: | |
| 8 | Class: ELFCLASS64 | |
| 9 | Data: ELFDATA2LSB | |
| 10 | Type: ET_REL | |
| 11 | Machine: EM_X86_64 | |
| 12 | Sections: | |
| 13 | - Name: .text | |
| 14 | Type: SHT_PROGBITS | |
| 15 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 16 | AddressAlign: 0x3 |
deps/lld/test/ELF/invalid/section-index.test created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | ## If an object contains a symbol with a broken (too large) st_shndx, | |
| 2 | ## check we report it. | |
| 3 | ||
| 4 | # RUN: yaml2obj %s -o %t1.o | |
| 5 | # RUN: not ld.lld %t1.o -o %t 2>&1 | FileCheck %s | |
| 6 | # CHECK: {{.*}}1.o: invalid section index: 256 | |
| 7 | ||
| 8 | !ELF | |
| 9 | FileHeader: | |
| 10 | Class: ELFCLASS32 | |
| 11 | Data: ELFDATA2LSB | |
| 12 | Type: ET_REL | |
| 13 | Machine: EM_386 | |
| 14 | Symbols: | |
| 15 | - Name: foo | |
| 16 | Index: 0x100 |
deps/lld/test/ELF/invalid/sht-group-wrong-section.test+2-2| ... | ... | @@ -18,5 +18,5 @@ Sections: |
| 18 | 18 | - SectionOrType: GRP_COMDAT |
| 19 | 19 | - SectionOrType: 12345 |
| 20 | 20 | Symbols: |
| 21 | Global: | |
| 22 | - Name: foo | |
| 21 | - Name: foo | |
| 22 | Binding: STB_GLOBAL |
deps/lld/test/ELF/invalid/symbol-index.s deleted-10| ... | ... | @@ -1,10 +0,0 @@ |
| 1 | ## symbol-index.elf has incorrect type of .symtab section. | |
| 2 | ## There is no symbol bodies because of that and any symbol index becomes incorrect. | |
| 3 | ## Section Headers: | |
| 4 | ## [Nr] Name Type Address Off Size ES Flg Lk Inf Al | |
| 5 | ## [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 | |
| 6 | ## ... | |
| 7 | ## [ 4] .symtab RELA 0000000000000000 000048 000030 18 1 2 8 | |
| 8 | # RUN: not ld.lld %p/Inputs/symbol-index.elf -o /dev/null 2>&1 | \ | |
| 9 | # RUN: FileCheck --check-prefix=INVALID-SYMBOL-INDEX %s | |
| 10 | # INVALID-SYMBOL-INDEX: invalid symbol index |
deps/lld/test/ELF/invalid/symbol-name.s deleted-7| ... | ... | @@ -1,7 +0,0 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | ## symbol-name-offset.elf contains symbol with invalid (too large) | |
| 4 | ## st_name value. | |
| 5 | # RUN: not ld.lld %S/Inputs/symbol-name-offset.elf \ | |
| 6 | # RUN: -o /dev/null 2>&1 | FileCheck %s | |
| 7 | # CHECK: invalid symbol name offset |
deps/lld/test/ELF/invalid/symbol-name.test created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | # RUN: yaml2obj %s -o %t.o | |
| 2 | # RUN: not ld.lld %t.o -o %t.exe 2>&1 | FileCheck %s | |
| 3 | # CHECK: error: {{.*}}.o: invalid symbol name offset | |
| 4 | ||
| 5 | ## YAML below contains symbol with name offset in st_name | |
| 6 | ## larger than string table size. Check we report it. | |
| 7 | ||
| 8 | !ELF | |
| 9 | FileHeader: | |
| 10 | Class: ELFCLASS64 | |
| 11 | Data: ELFDATA2LSB | |
| 12 | Type: ET_REL | |
| 13 | Machine: EM_X86_64 | |
| 14 | Symbols: | |
| 15 | - NameIndex: 255 |
deps/lld/test/ELF/invalid/symtab-sh-info.s+59-9| ... | ... | @@ -1,9 +1,59 @@ |
| 1 | ## sh_info contains zero value. First entry in a symbol table is always completely zeroed, | |
| 2 | ## so sh_info should be at least 1 in a valid ELF. | |
| 3 | # RUN: not ld.lld %p/Inputs/symtab-sh_info2.elf -o %t2 2>&1 | FileCheck %s | |
| 4 | # CHECK: invalid sh_info in symbol table | |
| 5 | ||
| 6 | ## sh_info contains invalid value saying non-local symbol is local. | |
| 7 | # RUN: not ld.lld %p/Inputs/symtab-sh_info3.elf -o %t2 2>&1 | \ | |
| 8 | # RUN: FileCheck --check-prefix=INVALID-SYMTAB-SHINFO %s | |
| 9 | # INVALID-SYMTAB-SHINFO: broken object: getLocalSymbols returns a non-local symbol | |
| 1 | ## .symtab's sh_info contains zero value. First entry in a .symtab is a | |
| 2 | ## zero entry that must exist in a valid object, so sh_info can't be null. | |
| 3 | ## Check we report a proper error for that case. | |
| 4 | # RUN: yaml2obj -docnum=1 %s -o %t.o | |
| 5 | # RUN: not ld.lld %t.o -o %t2 2>&1 | FileCheck %s --check-prefix=ERR1 | |
| 6 | # ERR1: invalid sh_info in symbol table | |
| 7 | ||
| 8 | --- !ELF | |
| 9 | FileHeader: | |
| 10 | Class: ELFCLASS64 | |
| 11 | Data: ELFDATA2LSB | |
| 12 | Type: ET_REL | |
| 13 | Machine: EM_X86_64 | |
| 14 | Sections: | |
| 15 | - Name: .symtab | |
| 16 | Info: 0 | |
| 17 | Type: SHT_SYMTAB | |
| 18 | Symbols: | |
| 19 | - Name: foo | |
| 20 | Binding: STB_GLOBAL | |
| 21 | ||
| 22 | ## sh_info has value 2 what says that non-local symbol `foo` is local. | |
| 23 | ## Check we report this case. | |
| 24 | # RUN: yaml2obj -docnum=2 %s -o %t.o | |
| 25 | # RUN: not ld.lld %t.o -o %t2 2>&1 | FileCheck --check-prefix=ERR2 %s | |
| 26 | # ERR2: broken object: getLocalSymbols returns a non-local symbol | |
| 27 | ||
| 28 | --- !ELF | |
| 29 | FileHeader: | |
| 30 | Class: ELFCLASS64 | |
| 31 | Data: ELFDATA2LSB | |
| 32 | Type: ET_REL | |
| 33 | Machine: EM_X86_64 | |
| 34 | Sections: | |
| 35 | - Name: .symtab | |
| 36 | Info: 2 | |
| 37 | Type: SHT_SYMTAB | |
| 38 | Symbols: | |
| 39 | - Name: foo | |
| 40 | Binding: STB_GLOBAL | |
| 41 | ||
| 42 | ## sh_info has value 0xff what is larger than number of symbols in a .symtab. | |
| 43 | ## Check we report this case. | |
| 44 | # RUN: yaml2obj -docnum=3 %s -o %t.o | |
| 45 | # RUN: not ld.lld %t.o -o %t2 2>&1 | FileCheck --check-prefix=ERR1 %s | |
| 46 | ||
| 47 | --- !ELF | |
| 48 | FileHeader: | |
| 49 | Class: ELFCLASS64 | |
| 50 | Data: ELFDATA2LSB | |
| 51 | Type: ET_REL | |
| 52 | Machine: EM_X86_64 | |
| 53 | Sections: | |
| 54 | - Name: .symtab | |
| 55 | Info: 0xff | |
| 56 | Type: SHT_SYMTAB | |
| 57 | Symbols: | |
| 58 | - Name: foo | |
| 59 | Binding: STB_GLOBAL |
deps/lld/test/ELF/invalid/symtab-symbols.test+2-3| ... | ... | @@ -20,6 +20,5 @@ Sections: |
| 20 | 20 | AddressAlign: 0x0000000000000010 |
| 21 | 21 | Content: "00000000" |
| 22 | 22 | Symbols: |
| 23 | Local: | |
| 24 | - Type: STT_NOTYPE | |
| 25 | Section: .symtab | |
| 23 | - Type: STT_NOTYPE | |
| 24 | Section: .symtab |
deps/lld/test/ELF/invalid/tls-symbol.s+22-3| ... | ... | @@ -1,5 +1,24 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | 1 | ## The test file contains an STT_TLS symbol but has no TLS section. |
| 4 | # RUN: not ld.lld %S/Inputs/tls-symbol.elf -o /dev/null 2>&1 | FileCheck %s | |
| 2 | ## Check we report an error properly. | |
| 3 | ||
| 4 | # RUN: yaml2obj %s -o %t.o | |
| 5 | # RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s | |
| 6 | ||
| 5 | 7 | # CHECK: has an STT_TLS symbol but doesn't have an SHF_TLS section |
| 8 | ||
| 9 | --- !ELF | |
| 10 | FileHeader: | |
| 11 | Class: ELFCLASS64 | |
| 12 | Data: ELFDATA2LSB | |
| 13 | Type: ET_REL | |
| 14 | Machine: EM_X86_64 | |
| 15 | Sections: | |
| 16 | - Name: .text | |
| 17 | Type: SHT_PROGBITS | |
| 18 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 19 | Content: '' | |
| 20 | Symbols: | |
| 21 | - Name: bar | |
| 22 | Type: STT_TLS | |
| 23 | Section: .text | |
| 24 | Binding: STB_GLOBAL |
deps/lld/test/ELF/invalid/undefined-local-symbol-in-dso.test+16-56| ... | ... | @@ -8,59 +8,19 @@ |
| 8 | 8 | # STB_LOCAL is a nonsensical combination. Nevertheless, we should warn on such |
| 9 | 9 | # input files instead of crashing. |
| 10 | 10 | |
| 11 | # We've found actual broken DSOs of this sort in the wild, but for this test, we | |
| 12 | # created a reduced broken input file. There are no tools capable of producing a | |
| 13 | # broken DSO of this nature, so instead we created a valid DSO with an undefined | |
| 14 | # global symbol in the dynamic symbol table and then manually edited the binary | |
| 15 | # to make that symbol local. The valid DSO was created as follows: | |
| 16 | ||
| 17 | ``` | |
| 18 | % cat undef.s | |
| 19 | .hidden bar | |
| 20 | bar: | |
| 21 | 	movq	foo@GOT, %rax | |
| 22 | ||
| 23 | % llvm-mc -triple=x86_64-linux-gnu -filetype=obj -o undef.o undef.s | |
| 24 | % ld.lld --no-rosegment -shared -o undefined-local-symbol-in-dso.so undef.o | |
| 25 | % strip undef.so | |
| 26 | ``` | |
| 27 | ||
| 28 | # (--no-rosegment and stripping are unnecessary; they just produce a smaller | |
| 29 | # binary) | |
| 30 | ||
| 31 | # This DSO should only have a single dynamic symbol table entry for foo, and | |
| 32 | # then we can use a small C program to modify that symbol table entry to be | |
| 33 | # STB_LOCAL instead of STB_GLOBAL. | |
| 34 | ||
| 35 | ``` | |
| 36 | #include <elf.h> | |
| 37 | #include <stdio.h> | |
| 38 | ||
| 39 | int main(int argc, char *argv[]) { | |
| 40 | FILE *F = fopen(argv[1], "rb+"); | |
| 41 | ||
| 42 | Elf64_Ehdr Ehdr; | |
| 43 | fread(&Ehdr, sizeof(Ehdr), 1, F); | |
| 44 | fseek(F, Ehdr.e_shoff, SEEK_SET); | |
| 45 | ||
| 46 | Elf64_Shdr Shdr; | |
| 47 | do { | |
| 48 | fread(&Shdr, sizeof(Shdr), 1, F); | |
| 49 | } while (Shdr.sh_type != SHT_DYNSYM); | |
| 50 | ||
| 51 | Elf64_Sym Sym; | |
| 52 | fseek(F, Shdr.sh_offset + sizeof(Elf64_Sym), SEEK_SET); | |
| 53 | fread(&Sym, sizeof(Sym), 1, F); | |
| 54 | Sym.st_info = STB_LOCAL << 4 | ELF64_ST_TYPE(Sym.st_info); | |
| 55 | fseek(F, Shdr.sh_offset + sizeof(Elf64_Sym), SEEK_SET); | |
| 56 | fwrite(&Sym, sizeof(Sym), 1, F); | |
| 57 | fclose(F); | |
| 58 | } | |
| 59 | ``` | |
| 60 | ||
| 61 | # (the C program just takes its input DSO and modifies the binding of the first | |
| 62 | # dynamic symbol table entry to be STB_LOCAL instead of STB_GLOBAL) | |
| 63 | ||
| 64 | # RUN: ld.lld %p/Inputs/undefined-local-symbol-in-dso.so -o %t 2>&1 | \ | |
| 65 | # RUN: FileCheck -check-prefix=WARN %s | |
| 66 | # WARN: found local symbol 'foo' in global part of symbol table in file {{.*}}undefined-local-symbol-in-dso.so | |
| 11 | # RUN: yaml2obj %s -o %t.so | |
| 12 | # RUN: ld.lld %t.so -o %t 2>&1 | FileCheck -check-prefix=WARN %s | |
| 13 | # WARN: found local symbol 'foo' in global part of symbol table in file {{.*}}.so | |
| 14 | ||
| 15 | --- !ELF | |
| 16 | FileHeader: | |
| 17 | Class: ELFCLASS64 | |
| 18 | Data: ELFDATA2LSB | |
| 19 | Type: ET_DYN | |
| 20 | Machine: EM_X86_64 | |
| 21 | Sections: | |
| 22 | - Name: .dynsym | |
| 23 | Info: 1 | |
| 24 | Type: SHT_DYNSYM | |
| 25 | DynamicSymbols: | |
| 26 | - Name: foo |
deps/lld/test/ELF/invalid/verdef-no-symtab.test+1-8| ... | ... | @@ -14,13 +14,6 @@ Sections: |
| 14 | 14 | Type: SHT_GNU_versym |
| 15 | 15 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] |
| 16 | 16 | AddressAlign: 0x1 |
| 17 | Content: "00000000" | |
| 18 | ||
| 19 | - Name: .verdef | |
| 20 | Type: SHT_GNU_verdef | |
| 21 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 22 | AddressAlign: 0x1 | |
| 23 | Content: "00000000" | |
| 24 | ||
| 17 | Entries: [ 0 ] | |
| 25 | 18 | |
| 26 | 19 | # CHECK: SHT_GNU_versym should be associated with symbol table |
deps/lld/test/ELF/invalid/x86-64-tlsdesc-gd.s created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | # RUN: echo '.tbss; .globl a; a:' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o | |
| 4 | # RUN: ld.lld -shared %t1.o -o %t1.so | |
| 5 | ||
| 6 | ## GD to LE relaxation. | |
| 7 | # RUN: not ld.lld %t.o %t1.o -o /dev/null 2>&1 | FileCheck -DINPUT=%t.o %s | |
| 8 | ## GD to IE relaxation. | |
| 9 | # RUN: not ld.lld %t.o %t1.so -o /dev/null 2>&1 | FileCheck -DINPUT=%t.o %s | |
| 10 | ||
| 11 | # CHECK: error: [[INPUT]]:(.text+0x0): R_X86_64_GOTPC32_TLSDESC must be used in callq *x@tlsdesc(%rip), %rax | |
| 12 | ||
| 13 | leaq a@tlsdesc(%rip), %rdx | |
| 14 | call *a@tlscall(%rdx) | |
| 15 | movl %fs:(%rax), %eax |
deps/lld/test/ELF/linkerscript/absolute-expr.test+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: echo ".global foo; foo = 0x123" | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t.o |
| 3 | 3 | # RUN: ld.lld -o %t.so --script %s %t.o -shared |
| 4 | # RUN: llvm-readobj -t %t.so | FileCheck %s | |
| 4 | # RUN: llvm-readobj --symbols %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | SECTIONS { |
| 7 | 7 | .text : { |
deps/lld/test/ELF/linkerscript/addr-zero.test+10-4| ... | ... | @@ -1,14 +1,14 @@ |
| 1 | # REQUIRES: x86 | |
| 1 | # REQUIRES: x86, aarch64 | |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o |
| 3 | 3 | # RUN: ld.lld -o %t.so --script %s %t.o -shared |
| 4 | 4 | # RUN: llvm-readobj --symbols %t.so | FileCheck %s |
| 5 | 5 | |
| 6 | # Test that the script creates a non absolute symbol with value | |
| 7 | # 0 I.E., a symbol that refers to the load address. | |
| 6 | ## Test that the script creates a non absolute symbol with value | |
| 7 | ## 0 I.E., a symbol that refers to the load address. | |
| 8 | 8 | |
| 9 | 9 | # CHECK: Symbol { |
| 10 | 10 | # CHECK: Name: foo |
| 11 | # CHECK-NEXT: Value: 0x70 | |
| 11 | # CHECK-NEXT: Value: 0x0 | |
| 12 | 12 | # CHECK-NEXT: Size: 0 |
| 13 | 13 | # CHECK-NEXT: Binding: Global |
| 14 | 14 | # CHECK-NEXT: Type: None |
| ... | ... | @@ -16,6 +16,12 @@ |
| 16 | 16 | # CHECK-NEXT: Section: .text |
| 17 | 17 | # CHECK-NEXT: } |
| 18 | 18 | |
| 19 | ## Because of a bug we had a different behavior (different symbol 'foo' value) | |
| 20 | ## on a platforms that might use thunks, like AArch64. Check that issue is fixed. | |
| 21 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu /dev/null -o %t.o | |
| 22 | # RUN: ld.lld -o %t.so --script %s %t.o -shared | |
| 23 | # RUN: llvm-readobj --symbols %t.so | FileCheck %s | |
| 24 | ||
| 19 | 25 | SECTIONS { |
| 20 | 26 | foo = ADDR(.text) - ABSOLUTE(ADDR(.text)); |
| 21 | 27 | }; |
deps/lld/test/ELF/linkerscript/addr.test+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: llvm-objdump -section-headers %t1 | FileCheck %s |
| 5 | 5 | |
| 6 | 6 | # CHECK: Sections: |
| 7 | # CHECK-NEXT: Idx Name Size Address Type | |
| 7 | # CHECK-NEXT: Idx Name Size VMA Type | |
| 8 | 8 | # CHECK-NEXT: 0 00000000 0000000000000000 |
| 9 | 9 | # CHECK-NEXT: 1 .text 00000000 0000000000001000 TEXT |
| 10 | 10 | # CHECK-NEXT: 2 .foo.1 00000008 0000000000001000 DATA |
deps/lld/test/ELF/linkerscript/align-empty.test+1-1| ... | ... | @@ -13,7 +13,7 @@ SECTIONS { |
| 13 | 13 | } |
| 14 | 14 | |
| 15 | 15 | # CHECK: Sections: |
| 16 | # CHECK-NEXT: Idx Name Size Address | |
| 16 | # CHECK-NEXT: Idx Name Size VMA | |
| 17 | 17 | # CHECK-NEXT: 0 00000000 0000000000000000 |
| 18 | 18 | # CHECK-NEXT: 1 .dynsym 00000018 0000000000000190 |
| 19 | 19 | # CHECK-NEXT: 2 .gnu.hash 0000001c 00000000000001a8 |
deps/lld/test/ELF/linkerscript/align1.test+2-2| ... | ... | @@ -13,7 +13,7 @@ SECTIONS { |
| 13 | 13 | } |
| 14 | 14 | |
| 15 | 15 | # CHECK: Sections: |
| 16 | # CHECK-NEXT: Idx Name Size Address Type | |
| 16 | # CHECK-NEXT: Idx Name Size VMA Type | |
| 17 | 17 | # CHECK-NEXT: 0 00000000 0000000000000000 |
| 18 | 18 | # CHECK-NEXT: 1 .aaa 00000008 0000000000010000 DATA |
| 19 | 19 | # CHECK-NEXT: 2 .bbb 00000008 0000000000011000 DATA |
| ... | ... | @@ -25,7 +25,7 @@ SECTIONS { |
| 25 | 25 | # RUN: llvm-objdump -section-headers %t4 | FileCheck %s -check-prefix=ZERO |
| 26 | 26 | |
| 27 | 27 | # ZERO: Sections: |
| 28 | # ZERO-NEXT: Idx Name Size Address Type | |
| 28 | # ZERO-NEXT: Idx Name Size VMA Type | |
| 29 | 29 | # ZERO-NEXT: 0 00000000 0000000000000000 |
| 30 | 30 | # ZERO-NEXT: 1 .aaa 00000008 0000000000000123 DATA |
| 31 | 31 |
deps/lld/test/ELF/linkerscript/align2.test+1-1| ... | ... | @@ -13,7 +13,7 @@ SECTIONS { |
| 13 | 13 | } |
| 14 | 14 | |
| 15 | 15 | # CHECK: Sections: |
| 16 | # CHECK-NEXT: Idx Name Size Address Type | |
| 16 | # CHECK-NEXT: Idx Name Size VMA Type | |
| 17 | 17 | # CHECK-NEXT: 0 00000000 0000000000000000 |
| 18 | 18 | # CHECK-NEXT: 1 .aaa 00000008 0000000000010000 DATA |
| 19 | 19 | # CHECK-NEXT: 2 .bbb 00000008 0000000000011000 DATA |
deps/lld/test/ELF/linkerscript/align3.test+1-1| ... | ... | @@ -11,7 +11,7 @@ SECTIONS { |
| 11 | 11 | } |
| 12 | 12 | |
| 13 | 13 | # CHECK: Sections: |
| 14 | # CHECK-NEXT: Idx Name Size Address Type | |
| 14 | # CHECK-NEXT: Idx Name Size VMA Type | |
| 15 | 15 | # CHECK-NEXT: 0 00000000 0000000000000000 |
| 16 | 16 | # CHECK-NEXT: 1 .aaa 00000008 0000000000010000 DATA |
| 17 | 17 | # CHECK-NEXT: 2 .bbb 00000008 0000000000011000 DATA |
deps/lld/test/ELF/linkerscript/alternate-sections.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: echo "SECTIONS { abc : { *(foo) *(bar) *(zed) } }" > %t.script |
| 4 | 4 | # RUN: ld.lld -o %t --script %t.script %t.o -shared |
| 5 | # RUN: llvm-readobj -s -section-data %t | FileCheck %s | |
| 5 | # RUN: llvm-readobj -S --section-data %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: Section { |
| 8 | 8 | # CHECK: Index: |
deps/lld/test/ELF/linkerscript/arm-exidx-order.test+2-2| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: echo ".fnstart; .cantunwind; .fnend" \ |
| 3 | 3 | # RUN: | llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi - -o %t.o |
| 4 | 4 | # RUN: ld.lld -T %s %t.o -shared -o %t.so |
| 5 | # RUN: llvm-readobj -s %t.so | FileCheck %s | |
| 5 | # RUN: llvm-readobj -S %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | SECTIONS { |
| 8 | 8 | . = SIZEOF_HEADERS; |
| ... | ... | @@ -13,7 +13,7 @@ SECTIONS { |
| 13 | 13 | # CHECK: Section { |
| 14 | 14 | # CHECK: Index: |
| 15 | 15 | # CHECK: Name: .foo |
| 16 | # CHECK-NEXT: Type: SHT_NOBITS | |
| 16 | # CHECK-NEXT: Type: SHT_PROGBITS | |
| 17 | 17 | # CHECK-NEXT: Flags [ |
| 18 | 18 | # CHECK-NEXT: SHF_ALLOC |
| 19 | 19 | # CHECK-NEXT: ] |
deps/lld/test/ELF/linkerscript/arm-exidx-sentinel-and-assignment.s+1-1| ... | ... | @@ -8,7 +8,7 @@ |
| 8 | 8 | ## was anything but an input section description. |
| 9 | 9 | # RUN: ld.lld --no-merge-exidx-entries -T %t.script %t.o -shared -o %t.so |
| 10 | 10 | # RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t.so | FileCheck %s |
| 11 | # RUN: llvm-readobj -s -t %t.so | FileCheck %s --check-prefix=SYMBOL | |
| 11 | # RUN: llvm-readobj -S --symbols %t.so | FileCheck %s --check-prefix=SYMBOL | |
| 12 | 12 | |
| 13 | 13 | .syntax unified |
| 14 | 14 | .text |
deps/lld/test/ELF/linkerscript/at-addr.s+1-1| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | # RUN: .ccc : AT(ADDR(.ccc) - 0x500) { *(.ccc) } \ |
| 7 | 7 | # RUN: }" > %t.script |
| 8 | 8 | # RUN: ld.lld %t --script %t.script -o %t2 |
| 9 | # RUN: llvm-readobj -program-headers %t2 | FileCheck %s | |
| 9 | # RUN: llvm-readobj -l %t2 | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | # CHECK: Type: PT_LOAD |
| 12 | 12 | # CHECK-NEXT: Offset: 0x1000 |
deps/lld/test/ELF/linkerscript/at-self-reference.s+1-1| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | # RUN: .bbb : AT(ADDR(.bbb)) { *(.bbb) } \ |
| 7 | 7 | # RUN: }" > %t.script |
| 8 | 8 | # RUN: ld.lld %t --script %t.script -o %t2 |
| 9 | # RUN: llvm-readobj -program-headers %t2 | FileCheck %s | |
| 9 | # RUN: llvm-readobj -l %t2 | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | # CHECK: ProgramHeaders [ |
| 12 | 12 | # CHECK-NEXT: ProgramHeader { |
deps/lld/test/ELF/linkerscript/at.s+1-1| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | # RUN: .eee 0x5000 : AT(0x5000) { *(.eee) } \ |
| 10 | 10 | # RUN: }" > %t.script |
| 11 | 11 | # RUN: ld.lld %t --script %t.script -o %t2 |
| 12 | # RUN: llvm-readobj -program-headers %t2 | FileCheck %s | |
| 12 | # RUN: llvm-readobj -l %t2 | FileCheck %s | |
| 13 | 13 | |
| 14 | 14 | # CHECK: ProgramHeaders [ |
| 15 | 15 | # CHECK-NEXT: ProgramHeader { |
deps/lld/test/ELF/linkerscript/at2.test+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/at2.s -o %t.o |
| 3 | 3 | # RUN: ld.lld -o %t.exe %t.o --script %s |
| 4 | # RUN: llvm-readobj -program-headers %t.exe | FileCheck %s | |
| 4 | # RUN: llvm-readobj -l %t.exe | FileCheck %s | |
| 5 | 5 | # RUN: llvm-objdump -section-headers %t.exe | FileCheck %s --check-prefix=SECTIONS |
| 6 | 6 | |
| 7 | 7 | MEMORY { |
| ... | ... | @@ -48,7 +48,7 @@ SECTIONS { |
| 48 | 48 | # CHECK-NEXT: } |
| 49 | 49 | |
| 50 | 50 | # SECTIONS: Sections: |
| 51 | # SECTIONS-NEXT: Idx Name Size Address | |
| 51 | # SECTIONS-NEXT: Idx Name Size VMA | |
| 52 | 52 | # SECTIONS-NEXT: 0 00000000 0000000000000000 |
| 53 | 53 | # SECTIONS-NEXT: 1 .foo1 00000008 0000000000002000 |
| 54 | 54 | # SECTIONS-NEXT: 2 .foo2 00000008 0000000000002008 |
deps/lld/test/ELF/linkerscript/at4.s+1-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: .ccc : { *(.ccc) } \ |
| 8 | 8 | # RUN: }" > %t.script |
| 9 | 9 | # RUN: ld.lld %t --script %t.script -o %t2 |
| 10 | # RUN: llvm-readobj -program-headers %t2 | FileCheck %s | |
| 10 | # RUN: llvm-readobj -l %t2 | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | # CHECK: Type: PT_LOAD |
| 13 | 13 | # CHECK-NEXT: Offset: 0x1000 |
deps/lld/test/ELF/linkerscript/comdat-gc.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/comdat-gc.s -o %t1 |
| 5 | 5 | # RUN: echo "SECTIONS { .text : { *(.text*) } }" > %t.script |
| 6 | 6 | # RUN: ld.lld --gc-sections --script %t.script %t %t1 -o %t2 |
| 7 | # RUN: llvm-readobj -sections -symbols %t2 | FileCheck -check-prefix=GC1 %s | |
| 7 | # RUN: llvm-readobj --sections --symbols %t2 | FileCheck -check-prefix=GC1 %s | |
| 8 | 8 | |
| 9 | 9 | # GC1: Name: .debug_line |
| 10 | 10 |
deps/lld/test/ELF/linkerscript/common-assign.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | # RUN: echo "SECTIONS { . = SIZEOF_HEADERS; pfoo = foo; pbar = bar; }" > %t.script |
| 4 | 4 | # RUN: ld.lld -o %t1 --script %t.script %t |
| 5 | # RUN: llvm-readobj -symbols %t1 | FileCheck %s | |
| 5 | # RUN: llvm-readobj --symbols %t1 | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: Symbol { |
| 8 | 8 | # CHECK: Name: bar |
deps/lld/test/ELF/linkerscript/common-exclude.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/common-filespec2.s -o %tfile2.o |
| 5 | 5 | # RUN: echo "SECTIONS { .common.incl : { *(EXCLUDE_FILE (*file2.o) COMMON) } .common.excl : { *(COMMON) } }" > %t.script |
| 6 | 6 | # RUN: ld.lld -o %t1 --script %t.script %tfile0.o %tfile1.o %tfile2.o |
| 7 | # RUN: llvm-readobj -s -t %t1 | FileCheck %s | |
| 7 | # RUN: llvm-readobj -S --symbols %t1 | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | # Commons from file0 and file1 are not excluded, so they must be in .common.incl |
| 10 | 10 | # Commons from file2 are excluded from the first rule and should be caught by |
deps/lld/test/ELF/linkerscript/common-filespec.test+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/common-filespec1.s -o %tfile1.o |
| 5 | 5 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/common-filespec2.s -o %tfile2.o |
| 6 | 6 | # RUN: ld.lld -o %t1 --script %s %tfile0.o %tfile1.o %tfile2.o |
| 7 | # RUN: llvm-readobj -s -t %t1 | FileCheck %s | |
| 7 | # RUN: llvm-readobj -S --symbols %t1 | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | SECTIONS { |
| 10 | 10 | .common_0 : { *file0.o(COMMON) } |
deps/lld/test/ELF/linkerscript/common.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | # RUN: echo "SECTIONS { . = SIZEOF_HEADERS; .common : { *(COMMON) } }" > %t.script |
| 4 | 4 | # RUN: ld.lld -o %t1 --script %t.script %t |
| 5 | # RUN: llvm-readobj -s -t %t1 | FileCheck %s | |
| 5 | # RUN: llvm-readobj -S --symbols %t1 | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: Section { |
| 8 | 8 | # CHECK: Index: |
deps/lld/test/ELF/linkerscript/compress-debug-sections.s+2-2| ... | ... | @@ -11,12 +11,12 @@ |
| 11 | 11 | # RUN: echo "SECTIONS { }" > %t.script |
| 12 | 12 | # RUN: ld.lld -O0 %t1.o %t2.o %t.script -o %t1 --compress-debug-sections=zlib |
| 13 | 13 | # RUN: llvm-dwarfdump -a %t1 | FileCheck %s |
| 14 | # RUN: llvm-readobj -s %t1 | FileCheck %s --check-prefix=ZLIBFLAGS | |
| 14 | # RUN: llvm-readobj -S %t1 | FileCheck %s --check-prefix=ZLIBFLAGS | |
| 15 | 15 | |
| 16 | 16 | # RUN: echo "SECTIONS { .debug_str 0 : { *(.debug_str) } }" > %t2.script |
| 17 | 17 | # RUN: ld.lld -O0 %t1.o %t2.o %t2.script -o %t2 --compress-debug-sections=zlib |
| 18 | 18 | # RUN: llvm-dwarfdump -a %t2 | FileCheck %s |
| 19 | # RUN: llvm-readobj -s %t2 | FileCheck %s --check-prefix=ZLIBFLAGS | |
| 19 | # RUN: llvm-readobj -S %t2 | FileCheck %s --check-prefix=ZLIBFLAGS | |
| 20 | 20 | |
| 21 | 21 | # CHECK: .debug_str contents: |
| 22 | 22 | # CHECK-NEXT: CCC |
deps/lld/test/ELF/linkerscript/copy-rel-symbol-value.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: ld.lld %t2.o -o %t2.so -shared |
| 5 | 5 | # RUN: echo "SECTIONS { . = . + SIZEOF_HEADERS; foo = bar; }" > %t.script |
| 6 | 6 | # RUN: ld.lld %t.o %t2.so --script %t.script -o %t |
| 7 | # RUN: llvm-readobj -t %t | FileCheck %s | |
| 7 | # RUN: llvm-readobj --symbols %t | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | # CHECK: Name: bar |
| 10 | 10 | # CHECK-NEXT: Value: 0x[[VAL:.*]] |
deps/lld/test/ELF/linkerscript/data-segment-relro.test+2-2| ... | ... | @@ -7,10 +7,10 @@ |
| 7 | 7 | ## page boundary. |
| 8 | 8 | |
| 9 | 9 | # RUN: ld.lld --hash-style=sysv -z norelro %t1.o %t2.so --script %s -o %t |
| 10 | # RUN: llvm-readobj -s %t | FileCheck %s | |
| 10 | # RUN: llvm-readobj -S %t | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | # RUN: ld.lld --hash-style=sysv -z relro %t1.o %t2.so --script %s -o %t2 |
| 13 | # RUN: llvm-readobj -s %t2 | FileCheck %s | |
| 13 | # RUN: llvm-readobj -S %t2 | FileCheck %s | |
| 14 | 14 | |
| 15 | 15 | SECTIONS { |
| 16 | 16 | . = SIZEOF_HEADERS; |
deps/lld/test/ELF/linkerscript/defsym.s+2-2| ... | ... | @@ -7,13 +7,13 @@ |
| 7 | 7 | |
| 8 | 8 | ## Check that linker script can override -defsym assignments. |
| 9 | 9 | # RUN: ld.lld %t.o -defsym=foo=0x11 -script %t.script -o %t |
| 10 | # RUN: llvm-readobj -t %t | FileCheck %s | |
| 10 | # RUN: llvm-readobj --symbols %t | FileCheck %s | |
| 11 | 11 | # CHECK: Name: foo |
| 12 | 12 | # CHECK-NEXT: Value: 0x22 |
| 13 | 13 | |
| 14 | 14 | ## Check that -defsym can override linker script. Check that multiple |
| 15 | 15 | ## -defsym commands for the same symbol are allowed. |
| 16 | 16 | # RUN: ld.lld %t.o -script %t.script -defsym=foo=0x11 -defsym=foo=0x33 -o %t |
| 17 | # RUN: llvm-readobj -t %t | FileCheck %s --check-prefix=REORDER | |
| 17 | # RUN: llvm-readobj --symbols %t | FileCheck %s --check-prefix=REORDER | |
| 18 | 18 | # REORDER: Name: foo |
| 19 | 19 | # REORDER-NEXT: Value: 0x33 |
deps/lld/test/ELF/linkerscript/discard-interp.test+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/../Inputs/shared.s -o %t2.o |
| 4 | 4 | # RUN: ld.lld -shared %t2.o -o %t2.so |
| 5 | 5 | # RUN: ld.lld -dynamic-linker foo -rpath bar -rpath baz --script %s --export-dynamic %t.o %t2.so -o %t |
| 6 | # RUN: llvm-readobj -s %t | FileCheck %s | |
| 6 | # RUN: llvm-readobj -S %t | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | # CHECK-NOT: Name: .interp |
| 9 | 9 |
deps/lld/test/ELF/linkerscript/discard-phdr.s created+36| ... | ... | @@ -0,0 +1,36 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 3 | # RUN: echo "PHDRS { \ | |
| 4 | # RUN: exec PT_LOAD FLAGS(0x4 | 0x1); \ | |
| 5 | # RUN: } \ | |
| 6 | # RUN: SECTIONS { \ | |
| 7 | # RUN: .text : { *(.text) } :exec \ | |
| 8 | # RUN: .foo : { *(.foo) } \ | |
| 9 | # RUN: .bar : { *(.bar) } \ | |
| 10 | # RUN: /DISCARD/ : { *(.discard) } :NONE \ | |
| 11 | # RUN: }" > %t.script | |
| 12 | # RUN: ld.lld -o %t --script %t.script %t.o | |
| 13 | # RUN: llvm-readelf -S -l %t | FileCheck --implicit-check-not=/DISCARD/ %s | |
| 14 | ||
| 15 | ## Check that /DISCARD/ does not interfere with the assignment of segments to | |
| 16 | ## sections. | |
| 17 | ||
| 18 | # CHECK: Section Headers | |
| 19 | # CHECK: .text | |
| 20 | # CHECK-NEXT: .foo | |
| 21 | # CHECK-NEXT: .bar | |
| 22 | ||
| 23 | # CHECK: Segment Sections | |
| 24 | # CHECK-NEXT: .text .foo .bar | |
| 25 | ||
| 26 | .section .text,"ax" | |
| 27 | ret | |
| 28 | ||
| 29 | .section .foo,"a" | |
| 30 | .byte 0 | |
| 31 | ||
| 32 | .section .bar,"ax" | |
| 33 | ret | |
| 34 | ||
| 35 | .section .discard | |
| 36 | .byte 0 |
deps/lld/test/ELF/linkerscript/dot-is-not-abs.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | |
| 4 | 4 | # RUN: echo "SECTIONS { .text : { *(.text) } foo = .; .bar : { *(.bar) } }" > %t1.script |
| 5 | 5 | # RUN: ld.lld -o %t1 --script %t1.script %t.o -shared |
| 6 | # RUN: llvm-readobj -t -s -section-data %t1 | FileCheck %s | |
| 6 | # RUN: llvm-readobj --symbols -S --section-data %t1 | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | .hidden foo |
| 9 | 9 | .long foo - . |
deps/lld/test/ELF/linkerscript/dynamic-sym.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: echo "_DYNAMIC = 0x123;" > %t.script |
| 4 | 4 | # RUN: ld.lld -T %t.script %t.o -shared -o %t.so |
| 5 | # RUN: llvm-readobj -t %t.so | FileCheck %s | |
| 5 | # RUN: llvm-readobj --symbols %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: Symbol { |
| 8 | 8 | # CHECK: Name: _DYNAMIC |
deps/lld/test/ELF/linkerscript/dynamic.s+1-1| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | |
| 6 | 6 | # RUN: echo "SECTIONS { }" > %t.script |
| 7 | 7 | # RUN: ld.lld %t1.o %t2.so -o %t |
| 8 | # RUN: llvm-readobj -dynamic-table %t | FileCheck %s | |
| 8 | # RUN: llvm-readobj --dynamic-table %t | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | # CHECK: DynamicSection [ |
| 11 | 11 | # CHECK-NEXT: Tag Type Name/Value |
deps/lld/test/ELF/linkerscript/eh-frame-merge.s created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 3 | # RUN: echo "SECTIONS { .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame) } }" > %t.script | |
| 4 | # RUN: ld.lld -o %t --no-threads --eh-frame-hdr --script %t.script %t.o | |
| 5 | # RUN: llvm-readobj -S -u %t | FileCheck %s | |
| 6 | ||
| 7 | # CHECK: Name: .dah | |
| 8 | # CHECK-NOT: Section | |
| 9 | # CHECK: Address: 0x4D | |
| 10 | ||
| 11 | # CHECK: initial_location: 0x4d | |
| 12 | ||
| 13 | .global _start | |
| 14 | _start: | |
| 15 | nop | |
| 16 | ||
| 17 | .section .dah,"ax",@progbits | |
| 18 | .cfi_startproc | |
| 19 | nop | |
| 20 | .cfi_endproc |
deps/lld/test/ELF/linkerscript/ehdr_start.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 4 | 4 | # RUN: echo "SECTIONS { }" > %t.script |
| 5 | 5 | # RUN: ld.lld %t.o -script %t.script -o %t |
| 6 | # RUN: llvm-readobj -symbols %t | FileCheck %s | |
| 6 | # RUN: llvm-readobj --symbols %t | FileCheck %s | |
| 7 | 7 | # CHECK: Name: __ehdr_start (1) |
| 8 | 8 | # CHECK-NEXT: Value: 0x0 |
| 9 | 9 | # CHECK-NEXT: Size: 0 |
deps/lld/test/ELF/linkerscript/emit-reloc.s+2-2| ... | ... | @@ -9,9 +9,9 @@ |
| 9 | 9 | |
| 10 | 10 | # CHECK: Relocations [ |
| 11 | 11 | # CHECK-NEXT: Section ({{.*}}) .rela.dyn { |
| 12 | # CHECK-NEXT: 0x68 R_X86_64_64 .foo 0x0 | |
| 12 | # CHECK-NEXT: 0xF8 R_X86_64_64 .foo 0x0 | |
| 13 | 13 | # CHECK-NEXT: } |
| 14 | 14 | # CHECK-NEXT: Section ({{.*}}) .rela.data { |
| 15 | # CHECK-NEXT: 0x68 R_X86_64_64 .foo 0x0 | |
| 15 | # CHECK-NEXT: 0xF8 R_X86_64_64 .foo 0x0 | |
| 16 | 16 | # CHECK-NEXT: } |
| 17 | 17 | # CHECK-NEXT: ] |
deps/lld/test/ELF/linkerscript/empty-link-order.test+1-1| ... | ... | @@ -11,7 +11,7 @@ SECTIONS { |
| 11 | 11 | # RUN: ld.lld %t.o -o %t --script %s |
| 12 | 12 | |
| 13 | 13 | ## Check we do not crash and do not set SHF_LINK_ORDER flag for .foo |
| 14 | # RUN: llvm-readobj -s %t | FileCheck %s | |
| 14 | # RUN: llvm-readobj -S %t | FileCheck %s | |
| 15 | 15 | # CHECK: Section { |
| 16 | 16 | # CHECK: Index: |
| 17 | 17 | # CHECK: Name: .foo |
deps/lld/test/ELF/linkerscript/empty-relaplt-dyntags.test created+44| ... | ... | @@ -0,0 +1,44 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o | |
| 3 | # RUN: ld.lld -shared %t.o -T %s -o %t | |
| 4 | # RUN: llvm-readobj --dynamic-table --sections %t | FileCheck %s | |
| 5 | ||
| 6 | ## In spite of .rela.plt is empty, it might have been preserved because it is | |
| 7 | ## mentioned in the linker script. However, even in that case, we should not | |
| 8 | ## produce DT_JMPREL and DT_PLTGOT tags because this can cause a dynamic loader | |
| 9 | ## to write into slots in .got.plt it considers reserved to support lazy symbol | |
| 10 | ## resolution. In fact, as .got.plt is also empty, that memory might be | |
| 11 | ## allocated for something else. | |
| 12 | ||
| 13 | # CHECK: Sections [ | |
| 14 | # CHECK: Name: .rela.plt | |
| 15 | # CHECK-NEXT: Type: SHT_RELA | |
| 16 | # CHECK-NEXT: Flags [ | |
| 17 | # CHECK-NEXT: SHF_ALLOC | |
| 18 | # CHECK-NEXT: ] | |
| 19 | # CHECK-NEXT: Address: | |
| 20 | # CHECK-NEXT: Offset: | |
| 21 | # CHECK-NEXT: Size: 0 | |
| 22 | # CHECK: Name: .got.plt | |
| 23 | # CHECK-NEXT: Type: SHT_PROGBITS | |
| 24 | # CHECK-NEXT: Flags [ | |
| 25 | # CHECK-NEXT: SHF_ALLOC | |
| 26 | # CHECK-NEXT: SHF_WRITE | |
| 27 | # CHECK-NEXT: ] | |
| 28 | # CHECK-NEXT: Address: | |
| 29 | # CHECK-NEXT: Offset: | |
| 30 | # CHECK-NEXT: Size: 0 | |
| 31 | ||
| 32 | # CHECK: DynamicSection [ | |
| 33 | # CHECK-NOT: JMPREL | |
| 34 | # CHECK-NOT: PLTGOT | |
| 35 | ||
| 36 | PHDRS { | |
| 37 | all PT_LOAD; | |
| 38 | dyn PT_DYNAMIC; | |
| 39 | } | |
| 40 | SECTIONS { | |
| 41 | .rela.plt : { *(.rela.plt) }: all | |
| 42 | .dynamic : { *(.dynamic) }: all : dyn | |
| 43 | .got.plt : {*(.got.plt)}: all | |
| 44 | } |
deps/lld/test/ELF/linkerscript/empty-section-size.test+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o |
| 3 | 3 | # RUN: ld.lld %t.o --script %s -o %t1 |
| 4 | # RUN: llvm-readobj -symbols %t1 | FileCheck %s | |
| 4 | # RUN: llvm-readobj --symbols %t1 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | ## We had a bug when LLD increased the size of the output section even |
| 7 | 7 | ## if it was empty. That happened because of empty synthetic sections included. |
deps/lld/test/ELF/linkerscript/empty-sections-expressions.test created+24| ... | ... | @@ -0,0 +1,24 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: echo ".text; nop; .data; .byte 0" \ | |
| 3 | # RUN: | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t.o | |
| 4 | # RUN: ld.lld -o %t --script %s %t.o | |
| 5 | # RUN: llvm-readelf -program-headers %t | FileCheck %s | |
| 6 | ||
| 7 | ## Check we do not remove the empty output sections used in LOADADDR/ADDR | |
| 8 | ## expressions and hence can evaluate the correct addresses. | |
| 9 | ||
| 10 | # CHECK: Program Headers: | |
| 11 | # CHECK-NEXT: Type Offset VirtAddr PhysAddr | |
| 12 | # CHECK-NEXT: LOAD 0x001000 0x0000000000080000 0x0000000000080000 | |
| 13 | # CHECK-NEXT: LOAD 0x001001 0x0000000000080001 0x0000000000082000 | |
| 14 | ||
| 15 | # CHECK: Section to Segment mapping: | |
| 16 | # CHECK: 00 .empty .text | |
| 17 | # CHECK-NEXT: 01 .data | |
| 18 | ||
| 19 | SECTIONS { | |
| 20 | . = 0x00080000; | |
| 21 | .empty : { *(.empty ) } | |
| 22 | .text : AT(LOADADDR(.empty) + SIZEOF(.empty)) { *(.text) } | |
| 23 | .data : AT(ADDR(.empty) + 0x2000) { *(.data) } | |
| 24 | } |
deps/lld/test/ELF/linkerscript/empty-synthetic-removed-flags.s+2-2| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 3 | 3 | # RUN: echo "SECTIONS { .foo : { *(.foo) } .bar : { *(.got.plt) BYTE(0x11) }}" > %t.script |
| 4 | 4 | # RUN: ld.lld -o %t --script %t.script %t.o |
| 5 | # RUN: llvm-readobj -s %t | FileCheck %s | |
| 5 | # RUN: llvm-readobj -S %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | ## We have ".got.plt" synthetic section with SHF_ALLOC|SHF_WRITE flags. |
| 8 | 8 | ## It is empty, so linker removes it, but it has to keep ".got.plt" output |
| ... | ... | @@ -21,7 +21,7 @@ |
| 21 | 21 | ## Check flags are not the same if we omit empty synthetic section in script. |
| 22 | 22 | # RUN: echo "SECTIONS { .foo : { *(.foo) } .bar : { BYTE(0x11) }}" > %t.script |
| 23 | 23 | # RUN: ld.lld -o %t --script %t.script %t.o |
| 24 | # RUN: llvm-readobj -s %t | FileCheck --check-prefix=EMPTY %s | |
| 24 | # RUN: llvm-readobj -S %t | FileCheck --check-prefix=EMPTY %s | |
| 25 | 25 | |
| 26 | 26 | # EMPTY: Section { |
| 27 | 27 | # EMPTY: Index: 2 |
deps/lld/test/ELF/linkerscript/entry.s+2-2| ... | ... | @@ -14,7 +14,7 @@ |
| 14 | 14 | # -e has precedence over linker script's ENTRY. |
| 15 | 15 | # RUN: echo "ENTRY(_label)" > %t.script |
| 16 | 16 | # RUN: ld.lld -e _start -o %t2 %t.script %t |
| 17 | # RUN: llvm-readobj -file-headers -symbols %t2 | \ | |
| 17 | # RUN: llvm-readobj --file-headers --symbols %t2 | \ | |
| 18 | 18 | # RUN: FileCheck -check-prefix=OVERLOAD %s |
| 19 | 19 | |
| 20 | 20 | # OVERLOAD: Entry: [[ENTRY:0x[0-9A-F]+]] |
| ... | ... | @@ -24,7 +24,7 @@ |
| 24 | 24 | # The entry symbol can be a linker-script-defined symbol. |
| 25 | 25 | # RUN: echo "ENTRY(foo); foo = 1;" > %t.script |
| 26 | 26 | # RUN: ld.lld -o %t2 %t.script %t |
| 27 | # RUN: llvm-readobj -file-headers -symbols %t2 | \ | |
| 27 | # RUN: llvm-readobj --file-headers --symbols %t2 | \ | |
| 28 | 28 | # RUN: FileCheck -check-prefix=SCRIPT %s |
| 29 | 29 | |
| 30 | 30 | # SCRIPT: Entry: 0x1 |
deps/lld/test/ELF/linkerscript/excludefile.s+3| ... | ... | @@ -10,6 +10,7 @@ |
| 10 | 10 | # RUN: llvm-objdump -d %t | FileCheck %s |
| 11 | 11 | |
| 12 | 12 | # CHECK: Disassembly of section .text: |
| 13 | # CHECK-EMPTY: | |
| 13 | 14 | # CHECK: _start: |
| 14 | 15 | # CHECK-NEXT: : 48 c7 c0 3c 00 00 00 movq $60, %rax |
| 15 | 16 | # CHECK-NEXT: : 48 c7 c7 2a 00 00 00 movq $42, %rdi |
| ... | ... | @@ -30,6 +31,7 @@ |
| 30 | 31 | # RUN: llvm-objdump -d %t4 | FileCheck %s --check-prefix=EXCLUDE |
| 31 | 32 | |
| 32 | 33 | # EXCLUDE: Disassembly of section .patatino: |
| 34 | # EXCLUDE-EMPTY: | |
| 33 | 35 | # EXCLUDE: _start: |
| 34 | 36 | # EXCLUDE-NEXT: : 48 c7 c0 3c 00 00 00 movq $60, %rax |
| 35 | 37 | # EXCLUDE-NEXT: : 48 c7 c7 2a 00 00 00 movq $42, %rdi |
| ... | ... | @@ -39,6 +41,7 @@ |
| 39 | 41 | # EXCLUDE-NEXT: : 90 nop |
| 40 | 42 | # EXCLUDE-NEXT: : 90 nop |
| 41 | 43 | # EXCLUDE: Disassembly of section .text: |
| 44 | # EXCLUDE-EMPTY: | |
| 42 | 45 | # EXCLUDE: tomato: |
| 43 | 46 | # EXCLUDE-NEXT: : b8 01 00 00 00 movl $1, %eax |
| 44 | 47 |
deps/lld/test/ELF/linkerscript/extend-pt-load1.test+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/extend-pt-load.s -o %t.o |
| 3 | 3 | # RUN: ld.lld --hash-style=sysv -o %t1 --script %s %t.o -shared |
| 4 | # RUN: llvm-readobj --elf-output-style=GNU -l -s %t1 | FileCheck %s | |
| 4 | # RUN: llvm-readelf -S -l %t1 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # This test demonstrates an odd consequence of the way we handle sections with just symbol |
| 7 | 7 | # assignments. |
deps/lld/test/ELF/linkerscript/extend-pt-load2.test+3-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/extend-pt-load.s -o %t.o |
| 3 | 3 | # RUN: ld.lld --hash-style=sysv -o %t2 --script %s %t.o -shared |
| 4 | # RUN: llvm-readobj --elf-output-style=GNU -l -s %t2 | FileCheck %s | |
| 4 | # RUN: llvm-readelf -S -l %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # Then add the section bar. Note how bar is given AX flags, which causes the PT_LOAD to now |
| 7 | 7 | # cover the padding bits created by ALIGN. |
| ... | ... | @@ -17,8 +17,8 @@ SECTIONS { |
| 17 | 17 | } |
| 18 | 18 | |
| 19 | 19 | # CHECK: .text PROGBITS 00000000000001bc 0001bc 000001 00 AX |
| 20 | # CHECK-NEXT: bar NOBITS 00000000000001bd 0001bd 000e43 00 AX | |
| 20 | # CHECK-NEXT: bar PROGBITS 00000000000001bd 0001bd 000e43 00 AX | |
| 21 | 21 | # CHECK-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA |
| 22 | 22 | |
| 23 | # CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0001bd 0x001000 R E | |
| 23 | # CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x001000 0x001000 R E | |
| 24 | 24 | # CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW |
deps/lld/test/ELF/linkerscript/extend-pt-load3.test+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/extend-pt-load.s -o %t.o |
| 3 | 3 | # RUN: ld.lld --hash-style=sysv -o %t3 --script %s %t.o -shared |
| 4 | # RUN: llvm-readobj --elf-output-style=GNU -l -s %t3 | FileCheck --check-prefix=CHECK %s | |
| 4 | # RUN: llvm-readelf -S -l %t3 | FileCheck --check-prefix=CHECK %s | |
| 5 | 5 | |
| 6 | 6 | # If the current behavior becomes a problem we should consider just moving the commands out |
| 7 | 7 | # of the section. That is, handle the above like the following test. |
deps/lld/test/ELF/linkerscript/fill.test+6-1| ... | ... | @@ -7,14 +7,19 @@ SECTIONS { |
| 7 | 7 | .out : { |
| 8 | 8 | FILL(0x11111111) |
| 9 | 9 | . += 2; |
| 10 | FILL(0x10101010) | |
| 10 | 11 | *(.aaa) |
| 11 | 12 | . += 4; |
| 12 | 13 | *(.bbb) |
| 13 | 14 | . += 4; |
| 14 | FILL(0x22222222); | |
| 15 | FILL(0x22220000 + 0x2222); | |
| 15 | 16 | . += 4; |
| 16 | 17 | } |
| 17 | 18 | } |
| 18 | 19 | |
| 19 | 20 | # CHECK: Contents of section .out: |
| 20 | 21 | # CHECK-NEXT: 2222aa22 222222bb 22222222 22222222 |
| 22 | ||
| 23 | # RUN: echo 'SECTIONS { .out : { FILL 0x11111111 } }' > %t.script | |
| 24 | # RUN: not ld.lld -o /dev/null --script %t.script 2>&1 | FileCheck %s --check-prefix=ERR | |
| 25 | # ERR: ( expected, but got 0x11111111 |
deps/lld/test/ELF/linkerscript/header-addr.test+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o |
| 3 | 3 | # RUN: ld.lld --hash-style=sysv -o %t.so --script %s %t.o -shared |
| 4 | # RUN: llvm-readobj -program-headers %t.so | FileCheck %s | |
| 4 | # RUN: llvm-readobj -l %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | PHDRS { all PT_LOAD PHDRS; } |
| 7 | 7 | |
| ... | ... | @@ -28,7 +28,7 @@ SECTIONS { |
| 28 | 28 | # CHECK-NEXT: ] |
| 29 | 29 | |
| 30 | 30 | # RUN: ld.lld --hash-style=sysv -o %t2.so --script %s %t.o -shared -z max-page-size=0x2000 |
| 31 | # RUN: llvm-readobj -program-headers %t2.so \ | |
| 31 | # RUN: llvm-readobj -l %t2.so \ | |
| 32 | 32 | # RUN: | FileCheck --check-prefix=MAXPAGE %s |
| 33 | 33 | |
| 34 | 34 | # MAXPAGE: ProgramHeaders [ |
deps/lld/test/ELF/linkerscript/header-phdr.test+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: echo '.section .zed, "a"; .zero 4' \ |
| 3 | 3 | # RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o |
| 4 | 4 | # RUN: ld.lld --script %s %t.o -o %t |
| 5 | # RUN: llvm-readelf -l -S -W %t | FileCheck %s | |
| 5 | # RUN: llvm-readelf -S -l -W %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: [ 1] .abc PROGBITS 0000000000001000 001000 000004 00 A 0 0 1 |
| 8 | 8 | # CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x001004 0x001004 R E 0x1000 |
deps/lld/test/ELF/linkerscript/info-section-type.s+9-5| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | |
| 7 | 7 | # RUN: echo "SECTIONS { .bar : { *(.foo) } };" > %t.script |
| 8 | 8 | # RUN: ld.lld -o %t --script %t.script %t.o |
| 9 | # RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=DEFAULT | |
| 9 | # RUN: llvm-readobj --sections %t | FileCheck %s --check-prefix=DEFAULT | |
| 10 | 10 | # DEFAULT: Name: .bar |
| 11 | 11 | # DEFAULT: Type: SHT_PROGBITS |
| 12 | 12 | # DEFAULT-NEXT: Flags [ |
| ... | ... | @@ -15,7 +15,7 @@ |
| 15 | 15 | |
| 16 | 16 | # RUN: echo "SECTIONS { .bar (COPY) : { *(.foo) } };" > %t.script |
| 17 | 17 | # RUN: ld.lld -o %t --script %t.script %t.o |
| 18 | # RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=NONALLOC | |
| 18 | # RUN: llvm-readobj --sections %t | FileCheck %s --check-prefix=NONALLOC | |
| 19 | 19 | # NONALLOC: Name: .bar |
| 20 | 20 | # NONALLOC: Type: SHT_PROGBITS |
| 21 | 21 | # NONALLOC-NEXT: Flags [ |
| ... | ... | @@ -23,15 +23,19 @@ |
| 23 | 23 | |
| 24 | 24 | # RUN: echo "SECTIONS { .bar (INFO) : { *(.foo) } };" > %t.script |
| 25 | 25 | # RUN: ld.lld -o %t --script %t.script %t.o |
| 26 | # RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=NONALLOC | |
| 26 | # RUN: llvm-readobj --sections %t | FileCheck %s --check-prefix=NONALLOC | |
| 27 | 27 | |
| 28 | 28 | # RUN: echo "SECTIONS { .bar (OVERLAY) : { *(.foo) } };" > %t.script |
| 29 | 29 | # RUN: ld.lld -o %t --script %t.script %t.o |
| 30 | # RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=NONALLOC | |
| 30 | # RUN: llvm-readobj --sections %t | FileCheck %s --check-prefix=NONALLOC | |
| 31 | ||
| 32 | # RUN: echo "SECTIONS { .bar (INFO) : { . += 1; } };" > %t.script | |
| 33 | # RUN: ld.lld -o %t --script %t.script %t.o | |
| 34 | # RUN: llvm-readobj --sections %t | FileCheck %s --check-prefix=NONALLOC | |
| 31 | 35 | |
| 32 | 36 | # RUN: echo "SECTIONS { .bar 0x20000 (INFO) : { *(.foo) } };" > %t.script |
| 33 | 37 | # RUN: ld.lld -o %t --script %t.script %t.o |
| 34 | # RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=NONALLOC | |
| 38 | # RUN: llvm-readobj --sections %t | FileCheck %s --check-prefix=NONALLOC | |
| 35 | 39 | |
| 36 | 40 | # RUN: echo "SECTIONS { .bar 0x20000 (BAR) : { *(.foo) } };" > %t.script |
| 37 | 41 | # RUN: not ld.lld -o %t --script %t.script %t.o 2>&1 |\ |
deps/lld/test/ELF/linkerscript/insert-after.test+1-1| ... | ... | @@ -16,7 +16,7 @@ SECTIONS { |
| 16 | 16 | # RUN: ld.lld %t1.o -o %t1 --script %p/Inputs/insert-after.script --script %s |
| 17 | 17 | # RUN: llvm-objdump -section-headers %t1 | FileCheck %s |
| 18 | 18 | # CHECK: Sections: |
| 19 | # CHECK-NEXT: Idx Name Size Address Type | |
| 19 | # CHECK-NEXT: Idx Name Size VMA Type | |
| 20 | 20 | # CHECK-NEXT: 0 00000000 0000000000000000 |
| 21 | 21 | # CHECK-NEXT: 1 .text 00000008 0000000000000000 TEXT |
| 22 | 22 | # CHECK-NEXT: 2 .foo.text 00000008 0000000000000008 TEXT |
deps/lld/test/ELF/linkerscript/insert-before.test+1-1| ... | ... | @@ -16,7 +16,7 @@ SECTIONS { |
| 16 | 16 | # RUN: ld.lld %t1.o -o %t1 --script %p/Inputs/insert-after.script --script %s |
| 17 | 17 | # RUN: llvm-objdump -section-headers %t1 | FileCheck %s |
| 18 | 18 | # CHECK: Sections: |
| 19 | # CHECK-NEXT: Idx Name Size Address Type | |
| 19 | # CHECK-NEXT: Idx Name Size VMA Type | |
| 20 | 20 | # CHECK-NEXT: 0 00000000 0000000000000000 |
| 21 | 21 | # CHECK-NEXT: 1 .foo.text 00000008 0000000000000000 TEXT |
| 22 | 22 | # CHECK-NEXT: 2 .text 00000008 0000000000000008 TEXT |
deps/lld/test/ELF/linkerscript/lazy-symbols.test+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: llvm-ar rcs %tar %t1 |
| 5 | 5 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t2 |
| 6 | 6 | # RUN: ld.lld %t2 %tar --script %s -o %tout |
| 7 | # RUN: llvm-readobj -symbols %tout | FileCheck %s | |
| 7 | # RUN: llvm-readobj --symbols %tout | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | foo = 1; |
| 10 | 10 |
deps/lld/test/ELF/linkerscript/linkerscript.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ |
| 4 | 4 | # RUN: %p/Inputs/libsearch-st.s -o %t2.o |
| 5 | 5 | |
| 6 | # RUN: echo "EXTERN( undef undef2 )" > %t.script | |
| 6 | # RUN: echo "EXTERN( undef undef2 \"undef3\" \"undef4@@other\")" > %t.script | |
| 7 | 7 | # RUN: ld.lld %t -o %t2 %t.script |
| 8 | 8 | # RUN: llvm-readobj %t2 > /dev/null |
| 9 | 9 |
deps/lld/test/ELF/linkerscript/locationcountererr2.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: echo ". = 0x150; . = 0x10; .text : {} }" >> %t.script |
| 5 | 5 | # RUN: ld.lld %t.o --script %t.script -o %t -shared |
| 6 | 6 | # RUN: llvm-objdump -section-headers %t | FileCheck %s |
| 7 | # CHECK: Name Size Address | |
| 7 | # CHECK: Name Size VMA | |
| 8 | 8 | # CHECK: .text 00000000 0000000000000010 |
| 9 | 9 | |
| 10 | 10 | # RUN: echo "SECTIONS { . = 0x20; . = ASSERT(0x1, "foo"); }" > %t2.script |
deps/lld/test/ELF/linkerscript/memory-at.test+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: echo '.section .data,"aw"; .quad 0' >> %t.s |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t |
| 5 | 5 | # RUN: ld.lld %t --script %s -o %t2 |
| 6 | # RUN: llvm-readobj -program-headers %t2 | FileCheck %s | |
| 6 | # RUN: llvm-readobj -l %t2 | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | MEMORY { |
| 9 | 9 | FLASH (rx) : ORIGIN = 0x1000, LENGTH = 0x100 |
deps/lld/test/ELF/linkerscript/memory-region-alignment.test+1-1| ... | ... | @@ -17,7 +17,7 @@ SECTIONS { |
| 17 | 17 | } |
| 18 | 18 | |
| 19 | 19 | # RUN: ld.lld %t.o -o %t --script %s |
| 20 | # RUN: llvm-readobj -sections %t | FileCheck %s | |
| 20 | # RUN: llvm-readobj --sections %t | FileCheck %s | |
| 21 | 21 | |
| 22 | 22 | # CHECK: Name: .foo |
| 23 | 23 | # CHECK-NEXT: Type: SHT_PROGBITS |
deps/lld/test/ELF/linkerscript/memory3.s+1-1| ... | ... | @@ -14,7 +14,7 @@ |
| 14 | 14 | |
| 15 | 15 | ## Check we place .text into first defined memory region with appropriate flags. |
| 16 | 16 | # CHECK: Sections: |
| 17 | # CHECK: Idx Name Size Address | |
| 17 | # CHECK: Idx Name Size VMA | |
| 18 | 18 | # CHECK: 0 00000000 0000000000000000 |
| 19 | 19 | # CHECK: 1 .text 00000001 0000000000001000 |
| 20 | 20 |
deps/lld/test/ELF/linkerscript/memory5.test+2-2| ... | ... | @@ -5,9 +5,9 @@ |
| 5 | 5 | # RUN: llvm-objdump -section-headers %t.so | FileCheck %s |
| 6 | 6 | |
| 7 | 7 | # CHECK: 1 .text 00000001 0000000000042000 |
| 8 | # CHECK-NEXT: 2 .data 00000001 0000000000044001 | |
| 8 | # CHECK-NEXT: 2 .data 00000001 0000000000042001 | |
| 9 | 9 | |
| 10 | ## Test that assign to Dot changes the position in a memory region. | |
| 10 | ## Test that assigning to Dot does not change the position in a memory region. | |
| 11 | 11 | |
| 12 | 12 | MEMORY { |
| 13 | 13 | ram (wxa) : ORIGIN = 0x42000, LENGTH = 0x100000 |
deps/lld/test/ELF/linkerscript/merge-sections.s+3-3| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | # RUN: .foo : { begin = .; *(.foo.*) end = .;} \ |
| 7 | 7 | # RUN: }" > %t.script |
| 8 | 8 | # RUN: ld.lld -o %t1 --script %t.script %t -shared |
| 9 | # RUN: llvm-readobj -s -t %t1 | FileCheck %s | |
| 9 | # RUN: llvm-readobj -S --symbols %t1 | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | # CHECK: Name: .foo |
| 12 | 12 | # CHECK-NEXT: Type: SHT_PROGBITS |
| ... | ... | @@ -32,10 +32,10 @@ |
| 32 | 32 | |
| 33 | 33 | # Check that we don't crash with --gc-sections |
| 34 | 34 | # RUN: ld.lld --gc-sections -o %t2 --script %t.script %t -shared |
| 35 | # RUN: llvm-readobj -s -t %t2 | FileCheck %s --check-prefix=GC | |
| 35 | # RUN: llvm-readobj -S --symbols %t2 | FileCheck %s --check-prefix=GC | |
| 36 | 36 | |
| 37 | 37 | # GC: Name: .foo |
| 38 | # GC-NEXT: Type: SHT_NOBITS | |
| 38 | # GC-NEXT: Type: SHT_PROGBITS | |
| 39 | 39 | # GC-NEXT: Flags [ |
| 40 | 40 | # GC-NEXT: SHF_ALLOC |
| 41 | 41 | # GC-NEXT: ] |
deps/lld/test/ELF/linkerscript/multi-sections-constraint.s+2-2| ... | ... | @@ -8,7 +8,7 @@ |
| 8 | 8 | # RUN: llvm-objdump -section-headers %t1 | FileCheck %s |
| 9 | 9 | |
| 10 | 10 | # CHECK: Sections: |
| 11 | # CHECK-NEXT: Idx Name Size Address Type | |
| 11 | # CHECK-NEXT: Idx Name Size VMA Type | |
| 12 | 12 | # CHECK: .aaa 00000010 0000000000002000 DATA |
| 13 | 13 | |
| 14 | 14 | |
| ... | ... | @@ -20,7 +20,7 @@ |
| 20 | 20 | # RUN: llvm-objdump -section-headers %t2 | FileCheck %s --check-prefix=REV |
| 21 | 21 | |
| 22 | 22 | # REV: Sections: |
| 23 | # REV-NEXT: Idx Name Size Address Type | |
| 23 | # REV-NEXT: Idx Name Size VMA Type | |
| 24 | 24 | # REV: .aaa 00000010 0000000000001000 DATA |
| 25 | 25 | |
| 26 | 26 | .global _start |
deps/lld/test/ELF/linkerscript/multiple-tbss.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: echo "SECTIONS { }" > %t.script |
| 4 | 4 | # RUN: ld.lld -T %t.script %t.o -o %t |
| 5 | # RUN: llvm-readobj -l -s %t | FileCheck %s | |
| 5 | # RUN: llvm-readobj -S -l %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: Name: .tbss |
| 8 | 8 | # CHECK-NEXT: Type: SHT_NOBITS |
deps/lld/test/ELF/linkerscript/nmagic-alignment.test created+85| ... | ... | @@ -0,0 +1,85 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # Test that mimics a use case of -n to produce a kernel mapped shared-object | |
| 4 | # in a non paged context. We specifically want to test: | |
| 5 | # - We can allocate the headers into the first program header (via PHDRS) | |
| 6 | # typically -n does not allocate headers. | |
| 7 | # - The alignment of the .text section is not page aligned. | |
| 8 | ||
| 9 | # RUN: echo ".text; .globl foo; foo: nop" > %t.s | |
| 10 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t.s -o %t.o | |
| 11 | # RUN: ld.lld %t.o -o %t.so --shared --hash-style=sysv --script %s | |
| 12 | # RUN: llvm-readobj --program-headers %t.so | FileCheck %s | |
| 13 | # RUN: ld.lld %t.o -o %t2.so --shared --hash-style=sysv -n --script %s | |
| 14 | # RUN: llvm-readobj --program-headers %t2.so | FileCheck %s --check-prefix=CHECK-N | |
| 15 | ||
| 16 | SECTIONS { | |
| 17 | . = 0x0 + SIZEOF_HEADERS; | |
| 18 | .hash : { *(.hash) } :text | |
| 19 | .dynsym : { *(.dynsym) } | |
| 20 | .dynstr : { *(.dynstr) } | |
| 21 | . = ALIGN(4); | |
| 22 | .text : { *(.text*) } | |
| 23 | .dynamic : { *(.dynamic) } :text :dynamic | |
| 24 | } | |
| 25 | ||
| 26 | PHDRS { | |
| 27 | text PT_LOAD FLAGS(5) FILEHDR PHDRS; | |
| 28 | dynamic PT_DYNAMIC FLAGS(4); | |
| 29 | } | |
| 30 | ||
| 31 | # CHECK: ProgramHeaders [ | |
| 32 | # CHECK-NEXT: ProgramHeader { | |
| 33 | # CHECK-NEXT: Type: PT_LOAD | |
| 34 | # CHECK-NEXT: Offset: 0x0 | |
| 35 | # CHECK-NEXT: VirtualAddress: 0x0 | |
| 36 | # CHECK-NEXT: PhysicalAddress: 0x0 | |
| 37 | # CHECK-NEXT: FileSize: | |
| 38 | # CHECK-NEXT: MemSize: | |
| 39 | # CHECK-NEXT: Flags [ | |
| 40 | # CHECK-NEXT: PF_R | |
| 41 | # CHECK-NEXT: PF_X | |
| 42 | # CHECK-NEXT: ] | |
| 43 | # CHECK-NEXT: Alignment: 4096 | |
| 44 | # CHECK-NEXT: } | |
| 45 | # CHECK-NEXT: ProgramHeader { | |
| 46 | # CHECK-NEXT: Type: PT_DYNAMIC | |
| 47 | # CHECK-NEXT: Offset: 0x108 | |
| 48 | # CHECK-NEXT: VirtualAddress: 0x108 | |
| 49 | # CHECK-NEXT: PhysicalAddress: 0x108 | |
| 50 | # CHECK-NEXT: FileSize: | |
| 51 | # CHECK-NEXT: MemSize: | |
| 52 | # CHECK-NEXT: Flags [ | |
| 53 | # CHECK-NEXT: PF_R | |
| 54 | # CHECK-NEXT: ] | |
| 55 | # CHECK-NEXT: Alignment: 8 | |
| 56 | # CHECK-NEXT: } | |
| 57 | # CHECK-NEXT: ] | |
| 58 | ||
| 59 | # CHECK-N: ProgramHeaders [ | |
| 60 | # CHECK-N-NEXT: ProgramHeader { | |
| 61 | # CHECK-N-NEXT: Type: PT_LOAD | |
| 62 | # CHECK-N-NEXT: Offset: 0x0 | |
| 63 | # CHECK-N-NEXT: VirtualAddress: 0x0 | |
| 64 | # CHECK-N-NEXT: PhysicalAddress: 0x0 | |
| 65 | # CHECK-N-NEXT: FileSize: 360 | |
| 66 | # CHECK-N-NEXT: MemSize: 360 | |
| 67 | # CHECK-N-NEXT: Flags [ | |
| 68 | # CHECK-N-NEXT: PF_R | |
| 69 | # CHECK-N-NEXT: PF_X | |
| 70 | # CHECK-N-NEXT: ] | |
| 71 | # CHECK-N-NEXT: Alignment: 8 | |
| 72 | # CHECK-N-NEXT: } | |
| 73 | # CHECK-N-NEXT: ProgramHeader { | |
| 74 | # CHECK-N-NEXT: Type: PT_DYNAMIC | |
| 75 | # CHECK-N-NEXT: Offset: 0x108 | |
| 76 | # CHECK-N-NEXT: VirtualAddress: 0x108 | |
| 77 | # CHECK-N-NEXT: PhysicalAddress: 0x108 | |
| 78 | # CHECK-N-NEXT: FileSize: | |
| 79 | # CHECK-N-NEXT: MemSize: | |
| 80 | # CHECK-N-NEXT: Flags [ | |
| 81 | # CHECK-N-NEXT: PF_R | |
| 82 | # CHECK-N-NEXT: ] | |
| 83 | # CHECK-N-NEXT: Alignment: 8 | |
| 84 | # CHECK-N-NEXT: } | |
| 85 | # CHECK-N-NEXT: ] |
deps/lld/test/ELF/linkerscript/noload.s+1-1| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | # RUN: .data_noload_b (0x10000) (NOLOAD) : { *(.data_noload_b) } \ |
| 6 | 6 | # RUN: .text (0x20000) : { *(.text) } };" > %t.script |
| 7 | 7 | # RUN: ld.lld -o %t --script %t.script %t.o |
| 8 | # RUN: llvm-readobj -sections -program-headers %t | FileCheck %s | |
| 8 | # RUN: llvm-readobj --sections -l %t | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | # CHECK: Section { |
| 11 | 11 | # CHECK: Index: 1 |
deps/lld/test/ELF/linkerscript/non-absolute.s+2-1| ... | ... | @@ -3,11 +3,12 @@ |
| 3 | 3 | # RUN: echo "SECTIONS { A = . - 0x10; B = A + 0x1; }" > %t.script |
| 4 | 4 | # RUN: ld.lld -shared %t1.o --script %t.script -o %t |
| 5 | 5 | # RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=DUMP |
| 6 | # RUN: llvm-readobj -t %t | FileCheck %s --check-prefix=SYMBOL | |
| 6 | # RUN: llvm-readobj --symbols %t | FileCheck %s --check-prefix=SYMBOL | |
| 7 | 7 | |
| 8 | 8 | # B = A + 0x1 = -0x10 + 0x1 = -0xf -> 0xFFFFFFFFFFFFFFF1 |
| 9 | 9 | # B - (0x94+6) = -0xf - (0x94+6) = -169 |
| 10 | 10 | # DUMP: Disassembly of section .text: |
| 11 | # DUMP-EMPTY: | |
| 11 | 12 | # DUMP-NEXT: foo: |
| 12 | 13 | # DUMP-NEXT: 94: {{.*}} -169(%rip), %eax |
| 13 | 14 |
deps/lld/test/ELF/linkerscript/non-absolute2.test+1-1| ... | ... | @@ -9,7 +9,7 @@ SECTIONS { |
| 9 | 9 | } |
| 10 | 10 | |
| 11 | 11 | # CHECK: Sections: |
| 12 | # CHECK-NEXT: Idx Name Size Address | |
| 12 | # CHECK-NEXT: Idx Name Size VMA | |
| 13 | 13 | # CHECK-NEXT: 0 00000000 0000000000000000 |
| 14 | 14 | # CHECK-NEXT: 1 .dynsym 00000030 0000000000001000 |
| 15 | 15 | # CHECK: 5 .text 00000000 000000000000106c |
deps/lld/test/ELF/linkerscript/numbers.s+2-2| ... | ... | @@ -18,7 +18,7 @@ |
| 18 | 18 | # RUN: llvm-objdump -section-headers %t2 | FileCheck %s |
| 19 | 19 | |
| 20 | 20 | # CHECK: Sections: |
| 21 | # CHECK-NEXT: Idx Name Size Address | |
| 21 | # CHECK-NEXT: Idx Name Size VMA | |
| 22 | 22 | # CHECK-NEXT: 0 00000000 0000000000000000 |
| 23 | 23 | # CHECK-NEXT: 1 .hex1 00000008 0000000000001000 |
| 24 | 24 | # CHECK-NEXT: 2 .hex2 00000008 0000000000001010 |
| ... | ... | @@ -67,7 +67,7 @@ |
| 67 | 67 | # RUN: ld.lld %t --script %t8.script -o %t6 |
| 68 | 68 | # RUN: llvm-objdump -section-headers %t6 | FileCheck -check-prefix=SECADDR %s |
| 69 | 69 | # SECADDR: Sections: |
| 70 | # SECADDR-NEXT: Idx Name Size Address | |
| 70 | # SECADDR-NEXT: Idx Name Size VMA | |
| 71 | 71 | # SECADDR-NEXT: 0 00000000 0000000000000000 |
| 72 | 72 | # SECADDR-NEXT: 1 .hex1 00000008 0000000000000400 |
| 73 | 73 | # SECADDR-NEXT: 2 .hex2 00000008 0000000000000500 |
deps/lld/test/ELF/linkerscript/obj-symbol-value.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: echo "SECTIONS { foo = bar; .bar : { *(.bar*) } }" > %t.script |
| 4 | 4 | # RUN: ld.lld %t.o --script %t.script -o %t.so -shared |
| 5 | # RUN: llvm-readobj -t %t.so | FileCheck %s | |
| 5 | # RUN: llvm-readobj --symbols %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: Symbol { |
| 8 | 8 | # CHECK: Name: bar |
deps/lld/test/ELF/linkerscript/openbsd-bootdata.test+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux /dev/null -o %t.o |
| 3 | 3 | # RUN: ld.lld --script %s %t.o -o %t |
| 4 | # RUN: llvm-readobj --program-headers -s %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj --program-headers -S %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | PHDRS { boot PT_OPENBSD_BOOTDATA; } |
| 7 | 7 |
deps/lld/test/ELF/linkerscript/openbsd-randomize.s+1-1| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | # RUN: .text : { *(.text) } \ |
| 6 | 6 | # RUN: .openbsd.randomdata : { *(.openbsd.randomdata) } : rand }" > %t.script |
| 7 | 7 | # RUN: ld.lld --script %t.script %t.o -o %t |
| 8 | # RUN: llvm-readobj --program-headers -s %t | FileCheck %s | |
| 8 | # RUN: llvm-readobj --program-headers -S %t | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | # CHECK: ProgramHeader { |
| 11 | 11 | # CHECK: Type: PT_OPENBSD_RANDOMIZE (0x65A3DBE6) |
deps/lld/test/ELF/linkerscript/orphan-first-cmd.test+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: echo '.section .bar, "aw"' \ |
| 3 | 3 | # RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o |
| 4 | 4 | # RUN: ld.lld -o %t -T %s %t.o -shared |
| 5 | # RUN: llvm-readobj -s %t | FileCheck %s | |
| 5 | # RUN: llvm-readobj -S %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | SECTIONS { |
| 8 | 8 | foo = 123; |
deps/lld/test/ELF/linkerscript/orphan-live-only.s created+42| ... | ... | @@ -0,0 +1,42 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 3 | # RUN: echo "PHDRS { \ | |
| 4 | # RUN: exec PT_LOAD FLAGS(0x4 | 0x1); \ | |
| 5 | # RUN: ro PT_LOAD FLAGS(0x4); \ | |
| 6 | # RUN: } \ | |
| 7 | # RUN: SECTIONS { \ | |
| 8 | # RUN: .pad : { QUAD(0); } :exec \ | |
| 9 | # RUN: .text : { *(.text) } \ | |
| 10 | # RUN: .ro : { *(.ro) } :ro \ | |
| 11 | # RUN: }" > %t.script | |
| 12 | # RUN: ld.lld -o %t --script %t.script %t.o | |
| 13 | # RUN: llvm-readelf -S -l %t | FileCheck %s | |
| 14 | ||
| 15 | ## The ".pad" section is not "live" and should be ignored by the | |
| 16 | ## orphan placement. | |
| 17 | ## | |
| 18 | ## Check that the orphan section is placed correctly and belongs to | |
| 19 | ## the correct segment. | |
| 20 | ||
| 21 | # CHECK: Section Headers | |
| 22 | # CHECK: .pad | |
| 23 | # CHECK-NEXT: .text | |
| 24 | # CHECK-NEXT: .orphan2 | |
| 25 | # CHECK-NEXT: .ro | |
| 26 | # CHECK-NEXT: .orphan1 | |
| 27 | ||
| 28 | # CHECK: Segment Sections | |
| 29 | # CHECK-NEXT: .pad .text .orphan2 | |
| 30 | # CHECK-NEXT: .ro .orphan1 | |
| 31 | ||
| 32 | .section .text,"ax" | |
| 33 | ret | |
| 34 | ||
| 35 | .section .ro,"a" | |
| 36 | .byte 0 | |
| 37 | ||
| 38 | .section .orphan1,"a" | |
| 39 | .byte 0 | |
| 40 | ||
| 41 | .section .orphan2,"ax" | |
| 42 | ret |
deps/lld/test/ELF/linkerscript/orphan-phdrs.s+4-4| ... | ... | @@ -23,13 +23,13 @@ |
| 23 | 23 | |
| 24 | 24 | # CHECK: Segment Sections |
| 25 | 25 | # CHECK-NEXT: .text .orphan |
| 26 | # CHECK-NEXT: .rw | |
| 26 | # CHECK-NEXT: .empty .rw | |
| 27 | 27 | |
| 28 | .section .text, "ax" | |
| 28 | .section .text,"ax" | |
| 29 | 29 | ret |
| 30 | 30 | |
| 31 | .section .rw, "aw" | |
| 31 | .section .rw,"aw" | |
| 32 | 32 | .quad 0 |
| 33 | 33 | |
| 34 | .section .orphan, "ax" | |
| 34 | .section .orphan,"ax" | |
| 35 | 35 | ret |
deps/lld/test/ELF/linkerscript/orphan-report.s+2-2| ... | ... | @@ -27,6 +27,7 @@ |
| 27 | 27 | # REPORT-NEXT: <internal>:(.dynamic) is being placed in '.dynamic' |
| 28 | 28 | # REPORT-NEXT: <internal>:(.dynstr) is being placed in '.dynstr' |
| 29 | 29 | # REPORT-NEXT: <internal>:(.rela.dyn) is being placed in '.rela.dyn' |
| 30 | # REPORT-NEXT: <internal>:(.eh_frame) is being placed in '.eh_frame' | |
| 30 | 31 | # REPORT-NEXT: <internal>:(.got) is being placed in '.got' |
| 31 | 32 | # REPORT-NEXT: <internal>:(.got.plt) is being placed in '.got.plt' |
| 32 | 33 | # REPORT-NEXT: <internal>:(.got.plt) is being placed in '.got.plt' |
| ... | ... | @@ -34,9 +35,8 @@ |
| 34 | 35 | # REPORT-NEXT: <internal>:(.rela.plt) is being placed in '.rela.plt' |
| 35 | 36 | # REPORT-NEXT: <internal>:(.plt) is being placed in '.plt' |
| 36 | 37 | # REPORT-NEXT: <internal>:(.plt) is being placed in '.plt' |
| 37 | # REPORT-NEXT: <internal>:(.eh_frame) is being placed in '.eh_frame' | |
| 38 | 38 | # REPORT-NEXT: <internal>:(.symtab) is being placed in '.symtab' |
| 39 | # REPORT-NEXT: <internal>:(.symtab_shndxr) is being placed in '.symtab_shndxr' | |
| 39 | # REPORT-NEXT: <internal>:(.symtab_shndx) is being placed in '.symtab_shndx' | |
| 40 | 40 | # REPORT-NEXT: <internal>:(.shstrtab) is being placed in '.shstrtab' |
| 41 | 41 | # REPORT-NEXT: <internal>:(.strtab) is being placed in '.strtab' |
| 42 | 42 |
deps/lld/test/ELF/linkerscript/orphan.s+5-5| ... | ... | @@ -9,15 +9,15 @@ |
| 9 | 9 | # RUN: ld.lld -o %t1 --script %t.script %t |
| 10 | 10 | # RUN: llvm-objdump -section-headers %t1 | FileCheck %s |
| 11 | 11 | |
| 12 | ## .jcr is a relro section and should be placed after other RW sections. | |
| 12 | ## .jcr is a relro section and should be placed before other RW sections. | |
| 13 | 13 | ## .bss is SHT_NOBITS section and should be last RW section, so some space |
| 14 | 14 | ## in ELF file could be saved. |
| 15 | 15 | # CHECK: 0 00000000 0000000000000000 |
| 16 | 16 | # CHECK-NEXT: 1 .text 00000000 0000000000000000 TEXT |
| 17 | # CHECK-NEXT: 2 .rw1 00000008 0000000000000000 DATA | |
| 18 | # CHECK-NEXT: 3 .rw2 00000008 0000000000000008 DATA | |
| 19 | # CHECK-NEXT: 4 .rw3 00000008 0000000000000010 DATA | |
| 20 | # CHECK-NEXT: 5 .jcr 00000008 0000000000000018 DATA | |
| 17 | # CHECK-NEXT: 2 .jcr 00000008 0000000000000000 DATA | |
| 18 | # CHECK-NEXT: 3 .rw1 00000008 0000000000000008 DATA | |
| 19 | # CHECK-NEXT: 4 .rw2 00000008 0000000000000010 DATA | |
| 20 | # CHECK-NEXT: 5 .rw3 00000008 0000000000000018 DATA | |
| 21 | 21 | # CHECK-NEXT: 6 .bss 00000008 0000000000000020 BSS |
| 22 | 22 | |
| 23 | 23 | .section .rw1, "aw" |
deps/lld/test/ELF/linkerscript/out-of-order-section-in-region.test created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: echo ".section .aaa, \"a\"; .quad 0; .section .bbb, \"a\"; .quad 0;" \ | |
| 4 | # RUN: | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t | |
| 5 | # RUN: ld.lld %t --script %s -o %t2 | |
| 6 | ||
| 7 | # RUN: llvm-objdump -section-headers %t2 | FileCheck %s | |
| 8 | # CHECK: .aaa 00000008 0000000000001008 DATA | |
| 9 | # CHECK: .bbb 00000008 0000000000001000 DATA | |
| 10 | ||
| 11 | MEMORY { | |
| 12 | REGION (rwx) : ORIGIN = 0x1000, LENGTH = 0x100 | |
| 13 | } | |
| 14 | ||
| 15 | SECTIONS { | |
| 16 | .aaa ORIGIN(REGION) + 0x8 : { *(.aaa) } > REGION | |
| 17 | _stext = .; | |
| 18 | .bbb ORIGIN(REGION) : { *(.bbb) } > REGION | |
| 19 | . = _stext; | |
| 20 | } |
deps/lld/test/ELF/linkerscript/out-of-order.s+3-3| ... | ... | @@ -22,10 +22,10 @@ |
| 22 | 22 | # must take responsibility to make sure this does not happen. |
| 23 | 23 | |
| 24 | 24 | # CHECK: Sections: |
| 25 | # CHECK-NEXT: Idx Name Size Address Type | |
| 25 | # CHECK-NEXT: Idx Name Size VMA Type | |
| 26 | 26 | # CHECK-NEXT: 0 00000000 0000000000000000 |
| 27 | # CHECK-NEXT: 1 .data 00000008 0000000000004000 | |
| 28 | # CHECK-NEXT: 2 .dynamic 00000060 0000000000004008 | |
| 27 | # CHECK-NEXT: 1 .dynamic 00000060 0000000000000000 | |
| 28 | # CHECK-NEXT: 2 .data 00000008 0000000000004000 | |
| 29 | 29 | # CHECK-NEXT: 3 .dynsym 00000018 0000000000002000 |
| 30 | 30 | # CHECK-NEXT: 4 .dynstr 00000001 0000000000002018 |
| 31 | 31 | # CHECK-NEXT: 5 .hash 00000010 000000000000201c |
deps/lld/test/ELF/linkerscript/output-too-large-32bit.s created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | # REQUIRES: x86 && !llvm-64-bits | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 4 | # RUN: echo "SECTIONS { .text : { . = 0x6fffffffffffffff; *(.text*); } }" > %t.script | |
| 5 | # RUN: not ld.lld --no-check-sections --script %t.script %t.o -o /dev/null 2>&1 | FileCheck %s | |
| 6 | ||
| 7 | # CHECK: output file too large | |
| 8 | ||
| 9 | .global _start | |
| 10 | _start: | |
| 11 | nop |
deps/lld/test/ELF/linkerscript/outsections-addr.s+1-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: .ddd 0x5001 : { *(.ddd) } \ |
| 8 | 8 | # RUN: }" > %t.script |
| 9 | 9 | # RUN: ld.lld %t --script %t.script -o %tout |
| 10 | # RUN: llvm-readobj -s %tout | FileCheck %s | |
| 10 | # RUN: llvm-readobj -S %tout | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | ## Check: |
| 13 | 13 | ## 1) Simple constant as address. |
deps/lld/test/ELF/linkerscript/overlapping-sections.s+11-11| ... | ... | @@ -17,18 +17,18 @@ |
| 17 | 17 | |
| 18 | 18 | # Verify that the .sec2 was indeed placed in a PT_LOAD where the PhysAddr |
| 19 | 19 | # overlaps with where .sec1 is loaded: |
| 20 | # RUN: llvm-readobj -sections -program-headers -elf-output-style=GNU %t.so | FileCheck %s -check-prefix BAD-LMA | |
| 20 | # RUN: llvm-readelf --sections -l %t.so | FileCheck %s -check-prefix BAD-LMA | |
| 21 | 21 | # BAD-LMA-LABEL: Section Headers: |
| 22 | 22 | # BAD-LMA: .sec1 PROGBITS 0000000000008000 002000 000100 00 WA 0 0 1 |
| 23 | 23 | # BAD-LMA: .sec2 PROGBITS 0000000000008800 002800 000100 00 WA 0 0 1 |
| 24 | 24 | # BAD-LMA-LABEL: Program Headers: |
| 25 | 25 | # BAD-LMA-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align |
| 26 | 26 | # BAD-LMA-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x000100 0x000100 R E 0x1000 |
| 27 | # BAD-LMA-NEXT: LOAD 0x001100 0x0000000000000100 0x0000000000000100 0x000070 0x000070 RW 0x1000 | |
| 27 | 28 | # BAD-LMA-NEXT: LOAD 0x002000 0x0000000000008000 0x0000000000008000 0x000100 0x000100 RW 0x1000 |
| 28 | # BAD-LMA-NEXT: LOAD 0x002800 0x0000000000008800 0x0000000000008080 0x000170 0x000170 RW 0x1000 | |
| 29 | 29 | # BAD-LMA-LABEL: Section to Segment mapping: |
| 30 | # BAD-LMA: 01 .sec1 | |
| 31 | # BAD-LMA: 02 .sec2 .dynamic | |
| 30 | # BAD-LMA: 01 .text .dynamic | |
| 31 | # BAD-LMA: 02 .sec1 | |
| 32 | 32 | |
| 33 | 33 | # Now try a script where the virtual memory addresses overlap but ensure that the |
| 34 | 34 | # load addresses don't: |
| ... | ... | @@ -43,18 +43,18 @@ |
| 43 | 43 | |
| 44 | 44 | # Check that the expected binary was created with --noinhibit-exec: |
| 45 | 45 | # RUN: ld.lld -o %t.so --script %t-vaddr.script %t.o -shared --noinhibit-exec |
| 46 | # RUN: llvm-readobj -sections -program-headers -elf-output-style=GNU %t.so | FileCheck %s -check-prefix BAD-VADDR | |
| 46 | # RUN: llvm-readelf --sections -l %t.so | FileCheck %s -check-prefix BAD-VADDR | |
| 47 | 47 | # BAD-VADDR-LABEL: Section Headers: |
| 48 | 48 | # BAD-VADDR: .sec1 PROGBITS 0000000000008000 002000 000100 00 WA 0 0 1 |
| 49 | 49 | # BAD-VADDR: .sec2 PROGBITS 0000000000008020 003020 000100 00 WA 0 0 1 |
| 50 | 50 | # BAD-VADDR-LABEL: Program Headers: |
| 51 | 51 | # BAD-VADDR-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align |
| 52 | 52 | # BAD-VADDR-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x000100 0x000100 R E 0x1000 |
| 53 | # BAD-VADDR-NEXT: LOAD 0x001100 0x0000000000000100 0x0000000000000100 0x000070 0x000070 RW 0x1000 | |
| 53 | 54 | # BAD-VADDR-NEXT: LOAD 0x002000 0x0000000000008000 0x0000000000008000 0x000100 0x000100 RW 0x1000 |
| 54 | # BAD-VADDR-NEXT: LOAD 0x003020 0x0000000000008020 0x0000000000008800 0x000170 0x000170 RW 0x1000 | |
| 55 | 55 | # BAD-VADDR-LABEL: Section to Segment mapping: |
| 56 | # BAD-VADDR: 01 .sec1 | |
| 57 | # BAD-VADDR: 02 .sec2 .dynamic | |
| 56 | # BAD-VADDR: 01 .text .dynamic | |
| 57 | # BAD-VADDR: 02 .sec1 | |
| 58 | 58 | |
| 59 | 59 | # Finally check the case where both LMA and vaddr overlap |
| 60 | 60 | |
| ... | ... | @@ -91,16 +91,16 @@ |
| 91 | 91 | # Starting here the contents of .sec2 overwrites .sec1: |
| 92 | 92 | # BROKEN-OUTPUT-FILE-NEXT: 8040 02020202 02020202 02020202 02020202 |
| 93 | 93 | |
| 94 | # RUN: llvm-readobj -sections -program-headers -elf-output-style=GNU %t.so | FileCheck %s -check-prefix BAD-BOTH | |
| 94 | # RUN: llvm-readelf --sections -l %t.so | FileCheck %s -check-prefix BAD-BOTH | |
| 95 | 95 | # BAD-BOTH-LABEL: Section Headers: |
| 96 | 96 | # BAD-BOTH: .sec1 PROGBITS 0000000000008000 002000 000100 00 WA 0 0 1 |
| 97 | 97 | # BAD-BOTH: .sec2 PROGBITS 0000000000008040 002040 000100 00 WA 0 0 1 |
| 98 | 98 | # BAD-BOTH-LABEL: Program Headers: |
| 99 | 99 | # BAD-BOTH-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align |
| 100 | 100 | # BAD-BOTH-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x000100 0x000100 R E 0x1000 |
| 101 | # BAD-BOTH-NEXT: LOAD 0x002000 0x0000000000008000 0x0000000000008000 0x0001b0 0x0001b0 RW 0x1000 | |
| 101 | # BAD-BOTH-NEXT: LOAD 0x001100 0x0000000000000100 0x0000000000000100 0x000070 0x000070 RW 0x1000 | |
| 102 | 102 | # BAD-BOTH-LABEL: Section to Segment mapping: |
| 103 | # BAD-BOTH: 01 .sec1 .sec2 .dynamic | |
| 103 | # BAD-BOTH: 01 .text .dynamic | |
| 104 | 104 | |
| 105 | 105 | .section .first_sec,"aw",@progbits |
| 106 | 106 | .rept 0x100 |
deps/lld/test/ELF/linkerscript/overlay.test+1-1| ... | ... | @@ -16,7 +16,7 @@ SECTIONS { |
| 16 | 16 | ## .text does not cause overlapping error and that |
| 17 | 17 | ## .text's VA is 0x1000 + max(sizeof(.out.big), sizeof(.out.small)). |
| 18 | 18 | |
| 19 | # RUN: llvm-readobj -sections -program-headers -elf-output-style=GNU %t | FileCheck %s | |
| 19 | # RUN: llvm-readelf --sections -l %t | FileCheck %s | |
| 20 | 20 | |
| 21 | 21 | # CHECK: Section Headers: |
| 22 | 22 | # CHECK: Name Type Address Off Size |
deps/lld/test/ELF/linkerscript/page-size-align.test+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o |
| 3 | 3 | # RUN: ld.lld -T %s -z max-page-size=0x4000 %t.o -o %t.so -shared |
| 4 | # RUN: llvm-readobj -s %t.so | FileCheck %s | |
| 4 | # RUN: llvm-readobj -S %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | SECTIONS { |
| 7 | 7 | . = SIZEOF_HEADERS; |
deps/lld/test/ELF/linkerscript/page-size.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | |
| 4 | 4 | # RUN: ld.lld -z max-page-size=0x4000 %t -o %t2 |
| 5 | # RUN: llvm-readobj -program-headers %t2 | FileCheck %s | |
| 5 | # RUN: llvm-readobj -l %t2 | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: ProgramHeaders [ |
| 8 | 8 | # CHECK: ProgramHeader { |
deps/lld/test/ELF/linkerscript/phdr-check.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | |
| 4 | 4 | # RUN: echo "SECTIONS { . = 0x10000000 + SIZEOF_HEADERS; .text : {*(.text.*)} }" > %t.script |
| 5 | 5 | # RUN: ld.lld -o %t1 --script %t.script %t |
| 6 | # RUN: llvm-readobj -program-headers %t1 | FileCheck %s | |
| 6 | # RUN: llvm-readobj -l %t1 | FileCheck %s | |
| 7 | 7 | # CHECK: ProgramHeaders [ |
| 8 | 8 | # CHECK-NEXT: ProgramHeader { |
| 9 | 9 | # CHECK-NEXT: Type: PT_PHDR (0x6) |
deps/lld/test/ELF/linkerscript/phdrs-flags.s+2-2| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: .foo : {*(.foo.*)} :all \ |
| 8 | 8 | # RUN: .data : {*(.data.*)} :all}" > %t.script |
| 9 | 9 | # RUN: ld.lld -o %t1 --script %t.script %t |
| 10 | # RUN: llvm-readobj -program-headers %t1 | FileCheck %s | |
| 10 | # RUN: llvm-readobj -l %t1 | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | # RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS FLAGS (0x1);} \ |
| 13 | 13 | # RUN: SECTIONS { \ |
| ... | ... | @@ -16,7 +16,7 @@ |
| 16 | 16 | # RUN: .foo : {*(.foo.*)} \ |
| 17 | 17 | # RUN: .data : {*(.data.*)} }" > %t.script |
| 18 | 18 | # RUN: ld.lld -o %t1 --script %t.script %t |
| 19 | # RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=DEFHDR %s | |
| 19 | # RUN: llvm-readobj -l %t1 | FileCheck --check-prefix=DEFHDR %s | |
| 20 | 20 | |
| 21 | 21 | # CHECK: ProgramHeaders [ |
| 22 | 22 | # CHECK-NEXT: ProgramHeader { |
deps/lld/test/ELF/linkerscript/phdrs.s+5-5| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: .foo : {*(.foo.*)} :all \ |
| 8 | 8 | # RUN: .data : {*(.data.*)} :all}" > %t.script |
| 9 | 9 | # RUN: ld.lld -o %t1 --script %t.script %t |
| 10 | # RUN: llvm-readobj -program-headers %t1 | FileCheck %s | |
| 10 | # RUN: llvm-readobj -l %t1 | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | ## Check that program headers are not written, unless we explicitly tell |
| 13 | 13 | ## lld to do this. |
| ... | ... | @@ -18,7 +18,7 @@ |
| 18 | 18 | # RUN: .foo : {*(.foo.*)} :all \ |
| 19 | 19 | # RUN: }" > %t.script |
| 20 | 20 | # RUN: ld.lld -o %t1 --script %t.script %t |
| 21 | # RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=NOPHDR %s | |
| 21 | # RUN: llvm-readobj -l %t1 | FileCheck --check-prefix=NOPHDR %s | |
| 22 | 22 | |
| 23 | 23 | ## Check the AT(expr) |
| 24 | 24 | # RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS AT(0x500 + 0x500) ;} \ |
| ... | ... | @@ -28,7 +28,7 @@ |
| 28 | 28 | # RUN: .foo : {*(.foo.*)} :all \ |
| 29 | 29 | # RUN: .data : {*(.data.*)} :all}" > %t.script |
| 30 | 30 | # RUN: ld.lld -o %t1 --script %t.script %t |
| 31 | # RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=AT %s | |
| 31 | # RUN: llvm-readobj -l %t1 | FileCheck --check-prefix=AT %s | |
| 32 | 32 | |
| 33 | 33 | # RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS ;} \ |
| 34 | 34 | # RUN: SECTIONS { \ |
| ... | ... | @@ -37,7 +37,7 @@ |
| 37 | 37 | # RUN: .foo : {*(.foo.*)} \ |
| 38 | 38 | # RUN: .data : {*(.data.*)} }" > %t.script |
| 39 | 39 | # RUN: ld.lld -o %t1 --script %t.script %t |
| 40 | # RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=DEFHDR %s | |
| 40 | # RUN: llvm-readobj -l %t1 | FileCheck --check-prefix=DEFHDR %s | |
| 41 | 41 | |
| 42 | 42 | ## Check that error is reported when trying to use phdr which is not listed |
| 43 | 43 | ## inside PHDRS {} block |
| ... | ... | @@ -95,7 +95,7 @@ |
| 95 | 95 | # RUN: echo "PHDRS {text PT_LOAD FILEHDR PHDRS; foo 0x11223344; } \ |
| 96 | 96 | # RUN: SECTIONS { . = SIZEOF_HEADERS; .foo : { *(.foo* .text*) } : text : foo}" > %t1.script |
| 97 | 97 | # RUN: ld.lld -o %t2 --script %t1.script %t |
| 98 | # RUN: llvm-readobj -program-headers %t2 | FileCheck --check-prefix=INT-PHDRS %s | |
| 98 | # RUN: llvm-readobj -l %t2 | FileCheck --check-prefix=INT-PHDRS %s | |
| 99 | 99 | |
| 100 | 100 | # INT-PHDRS: ProgramHeaders [ |
| 101 | 101 | # INT-PHDRS: ProgramHeader { |
deps/lld/test/ELF/linkerscript/provide-empty-section.s+4-4| ... | ... | @@ -8,19 +8,19 @@ |
| 8 | 8 | |
| 9 | 9 | # Case 1: Provided symbol is undefined and not referenced - empty section should be removed. |
| 10 | 10 | # RUN: ld.lld %tundefined.o -T %t.script -o %t1.elf |
| 11 | # RUN: llvm-readobj -sections %t1.elf | FileCheck %s --check-prefix=NOSECTION | |
| 11 | # RUN: llvm-readobj --sections %t1.elf | FileCheck %s --check-prefix=NOSECTION | |
| 12 | 12 | |
| 13 | 13 | # Case 2: Provided symbol is undefined and referenced - empty section should not be removed. |
| 14 | 14 | # RUN: ld.lld %tundefined.o %treference.o -T %t.script -o %t2.elf |
| 15 | # RUN: llvm-readobj -sections %t2.elf | FileCheck %s --check-prefix=SECTION | |
| 15 | # RUN: llvm-readobj --sections %t2.elf | FileCheck %s --check-prefix=SECTION | |
| 16 | 16 | |
| 17 | 17 | # Case 3: Provided symbol is defined and not referenced - empty section should be removed. |
| 18 | 18 | # RUN: ld.lld %tdefined.o -T %t.script -o %t3.elf |
| 19 | # RUN: llvm-readobj -sections %t3.elf | FileCheck %s --check-prefix=NOSECTION | |
| 19 | # RUN: llvm-readobj --sections %t3.elf | FileCheck %s --check-prefix=NOSECTION | |
| 20 | 20 | |
| 21 | 21 | # Case 4: Provided symbol is defined and referenced - empty section should not be removed. |
| 22 | 22 | # RUN: ld.lld %tdefined.o %treference.o -T %t.script -o %t4.elf |
| 23 | # RUN: llvm-readobj -sections %t4.elf | FileCheck %s --check-prefix=SECTION | |
| 23 | # RUN: llvm-readobj --sections %t4.elf | FileCheck %s --check-prefix=SECTION | |
| 24 | 24 | |
| 25 | 25 | .global _start |
| 26 | 26 | _start: |
deps/lld/test/ELF/linkerscript/provide-shared2.s+1-1| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | # RUN: ld.lld -o %t --script %t.script %t.o %t2.so |
| 7 | 7 | # RUN: llvm-readelf --dyn-symbols %t | FileCheck %s |
| 8 | 8 | |
| 9 | # CHECK: 1 1: 000000000000002a 0 NOTYPE GLOBAL DEFAULT ABS foo | |
| 9 | # CHECK: 1: 000000000000002a 0 NOTYPE GLOBAL DEFAULT ABS foo | |
| 10 | 10 | |
| 11 | 11 | .global _start |
| 12 | 12 | _start: |
deps/lld/test/ELF/linkerscript/pt-interp.test+3-3| ... | ... | @@ -5,17 +5,17 @@ |
| 5 | 5 | ## Check we create PT_INTERP program header when it is specified in PHDRS. |
| 6 | 6 | # RUN: echo "PHDRS { interp PT_INTERP; }" > %t1.script |
| 7 | 7 | # RUN: ld.lld -o %t1 --script %t1.script %t.o %t.so --dynamic-linker foo |
| 8 | # RUN: llvm-readobj -program-headers %t1 | FileCheck %s | |
| 8 | # RUN: llvm-readobj -l %t1 | FileCheck %s | |
| 9 | 9 | # CHECK: PT_INTERP |
| 10 | 10 | |
| 11 | 11 | ## Check we do not create it if it is not specified, |
| 12 | 12 | ## but only if PHDRS is not empty by itself. |
| 13 | 13 | # RUN: echo "PHDRS { ph_text PT_LOAD; }" > %t2.script |
| 14 | 14 | # RUN: ld.lld -o %t1 --script %t2.script %t.o %t.so --dynamic-linker foo |
| 15 | # RUN: llvm-readobj -program-headers %t1 | FileCheck %s --check-prefix=NOINTERP | |
| 15 | # RUN: llvm-readobj -l %t1 | FileCheck %s --check-prefix=NOINTERP | |
| 16 | 16 | # NOINTERP-NOT: PT_INTERP |
| 17 | 17 | |
| 18 | 18 | ## Otherwise, if PHDRS is empty, we create PT_INTERP header. |
| 19 | 19 | # RUN: echo "PHDRS {}" > %t3.script |
| 20 | 20 | # RUN: ld.lld -o %t1 --script %t3.script %t.o %t.so --dynamic-linker foo |
| 21 | # RUN: llvm-readobj -program-headers %t1 | FileCheck %s | |
| 21 | # RUN: llvm-readobj -l %t1 | FileCheck %s |
deps/lld/test/ELF/linkerscript/quoted-section-name.test created+13| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | ## Handling of quotes is tricky sometimes. Check we do that right and include | |
| 4 | ## "foo bar" section into .data as expected. | |
| 5 | ||
| 6 | # RUN: echo '.section "foo bar", "aw"; nop' | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t | |
| 7 | # RUN: ld.lld %t --script %s -o %t2 --print-map | FileCheck %s | |
| 8 | # CHECK: .data | |
| 9 | # CHECK-NEXT: {{.*}}(foo bar) | |
| 10 | ||
| 11 | SECTIONS { | |
| 12 | .data : { *("foo bar") } | |
| 13 | } |
deps/lld/test/ELF/linkerscript/relocatable-discard.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 3 | 3 | # RUN: echo "SECTIONS { /DISCARD/ : { *(.discard.*) }}" > %t.script |
| 4 | 4 | # RUN: ld.lld -o %t --script %t.script -r %t.o |
| 5 | # RUN: llvm-readobj -sections %t | FileCheck %s | |
| 5 | # RUN: llvm-readobj --sections %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | ## Test shows that we do not crash after discarding the .discard.foo with -r. |
| 8 | 8 | ## Previously it happened because of 2 reasons: |
deps/lld/test/ELF/linkerscript/repsection-symbol.s+4-4| ... | ... | @@ -7,16 +7,16 @@ |
| 7 | 7 | # RUN: .foo : {foo1 = .; *(.foo.*) foo2 = .; *(.bar) foo3 = .;} \ |
| 8 | 8 | # RUN: }" > %t.script |
| 9 | 9 | # RUN: ld.lld --hash-style=sysv -o %t1 --script %t.script %t -shared |
| 10 | # RUN: llvm-readobj -t %t1 | FileCheck %s | |
| 10 | # RUN: llvm-readobj --symbols %t1 | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | # CHECK: Name: foo1 |
| 13 | # CHECK-NEXT: Value: 0x228 | |
| 13 | # CHECK-NEXT: Value: 0x2C0 | |
| 14 | 14 | |
| 15 | 15 | # CHECK: Name: foo2 |
| 16 | # CHECK-NEXT: Value: 0x230 | |
| 16 | # CHECK-NEXT: Value: 0x2C8 | |
| 17 | 17 | |
| 18 | 18 | # CHECK: Name: foo3 |
| 19 | # CHECK-NEXT: Value: 0x234 | |
| 19 | # CHECK-NEXT: Value: 0x2CC | |
| 20 | 20 | |
| 21 | 21 | .section .foo.1,"a" |
| 22 | 22 | .long 1 |
deps/lld/test/ELF/linkerscript/repsection-va.s+1-1| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | # RUN: ld.lld -o %t1 --script %t.script %t |
| 6 | 6 | # RUN: llvm-objdump -section-headers %t1 | FileCheck %s |
| 7 | 7 | # CHECK: Sections: |
| 8 | # CHECK-NEXT: Idx Name Size Address Type | |
| 8 | # CHECK-NEXT: Idx Name Size VMA Type | |
| 9 | 9 | # CHECK-NOT: .foo |
| 10 | 10 | # CHECK: .foo 00000008 {{.*}} DATA |
| 11 | 11 | # CHECK-NOT: .foo |
deps/lld/test/ELF/linkerscript/section-align.s+1-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: .ccc : ALIGN(4096 * 8) { *(.ccc) } \ |
| 8 | 8 | # RUN: }" > %t.script |
| 9 | 9 | # RUN: ld.lld -o %t1 --script %t.script %t |
| 10 | # RUN: llvm-readobj -sections %t1 | FileCheck %s | |
| 10 | # RUN: llvm-readobj --sections %t1 | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | .global _start |
| 13 | 13 | _start: |
deps/lld/test/ELF/linkerscript/sections-constraint2.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: echo "SECTIONS { zed : ONLY_IF_RO { *(foo) *(bar) } }" > %t.script |
| 4 | 4 | # RUN: ld.lld -T %t.script %t.o -o %t.so -shared |
| 5 | # RUN: llvm-readobj -s %t.so | FileCheck %s | |
| 5 | # RUN: llvm-readobj -S %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: Sections [ |
| 8 | 8 | # CHECK-NOT: zed |
deps/lld/test/ELF/linkerscript/sections-constraint3.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: echo "SECTIONS { zed : ONLY_IF_RO { abc = 1; *(foo) } }" > %t.script |
| 4 | 4 | # RUN: ld.lld -T %t.script %t.o -o %t.so -shared |
| 5 | # RUN: llvm-readobj -t %t.so | FileCheck %s | |
| 5 | # RUN: llvm-readobj --symbols %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: Symbols [ |
| 8 | 8 | # CHECK-NOT: abc |
deps/lld/test/ELF/linkerscript/sections-constraint4.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: .foo : ONLY_IF_RO { *(.foo) } \ |
| 5 | 5 | # RUN: .bar : {bar1 = .; *(.bar) } }" > %t1.script |
| 6 | 6 | # RUN: ld.lld -o %t1 --script %t1.script %t |
| 7 | # RUN: llvm-readobj -t %t1 | FileCheck %s | |
| 7 | # RUN: llvm-readobj --symbols %t1 | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | # CHECK: Name: bar1 |
| 10 | 10 |
deps/lld/test/ELF/linkerscript/sections-constraint5.s+1-1| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | # RUN: }" > %t.script |
| 7 | 7 | |
| 8 | 8 | # RUN: ld.lld -o %t -T %t.script %t.o |
| 9 | # RUN: llvm-readobj -s -t %t | FileCheck %s | |
| 9 | # RUN: llvm-readobj -S --symbols %t | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | # CHECK: Sections [ |
| 12 | 12 | # CHECK: Name: bar |
deps/lld/test/ELF/linkerscript/sections-gc2.s+1-1| ... | ... | @@ -8,7 +8,7 @@ |
| 8 | 8 | # RUN: ld.lld -T %t.script -o %t.so %t.o --gc-sections |
| 9 | 9 | # RUN: llvm-objdump -h %t.so | FileCheck %s |
| 10 | 10 | |
| 11 | # CHECK: Idx Name Size Address Type | |
| 11 | # CHECK: Idx Name Size VMA Type | |
| 12 | 12 | # CHECK-NEXT: 0 |
| 13 | 13 | # CHECK-NEXT: used_in_reloc |
| 14 | 14 | # CHECK-NEXT: .text |
deps/lld/test/ELF/linkerscript/sections-padding.s+29-4| ... | ... | @@ -7,11 +7,16 @@ |
| 7 | 7 | # RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES %s |
| 8 | 8 | # YES: 66000011 22000011 22000011 22000011 |
| 9 | 9 | |
| 10 | # RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x1100+0x22 }" > %t.script | |
| 11 | # RUN: ld.lld -o %t.out --script %t.script %t | |
| 12 | # RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES2 %s | |
| 13 | # YES2: 66000011 22000011 22000011 22000011 | |
| 14 | ||
| 10 | 15 | ## Confirming that address was correct: |
| 11 | 16 | # RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x99887766 }" > %t.script |
| 12 | 17 | # RUN: ld.lld -o %t.out --script %t.script %t |
| 13 | # RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES2 %s | |
| 14 | # YES2: 66998877 66998877 66998877 66998877 | |
| 18 | # RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES3 %s | |
| 19 | # YES3: 66998877 66998877 66998877 66998877 | |
| 15 | 20 | |
| 16 | 21 | ## Default padding value is 0x00: |
| 17 | 22 | # RUN: echo "SECTIONS { .mysec : { *(.mysec*) } }" > %t.script |
| ... | ... | @@ -29,9 +34,9 @@ |
| 29 | 34 | # RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x99XX }" > %t.script |
| 30 | 35 | # RUN: not ld.lld -o %t.out --script %t.script %t 2>&1 \ |
| 31 | 36 | # RUN: | FileCheck --check-prefix=ERR2 %s |
| 32 | # ERR2: invalid filler expression: 0x99XX | |
| 37 | # ERR2: malformed number: 0x99XX | |
| 33 | 38 | |
| 34 | ## Check case with space between '=' and expression: | |
| 39 | ## Check case with space between '=' and a value: | |
| 35 | 40 | # RUN: echo "SECTIONS { .mysec : { *(.mysec*) } = 0x1122 }" > %t.script |
| 36 | 41 | # RUN: ld.lld -o %t.out --script %t.script %t |
| 37 | 42 | # RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES %s |
| ... | ... | @@ -41,6 +46,26 @@ |
| 41 | 46 | # RUN: ld.lld -o %t.out --script %t.script %t |
| 42 | 47 | # RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES %s |
| 43 | 48 | |
| 49 | ## Check we can use an artbitrary expression as a filler. | |
| 50 | # RUN: echo "SECTIONS { .mysec : { *(.mysec*) } = ((0x11<<8) | 0x22) }" > %t.script | |
| 51 | # RUN: ld.lld -o %t.out --script %t.script %t | |
| 52 | # RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES %s | |
| 53 | ||
| 54 | ## Check case with space between '=' and expression: | |
| 55 | # RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =((0x11 << 8) | 0x22) }" > %t.script | |
| 56 | # RUN: ld.lld -o %t.out --script %t.script %t | |
| 57 | # RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES %s | |
| 58 | ||
| 59 | ## Check we report an error if expression value is larger than 32-bits. | |
| 60 | # RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =(0x11 << 32) }" > %t.script | |
| 61 | # RUN: not ld.lld -o %t.out --script %t.script %t 2>&1 | FileCheck --check-prefix=ERR3 %s | |
| 62 | # ERR3: filler expression result does not fit 32-bit: 0x1100000000 | |
| 63 | ||
| 64 | ## Check we report an error if an expression use a symbol. | |
| 65 | # RUN: echo "SECTIONS { foo = 0x11; .mysec : { *(.mysec*) } = foo }" > %t.script | |
| 66 | # RUN: not ld.lld -o %t.out %t --script %t.script 2>&1 | FileCheck --check-prefix=ERR4 %s | |
| 67 | # ERR4: symbol not found: foo | |
| 68 | ||
| 44 | 69 | .section .mysec.1,"a" |
| 45 | 70 | .align 16 |
| 46 | 71 | .byte 0x66 |
deps/lld/test/ELF/linkerscript/segment-none.s+1-1| ... | ... | @@ -23,7 +23,7 @@ |
| 23 | 23 | |
| 24 | 24 | # CHECK: Section to Segment mapping: |
| 25 | 25 | # CHECK-NEXT: Segment Sections... |
| 26 | # CHECK-NOT: .foo | |
| 26 | # CHECK: None {{.*}}.foo | |
| 27 | 27 | |
| 28 | 28 | # DEFINED: Section to Segment mapping: |
| 29 | 29 | # DEFINED-NEXT: Segment Sections... |
deps/lld/test/ELF/linkerscript/sort-non-script.s+1-1| ... | ... | @@ -9,8 +9,8 @@ |
| 9 | 9 | # CHECK-NEXT: .hash {{.*}} A |
| 10 | 10 | # CHECK-NEXT: .dynstr {{.*}} A |
| 11 | 11 | # CHECK-NEXT: .text {{.*}} AX |
| 12 | # CHECK-NEXT: foo {{.*}} WA | |
| 13 | 12 | # CHECK-NEXT: .dynamic {{.*}} WA |
| 13 | # CHECK-NEXT: foo {{.*}} WA | |
| 14 | 14 | |
| 15 | 15 | .section foo, "aw" |
| 16 | 16 | .byte 0 |
deps/lld/test/ELF/linkerscript/symbol-alias-relocation.s created+36| ... | ... | @@ -0,0 +1,36 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 3 | # RUN: echo "aliasto__text = __text; SECTIONS { .text 0x1000 : { __text = . ; *(.text) } }" > %t.script | |
| 4 | # RUN: ld.lld -pie -o %t --script %t.script %t.o | |
| 5 | # RUN: llvm-readobj --symbols %t | FileCheck %s | |
| 6 | ||
| 7 | ## Check that alias 'aliasto__text' has the correct value. | |
| 8 | ## (It should belong to the section .text and point to it's start). | |
| 9 | ||
| 10 | # CHECK: Symbol { | |
| 11 | # CHECK: Name: __text | |
| 12 | # CHECK-NEXT: Value: 0x1000 | |
| 13 | # CHECK-NEXT: Size: 0 | |
| 14 | # CHECK-NEXT: Binding: Global | |
| 15 | # CHECK-NEXT: Type: None | |
| 16 | # CHECK-NEXT: Other: 0 | |
| 17 | # CHECK-NEXT: Section: .text | |
| 18 | # CHECK-NEXT: } | |
| 19 | ||
| 20 | # CHECK: Symbol { | |
| 21 | # CHECK: Name: aliasto__text | |
| 22 | # CHECK-NEXT: Value: 0x1000 | |
| 23 | # CHECK-NEXT: Size: 0 | |
| 24 | # CHECK-NEXT: Binding: Global | |
| 25 | # CHECK-NEXT: Type: None | |
| 26 | # CHECK-NEXT: Other: 0 | |
| 27 | # CHECK-NEXT: Section: .text | |
| 28 | # CHECK-NEXT: } | |
| 29 | ||
| 30 | .text | |
| 31 | .globl _start | |
| 32 | .type _start, %function | |
| 33 | _start: | |
| 34 | .globl aliasto__text | |
| 35 | call __text | |
| 36 | call aliasto__text |
deps/lld/test/ELF/linkerscript/symbol-location.s+6-5| ... | ... | @@ -1,15 +1,16 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 3 | # RUN: echo "foo = 1;" > %t.script | |
| 4 | # RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | FileCheck %s | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | # RUN: echo 'foo = _start;' > %t.script | |
| 4 | # RUN: not ld.lld -shared -T %t.script %t.o -o /dev/null 2>&1 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | ## Here we check that symbol 'foo' location is reported properly. |
| 7 | 7 | |
| 8 | # CHECK: error: relocation R_X86_64_PLT32 cannot refer to absolute symbol: foo | |
| 8 | # CHECK: error: relocation R_X86_64_PC32 cannot be used against symbol foo | |
| 9 | 9 | # CHECK: >>> defined in {{.*}}.script:1 |
| 10 | 10 | # CHECK: >>> referenced by {{.*}}.o:(.text+0x1) |
| 11 | 11 | |
| 12 | 12 | .text |
| 13 | 13 | .globl _start |
| 14 | 14 | _start: |
| 15 | call foo@PLT | |
| 15 | .byte 0xe8 | |
| 16 | .long foo - . |
deps/lld/test/ELF/linkerscript/symbol-only-align.test created+35| ... | ... | @@ -0,0 +1,35 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: echo '.text; ret; .data; .quad 0' > %t.s | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t.o | |
| 4 | # RUN: ld.lld -o %t --script %s %t.o -shared | |
| 5 | # RUN: llvm-readelf -S --symbols -l %t | FileCheck %s | |
| 6 | ||
| 7 | PHDRS { | |
| 8 | text PT_LOAD FLAGS(0x5); | |
| 9 | data PT_LOAD FLAGS(0x6); | |
| 10 | } | |
| 11 | ||
| 12 | SECTIONS { | |
| 13 | . = SIZEOF_HEADERS; | |
| 14 | .text : { *(.text) } : text | |
| 15 | . = ALIGN(CONSTANT(MAXPAGESIZE)); | |
| 16 | foo : { __start_foo = .; *(foo); __end_foo = .; } : data | |
| 17 | .data : { *(.data) } | |
| 18 | .dynamic : { *(.dynamic) } | |
| 19 | } | |
| 20 | ||
| 21 | ## Check that foo, the symbol only section, has the expected aligned address and | |
| 22 | ## file offset. Also check that the section's symbols and the data segment's | |
| 23 | ## offset and addresses match. | |
| 24 | ||
| 25 | # CHECK: Section Headers | |
| 26 | # CHECK: foo PROGBITS 0000000000[[ADDR:[0-9a-f]*]] [[ADDR]] | |
| 27 | # CHECK-NEXT: .data PROGBITS 0000000000[[ADDR]] [[ADDR]] | |
| 28 | ||
| 29 | # CHECK: Symbol table | |
| 30 | # CHECK: 0000000000[[ADDR]] 0 NOTYPE GLOBAL DEFAULT {{[0-9]+}} __start_foo | |
| 31 | # CHECK: 0000000000[[ADDR]] 0 NOTYPE GLOBAL DEFAULT {{[0-9]+}} __end_foo | |
| 32 | ||
| 33 | # CHECK: Program Headers | |
| 34 | # CHECK: LOAD | |
| 35 | # CHECK-NEXT: LOAD 0x[[ADDR]] 0x0000000000[[ADDR]] 0x0000000000[[ADDR]] |
deps/lld/test/ELF/linkerscript/symbol-only-flags.test+2-2| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: echo '.section .tbss,"awT",@nobits; .quad 0' \ |
| 3 | 3 | # RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o |
| 4 | 4 | # RUN: ld.lld -o %t --script %s %t.o |
| 5 | # RUN: llvm-readobj -s %t | FileCheck %s | |
| 5 | # RUN: llvm-readobj -S %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | SECTIONS { |
| 8 | 8 | . = SIZEOF_HEADERS; |
| ... | ... | @@ -14,7 +14,7 @@ SECTIONS { |
| 14 | 14 | # CHECK: Section { |
| 15 | 15 | # CHECK: Index: |
| 16 | 16 | # CHECK: Name: .foo |
| 17 | # CHECK-NEXT: Type: SHT_NOBITS | |
| 17 | # CHECK-NEXT: Type: SHT_PROGBITS | |
| 18 | 18 | # CHECK-NEXT: Flags [ |
| 19 | 19 | # CHECK-NEXT: SHF_ALLOC |
| 20 | 20 | # CHECK-NEXT: SHF_WRITE |
deps/lld/test/ELF/linkerscript/symbol-only.test+1-1| ... | ... | @@ -12,7 +12,7 @@ SECTIONS { |
| 12 | 12 | } |
| 13 | 13 | |
| 14 | 14 | # CHECK: Sections: |
| 15 | # CHECK-NEXT: Idx Name Size Address | |
| 15 | # CHECK-NEXT: Idx Name Size VMA | |
| 16 | 16 | # CHECK-NEXT: 0 00000000 0000000000000000 |
| 17 | 17 | # CHECK: abc 00000000 [[ADDR:[0-9a-f]*]] |
| 18 | 18 | # CHECK: bar 00000000 0000000000001000 |
deps/lld/test/ELF/linkerscript/symbol-pie.s created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 4 | # RUN: echo "SECTIONS { .data 0x2000 : { foo = .; *(.data) } }" > %t.script | |
| 5 | # RUN: ld.lld -pie -o %t --script %t.script %t.o | |
| 6 | # RUN: llvm-readobj -r %t | FileCheck %s | |
| 7 | ||
| 8 | ## Position independent executables require dynamic | |
| 9 | ## relocations for references to non-absolute script | |
| 10 | ## symbols. | |
| 11 | ||
| 12 | # CHECK: Relocations [ | |
| 13 | # CHECK-NEXT: Section ({{.*}}) .rela.dyn { | |
| 14 | # CHECK-NEXT: 0x2000 R_X86_64_RELATIVE - 0x2000 | |
| 15 | # CHECK-NEXT: } | |
| 16 | # CHECK-NEXT: ] | |
| 17 | ||
| 18 | .data | |
| 19 | .quad foo |
deps/lld/test/ELF/linkerscript/tbss.s+1-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: bar : { *(bar) } \ |
| 8 | 8 | # RUN: }" > %t.script |
| 9 | 9 | # RUN: ld.lld -T %t.script %t.o -o %t |
| 10 | # RUN: llvm-readobj -s %t | FileCheck %s | |
| 10 | # RUN: llvm-readobj -S %t | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | # test that a tbss section doesn't use address space. |
| 13 | 13 |
deps/lld/test/ELF/linkerscript/ttext-script.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: echo "SECTIONS { .text 0x200000 : { *(.text) } }" > %t.script |
| 4 | 4 | # RUN: ld.lld -T %t.script -Ttext 0x100000 %t.o -o %t |
| 5 | # RUN: llvm-readobj --elf-output-style=GNU -s %t | FileCheck %s | |
| 5 | # RUN: llvm-readelf -S %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: .text PROGBITS 0000000000100000 |
| 8 | 8 |
deps/lld/test/ELF/linkerscript/va.s+1-1| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | # RUN: ld.lld -o %t1 --script %t.script %t |
| 6 | 6 | # RUN: llvm-objdump -section-headers %t1 | FileCheck %s |
| 7 | 7 | # CHECK: Sections: |
| 8 | # CHECK-NEXT: Idx Name Size Address | |
| 8 | # CHECK-NEXT: Idx Name Size VMA | |
| 9 | 9 | # CHECK-NEXT: 0 00000000 0000000000000000 |
| 10 | 10 | # CHECK-NEXT: 1 .foo 00000004 0000000000000000 |
| 11 | 11 | # CHECK-NEXT: 2 .boo 00000004 0000000000000004 |
deps/lld/test/ELF/linkerscript/version-linker-symbol.s+2-2| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: echo "VER1 { global: _end; foo ; local: * ; } ;" > %t.script |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 5 | 5 | # RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so |
| 6 | # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s | |
| 6 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | # CHECK: Name: _end@@VER1 |
| 9 | 9 | # CHECK-NEXT: Value: 0 |
| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | # CHECK-NEXT: Binding: Global |
| 12 | 12 | # CHECK-NEXT: Type: None |
| 13 | 13 | # CHECK-NEXT: Other: 0 |
| 14 | # CHECK-NEXT: Section: .dynamic | |
| 14 | # CHECK-NEXT: Section: .data | |
| 15 | 15 | |
| 16 | 16 | # CHECK: Name: foo@@VER1 |
| 17 | 17 | # CHECK-NEXT: Value: 0 |
deps/lld/test/ELF/linkerscript/visibility.s+2-2| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | |
| 4 | 4 | # RUN: echo "SECTIONS { foo = .; }" > %t1.script |
| 5 | 5 | # RUN: ld.lld -o %t1 --script %t1.script %t.o -shared |
| 6 | # RUN: llvm-readobj -t %t1 | FileCheck %s | |
| 6 | # RUN: llvm-readobj --symbols %t1 | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | # CHECK: Symbol { |
| 9 | 9 | # CHECK: Name: foo |
| ... | ... | @@ -19,4 +19,4 @@ |
| 19 | 19 | |
| 20 | 20 | .data |
| 21 | 21 | .hidden foo |
| 22 | .long foo | |
| 22 | .quad foo |
deps/lld/test/ELF/local-dynamic.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // Check that local symbols are not inserted into dynamic table. |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t |
| 4 | 4 | // RUN: ld.lld %t -shared -o %t1.so |
| 5 | // RUN: llvm-readobj -t -dyn-symbols %t1.so | FileCheck %s | |
| 5 | // RUN: llvm-readobj --symbols --dyn-syms %t1.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // CHECK: Symbols [ |
| 8 | 8 | // CHECK-NEXT: Symbol { |
deps/lld/test/ELF/local-got-pie.s+2-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv %t.o -o %t -pie |
| 4 | // RUN: llvm-readobj -s -r -d %t | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S -r -d %t | FileCheck %s | |
| 5 | 5 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s |
| 6 | 6 | |
| 7 | 7 | .globl _start |
| ... | ... | @@ -15,6 +15,7 @@ foo: |
| 15 | 15 | |
| 16 | 16 | // 0x20B0 - 1001 - 5 = 4266 |
| 17 | 17 | // DISASM: Disassembly of section .text: |
| 18 | // DISASM-EMPTY: | |
| 18 | 19 | // DISASM-NEXT: _start: |
| 19 | 20 | // DISASM-NEXT: 1000: {{.*}} callq 4267 |
| 20 | 21 | // DISASM: foo: |
deps/lld/test/ELF/local-got-shared.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv %t.o -o %t -shared |
| 4 | // RUN: llvm-readobj -s -r -d %t | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S -r -d %t | FileCheck %s | |
| 5 | 5 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s |
| 6 | 6 | |
| 7 | 7 | bar: |
deps/lld/test/ELF/local-got.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld -shared %t2.o -o %t2.so |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv %t.o %t2.so -o %t |
| 6 | // RUN: llvm-readobj -s -r -section-data %t | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S -r --section-data %t | FileCheck %s | |
| 7 | 7 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s |
| 8 | 8 | |
| 9 | 9 | .globl _start |
deps/lld/test/ELF/local-symbols-order.s+1-1| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o |
| 6 | 6 | |
| 7 | 7 | # RUN: ld.lld -o %t %t1.o %t2.o --emit-relocs |
| 8 | # RUN: llvm-readobj -symbols -sections -elf-output-style=GNU %t | FileCheck %s | |
| 8 | # RUN: llvm-readelf --symbols --sections %t | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | ## Check we sort local symbols to match the following order: |
| 11 | 11 | ## file1, local1, section1, hidden1, file2, local2, section2, hidden2 ... |
deps/lld/test/ELF/local-undefined-symbol.s+3-5| ... | ... | @@ -1,10 +1,8 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t | |
| 3 | # RUN: ld.lld %t -o %t1 | |
| 4 | # RUN: llvm-readobj -t %t1 | FileCheck %s | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 3 | # RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s | |
| 5 | 4 | |
| 6 | # CHECK: Symbols [ | |
| 7 | # CHECK-NOT: Name: foo | |
| 5 | # CHECK: error: undefined symbol: foo | |
| 8 | 6 | |
| 9 | 7 | .global _start |
| 10 | 8 | _start: |
deps/lld/test/ELF/local.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // Check that symbol table is correctly populated with local symbols. |
| 3 | 3 | // RUN: llvm-mc -save-temp-labels -filetype=obj -triple=x86_64-pc-linux %s -o %t |
| 4 | 4 | // RUN: ld.lld %t -o %t1 |
| 5 | // RUN: llvm-readobj -t -s %t1 | FileCheck %s | |
| 5 | // RUN: llvm-readobj --symbols -S %t1 | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // Check that Info is equal to the number of local symbols. |
| 8 | 8 | // CHECK: Section { |
deps/lld/test/ELF/lto/Inputs/irmover-warning.ll created+10| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | target triple = "x86_64-unknown-linux-gnu" | |
| 2 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" | |
| 3 | ||
| 4 | define void @f() { | |
| 5 | ret void | |
| 6 | } | |
| 7 | ||
| 8 | !0 = !{ i32 2, !"foo", i32 2 } | |
| 9 | ||
| 10 | !llvm.module.flags = !{ !0 } |
deps/lld/test/ELF/lto/Inputs/obj-path.ll created+7| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" | |
| 2 | target triple = "x86_64-unknown-linux-gnu" | |
| 3 | ||
| 4 | define void @g() { | |
| 5 | entry: | |
| 6 | ret void | |
| 7 | } |
deps/lld/test/ELF/lto/archive-2.ll+2-2| ... | ... | @@ -4,9 +4,9 @@ |
| 4 | 4 | ; RUN: llvm-ar rcs %t.a %t1.o |
| 5 | 5 | ; RUN: llvm-as %s -o %t2.o |
| 6 | 6 | ; RUN: ld.lld %t2.o %t.a -o %t3 |
| 7 | ; RUN: llvm-readobj -t %t3 | FileCheck %s | |
| 7 | ; RUN: llvm-readobj --symbols %t3 | FileCheck %s | |
| 8 | 8 | ; RUN: ld.lld %t2.o --whole-archive %t.a -o %t3 -shared |
| 9 | ; RUN: llvm-readobj -t %t3 | FileCheck %s | |
| 9 | ; RUN: llvm-readobj --symbols %t3 | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | ; CHECK: Name: _start ( |
| 12 | 12 | ; CHECK-NEXT: Value: |
deps/lld/test/ELF/lto/archive-no-index.ll+13-4| ... | ... | @@ -1,8 +1,6 @@ |
| 1 | 1 | ; REQUIRES: x86 |
| 2 | ; Tests that we suggest that LTO symbols missing from an archive index | |
| 3 | ; may be the cause of undefined references, but only if we both | |
| 4 | ; encountered an empty archive index and undefined references (to prevent | |
| 5 | ; noisy false alarms). | |
| 2 | ; Tests that we accept an archive file without symbol table | |
| 3 | ; if all the member files are bitcode files. | |
| 6 | 4 | |
| 7 | 5 | ; RUN: llvm-as -o %t1.o %s |
| 8 | 6 | ; RUN: llvm-as -o %t2.o %S/Inputs/archive.ll |
| ... | ... | @@ -23,3 +21,14 @@ define i32 @main() { |
| 23 | 21 | call void @f() |
| 24 | 22 | ret i32 0 |
| 25 | 23 | } |
| 24 | ||
| 25 | ; RUN: echo 'f:' | llvm-mc -triple=x86_64-pc-linux -filetype=obj - -o %t3.o | |
| 26 | ; RUN: rm -f %t3.a | |
| 27 | ; RUN: llvm-ar crS %t3.a %t3.o | |
| 28 | ; RUN: not ld.lld -o /dev/null -emain %t1.o %t3.a 2>&1 | FileCheck -check-prefix=ERR1 %s | |
| 29 | ; ERR1: error: {{.*}}.a: archive has no index; run ranlib to add one | |
| 30 | ||
| 31 | ; RUN: rm -f %t4.a | |
| 32 | ; RUN: llvm-ar cr %t4.a | |
| 33 | ; RUN: not ld.lld -o /dev/null -emain %t1.o %t4.a 2>&1 | FileCheck -check-prefix=ERR2 %s | |
| 34 | ; ERR2: error: undefined symbol: f |
deps/lld/test/ELF/lto/archive.ll+2-2| ... | ... | @@ -4,9 +4,9 @@ |
| 4 | 4 | ; RUN: llvm-ar rcs %t.a %t1.o |
| 5 | 5 | ; RUN: llvm-as %s -o %t2.o |
| 6 | 6 | ; RUN: ld.lld %t2.o %t.a -o %t3 -shared |
| 7 | ; RUN: llvm-readobj -t %t3 | FileCheck %s | |
| 7 | ; RUN: llvm-readobj --symbols %t3 | FileCheck %s | |
| 8 | 8 | ; RUN: ld.lld %t2.o --whole-archive %t.a -o %t3 -shared |
| 9 | ; RUN: llvm-readobj -t %t3 | FileCheck %s | |
| 9 | ; RUN: llvm-readobj --symbols %t3 | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | ; CHECK: Name: g ( |
| 12 | 12 | ; CHECK-NEXT: Value: |
deps/lld/test/ELF/lto/comdat.ll+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | ; REQUIRES: x86 |
| 2 | 2 | ; RUN: llvm-as %s -o %t.o |
| 3 | 3 | ; RUN: ld.lld %t.o %t.o -o %t.so -shared |
| 4 | ; RUN: llvm-readobj -t %t.so | FileCheck %s | |
| 4 | ; RUN: llvm-readobj --symbols %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | ; CHECK: Name: foo |
| 7 | 7 | ; CHECK-NEXT: Value: |
deps/lld/test/ELF/lto/comdat2.ll+2-2| ... | ... | @@ -2,9 +2,9 @@ |
| 2 | 2 | ; RUN: llvm-as %s -o %t.o |
| 3 | 3 | ; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/comdat.s -o %t2.o -filetype=obj |
| 4 | 4 | ; RUN: ld.lld %t.o %t2.o -o %t.so -shared |
| 5 | ; RUN: llvm-readobj -t %t.so | FileCheck %s | |
| 5 | ; RUN: llvm-readobj --symbols %t.so | FileCheck %s | |
| 6 | 6 | ; RUN: ld.lld %t2.o %t.o -o %t2.so -shared |
| 7 | ; RUN: llvm-readobj -t %t2.so | FileCheck %s --check-prefix=OTHER | |
| 7 | ; RUN: llvm-readobj --symbols %t2.so | FileCheck %s --check-prefix=OTHER | |
| 8 | 8 | |
| 9 | 9 | |
| 10 | 10 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" |
deps/lld/test/ELF/lto/common.ll+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | ; RUN: llvm-as %s -o %t1.o |
| 3 | 3 | ; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/common.s -o %t2.o -filetype=obj |
| 4 | 4 | ; RUN: ld.lld %t1.o %t2.o -o %t.so -shared |
| 5 | ; RUN: llvm-readobj -s -t %t.so | FileCheck %s | |
| 5 | ; RUN: llvm-readobj -S --symbols %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | ; CHECK: Name: .bss |
| 8 | 8 | ; CHECK-NEXT: Type: SHT_NOBITS |
deps/lld/test/ELF/lto/common2.ll+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | ; RUN: llvm-as %s -o %t1.o |
| 3 | 3 | ; RUN: ld.lld %t1.o -o %t -shared -save-temps |
| 4 | 4 | ; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s |
| 5 | ; RUN: llvm-readobj -t %t | FileCheck %s --check-prefix=SHARED | |
| 5 | ; RUN: llvm-readobj --symbols %t | FileCheck %s --check-prefix=SHARED | |
| 6 | 6 | |
| 7 | 7 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" |
| 8 | 8 | target triple = "x86_64-unknown-linux-gnu" |
deps/lld/test/ELF/lto/common4.ll created+21| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | ; REQUIRES: x86 | |
| 2 | ||
| 3 | ;; Make sure that common symbols are properly internalized. | |
| 4 | ;; In this file, @a does not interpose any symbol in a DSO, | |
| 5 | ;; so LTO should be able to internelize it. | |
| 6 | ||
| 7 | ; RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.so.o | |
| 8 | ; RUN: ld.lld -shared -o %t.so %t.so.o | |
| 9 | ||
| 10 | ; RUN: llvm-as %s -o %t.o | |
| 11 | ; RUN: ld.lld -o %t.exe -save-temps %t.o %t.so | |
| 12 | ; RUN: llvm-dis < %t.exe.0.2.internalize.bc | FileCheck %s | |
| 13 | ||
| 14 | ; RUN: ld.lld -pie -o %t.exe -save-temps %t.o | |
| 15 | ; RUN: llvm-dis < %t.exe.0.2.internalize.bc | FileCheck %s | |
| 16 | ||
| 17 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" | |
| 18 | target triple = "x86_64-unknown-linux-gnu" | |
| 19 | ||
| 20 | @a = common dso_local local_unnamed_addr global i32 0, align 4 | |
| 21 | ; CHECK-DAG: @a = internal global i32 0, align 4 |
deps/lld/test/ELF/lto/ctors.ll+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | ; REQUIRES: x86 |
| 2 | 2 | ; RUN: llvm-as %s -o %t.o |
| 3 | 3 | ; RUN: ld.lld %t.o -o %t.so -shared |
| 4 | ; RUN: llvm-readobj -sections %t.so | FileCheck %s | |
| 4 | ; RUN: llvm-readobj --sections %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" |
| 7 | 7 | target triple = "x86_64-unknown-linux-gnu" |
deps/lld/test/ELF/lto/defsym.ll+4-10| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | ; RUN: opt -module-summary %S/Inputs/defsym-bar.ll -o %t1.o |
| 12 | 12 | ; RUN: ld.lld %t.o %t1.o -shared -o %t2.so -defsym=bar2=bar3 -save-temps |
| 13 | 13 | ; RUN: llvm-readelf --symbols %t2.so1.lto.o | FileCheck --check-prefix=OBJ %s |
| 14 | ; RUN: llvm-objdump -d %t2.so | FileCheck %s --check-prefix=THIN | |
| 14 | ; RUN: llvm-objdump -d %t2.so | FileCheck %s | |
| 15 | 15 | |
| 16 | 16 | ; OBJ: UND bar2 |
| 17 | 17 | |
| ... | ... | @@ -19,17 +19,11 @@ |
| 19 | 19 | ; Symbol bar3 should not be eliminated |
| 20 | 20 | |
| 21 | 21 | ; CHECK: foo: |
| 22 | ; CHECK-NEXT: pushq	%rax | |
| 22 | ; CHECK-NEXT: pushq %rax | |
| 23 | 23 | ; CHECK-NEXT: callq |
| 24 | 24 | ; CHECK-NEXT: callq{{.*}}<bar3> |
| 25 | ; CHECK-NEXT: callq | |
| 26 | ||
| 27 | ; THIN: foo | |
| 28 | ; THIN-NEXT: pushq %rax | |
| 29 | ; THIN-NEXT: callq | |
| 30 | ; THIN-NEXT: callq{{.*}}<bar3> | |
| 31 | ; THIN-NEXT: popq %rax | |
| 32 | ; THIN-NEXT: jmp | |
| 25 | ; CHECK-NEXT: popq %rax | |
| 26 | ; CHECK-NEXT: jmp | |
| 33 | 27 | |
| 34 | 28 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" |
| 35 | 29 | target triple = "x86_64-unknown-linux-gnu" |
deps/lld/test/ELF/lto/deplibs.s created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | ; REQUIRES: x86 | |
| 2 | ||
| 3 | ; RUN: llvm-as %s -o %t.o | |
| 4 | ; RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s -DOBJ=%t.o | |
| 5 | ||
| 6 | ; CHECK: error: [[OBJ]]: unable to find library from dependent library specifier: foo | |
| 7 | ; CHECK: error: [[OBJ]]: unable to find library from dependent library specifier: bar | |
| 8 | ||
| 9 | target triple = "x86_64-unknown-linux-gnu" | |
| 10 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" | |
| 11 | ||
| 12 | !llvm.dependent-libraries = !{!0, !1} | |
| 13 | ||
| 14 | !0 = !{!"foo"} | |
| 15 | !1 = !{!"bar"} |
deps/lld/test/ELF/lto/dynamic-list.ll+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | ; RUN: llvm-as %s -o %t.o |
| 3 | 3 | ; RUN: echo "{ foo; };" > %t.list |
| 4 | 4 | ; RUN: ld.lld -o %t --dynamic-list %t.list -pie %t.o |
| 5 | ; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s | |
| 5 | ; RUN: llvm-readobj --dyn-syms %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | ; CHECK: Name: foo |
| 8 | 8 | ; CHECK-NEXT: Value: 0x1010 |
deps/lld/test/ELF/lto/dynsym.ll+2-2| ... | ... | @@ -3,12 +3,12 @@ |
| 3 | 3 | ; RUN: ld.lld %t.o -o %t.so -shared |
| 4 | 4 | ; RUN: llvm-as %s -o %t2.o |
| 5 | 5 | ; RUN: ld.lld %t2.o %t.so -o %t |
| 6 | ; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s | |
| 6 | ; RUN: llvm-readobj --dyn-syms %t | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | ; Check that we don't crash when gc'ing sections and printing the result. |
| 9 | 9 | ; RUN: ld.lld %t2.o %t.so --gc-sections --print-gc-sections \ |
| 10 | 10 | ; RUN: -o %t |
| 11 | ; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s | |
| 11 | ; RUN: llvm-readobj --dyn-syms %t | FileCheck %s | |
| 12 | 12 | |
| 13 | 13 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" |
| 14 | 14 | target triple = "x86_64-unknown-linux-gnu" |
deps/lld/test/ELF/lto/irmover-warning.ll created+23| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | ; REQUIRES: x86 | |
| 2 | ; RUN: llvm-as -o %t1.bc %s | |
| 3 | ; RUN: llvm-as -o %t2.bc %S/Inputs/irmover-warning.ll | |
| 4 | ; RUN: rm -f %t.a | |
| 5 | ; RUN: llvm-ar rcs %t.a %t2.bc | |
| 6 | ; RUN: ld.lld %t1.bc %t.a -o %t 2>&1 | FileCheck %s | |
| 7 | ||
| 8 | ; CHECK: warning: linking module flags 'foo': IDs have conflicting values | |
| 9 | ; CHECK-SAME: irmover-warning.ll.tmp.a(irmover-warning.ll.tmp2.bc at {{[0-9]+}}) | |
| 10 | ||
| 11 | target triple = "x86_64-unknown-linux-gnu" | |
| 12 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" | |
| 13 | ||
| 14 | declare void @f() | |
| 15 | ||
| 16 | define void @g() { | |
| 17 | call void @f() | |
| 18 | ret void | |
| 19 | } | |
| 20 | ||
| 21 | !0 = !{ i32 2, !"foo", i32 1 } | |
| 22 | ||
| 23 | !llvm.module.flags = !{ !0 } |
deps/lld/test/ELF/lto/linker-script-symbols-assign.ll+3-3| ... | ... | @@ -3,12 +3,12 @@ |
| 3 | 3 | |
| 4 | 4 | ; RUN: echo "foo = 1;" > %t.script |
| 5 | 5 | ; RUN: ld.lld %t.o -o %t2 --script %t.script -save-temps |
| 6 | ; RUN: llvm-readobj -symbols %t2.lto.o | FileCheck %s | |
| 6 | ; RUN: llvm-readobj --symbols %t2.lto.o | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | ; CHECK-NOT: bar |
| 9 | 9 | ; CHECK-NOT: foo |
| 10 | 10 | |
| 11 | ; RUN: llvm-readobj -symbols %t2 | FileCheck %s --check-prefix=VAL | |
| 11 | ; RUN: llvm-readobj --symbols %t2 | FileCheck %s --check-prefix=VAL | |
| 12 | 12 | ; VAL: Symbol { |
| 13 | 13 | ; VAL: Name: foo |
| 14 | 14 | ; VAL-NEXT: Value: 0x1 |
| ... | ... | @@ -21,7 +21,7 @@ |
| 21 | 21 | |
| 22 | 22 | ; RUN: echo "zed = 1;" > %t2.script |
| 23 | 23 | ; RUN: ld.lld %t.o -o %t3 --script %t2.script |
| 24 | ; RUN: llvm-readobj -symbols %t3 | FileCheck %s --check-prefix=ABS | |
| 24 | ; RUN: llvm-readobj --symbols %t3 | FileCheck %s --check-prefix=ABS | |
| 25 | 25 | ; ABS: Symbol { |
| 26 | 26 | ; ABS: Name: zed |
| 27 | 27 | ; ABS-NEXT: Value: 0x1 |
deps/lld/test/ELF/lto/linker-script-symbols.ll+2-1| ... | ... | @@ -3,8 +3,9 @@ |
| 3 | 3 | ; RUN: echo "foo = bar;" > %t.script |
| 4 | 4 | |
| 5 | 5 | ; RUN: ld.lld %t.o -o %t2 --script %t.script -save-temps |
| 6 | ; RUN: llvm-readobj -symbols %t2.lto.o | FileCheck %s | |
| 6 | ; RUN: llvm-readobj --symbols %t2.lto.o | FileCheck %s | |
| 7 | 7 | |
| 8 | ; CHECK: Symbols [ | |
| 8 | 9 | ; CHECK-NOT: zed |
| 9 | 10 | ; CHECK: Symbol { |
| 10 | 11 | ; CHECK: Name: bar |
deps/lld/test/ELF/lto/lto-start.ll+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | ; REQUIRES: x86 |
| 2 | 2 | ; RUN: llvm-as %s -o %t.o |
| 3 | 3 | ; RUN: ld.lld %t.o -o %t2 |
| 4 | ; RUN: llvm-readobj -t %t2 | FileCheck %s | |
| 4 | ; RUN: llvm-readobj --symbols %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | ; CHECK: Format: ELF64-x86-64 |
| 7 | 7 | ; CHECK-NEXT: Arch: x86_64 |
deps/lld/test/ELF/lto/obj-path.ll created+35| ... | ... | @@ -0,0 +1,35 @@ |
| 1 | ; REQUIRES: x86 | |
| 2 | ||
| 3 | ; RUN: opt -module-summary %s -o %t1.o | |
| 4 | ; RUN: opt -module-summary %p/Inputs/obj-path.ll -o %t2.o | |
| 5 | ||
| 6 | ; Test to ensure that obj-path creates the ELF file. | |
| 7 | ; RUN: rm -f %t4.o | |
| 8 | ; RUN: ld.lld --plugin-opt=obj-path=%t4.o -shared %t1.o %t2.o -o %t3 | |
| 9 | ; RUN: llvm-readobj --symbols %t3 | FileCheck %s | |
| 10 | ; RUN: llvm-readobj -h %t4.o1 | FileCheck %s -check-prefix=ELF1 | |
| 11 | ; RUN: llvm-readobj -h %t4.o2 | FileCheck %s -check-prefix=ELF2 | |
| 12 | ; RUN: llvm-nm %t4.o1 2>&1 | FileCheck %s -check-prefix=NM1 | |
| 13 | ; RUN: llvm-nm %t4.o2 2>&1 | FileCheck %s -check-prefix=NM2 | |
| 14 | ||
| 15 | ; CHECK: Name: g | |
| 16 | ; CHECK-NEXT: Value: 0x1010 | |
| 17 | ; CHECK: Name: f | |
| 18 | ; CHECK-NEXT: Value: 0x1000 | |
| 19 | ||
| 20 | ; NM1: T f | |
| 21 | ; ELF1: Format: ELF64-x86-64 | |
| 22 | ||
| 23 | ; NM2: T g | |
| 24 | ; ELF2: Format: ELF64-x86-64 | |
| 25 | ||
| 26 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" | |
| 27 | target triple = "x86_64-unknown-linux-gnu" | |
| 28 | ||
| 29 | declare void @g(...) | |
| 30 | ||
| 31 | define void @f() { | |
| 32 | entry: | |
| 33 | call void (...) @g() | |
| 34 | ret void | |
| 35 | } |
deps/lld/test/ELF/lto/opt-remarks.ll+9-1| ... | ... | @@ -8,10 +8,16 @@ |
| 8 | 8 | ; RUN: %t.o -o %t -shared |
| 9 | 9 | ; RUN: cat %t.yaml | FileCheck %s -check-prefix=YAML |
| 10 | 10 | ; RUN: cat %t.hot.yaml | FileCheck %s -check-prefix=YAML-HOT |
| 11 | ; RUN: ld.lld --opt-remarks-filename %t1.yaml --opt-remarks-passes inline %t.o \ | |
| 12 | ; RUN: -o /dev/null -shared | |
| 13 | ; RUN: cat %t1.yaml | FileCheck %s -check-prefix=YAML-PASSES | |
| 14 | ; RUN: ld.lld --opt-remarks-filename %t1.yaml --opt-remarks-format yaml %t.o \ | |
| 15 | ; RUN: -o /dev/null -shared | |
| 16 | ; RUN: cat %t.yaml | FileCheck %s -check-prefix=YAML | |
| 11 | 17 | |
| 12 | 18 | ; Check that @tinkywinky is inlined after optimizations. |
| 13 | 19 | ; CHECK-LABEL: define i32 @main |
| 14 | ; CHECK-NEXT: %a.i = call i32 @patatino() | |
| 20 | ; CHECK-NEXT: %a.i = {{.*}}call i32 @patatino() | |
| 15 | 21 | ; CHECK-NEXT: ret i32 %a.i |
| 16 | 22 | ; CHECK-NEXT: } |
| 17 | 23 | |
| ... | ... | @@ -48,6 +54,8 @@ |
| 48 | 54 | ; YAML-HOT-NEXT: - String: ')' |
| 49 | 55 | ; YAML-HOT-NEXT: ... |
| 50 | 56 | |
| 57 | ; YAML-PASSES: Pass: inline | |
| 58 | ||
| 51 | 59 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" |
| 52 | 60 | target triple = "x86_64-scei-ps4" |
| 53 | 61 |
deps/lld/test/ELF/lto/parallel-internalize.ll+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | ; RUN: rm -f %t.lto.o %t1.lto.o |
| 4 | 4 | ; RUN: ld.lld --lto-partitions=2 -save-temps -o %t %t.bc \ |
| 5 | 5 | ; RUN: -e foo --lto-O0 |
| 6 | ; RUN: llvm-readobj -t -dyn-symbols %t | FileCheck %s | |
| 6 | ; RUN: llvm-readobj --symbols --dyn-syms %t | FileCheck %s | |
| 7 | 7 | ; RUN: llvm-nm %t.lto.o | FileCheck --check-prefix=CHECK0 %s |
| 8 | 8 | ; RUN: llvm-nm %t1.lto.o | FileCheck --check-prefix=CHECK1 %s |
| 9 | 9 |
deps/lld/test/ELF/lto/relocatable.ll+3-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | ; REQUIRES: x86 |
| 2 | 2 | ; RUN: llvm-as %s -o %t1.o |
| 3 | 3 | ; RUN: ld.lld %t1.o -r -o %t |
| 4 | ; RUN: llvm-readobj -symbols %t | FileCheck %s | |
| 4 | ; RUN: llvm-readobj --symbols %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | ; CHECK: Symbols [ |
| 7 | 7 | ; CHECK-NEXT: Symbol { |
| ... | ... | @@ -71,3 +71,5 @@ define void @foo() { |
| 71 | 71 | define internal void @bar() { |
| 72 | 72 | ret void |
| 73 | 73 | } |
| 74 | ||
| 75 | declare i32 @baz(...) |
deps/lld/test/ELF/lto/resolution.ll+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | ; RUN: llvm-as %s -o %t1.o |
| 3 | 3 | ; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/resolution.s -o %t2.o -filetype=obj |
| 4 | 4 | ; RUN: ld.lld %t1.o %t2.o -o %t.so -shared |
| 5 | ; RUN: llvm-readobj -s --section-data %t.so | FileCheck %s | |
| 5 | ; RUN: llvm-readobj -S --section-data %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | ; CHECK: Name: .data |
| 8 | 8 | ; CHECK-NEXT: Type: SHT_PROGBITS |
deps/lld/test/ELF/lto/riscv32.ll created+10| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | ; REQUIRES: riscv | |
| 2 | ||
| 3 | ; RUN: llvm-as %s -o %t.o | |
| 4 | ; RUN: ld.lld %t.o -o %t | |
| 5 | target datalayout = "e-m:e-p:32:32-i64:64-n32-S128" | |
| 6 | target triple = "riscv32-unknown-elf" | |
| 7 | ||
| 8 | define void @f() { | |
| 9 | ret void | |
| 10 | } |
deps/lld/test/ELF/lto/riscv64.ll created+10| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | ; REQUIRES: riscv | |
| 2 | ||
| 3 | ; RUN: llvm-as %s -o %t.o | |
| 4 | ; RUN: ld.lld %t.o -o %t | |
| 5 | target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128" | |
| 6 | target triple = "riscv64-unknown-elf" | |
| 7 | ||
| 8 | define void @f() { | |
| 9 | ret void | |
| 10 | } |
deps/lld/test/ELF/lto/setting-dso-local.ll+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | ; RUN: llvm-as %s -o %t1.o |
| 3 | 3 | ; RUN: not ld.lld -o %t %t1.o 2>&1 | FileCheck %s |
| 4 | 4 | |
| 5 | ; CHECK: undefined symbol: foobar | |
| 5 | ; CHECK: undefined hidden symbol: foobar | |
| 6 | 6 | |
| 7 | 7 | ; We used to crash setting foobar to non-dso_local |
| 8 | 8 |
deps/lld/test/ELF/lto/shlib-undefined.ll+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | ; RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t2.s -o %t2.o |
| 5 | 5 | ; RUN: ld.lld -shared %t2.o -o %t2.so |
| 6 | 6 | ; RUN: ld.lld -o %t %t.o %t2.so |
| 7 | ; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s | |
| 7 | ; RUN: llvm-readobj --dyn-syms %t | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | ; CHECK: Name: __progname |
| 10 | 10 | ; CHECK-NEXT: Value: 0x201010 |
deps/lld/test/ELF/lto/thinlto-cant-write-index.ll+2-1| ... | ... | @@ -7,8 +7,9 @@ |
| 7 | 7 | ; Ensure lld generates error if unable to write to index files |
| 8 | 8 | ; RUN: rm -f %t2.o.thinlto.bc |
| 9 | 9 | ; RUN: touch %t2.o.thinlto.bc |
| 10 | ; RUN: chmod 400 %t2.o.thinlto.bc | |
| 10 | ; RUN: chmod u-w %t2.o.thinlto.bc | |
| 11 | 11 | ; RUN: not ld.lld --plugin-opt=thinlto-index-only -shared %t1.o %t2.o -o %t3 2>&1 | FileCheck %s |
| 12 | ; RUN: chmod u+w %t2.o.thinlto.bc | |
| 12 | 13 | ; CHECK: cannot open {{.*}}2.o.thinlto.bc: {{P|p}}ermission denied |
| 13 | 14 | |
| 14 | 15 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" |
deps/lld/test/ELF/lto/thinlto-index-only.ll+4-8| ... | ... | @@ -38,15 +38,11 @@ |
| 38 | 38 | ; RUN: ls %t1.o.thinlto.bc |
| 39 | 39 | ; RUN: ls %t1.o.imports |
| 40 | 40 | |
| 41 | ; Ensure lld generates an error if unable to write an empty index file | |
| 42 | ; for lazy object file that is not added to link. | |
| 43 | ; RUN: rm -f %t1.o.thinlto.bc | |
| 44 | ; RUN: touch %t1.o.thinlto.bc | |
| 45 | ; RUN: chmod 400 %t1.o.thinlto.bc | |
| 46 | ; RUN: not ld.lld --plugin-opt=thinlto-index-only -shared %t2.o --start-lib %t1.o --end-lib \ | |
| 47 | ; RUN: -o %t3 2>&1 | FileCheck %s | |
| 48 | ; CHECK: cannot open {{.*}}1.o.thinlto.bc: {{P|p}}ermission denied | |
| 41 | ; Ensure LLD generates an empty index for each bitcode file even if all bitcode files are lazy. | |
| 49 | 42 | ; RUN: rm -f %t1.o.thinlto.bc |
| 43 | ; RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux-gnu /dev/null -o %tdummy.o | |
| 44 | ; RUN: ld.lld --plugin-opt=thinlto-index-only -shared %tdummy.o --start-lib %t1.o --end-lib -o /dev/null | |
| 45 | ; RUN: ls %t1.o.thinlto.bc | |
| 50 | 46 | |
| 51 | 47 | ; NM: T f |
| 52 | 48 |
deps/lld/test/ELF/lto/tls-preserve.ll+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | ; REQUIRES: x86 |
| 3 | 3 | ; RUN: llvm-as %s -o %t1.o |
| 4 | 4 | ; RUN: ld.lld -shared %t1.o -o %t1 |
| 5 | ; RUN: llvm-readobj -t %t1 | FileCheck %s | |
| 5 | ; RUN: llvm-readobj --symbols %t1 | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" |
| 8 | 8 | target triple = "x86_64-unknown-linux-gnu" |
deps/lld/test/ELF/lto/undef-mixed.ll+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | ; RUN: llvm-mc %p/Inputs/undef-mixed.s -o %t.o -filetype=obj -triple=x86_64-pc-linux |
| 3 | 3 | ; RUN: llvm-as %s -o %t2.o |
| 4 | 4 | ; RUN: ld.lld %t2.o %t.o -o %t.so -shared |
| 5 | ; RUN: llvm-readobj -t %t.so | FileCheck %s | |
| 5 | ; RUN: llvm-readobj --symbols %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | ; CHECK: Name: bar |
| 8 | 8 | ; CHECK-NEXT: Value: |
deps/lld/test/ELF/lto/undef-weak.ll+1-1| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | |
| 6 | 6 | ; RUN: llvm-as %s -o %t2.o |
| 7 | 7 | ; RUN: ld.lld %t2.o -o %t2.so %t.a -shared |
| 8 | ; RUN: llvm-readobj -t %t2.so | FileCheck %s | |
| 8 | ; RUN: llvm-readobj --symbols %t2.so | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | target triple = "x86_64-unknown-linux-gnu" |
| 11 | 11 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" |
deps/lld/test/ELF/lto/undef.ll+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | ; REQUIRES: x86 |
| 2 | 2 | ; RUN: llvm-as %s -o %t.o |
| 3 | 3 | ; RUN: ld.lld %t.o -o %t.so -shared |
| 4 | ; RUN: llvm-readobj -t %t.so | FileCheck %s | |
| 4 | ; RUN: llvm-readobj --symbols %t.so | FileCheck %s | |
| 5 | 5 | target triple = "x86_64-unknown-linux-gnu" |
| 6 | 6 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" |
| 7 | 7 |
deps/lld/test/ELF/lto/undefined-puts.ll+2-2| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | ; RUN: ld.lld %t1.o -o %t1.so -shared |
| 4 | 4 | ; RUN: llvm-as %s -o %t2.o |
| 5 | 5 | ; RUN: ld.lld %t1.so %t2.o -o %t |
| 6 | ; RUN: llvm-readobj -dyn-symbols -dyn-relocations %t | FileCheck %s | |
| 6 | ; RUN: llvm-readobj --dyn-syms --dyn-relocations %t | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" |
| 9 | 9 | target triple = "x86_64-unknown-linux-gnu" |
| ... | ... | @@ -20,7 +20,7 @@ declare i32 @printf(i8*, ...) |
| 20 | 20 | ; Check that puts symbol is present in the dynamic symbol table and |
| 21 | 21 | ; there's a relocation for it. |
| 22 | 22 | ; CHECK: Dynamic Relocations { |
| 23 | ; CHECK-NEXT: 0x202018 R_X86_64_JUMP_SLOT puts 0x0 | |
| 23 | ; CHECK-NEXT: 0x203018 R_X86_64_JUMP_SLOT puts 0x0 | |
| 24 | 24 | ; CHECK-NEXT: } |
| 25 | 25 | |
| 26 | 26 | ; CHECK: DynamicSymbols [ |
deps/lld/test/ELF/lto/version-script.ll+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | ; RUN: echo "VERSION_1.0{ global: foo; local: *; }; VERSION_2.0{ global: bar; local: *; };" > %t.script |
| 4 | 4 | ; RUN: ld.lld %t.o -o %t2 -shared --version-script %t.script -save-temps |
| 5 | 5 | ; RUN: llvm-dis < %t2.0.0.preopt.bc | FileCheck %s |
| 6 | ; RUN: llvm-readobj -V -dyn-symbols %t2 | FileCheck --check-prefix=DSO %s | |
| 6 | ; RUN: llvm-readobj -V --dyn-syms %t2 | FileCheck --check-prefix=DSO %s | |
| 7 | 7 | |
| 8 | 8 | target triple = "x86_64-unknown-linux-gnu" |
| 9 | 9 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" |
deps/lld/test/ELF/lto/version-script2.ll+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | ; RUN: llvm-as %s -o %t.o |
| 3 | 3 | ; RUN: echo "VER1 {};" > %t.script |
| 4 | 4 | ; RUN: ld.lld %t.o -o %t.so -shared --version-script %t.script |
| 5 | ; RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s | |
| 5 | ; RUN: llvm-readobj --dyn-syms %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | ; test that we have the correct version. |
| 8 | 8 | ; CHECK: Name: foo@@VER1 ( |
deps/lld/test/ELF/lto/visibility.ll+2-2| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | ; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/visibility.s -o %t2.o -filetype=obj |
| 4 | 4 | ; RUN: ld.lld %t1.o %t2.o -o %t.so -shared -save-temps |
| 5 | 5 | ; RUN: llvm-dis < %t.so.0.2.internalize.bc | FileCheck --check-prefix=IR %s |
| 6 | ; RUN: llvm-readobj -t %t.so | FileCheck %s | |
| 6 | ; RUN: llvm-readobj --symbols %t.so | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | ; CHECK: Name: g |
| 9 | 9 | ; CHECK-NEXT: Value: 0x1000 |
| ... | ... | @@ -16,7 +16,7 @@ |
| 16 | 16 | ; CHECK-NEXT: Section: .text |
| 17 | 17 | |
| 18 | 18 | ; CHECK: Name: a |
| 19 | ; CHECK-NEXT: Value: 0x2000 | |
| 19 | ; CHECK-NEXT: Value: 0x3000 | |
| 20 | 20 | ; CHECK-NEXT: Size: 0 |
| 21 | 21 | ; CHECK-NEXT: Binding: Local |
| 22 | 22 | ; CHECK-NEXT: Type: None |
deps/lld/test/ELF/lto/weak.ll+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | ; REQUIRES: x86 |
| 2 | 2 | ; RUN: llvm-as %s -o %t.o |
| 3 | 3 | ; RUN: ld.lld %t.o %t.o -o %t.so -shared |
| 4 | ; RUN: llvm-readobj -t %t.so | FileCheck %s | |
| 4 | ; RUN: llvm-readobj --symbols %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | target triple = "x86_64-unknown-linux-gnu" |
| 7 | 7 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" |
deps/lld/test/ELF/lto/weakodr-visibility.ll+2-2| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | ; but keeps `protected` visibility. |
| 10 | 10 | |
| 11 | 11 | ; RUN: ld.lld %t1.o %t2.o -o %t.so -shared |
| 12 | ; RUN: llvm-readobj -t %t.so | FileCheck %s | |
| 12 | ; RUN: llvm-readobj --symbols %t.so | FileCheck %s | |
| 13 | 13 | ; RUN: llvm-objdump -d %t.so | FileCheck %s --check-prefix=FIRST |
| 14 | 14 | ; CHECK: Symbol { |
| 15 | 15 | ; CHECK: Name: foo |
| ... | ... | @@ -27,7 +27,7 @@ |
| 27 | 27 | |
| 28 | 28 | ; Now swap the files order. |
| 29 | 29 | ; RUN: ld.lld %t2.o %t1.o -o %t.so -shared |
| 30 | ; RUN: llvm-readobj -t %t.so | FileCheck %s | |
| 30 | ; RUN: llvm-readobj --symbols %t.so | FileCheck %s | |
| 31 | 31 | ; RUN: llvm-objdump -d %t.so | FileCheck %s --check-prefix=SECOND |
| 32 | 32 | ; SECOND: foo: |
| 33 | 33 | ; SECOND-NEXT: movl $42, %eax |
deps/lld/test/ELF/lto/wrap-1.ll+2-2| ... | ... | @@ -2,13 +2,13 @@ |
| 2 | 2 | ; LTO |
| 3 | 3 | ; RUN: llvm-as %s -o %t.o |
| 4 | 4 | ; RUN: ld.lld %t.o -o %t.out -wrap=bar -save-temps |
| 5 | ; RUN: llvm-readobj -t %t.out | FileCheck %s | |
| 5 | ; RUN: llvm-readobj --symbols %t.out | FileCheck %s | |
| 6 | 6 | ; RUN: cat %t.out.resolution.txt | FileCheck -check-prefix=RESOLS %s |
| 7 | 7 | |
| 8 | 8 | ; ThinLTO |
| 9 | 9 | ; RUN: opt -module-summary %s -o %t.o |
| 10 | 10 | ; RUN: ld.lld %t.o -o %t.out -wrap=bar -save-temps |
| 11 | ; RUN: llvm-readobj -t %t.out | FileCheck %s | |
| 11 | ; RUN: llvm-readobj --symbols %t.out | FileCheck %s | |
| 12 | 12 | ; RUN: cat %t.out.resolution.txt | FileCheck -check-prefix=RESOLS %s |
| 13 | 13 | |
| 14 | 14 | ; CHECK: Name: __wrap_bar |
deps/lld/test/ELF/lto/wrap-2.ll+5-10| ... | ... | @@ -4,14 +4,14 @@ |
| 4 | 4 | ; RUN: llvm-as %S/Inputs/wrap-bar.ll -o %t1.o |
| 5 | 5 | ; RUN: ld.lld %t.o %t1.o -shared -o %t.so -wrap=bar |
| 6 | 6 | ; RUN: llvm-objdump -d %t.so | FileCheck %s |
| 7 | ; RUN: llvm-readobj -t %t.so | FileCheck -check-prefix=BIND %s | |
| 7 | ; RUN: llvm-readobj --symbols %t.so | FileCheck -check-prefix=BIND %s | |
| 8 | 8 | |
| 9 | 9 | ; ThinLTO |
| 10 | 10 | ; RUN: opt -module-summary %s -o %t.o |
| 11 | 11 | ; RUN: opt -module-summary %S/Inputs/wrap-bar.ll -o %t1.o |
| 12 | 12 | ; RUN: ld.lld %t.o %t1.o -shared -o %t.so -wrap=bar |
| 13 | ; RUN: llvm-objdump -d %t.so | FileCheck %s -check-prefix=THIN | |
| 14 | ; RUN: llvm-readobj -t %t.so | FileCheck -check-prefix=BIND %s | |
| 13 | ; RUN: llvm-objdump -d %t.so | FileCheck %s | |
| 14 | ; RUN: llvm-readobj --symbols %t.so | FileCheck -check-prefix=BIND %s | |
| 15 | 15 | |
| 16 | 16 | ; Make sure that calls in foo() are not eliminated and that bar is |
| 17 | 17 | ; routed to __wrap_bar and __real_bar is routed to bar. |
| ... | ... | @@ -19,13 +19,8 @@ |
| 19 | 19 | ; CHECK: foo: |
| 20 | 20 | ; CHECK-NEXT: pushq	%rax |
| 21 | 21 | ; CHECK-NEXT: callq{{.*}}<__wrap_bar> |
| 22 | ; CHECK-NEXT: callq{{.*}}<bar> | |
| 23 | ||
| 24 | ; THIN: foo: | |
| 25 | ; THIN-NEXT: pushq	%rax | |
| 26 | ; THIN-NEXT: callq{{.*}}<__wrap_bar> | |
| 27 | ; THIN-NEXT: popq %rax | |
| 28 | ; THIN-NEXT: jmp{{.*}}<bar> | |
| 22 | ; CHECK-NEXT: popq %rax | |
| 23 | ; CHECK-NEXT: jmp{{.*}}<bar> | |
| 29 | 24 | |
| 30 | 25 | ; Check that bar and __wrap_bar retain their original binding. |
| 31 | 26 | ; BIND: Name: bar |
deps/lld/test/ELF/magic-page-combo-warn.s created+86| ... | ... | @@ -0,0 +1,86 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t | |
| 3 | ||
| 4 | # Test that we warn when a page size is set and paging is disabled by -n or -N. | |
| 5 | ||
| 6 | # RUN: ld.lld -z max-page-size=0x10 -z common-page-size=0x10 -N %t -o %t2 2>&1 | FileCheck --check-prefix=WARN %s | |
| 7 | # RUN: llvm-readobj --program-headers %t2 | FileCheck --check-prefix=OMAGIC %s | |
| 8 | # RUN: ld.lld -z max-page-size=0x10 -z common-page-size=0x10 --omagic %t -o %t2 2>&1 | FileCheck --check-prefix=WARN %s | |
| 9 | # RUN: llvm-readobj --program-headers %t2 | FileCheck --check-prefix=OMAGIC %s | |
| 10 | ||
| 11 | # WARN: ld.lld: warning: -z max-page-size set, but paging disabled by omagic or nmagic | |
| 12 | # WARN-NEXT: ld.lld: warning: -z common-page-size set, but paging disabled by omagic or nmagic | |
| 13 | ||
| 14 | # OMAGIC: ProgramHeader { | |
| 15 | # OMAGIC: Type: PT_LOAD | |
| 16 | # OMAGIC-NEXT: Offset: 0xE8 | |
| 17 | # OMAGIC-NEXT: VirtualAddress: | |
| 18 | # OMAGIC-NEXT: PhysicalAddress: | |
| 19 | # OMAGIC-NEXT: FileSize: | |
| 20 | # OMAGIC-NEXT: MemSize: | |
| 21 | # OMAGIC-NEXT: Flags [ | |
| 22 | # OMAGIC-NEXT: PF_R | |
| 23 | # OMAGIC-NEXT: PF_W | |
| 24 | # OMAGIC-NEXT: PF_X | |
| 25 | # OMAGIC-NEXT: ] | |
| 26 | # OMAGIC-NEXT: Alignment: 8 | |
| 27 | # OMAGIC-NEXT: } | |
| 28 | # OMAGIC-NEXT: ProgramHeader { | |
| 29 | # OMAGIC-NEXT: Type: PT_GNU_STACK | |
| 30 | ||
| 31 | # RUN: ld.lld -z max-page-size=0x10 -z common-page-size=0x10 -n %t -o %t3 2>&1 | FileCheck --check-prefix=WARN %s | |
| 32 | # RUN: llvm-readobj --program-headers %t3 | FileCheck --check-prefix=NMAGIC %s | |
| 33 | # RUN: ld.lld -z max-page-size=0x10 -z common-page-size=0x10 --nmagic %t -o %t3 2>&1 | FileCheck --check-prefix=WARN %s | |
| 34 | # RUN: llvm-readobj --program-headers %t3 | FileCheck --check-prefix=NMAGIC %s | |
| 35 | ||
| 36 | # NMAGIC: ProgramHeader { | |
| 37 | # NMAGIC-NEXT: Type: PT_LOAD | |
| 38 | # NMAGIC-NEXT: Offset: 0x158 | |
| 39 | # NMAGIC-NEXT: VirtualAddress: | |
| 40 | # NMAGIC-NEXT: PhysicalAddress: | |
| 41 | # NMAGIC-NEXT: FileSize: 1 | |
| 42 | # NMAGIC-NEXT: MemSize: 1 | |
| 43 | # NMAGIC-NEXT: Flags [ | |
| 44 | # NMAGIC-NEXT: PF_R | |
| 45 | # NMAGIC-NEXT: ] | |
| 46 | # NMAGIC-NEXT: Alignment: 8 | |
| 47 | # NMAGIC-NEXT: } | |
| 48 | # NMAGIC-NEXT: ProgramHeader { | |
| 49 | # NMAGIC-NEXT: Type: PT_LOAD | |
| 50 | # NMAGIC-NEXT: Offset: 0x15C | |
| 51 | # NMAGIC-NEXT: VirtualAddress: | |
| 52 | # NMAGIC-NEXT: PhysicalAddress: | |
| 53 | # NMAGIC-NEXT: FileSize: 2 | |
| 54 | # NMAGIC-NEXT: MemSize: 2 | |
| 55 | # NMAGIC-NEXT: Flags [ | |
| 56 | # NMAGIC-NEXT: PF_R | |
| 57 | # NMAGIC-NEXT: PF_X | |
| 58 | # NMAGIC-NEXT: ] | |
| 59 | # NMAGIC-NEXT: Alignment: 4 | |
| 60 | # NMAGIC-NEXT: } | |
| 61 | # NMAGIC-NEXT: ProgramHeader { | |
| 62 | # NMAGIC-NEXT: Type: PT_LOAD (0x1) | |
| 63 | # NMAGIC-NEXT: Offset: 0x15E | |
| 64 | # NMAGIC-NEXT: VirtualAddress: | |
| 65 | # NMAGIC-NEXT: PhysicalAddress: | |
| 66 | # NMAGIC-NEXT: FileSize: 1 | |
| 67 | # NMAGIC-NEXT: MemSize: 1 | |
| 68 | # NMAGIC-NEXT: Flags [ | |
| 69 | # NMAGIC-NEXT: PF_R | |
| 70 | # NMAGIC-NEXT: PF_W | |
| 71 | # NMAGIC-NEXT: ] | |
| 72 | # NMAGIC-NEXT: Alignment: 1 | |
| 73 | # NMAGIC-NEXT: } | |
| 74 | ||
| 75 | .global _start | |
| 76 | _start: | |
| 77 | nop | |
| 78 | ||
| 79 | .section .ro,"a" | |
| 80 | nop | |
| 81 | ||
| 82 | .section .rw,"aw" | |
| 83 | nop | |
| 84 | ||
| 85 | .section .rx,"ax" | |
| 86 | nop |
deps/lld/test/ELF/many-alloc-sections.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t.o |
| 3 | 3 | // RUN: echo "SECTIONS { . = SIZEOF_HEADERS; .text : { *(.text) } }" > %t.script |
| 4 | 4 | // RUN: ld.lld -T %t.script %t.o -o %t |
| 5 | // RUN: llvm-readobj -t %t | FileCheck %s | |
| 5 | // RUN: llvm-readobj --symbols %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // Test that _start is in the correct section. |
| 8 | 8 | // CHECK: Name: _start |
deps/lld/test/ELF/many-sections.s+3-3| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t |
| 3 | // RUN: llvm-readobj -t %t | FileCheck %s | |
| 3 | // RUN: llvm-readobj --symbols %t | FileCheck %s | |
| 4 | 4 | |
| 5 | 5 | // Verify that the symbol _start is in a section with an index >= SHN_LORESERVE. |
| 6 | 6 | // CHECK: Name: _start |
| ... | ... | @@ -12,12 +12,12 @@ |
| 12 | 12 | // CHECK-NEXT: Section: dm (0xFF00) |
| 13 | 13 | |
| 14 | 14 | // RUN: ld.lld %t -o %t2 |
| 15 | // RUN: llvm-readobj -t %t2 | FileCheck --check-prefix=LINKED %s | |
| 15 | // RUN: llvm-readobj --symbols %t2 | FileCheck --check-prefix=LINKED %s | |
| 16 | 16 | |
| 17 | 17 | // Test also with a linker script. |
| 18 | 18 | // RUN: echo "SECTIONS { . = SIZEOF_HEADERS; .text : { *(.text) } }" > %t.script |
| 19 | 19 | // RUN: ld.lld -T %t.script %t -o %t2 |
| 20 | // RUN: llvm-readobj -t %t2 | FileCheck --check-prefix=LINKED %s | |
| 20 | // RUN: llvm-readobj --symbols %t2 | FileCheck --check-prefix=LINKED %s | |
| 21 | 21 | |
| 22 | 22 | // Test that _start is in the correct section. |
| 23 | 23 | // LINKED: Name: _start |
deps/lld/test/ELF/map-file.s+27-27| ... | ... | @@ -41,22 +41,22 @@ abs = 0xAB5 |
| 41 | 41 | labs = 0x1AB5 |
| 42 | 42 | |
| 43 | 43 | // CHECK: VMA LMA Size Align Out In Symbol |
| 44 | // CHECK-NEXT: 2001c8 2001c8 78 8 .dynsym | |
| 45 | // CHECK-NEXT: 2001c8 2001c8 78 8 <internal>:(.dynsym) | |
| 46 | // CHECK-NEXT: 200240 200240 2c 8 .gnu.hash | |
| 47 | // CHECK-NEXT: 200240 200240 2c 8 <internal>:(.gnu.hash) | |
| 48 | // CHECK-NEXT: 20026c 20026c 30 4 .hash | |
| 49 | // CHECK-NEXT: 20026c 20026c 30 4 <internal>:(.hash) | |
| 50 | // CHECK-NEXT: 20029c 20029c 31 1 .dynstr | |
| 51 | // CHECK-NEXT: 20029c 20029c 31 1 <internal>:(.dynstr) | |
| 52 | // CHECK-NEXT: 2002d0 2002d0 30 8 .rela.dyn | |
| 53 | // CHECK-NEXT: 2002d0 2002d0 30 8 <internal>:(.rela.dyn) | |
| 54 | // CHECK-NEXT: 200300 200300 30 8 .rela.plt | |
| 55 | // CHECK-NEXT: 200300 200300 30 8 <internal>:(.rela.plt) | |
| 56 | // CHECK-NEXT: 200330 200330 64 8 .eh_frame | |
| 57 | // CHECK-NEXT: 200330 200330 2c 1 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.eh_frame+0x0) | |
| 58 | // CHECK-NEXT: 200360 200360 14 1 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.eh_frame+0x2c) | |
| 59 | // CHECK-NEXT: 200378 200378 18 1 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.eh_frame+0x18) | |
| 44 | // CHECK-NEXT: 200200 200200 78 8 .dynsym | |
| 45 | // CHECK-NEXT: 200200 200200 78 8 <internal>:(.dynsym) | |
| 46 | // CHECK-NEXT: 200278 200278 2c 8 .gnu.hash | |
| 47 | // CHECK-NEXT: 200278 200278 2c 8 <internal>:(.gnu.hash) | |
| 48 | // CHECK-NEXT: 2002a4 2002a4 30 4 .hash | |
| 49 | // CHECK-NEXT: 2002a4 2002a4 30 4 <internal>:(.hash) | |
| 50 | // CHECK-NEXT: 2002d4 2002d4 31 1 .dynstr | |
| 51 | // CHECK-NEXT: 2002d4 2002d4 31 1 <internal>:(.dynstr) | |
| 52 | // CHECK-NEXT: 200308 200308 30 8 .rela.dyn | |
| 53 | // CHECK-NEXT: 200308 200308 30 8 <internal>:(.rela.dyn) | |
| 54 | // CHECK-NEXT: 200338 200338 30 8 .rela.plt | |
| 55 | // CHECK-NEXT: 200338 200338 30 8 <internal>:(.rela.plt) | |
| 56 | // CHECK-NEXT: 200368 200368 64 8 .eh_frame | |
| 57 | // CHECK-NEXT: 200368 200368 2c 1 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.eh_frame+0x0) | |
| 58 | // CHECK-NEXT: 200398 200398 14 1 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.eh_frame+0x2c) | |
| 59 | // CHECK-NEXT: 2003b0 2003b0 18 1 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.eh_frame+0x18) | |
| 60 | 60 | // CHECK-NEXT: 201000 201000 2d 4 .text |
| 61 | 61 | // CHECK-NEXT: 201000 201000 28 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.text) |
| 62 | 62 | // CHECK-NEXT: 201000 201000 0 1 _start |
| ... | ... | @@ -75,17 +75,17 @@ labs = 0x1AB5 |
| 75 | 75 | // CHECK-NEXT: 201030 201030 30 16 <internal>:(.plt) |
| 76 | 76 | // CHECK-NEXT: 201040 201040 0 1 sharedFunc1 |
| 77 | 77 | // CHECK-NEXT: 201050 201050 0 1 sharedFunc2 |
| 78 | // CHECK-NEXT: 202000 202000 28 8 .got.plt | |
| 79 | // CHECK-NEXT: 202000 202000 28 8 <internal>:(.got.plt) | |
| 80 | // CHECK-NEXT: 203000 203000 100 8 .dynamic | |
| 81 | // CHECK-NEXT: 203000 203000 100 8 <internal>:(.dynamic) | |
| 82 | // CHECK-NEXT: 204000 204000 10 16 .bss | |
| 83 | // CHECK-NEXT: 204000 204000 4 16 {{.*}}{{/|\\}}map-file.s.tmp1.o:(COMMON) | |
| 84 | // CHECK-NEXT: 204000 204000 4 1 common | |
| 85 | // CHECK-NEXT: 204004 204004 4 1 <internal>:(.bss) | |
| 86 | // CHECK-NEXT: 204004 204004 4 1 sharedFoo | |
| 87 | // CHECK-NEXT: 204008 204008 8 1 <internal>:(.bss) | |
| 88 | // CHECK-NEXT: 204008 204008 8 1 sharedBar | |
| 78 | // CHECK-NEXT: 202000 202000 100 8 .dynamic | |
| 79 | // CHECK-NEXT: 202000 202000 100 8 <internal>:(.dynamic) | |
| 80 | // CHECK-NEXT: 203000 203000 28 8 .got.plt | |
| 81 | // CHECK-NEXT: 203000 203000 28 8 <internal>:(.got.plt) | |
| 82 | // CHECK-NEXT: 203030 203030 10 16 .bss | |
| 83 | // CHECK-NEXT: 203030 203030 4 16 {{.*}}{{/|\\}}map-file.s.tmp1.o:(COMMON) | |
| 84 | // CHECK-NEXT: 203030 203030 4 1 common | |
| 85 | // CHECK-NEXT: 203034 203034 4 1 <internal>:(.bss) | |
| 86 | // CHECK-NEXT: 203034 203034 4 1 sharedFoo | |
| 87 | // CHECK-NEXT: 203038 203038 8 1 <internal>:(.bss) | |
| 88 | // CHECK-NEXT: 203038 203038 8 1 sharedBar | |
| 89 | 89 | // CHECK-NEXT: 0 0 8 1 .comment |
| 90 | 90 | // CHECK-NEXT: 0 0 8 1 <internal>:(.comment) |
| 91 | 91 | // CHECK-NEXT: 0 0 198 8 .symtab |
deps/lld/test/ELF/merge-align.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -s -section-data %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S --section-data %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .section .rodata.foo,"aM",@progbits,1 |
| 7 | 7 | .align 16 |
deps/lld/test/ELF/merge-align2.s created+35| ... | ... | @@ -0,0 +1,35 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | ||
| 4 | # RUN: ld.lld %t.o -o %t | |
| 5 | # RUN: llvm-readelf -S %t | FileCheck --check-prefix=SEC %s | |
| 6 | # RUN: llvm-readelf -x .cst8 %t | FileCheck %s | |
| 7 | ||
| 8 | # RUN: ld.lld -O0 -r %t.o -o %t1.o | |
| 9 | # RUN: llvm-readelf -S %t1.o | FileCheck --check-prefix=SEC %s | |
| 10 | # RUN: llvm-readelf -x .cst8 %t1.o | FileCheck %s | |
| 11 | ||
| 12 | ## Check that if we have SHF_MERGE sections with the same name, flags and | |
| 13 | ## entsize, but different alignments, we combine them with the maximum input | |
| 14 | ## alignment as the output alignment. | |
| 15 | ||
| 16 | # SEC: Name Type {{.*}} Size ES Flg Lk Inf Al | |
| 17 | # SEC: .cst8 PROGBITS {{.*}} 000018 08 AM 0 0 8 | |
| 18 | ||
| 19 | # CHECK: 0x{{[0-9a-f]+}} 02000000 00000000 01000000 00000000 | |
| 20 | # CHECK-NEXT: 0x{{[0-9a-f]+}} 03000000 00000000 | |
| 21 | ||
| 22 | .section .cst8,"aM",@progbits,8,unique,0 | |
| 23 | .align 4 | |
| 24 | .quad 1 | |
| 25 | .quad 1 | |
| 26 | ||
| 27 | .section .cst8,"aM",@progbits,8,unique,1 | |
| 28 | .align 4 | |
| 29 | .quad 1 | |
| 30 | .quad 2 | |
| 31 | ||
| 32 | .section .cst8,"aM",@progbits,8,unique,2 | |
| 33 | .align 8 | |
| 34 | .quad 1 | |
| 35 | .quad 3 |
deps/lld/test/ELF/merge-entsize.s+8-3| ... | ... | @@ -1,13 +1,18 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t |
| 4 | // RUN: llvm-readobj -s %t | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .section .rodata.1,"aM",@progbits,1 |
| 7 | .p2align 2 | |
| 7 | 8 | .byte 0x42 |
| 8 | 9 | |
| 9 | .section .rodata.2,"aM",@progbits,2 | |
| 10 | // sh_addralign = 4 while sh_entsize = 3. | |
| 11 | // sh_entsize is not necessarily a power of 2 and it can be unrelated to sh_addralign. | |
| 12 | .section .rodata.2,"aM",@progbits,3 | |
| 13 | .p2align 2 | |
| 10 | 14 | .short 0x42 |
| 15 | .byte 0 | |
| 11 | 16 | |
| 12 | 17 | // Since the output section has both .rodata.1 and .rodata.2, it |
| 13 | 18 | // contains elements of different sizes and we use an entsize of 0. |
| ... | ... | @@ -23,5 +28,5 @@ |
| 23 | 28 | // CHECK-NEXT: Size: |
| 24 | 29 | // CHECK-NEXT: Link: |
| 25 | 30 | // CHECK-NEXT: Info: |
| 26 | // CHECK-NEXT: AddressAlignment: | |
| 31 | // CHECK-NEXT: AddressAlignment: 4 | |
| 27 | 32 | // CHECK-NEXT: EntrySize: 0 |
deps/lld/test/ELF/merge-entsize2.s created+49| ... | ... | @@ -0,0 +1,49 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | ||
| 4 | # RUN: ld.lld %t.o -o %t | |
| 5 | # RUN: llvm-readelf -S %t | FileCheck --check-prefix=SEC %s | |
| 6 | # RUN: llvm-readelf -x .cst %t | FileCheck --check-prefix=HEX %s | |
| 7 | ||
| 8 | # RUN: ld.lld -O0 -r %t.o -o %t1.o | |
| 9 | # RUN: llvm-readelf -S %t1.o | FileCheck --check-prefix=SEC-R %s | |
| 10 | # RUN: llvm-readelf -x .cst %t1.o | FileCheck --check-prefix=HEX-R %s | |
| 11 | ||
| 12 | ## Check that SHF_MERGE sections with the same name, sh_flags and sh_entsize | |
| 13 | ## are grouped together and can be merged within the group. | |
| 14 | ||
| 15 | ## .cst 0 and .cst 1 are merged (sh_entsize=4). The result and .cst 2 and | |
| 16 | ## combined (sh_entsize=8). The output sh_entsize is 0. | |
| 17 | # SEC: Name Type {{.*}} Size ES Flg Lk Inf Al | |
| 18 | # SEC: .cst PROGBITS {{.*}} 000020 00 AM 0 0 8 | |
| 19 | ||
| 20 | ## .cst 0 and .cst 1 are merged, but emitted as a separate output section. | |
| 21 | # SEC-R: .cst PROGBITS {{.*}} 00000c 04 AM 0 0 4 | |
| 22 | # SEC-R: .cst PROGBITS {{.*}} 000010 08 AM 0 0 8 | |
| 23 | ||
| 24 | # HEX: Hex dump of section '.cst': | |
| 25 | # HEX-NEXT: 0x{{[0-9a-f]+}} 01000000 00000000 02000000 00000000 | |
| 26 | # HEX-NEXT: 0x{{[0-9a-f]+}} 01000000 00000000 03000000 00000000 | |
| 27 | ||
| 28 | # HEX-R: Hex dump of section '.cst': | |
| 29 | # HEX-R-NEXT: 0x00000000 01000000 00000000 02000000 | |
| 30 | # HEX-R-EMPTY: | |
| 31 | # HEX-R-NEXT: Hex dump of section '.cst': | |
| 32 | # HEX-R-NEXT: 0x00000000 01000000 00000000 03000000 00000000 | |
| 33 | ||
| 34 | .section .cst,"aM",@progbits,4,unique,0 | |
| 35 | .align 2 | |
| 36 | .long 1 | |
| 37 | .long 0 | |
| 38 | .long 2 | |
| 39 | ||
| 40 | .section .cst,"aM",@progbits,4,unique,1 | |
| 41 | .align 4 | |
| 42 | .long 1 | |
| 43 | .long 0 | |
| 44 | .long 2 | |
| 45 | ||
| 46 | .section .cst,"aM",@progbits,8,unique,2 | |
| 47 | .align 8 | |
| 48 | .quad 1 | |
| 49 | .quad 3 |
deps/lld/test/ELF/merge-gc-piece.s+3-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld %t.o -o %t.so -shared --gc-sections |
| 4 | # RUN: llvm-readobj -s -section-data %t.so | FileCheck %s | |
| 4 | # RUN: llvm-readobj -S --section-data %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | |
| 7 | 7 | # CHECK: Name: .foo |
| ... | ... | @@ -10,7 +10,7 @@ |
| 10 | 10 | # CHECK-NEXT: SHF_ALLOC |
| 11 | 11 | # CHECK-NEXT: SHF_MERGE |
| 12 | 12 | # CHECK-NEXT: ] |
| 13 | # CHECK-NEXT: Address: 0x200 | |
| 13 | # CHECK-NEXT: Address: 0x1FD | |
| 14 | 14 | |
| 15 | 15 | # CHECK: Name: .bar |
| 16 | 16 | # CHECK-NEXT: Type: SHT_PROGBITS |
| ... | ... | @@ -24,7 +24,7 @@ |
| 24 | 24 | # CHECK-NEXT: AddressAlignment: |
| 25 | 25 | # CHECK-NEXT: EntrySize: |
| 26 | 26 | # CHECK-NEXT: SectionData ( |
| 27 | # CHECK-NEXT: 0000: 01020000 00000000 02020000 00000000 | |
| 27 | # CHECK-NEXT: 0000: FE010000 00000000 FF010000 00000000 | |
| 28 | 28 | # CHECK-NEXT: ) |
| 29 | 29 | |
| 30 | 30 | .section .foo,"aM",@progbits,8 |
deps/lld/test/ELF/merge-gc-piece2.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld %t.o -o %t.so -shared --gc-sections |
| 4 | # RUN: llvm-readobj -s -section-data %t.so | FileCheck %s | |
| 4 | # RUN: llvm-readobj -S --section-data %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: Name: .bar |
| 7 | 7 | # CHECK-NEXT: Type: SHT_PROGBITS |
deps/lld/test/ELF/merge-reloc-O0.s deleted-48| ... | ... | @@ -1,48 +0,0 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -r -o %t2.o -O0 | |
| 4 | # RUN: llvm-readobj -s -section-data %t2.o | FileCheck %s | |
| 5 | ||
| 6 | # We combine just the sections with the same name and sh_entsize. | |
| 7 | ||
| 8 | # CHECK: Name: .foo | |
| 9 | # CHECK-NEXT: Type: SHT_PROGBITS | |
| 10 | # CHECK-NEXT: Flags [ | |
| 11 | # CHECK-NEXT: SHF_ALLOC | |
| 12 | # CHECK-NEXT: SHF_MERGE | |
| 13 | # CHECK-NEXT: ] | |
| 14 | # CHECK-NEXT: Address: | |
| 15 | # CHECK-NEXT: Offset: | |
| 16 | # CHECK-NEXT: Size: 16 | |
| 17 | # CHECK-NEXT: Link: | |
| 18 | # CHECK-NEXT: Info: | |
| 19 | # CHECK-NEXT: AddressAlignment: 8 | |
| 20 | # CHECK-NEXT: EntrySize: 8 | |
| 21 | # CHECK-NEXT: SectionData ( | |
| 22 | # CHECK-NEXT: 0000: 41000000 00000000 42000000 00000000 | |
| 23 | # CHECK-NEXT: ) | |
| 24 | ||
| 25 | # CHECK: Name: .foo | |
| 26 | # CHECK-NEXT: Type: SHT_PROGBITS | |
| 27 | # CHECK-NEXT: Flags [ | |
| 28 | # CHECK-NEXT: SHF_ALLOC | |
| 29 | # CHECK-NEXT: SHF_MERGE | |
| 30 | # CHECK-NEXT: ] | |
| 31 | # CHECK-NEXT: Address: | |
| 32 | # CHECK-NEXT: Offset: | |
| 33 | # CHECK-NEXT: Size: 8 | |
| 34 | # CHECK-NEXT: Link: | |
| 35 | # CHECK-NEXT: Info: | |
| 36 | # CHECK-NEXT: AddressAlignment: 4 | |
| 37 | # CHECK-NEXT: EntrySize: 4 | |
| 38 | # CHECK-NEXT: SectionData ( | |
| 39 | # CHECK-NEXT: 0000: 41000000 42000000 | |
| 40 | # CHECK-NEXT: ) | |
| 41 | ||
| 42 | .section .foo, "aM",@progbits,8,unique,0 | |
| 43 | .quad 0x41 | |
| 44 | .section .foo, "aM",@progbits,8,unique,1 | |
| 45 | .quad 0x42 | |
| 46 | .section .foo, "aM",@progbits,4,unique,2 | |
| 47 | .long 0x41 | |
| 48 | .long 0x42 |
deps/lld/test/ELF/merge-reloc.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld %t.o -r -o %t-rel |
| 4 | # RUN: llvm-readobj -s -section-data %t-rel | FileCheck %s | |
| 4 | # RUN: llvm-readobj -S --section-data %t-rel | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # When linker generates a relocatable object it does string merging in the same |
| 7 | 7 | # way as for regular link. It should keep SHF_MERGE flag and set proper sh_entsize |
deps/lld/test/ELF/merge-section-types.s+3-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld -shared %t.o -o %t |
| 4 | // RUN: llvm-readobj -s %t | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // CHECK: Name: .foo |
| 7 | 7 | // CHECK-NEXT: Type: SHT_PROGBITS |
| ... | ... | @@ -9,8 +9,8 @@ |
| 9 | 9 | // CHECK-NEXT: SHF_ALLOC |
| 10 | 10 | // CHECK-NEXT: SHF_WRITE |
| 11 | 11 | // CHECK-NEXT: ] |
| 12 | // CHECK-NEXT: Address: 0x1000 | |
| 13 | // CHECK-NEXT: Offset: 0x1000 | |
| 12 | // CHECK-NEXT: Address: 0x2000 | |
| 13 | // CHECK-NEXT: Offset: 0x2000 | |
| 14 | 14 | // CHECK-NEXT: Size: 16 |
| 15 | 15 | |
| 16 | 16 | .section .foo, "aw", @progbits, unique, 1 |
deps/lld/test/ELF/merge-shared-str.s+3-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared -O3 |
| 4 | // RUN: llvm-readobj -r -s %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -r -S %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | |
| 7 | 7 | .section foo,"aMS",@progbits,1 |
| ... | ... | @@ -19,10 +19,10 @@ |
| 19 | 19 | // CHECK-NEXT: SHF_MERGE |
| 20 | 20 | // CHECK-NEXT: SHF_STRINGS |
| 21 | 21 | // CHECK-NEXT: ] |
| 22 | // CHECK-NEXT: Address: 0x228 | |
| 22 | // CHECK-NEXT: Address: 0x260 | |
| 23 | 23 | |
| 24 | 24 | // CHECK: Relocations [ |
| 25 | 25 | // CHECK-NEXT: Section ({{.*}}) .rela.dyn { |
| 26 | // CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x229 | |
| 26 | // CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x261 | |
| 27 | 27 | // CHECK-NEXT: } |
| 28 | 28 | // CHECK-NEXT: ] |
deps/lld/test/ELF/merge-shared.s+3-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -r -s %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -r -S %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | 	.section	foo,"aM",@progbits,4 |
| 7 | 7 | .long 42 |
| ... | ... | @@ -17,10 +17,10 @@ |
| 17 | 17 | // CHECK-NEXT: SHF_ALLOC |
| 18 | 18 | // CHECK-NEXT: SHF_MERGE |
| 19 | 19 | // CHECK-NEXT: ] |
| 20 | // CHECK-NEXT: Address: 0x228 | |
| 20 | // CHECK-NEXT: Address: 0x260 | |
| 21 | 21 | |
| 22 | 22 | // CHECK: Relocations [ |
| 23 | 23 | // CHECK-NEXT: Section ({{.*}}) .rela.dyn { |
| 24 | // CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x22A | |
| 24 | // CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x262 | |
| 25 | 25 | // CHECK-NEXT: } |
| 26 | 26 | // CHECK-NEXT: ] |
deps/lld/test/ELF/merge-string-align.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -s -section-data %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S --section-data %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .section .rodata.foo,"aMS",@progbits,1 |
| 7 | 7 | .align 16 |
deps/lld/test/ELF/merge-string-align2.s created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | ||
| 4 | # RUN: ld.lld %t.o -o %t | |
| 5 | # RUN: llvm-readelf -S %t | FileCheck --check-prefix=SEC %s | |
| 6 | # RUN: llvm-readelf -x .rodata %t | FileCheck %s | |
| 7 | ||
| 8 | # SEC: Name Type {{.*}} Size ES Flg Lk Inf Al | |
| 9 | # SEC: .rodata PROGBITS {{.*}} 000006 01 AMS 0 0 8 | |
| 10 | ||
| 11 | ## Check there is no extra padding. | |
| 12 | ||
| 13 | # CHECK: a.b.c. | |
| 14 | ||
| 15 | .section .rodata.str1.8,"aMS",@progbits,1 | |
| 16 | .align 8 | |
| 17 | .asciz "a" | |
| 18 | ||
| 19 | .section .rodata.str1.2,"aMS",@progbits,1 | |
| 20 | .align 2 | |
| 21 | .asciz "b" | |
| 22 | ||
| 23 | .section .rodata.str1.1,"aMS",@progbits,1 | |
| 24 | .align 1 | |
| 25 | .asciz "c" |
deps/lld/test/ELF/merge-string-error.s+1-1| ... | ... | @@ -6,6 +6,6 @@ |
| 6 | 6 | 	.asciz	"abc" |
| 7 | 7 | |
| 8 | 8 | .data |
| 9 | .long .rodata.str1.1 + 4 | |
| 9 | .quad .rodata.str1.1 + 4 | |
| 10 | 10 | |
| 11 | 11 | // CHECK: merge-string-error.s.tmp.o:(.rodata.str1.1): offset is outside the section |
deps/lld/test/ELF/merge-string.s+3-3| ... | ... | @@ -1,11 +1,11 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld -O 2 %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -s -section-data -t %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S --section-data --symbols %t.so | FileCheck %s | |
| 5 | 5 | // RUN: ld.lld -O 1 %t.o -o %t.so -shared |
| 6 | // RUN: llvm-readobj -s -section-data -t %t.so | FileCheck --check-prefix=NOTAIL %s | |
| 6 | // RUN: llvm-readobj -S --section-data --symbols %t.so | FileCheck --check-prefix=NOTAIL %s | |
| 7 | 7 | // RUN: ld.lld -O 0 %t.o -o %t.so -shared |
| 8 | // RUN: llvm-readobj -s -section-data -t %t.so | FileCheck --check-prefix=NOMERGE %s | |
| 8 | // RUN: llvm-readobj -S --section-data --symbols %t.so | FileCheck --check-prefix=NOMERGE %s | |
| 9 | 9 | |
| 10 | 10 | .section	.rodata1,"aMS",@progbits,1 |
| 11 | 11 | 	.asciz	"abc" |
deps/lld/test/ELF/merge-sym.s+3-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -t -s %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols -S %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .section .rodata.cst4,"aM",@progbits,4 |
| 7 | 7 | .short 0 |
| ... | ... | @@ -15,7 +15,7 @@ foo: |
| 15 | 15 | // CHECK-NEXT: SHF_ALLOC |
| 16 | 16 | // CHECK-NEXT: SHF_MERGE |
| 17 | 17 | // CHECK-NEXT: ] |
| 18 | // CHECK-NEXT: Address: 0x210 | |
| 18 | // CHECK-NEXT: Address: 0x20D | |
| 19 | 19 | |
| 20 | 20 | // CHECK: Name: foo |
| 21 | // CHECK-NEXT: Value: 0x212 | |
| 21 | // CHECK-NEXT: Value: 0x20F |
deps/lld/test/ELF/merge-to-non-alloc.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -s -section-data -t %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S --section-data --symbols %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // CHECK: Name: .bar |
| 7 | 7 | // CHECK-NEXT: Type: SHT_PROGBITS |
deps/lld/test/ELF/merge.s+2-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/merge.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld %t.o %t2.o -o %t |
| 5 | // RUN: llvm-readobj -s -section-data -t %t | FileCheck %s | |
| 5 | // RUN: llvm-readobj -S --section-data --symbols %t | FileCheck %s | |
| 6 | 6 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s |
| 7 | 7 | |
| 8 | 8 | .section .mysec,"aM",@progbits,4 |
| ... | ... | @@ -72,6 +72,7 @@ zed: |
| 72 | 72 | .globl _start |
| 73 | 73 | _start: |
| 74 | 74 | // DISASM: Disassembly of section .text: |
| 75 | // DISASM-EMPTY: | |
| 75 | 76 | // DISASM-NEXT: _start: |
| 76 | 77 | |
| 77 | 78 | movl .mysec, %eax |
deps/lld/test/ELF/mips-26-mask.s+1| ... | ... | @@ -6,6 +6,7 @@ |
| 6 | 6 | # RUN: llvm-objdump -d %t.exe | FileCheck %s |
| 7 | 7 | |
| 8 | 8 | # CHECK: Disassembly of section .text: |
| 9 | # CHECK-EMPTY: | |
| 9 | 10 | # CHECK: __start: |
| 10 | 11 | # CHECK-NEXT: 20000: 0e 00 80 00 jal 134348800 |
| 11 | 12 |
deps/lld/test/ELF/mips-26-n32-n64.s deleted-40| ... | ... | @@ -1,40 +0,0 @@ |
| 1 | # REQUIRES: mips | |
| 2 | # Check R_MIPS_26 relocation handling in case of N64 ABIs. | |
| 3 | ||
| 4 | # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \ | |
| 5 | # RUN: %S/Inputs/mips-dynamic.s -o %t-so.o | |
| 6 | # RUN: ld.lld %t-so.o -shared -o %t.so | |
| 7 | # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o | |
| 8 | # RUN: ld.lld %t.o %t.so -o %t.exe | |
| 9 | # RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=CHECK,DEFAULT | |
| 10 | # RUN: ld.lld %t-so.o -shared -o %t.so -z hazardplt | |
| 11 | # RUN: ld.lld %t.o %t.so -o %t.exe -z hazardplt | |
| 12 | # RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=CHECK,HAZARDPLT | |
| 13 | ||
| 14 | ||
| 15 | # CHECK: Disassembly of section .text: | |
| 16 | # CHECK-NEXT: __start: | |
| 17 | # CHECK-NEXT: 20000: 0c 00 80 0c jal 131120 | |
| 18 | # CHECK-NEXT: 20004: 00 00 00 00 nop | |
| 19 | # CHECK-NEXT: Disassembly of section .plt: | |
| 20 | # CHECK-NEXT: .plt: | |
| 21 | # CHECK-NEXT: 20010: 3c 0e 00 03 lui $14, 3 | |
| 22 | # CHECK-NEXT: 20014: dd d9 00 08 ld $25, 8($14) | |
| 23 | # CHECK-NEXT: 20018: 25 ce 00 08 addiu $14, $14, 8 | |
| 24 | # CHECK-NEXT: 2001c: 03 0e c0 23 subu $24, $24, $14 | |
| 25 | # CHECK-NEXT: 20020: 03 e0 78 25 move $15, $ra | |
| 26 | # CHECK-NEXT: 20024: 00 18 c0 c2 srl $24, $24, 3 | |
| 27 | # DEFAULT: 20028: 03 20 f8 09 jalr $25 | |
| 28 | # HAZARDPLT: 20028: 03 20 fc 09 jalr.hb $25 | |
| 29 | # CHECK-NEXT: 2002c: 27 18 ff fe addiu $24, $24, -2 | |
| 30 | # CHECK-NEXT: 20030: 3c 0f 00 03 lui $15, 3 | |
| 31 | # CHECK-NEXT: 20034: 8d f9 00 18 lw $25, 24($15) | |
| 32 | # DEFAULT: 20038: 03 20 00 08 jr $25 | |
| 33 | # HAZARDPLT: 20038: 03 20 04 08 jr.hb $25 | |
| 34 | # CHECK-NEXT: 2003c: 25 f8 00 18 addiu $24, $15, 24 | |
| 35 | ||
| 36 | .text | |
| 37 | .option pic0 | |
| 38 | .global __start | |
| 39 | __start: | |
| 40 | jal foo0 |
deps/lld/test/ELF/mips-26.s+4-1| ... | ... | @@ -7,10 +7,11 @@ |
| 7 | 7 | # RUN: ld.lld %t2.o -shared -o %t.so |
| 8 | 8 | # RUN: ld.lld %t1.o %t.so -o %t.exe |
| 9 | 9 | # RUN: llvm-objdump -d %t.exe | FileCheck %s |
| 10 | # RUN: llvm-readobj -dynamic-table -s -r -mips-plt-got %t.exe \ | |
| 10 | # RUN: llvm-readobj --dynamic-table -S -r --mips-plt-got %t.exe \ | |
| 11 | 11 | # RUN: | FileCheck -check-prefix=REL %s |
| 12 | 12 | |
| 13 | 13 | # CHECK: Disassembly of section .text: |
| 14 | # CHECK-EMPTY: | |
| 14 | 15 | # CHECK-NEXT: bar: |
| 15 | 16 | # CHECK-NEXT: 20000: 0c 00 80 06 jal 131096 <loc> |
| 16 | 17 | # CHECK-NEXT: 20004: 00 00 00 00 nop |
| ... | ... | @@ -24,7 +25,9 @@ |
| 24 | 25 | # |
| 25 | 26 | # CHECK: loc: |
| 26 | 27 | # CHECK-NEXT: 20018: 00 00 00 00 nop |
| 28 | # CHECK-EMPTY: | |
| 27 | 29 | # CHECK-NEXT: Disassembly of section .plt: |
| 30 | # CHECK-EMPTY: | |
| 28 | 31 | # CHECK-NEXT: .plt: |
| 29 | 32 | # CHECK-NEXT: 20020: 3c 1c 00 03 lui $gp, 3 |
| 30 | 33 | # CHECK-NEXT: 20024: 8f 99 00 04 lw $25, 4($gp) |
deps/lld/test/ELF/mips-32.s+4-6| ... | ... | @@ -3,16 +3,14 @@ |
| 3 | 3 | |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o |
| 5 | 5 | # RUN: ld.lld -shared %t-be.o -o %t-be.so |
| 6 | # RUN: llvm-objdump -t -s %t-be.so \ | |
| 7 | # RUN: | FileCheck -check-prefix=SYM -check-prefix=BE %s | |
| 8 | # RUN: llvm-readobj -r -dynamic-table -mips-plt-got %t-be.so \ | |
| 6 | # RUN: llvm-objdump -t -s %t-be.so | FileCheck -check-prefixes=SYM,BE %s | |
| 7 | # RUN: llvm-readobj -r --dynamic-table --mips-plt-got %t-be.so \ | |
| 9 | 8 | # RUN: | FileCheck -check-prefix=REL %s |
| 10 | 9 | |
| 11 | 10 | # RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t-el.o |
| 12 | 11 | # RUN: ld.lld -shared %t-el.o -o %t-el.so |
| 13 | # RUN: llvm-objdump -t -s %t-el.so \ | |
| 14 | # RUN: | FileCheck -check-prefix=SYM -check-prefix=EL %s | |
| 15 | # RUN: llvm-readobj -r -dynamic-table -mips-plt-got %t-el.so \ | |
| 12 | # RUN: llvm-objdump -t -s %t-el.so | FileCheck -check-prefixes=SYM,EL %s | |
| 13 | # RUN: llvm-readobj -r --dynamic-table --mips-plt-got %t-el.so \ | |
| 16 | 14 | # RUN: | FileCheck -check-prefix=REL %s |
| 17 | 15 | |
| 18 | 16 | .globl __start |
deps/lld/test/ELF/mips-64-disp.s+19-54| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: ld.lld %t.so.o -shared -o %t.so |
| 8 | 8 | # RUN: ld.lld %t.exe.o %t.so -o %t.exe |
| 9 | 9 | # RUN: llvm-objdump -d -t %t.exe | FileCheck %s |
| 10 | # RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck -check-prefix=GOT %s | |
| 10 | # RUN: llvm-readelf -r --mips-plt-got %t.exe | FileCheck -check-prefix=GOT %s | |
| 11 | 11 | |
| 12 | 12 | # CHECK: __start: |
| 13 | 13 | # CHECK-NEXT: 20000: 24 42 80 40 addiu $2, $2, -32704 |
| ... | ... | @@ -20,59 +20,24 @@ |
| 20 | 20 | # CHECK: 0000000000020000 .text 00000000 __start |
| 21 | 21 | # CHECK: 0000000000000000 g F *UND* 00000000 foo1a |
| 22 | 22 | |
| 23 | # GOT: Relocations [ | |
| 24 | # GOT-NEXT: ] | |
| 25 | # GOT-NEXT: Primary GOT { | |
| 26 | # GOT-NEXT: Canonical gp value: | |
| 27 | # GOT-NEXT: Reserved entries [ | |
| 28 | # GOT-NEXT: Entry { | |
| 29 | # GOT-NEXT: Address: | |
| 30 | # GOT-NEXT: Access: -32752 | |
| 31 | # GOT-NEXT: Initial: 0x0 | |
| 32 | # GOT-NEXT: Purpose: Lazy resolver | |
| 33 | # GOT-NEXT: } | |
| 34 | # GOT-NEXT: Entry { | |
| 35 | # GOT-NEXT: Address: | |
| 36 | # GOT-NEXT: Access: -32744 | |
| 37 | # GOT-NEXT: Initial: 0x8000000000000000 | |
| 38 | # GOT-NEXT: Purpose: Module pointer (GNU extension) | |
| 39 | # GOT-NEXT: } | |
| 40 | # GOT-NEXT: ] | |
| 41 | # GOT-NEXT: Local entries [ | |
| 42 | # GOT-NEXT: Entry { | |
| 43 | # GOT-NEXT: Address: | |
| 44 | # GOT-NEXT: Access: -32736 | |
| 45 | # GOT-NEXT: Initial: 0x20014 | |
| 46 | # GOT-NEXT: } | |
| 47 | # GOT-NEXT: Entry { | |
| 48 | # GOT-NEXT: Address: | |
| 49 | # GOT-NEXT: Access: -32728 | |
| 50 | # GOT-NEXT: Initial: 0x20004 | |
| 51 | # GOT-NEXT: } | |
| 52 | # GOT-NEXT: Entry { | |
| 53 | # GOT-NEXT: Address: | |
| 54 | # GOT-NEXT: Access: -32720 | |
| 55 | # GOT-NEXT: Initial: 0x20008 | |
| 56 | # GOT-NEXT: } | |
| 57 | # GOT-NEXT: Entry { | |
| 58 | # GOT-NEXT: Address: | |
| 59 | # GOT-NEXT: Access: -32712 | |
| 60 | # GOT-NEXT: Initial: 0x2000C | |
| 61 | # GOT-NEXT: } | |
| 62 | # GOT-NEXT: ] | |
| 63 | # GOT-NEXT: Global entries [ | |
| 64 | # GOT-NEXT: Entry { | |
| 65 | # GOT-NEXT: Address: | |
| 66 | # GOT-NEXT: Access: -32704 | |
| 67 | # GOT-NEXT: Initial: 0x0 | |
| 68 | # GOT-NEXT: Value: 0x0 | |
| 69 | # GOT-NEXT: Type: Function | |
| 70 | # GOT-NEXT: Section: Undefined | |
| 71 | # GOT-NEXT: Name: foo1a | |
| 72 | # GOT-NEXT: } | |
| 73 | # GOT-NEXT: ] | |
| 74 | # GOT-NEXT: Number of TLS and multi-GOT entries: 0 | |
| 75 | # GOT-NEXT: } | |
| 23 | # GOT: Primary GOT: | |
| 24 | # GOT-NEXT: Canonical gp value: 0000000000038000 | |
| 25 | # GOT-EMPTY: | |
| 26 | # GOT-NEXT: Reserved entries: | |
| 27 | # GOT-NEXT: Address Access Initial Purpose | |
| 28 | # GOT-NEXT: 0000000000030010 -32752(gp) 0000000000000000 Lazy resolver | |
| 29 | # GOT-NEXT: 0000000000030018 -32744(gp) 8000000000000000 Module pointer (GNU extension) | |
| 30 | # GOT-EMPTY: | |
| 31 | # GOT-NEXT: Local entries: | |
| 32 | # GOT-NEXT: Address Access Initial | |
| 33 | # GOT-NEXT: 0000000000030020 -32736(gp) 0000000000020014 | |
| 34 | # GOT-NEXT: 0000000000030028 -32728(gp) 0000000000020004 | |
| 35 | # GOT-NEXT: 0000000000030030 -32720(gp) 0000000000020008 | |
| 36 | # GOT-NEXT: 0000000000030038 -32712(gp) 000000000002000c | |
| 37 | # GOT-EMPTY: | |
| 38 | # GOT-NEXT: Global entries: | |
| 39 | # GOT-NEXT: Address Access Initial Sym.Val. Type Ndx Name | |
| 40 | # GOT-NEXT: 0000000000030040 -32704(gp) 0000000000000000 0000000000000000 FUNC UND foo1a | |
| 76 | 41 | |
| 77 | 42 | .text |
| 78 | 43 | .global __start |
deps/lld/test/ELF/mips-64-got-overflow.s+27-61| ... | ... | @@ -6,69 +6,35 @@ |
| 6 | 6 | # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t2.so.o |
| 7 | 7 | # RUN: ld.lld -shared -mips-got-size 32 %t1.so.o %t2.so.o -o %t-sgot.so |
| 8 | 8 | # RUN: ld.lld -shared -mips-got-size 24 %t1.so.o %t2.so.o -o %t-mgot.so |
| 9 | # RUN: llvm-readobj -r -dt -mips-plt-got %t-sgot.so | FileCheck -check-prefix=SGOT %s | |
| 10 | # RUN: llvm-readobj -r -dt -mips-plt-got %t-mgot.so | FileCheck -check-prefix=MGOT %s | |
| 9 | # RUN: llvm-readelf --mips-plt-got %t-sgot.so | FileCheck -check-prefix=SGOT %s | |
| 10 | # RUN: llvm-readelf --mips-plt-got %t-mgot.so | FileCheck -check-prefix=MGOT %s | |
| 11 | 11 | |
| 12 | # SGOT: Primary GOT { | |
| 13 | # SGOT-NEXT: Canonical gp value: 0x27FF0 | |
| 14 | # SGOT-NEXT: Reserved entries [ | |
| 15 | # SGOT-NEXT: Entry { | |
| 16 | # SGOT-NEXT: Address: | |
| 17 | # SGOT-NEXT: Access: -32752 | |
| 18 | # SGOT-NEXT: Initial: 0x0 | |
| 19 | # SGOT-NEXT: Purpose: Lazy resolver | |
| 20 | # SGOT-NEXT: } | |
| 21 | # SGOT-NEXT: Entry { | |
| 22 | # SGOT-NEXT: Address: | |
| 23 | # SGOT-NEXT: Access: -32744 | |
| 24 | # SGOT-NEXT: Initial: 0x80000000 | |
| 25 | # SGOT-NEXT: Purpose: Module pointer (GNU extension) | |
| 26 | # SGOT-NEXT: } | |
| 27 | # SGOT-NEXT: ] | |
| 28 | # SGOT-NEXT: Local entries [ | |
| 29 | # SGOT-NEXT: Entry { | |
| 30 | # SGOT-NEXT: Address: | |
| 31 | # SGOT-NEXT: Access: -32736 | |
| 32 | # SGOT-NEXT: Initial: 0x20020 | |
| 33 | # SGOT-NEXT: } | |
| 34 | # SGOT-NEXT: Entry { | |
| 35 | # SGOT-NEXT: Address: | |
| 36 | # SGOT-NEXT: Access: -32728 | |
| 37 | # SGOT-NEXT: Initial: 0x20030 | |
| 38 | # SGOT-NEXT: } | |
| 39 | # SGOT-NEXT: ] | |
| 40 | # SGOT-NEXT: Global entries [ | |
| 41 | # SGOT-NEXT: ] | |
| 42 | # SGOT-NEXT: Number of TLS and multi-GOT entries: 0 | |
| 43 | # SGOT-NEXT: } | |
| 12 | # SGOT: Primary GOT: | |
| 13 | # SGOT-NEXT: Canonical gp value: 0000000000027ff0 | |
| 14 | # SGOT-EMPTY: | |
| 15 | # SGOT-NEXT: Reserved entries: | |
| 16 | # SGOT-NEXT: Address Access Initial Purpose | |
| 17 | # SGOT-NEXT: 0000000000020000 -32752(gp) 0000000000000000 Lazy resolver | |
| 18 | # SGOT-NEXT: 0000000000020008 -32744(gp) 8000000000000000 Module pointer (GNU extension) | |
| 19 | # SGOT-EMPTY: | |
| 20 | # SGOT-NEXT: Local entries: | |
| 21 | # SGOT-NEXT: Address Access Initial | |
| 22 | # SGOT-NEXT: 0000000000020010 -32736(gp) 0000000000020020 | |
| 23 | # SGOT-NEXT: 0000000000020018 -32728(gp) 0000000000020030 | |
| 44 | 24 | |
| 45 | # MGOT: Primary GOT { | |
| 46 | # MGOT-NEXT: Canonical gp value: 0x27FF0 | |
| 47 | # MGOT-NEXT: Reserved entries [ | |
| 48 | # MGOT-NEXT: Entry { | |
| 49 | # MGOT-NEXT: Address: | |
| 50 | # MGOT-NEXT: Access: -32752 | |
| 51 | # MGOT-NEXT: Initial: 0x0 | |
| 52 | # MGOT-NEXT: Purpose: Lazy resolver | |
| 53 | # MGOT-NEXT: } | |
| 54 | # MGOT-NEXT: Entry { | |
| 55 | # MGOT-NEXT: Address: | |
| 56 | # MGOT-NEXT: Access: -32744 | |
| 57 | # MGOT-NEXT: Initial: 0x80000000 | |
| 58 | # MGOT-NEXT: Purpose: Module pointer (GNU extension) | |
| 59 | # MGOT-NEXT: } | |
| 60 | # MGOT-NEXT: ] | |
| 61 | # MGOT-NEXT: Local entries [ | |
| 62 | # MGOT-NEXT: Entry { | |
| 63 | # MGOT-NEXT: Address: | |
| 64 | # MGOT-NEXT: Access: -32736 | |
| 65 | # MGOT-NEXT: Initial: 0x20020 | |
| 66 | # MGOT-NEXT: } | |
| 67 | # MGOT-NEXT: ] | |
| 68 | # MGOT-NEXT: Global entries [ | |
| 69 | # MGOT-NEXT: ] | |
| 70 | # MGOT-NEXT: Number of TLS and multi-GOT entries: 1 | |
| 71 | # MGOT-NEXT: } | |
| 25 | # MGOT: Primary GOT: | |
| 26 | # MGOT-NEXT: Canonical gp value: 0000000000027ff0 | |
| 27 | # MGOT-EMPTY: | |
| 28 | # MGOT-NEXT: Reserved entries: | |
| 29 | # MGOT-NEXT: Address Access Initial Purpose | |
| 30 | # MGOT-NEXT: 0000000000020000 -32752(gp) 0000000000000000 Lazy resolver | |
| 31 | # MGOT-NEXT: 0000000000020008 -32744(gp) 8000000000000000 Module pointer (GNU extension) | |
| 32 | # MGOT-EMPTY: | |
| 33 | # MGOT-NEXT: Local entries: | |
| 34 | # MGOT-NEXT: Address Access Initial | |
| 35 | # MGOT-NEXT: 0000000000020010 -32736(gp) 0000000000020020 | |
| 36 | # MGOT-EMPTY: | |
| 37 | # MGOT-NEXT: Number of TLS and multi-GOT entries 1 | |
| 72 | 38 | |
| 73 | 39 | .text |
| 74 | 40 | .global foo2 |
deps/lld/test/ELF/mips-64-got.s+20-54| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: ld.lld %t.so.o -shared -o %t.so |
| 8 | 8 | # RUN: ld.lld %t.exe.o %t.so -o %t.exe |
| 9 | 9 | # RUN: llvm-objdump -d -t %t.exe | FileCheck %s |
| 10 | # RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck -check-prefix=GOT %s | |
| 10 | # RUN: llvm-readelf -r --mips-plt-got %t.exe | FileCheck -check-prefix=GOT %s | |
| 11 | 11 | |
| 12 | 12 | # CHECK: __start: |
| 13 | 13 | |
| ... | ... | @@ -21,59 +21,25 @@ |
| 21 | 21 | # CHECK: 0000000000020000 .text 00000000 __start |
| 22 | 22 | # CHECK: 0000000000020014 .text 00000000 bar |
| 23 | 23 | |
| 24 | # GOT: Relocations [ | |
| 25 | # GOT-NEXT: ] | |
| 26 | # GOT-NEXT: Primary GOT { | |
| 27 | # GOT-NEXT: Canonical gp value: | |
| 28 | # GOT-NEXT: Reserved entries [ | |
| 29 | # GOT-NEXT: Entry { | |
| 30 | # GOT-NEXT: Address: | |
| 31 | # GOT-NEXT: Access: -32752 | |
| 32 | # GOT-NEXT: Initial: 0x0 | |
| 33 | # GOT-NEXT: Purpose: Lazy resolver | |
| 34 | # GOT-NEXT: } | |
| 35 | # GOT-NEXT: Entry { | |
| 36 | # GOT-NEXT: Address: | |
| 37 | # GOT-NEXT: Access: -32744 | |
| 38 | # GOT-NEXT: Initial: 0x8000000000000000 | |
| 39 | # GOT-NEXT: Purpose: Module pointer (GNU extension) | |
| 40 | # GOT-NEXT: } | |
| 41 | # GOT-NEXT: ] | |
| 42 | # GOT-NEXT: Local entries [ | |
| 43 | # GOT-NEXT: Entry { | |
| 44 | # GOT-NEXT: Address: | |
| 45 | # GOT-NEXT: Access: -32736 | |
| 46 | # GOT-NEXT: Initial: 0x20000 | |
| 47 | # GOT-NEXT: } | |
| 48 | # GOT-NEXT: Entry { | |
| 49 | # GOT-NEXT: Address: | |
| 50 | # GOT-NEXT: Access: -32728 | |
| 51 | # GOT-NEXT: Initial: 0x30000 | |
| 52 | # GOT-NEXT: } | |
| 53 | # GOT-NEXT: Entry { | |
| 54 | # GOT-NEXT: Address: | |
| 55 | # GOT-NEXT: Access: -32720 | |
| 56 | # GOT-NEXT: Initial: 0x20014 | |
| 57 | # GOT-NEXT: } | |
| 58 | # GOT-NEXT: Entry { | |
| 59 | # GOT-NEXT: Address: | |
| 60 | # GOT-NEXT: Access: -32712 | |
| 61 | # GOT-NEXT: Initial: 0x20018 | |
| 62 | # GOT-NEXT: } | |
| 63 | # GOT-NEXT: ] | |
| 64 | # GOT-NEXT: Global entries [ | |
| 65 | # GOT-NEXT: Entry { | |
| 66 | # GOT-NEXT: Address: | |
| 67 | # GOT-NEXT: Access: -32704 | |
| 68 | # GOT-NEXT: Initial: 0x0 | |
| 69 | # GOT-NEXT: Value: 0x0 | |
| 70 | # GOT-NEXT: Type: Function | |
| 71 | # GOT-NEXT: Section: Undefined | |
| 72 | # GOT-NEXT: Name: foo1a | |
| 73 | # GOT-NEXT: } | |
| 74 | # GOT-NEXT: ] | |
| 75 | # GOT-NEXT: Number of TLS and multi-GOT entries: 0 | |
| 76 | # GOT-NEXT: } | |
| 24 | # GOT: There are no relocations in this file. | |
| 25 | # GOT-NEXT: Primary GOT: | |
| 26 | # GOT-NEXT: Canonical gp value: 0000000000038000 | |
| 27 | # GOT-EMPTY: | |
| 28 | # GOT-NEXT: Reserved entries: | |
| 29 | # GOT-NEXT: Address Access Initial Purpose | |
| 30 | # GOT-NEXT: 0000000000030010 -32752(gp) 0000000000000000 Lazy resolver | |
| 31 | # GOT-NEXT: 0000000000030018 -32744(gp) 8000000000000000 Module pointer (GNU extension) | |
| 32 | # GOT-EMPTY: | |
| 33 | # GOT-NEXT: Local entries: | |
| 34 | # GOT-NEXT: Address Access Initial | |
| 35 | # GOT-NEXT: 0000000000030020 -32736(gp) 0000000000020000 | |
| 36 | # GOT-NEXT: 0000000000030028 -32728(gp) 0000000000030000 | |
| 37 | # GOT-NEXT: 0000000000030030 -32720(gp) 0000000000020014 | |
| 38 | # GOT-NEXT: 0000000000030038 -32712(gp) 0000000000020018 | |
| 39 | # GOT-EMPTY: | |
| 40 | # GOT-NEXT: Global entries: | |
| 41 | # GOT-NEXT: Address Access Initial Sym.Val. Type Ndx Name | |
| 42 | # GOT-NEXT: 0000000000030040 -32704(gp) 0000000000000000 0000000000000000 FUNC UND foo1a | |
| 77 | 43 | |
| 78 | 44 | .text |
| 79 | 45 | .global __start, bar |
deps/lld/test/ELF/mips-64-gprel-so.s+1| ... | ... | @@ -6,6 +6,7 @@ |
| 6 | 6 | # RUN: llvm-objdump -d -t %t.so | FileCheck %s |
| 7 | 7 | |
| 8 | 8 | # CHECK: Disassembly of section .text: |
| 9 | # CHECK-EMPTY: | |
| 9 | 10 | # CHECK-NEXT: foo: |
| 10 | 11 | # CHECK-NEXT: 10000: 3c 1c 00 01 lui $gp, 1 |
| 11 | 12 | # CHECK-NEXT: 10004: 03 99 e0 2d daddu $gp, $gp, $25 |
deps/lld/test/ELF/mips-64.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o |
| 5 | 5 | # RUN: ld.lld -shared %t.o -o %t.so |
| 6 | 6 | # RUN: llvm-objdump -t %t.so | FileCheck -check-prefix=SYM %s |
| 7 | # RUN: llvm-readobj -r -dynamic-table -mips-plt-got %t.so | FileCheck %s | |
| 7 | # RUN: llvm-readobj -r --dynamic-table --mips-plt-got %t.so | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | .global __start |
| 10 | 10 | __start: |
deps/lld/test/ELF/mips-abs-got.s+4-4| ... | ... | @@ -4,9 +4,9 @@ |
| 4 | 4 | |
| 5 | 5 | # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -o %t.o %s |
| 6 | 6 | # RUN: echo "SECTIONS { \ |
| 7 | # RUN: zero = 0; foo = 0x11004; bar = 0x22000; }" > %t.script | |
| 7 | # RUN: zero1 = 0; zero2 = 0; foo = 0x11004; bar = 0x22000; }" > %t.script | |
| 8 | 8 | # RUN: ld.lld --script %t.script -o %t.exe %t.o |
| 9 | # RUN: llvm-readobj -mips-plt-got %t.exe | FileCheck %s | |
| 9 | # RUN: llvm-readobj --mips-plt-got %t.exe | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | # CHECK: Static GOT { |
| 12 | 12 | # CHECK: Local entries [ |
| ... | ... | @@ -30,7 +30,7 @@ |
| 30 | 30 | |
| 31 | 31 | .text |
| 32 | 32 | nop |
| 33 | .reloc 0, R_MIPS_GOT_PAGE, 0 | |
| 34 | ld $v0, %got_page(zero)($gp) | |
| 33 | ld $v0, %got_page(zero1)($gp) | |
| 34 | ld $v0, %got_page(zero2)($gp) | |
| 35 | 35 | ld $v0, %got_page(foo)($gp) |
| 36 | 36 | ld $v0, %got_page(bar+0x10008)($gp) |
deps/lld/test/ELF/mips-call-hilo.s+19-31| ... | ... | @@ -4,9 +4,10 @@ |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o |
| 5 | 5 | # RUN: ld.lld %t.o -shared -o %t.so |
| 6 | 6 | # RUN: llvm-objdump -d %t.so | FileCheck %s |
| 7 | # RUN: llvm-readobj -r -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s | |
| 7 | # RUN: llvm-readelf -r --mips-plt-got %t.so | FileCheck -check-prefix=GOT %s | |
| 8 | 8 | |
| 9 | 9 | # CHECK: Disassembly of section .text: |
| 10 | # CHECK-EMPTY: | |
| 10 | 11 | # CHECK-NEXT: foo: |
| 11 | 12 | # CHECK-NEXT: 10000: 3c 02 00 00 lui $2, 0 |
| 12 | 13 | # CHECK-NEXT: 10004: 8c 42 80 20 lw $2, -32736($2) |
| ... | ... | @@ -15,36 +16,23 @@ |
| 15 | 16 | # CHECK-NEXT: 10010: 3c 02 00 00 lui $2, 0 |
| 16 | 17 | # CHECK-NEXT: 10014: 8c 42 80 1c lw $2, -32740($2) |
| 17 | 18 | |
| 18 | # GOT: Relocations [ | |
| 19 | # GOT-NEXT: ] | |
| 20 | ||
| 21 | # GOT: Primary GOT { | |
| 22 | # GOT-NEXT: Canonical gp value: 0x27FF0 | |
| 23 | # GOT: Local entries [ | |
| 24 | # GOT-NEXT: Entry { | |
| 25 | # GOT-NEXT: Address: 0x20008 | |
| 26 | # GOT-NEXT: Access: -32744 | |
| 27 | # GOT-NEXT: Initial: 0x10018 | |
| 28 | # GOT-NEXT: } | |
| 29 | # GOT-NEXT: Entry { | |
| 30 | # GOT-NEXT: Address: 0x2000C | |
| 31 | # GOT-NEXT: Access: -32740 | |
| 32 | # GOT-NEXT: Initial: 0x1001C | |
| 33 | # GOT-NEXT: } | |
| 34 | # GOT-NEXT: ] | |
| 35 | # GOT-NEXT: Global entries [ | |
| 36 | # GOT-NEXT: Entry { | |
| 37 | # GOT-NEXT: Address: 0x20010 | |
| 38 | # GOT-NEXT: Access: -32736 | |
| 39 | # GOT-NEXT: Initial: 0x0 | |
| 40 | # GOT-NEXT: Value: 0x0 | |
| 41 | # GOT-NEXT: Type: None | |
| 42 | # GOT-NEXT: Section: Undefined | |
| 43 | # GOT-NEXT: Name: bar | |
| 44 | # GOT-NEXT: } | |
| 45 | # GOT-NEXT: ] | |
| 46 | # GOT-NEXT: Number of TLS and multi-GOT entries: 0 | |
| 47 | # GOT-NEXT: } | |
| 19 | # GOT: There are no relocations in this file. | |
| 20 | # GOT: Primary GOT: | |
| 21 | # GOT-NEXT: Canonical gp value: 00027ff0 | |
| 22 | # GOT-EMPTY: | |
| 23 | # GOT-NEXT: Reserved entries: | |
| 24 | # GOT-NEXT: Address Access Initial Purpose | |
| 25 | # GOT-NEXT: 00020000 -32752(gp) 00000000 Lazy resolver | |
| 26 | # GOT-NEXT: 00020004 -32748(gp) 80000000 Module pointer (GNU extension) | |
| 27 | # GOT-EMPTY: | |
| 28 | # GOT-NEXT: Local entries: | |
| 29 | # GOT-NEXT: Address Access Initial | |
| 30 | # GOT-NEXT: 00020008 -32744(gp) 00010018 | |
| 31 | # GOT-NEXT: 0002000c -32740(gp) 0001001c | |
| 32 | # GOT-EMPTY: | |
| 33 | # GOT-NEXT: Global entries: | |
| 34 | # GOT-NEXT: Address Access Initial Sym.Val. Type Ndx Name | |
| 35 | # GOT-NEXT: 00020010 -32736(gp) 00000000 00000000 NOTYPE UND bar | |
| 48 | 36 | |
| 49 | 37 | .text |
| 50 | 38 | .global foo |
deps/lld/test/ELF/mips-call16.s+2-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o |
| 5 | 5 | # RUN: ld.lld %t.o -shared -o %t.exe |
| 6 | 6 | # RUN: llvm-objdump -d %t.exe | FileCheck %s |
| 7 | # RUN: llvm-readobj -mips-plt-got -symbols %t.exe \ | |
| 7 | # RUN: llvm-readobj --mips-plt-got --symbols %t.exe \ | |
| 8 | 8 | # RUN: | FileCheck -check-prefix=GOT %s |
| 9 | 9 | |
| 10 | 10 | .text |
| ... | ... | @@ -18,6 +18,7 @@ g1: |
| 18 | 18 | nop |
| 19 | 19 | |
| 20 | 20 | # CHECK: Disassembly of section .text: |
| 21 | # CHECK-EMPTY: | |
| 21 | 22 | # CHECK-NEXT: __start: |
| 22 | 23 | # CHECK-NEXT: 10000: 8f 88 80 18 lw $8, -32744 |
| 23 | 24 |
deps/lld/test/ELF/mips-dynamic.s+4-4| ... | ... | @@ -6,19 +6,19 @@ |
| 6 | 6 | # RUN: ld.lld -shared %td.o -o %td.so |
| 7 | 7 | |
| 8 | 8 | # RUN: ld.lld %t.o %td.so -o %t.exe |
| 9 | # RUN: llvm-readobj -sections -dynamic-table %t.exe \ | |
| 9 | # RUN: llvm-readobj --sections --dynamic-table %t.exe \ | |
| 10 | 10 | # RUN: | FileCheck -check-prefixes=EXE,NOPIE %s |
| 11 | 11 | |
| 12 | 12 | # RUN: ld.lld -pie %t.o %td.so -o %t.so |
| 13 | # RUN: llvm-readobj -sections -dyn-symbols -dynamic-table %t.so \ | |
| 13 | # RUN: llvm-readobj --sections --dyn-syms --dynamic-table %t.so \ | |
| 14 | 14 | # RUN: | FileCheck -check-prefixes=EXE,PIE %s |
| 15 | 15 | |
| 16 | 16 | # RUN: ld.lld %t.o --image-base=0x123000 %td.so -o %t.exe |
| 17 | # RUN: llvm-readobj -sections -dynamic-table %t.exe \ | |
| 17 | # RUN: llvm-readobj --sections --dynamic-table %t.exe \ | |
| 18 | 18 | # RUN: | FileCheck -check-prefix=IMAGE_BASE %s |
| 19 | 19 | |
| 20 | 20 | # RUN: ld.lld -shared %t.o %td.so -o %t.so |
| 21 | # RUN: llvm-readobj -sections -dyn-symbols -dynamic-table %t.so \ | |
| 21 | # RUN: llvm-readobj --sections --dyn-syms --dynamic-table %t.so \ | |
| 22 | 22 | # RUN: | FileCheck -check-prefix=DSO %s |
| 23 | 23 | |
| 24 | 24 | # EXE: Sections [ |
deps/lld/test/ELF/mips-dynsym-sort.s+2-2| ... | ... | @@ -3,11 +3,11 @@ |
| 3 | 3 | |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o |
| 5 | 5 | # RUN: ld.lld -shared %t-be.o -o %t-be.so |
| 6 | # RUN: llvm-readobj -symbols -dyn-symbols %t-be.so | FileCheck %s | |
| 6 | # RUN: llvm-readobj --symbols --dyn-syms %t-be.so | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | # RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t-el.o |
| 9 | 9 | # RUN: ld.lld -shared %t-el.o -o %t-el.so |
| 10 | # RUN: llvm-readobj -symbols -dyn-symbols %t-el.so | FileCheck %s | |
| 10 | # RUN: llvm-readobj --symbols --dyn-syms %t-el.so | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | .data |
| 13 | 13 | .globl v1,v2,v3 |
deps/lld/test/ELF/mips-elf-flags.s+7-7| ... | ... | @@ -4,16 +4,16 @@ |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ |
| 5 | 5 | # RUN: %S/Inputs/mips-dynamic.s -o %t-so.o |
| 6 | 6 | # RUN: ld.lld %t-so.o --gc-sections -shared -o %t.so |
| 7 | # RUN: llvm-readobj -h -mips-abi-flags %t.so | FileCheck -check-prefix=SO %s | |
| 7 | # RUN: llvm-readobj -h --mips-abi-flags %t.so | FileCheck -check-prefix=SO %s | |
| 8 | 8 | |
| 9 | 9 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o |
| 10 | 10 | # RUN: ld.lld %t.o -o %t.exe |
| 11 | # RUN: llvm-readobj -h -mips-abi-flags %t.exe | FileCheck -check-prefix=EXE %s | |
| 11 | # RUN: llvm-readobj -h --mips-abi-flags %t.exe | FileCheck -check-prefix=EXE %s | |
| 12 | 12 | |
| 13 | 13 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ |
| 14 | 14 | # RUN: -mcpu=mips32r2 %s -o %t-r2.o |
| 15 | 15 | # RUN: ld.lld %t-r2.o -o %t-r2.exe |
| 16 | # RUN: llvm-readobj -h -mips-abi-flags %t-r2.exe \ | |
| 16 | # RUN: llvm-readobj -h --mips-abi-flags %t-r2.exe \ | |
| 17 | 17 | # RUN: | FileCheck -check-prefix=EXE-R2 %s |
| 18 | 18 | |
| 19 | 19 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ |
| ... | ... | @@ -21,26 +21,26 @@ |
| 21 | 21 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ |
| 22 | 22 | # RUN: -mcpu=mips32r5 %S/Inputs/mips-dynamic.s -o %t-r5.o |
| 23 | 23 | # RUN: ld.lld %t-r2.o %t-r5.o -o %t-r5.exe |
| 24 | # RUN: llvm-readobj -h -mips-abi-flags %t-r5.exe \ | |
| 24 | # RUN: llvm-readobj -h --mips-abi-flags %t-r5.exe \ | |
| 25 | 25 | # RUN: | FileCheck -check-prefix=EXE-R5 %s |
| 26 | 26 | |
| 27 | 27 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ |
| 28 | 28 | # RUN: -mcpu=mips32r6 %s -o %t-r6.o |
| 29 | 29 | # RUN: ld.lld %t-r6.o -o %t-r6.exe |
| 30 | # RUN: llvm-readobj -h -mips-abi-flags %t-r6.exe \ | |
| 30 | # RUN: llvm-readobj -h --mips-abi-flags %t-r6.exe \ | |
| 31 | 31 | # RUN: | FileCheck -check-prefix=EXE-R6 %s |
| 32 | 32 | |
| 33 | 33 | # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \ |
| 34 | 34 | # RUN: -position-independent -mcpu=octeon %s -o %t.o |
| 35 | 35 | # RUN: ld.lld %t.o -o %t.exe |
| 36 | # RUN: llvm-readobj -h -mips-abi-flags %t.exe \ | |
| 36 | # RUN: llvm-readobj -h --mips-abi-flags %t.exe \ | |
| 37 | 37 | # RUN: | FileCheck -check-prefix=OCTEON %s |
| 38 | 38 | |
| 39 | 39 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o |
| 40 | 40 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ |
| 41 | 41 | # RUN: -mattr=micromips %S/Inputs/mips-fpic.s -o %t-mm.o |
| 42 | 42 | # RUN: ld.lld %t.o %t-mm.o -o %t.exe |
| 43 | # RUN: llvm-readobj -h -mips-abi-flags %t.exe | FileCheck -check-prefix=MICRO %s | |
| 43 | # RUN: llvm-readobj -h --mips-abi-flags %t.exe | FileCheck -check-prefix=MICRO %s | |
| 44 | 44 | |
| 45 | 45 | .text |
| 46 | 46 | .globl __start |
deps/lld/test/ELF/mips-got-and-copy.s+1-1| ... | ... | @@ -10,7 +10,7 @@ |
| 10 | 10 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o |
| 11 | 11 | # RUN: ld.lld %t.so.o -shared -o %t.so |
| 12 | 12 | # RUN: ld.lld %t.o %t.so -o %t.exe |
| 13 | # RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s | |
| 13 | # RUN: llvm-readobj -r --mips-plt-got %t.exe | FileCheck %s | |
| 14 | 14 | |
| 15 | 15 | # CHECK: Relocations [ |
| 16 | 16 | # CHECK-NEXT: Section (7) .rel.dyn { |
deps/lld/test/ELF/mips-got-extsym.s+1-1| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | # RUN: ld.lld -shared %t.so.o -o %t.so |
| 10 | 10 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o |
| 11 | 11 | # RUN: ld.lld %t.o %t.so -o %t.exe |
| 12 | # RUN: llvm-readobj -dt -t -mips-plt-got %t.exe | FileCheck %s | |
| 12 | # RUN: llvm-readobj --dyn-syms --symbols --mips-plt-got %t.exe | FileCheck %s | |
| 13 | 13 | |
| 14 | 14 | # CHECK: Symbols [ |
| 15 | 15 | # CHECK: Symbol { |
deps/lld/test/ELF/mips-got-hilo.s+2-1| ... | ... | @@ -4,9 +4,10 @@ |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o |
| 5 | 5 | # RUN: ld.lld %t.o -shared -o %t.so |
| 6 | 6 | # RUN: llvm-objdump -d %t.so | FileCheck %s |
| 7 | # RUN: llvm-readobj -r -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s | |
| 7 | # RUN: llvm-readobj -r --mips-plt-got %t.so | FileCheck -check-prefix=GOT %s | |
| 8 | 8 | |
| 9 | 9 | # CHECK: Disassembly of section .text: |
| 10 | # CHECK-EMPTY: | |
| 10 | 11 | # CHECK-NEXT: foo: |
| 11 | 12 | # CHECK-NEXT: 10000: 3c 02 00 00 lui $2, 0 |
| 12 | 13 | # CHECK-NEXT: 10004: 8c 42 80 20 lw $2, -32736($2) |
deps/lld/test/ELF/mips-got-page-script.s+1-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: .text : { *(.text) } \ |
| 8 | 8 | # RUN: .data 0x10000 : { *(.data) } }" > %t.script |
| 9 | 9 | # RUN: ld.lld -shared --script %t.script -o %t.so %t.o |
| 10 | # RUN: llvm-readobj -t -mips-plt-got %t.so | FileCheck %s | |
| 10 | # RUN: llvm-readobj --symbols --mips-plt-got %t.so | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | # CHECK: Name: foo1 |
| 13 | 13 | # CHECK-NEXT: Value: 0x10000 |
deps/lld/test/ELF/mips-got-page.s+1-1| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | |
| 6 | 6 | # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -o %t.o %s |
| 7 | 7 | # RUN: ld.lld --section-start .rodata=0x27FFC -shared -o %t.so %t.o |
| 8 | # RUN: llvm-readobj -t -mips-plt-got %t.so | FileCheck %s | |
| 8 | # RUN: llvm-readobj --symbols --mips-plt-got %t.so | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | # CHECK: Name: bar |
| 11 | 11 | # CHECK-NEXT: Value: 0x28000 |
deps/lld/test/ELF/mips-got-redundant.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o |
| 5 | 5 | # RUN: ld.lld %t.o -shared -o %t.so |
| 6 | # RUN: llvm-readobj -mips-plt-got %t.so | FileCheck %s | |
| 6 | # RUN: llvm-readobj --mips-plt-got %t.so | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | # CHECK: Local entries [ |
| 9 | 9 | # CHECK-NEXT: Entry { |
deps/lld/test/ELF/mips-got-relocs.s+41-74| ... | ... | @@ -3,33 +3,25 @@ |
| 3 | 3 | |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o |
| 5 | 5 | # RUN: ld.lld %t-be.o -o %t-be.exe |
| 6 | # RUN: llvm-objdump -section-headers -t %t-be.exe | FileCheck -check-prefix=EXE_SYM %s | |
| 7 | # RUN: llvm-objdump -s -section=.got %t-be.exe | FileCheck -check-prefix=EXE_GOT_BE %s | |
| 8 | # RUN: llvm-objdump -d %t-be.exe | FileCheck -check-prefix=EXE_DIS_BE %s | |
| 9 | # RUN: llvm-readobj -relocations %t-be.exe | FileCheck -check-prefix=NORELOC %s | |
| 10 | # RUN: llvm-readobj -sections %t-be.exe | FileCheck -check-prefix=SHFLAGS %s | |
| 6 | # RUN: llvm-readobj --sections -r --symbols --mips-plt-got %t-be.exe \ | |
| 7 | # RUN: | FileCheck -check-prefixes=ELF,EXE %s | |
| 8 | # RUN: llvm-objdump -d %t-be.exe | FileCheck -check-prefix=DIS %s | |
| 11 | 9 | |
| 12 | 10 | # RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t-el.o |
| 13 | 11 | # RUN: ld.lld %t-el.o -o %t-el.exe |
| 14 | # RUN: llvm-objdump -section-headers -t %t-el.exe | FileCheck -check-prefix=EXE_SYM %s | |
| 15 | # RUN: llvm-objdump -s -section=.got %t-el.exe | FileCheck -check-prefix=EXE_GOT_EL %s | |
| 16 | # RUN: llvm-objdump -d %t-el.exe | FileCheck -check-prefix=EXE_DIS_EL %s | |
| 17 | # RUN: llvm-readobj -relocations %t-el.exe | FileCheck -check-prefix=NORELOC %s | |
| 18 | # RUN: llvm-readobj -sections %t-el.exe | FileCheck -check-prefix=SHFLAGS %s | |
| 12 | # RUN: llvm-readobj --sections -r --symbols --mips-plt-got %t-el.exe \ | |
| 13 | # RUN: | FileCheck -check-prefixes=ELF,EXE %s | |
| 14 | # RUN: llvm-objdump -d %t-el.exe | FileCheck -check-prefix=DIS %s | |
| 19 | 15 | |
| 20 | 16 | # RUN: ld.lld -shared %t-be.o -o %t-be.so |
| 21 | # RUN: llvm-objdump -section-headers -t %t-be.so | FileCheck -check-prefix=DSO_SYM %s | |
| 22 | # RUN: llvm-objdump -s -section=.got %t-be.so | FileCheck -check-prefix=DSO_GOT_BE %s | |
| 23 | # RUN: llvm-objdump -d %t-be.so | FileCheck -check-prefix=DSO_DIS_BE %s | |
| 24 | # RUN: llvm-readobj -relocations %t-be.so | FileCheck -check-prefix=NORELOC %s | |
| 25 | # RUN: llvm-readobj -sections %t-be.so | FileCheck -check-prefix=SHFLAGS %s | |
| 17 | # RUN: llvm-readobj --sections -r --symbols --mips-plt-got %t-be.so \ | |
| 18 | # RUN: | FileCheck -check-prefixes=ELF,DSO %s | |
| 19 | # RUN: llvm-objdump -d %t-be.so | FileCheck -check-prefix=DIS %s | |
| 26 | 20 | |
| 27 | 21 | # RUN: ld.lld -shared %t-el.o -o %t-el.so |
| 28 | # RUN: llvm-objdump -section-headers -t %t-el.so | FileCheck -check-prefix=DSO_SYM %s | |
| 29 | # RUN: llvm-objdump -s -section=.got %t-el.so | FileCheck -check-prefix=DSO_GOT_EL %s | |
| 30 | # RUN: llvm-objdump -d %t-el.so | FileCheck -check-prefix=DSO_DIS_EL %s | |
| 31 | # RUN: llvm-readobj -relocations %t-el.so | FileCheck -check-prefix=NORELOC %s | |
| 32 | # RUN: llvm-readobj -sections %t-el.so | FileCheck -check-prefix=SHFLAGS %s | |
| 22 | # RUN: llvm-readobj --sections -r --symbols --mips-plt-got %t-el.so \ | |
| 23 | # RUN: | FileCheck -check-prefixes=ELF,DSO %s | |
| 24 | # RUN: llvm-objdump -d %t-el.so | FileCheck -check-prefix=DIS %s | |
| 33 | 25 | |
| 34 | 26 | .text |
| 35 | 27 | .globl __start |
| ... | ... | @@ -43,57 +35,32 @@ __start: |
| 43 | 35 | v1: |
| 44 | 36 | .word 0 |
| 45 | 37 | |
| 46 | # EXE_SYM: Sections: | |
| 47 | # EXE_SYM: .got 0000000c 0000000000030010 DATA | |
| 48 | # EXE_SYM: SYMBOL TABLE: | |
| 49 | # EXE_SYM: 00038000 .got 00000000 .hidden _gp | |
| 50 | # ^-- .got + GP offset (0x7ff0) | |
| 51 | # EXE_SYM: 00030000 g O .data		 00000004 v1 | |
| 52 | ||
| 53 | ||
| 54 | # EXE_GOT_BE: Contents of section .got: | |
| 55 | # EXE_GOT_BE: 30010 00000000 80000000 00030000 | |
| 56 | # ^ ^ ^-- v1 (0x30000) | |
| 57 | # | +-- Module pointer (0x80000000) | |
| 58 | # +-- Lazy resolver (0x0) | |
| 59 | ||
| 60 | # EXE_GOT_EL: Contents of section .got: | |
| 61 | # EXE_GOT_EL: 30010 00000000 00000080 00000300 | |
| 62 | # ^ ^ ^-- v1 (0x30000) | |
| 63 | # | +-- Module pointer (0x80000000) | |
| 64 | # +-- Lazy resolver (0x0) | |
| 65 | ||
| 66 | # v1GotAddr (0x3000c) - _gp (0x37ff4) = -0x7fe8 => 0x8018 = 32792 | |
| 67 | # EXE_DIS_BE: 20000: 3c 02 80 18 lui $2, 32792 | |
| 68 | # EXE_DIS_EL: 20000: 18 80 02 3c lui $2, 32792 | |
| 69 | ||
| 70 | # DSO_SYM: Sections: | |
| 71 | # DSO_SYM: .got 0000000c 0000000000020010 DATA | |
| 72 | # DSO_SYM: SYMBOL TABLE: | |
| 73 | # DSO_SYM: 00028000 .got 00000000 .hidden _gp | |
| 74 | # ^-- .got + GP offset (0x7ff0) | |
| 75 | # DSO_SYM: 00020000 g O .data		 00000004 v1 | |
| 76 | ||
| 77 | # DSO_GOT_BE: Contents of section .got: | |
| 78 | # DSO_GOT_BE: 20010 00000000 80000000 00020000 | |
| 79 | # ^ ^ ^-- v1 (0x20000) | |
| 80 | # | +-- Module pointer (0x80000000) | |
| 81 | # +-- Lazy resolver (0x0) | |
| 82 | ||
| 83 | # DSO_GOT_EL: Contents of section .got: | |
| 84 | # DSO_GOT_EL: 20010 00000000 00000080 00000200 | |
| 85 | # ^ ^ ^-- v1 (0x20000) | |
| 86 | # | +-- Module pointer (0x80000000) | |
| 87 | # +-- Lazy resolver (0x0) | |
| 88 | ||
| 89 | # v1GotAddr (0x2000c) - _gp (0x27ff4) = -0x7fe8 => 0x8018 = 32792 | |
| 90 | # DSO_DIS_BE: 10000: 3c 02 80 18 lui $2, 32792 | |
| 91 | # DSO_DIS_EL: 10000: 18 80 02 3c lui $2, 32792 | |
| 92 | ||
| 93 | # NORELOC: Relocations [ | |
| 94 | # NORELOC-NEXT: ] | |
| 95 | ||
| 96 | # SHFLAGS: Name: .got | |
| 97 | # SHFLAGS-NEXT: Type: SHT_PROGBITS | |
| 98 | # SHFLAGS-NEXT: Flags [ (0x10000003) | |
| 99 | # ^-- SHF_MIPS_GPREL | SHF_ALLOC | SHF_WRITE | |
| 38 | # ELF: Section { | |
| 39 | # ELF: Name: .got | |
| 40 | # ELF: Flags [ | |
| 41 | # ELF-NEXT: SHF_ALLOC | |
| 42 | # ELF-NEXT: SHF_MIPS_GPREL | |
| 43 | # ELF-NEXT: SHF_WRITE | |
| 44 | # ELF-NEXT: ] | |
| 45 | # | |
| 46 | # ELF: Relocations [ | |
| 47 | # ELF-NEXT: ] | |
| 48 | # | |
| 49 | # ELF: Symbol { | |
| 50 | # ELF: Name: v1 | |
| 51 | # ELF-NEXT: Value: 0x[[V1:[0-9A-F]+]] | |
| 52 | # | |
| 53 | # ELF: {{.*}} GOT { | |
| 54 | # EXE-NEXT: Canonical gp value: 0x38000 | |
| 55 | # DSO-NEXT: Canonical gp value: 0x28000 | |
| 56 | # | |
| 57 | # ELF: Entry { | |
| 58 | # EXE: Address: 0x30018 | |
| 59 | # DSO: Address: 0x20018 | |
| 60 | # ELF-NEXT: Access: -32744 | |
| 61 | # ELF-NEXT: Initial: 0x[[V1]] | |
| 62 | ||
| 63 | # "v1 GOT entry address" - _gp | |
| 64 | # exe: 0x30018 - 0x38000 = -0x7fe8 == 0x8018 == 32792 | |
| 65 | # dso: 0x20018 - 0x28000 = -0x7fe8 == 0x8018 == 32792 | |
| 66 | # DIS: {{.*}} lui $2, 32792 |
deps/lld/test/ELF/mips-got-script.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o |
| 5 | 5 | # RUN: echo "SECTIONS { .data : { *(.data.1); . += 0x10000; *(.data.2) } }" > %t.script |
| 6 | 6 | # RUN: ld.lld %t.o -shared -o %t.so -T %t.script |
| 7 | # RUN: llvm-readobj -mips-plt-got -dynamic-table %t.so | FileCheck %s | |
| 7 | # RUN: llvm-readobj --mips-plt-got --dynamic-table %t.so | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | # CHECK: 0x7000000A MIPS_LOCAL_GOTNO 4 |
| 10 | 10 | # ^-- 2 * header + 2 local entries |
deps/lld/test/ELF/mips-got-string.s+5-13| ... | ... | @@ -3,20 +3,12 @@ |
| 3 | 3 | |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -o %t.o %s |
| 5 | 5 | # RUN: ld.lld -shared -o %t.so %t.o |
| 6 | # RUN: llvm-readobj -t -mips-plt-got %t.so | FileCheck %s | |
| 6 | # RUN: llvm-readelf --mips-plt-got %t.so | FileCheck %s | |
| 7 | 7 | |
| 8 | # CHECK: Symbol { | |
| 9 | # CHECK: Name: $.str | |
| 10 | # CHECK-NEXT: Value: 0x1B1 | |
| 11 | # CHECK: } | |
| 12 | ||
| 13 | # CHECK: Local entries [ | |
| 14 | # CHECK-NEXT: Entry { | |
| 15 | # CHECK-NEXT: Address: | |
| 16 | # CHECK-NEXT: Access: -32744 | |
| 17 | # CHECK-NEXT: Initial: 0x0 | |
| 18 | # CHECK: } | |
| 19 | # CHECK: ] | |
| 8 | # CHECK: Local entries: | |
| 9 | # CHECK-NEXT: Address Access Initial | |
| 10 | # CHECK-NEXT: {{[0-9a-f]+}} -32744(gp) 00000000 | |
| 11 | # CHECK-NEXT: {{[0-9a-f]+}} -32740(gp) 00010000 | |
| 20 | 12 | |
| 21 | 13 | .text |
| 22 | 14 | lw $t9, %got($.str)($gp) |
deps/lld/test/ELF/mips-got-weak.s+2-2| ... | ... | @@ -3,10 +3,10 @@ |
| 3 | 3 | |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o |
| 5 | 5 | # RUN: ld.lld %t.o -shared -o %t1.so |
| 6 | # RUN: llvm-readobj -r -dt -dynamic-table -mips-plt-got %t1.so \ | |
| 6 | # RUN: llvm-readobj -r --dyn-syms --dynamic-table --mips-plt-got %t1.so \ | |
| 7 | 7 | # RUN: | FileCheck -check-prefixes=CHECK,NOSYM %s |
| 8 | 8 | # RUN: ld.lld %t.o -shared -Bsymbolic -o %t2.so |
| 9 | # RUN: llvm-readobj -r -dt -dynamic-table -mips-plt-got %t2.so \ | |
| 9 | # RUN: llvm-readobj -r --dyn-syms --dynamic-table --mips-plt-got %t2.so \ | |
| 10 | 10 | # RUN: | FileCheck -check-prefixes=CHECK,SYM %s |
| 11 | 11 | |
| 12 | 12 | # CHECK: Relocations [ |
deps/lld/test/ELF/mips-got16-relocatable.s+2| ... | ... | @@ -9,6 +9,7 @@ |
| 9 | 9 | # RUN: llvm-objdump -d %t.so | FileCheck -check-prefix=SO %s |
| 10 | 10 | |
| 11 | 11 | # OBJ: Disassembly of section .text: |
| 12 | # OBJ-EMPTY: | |
| 12 | 13 | # OBJ-NEXT: .text: |
| 13 | 14 | # OBJ-NEXT: 0: 8f 99 00 00 lw $25, 0($gp) |
| 14 | 15 | # OBJ-NEXT: 00000000: R_MIPS_GOT16 .data |
| ... | ... | @@ -20,6 +21,7 @@ |
| 20 | 21 | # OBJ-NEXT: 00000014: R_MIPS_LO16 .data |
| 21 | 22 | |
| 22 | 23 | # SO: Disassembly of section .text: |
| 24 | # SO-EMPTY: | |
| 23 | 25 | # SO-NEXT: .text: |
| 24 | 26 | # SO-NEXT: 10000: 8f 99 80 18 lw $25, -32744($gp) |
| 25 | 27 | # SO-NEXT: 10004: 27 24 00 00 addiu $4, $25, 0 |
deps/lld/test/ELF/mips-got16.s+24-77| ... | ... | @@ -4,9 +4,10 @@ |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o |
| 5 | 5 | # RUN: ld.lld %t.o -shared -o %t.so |
| 6 | 6 | # RUN: llvm-objdump -d -t %t.so | FileCheck %s |
| 7 | # RUN: llvm-readobj -r -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s | |
| 7 | # RUN: llvm-readelf -r --mips-plt-got %t.so | FileCheck -check-prefix=GOT %s | |
| 8 | 8 | |
| 9 | 9 | # CHECK: Disassembly of section .text: |
| 10 | # CHECK-EMPTY: | |
| 10 | 11 | # CHECK-NEXT: __start: |
| 11 | 12 | # CHECK-NEXT: 10000: 8f 88 80 18 lw $8, -32744($gp) |
| 12 | 13 | # CHECK-NEXT: 10004: 21 08 00 2c addi $8, $8, 44 |
| ... | ... | @@ -24,83 +25,29 @@ |
| 24 | 25 | # CHECK: 00041008 .data 00000000 .hidden bar |
| 25 | 26 | # CHECK: 00000000 *UND* 00000000 foo |
| 26 | 27 | |
| 27 | # GOT: Relocations [ | |
| 28 | # GOT-NEXT: ] | |
| 28 | # GOT: There are no relocations in this file. | |
| 29 | 29 | |
| 30 | # GOT: Primary GOT { | |
| 31 | # GOT-NEXT: Canonical gp value: | |
| 32 | # GOT-NEXT: Reserved entries [ | |
| 33 | # GOT-NEXT: Entry { | |
| 34 | # GOT-NEXT: Address: | |
| 35 | # GOT-NEXT: Access: -32752 | |
| 36 | # GOT-NEXT: Initial: 0x0 | |
| 37 | # GOT-NEXT: Purpose: Lazy resolver | |
| 38 | # GOT-NEXT: } | |
| 39 | # GOT-NEXT: Entry { | |
| 40 | # GOT-NEXT: Address: | |
| 41 | # GOT-NEXT: Access: -32748 | |
| 42 | # GOT-NEXT: Initial: 0x80000000 | |
| 43 | # GOT-NEXT: Purpose: Module pointer (GNU extension) | |
| 44 | # GOT-NEXT: } | |
| 45 | # GOT-NEXT: ] | |
| 46 | # GOT-NEXT: Local entries [ | |
| 47 | # GOT-NEXT: Entry { | |
| 48 | # GOT-NEXT: Address: | |
| 49 | # GOT-NEXT: Access: -32744 | |
| 50 | # GOT-NEXT: Initial: 0x10000 | |
| 51 | # ^-- (0x1002c + 0x8000) & ~0xffff | |
| 52 | # GOT-NEXT: } | |
| 53 | # GOT-NEXT: Entry { | |
| 54 | # GOT-NEXT: Address: | |
| 55 | # GOT-NEXT: Access: -32740 | |
| 56 | # GOT-NEXT: Initial: 0x20000 | |
| 57 | # ^-- redundant unused entry | |
| 58 | # GOT-NEXT: } | |
| 59 | # GOT-NEXT: Entry { | |
| 60 | # GOT-NEXT: Address: | |
| 61 | # GOT-NEXT: Access: -32736 | |
| 62 | # GOT-NEXT: Initial: 0x20000 | |
| 63 | # ^-- redundant unused entry | |
| 64 | # GOT-NEXT: } | |
| 65 | # GOT-NEXT: Entry { | |
| 66 | # GOT-NEXT: Address: | |
| 67 | # GOT-NEXT: Access: -32732 | |
| 68 | # GOT-NEXT: Initial: 0x30000 | |
| 69 | # ^-- (0x29000 + 0x8000) & ~0xffff | |
| 70 | # GOT-NEXT: } | |
| 71 | # GOT-NEXT: Entry { | |
| 72 | # GOT-NEXT: Address: | |
| 73 | # GOT-NEXT: Access: -32728 | |
| 74 | # GOT-NEXT: Initial: 0x40000 | |
| 75 | # ^-- (0x29000 + 0x10004 + 0x8000) & ~0xffff | |
| 76 | # ^-- (0x29000 + 0x18004 + 0x8000) & ~0xffff | |
| 77 | # GOT-NEXT: } | |
| 78 | # GOT-NEXT: Entry { | |
| 79 | # GOT-NEXT: Address: | |
| 80 | # GOT-NEXT: Access: -32724 | |
| 81 | # GOT-NEXT: Initial: 0x50000 | |
| 82 | # ^-- redundant unused entry | |
| 83 | # GOT-NEXT: } | |
| 84 | # GOT-NEXT: Entry { | |
| 85 | # GOT-NEXT: Address: | |
| 86 | # GOT-NEXT: Access: -32720 | |
| 87 | # GOT-NEXT: Initial: 0x41008 | |
| 88 | # ^-- 'bar' address | |
| 89 | # GOT-NEXT: } | |
| 90 | # GOT-NEXT: ] | |
| 91 | # GOT-NEXT: Global entries [ | |
| 92 | # GOT-NEXT: Entry { | |
| 93 | # GOT-NEXT: Address: | |
| 94 | # GOT-NEXT: Access: -32716 | |
| 95 | # GOT-NEXT: Initial: 0x0 | |
| 96 | # GOT-NEXT: Value: 0x0 | |
| 97 | # GOT-NEXT: Type: None | |
| 98 | # GOT-NEXT: Section: Undefined | |
| 99 | # GOT-NEXT: Name: foo | |
| 100 | # GOT-NEXT: } | |
| 101 | # GOT-NEXT: ] | |
| 102 | # GOT-NEXT: Number of TLS and multi-GOT entries: 0 | |
| 103 | # GOT-NEXT: } | |
| 30 | # GOT: Local entries: | |
| 31 | # GOT-NEXT: Address Access Initial | |
| 32 | # GOT-NEXT: 00041018 -32744(gp) 00010000 | |
| 33 | # ^-- (0x1002c + 0x8000) & ~0xffff | |
| 34 | # GOT-NEXT: 0004101c -32740(gp) 00020000 | |
| 35 | # ^-- redundant unused entry | |
| 36 | # GOT-NEXT: 00041020 -32736(gp) 00020000 | |
| 37 | # ^-- redundant unused entry | |
| 38 | # GOT-NEXT: 00041024 -32732(gp) 00030000 | |
| 39 | # ^-- (0x29000 + 0x8000) & ~0xffff | |
| 40 | # GOT-NEXT: 00041028 -32728(gp) 00040000 | |
| 41 | # ^-- (0x29000 + 0x10004 + 0x8000) & ~0xffff | |
| 42 | # ^-- (0x29000 + 0x18004 + 0x8000) & ~0xffff | |
| 43 | # GOT-NEXT: 0004102c -32724(gp) 00050000 | |
| 44 | # ^-- redundant unused entry | |
| 45 | # GOT-NEXT: 00041030 -32720(gp) 00041008 | |
| 46 | # ^-- 'bar' address | |
| 47 | # GOT-EMPTY: | |
| 48 | # GOT-NEXT: Global entries: | |
| 49 | # GOT-NEXT: Address Access Initial Sym.Val. Type Ndx Name | |
| 50 | # GOT-NEXT: 00041034 -32716(gp) 00000000 00000000 NOTYPE UND foo | |
| 104 | 51 | |
| 105 | 52 | .text |
| 106 | 53 | .globl __start |
deps/lld/test/ELF/mips-gp-disp.s+4-3| ... | ... | @@ -4,11 +4,11 @@ |
| 4 | 4 | |
| 5 | 5 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o |
| 6 | 6 | # RUN: ld.lld -shared -o %t.so %t.o %S/Inputs/mips-gp-disp.so |
| 7 | # RUN: llvm-readobj -symbols %t.so | FileCheck -check-prefix=INT-SO %s | |
| 8 | # RUN: llvm-readobj -symbols %S/Inputs/mips-gp-disp.so \ | |
| 7 | # RUN: llvm-readobj --symbols %t.so | FileCheck -check-prefix=INT-SO %s | |
| 8 | # RUN: llvm-readobj --symbols %S/Inputs/mips-gp-disp.so \ | |
| 9 | 9 | # RUN: | FileCheck -check-prefix=EXT-SO %s |
| 10 | 10 | # RUN: llvm-objdump -d -t %t.so | FileCheck -check-prefix=DIS %s |
| 11 | # RUN: llvm-readobj -relocations %t.so | FileCheck -check-prefix=REL %s | |
| 11 | # RUN: llvm-readobj -r %t.so | FileCheck -check-prefix=REL %s | |
| 12 | 12 | |
| 13 | 13 | # INT-SO: Name: _gp_disp |
| 14 | 14 | # INT-SO-NEXT: Value: |
| ... | ... | @@ -19,6 +19,7 @@ |
| 19 | 19 | # EXT-SO-NEXT: Value: 0x20000 |
| 20 | 20 | |
| 21 | 21 | # DIS: Disassembly of section .text: |
| 22 | # DIS-EMPTY: | |
| 22 | 23 | # DIS-NEXT: __start: |
| 23 | 24 | # DIS-NEXT: 10000: 3c 08 00 01 lui $8, 1 |
| 24 | 25 | # DIS-NEXT: 10004: 21 08 7f f0 addi $8, $8, 32752 |
deps/lld/test/ELF/mips-gp-local.s+1| ... | ... | @@ -6,6 +6,7 @@ |
| 6 | 6 | # RUN: llvm-objdump -d -t %t.exe | FileCheck %s |
| 7 | 7 | |
| 8 | 8 | # CHECK: Disassembly of section .text: |
| 9 | # CHECK-EMPTY: | |
| 9 | 10 | # CHECK-NEXT: __start: |
| 10 | 11 | # CHECK-NEXT: 20000: 3c 08 00 03 lui $8, 3 |
| 11 | 12 | # CHECK-NEXT: 20004: 21 08 7f f0 addi $8, $8, 32752 |
deps/lld/test/ELF/mips-gp-lowest.s+1-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: .sdata : { *(.sdata) } \ |
| 8 | 8 | # RUN: .got : { *(.got) } }" > %t.rel.script |
| 9 | 9 | # RUN: ld.lld %t.o --script %t.rel.script -shared -o %t.so |
| 10 | # RUN: llvm-readobj -s -t %t.so | FileCheck %s | |
| 10 | # RUN: llvm-readobj -S --symbols %t.so | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | .text |
| 13 | 13 | .global foo |
deps/lld/test/ELF/mips-gprel-sec.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o |
| 5 | 5 | # RUN: ld.lld %t.o -shared -o %t.so |
| 6 | # RUN: llvm-readobj -s %t.so | FileCheck %s | |
| 6 | # RUN: llvm-readobj -S %t.so | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | .text |
| 9 | 9 | nop |
deps/lld/test/ELF/mips-gprel32-relocs-gp0.s+2-2| ... | ... | @@ -3,10 +3,10 @@ |
| 3 | 3 | |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o |
| 5 | 5 | # RUN: ld.lld -r -o %t-rel.o %t.o |
| 6 | # RUN: llvm-readobj -mips-reginfo %t-rel.o | FileCheck --check-prefix=REL %s | |
| 6 | # RUN: llvm-readobj --mips-reginfo %t-rel.o | FileCheck --check-prefix=REL %s | |
| 7 | 7 | |
| 8 | 8 | # RUN: ld.lld -shared -o %t.so %S/Inputs/mips-gp0-non-zero.o |
| 9 | # RUN: llvm-readobj -mips-reginfo %t.so | FileCheck --check-prefix=DSO %s | |
| 9 | # RUN: llvm-readobj --mips-reginfo %t.so | FileCheck --check-prefix=DSO %s | |
| 10 | 10 | # RUN: llvm-objdump -s -t %t.so | FileCheck --check-prefix=DUMP %s |
| 11 | 11 | |
| 12 | 12 | # REL: GP: 0x0 |
deps/lld/test/ELF/mips-hilo-gp-disp.s+2| ... | ... | @@ -20,6 +20,7 @@ bar: |
| 20 | 20 | addi $t0,$t0,%lo(_gp_disp) |
| 21 | 21 | |
| 22 | 22 | # EXE: Disassembly of section .text: |
| 23 | # EXE-EMPTY: | |
| 23 | 24 | # EXE-NEXT: __start: |
| 24 | 25 | # EXE-NEXT: 20000: 3c 08 00 02 lui $8, 2 |
| 25 | 26 | # ^-- %hi(0x47ff0-0x20000) |
| ... | ... | @@ -37,6 +38,7 @@ bar: |
| 37 | 38 | # EXE: 00020000 .text 00000000 __start |
| 38 | 39 | |
| 39 | 40 | # SO: Disassembly of section .text: |
| 41 | # SO-EMPTY: | |
| 40 | 42 | # SO-NEXT: __start: |
| 41 | 43 | # SO-NEXT: 10000: 3c 08 00 02 lui $8, 2 |
| 42 | 44 | # ^-- %hi(0x28000-0x10000) |
deps/lld/test/ELF/mips-hilo-hi-only.s+1| ... | ... | @@ -16,6 +16,7 @@ _label: |
| 16 | 16 | # WARN: can't find matching R_MIPS_LO16 relocation for R_MIPS_HI16 |
| 17 | 17 | |
| 18 | 18 | # CHECK: Disassembly of section .text: |
| 19 | # CHECK-EMPTY: | |
| 19 | 20 | # CHECK-NEXT: __start: |
| 20 | 21 | # CHECK-NEXT: 20000: 3c 08 00 03 lui $8, 3 |
| 21 | 22 | # ^-- %hi(__start) w/o addend |
deps/lld/test/ELF/mips-hilo.s+1| ... | ... | @@ -30,6 +30,7 @@ g1: |
| 30 | 30 | .word 0 |
| 31 | 31 | |
| 32 | 32 | # CHECK: Disassembly of section .text: |
| 33 | # CHECK-EMPTY: | |
| 33 | 34 | # CHECK-NEXT: __start: |
| 34 | 35 | # CHECK-NEXT: 20000: 3c 08 00 02 lui $8, 2 |
| 35 | 36 | # ^-- %hi(__start+4) |
deps/lld/test/ELF/mips-jalr.test+12-13| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: yaml2obj %s -o %t.o |
| 4 | 4 | # RUN: ld.lld %t.o -o %t.so -shared |
| 5 | 5 | # RUN: llvm-objdump -d %t.so | FileCheck %s |
| 6 | # RUN: llvm-readobj -relocations %t.so | FileCheck -check-prefix=REL %s | |
| 6 | # RUN: llvm-readobj -r %t.so | FileCheck -check-prefix=REL %s | |
| 7 | 7 | |
| 8 | 8 | # REQUIRES: mips |
| 9 | 9 | |
| ... | ... | @@ -38,15 +38,14 @@ Sections: |
| 38 | 38 | Type: R_MIPS_JALR |
| 39 | 39 | |
| 40 | 40 | Symbols: |
| 41 | Local: | |
| 42 | - Name: T1 | |
| 43 | Type: STT_FUNC | |
| 44 | Section: .text | |
| 45 | Value: 0 | |
| 46 | Size: 4 | |
| 47 | Global: | |
| 48 | - Name: __start | |
| 49 | Type: STT_FUNC | |
| 50 | Section: .text | |
| 51 | Value: 0 | |
| 52 | Size: 4 | |
| 41 | - Name: T1 | |
| 42 | Type: STT_FUNC | |
| 43 | Section: .text | |
| 44 | Value: 0 | |
| 45 | Size: 4 | |
| 46 | - Name: __start | |
| 47 | Type: STT_FUNC | |
| 48 | Section: .text | |
| 49 | Value: 0 | |
| 50 | Size: 4 | |
| 51 | Binding: STB_GLOBAL |
deps/lld/test/ELF/mips-merge-abiflags.s+2-2| ... | ... | @@ -4,8 +4,8 @@ |
| 4 | 4 | |
| 5 | 5 | # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o |
| 6 | 6 | # RUN: ld.lld %t.o %p/Inputs/mips-concatenated-abiflags.o -o %t.exe |
| 7 | # RUN: llvm-readobj -sections -mips-abi-flags %t.exe | FileCheck %s | |
| 8 | # RUN: llvm-readobj -sections -mips-abi-flags \ | |
| 7 | # RUN: llvm-readobj --sections --mips-abi-flags %t.exe | FileCheck %s | |
| 8 | # RUN: llvm-readobj --sections --mips-abi-flags \ | |
| 9 | 9 | # RUN: %p/Inputs/mips-concatenated-abiflags.o | \ |
| 10 | 10 | # RUN: FileCheck --check-prefix=INPUT-OBJECT %s |
| 11 | 11 |
deps/lld/test/ELF/mips-mgot.s+21-21| ... | ... | @@ -8,14 +8,14 @@ |
| 8 | 8 | # RUN: %p/Inputs/mips-mgot-2.s -o %t2.o |
| 9 | 9 | # RUN: ld.lld -shared -mips-got-size 52 %t0.o %t1.o %t2.o -o %t.so |
| 10 | 10 | # RUN: llvm-objdump -s -section=.got -t %t.so | FileCheck %s |
| 11 | # RUN: llvm-readobj -r -dt -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s | |
| 11 | # RUN: llvm-readobj -r --dyn-syms --mips-plt-got %t.so | FileCheck -check-prefix=GOT %s | |
| 12 | 12 | |
| 13 | 13 | # CHECK: Contents of section .got: |
| 14 | # CHECK-NEXT: 60000 00000000 80000000 00010000 00010030 | |
| 15 | # CHECK-NEXT: 60010 00000000 00000004 00020000 00030000 | |
| 16 | # CHECK-NEXT: 60020 00040000 00050000 00060000 00070000 | |
| 17 | # CHECK-NEXT: 60030 00000000 00000000 00000000 00000000 | |
| 18 | # CHECK-NEXT: 60040 00000000 00000000 00000000 | |
| 14 | # CHECK-NEXT: 70000 00000000 80000000 00010000 00010030 | |
| 15 | # CHECK-NEXT: 70010 00000000 00000004 00030000 00040000 | |
| 16 | # CHECK-NEXT: 70020 00050000 00060000 00070000 00080000 | |
| 17 | # CHECK-NEXT: 70030 00000000 00000000 00000000 00000000 | |
| 18 | # CHECK-NEXT: 70040 00000000 00000000 00000000 | |
| 19 | 19 | |
| 20 | 20 | # CHECK: SYMBOL TABLE: |
| 21 | 21 | # CHECK: 00000000 l O .tdata 00000000 loc0 |
| ... | ... | @@ -28,20 +28,20 @@ |
| 28 | 28 | |
| 29 | 29 | # GOT: Relocations [ |
| 30 | 30 | # GOT-NEXT: Section (7) .rel.dyn { |
| 31 | # GOT-NEXT: 0x60018 R_MIPS_REL32 - 0x0 | |
| 32 | # GOT-NEXT: 0x6001C R_MIPS_REL32 - 0x0 | |
| 33 | # GOT-NEXT: 0x60020 R_MIPS_REL32 - 0x0 | |
| 34 | # GOT-NEXT: 0x60024 R_MIPS_REL32 - 0x0 | |
| 35 | # GOT-NEXT: 0x60028 R_MIPS_REL32 - 0x0 | |
| 36 | # GOT-NEXT: 0x6002C R_MIPS_REL32 - 0x0 | |
| 37 | # GOT-NEXT: 0x60030 R_MIPS_REL32 foo0 0x0 | |
| 38 | # GOT-NEXT: 0x60034 R_MIPS_REL32 foo2 0x0 | |
| 39 | # GOT-NEXT: 0x60044 R_MIPS_TLS_DTPMOD32 - 0x0 | |
| 40 | # GOT-NEXT: 0x60010 R_MIPS_TLS_TPREL32 tls0 0x0 | |
| 41 | # GOT-NEXT: 0x60038 R_MIPS_TLS_TPREL32 tls0 0x0 | |
| 42 | # GOT-NEXT: 0x6003C R_MIPS_TLS_DTPMOD32 tls0 0x0 | |
| 43 | # GOT-NEXT: 0x60040 R_MIPS_TLS_DTPREL32 tls0 0x0 | |
| 44 | # GOT-NEXT: 0x60014 R_MIPS_TLS_TPREL32 tls1 0x0 | |
| 31 | # GOT-NEXT: 0x70018 R_MIPS_REL32 - 0x0 | |
| 32 | # GOT-NEXT: 0x7001C R_MIPS_REL32 - 0x0 | |
| 33 | # GOT-NEXT: 0x70020 R_MIPS_REL32 - 0x0 | |
| 34 | # GOT-NEXT: 0x70024 R_MIPS_REL32 - 0x0 | |
| 35 | # GOT-NEXT: 0x70028 R_MIPS_REL32 - 0x0 | |
| 36 | # GOT-NEXT: 0x7002C R_MIPS_REL32 - 0x0 | |
| 37 | # GOT-NEXT: 0x70030 R_MIPS_REL32 foo0 0x0 | |
| 38 | # GOT-NEXT: 0x70034 R_MIPS_REL32 foo2 0x0 | |
| 39 | # GOT-NEXT: 0x70044 R_MIPS_TLS_DTPMOD32 - 0x0 | |
| 40 | # GOT-NEXT: 0x70010 R_MIPS_TLS_TPREL32 tls0 0x0 | |
| 41 | # GOT-NEXT: 0x70038 R_MIPS_TLS_TPREL32 tls0 0x0 | |
| 42 | # GOT-NEXT: 0x7003C R_MIPS_TLS_DTPMOD32 tls0 0x0 | |
| 43 | # GOT-NEXT: 0x70040 R_MIPS_TLS_DTPREL32 tls0 0x0 | |
| 44 | # GOT-NEXT: 0x70014 R_MIPS_TLS_TPREL32 tls1 0x0 | |
| 45 | 45 | # GOT-NEXT: } |
| 46 | 46 | # GOT-NEXT: ] |
| 47 | 47 | |
| ... | ... | @@ -57,7 +57,7 @@ |
| 57 | 57 | # GOT-NEXT: ] |
| 58 | 58 | |
| 59 | 59 | # GOT: Primary GOT { |
| 60 | # GOT-NEXT: Canonical gp value: 0x67FF0 | |
| 60 | # GOT-NEXT: Canonical gp value: 0x77FF0 | |
| 61 | 61 | # GOT-NEXT: Reserved entries [ |
| 62 | 62 | # GOT-NEXT: Entry { |
| 63 | 63 | # GOT-NEXT: Address: |
deps/lld/test/ELF/mips-micro-bad-cross-calls.s created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | # REQUIRES: mips | |
| 2 | # Check error message for invalid cross-mode branch instructions. | |
| 3 | ||
| 4 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ | |
| 5 | # RUN: %S/Inputs/mips-dynamic.s -o %t2.o | |
| 6 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o | |
| 7 | # RUN: not ld.lld -o %t.exe %t1.o %t2.o 2>&1 | FileCheck %s | |
| 8 | ||
| 9 | # CHECK: (.text+0x0): unsupported jump/branch instruction between ISA modes referenced by R_MICROMIPS_PC10_S1 relocation | |
| 10 | ||
| 11 | .text | |
| 12 | .set micromips | |
| 13 | .global __start | |
| 14 | __start: | |
| 15 | b16 foo0 |
deps/lld/test/ELF/mips-micro-cross-calls.s created+44| ... | ... | @@ -0,0 +1,44 @@ |
| 1 | # REQUIRES: mips | |
| 2 | # Check various cases of microMIPS - regular code cross-calls. | |
| 3 | ||
| 4 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ | |
| 5 | # RUN: -mattr=micromips %s -o %t-eb.o | |
| 6 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ | |
| 7 | # RUN: -position-independent -mattr=micromips \ | |
| 8 | # RUN: %S/Inputs/mips-micro.s -o %t-eb-pic.o | |
| 9 | # RUN: ld.lld -o %t-eb.exe %t-eb.o %t-eb-pic.o | |
| 10 | # RUN: llvm-objdump -d -mattr=-micromips %t-eb.exe \ | |
| 11 | # RUN: | FileCheck --check-prefix=REG %s | |
| 12 | # RUN: llvm-objdump -d -mattr=+micromips %t-eb.exe \ | |
| 13 | # RUN: | FileCheck --check-prefix=MICRO %s | |
| 14 | ||
| 15 | # REG: __start: | |
| 16 | # REG-NEXT: 20000: 74 00 80 04 jalx 131088 <micro> | |
| 17 | # REG-NEXT: 20004: 00 00 00 00 nop | |
| 18 | # REG-NEXT: 20008: 74 00 80 08 jalx 131104 <__microLA25Thunk_foo> | |
| 19 | ||
| 20 | # REG: __LA25Thunk_bar: | |
| 21 | # REG-NEXT: 20030: 3c 19 00 02 lui $25, 2 | |
| 22 | # REG-NEXT: 20034: 08 00 80 11 j 131140 <bar> | |
| 23 | ||
| 24 | # MICRO: micro: | |
| 25 | # MICRO-NEXT: 20010: f0 00 80 00 jalx 65536 | |
| 26 | # MICRO-NEXT: 20014: 00 00 00 00 nop | |
| 27 | # MICRO-NEXT: 20018: f0 00 80 0c jalx 65560 | |
| 28 | ||
| 29 | # MICRO: __microLA25Thunk_foo: | |
| 30 | # MICRO-NEXT: 20020: 41 b9 00 02 lui $25, 2 | |
| 31 | # MICRO-NEXT: 20024: d4 01 00 20 j 131136 | |
| 32 | ||
| 33 | .text | |
| 34 | .set nomicromips | |
| 35 | .global __start | |
| 36 | __start: | |
| 37 | jal micro | |
| 38 | jal foo | |
| 39 | ||
| 40 | .set micromips | |
| 41 | .global micro | |
| 42 | micro: | |
| 43 | jal __start | |
| 44 | jal bar |
deps/lld/test/ELF/mips-micro-got.s+1-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: %S/Inputs/mips-dynamic.s -o %t2.o |
| 8 | 8 | # RUN: ld.lld %t2.o -shared -o %t.so |
| 9 | 9 | # RUN: ld.lld %t1.o %t.so -o %t.exe |
| 10 | # RUN: llvm-readobj -mips-plt-got %t.exe | FileCheck %s | |
| 10 | # RUN: llvm-readobj --mips-plt-got %t.exe | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | # CHECK: Local entries [ |
| 13 | 13 | # CHECK-NEXT: Entry { |
deps/lld/test/ELF/mips-micro-jal.s+7-2| ... | ... | @@ -8,7 +8,7 @@ |
| 8 | 8 | # RUN: -mattr=micromips %s -o %t2eb.o |
| 9 | 9 | # RUN: ld.lld -o %teb.exe %t2eb.o %teb.so |
| 10 | 10 | # RUN: llvm-objdump -d -mattr=micromips %teb.exe | FileCheck --check-prefix=EB %s |
| 11 | # RUN: llvm-readobj -mips-plt-got %teb.exe | FileCheck --check-prefix=PLT %s | |
| 11 | # RUN: llvm-readobj --mips-plt-got %teb.exe | FileCheck --check-prefix=PLT %s | |
| 12 | 12 | |
| 13 | 13 | # RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \ |
| 14 | 14 | # RUN: -mattr=micromips %S/Inputs/mips-micro.s -o %t1el.o |
| ... | ... | @@ -17,7 +17,7 @@ |
| 17 | 17 | # RUN: -mattr=micromips %s -o %t2el.o |
| 18 | 18 | # RUN: ld.lld -o %tel.exe %t2el.o %tel.so |
| 19 | 19 | # RUN: llvm-objdump -d -mattr=micromips %tel.exe | FileCheck --check-prefix=EL %s |
| 20 | # RUN: llvm-readobj -mips-plt-got %tel.exe | FileCheck --check-prefix=PLT %s | |
| 20 | # RUN: llvm-readobj --mips-plt-got %tel.exe | FileCheck --check-prefix=PLT %s | |
| 21 | 21 | |
| 22 | 22 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ |
| 23 | 23 | # RUN: -mattr=micromips -mcpu=mips32r6 %S/Inputs/mips-micro.s -o %t1eb.o |
| ... | ... | @@ -47,6 +47,7 @@ |
| 47 | 47 | # RUN: | FileCheck --check-prefix=MIXED %s |
| 48 | 48 | |
| 49 | 49 | # EB: Disassembly of section .plt: |
| 50 | # EB-EMPTY: | |
| 50 | 51 | # EB-NEXT: .plt: |
| 51 | 52 | # EB-NEXT: 20010: 79 80 3f fd addiupc $3, 65524 |
| 52 | 53 | # EB-NEXT: 20014: ff 23 00 00 lw $25, 0($3) |
| ... | ... | @@ -64,6 +65,7 @@ |
| 64 | 65 | # EB-NEXT: 2003a: 0f 02 move $24, $2 |
| 65 | 66 | |
| 66 | 67 | # EL: Disassembly of section .plt: |
| 68 | # EL-EMPTY: | |
| 67 | 69 | # EL-NEXT: .plt: |
| 68 | 70 | # EL-NEXT: 20010: 80 79 fd 3f addiupc $3, 65524 |
| 69 | 71 | # EL-NEXT: 20014: 23 ff 00 00 lw $25, 0($3) |
| ... | ... | @@ -81,6 +83,7 @@ |
| 81 | 83 | # EL-NEXT: 2003a: 02 0f move $24, $2 |
| 82 | 84 | |
| 83 | 85 | # EBR6: Disassembly of section .plt: |
| 86 | # EBR6-EMPTY: | |
| 84 | 87 | # EBR6-NEXT: .plt: |
| 85 | 88 | # EBR6-NEXT: 20010: 78 60 3f fd lapc $3, 65524 |
| 86 | 89 | # EBR6-NEXT: 20014: ff 23 00 00 lw $25, 0($3) |
| ... | ... | @@ -97,6 +100,7 @@ |
| 97 | 100 | # EBR6-NEXT: 2003a: 47 23 jrc16 $25 |
| 98 | 101 | |
| 99 | 102 | # ELR6: Disassembly of section .plt: |
| 103 | # ELR6-EMPTY: | |
| 100 | 104 | # ELR6-NEXT: .plt: |
| 101 | 105 | # ELR6-NEXT: 20010: 60 78 fd 3f lapc $3, 65524 |
| 102 | 106 | # ELR6-NEXT: 20014: 23 ff 00 00 lw $25, 0($3) |
| ... | ... | @@ -113,6 +117,7 @@ |
| 113 | 117 | # ELR6-NEXT: 2003a: 23 47 jrc16 $25 |
| 114 | 118 | |
| 115 | 119 | # MIXED: Disassembly of section .plt: |
| 120 | # MIXED-EMPTY: | |
| 116 | 121 | # MIXED-NEXT: .plt: |
| 117 | 122 | # MIXED-NEXT: 20020: 79 80 3f f9 addiupc $3, 65508 |
| 118 | 123 | # MIXED-NEXT: 20024: ff 23 00 00 lw $25, 0($3) |
deps/lld/test/ELF/mips-micro-plt.s+3-3| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ |
| 8 | 8 | # RUN: -mattr=micromips %s -o %t-exe.o |
| 9 | 9 | # RUN: ld.lld %t-exe.o %t.so -o %t.exe |
| 10 | # RUN: llvm-readobj -t -dt -mips-plt-got %t.exe | FileCheck %s | |
| 10 | # RUN: llvm-readobj --symbols --dyn-syms --mips-plt-got %t.exe | FileCheck %s | |
| 11 | 11 | # RUN: llvm-objdump -d -mattr=micromips %t.exe | FileCheck --check-prefix=ASM %s |
| 12 | 12 | |
| 13 | 13 | # CHECK: Symbols [ |
| ... | ... | @@ -87,9 +87,9 @@ |
| 87 | 87 | |
| 88 | 88 | # ASM: __start: |
| 89 | 89 | # ASM-NEXT: 20000: fd 1c 80 18 lw $8, -32744($gp) |
| 90 | # ASM-NEXT: 20004: 11 08 00 10 addi $8, $8, 16 | |
| 90 | # ASM-NEXT: 20004: 11 08 00 11 addi $8, $8, 17 | |
| 91 | 91 | # ASM-NEXT: 20008: 41 a8 00 02 lui $8, 2 |
| 92 | # ASM-NEXT: 2000c: 11 08 00 40 addi $8, $8, 64 | |
| 92 | # ASM-NEXT: 2000c: 11 08 00 41 addi $8, $8, 65 | |
| 93 | 93 | # |
| 94 | 94 | # ASM: foo: |
| 95 | 95 | # ASM-NEXT: 20010: f4 01 00 20 jal 131136 |
deps/lld/test/ELF/mips-micro-relocs.s+30-7| ... | ... | @@ -6,20 +6,22 @@ |
| 6 | 6 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ |
| 7 | 7 | # RUN: -mattr=micromips %s -o %t2eb.o |
| 8 | 8 | # RUN: ld.lld -o %teb.exe %t1eb.o %t2eb.o |
| 9 | # RUN: llvm-objdump -d -t -mattr=micromips %teb.exe \ | |
| 9 | # RUN: llvm-objdump -d -t -s -mattr=micromips %teb.exe \ | |
| 10 | 10 | # RUN: | FileCheck --check-prefixes=EB,SYM %s |
| 11 | # RUN: llvm-readobj -h %teb.exe | FileCheck --check-prefix=ELF %s | |
| 11 | 12 | |
| 12 | 13 | # RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \ |
| 13 | 14 | # RUN: -mattr=micromips %S/Inputs/mips-micro.s -o %t1el.o |
| 14 | 15 | # RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \ |
| 15 | 16 | # RUN: -mattr=micromips %s -o %t2el.o |
| 16 | 17 | # RUN: ld.lld -o %tel.exe %t1el.o %t2el.o |
| 17 | # RUN: llvm-objdump -d -t -mattr=micromips %tel.exe \ | |
| 18 | # RUN: llvm-objdump -d -t -s -mattr=micromips %tel.exe \ | |
| 18 | 19 | # RUN: | FileCheck --check-prefixes=EL,SYM %s |
| 20 | # RUN: llvm-readobj -h %tel.exe | FileCheck --check-prefix=ELF %s | |
| 19 | 21 | |
| 20 | 22 | # EB: __start: |
| 21 | 23 | # EB-NEXT: 20010: 41 a3 00 01 lui $3, 1 |
| 22 | # EB-NEXT: 20014: 30 63 7f df addiu $3, $3, 32735 | |
| 24 | # EB-NEXT: 20014: 30 63 7f ef addiu $3, $3, 32751 | |
| 23 | 25 | # EB-NEXT: 20018: fc 7c 80 18 lw $3, -32744($gp) |
| 24 | 26 | # EB-NEXT: 2001c: fc 63 80 18 lw $3, -32744($3) |
| 25 | 27 | # EB-NEXT: 20020: 8f 70 beqz16 $6, -32 |
| ... | ... | @@ -28,9 +30,15 @@ |
| 28 | 30 | # EB-NEXT: 20028: 00 00 00 00 nop |
| 29 | 31 | # EB-NEXT: 2002c: 94 00 ff e8 b -44 |
| 30 | 32 | |
| 33 | # EB: Contents of section .data: | |
| 34 | # EB-NEXT: 30000 fffe8011 | |
| 35 | ||
| 36 | # EB: Contents of section .debug_info | |
| 37 | # EB-NEXT: 0000 00020011 | |
| 38 | ||
| 31 | 39 | # EL: __start: |
| 32 | 40 | # EL-NEXT: 20010: a3 41 01 00 lui $3, 1 |
| 33 | # EL-NEXT: 20014: 63 30 df 7f addiu $3, $3, 32735 | |
| 41 | # EL-NEXT: 20014: 63 30 ef 7f addiu $3, $3, 32751 | |
| 34 | 42 | # EL-NEXT: 20018: 7c fc 18 80 lw $3, -32744($gp) |
| 35 | 43 | # EL-NEXT: 2001c: 63 fc 18 80 lw $3, -32744($3) |
| 36 | 44 | # EL-NEXT: 20020: 70 8f beqz16 $6, -32 |
| ... | ... | @@ -39,9 +47,18 @@ |
| 39 | 47 | # EL-NEXT: 20028: 00 00 00 00 nop |
| 40 | 48 | # EL-NEXT: 2002c: 00 94 e8 ff b -44 |
| 41 | 49 | |
| 42 | # SYM: 00037ff0 .got 00000000 .hidden _gp | |
| 43 | # SYM: 00020000 g F .text 00000000 foo | |
| 44 | # SYM: 00020010 .text 00000000 __start | |
| 50 | # EL: Contents of section .data: | |
| 51 | # EL-NEXT: 30000 1180feff | |
| 52 | ||
| 53 | # EL: Contents of section .debug_info | |
| 54 | # EL-NEXT: 0000 11000200 | |
| 55 | ||
| 56 | # SYM: 00038000 .got 00000000 .hidden _gp | |
| 57 | # SYM: 00020000 g F .text 00000000 0x80 foo | |
| 58 | # SYM: 00020010 .text 00000000 0x80 __start | |
| 59 | ||
| 60 | # ELF: ElfHeader { | |
| 61 | # ELF: Entry: 0x20011 | |
| 45 | 62 | |
| 46 | 63 | .text |
| 47 | 64 | .set micromips |
| ... | ... | @@ -56,3 +73,9 @@ __start: |
| 56 | 73 | beqz16 $6, foo # R_MICROMIPS_PC7_S1 |
| 57 | 74 | b16 foo # R_MICROMIPS_PC10_S1 |
| 58 | 75 | b foo # R_MICROMIPS_PC16_S1 |
| 76 | ||
| 77 | .data | |
| 78 | .gpword __start # R_MIPS_GPREL32 | |
| 79 | ||
| 80 | .section .debug_info | |
| 81 | .word __start # R_MIPS_32 |
deps/lld/test/ELF/mips-micror6-relocs.s+2-2| ... | ... | @@ -26,8 +26,8 @@ |
| 26 | 26 | # EL-NEXT: 20014: 7f 80 f6 ff beqzc $3, -36 |
| 27 | 27 | # EL-NEXT: 20018: ff b7 f4 ff balc -24 <foo> |
| 28 | 28 | |
| 29 | # SYM: 00020000 g F .text 00000000 foo | |
| 30 | # SYM: 00020010 .text 00000000 __start | |
| 29 | # SYM: 00020000 g F .text 00000000 0x80 foo | |
| 30 | # SYM: 00020010 .text 00000000 0x80 __start | |
| 31 | 31 | |
| 32 | 32 | .text |
| 33 | 33 | .set micromips |
deps/lld/test/ELF/mips-n32-rels.s+1| ... | ... | @@ -24,6 +24,7 @@ loc: |
| 24 | 24 | .gpword(loc) # R_MIPS_GPREL32 |
| 25 | 25 | |
| 26 | 26 | # CHECK: Disassembly of section .text: |
| 27 | # CHECK-EMPTY: | |
| 27 | 28 | # CHECK-NEXT: __start: |
| 28 | 29 | # CHECK-NEXT: 20000: 3c 1c 00 01 lui $gp, 1 |
| 29 | 30 | # ^-- 0x20000 - 0x37ff0 |
deps/lld/test/ELF/mips-non-zero-gp0.s+2-2| ... | ... | @@ -34,11 +34,11 @@ |
| 34 | 34 | # lui $gp,%hi(%neg(%gp_rel(foo))) |
| 35 | 35 | |
| 36 | 36 | # RUN: ld.lld -r -o %t-32.r %S/Inputs/mips-gp0-non-zero.o |
| 37 | # RUN: llvm-readobj -mips-reginfo %t-32.r | FileCheck --check-prefix=GPVAL %s | |
| 37 | # RUN: llvm-readobj --mips-reginfo %t-32.r | FileCheck --check-prefix=GPVAL %s | |
| 38 | 38 | # RUN: llvm-objdump -s %t-32.r | FileCheck --check-prefix=ADDEND32 %s |
| 39 | 39 | |
| 40 | 40 | # RUN: ld.lld -r -o %t-64.r %S/Inputs/mips-n64-gp0-non-zero.o |
| 41 | # RUN: llvm-readobj -mips-options %t-64.r | FileCheck --check-prefix=GPVAL %s | |
| 41 | # RUN: llvm-readobj --mips-options %t-64.r | FileCheck --check-prefix=GPVAL %s | |
| 42 | 42 | # RUN: llvm-readobj -r %S/Inputs/mips-n64-gp0-non-zero.o %t-64.r \ |
| 43 | 43 | # RUN: | FileCheck --check-prefix=ADDEND64 %s |
| 44 | 44 |
deps/lld/test/ELF/mips-npic-call-pic-os.s+5| ... | ... | @@ -14,6 +14,7 @@ |
| 14 | 14 | # RUN: llvm-objdump -d %t.exe | FileCheck %s |
| 15 | 15 | |
| 16 | 16 | # CHECK: Disassembly of section .text: |
| 17 | # CHECK-EMPTY: | |
| 17 | 18 | # CHECK-NEXT: __LA25Thunk_foo1a: |
| 18 | 19 | # CHECK-NEXT: 20000: 3c 19 00 02 lui $25, 2 |
| 19 | 20 | # CHECK-NEXT: 20004: 08 00 80 08 j 131104 <foo1a> |
| ... | ... | @@ -52,7 +53,9 @@ |
| 52 | 53 | |
| 53 | 54 | # CHECK: fnpic: |
| 54 | 55 | # CHECK-NEXT: 20070: 00 00 00 00 nop |
| 56 | # CHECK-EMPTY: | |
| 55 | 57 | # CHECK-NEXT: Disassembly of section differentos: |
| 58 | # CHECK-EMPTY: | |
| 56 | 59 | # CHECK-NEXT: __start: |
| 57 | 60 | # CHECK-NEXT: 20074: 0c 00 80 00 jal 131072 <__LA25Thunk_foo1a> |
| 58 | 61 | # CHECK-NEXT: 20078: 00 00 00 00 nop |
| ... | ... | @@ -74,6 +77,7 @@ |
| 74 | 77 | # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=REVERSE %s |
| 75 | 78 | |
| 76 | 79 | # REVERSE: Disassembly of section .text: |
| 80 | # REVERSE-EMPTY: | |
| 77 | 81 | # REVERSE-NEXT: __LA25Thunk_foo1a: |
| 78 | 82 | # REVERSE-NEXT: 20000: 3c 19 00 02 lui $25, 2 |
| 79 | 83 | # REVERSE-NEXT: 20004: 08 00 80 08 j 131104 <foo1a> |
| ... | ... | @@ -114,6 +118,7 @@ |
| 114 | 118 | # REVERSE-NEXT: 20070: 00 00 00 00 nop |
| 115 | 119 | |
| 116 | 120 | # REVERSE: Disassembly of section differentos: |
| 121 | # REVERSE-EMPTY: | |
| 117 | 122 | # REVERSE-NEXT: __start: |
| 118 | 123 | # REVERSE-NEXT: 20074: 0c 00 80 00 jal 131072 <__LA25Thunk_foo1a> |
| 119 | 124 | # REVERSE-NEXT: 20078: 00 00 00 00 nop |
deps/lld/test/ELF/mips-npic-call-pic-script.s+5| ... | ... | @@ -14,6 +14,7 @@ |
| 14 | 14 | # RUN: llvm-objdump -d %t.exe | FileCheck %s |
| 15 | 15 | |
| 16 | 16 | # CHECK: Disassembly of section .out: |
| 17 | # CHECK-EMPTY: | |
| 17 | 18 | # CHECK-NEXT: __LA25Thunk_foo1a: |
| 18 | 19 | # CHECK-NEXT: 20000: 3c 19 00 02 lui $25, 2 |
| 19 | 20 | # CHECK-NEXT: 20004: 08 00 80 08 j 131104 <foo1a> |
| ... | ... | @@ -84,6 +85,7 @@ __start: |
| 84 | 85 | # RUN: llvm-objdump -d %t2.exe | FileCheck -check-prefix=ORPH1 %s |
| 85 | 86 | |
| 86 | 87 | # ORPH1: Disassembly of section .text: |
| 88 | # ORPH1-EMPTY: | |
| 87 | 89 | # ORPH1-NEXT: __start: |
| 88 | 90 | # ORPH1-NEXT: 20000: 0c 00 80 15 jal 131156 <__LA25Thunk_foo1a> |
| 89 | 91 | # ORPH1-NEXT: 20004: 00 00 00 00 nop |
| ... | ... | @@ -144,6 +146,7 @@ __start: |
| 144 | 146 | # RUN: llvm-objdump -d %t3.exe | FileCheck -check-prefix=ORPH2 %s |
| 145 | 147 | |
| 146 | 148 | # ORPH2: Disassembly of section .out: |
| 149 | # ORPH2-EMPTY: | |
| 147 | 150 | # ORPH2-NEXT: __start: |
| 148 | 151 | # ORPH2-NEXT: 20000: 0c 00 80 18 jal 131168 <__LA25Thunk_foo1a> |
| 149 | 152 | # ORPH2-NEXT: 20004: 00 00 00 00 nop |
| ... | ... | @@ -169,7 +172,9 @@ __start: |
| 169 | 172 | |
| 170 | 173 | # ORPH2: fnpic: |
| 171 | 174 | # ORPH2-NEXT: 20050: 00 00 00 00 nop |
| 175 | # ORPH2-EMPTY: | |
| 172 | 176 | # ORPH2-NEXT: Disassembly of section .text: |
| 177 | # ORPH2-EMPTY: | |
| 173 | 178 | |
| 174 | 179 | # ORPH2-NEXT: __LA25Thunk_foo1a: |
| 175 | 180 | # ORPH2-NEXT: 20060: 3c 19 00 02 lui $25, 2 |
deps/lld/test/ELF/mips-npic-call-pic.s+49-23| ... | ... | @@ -2,18 +2,32 @@ |
| 2 | 2 | # Check LA25 stubs creation. This stub code is necessary when |
| 3 | 3 | # non-PIC code calls PIC function. |
| 4 | 4 | |
| 5 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ | |
| 5 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mcpu=mips32r2 \ | |
| 6 | 6 | # RUN: %p/Inputs/mips-fpic.s -o %t-fpic.o |
| 7 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ | |
| 7 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mcpu=mips32r2 \ | |
| 8 | 8 | # RUN: %p/Inputs/mips-fnpic.s -o %t-fnpic.o |
| 9 | # RUN: ld.lld -r %t-fpic.o %t-fnpic.o -o %t-sto-pic.o | |
| 10 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ | |
| 11 | # RUN: %p/Inputs/mips-pic.s -o %t-pic.o | |
| 12 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-npic.o | |
| 13 | # RUN: ld.lld %t-npic.o %t-pic.o %t-sto-pic.o -o %t.exe | |
| 14 | # RUN: llvm-objdump -d %t.exe | FileCheck %s | |
| 9 | # RUN: ld.lld -r %t-fpic.o %t-fnpic.o -o %t-sto-pic-r2.o | |
| 10 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mcpu=mips32r2 \ | |
| 11 | # RUN: %p/Inputs/mips-pic.s -o %t-pic-r2.o | |
| 12 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mcpu=mips32r2 \ | |
| 13 | # RUN: %s -o %t-npic-r2.o | |
| 14 | # RUN: ld.lld %t-npic-r2.o %t-pic-r2.o %t-sto-pic-r2.o -o %t-r2.exe | |
| 15 | # RUN: llvm-objdump -d %t-r2.exe | FileCheck --check-prefixes=CHECK,R2 %s | |
| 16 | ||
| 17 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mcpu=mips32r6 \ | |
| 18 | # RUN: %p/Inputs/mips-fpic.s -o %t-fpic.o | |
| 19 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mcpu=mips32r6 \ | |
| 20 | # RUN: %p/Inputs/mips-fnpic.s -o %t-fnpic.o | |
| 21 | # RUN: ld.lld -r %t-fpic.o %t-fnpic.o -o %t-sto-pic-r6.o | |
| 22 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mcpu=mips32r6 \ | |
| 23 | # RUN: %p/Inputs/mips-pic.s -o %t-pic-r6.o | |
| 24 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mcpu=mips32r6 \ | |
| 25 | # RUN: %s -o %t-npic-r6.o | |
| 26 | # RUN: ld.lld %t-npic-r6.o %t-pic-r6.o %t-sto-pic-r6.o -o %t-r6.exe | |
| 27 | # RUN: llvm-objdump -d %t-r6.exe | FileCheck --check-prefixes=CHECK,R6 %s | |
| 15 | 28 | |
| 16 | 29 | # CHECK: Disassembly of section .text: |
| 30 | # CHECK-EMPTY: | |
| 17 | 31 | # CHECK-NEXT: __start: |
| 18 | 32 | # CHECK-NEXT: 20000: 0c 00 80 0c jal 131120 <__LA25Thunk_foo1a> |
| 19 | 33 | # CHECK-NEXT: 20004: 00 00 00 00 nop |
| ... | ... | @@ -29,13 +43,15 @@ |
| 29 | 43 | # CHECK-NEXT: 2002c: 00 00 00 00 nop |
| 30 | 44 | # |
| 31 | 45 | # CHECK: __LA25Thunk_foo1a: |
| 32 | # CHECK-NEXT: 20030: 3c 19 00 02 lui $25, 2 | |
| 33 | # CHECK-NEXT: 20034: 08 00 80 14 j 131152 <foo1a> | |
| 46 | # R2: 20030: 3c 19 00 02 lui $25, 2 | |
| 47 | # R6: 20030: 3c 19 00 02 aui $25, $zero, 2 | |
| 48 | # CHECK: 20034: 08 00 80 14 j 131152 <foo1a> | |
| 34 | 49 | # CHECK-NEXT: 20038: 27 39 00 50 addiu $25, $25, 80 |
| 35 | 50 | # CHECK-NEXT: 2003c: 00 00 00 00 nop |
| 36 | 51 | |
| 37 | 52 | # CHECK: __LA25Thunk_foo1b: |
| 38 | # CHECK-NEXT: 20040: 3c 19 00 02 lui $25, 2 | |
| 53 | # R2: 20040: 3c 19 00 02 lui $25, 2 | |
| 54 | # R6: 20040: 3c 19 00 02 aui $25, $zero, 2 | |
| 39 | 55 | # CHECK-NEXT: 20044: 08 00 80 15 j 131156 <foo1b> |
| 40 | 56 | # CHECK-NEXT: 20048: 27 39 00 54 addiu $25, $25, 84 |
| 41 | 57 | # CHECK-NEXT: 2004c: 00 00 00 00 nop |
| ... | ... | @@ -47,7 +63,8 @@ |
| 47 | 63 | # CHECK-NEXT: 20054: 00 00 00 00 nop |
| 48 | 64 | |
| 49 | 65 | # CHECK: __LA25Thunk_foo2: |
| 50 | # CHECK-NEXT: 20058: 3c 19 00 02 lui $25, 2 | |
| 66 | # R2: 20058: 3c 19 00 02 lui $25, 2 | |
| 67 | # R6: 20058: 3c 19 00 02 aui $25, $zero, 2 | |
| 51 | 68 | # CHECK-NEXT: 2005c: 08 00 80 1c j 131184 <foo2> |
| 52 | 69 | # CHECK-NEXT: 20060: 27 39 00 70 addiu $25, $25, 112 |
| 53 | 70 | # CHECK-NEXT: 20064: 00 00 00 00 nop |
| ... | ... | @@ -56,7 +73,8 @@ |
| 56 | 73 | # CHECK-NEXT: 20070: 00 00 00 00 nop |
| 57 | 74 | |
| 58 | 75 | # CHECK: __LA25Thunk_fpic: |
| 59 | # CHECK-NEXT: 20074: 3c 19 00 02 lui $25, 2 | |
| 76 | # R2: 20074: 3c 19 00 02 lui $25, 2 | |
| 77 | # R6: 20074: 3c 19 00 02 aui $25, $zero, 2 | |
| 60 | 78 | # CHECK-NEXT: 20078: 08 00 80 24 j 131216 <fpic> |
| 61 | 79 | # CHECK-NEXT: 2007c: 27 39 00 90 addiu $25, $25, 144 |
| 62 | 80 | # CHECK-NEXT: 20080: 00 00 00 00 nop |
| ... | ... | @@ -70,19 +88,25 @@ |
| 70 | 88 | # Make sure the thunks are created properly no matter how |
| 71 | 89 | # objects are laid out. |
| 72 | 90 | # |
| 73 | # RUN: ld.lld %t-pic.o %t-npic.o %t-sto-pic.o -o %t.exe | |
| 74 | # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=REVERSE %s | |
| 91 | # RUN: ld.lld %t-pic-r2.o %t-npic-r2.o %t-sto-pic-r2.o -o %t.exe | |
| 92 | # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefixes=REVERSE,REV-R2 %s | |
| 93 | # | |
| 94 | # RUN: ld.lld %t-pic-r6.o %t-npic-r6.o %t-sto-pic-r6.o -o %t.exe | |
| 95 | # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefixes=REVERSE,REV-R6 %s | |
| 75 | 96 | |
| 76 | 97 | # REVERSE: Disassembly of section .text: |
| 98 | # REVERSE-EMPTY: | |
| 77 | 99 | # REVERSE-NEXT: __LA25Thunk_foo1a: |
| 78 | # REVERSE-NEXT: 20000: 3c 19 00 02 lui $25, 2 | |
| 79 | # REVERSE-NEXT: 20004: 08 00 80 08 j 131104 <foo1a> | |
| 100 | # REV-R2: 20000: 3c 19 00 02 lui $25, 2 | |
| 101 | # REV-R6: 20000: 3c 19 00 02 aui $25, $zero, 2 | |
| 102 | # REVERSE: 20004: 08 00 80 08 j 131104 <foo1a> | |
| 80 | 103 | # REVERSE-NEXT: 20008: 27 39 00 20 addiu $25, $25, 32 |
| 81 | 104 | # REVERSE-NEXT: 2000c: 00 00 00 00 nop |
| 82 | 105 | |
| 83 | 106 | # REVERSE: __LA25Thunk_foo1b: |
| 84 | # REVERSE-NEXT: 20010: 3c 19 00 02 lui $25, 2 | |
| 85 | # REVERSE-NEXT: 20014: 08 00 80 09 j 131108 <foo1b> | |
| 107 | # REV-R2: 20010: 3c 19 00 02 lui $25, 2 | |
| 108 | # REV-R6: 20010: 3c 19 00 02 aui $25, $zero, 2 | |
| 109 | # REVERSE: 20014: 08 00 80 09 j 131108 <foo1b> | |
| 86 | 110 | # REVERSE-NEXT: 20018: 27 39 00 24 addiu $25, $25, 36 |
| 87 | 111 | # REVERSE-NEXT: 2001c: 00 00 00 00 nop |
| 88 | 112 | |
| ... | ... | @@ -93,8 +117,9 @@ |
| 93 | 117 | # REVERSE-NEXT: 20024: 00 00 00 00 nop |
| 94 | 118 | |
| 95 | 119 | # REVERSE: __LA25Thunk_foo2: |
| 96 | # REVERSE-NEXT: 20028: 3c 19 00 02 lui $25, 2 | |
| 97 | # REVERSE-NEXT: 2002c: 08 00 80 10 j 131136 <foo2> | |
| 120 | # REV-R2: 20028: 3c 19 00 02 lui $25, 2 | |
| 121 | # REV-R6: 20028: 3c 19 00 02 aui $25, $zero, 2 | |
| 122 | # REVERSE: 2002c: 08 00 80 10 j 131136 <foo2> | |
| 98 | 123 | # REVERSE-NEXT: 20030: 27 39 00 40 addiu $25, $25, 64 |
| 99 | 124 | # REVERSE-NEXT: 20034: 00 00 00 00 nop |
| 100 | 125 | |
| ... | ... | @@ -116,8 +141,9 @@ |
| 116 | 141 | # REVERSE-NEXT: 2007c: 00 00 00 00 nop |
| 117 | 142 | |
| 118 | 143 | # REVERSE: __LA25Thunk_fpic: |
| 119 | # REVERSE-NEXT: 20080: 3c 19 00 02 lui $25, 2 | |
| 120 | # REVERSE-NEXT: 20084: 08 00 80 24 j 131216 <fpic> | |
| 144 | # REV-R2: 20080: 3c 19 00 02 lui $25, 2 | |
| 145 | # REV-R6: 20080: 3c 19 00 02 aui $25, $zero, 2 | |
| 146 | # REVERSE: 20084: 08 00 80 24 j 131216 <fpic> | |
| 121 | 147 | # REVERSE-NEXT: 20088: 27 39 00 90 addiu $25, $25, 144 |
| 122 | 148 | # REVERSE-NEXT: 2008c: 00 00 00 00 nop |
| 123 | 149 |
deps/lld/test/ELF/mips-options-r.test+1-1| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | # % as -mabi=64 -mips64r2 t.s |
| 12 | 12 | |
| 13 | 13 | # RUN: ld.lld -r %p/Inputs/mips-options.o -o %t.o |
| 14 | # RUN: llvm-readobj -s %t.o | FileCheck %s | |
| 14 | # RUN: llvm-readobj -S %t.o | FileCheck %s | |
| 15 | 15 | |
| 16 | 16 | # REQUIRES: mips |
| 17 | 17 |
deps/lld/test/ELF/mips-options.s+14-1| ... | ... | @@ -8,7 +8,7 @@ |
| 8 | 8 | # RUN: . = 0x100000000; \ |
| 9 | 9 | # RUN: .got : { *(.got) } }" > %t.rel.script |
| 10 | 10 | # RUN: ld.lld %t1.o %t2.o --gc-sections --script %t.rel.script -shared -o %t.so |
| 11 | # RUN: llvm-readobj -symbols -mips-options %t.so | FileCheck %s | |
| 11 | # RUN: llvm-readobj -l --symbols --mips-options %t.so | FileCheck %s | |
| 12 | 12 | |
| 13 | 13 | .text |
| 14 | 14 | .globl __start |
| ... | ... | @@ -18,6 +18,19 @@ __start: |
| 18 | 18 | # CHECK: Name: _gp |
| 19 | 19 | # CHECK-NEXT: Value: 0x[[GP:[0-9A-F]+]] |
| 20 | 20 | |
| 21 | # CHECK: ProgramHeader { | |
| 22 | # CHECK: Type: PT_MIPS_OPTIONS | |
| 23 | # CHECK-NEXT: Offset: | |
| 24 | # CHECK-NEXT: VirtualAddress: | |
| 25 | # CHECK-NEXT: PhysicalAddress: | |
| 26 | # CHECK-NEXT: FileSize: | |
| 27 | # CHECK-NEXT: MemSize: | |
| 28 | # CHECK-NEXT: Flags [ | |
| 29 | # CHECK-NEXT: PF_R | |
| 30 | # CHECK-NEXT: ] | |
| 31 | # CHECK-NEXT: Alignment: 8 | |
| 32 | # CHECK-NEXT: } | |
| 33 | ||
| 21 | 34 | # CHECK: MIPS Options { |
| 22 | 35 | # CHECK-NEXT: ODK_REGINFO { |
| 23 | 36 | # CHECK-NEXT: GP: 0x[[GP]] |
deps/lld/test/ELF/mips-pc-relocs.s+1| ... | ... | @@ -22,6 +22,7 @@ __start: |
| 22 | 22 | .word _foo+8-. # R_MIPS_PC32 |
| 23 | 23 | |
| 24 | 24 | # CHECK: Disassembly of section .text: |
| 25 | # CHECK-EMPTY: | |
| 25 | 26 | # CHECK-NEXT: __start: |
| 26 | 27 | # CHECK-NEXT: 20000: ec c8 00 08 lwpc $6, 32 |
| 27 | 28 | # ^-- (0x20020-0x20000)>>2 |
deps/lld/test/ELF/mips-plt-copy.s+1-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: %S/Inputs/mips-dynamic.s -o %t.so.o |
| 8 | 8 | # RUN: ld.lld %t.so.o -shared -o %t.so |
| 9 | 9 | # RUN: ld.lld %t.o %t.so -o %t.exe |
| 10 | # RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s | |
| 10 | # RUN: llvm-readobj -r --mips-plt-got %t.exe | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | # CHECK: Relocations [ |
| 13 | 13 | # CHECK-NEXT: Section ({{.*}}) .rel.dyn { |
deps/lld/test/ELF/mips-plt-n32.s+3| ... | ... | @@ -14,12 +14,15 @@ |
| 14 | 14 | # RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=HAZARDPLT,CHECK |
| 15 | 15 | |
| 16 | 16 | # CHECK: Disassembly of section .text: |
| 17 | # CHECK-EMPTY: | |
| 17 | 18 | # CHECK-NEXT: __start: |
| 18 | 19 | # CHECK-NEXT: 20000: 0c 00 80 0c jal 131120 |
| 19 | 20 | # ^-- 0x20030 gotplt[foo0] |
| 20 | 21 | # CHECK-NEXT: 20004: 00 00 00 00 nop |
| 21 | 22 | # |
| 23 | # CHECK-EMPTY: | |
| 22 | 24 | # CHECK-NEXT: Disassembly of section .plt: |
| 25 | # CHECK-EMPTY: | |
| 23 | 26 | # CHECK-NEXT: .plt: |
| 24 | 27 | # CHECK-NEXT: 20010: 3c 0e 00 03 lui $14, 3 |
| 25 | 28 | # CHECK-NEXT: 20014: 8d d9 00 04 lw $25, 4($14) |
deps/lld/test/ELF/mips-plt-n64.s created+42| ... | ... | @@ -0,0 +1,42 @@ |
| 1 | # REQUIRES: mips | |
| 2 | # Check R_MIPS_26 relocation handling in case of N64 ABIs. | |
| 3 | ||
| 4 | # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \ | |
| 5 | # RUN: %S/Inputs/mips-dynamic.s -o %t-so.o | |
| 6 | # RUN: ld.lld %t-so.o -shared -o %t.so | |
| 7 | # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o | |
| 8 | # RUN: ld.lld %t.o %t.so -o %t.exe | |
| 9 | # RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=CHECK,DEFAULT | |
| 10 | # RUN: ld.lld %t-so.o -shared -o %t.so -z hazardplt | |
| 11 | # RUN: ld.lld %t.o %t.so -o %t.exe -z hazardplt | |
| 12 | # RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=CHECK,HAZARDPLT | |
| 13 | ||
| 14 | # CHECK: Disassembly of section .text: | |
| 15 | # CHECK-EMPTY: | |
| 16 | # CHECK-NEXT: __start: | |
| 17 | # CHECK-NEXT: 20000: 0c 00 80 0c jal 131120 | |
| 18 | # CHECK-NEXT: 20004: 00 00 00 00 nop | |
| 19 | # CHECK-EMPTY: | |
| 20 | # CHECK-NEXT: Disassembly of section .plt: | |
| 21 | # CHECK-EMPTY: | |
| 22 | # CHECK-NEXT: .plt: | |
| 23 | # CHECK-NEXT: 20010: 3c 0e 00 03 lui $14, 3 | |
| 24 | # CHECK-NEXT: 20014: dd d9 00 08 ld $25, 8($14) | |
| 25 | # CHECK-NEXT: 20018: 25 ce 00 08 addiu $14, $14, 8 | |
| 26 | # CHECK-NEXT: 2001c: 03 0e c0 23 subu $24, $24, $14 | |
| 27 | # CHECK-NEXT: 20020: 03 e0 78 25 move $15, $ra | |
| 28 | # CHECK-NEXT: 20024: 00 18 c0 c2 srl $24, $24, 3 | |
| 29 | # DEFAULT: 20028: 03 20 f8 09 jalr $25 | |
| 30 | # HAZARDPLT: 20028: 03 20 fc 09 jalr.hb $25 | |
| 31 | # CHECK-NEXT: 2002c: 27 18 ff fe addiu $24, $24, -2 | |
| 32 | # CHECK-NEXT: 20030: 3c 0f 00 03 lui $15, 3 | |
| 33 | # CHECK-NEXT: 20034: dd f9 00 18 ld $25, 24($15) | |
| 34 | # DEFAULT: 20038: 03 20 00 08 jr $25 | |
| 35 | # HAZARDPLT: 20038: 03 20 04 08 jr.hb $25 | |
| 36 | # CHECK-NEXT: 2003c: 65 f8 00 18 daddiu $24, $15, 24 | |
| 37 | ||
| 38 | .text | |
| 39 | .option pic0 | |
| 40 | .global __start | |
| 41 | __start: | |
| 42 | jal foo0 |
deps/lld/test/ELF/mips-plt-r6.s+3| ... | ... | @@ -13,12 +13,15 @@ |
| 13 | 13 | # RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=HAZARDPLT,CHECK |
| 14 | 14 | |
| 15 | 15 | # CHECK: Disassembly of section .text: |
| 16 | # CHECK-EMPTY: | |
| 16 | 17 | # CHECK-NEXT: __start: |
| 17 | 18 | # CHECK-NEXT: 20000: 0c 00 80 0c jal 131120 |
| 18 | 19 | # ^-- 0x20030 gotplt[foo0] |
| 19 | 20 | # CHECK-NEXT: 20004: 00 00 00 00 nop |
| 20 | 21 | # |
| 22 | # CHECK-EMPTY: | |
| 21 | 23 | # CHECK-NEXT: Disassembly of section .plt: |
| 24 | # CHECK-EMPTY: | |
| 22 | 25 | # CHECK-NEXT: .plt: |
| 23 | 26 | # CHECK-NEXT: 20010: 3c 1c 00 03 aui $gp, $zero, 3 |
| 24 | 27 | # CHECK-NEXT: 20014: 8f 99 00 04 lw $25, 4($gp) |
deps/lld/test/ELF/mips-reginfo.s+1-1| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ |
| 6 | 6 | # RUN: %S/Inputs/mips-dynamic.s -o %t2.o |
| 7 | 7 | # RUN: ld.lld %t1.o %t2.o --gc-sections -shared -o %t.so |
| 8 | # RUN: llvm-readobj -symbols -mips-reginfo %t.so | FileCheck %s | |
| 8 | # RUN: llvm-readobj --symbols --mips-reginfo %t.so | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | .text |
| 11 | 11 | .globl __start |
deps/lld/test/ELF/mips-sto-pic-flag.s+1-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ |
| 8 | 8 | # RUN: %p/Inputs/mips-pic.s -o %t-pic.o |
| 9 | 9 | # RUN: ld.lld -r %t-npic.o %t-pic.o -o %t-rel.o |
| 10 | # RUN: llvm-readobj -t %t-rel.o | FileCheck %s | |
| 10 | # RUN: llvm-readobj --symbols %t-rel.o | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | # CHECK: Symbol { |
| 13 | 13 | # CHECK: Name: main |
deps/lld/test/ELF/mips-sto-plt.s+1-1| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | # RUN: ld.lld %t.so.o -shared -o %t.so |
| 7 | 7 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o |
| 8 | 8 | # RUN: ld.lld %t.o %t.so -o %t.exe |
| 9 | # RUN: llvm-readobj -dt -mips-plt-got %t.exe | FileCheck %s | |
| 9 | # RUN: llvm-readobj --dyn-syms --mips-plt-got %t.exe | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | # CHECK: Symbol { |
| 12 | 12 | # CHECK: Name: foo0 |
deps/lld/test/ELF/mips-tls-64.s+24-24| ... | ... | @@ -8,11 +8,11 @@ |
| 8 | 8 | |
| 9 | 9 | # RUN: ld.lld %t.o %t.so -o %t.exe |
| 10 | 10 | # RUN: llvm-objdump -d -s -t %t.exe | FileCheck -check-prefix=DIS %s |
| 11 | # RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s | |
| 11 | # RUN: llvm-readobj -r --mips-plt-got %t.exe | FileCheck %s | |
| 12 | 12 | |
| 13 | 13 | # RUN: ld.lld -shared %t.o %t.so -o %t-out.so |
| 14 | 14 | # RUN: llvm-objdump -d -s -t %t-out.so | FileCheck -check-prefix=DIS-SO %s |
| 15 | # RUN: llvm-readobj -r -mips-plt-got %t-out.so | FileCheck -check-prefix=SO %s | |
| 15 | # RUN: llvm-readobj -r --mips-plt-got %t-out.so | FileCheck -check-prefix=SO %s | |
| 16 | 16 | |
| 17 | 17 | # DIS: __start: |
| 18 | 18 | # DIS-NEXT: 20000: 24 62 80 30 addiu $2, $3, -32720 |
| ... | ... | @@ -22,11 +22,11 @@ |
| 22 | 22 | # DIS-NEXT: 20010: 24 62 80 28 addiu $2, $3, -32728 |
| 23 | 23 | |
| 24 | 24 | # DIS: Contents of section .got: |
| 25 | # DIS-NEXT: 30010 00000000 00000000 80000000 00000000 | |
| 26 | # DIS-NEXT: 30020 00000000 00000000 ffffffff ffff9004 | |
| 27 | # DIS-NEXT: 30030 00000000 00000000 00000000 00000000 | |
| 28 | # DIS-NEXT: 30040 00000000 00000001 00000000 00000000 | |
| 29 | # DIS-NEXT: 30050 00000000 00000001 ffffffff ffff8004 | |
| 25 | # DIS-NEXT: 40010 00000000 00000000 80000000 00000000 | |
| 26 | # DIS-NEXT: 40020 00000000 00000000 ffffffff ffff9004 | |
| 27 | # DIS-NEXT: 40030 00000000 00000000 00000000 00000000 | |
| 28 | # DIS-NEXT: 40040 00000000 00000001 00000000 00000000 | |
| 29 | # DIS-NEXT: 40050 00000000 00000001 ffffffff ffff8004 | |
| 30 | 30 | |
| 31 | 31 | # DIS: 0000000000000000 l O .tdata 00000000 loc |
| 32 | 32 | # DIS: 0000000000000004 g O .tdata 00000000 bar |
| ... | ... | @@ -34,13 +34,13 @@ |
| 34 | 34 | |
| 35 | 35 | # CHECK: Relocations [ |
| 36 | 36 | # CHECK-NEXT: Section (7) .rel.dyn { |
| 37 | # CHECK-NEXT: 0x30020 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 | |
| 38 | # CHECK-NEXT: 0x30030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 | |
| 39 | # CHECK-NEXT: 0x30038 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 | |
| 37 | # CHECK-NEXT: 0x40020 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 | |
| 38 | # CHECK-NEXT: 0x40030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 | |
| 39 | # CHECK-NEXT: 0x40038 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 | |
| 40 | 40 | # CHECK-NEXT: } |
| 41 | 41 | # CHECK-NEXT: ] |
| 42 | 42 | # CHECK-NEXT: Primary GOT { |
| 43 | # CHECK-NEXT: Canonical gp value: 0x38000 | |
| 43 | # CHECK-NEXT: Canonical gp value: 0x48000 | |
| 44 | 44 | # CHECK-NEXT: Reserved entries [ |
| 45 | 45 | # CHECK: ] |
| 46 | 46 | # CHECK-NEXT: Local entries [ |
| ... | ... | @@ -58,25 +58,25 @@ |
| 58 | 58 | # ^-- -32680 VA - 0x8000 bar |
| 59 | 59 | |
| 60 | 60 | # DIS-SO: Contents of section .got: |
| 61 | # DIS-SO-NEXT: 20000 00000000 00000000 80000000 00000000 | |
| 62 | # DIS-SO-NEXT: 20010 00000000 00000000 00000000 00000004 | |
| 63 | # DIS-SO-NEXT: 20020 00000000 00000000 00000000 00000000 | |
| 64 | # DIS-SO-NEXT: 20030 00000000 00000000 00000000 00000000 | |
| 65 | # DIS-SO-NEXT: 20040 00000000 00000000 00000000 00000000 | |
| 61 | # DIS-SO-NEXT: 30000 00000000 00000000 80000000 00000000 | |
| 62 | # DIS-SO-NEXT: 30010 00000000 00000000 00000000 00000004 | |
| 63 | # DIS-SO-NEXT: 30020 00000000 00000000 00000000 00000000 | |
| 64 | # DIS-SO-NEXT: 30030 00000000 00000000 00000000 00000000 | |
| 65 | # DIS-SO-NEXT: 30040 00000000 00000000 00000000 00000000 | |
| 66 | 66 | |
| 67 | 67 | # SO: Relocations [ |
| 68 | 68 | # SO-NEXT: Section (7) .rel.dyn { |
| 69 | # SO-NEXT: 0x20030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0 | |
| 70 | # SO-NEXT: 0x20018 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 | |
| 71 | # SO-NEXT: 0x20040 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 | |
| 72 | # SO-NEXT: 0x20048 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 | |
| 73 | # SO-NEXT: 0x20010 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 | |
| 74 | # SO-NEXT: 0x20020 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 | |
| 75 | # SO-NEXT: 0x20028 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 | |
| 69 | # SO-NEXT: 0x30030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0 | |
| 70 | # SO-NEXT: 0x30018 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 | |
| 71 | # SO-NEXT: 0x30040 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 | |
| 72 | # SO-NEXT: 0x30048 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 | |
| 73 | # SO-NEXT: 0x30010 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 | |
| 74 | # SO-NEXT: 0x30020 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 | |
| 75 | # SO-NEXT: 0x30028 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 | |
| 76 | 76 | # SO-NEXT: } |
| 77 | 77 | # SO-NEXT: ] |
| 78 | 78 | # SO-NEXT: Primary GOT { |
| 79 | # SO-NEXT: Canonical gp value: 0x27FF0 | |
| 79 | # SO-NEXT: Canonical gp value: 0x37FF0 | |
| 80 | 80 | # SO-NEXT: Reserved entries [ |
| 81 | 81 | # SO: ] |
| 82 | 82 | # SO-NEXT: Local entries [ |
deps/lld/test/ELF/mips-tls-hilo.s+2-2| ... | ... | @@ -5,10 +5,10 @@ |
| 5 | 5 | # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o |
| 6 | 6 | # RUN: ld.lld %t.o -o %t.exe |
| 7 | 7 | # RUN: llvm-objdump -d -t %t.exe | FileCheck -check-prefix=DIS %s |
| 8 | # RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s | |
| 8 | # RUN: llvm-readobj -r --mips-plt-got %t.exe | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | # RUN: ld.lld %t.o -shared -o %t.so |
| 11 | # RUN: llvm-readobj -r -mips-plt-got %t.so | FileCheck -check-prefix=SO %s | |
| 11 | # RUN: llvm-readobj -r --mips-plt-got %t.so | FileCheck -check-prefix=SO %s | |
| 12 | 12 | |
| 13 | 13 | # DIS: __start: |
| 14 | 14 | # DIS-NEXT: 20000: 24 62 00 00 addiu $2, $3, 0 |
deps/lld/test/ELF/mips-tls-static-64.s+2-2| ... | ... | @@ -7,8 +7,8 @@ |
| 7 | 7 | # RUN: llvm-objdump -s -t %t.exe | FileCheck %s |
| 8 | 8 | |
| 9 | 9 | # CHECK: Contents of section .data: |
| 10 | # CHECK-NEXT: 30000 00020004 ffffffff ffff8004 ffffffff | |
| 11 | # CHECK-NEXT: 30010 ffff9004 | |
| 10 | # CHECK-NEXT: 40000 00020004 ffffffff ffff8004 ffffffff | |
| 11 | # CHECK-NEXT: 40010 ffff9004 | |
| 12 | 12 | # |
| 13 | 13 | # CHECK: SYMBOL TABLE: |
| 14 | 14 | # CHECK: 0000000000020004 .text 00000000 __tls_get_addr |
deps/lld/test/ELF/mips-tls-static.s+3-3| ... | ... | @@ -7,10 +7,10 @@ |
| 7 | 7 | # RUN: llvm-objdump -s -t %t.exe | FileCheck %s |
| 8 | 8 | |
| 9 | 9 | # CHECK: Contents of section .data: |
| 10 | # CHECK-NEXT: 30000 0002000c ffff8004 ffff9004 | |
| 10 | # CHECK-NEXT: 40000 0002000c ffff8004 ffff9004 | |
| 11 | 11 | # CHECK: Contents of section .got: |
| 12 | # CHECK-NEXT: 30010 00000000 80000000 ffff9000 00000001 | |
| 13 | # CHECK-NEXT: 30020 ffff8000 00000001 00000000 | |
| 12 | # CHECK-NEXT: 40010 00000000 80000000 ffff9000 00000001 | |
| 13 | # CHECK-NEXT: 40020 ffff8000 00000001 00000000 | |
| 14 | 14 | # |
| 15 | 15 | # CHECK: SYMBOL TABLE: |
| 16 | 16 | # CHECK: 0002000c .text 00000000 __tls_get_addr |
deps/lld/test/ELF/mips-tls.s+20-20| ... | ... | @@ -8,11 +8,11 @@ |
| 8 | 8 | |
| 9 | 9 | # RUN: ld.lld %t.o %t.so -o %t.exe |
| 10 | 10 | # RUN: llvm-objdump -d -s -t %t.exe | FileCheck -check-prefix=DIS %s |
| 11 | # RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s | |
| 11 | # RUN: llvm-readobj -r --mips-plt-got %t.exe | FileCheck %s | |
| 12 | 12 | |
| 13 | 13 | # RUN: ld.lld -shared %t.o %t.so -o %t-out.so |
| 14 | 14 | # RUN: llvm-objdump -d -s -t %t-out.so | FileCheck -check-prefix=DIS-SO %s |
| 15 | # RUN: llvm-readobj -r -mips-plt-got %t-out.so | FileCheck -check-prefix=SO %s | |
| 15 | # RUN: llvm-readobj -r --mips-plt-got %t-out.so | FileCheck -check-prefix=SO %s | |
| 16 | 16 | |
| 17 | 17 | # DIS: __start: |
| 18 | 18 | # DIS-NEXT: 20000: 24 62 80 20 addiu $2, $3, -32736 |
| ... | ... | @@ -22,9 +22,9 @@ |
| 22 | 22 | # DIS-NEXT: 20010: 24 62 80 1c addiu $2, $3, -32740 |
| 23 | 23 | |
| 24 | 24 | # DIS: Contents of section .got: |
| 25 | # DIS-NEXT: 30010 00000000 80000000 00000000 ffff9004 | |
| 26 | # DIS-NEXT: 30020 00000000 00000000 00000001 00000000 | |
| 27 | # DIS-NEXT: 30030 00000001 ffff8004 | |
| 25 | # DIS-NEXT: 40010 00000000 80000000 00000000 ffff9004 | |
| 26 | # DIS-NEXT: 40020 00000000 00000000 00000001 00000000 | |
| 27 | # DIS-NEXT: 40030 00000001 ffff8004 | |
| 28 | 28 | |
| 29 | 29 | # DIS: 00000000 l O .tdata 00000000 loc |
| 30 | 30 | # DIS: 00000004 g O .tdata 00000000 bar |
| ... | ... | @@ -32,13 +32,13 @@ |
| 32 | 32 | |
| 33 | 33 | # CHECK: Relocations [ |
| 34 | 34 | # CHECK-NEXT: Section (7) .rel.dyn { |
| 35 | # CHECK-NEXT: 0x30018 R_MIPS_TLS_TPREL32 foo 0x0 | |
| 36 | # CHECK-NEXT: 0x30020 R_MIPS_TLS_DTPMOD32 foo 0x0 | |
| 37 | # CHECK-NEXT: 0x30024 R_MIPS_TLS_DTPREL32 foo 0x0 | |
| 35 | # CHECK-NEXT: 0x40018 R_MIPS_TLS_TPREL32 foo 0x0 | |
| 36 | # CHECK-NEXT: 0x40020 R_MIPS_TLS_DTPMOD32 foo 0x0 | |
| 37 | # CHECK-NEXT: 0x40024 R_MIPS_TLS_DTPREL32 foo 0x0 | |
| 38 | 38 | # CHECK-NEXT: } |
| 39 | 39 | # CHECK-NEXT: ] |
| 40 | 40 | # CHECK-NEXT: Primary GOT { |
| 41 | # CHECK-NEXT: Canonical gp value: 0x38000 | |
| 41 | # CHECK-NEXT: Canonical gp value: 0x48000 | |
| 42 | 42 | # CHECK-NEXT: Reserved entries [ |
| 43 | 43 | # CHECK: ] |
| 44 | 44 | # CHECK-NEXT: Local entries [ |
| ... | ... | @@ -56,23 +56,23 @@ |
| 56 | 56 | # ^-- -32716 VA - 0x8000 bar |
| 57 | 57 | |
| 58 | 58 | # DIS-SO: Contents of section .got: |
| 59 | # DIS-SO-NEXT: 20000 00000000 80000000 00000000 00000004 | |
| 60 | # DIS-SO-NEXT: 20010 00000000 00000000 00000000 00000000 | |
| 61 | # DIS-SO-NEXT: 20020 00000000 00000000 | |
| 59 | # DIS-SO-NEXT: 30000 00000000 80000000 00000000 00000004 | |
| 60 | # DIS-SO-NEXT: 30010 00000000 00000000 00000000 00000000 | |
| 61 | # DIS-SO-NEXT: 30020 00000000 00000000 | |
| 62 | 62 | |
| 63 | 63 | # SO: Relocations [ |
| 64 | 64 | # SO-NEXT: Section (7) .rel.dyn { |
| 65 | # SO-NEXT: 0x20018 R_MIPS_TLS_DTPMOD32 - 0x0 | |
| 66 | # SO-NEXT: 0x2000C R_MIPS_TLS_TPREL32 bar 0x0 | |
| 67 | # SO-NEXT: 0x20020 R_MIPS_TLS_DTPMOD32 bar 0x0 | |
| 68 | # SO-NEXT: 0x20024 R_MIPS_TLS_DTPREL32 bar 0x0 | |
| 69 | # SO-NEXT: 0x20008 R_MIPS_TLS_TPREL32 foo 0x0 | |
| 70 | # SO-NEXT: 0x20010 R_MIPS_TLS_DTPMOD32 foo 0x0 | |
| 71 | # SO-NEXT: 0x20014 R_MIPS_TLS_DTPREL32 foo 0x0 | |
| 65 | # SO-NEXT: 0x30018 R_MIPS_TLS_DTPMOD32 - 0x0 | |
| 66 | # SO-NEXT: 0x3000C R_MIPS_TLS_TPREL32 bar 0x0 | |
| 67 | # SO-NEXT: 0x30020 R_MIPS_TLS_DTPMOD32 bar 0x0 | |
| 68 | # SO-NEXT: 0x30024 R_MIPS_TLS_DTPREL32 bar 0x0 | |
| 69 | # SO-NEXT: 0x30008 R_MIPS_TLS_TPREL32 foo 0x0 | |
| 70 | # SO-NEXT: 0x30010 R_MIPS_TLS_DTPMOD32 foo 0x0 | |
| 71 | # SO-NEXT: 0x30014 R_MIPS_TLS_DTPREL32 foo 0x0 | |
| 72 | 72 | # SO-NEXT: } |
| 73 | 73 | # SO-NEXT: ] |
| 74 | 74 | # SO-NEXT: Primary GOT { |
| 75 | # SO-NEXT: Canonical gp value: 0x27FF0 | |
| 75 | # SO-NEXT: Canonical gp value: 0x37FF0 | |
| 76 | 76 | # SO-NEXT: Reserved entries [ |
| 77 | 77 | # SO: ] |
| 78 | 78 | # SO-NEXT: Local entries [ |
deps/lld/test/ELF/mips-xgot-order.s+1| ... | ... | @@ -7,6 +7,7 @@ |
| 7 | 7 | # RUN: llvm-objdump -d -s -t %t.exe | FileCheck %s |
| 8 | 8 | |
| 9 | 9 | # CHECK: Disassembly of section .text: |
| 10 | # CHECK-EMPTY: | |
| 10 | 11 | # CHECK-NEXT: __start: |
| 11 | 12 | # CHECK-NEXT: 20000: 3c 02 00 00 lui $2, 0 |
| 12 | 13 | # CHECK-NEXT: 20004: 8c 42 80 24 lw $2, -32732($2) |
deps/lld/test/ELF/msp430.s+1| ... | ... | @@ -13,6 +13,7 @@ foo: |
| 13 | 13 | jmp _start |
| 14 | 14 | |
| 15 | 15 | ; CHECK: Disassembly of section .text: |
| 16 | ; CHECK-EMPTY: | |
| 16 | 17 | ; CHECK-NEXT: _start: |
| 17 | 18 | ; CHECK-NEXT: 8000: {{.*}} nop |
| 18 | 19 | ; CHECK: foo: |
deps/lld/test/ELF/new-dtags.test+2-2| ... | ... | @@ -10,11 +10,11 @@ |
| 10 | 10 | // RUN: llvm-readobj --dynamic-table %t2 | FileCheck --check-prefix=ENABLE %s |
| 11 | 11 | |
| 12 | 12 | // DISABLE: DynamicSection [ |
| 13 | // DISABLE: 0x000000000000000F RPATH /somepath | |
| 13 | // DISABLE: 0x000000000000000F RPATH Library rpath: [/somepath] | |
| 14 | 14 | // DISABLE-NOT: RUNPATH |
| 15 | 15 | // DISABLE: ] |
| 16 | 16 | |
| 17 | 17 | // ENABLE: DynamicSection [ |
| 18 | // ENABLE: 0x000000000000001D RUNPATH /somepath | |
| 18 | // ENABLE: 0x000000000000001D RUNPATH Library runpath: [/somepath] | |
| 19 | 19 | // ENABLE-NOT: RPATH |
| 20 | 20 | // ENABLE: ] |
deps/lld/test/ELF/no-discard-this_module.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu -save-temp-labels %s -o %t |
| 3 | 3 | // RUN: ld.lld %t -o %t2 |
| 4 | // RUN: llvm-readobj -s -sd -t %t2 | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S --section-data --symbols %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .global _start |
| 7 | 7 | _start: |
deps/lld/test/ELF/no-inhibit-exec.s+1| ... | ... | @@ -6,6 +6,7 @@ |
| 6 | 6 | # RUN: llvm-readobj -r %t2 | FileCheck %s --check-prefix=RELOC |
| 7 | 7 | |
| 8 | 8 | # CHECK: Disassembly of section .text: |
| 9 | # CHECK-EMPTY: | |
| 9 | 10 | # CHECK-NEXT: _start |
| 10 | 11 | # CHECK-NEXT: 201000: {{.*}} callq -2101253 |
| 11 | 12 |
deps/lld/test/ELF/non-abs-reloc.s+1| ... | ... | @@ -6,6 +6,7 @@ |
| 6 | 6 | |
| 7 | 7 | // RUN: llvm-objdump -D %t | FileCheck --check-prefix=DISASM %s |
| 8 | 8 | // DISASM: Disassembly of section .nonalloc: |
| 9 | // DISASM-EMPTY: | |
| 9 | 10 | // DISASM-NEXT: .nonalloc: |
| 10 | 11 | // DISASM-NEXT: 0: {{.*}} callq {{.*}} <_start> |
| 11 | 12 | // DISASM-NEXT: 5: {{.*}} callq {{.*}} <_start> |
deps/lld/test/ELF/non-alloc-link-order-gc.s+1| ... | ... | @@ -6,6 +6,7 @@ |
| 6 | 6 | ## Check that we are able to GC non-allocatable metadata sections without crash. |
| 7 | 7 | |
| 8 | 8 | # CHECK: Disassembly of section .stack_sizes: |
| 9 | # CHECK-EMPTY: | |
| 9 | 10 | # CHECK-NEXT: .stack_sizes: |
| 10 | 11 | # CHECK-NEXT: 01 |
| 11 | 12 |
deps/lld/test/ELF/noplt-pie.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o |
| 4 | 4 | # RUN: ld.lld -shared %t2.o -o %t2.so |
| 5 | 5 | # RUN: ld.lld --hash-style=sysv %t1.o %t2.so -o %t.out |
| 6 | # RUN: llvm-readobj -s -r %t.out | FileCheck %s | |
| 6 | # RUN: llvm-readobj -S -r %t.out | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | # CHECK: Section { |
| 9 | 9 | # CHECK-NOT: Name: .plt |
deps/lld/test/ELF/note-alignment.s created+36| ... | ... | @@ -0,0 +1,36 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -o %t | |
| 4 | # RUN: llvm-readelf -l %t | FileCheck %s | |
| 5 | ||
| 6 | # Check that we don't mix 4-byte and 8-byte aligned notes in one PT_LOAD. | |
| 7 | # The possible 4-byte padding before the 8-byte align note may make consumers | |
| 8 | # fail to parse it. | |
| 9 | ||
| 10 | # CHECK: NOTE {{0x[0-9a-f]+}} {{0x[0-9a-f]+}} {{0x[0-9a-f]+}} 0x000004 0x000004 R 0x4 | |
| 11 | # CHECK: NOTE {{0x[0-9a-f]+}} {{0x[0-9a-f]+}} {{0x[0-9a-f]+}} 0x000010 0x000010 R 0x8 | |
| 12 | # CHECK: NOTE {{0x[0-9a-f]+}} {{0x[0-9a-f]+}} {{0x[0-9a-f]+}} 0x000008 0x000008 R 0x4 | |
| 13 | ||
| 14 | # CHECK: 03 .note.a | |
| 15 | # CHECK-NEXT: 04 .note.b .note.c | |
| 16 | # CHECK-NEXT: 05 .note.d .note.e | |
| 17 | ||
| 18 | .section .note.a, "a", @note | |
| 19 | .align 4 | |
| 20 | .long 0 | |
| 21 | ||
| 22 | .section .note.b, "a", @note | |
| 23 | .align 8 | |
| 24 | .quad 0 | |
| 25 | ||
| 26 | .section .note.c, "a", @note | |
| 27 | .align 8 | |
| 28 | .quad 0 | |
| 29 | ||
| 30 | .section .note.d, "a", @note | |
| 31 | .align 4 | |
| 32 | .long 0 | |
| 33 | ||
| 34 | .section .note.e, "a", @note | |
| 35 | .align 4 | |
| 36 | .long 0 |
deps/lld/test/ELF/note-contiguous.s+2-2| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | |
| 4 | 4 | // RUN: ld.lld %t.o -o %t1 |
| 5 | // RUN: llvm-readobj -program-headers %t1 | FileCheck %s | |
| 5 | // RUN: llvm-readobj -l %t1 | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // CHECK: Type: PT_NOTE |
| 8 | 8 | // CHECK-NEXT: Offset: |
| ... | ... | @@ -18,7 +18,7 @@ |
| 18 | 18 | |
| 19 | 19 | // RUN: echo "SECTIONS { .note : { *(.note.a) *(.note.b) } }" > %t.script |
| 20 | 20 | // RUN: ld.lld %t.o --script %t.script -o %t2 |
| 21 | // RUN: llvm-readobj -program-headers %t2 | FileCheck -check-prefix=SCRIPT %s | |
| 21 | // RUN: llvm-readobj -l %t2 | FileCheck -check-prefix=SCRIPT %s | |
| 22 | 22 | |
| 23 | 23 | // SCRIPT: Type: PT_NOTE |
| 24 | 24 | // SCRIPT-NEXT: Offset: |
deps/lld/test/ELF/note-loadaddr.s+1-1| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | // RUN: .note.b : AT(0x2000) { *(.note.b) } \ |
| 6 | 6 | // RUN: }" > %t.script |
| 7 | 7 | // RUN: ld.lld %t.o --script %t.script -o %t |
| 8 | // RUN: llvm-readobj -program-headers %t | FileCheck %s | |
| 8 | // RUN: llvm-readobj -l %t | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | // CHECK: Type: PT_NOTE |
| 11 | 11 | // CHECK-NEXT: Offset: 0x1000 |
deps/lld/test/ELF/note-multiple.s+1-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | // RUN: .note.d : { *(.note.d) } \ |
| 8 | 8 | // RUN: }" > %t.script |
| 9 | 9 | // RUN: ld.lld %t.o --script %t.script -o %t |
| 10 | // RUN: llvm-readobj -program-headers %t | FileCheck %s | |
| 10 | // RUN: llvm-readobj -l %t | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | // CHECK: Type: PT_NOTE |
| 13 | 13 | // CHECK-NEXT: Offset: 0x1000 |
deps/lld/test/ELF/note-noalloc.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t -shared |
| 4 | // RUN: llvm-readobj -program-headers -sections %t | FileCheck %s | |
| 4 | // RUN: llvm-readobj -l --sections %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // PR37361: A note without SHF_ALLOC should not be included into a PT_NOTE program header. |
| 7 | 7 |
deps/lld/test/ELF/note-noalloc2.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld %t.o -o %t |
| 4 | # RUN: llvm-readobj -program-headers %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj -l %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | ## Check we do not create a PT_NOTE segment for non-allocatable note section. |
| 7 | 7 |
deps/lld/test/ELF/note.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t -shared |
| 4 | // RUN: llvm-readobj -program-headers %t | FileCheck %s | |
| 4 | // RUN: llvm-readobj -l %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // CHECK: Type: PT_NOTE |
| 7 | 7 | // CHECK-NEXT: Offset: |
deps/lld/test/ELF/output-section.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld %t -o %t2 |
| 4 | // RUN: llvm-readobj -t %t2 | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // CHECK: Symbol { |
| 7 | 7 | // CHECK: Name: bar_sym |
deps/lld/test/ELF/pack-dyn-relocs-loop.s+12-12| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | 1 | // REQUIRES: arm, aarch64 |
| 2 | 2 | |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-android %s -o %t.o |
| 4 | // RUN: ld.lld -shared %t.o -o %t.so --pack-dyn-relocs=android | |
| 5 | // RUN: llvm-readobj -s %t.so | FileCheck %s | |
| 4 | // RUN: ld.lld -shared %t.o -o %t.so --pack-dyn-relocs=android -z norelro | |
| 5 | // RUN: llvm-readobj -S %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // This test is making sure the Android packed relocation support doesn't |
| 8 | 8 | // cause an infinite loop due to the size of the section oscillating |
| ... | ... | @@ -16,8 +16,8 @@ |
| 16 | 16 | // CHECK-NEXT: Flags [ (0x2) |
| 17 | 17 | // CHECK-NEXT: SHF_ALLOC (0x2) |
| 18 | 18 | // CHECK-NEXT: ] |
| 19 | // CHECK-NEXT: Address: 0x210 | |
| 20 | // CHECK-NEXT: Offset: 0x210 | |
| 19 | // CHECK-NEXT: Address: 0x1D8 | |
| 20 | // CHECK-NEXT: Offset: 0x1D8 | |
| 21 | 21 | // CHECK-NEXT: Size: 21 |
| 22 | 22 | |
| 23 | 23 | // CHECK: Name: x (43) |
| ... | ... | @@ -25,9 +25,9 @@ |
| 25 | 25 | // CHECK-NEXT: Flags [ (0x2) |
| 26 | 26 | // CHECK-NEXT: SHF_ALLOC (0x2) |
| 27 | 27 | // CHECK-NEXT: ] |
| 28 | // CHECK-NEXT: Address: 0x225 | |
| 29 | // CHECK-NEXT: Offset: 0x225 | |
| 30 | // CHECK-NEXT: Size: 64980 | |
| 28 | // CHECK-NEXT: Address: 0x1ED | |
| 29 | // CHECK-NEXT: Offset: 0x1ED | |
| 30 | // CHECK-NEXT: Size: 65036 | |
| 31 | 31 | |
| 32 | 32 | // CHECK: Name: barr (45) |
| 33 | 33 | // CHECK-NEXT: Type: SHT_PROGBITS (0x1) |
| ... | ... | @@ -46,7 +46,7 @@ |
| 46 | 46 | // CHECK-NEXT: ] |
| 47 | 47 | // CHECK-NEXT: Address: 0x10004 |
| 48 | 48 | // CHECK-NEXT: Offset: 0x10004 |
| 49 | // CHECK-NEXT: Size: 12 | |
| 49 | // CHECK-NEXT: Size: 24 | |
| 50 | 50 | |
| 51 | 51 | |
| 52 | 52 | .data |
| ... | ... | @@ -54,12 +54,12 @@ |
| 54 | 54 | |
| 55 | 55 | .section foo,"aw" |
| 56 | 56 | foof: |
| 57 | .long foof | |
| 58 | .long bar-53 | |
| 59 | .long bar | |
| 57 | .quad foof | |
| 58 | .quad bar-53 | |
| 59 | .quad bar | |
| 60 | 60 | |
| 61 | 61 | .section x,"a" |
| 62 | .zero 64980 | |
| 62 | .zero 65036 | |
| 63 | 63 | |
| 64 | 64 | .section barr,"a" |
| 65 | 65 | .p2align 1 |
deps/lld/test/ELF/pack-dyn-relocs-tls-aarch64.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %t.o |
| 4 | 4 | // RUN: ld.lld -shared --pack-dyn-relocs=android %t.o -o %t.so |
| 5 | // RUN: llvm-readobj -relocations %t.so | FileCheck %s | |
| 5 | // RUN: llvm-readobj -r %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // Bug 37841: Symbol::getVA must work on TLS symbols during the layout loop in |
| 8 | 8 | // finalizeSections. |
deps/lld/test/ELF/pack-dyn-relocs-tls-x86-64.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 4 | 4 | // RUN: ld.lld -shared --pack-dyn-relocs=android %t.o -o %t.so |
| 5 | // RUN: llvm-readobj -relocations %t.so | FileCheck %s | |
| 5 | // RUN: llvm-readobj -r %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // Bug 37841: Symbol::getVA must work on TLS symbols during the layout loop in |
| 8 | 8 | // finalizeSections. This test uses an atypical IE access in a shared object to |
deps/lld/test/ELF/pack-dyn-relocs.s+192-192| ... | ... | @@ -4,45 +4,45 @@ |
| 4 | 4 | // RUN: ld.lld -shared %t.a32.so.o -o %t.a32.so |
| 5 | 5 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.a32 |
| 6 | 6 | // RUN: ld.lld -pie --pack-dyn-relocs=none %t.a32 %t.a32.so -o %t2.a32 |
| 7 | // RUN: llvm-readobj -relocations %t2.a32 | FileCheck --check-prefix=UNPACKED32 %s | |
| 7 | // RUN: llvm-readobj -r %t2.a32 | FileCheck --check-prefix=UNPACKED32 %s | |
| 8 | 8 | |
| 9 | 9 | // Unpacked should have the relative relocations in their natural order. |
| 10 | 10 | // UNPACKED32: Section ({{.+}}) .rel.dyn { |
| 11 | // UNPACKED32-NEXT: 0x1000 R_ARM_RELATIVE - 0x0 | |
| 12 | // UNPACKED32-NEXT: 0x1004 R_ARM_RELATIVE - 0x0 | |
| 13 | // UNPACKED32-NEXT: 0x1008 R_ARM_RELATIVE - 0x0 | |
| 14 | // UNPACKED32-NEXT: 0x100C R_ARM_RELATIVE - 0x0 | |
| 15 | // UNPACKED32-NEXT: 0x1010 R_ARM_RELATIVE - 0x0 | |
| 16 | // UNPACKED32-NEXT: 0x1014 R_ARM_RELATIVE - 0x0 | |
| 17 | // UNPACKED32-NEXT: 0x1018 R_ARM_RELATIVE - 0x0 | |
| 18 | // UNPACKED32-NEXT: 0x101C R_ARM_RELATIVE - 0x0 | |
| 19 | ||
| 20 | // UNPACKED32-NEXT: 0x1024 R_ARM_RELATIVE - 0x0 | |
| 21 | // UNPACKED32-NEXT: 0x1028 R_ARM_RELATIVE - 0x0 | |
| 22 | // UNPACKED32-NEXT: 0x102C R_ARM_RELATIVE - 0x0 | |
| 23 | // UNPACKED32-NEXT: 0x1030 R_ARM_RELATIVE - 0x0 | |
| 24 | // UNPACKED32-NEXT: 0x1034 R_ARM_RELATIVE - 0x0 | |
| 25 | // UNPACKED32-NEXT: 0x1038 R_ARM_RELATIVE - 0x0 | |
| 26 | // UNPACKED32-NEXT: 0x103C R_ARM_RELATIVE - 0x0 | |
| 27 | ||
| 28 | // UNPACKED32-NEXT: 0x1044 R_ARM_RELATIVE - 0x0 | |
| 29 | // UNPACKED32-NEXT: 0x1048 R_ARM_RELATIVE - 0x0 | |
| 30 | // UNPACKED32-NEXT: 0x104C R_ARM_RELATIVE - 0x0 | |
| 31 | // UNPACKED32-NEXT: 0x1050 R_ARM_RELATIVE - 0x0 | |
| 32 | // UNPACKED32-NEXT: 0x1054 R_ARM_RELATIVE - 0x0 | |
| 33 | // UNPACKED32-NEXT: 0x1058 R_ARM_RELATIVE - 0x0 | |
| 34 | // UNPACKED32-NEXT: 0x105C R_ARM_RELATIVE - 0x0 | |
| 35 | // UNPACKED32-NEXT: 0x1060 R_ARM_RELATIVE - 0x0 | |
| 36 | // UNPACKED32-NEXT: 0x1064 R_ARM_RELATIVE - 0x0 | |
| 37 | ||
| 38 | // UNPACKED32-NEXT: 0x1069 R_ARM_RELATIVE - 0x0 | |
| 39 | // UNPACKED32-NEXT: 0x1020 R_ARM_ABS32 bar2 0x0 | |
| 40 | // UNPACKED32-NEXT: 0x1040 R_ARM_ABS32 zed2 0x0 | |
| 11 | // UNPACKED32-NEXT: 0x2000 R_ARM_RELATIVE - 0x0 | |
| 12 | // UNPACKED32-NEXT: 0x2004 R_ARM_RELATIVE - 0x0 | |
| 13 | // UNPACKED32-NEXT: 0x2008 R_ARM_RELATIVE - 0x0 | |
| 14 | // UNPACKED32-NEXT: 0x200C R_ARM_RELATIVE - 0x0 | |
| 15 | // UNPACKED32-NEXT: 0x2010 R_ARM_RELATIVE - 0x0 | |
| 16 | // UNPACKED32-NEXT: 0x2014 R_ARM_RELATIVE - 0x0 | |
| 17 | // UNPACKED32-NEXT: 0x2018 R_ARM_RELATIVE - 0x0 | |
| 18 | // UNPACKED32-NEXT: 0x201C R_ARM_RELATIVE - 0x0 | |
| 19 | ||
| 20 | // UNPACKED32-NEXT: 0x2024 R_ARM_RELATIVE - 0x0 | |
| 21 | // UNPACKED32-NEXT: 0x2028 R_ARM_RELATIVE - 0x0 | |
| 22 | // UNPACKED32-NEXT: 0x202C R_ARM_RELATIVE - 0x0 | |
| 23 | // UNPACKED32-NEXT: 0x2030 R_ARM_RELATIVE - 0x0 | |
| 24 | // UNPACKED32-NEXT: 0x2034 R_ARM_RELATIVE - 0x0 | |
| 25 | // UNPACKED32-NEXT: 0x2038 R_ARM_RELATIVE - 0x0 | |
| 26 | // UNPACKED32-NEXT: 0x203C R_ARM_RELATIVE - 0x0 | |
| 27 | ||
| 28 | // UNPACKED32-NEXT: 0x2044 R_ARM_RELATIVE - 0x0 | |
| 29 | // UNPACKED32-NEXT: 0x2048 R_ARM_RELATIVE - 0x0 | |
| 30 | // UNPACKED32-NEXT: 0x204C R_ARM_RELATIVE - 0x0 | |
| 31 | // UNPACKED32-NEXT: 0x2050 R_ARM_RELATIVE - 0x0 | |
| 32 | // UNPACKED32-NEXT: 0x2054 R_ARM_RELATIVE - 0x0 | |
| 33 | // UNPACKED32-NEXT: 0x2058 R_ARM_RELATIVE - 0x0 | |
| 34 | // UNPACKED32-NEXT: 0x205C R_ARM_RELATIVE - 0x0 | |
| 35 | // UNPACKED32-NEXT: 0x2060 R_ARM_RELATIVE - 0x0 | |
| 36 | // UNPACKED32-NEXT: 0x2064 R_ARM_RELATIVE - 0x0 | |
| 37 | ||
| 38 | // UNPACKED32-NEXT: 0x2069 R_ARM_RELATIVE - 0x0 | |
| 39 | // UNPACKED32-NEXT: 0x2020 R_ARM_ABS32 bar2 0x0 | |
| 40 | // UNPACKED32-NEXT: 0x2040 R_ARM_ABS32 zed2 0x0 | |
| 41 | 41 | // UNPACKED32-NEXT: } |
| 42 | 42 | |
| 43 | 43 | // RUN: ld.lld -pie --pack-dyn-relocs=android %t.a32 %t.a32.so -o %t3.a32 |
| 44 | // RUN: llvm-readobj -s -dynamic-table %t3.a32 | FileCheck --check-prefix=ANDROID32-HEADERS %s | |
| 45 | // RUN: llvm-readobj -relocations %t3.a32 | FileCheck --check-prefix=ANDROID32 %s | |
| 44 | // RUN: llvm-readobj -S --dynamic-table %t3.a32 | FileCheck --check-prefix=ANDROID32-HEADERS %s | |
| 45 | // RUN: llvm-readobj -r %t3.a32 | FileCheck --check-prefix=ANDROID32 %s | |
| 46 | 46 | |
| 47 | 47 | // ANDROID32-HEADERS: Index: 1 |
| 48 | 48 | // ANDROID32-HEADERS-NEXT: Name: .dynsym |
| ... | ... | @@ -66,42 +66,42 @@ |
| 66 | 66 | // Packed should have the larger groups of relative relocations first, |
| 67 | 67 | // i.e. the 8 and 9 followed by the 7. |
| 68 | 68 | // ANDROID32: Section ({{.+}}) .rel.dyn { |
| 69 | // ANDROID32-NEXT: 0x1000 R_ARM_RELATIVE - 0x0 | |
| 70 | // ANDROID32-NEXT: 0x1004 R_ARM_RELATIVE - 0x0 | |
| 71 | // ANDROID32-NEXT: 0x1008 R_ARM_RELATIVE - 0x0 | |
| 72 | // ANDROID32-NEXT: 0x100C R_ARM_RELATIVE - 0x0 | |
| 73 | // ANDROID32-NEXT: 0x1010 R_ARM_RELATIVE - 0x0 | |
| 74 | // ANDROID32-NEXT: 0x1014 R_ARM_RELATIVE - 0x0 | |
| 75 | // ANDROID32-NEXT: 0x1018 R_ARM_RELATIVE - 0x0 | |
| 76 | // ANDROID32-NEXT: 0x101C R_ARM_RELATIVE - 0x0 | |
| 77 | ||
| 78 | // ANDROID32-NEXT: 0x1044 R_ARM_RELATIVE - 0x0 | |
| 79 | // ANDROID32-NEXT: 0x1048 R_ARM_RELATIVE - 0x0 | |
| 80 | // ANDROID32-NEXT: 0x104C R_ARM_RELATIVE - 0x0 | |
| 81 | // ANDROID32-NEXT: 0x1050 R_ARM_RELATIVE - 0x0 | |
| 82 | // ANDROID32-NEXT: 0x1054 R_ARM_RELATIVE - 0x0 | |
| 83 | // ANDROID32-NEXT: 0x1058 R_ARM_RELATIVE - 0x0 | |
| 84 | // ANDROID32-NEXT: 0x105C R_ARM_RELATIVE - 0x0 | |
| 85 | // ANDROID32-NEXT: 0x1060 R_ARM_RELATIVE - 0x0 | |
| 86 | // ANDROID32-NEXT: 0x1064 R_ARM_RELATIVE - 0x0 | |
| 87 | ||
| 88 | // ANDROID32-NEXT: 0x1024 R_ARM_RELATIVE - 0x0 | |
| 89 | // ANDROID32-NEXT: 0x1028 R_ARM_RELATIVE - 0x0 | |
| 90 | // ANDROID32-NEXT: 0x102C R_ARM_RELATIVE - 0x0 | |
| 91 | // ANDROID32-NEXT: 0x1030 R_ARM_RELATIVE - 0x0 | |
| 92 | // ANDROID32-NEXT: 0x1034 R_ARM_RELATIVE - 0x0 | |
| 93 | // ANDROID32-NEXT: 0x1038 R_ARM_RELATIVE - 0x0 | |
| 94 | // ANDROID32-NEXT: 0x103C R_ARM_RELATIVE - 0x0 | |
| 95 | ||
| 96 | // ANDROID32-NEXT: 0x1069 R_ARM_RELATIVE - 0x0 | |
| 97 | // ANDROID32-NEXT: 0x1020 R_ARM_ABS32 bar2 0x0 | |
| 98 | // ANDROID32-NEXT: 0x1040 R_ARM_ABS32 zed2 0x0 | |
| 69 | // ANDROID32-NEXT: 0x2000 R_ARM_RELATIVE - 0x0 | |
| 70 | // ANDROID32-NEXT: 0x2004 R_ARM_RELATIVE - 0x0 | |
| 71 | // ANDROID32-NEXT: 0x2008 R_ARM_RELATIVE - 0x0 | |
| 72 | // ANDROID32-NEXT: 0x200C R_ARM_RELATIVE - 0x0 | |
| 73 | // ANDROID32-NEXT: 0x2010 R_ARM_RELATIVE - 0x0 | |
| 74 | // ANDROID32-NEXT: 0x2014 R_ARM_RELATIVE - 0x0 | |
| 75 | // ANDROID32-NEXT: 0x2018 R_ARM_RELATIVE - 0x0 | |
| 76 | // ANDROID32-NEXT: 0x201C R_ARM_RELATIVE - 0x0 | |
| 77 | ||
| 78 | // ANDROID32-NEXT: 0x2044 R_ARM_RELATIVE - 0x0 | |
| 79 | // ANDROID32-NEXT: 0x2048 R_ARM_RELATIVE - 0x0 | |
| 80 | // ANDROID32-NEXT: 0x204C R_ARM_RELATIVE - 0x0 | |
| 81 | // ANDROID32-NEXT: 0x2050 R_ARM_RELATIVE - 0x0 | |
| 82 | // ANDROID32-NEXT: 0x2054 R_ARM_RELATIVE - 0x0 | |
| 83 | // ANDROID32-NEXT: 0x2058 R_ARM_RELATIVE - 0x0 | |
| 84 | // ANDROID32-NEXT: 0x205C R_ARM_RELATIVE - 0x0 | |
| 85 | // ANDROID32-NEXT: 0x2060 R_ARM_RELATIVE - 0x0 | |
| 86 | // ANDROID32-NEXT: 0x2064 R_ARM_RELATIVE - 0x0 | |
| 87 | ||
| 88 | // ANDROID32-NEXT: 0x2024 R_ARM_RELATIVE - 0x0 | |
| 89 | // ANDROID32-NEXT: 0x2028 R_ARM_RELATIVE - 0x0 | |
| 90 | // ANDROID32-NEXT: 0x202C R_ARM_RELATIVE - 0x0 | |
| 91 | // ANDROID32-NEXT: 0x2030 R_ARM_RELATIVE - 0x0 | |
| 92 | // ANDROID32-NEXT: 0x2034 R_ARM_RELATIVE - 0x0 | |
| 93 | // ANDROID32-NEXT: 0x2038 R_ARM_RELATIVE - 0x0 | |
| 94 | // ANDROID32-NEXT: 0x203C R_ARM_RELATIVE - 0x0 | |
| 95 | ||
| 96 | // ANDROID32-NEXT: 0x2069 R_ARM_RELATIVE - 0x0 | |
| 97 | // ANDROID32-NEXT: 0x2020 R_ARM_ABS32 bar2 0x0 | |
| 98 | // ANDROID32-NEXT: 0x2040 R_ARM_ABS32 zed2 0x0 | |
| 99 | 99 | // ANDROID32-NEXT: } |
| 100 | 100 | |
| 101 | 101 | // RUN: ld.lld -pie --pack-dyn-relocs=relr %t.a32 %t.a32.so -o %t4.a32 |
| 102 | // RUN: llvm-readobj -s -dynamic-table %t4.a32 | FileCheck --check-prefix=RELR32-HEADERS %s | |
| 103 | // RUN: llvm-readobj -relocations -raw-relr %t4.a32 | FileCheck --check-prefix=RAW-RELR32 %s | |
| 104 | // RUN: llvm-readobj -relocations %t4.a32 | FileCheck --check-prefix=RELR32 %s | |
| 102 | // RUN: llvm-readobj -S --dynamic-table %t4.a32 | FileCheck --check-prefix=RELR32-HEADERS %s | |
| 103 | // RUN: llvm-readobj -r --raw-relr %t4.a32 | FileCheck --check-prefix=RAW-RELR32 %s | |
| 104 | // RUN: llvm-readobj -r %t4.a32 | FileCheck --check-prefix=RELR32 %s | |
| 105 | 105 | |
| 106 | 106 | // RELR32-HEADERS: Index: 1 |
| 107 | 107 | // RELR32-HEADERS-NEXT: Name: .dynsym |
| ... | ... | @@ -126,7 +126,7 @@ |
| 126 | 126 | // SHT_RELR section contains address/bitmap entries |
| 127 | 127 | // encoding the offsets for relative relocation. |
| 128 | 128 | // RAW-RELR32: Section ({{.+}}) .relr.dyn { |
| 129 | // RAW-RELR32-NEXT: 0x1000 | |
| 129 | // RAW-RELR32-NEXT: 0x2000 | |
| 130 | 130 | // RAW-RELR32-NEXT: 0x3FEFEFF |
| 131 | 131 | // RAW-RELR32-NEXT: } |
| 132 | 132 | |
| ... | ... | @@ -134,81 +134,81 @@ |
| 134 | 134 | // but contains only the relative relocations. |
| 135 | 135 | // Any relative relocations with odd offset stay in SHT_REL. |
| 136 | 136 | // RELR32: Section ({{.+}}) .rel.dyn { |
| 137 | // RELR32-NEXT: 0x1069 R_ARM_RELATIVE - 0x0 | |
| 138 | // RELR32-NEXT: 0x1020 R_ARM_ABS32 bar2 0x0 | |
| 139 | // RELR32-NEXT: 0x1040 R_ARM_ABS32 zed2 0x0 | |
| 137 | // RELR32-NEXT: 0x2069 R_ARM_RELATIVE - 0x0 | |
| 138 | // RELR32-NEXT: 0x2020 R_ARM_ABS32 bar2 0x0 | |
| 139 | // RELR32-NEXT: 0x2040 R_ARM_ABS32 zed2 0x0 | |
| 140 | 140 | // RELR32-NEXT: } |
| 141 | 141 | // RELR32-NEXT: Section ({{.+}}) .relr.dyn { |
| 142 | // RELR32-NEXT: 0x1000 R_ARM_RELATIVE - 0x0 | |
| 143 | // RELR32-NEXT: 0x1004 R_ARM_RELATIVE - 0x0 | |
| 144 | // RELR32-NEXT: 0x1008 R_ARM_RELATIVE - 0x0 | |
| 145 | // RELR32-NEXT: 0x100C R_ARM_RELATIVE - 0x0 | |
| 146 | // RELR32-NEXT: 0x1010 R_ARM_RELATIVE - 0x0 | |
| 147 | // RELR32-NEXT: 0x1014 R_ARM_RELATIVE - 0x0 | |
| 148 | // RELR32-NEXT: 0x1018 R_ARM_RELATIVE - 0x0 | |
| 149 | // RELR32-NEXT: 0x101C R_ARM_RELATIVE - 0x0 | |
| 150 | ||
| 151 | // RELR32-NEXT: 0x1024 R_ARM_RELATIVE - 0x0 | |
| 152 | // RELR32-NEXT: 0x1028 R_ARM_RELATIVE - 0x0 | |
| 153 | // RELR32-NEXT: 0x102C R_ARM_RELATIVE - 0x0 | |
| 154 | // RELR32-NEXT: 0x1030 R_ARM_RELATIVE - 0x0 | |
| 155 | // RELR32-NEXT: 0x1034 R_ARM_RELATIVE - 0x0 | |
| 156 | // RELR32-NEXT: 0x1038 R_ARM_RELATIVE - 0x0 | |
| 157 | // RELR32-NEXT: 0x103C R_ARM_RELATIVE - 0x0 | |
| 158 | ||
| 159 | // RELR32-NEXT: 0x1044 R_ARM_RELATIVE - 0x0 | |
| 160 | // RELR32-NEXT: 0x1048 R_ARM_RELATIVE - 0x0 | |
| 161 | // RELR32-NEXT: 0x104C R_ARM_RELATIVE - 0x0 | |
| 162 | // RELR32-NEXT: 0x1050 R_ARM_RELATIVE - 0x0 | |
| 163 | // RELR32-NEXT: 0x1054 R_ARM_RELATIVE - 0x0 | |
| 164 | // RELR32-NEXT: 0x1058 R_ARM_RELATIVE - 0x0 | |
| 165 | // RELR32-NEXT: 0x105C R_ARM_RELATIVE - 0x0 | |
| 166 | // RELR32-NEXT: 0x1060 R_ARM_RELATIVE - 0x0 | |
| 167 | // RELR32-NEXT: 0x1064 R_ARM_RELATIVE - 0x0 | |
| 142 | // RELR32-NEXT: 0x2000 R_ARM_RELATIVE - 0x0 | |
| 143 | // RELR32-NEXT: 0x2004 R_ARM_RELATIVE - 0x0 | |
| 144 | // RELR32-NEXT: 0x2008 R_ARM_RELATIVE - 0x0 | |
| 145 | // RELR32-NEXT: 0x200C R_ARM_RELATIVE - 0x0 | |
| 146 | // RELR32-NEXT: 0x2010 R_ARM_RELATIVE - 0x0 | |
| 147 | // RELR32-NEXT: 0x2014 R_ARM_RELATIVE - 0x0 | |
| 148 | // RELR32-NEXT: 0x2018 R_ARM_RELATIVE - 0x0 | |
| 149 | // RELR32-NEXT: 0x201C R_ARM_RELATIVE - 0x0 | |
| 150 | ||
| 151 | // RELR32-NEXT: 0x2024 R_ARM_RELATIVE - 0x0 | |
| 152 | // RELR32-NEXT: 0x2028 R_ARM_RELATIVE - 0x0 | |
| 153 | // RELR32-NEXT: 0x202C R_ARM_RELATIVE - 0x0 | |
| 154 | // RELR32-NEXT: 0x2030 R_ARM_RELATIVE - 0x0 | |
| 155 | // RELR32-NEXT: 0x2034 R_ARM_RELATIVE - 0x0 | |
| 156 | // RELR32-NEXT: 0x2038 R_ARM_RELATIVE - 0x0 | |
| 157 | // RELR32-NEXT: 0x203C R_ARM_RELATIVE - 0x0 | |
| 158 | ||
| 159 | // RELR32-NEXT: 0x2044 R_ARM_RELATIVE - 0x0 | |
| 160 | // RELR32-NEXT: 0x2048 R_ARM_RELATIVE - 0x0 | |
| 161 | // RELR32-NEXT: 0x204C R_ARM_RELATIVE - 0x0 | |
| 162 | // RELR32-NEXT: 0x2050 R_ARM_RELATIVE - 0x0 | |
| 163 | // RELR32-NEXT: 0x2054 R_ARM_RELATIVE - 0x0 | |
| 164 | // RELR32-NEXT: 0x2058 R_ARM_RELATIVE - 0x0 | |
| 165 | // RELR32-NEXT: 0x205C R_ARM_RELATIVE - 0x0 | |
| 166 | // RELR32-NEXT: 0x2060 R_ARM_RELATIVE - 0x0 | |
| 167 | // RELR32-NEXT: 0x2064 R_ARM_RELATIVE - 0x0 | |
| 168 | 168 | // RELR32-NEXT: } |
| 169 | 169 | |
| 170 | 170 | // RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %p/Inputs/shared2.s -o %t.a64.so.o |
| 171 | 171 | // RUN: ld.lld -shared %t.a64.so.o -o %t.a64.so |
| 172 | 172 | // RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %t.a64 |
| 173 | 173 | // RUN: ld.lld -pie --pack-dyn-relocs=none %t.a64 %t.a64.so -o %t2.a64 |
| 174 | // RUN: llvm-readobj -relocations %t2.a64 | FileCheck --check-prefix=UNPACKED64 %s | |
| 174 | // RUN: llvm-readobj -r %t2.a64 | FileCheck --check-prefix=UNPACKED64 %s | |
| 175 | 175 | |
| 176 | 176 | // UNPACKED64: Section ({{.+}}) .rela.dyn { |
| 177 | // UNPACKED64-NEXT: 0x10000 R_AARCH64_RELATIVE - 0x1 | |
| 178 | // UNPACKED64-NEXT: 0x10008 R_AARCH64_RELATIVE - 0x2 | |
| 179 | // UNPACKED64-NEXT: 0x10010 R_AARCH64_RELATIVE - 0x3 | |
| 180 | // UNPACKED64-NEXT: 0x10018 R_AARCH64_RELATIVE - 0x4 | |
| 181 | // UNPACKED64-NEXT: 0x10020 R_AARCH64_RELATIVE - 0x5 | |
| 182 | // UNPACKED64-NEXT: 0x10028 R_AARCH64_RELATIVE - 0x6 | |
| 183 | // UNPACKED64-NEXT: 0x10030 R_AARCH64_RELATIVE - 0x7 | |
| 184 | // UNPACKED64-NEXT: 0x10038 R_AARCH64_RELATIVE - 0x8 | |
| 185 | ||
| 186 | // UNPACKED64-NEXT: 0x10048 R_AARCH64_RELATIVE - 0x1 | |
| 187 | // UNPACKED64-NEXT: 0x10050 R_AARCH64_RELATIVE - 0x2 | |
| 188 | // UNPACKED64-NEXT: 0x10058 R_AARCH64_RELATIVE - 0x3 | |
| 189 | // UNPACKED64-NEXT: 0x10060 R_AARCH64_RELATIVE - 0x4 | |
| 190 | // UNPACKED64-NEXT: 0x10068 R_AARCH64_RELATIVE - 0x5 | |
| 191 | // UNPACKED64-NEXT: 0x10070 R_AARCH64_RELATIVE - 0x6 | |
| 192 | // UNPACKED64-NEXT: 0x10078 R_AARCH64_RELATIVE - 0x7 | |
| 193 | ||
| 194 | // UNPACKED64-NEXT: 0x10088 R_AARCH64_RELATIVE - 0x1 | |
| 195 | // UNPACKED64-NEXT: 0x10090 R_AARCH64_RELATIVE - 0x2 | |
| 196 | // UNPACKED64-NEXT: 0x10098 R_AARCH64_RELATIVE - 0x3 | |
| 197 | // UNPACKED64-NEXT: 0x100A0 R_AARCH64_RELATIVE - 0x4 | |
| 198 | // UNPACKED64-NEXT: 0x100A8 R_AARCH64_RELATIVE - 0x5 | |
| 199 | // UNPACKED64-NEXT: 0x100B0 R_AARCH64_RELATIVE - 0x6 | |
| 200 | // UNPACKED64-NEXT: 0x100B8 R_AARCH64_RELATIVE - 0x7 | |
| 201 | // UNPACKED64-NEXT: 0x100C0 R_AARCH64_RELATIVE - 0x8 | |
| 202 | // UNPACKED64-NEXT: 0x100C8 R_AARCH64_RELATIVE - 0x9 | |
| 203 | ||
| 204 | // UNPACKED64-NEXT: 0x100D1 R_AARCH64_RELATIVE - 0xA | |
| 205 | // UNPACKED64-NEXT: 0x10040 R_AARCH64_ABS64 bar2 0x1 | |
| 206 | // UNPACKED64-NEXT: 0x10080 R_AARCH64_ABS64 zed2 0x0 | |
| 177 | // UNPACKED64-NEXT: 0x20000 R_AARCH64_RELATIVE - 0x1 | |
| 178 | // UNPACKED64-NEXT: 0x20008 R_AARCH64_RELATIVE - 0x2 | |
| 179 | // UNPACKED64-NEXT: 0x20010 R_AARCH64_RELATIVE - 0x3 | |
| 180 | // UNPACKED64-NEXT: 0x20018 R_AARCH64_RELATIVE - 0x4 | |
| 181 | // UNPACKED64-NEXT: 0x20020 R_AARCH64_RELATIVE - 0x5 | |
| 182 | // UNPACKED64-NEXT: 0x20028 R_AARCH64_RELATIVE - 0x6 | |
| 183 | // UNPACKED64-NEXT: 0x20030 R_AARCH64_RELATIVE - 0x7 | |
| 184 | // UNPACKED64-NEXT: 0x20038 R_AARCH64_RELATIVE - 0x8 | |
| 185 | ||
| 186 | // UNPACKED64-NEXT: 0x20048 R_AARCH64_RELATIVE - 0x1 | |
| 187 | // UNPACKED64-NEXT: 0x20050 R_AARCH64_RELATIVE - 0x2 | |
| 188 | // UNPACKED64-NEXT: 0x20058 R_AARCH64_RELATIVE - 0x3 | |
| 189 | // UNPACKED64-NEXT: 0x20060 R_AARCH64_RELATIVE - 0x4 | |
| 190 | // UNPACKED64-NEXT: 0x20068 R_AARCH64_RELATIVE - 0x5 | |
| 191 | // UNPACKED64-NEXT: 0x20070 R_AARCH64_RELATIVE - 0x6 | |
| 192 | // UNPACKED64-NEXT: 0x20078 R_AARCH64_RELATIVE - 0x7 | |
| 193 | ||
| 194 | // UNPACKED64-NEXT: 0x20088 R_AARCH64_RELATIVE - 0x1 | |
| 195 | // UNPACKED64-NEXT: 0x20090 R_AARCH64_RELATIVE - 0x2 | |
| 196 | // UNPACKED64-NEXT: 0x20098 R_AARCH64_RELATIVE - 0x3 | |
| 197 | // UNPACKED64-NEXT: 0x200A0 R_AARCH64_RELATIVE - 0x4 | |
| 198 | // UNPACKED64-NEXT: 0x200A8 R_AARCH64_RELATIVE - 0x5 | |
| 199 | // UNPACKED64-NEXT: 0x200B0 R_AARCH64_RELATIVE - 0x6 | |
| 200 | // UNPACKED64-NEXT: 0x200B8 R_AARCH64_RELATIVE - 0x7 | |
| 201 | // UNPACKED64-NEXT: 0x200C0 R_AARCH64_RELATIVE - 0x8 | |
| 202 | // UNPACKED64-NEXT: 0x200C8 R_AARCH64_RELATIVE - 0x9 | |
| 203 | ||
| 204 | // UNPACKED64-NEXT: 0x200D1 R_AARCH64_RELATIVE - 0xA | |
| 205 | // UNPACKED64-NEXT: 0x20040 R_AARCH64_ABS64 bar2 0x1 | |
| 206 | // UNPACKED64-NEXT: 0x20080 R_AARCH64_ABS64 zed2 0x0 | |
| 207 | 207 | // UNPACKED64-NEXT: } |
| 208 | 208 | |
| 209 | 209 | // RUN: ld.lld -pie --pack-dyn-relocs=android %t.a64 %t.a64.so -o %t3.a64 |
| 210 | // RUN: llvm-readobj -s -dynamic-table %t3.a64 | FileCheck --check-prefix=ANDROID64-HEADERS %s | |
| 211 | // RUN: llvm-readobj -relocations %t3.a64 | FileCheck --check-prefix=ANDROID64 %s | |
| 210 | // RUN: llvm-readobj -S --dynamic-table %t3.a64 | FileCheck --check-prefix=ANDROID64-HEADERS %s | |
| 211 | // RUN: llvm-readobj -r %t3.a64 | FileCheck --check-prefix=ANDROID64 %s | |
| 212 | 212 | |
| 213 | 213 | // ANDROID64-HEADERS: Index: 1 |
| 214 | 214 | // ANDROID64-HEADERS-NEXT: Name: .dynsym |
| ... | ... | @@ -230,42 +230,42 @@ |
| 230 | 230 | // ANDROID64-HEADERS: 0x0000000060000012 ANDROID_RELASZ [[SIZE]] |
| 231 | 231 | |
| 232 | 232 | // ANDROID64: Section ({{.+}}) .rela.dyn { |
| 233 | // ANDROID64-NEXT: 0x10000 R_AARCH64_RELATIVE - 0x1 | |
| 234 | // ANDROID64-NEXT: 0x10008 R_AARCH64_RELATIVE - 0x2 | |
| 235 | // ANDROID64-NEXT: 0x10010 R_AARCH64_RELATIVE - 0x3 | |
| 236 | // ANDROID64-NEXT: 0x10018 R_AARCH64_RELATIVE - 0x4 | |
| 237 | // ANDROID64-NEXT: 0x10020 R_AARCH64_RELATIVE - 0x5 | |
| 238 | // ANDROID64-NEXT: 0x10028 R_AARCH64_RELATIVE - 0x6 | |
| 239 | // ANDROID64-NEXT: 0x10030 R_AARCH64_RELATIVE - 0x7 | |
| 240 | // ANDROID64-NEXT: 0x10038 R_AARCH64_RELATIVE - 0x8 | |
| 241 | ||
| 242 | // ANDROID64-NEXT: 0x10088 R_AARCH64_RELATIVE - 0x1 | |
| 243 | // ANDROID64-NEXT: 0x10090 R_AARCH64_RELATIVE - 0x2 | |
| 244 | // ANDROID64-NEXT: 0x10098 R_AARCH64_RELATIVE - 0x3 | |
| 245 | // ANDROID64-NEXT: 0x100A0 R_AARCH64_RELATIVE - 0x4 | |
| 246 | // ANDROID64-NEXT: 0x100A8 R_AARCH64_RELATIVE - 0x5 | |
| 247 | // ANDROID64-NEXT: 0x100B0 R_AARCH64_RELATIVE - 0x6 | |
| 248 | // ANDROID64-NEXT: 0x100B8 R_AARCH64_RELATIVE - 0x7 | |
| 249 | // ANDROID64-NEXT: 0x100C0 R_AARCH64_RELATIVE - 0x8 | |
| 250 | // ANDROID64-NEXT: 0x100C8 R_AARCH64_RELATIVE - 0x9 | |
| 251 | ||
| 252 | // ANDROID64-NEXT: 0x10048 R_AARCH64_RELATIVE - 0x1 | |
| 253 | // ANDROID64-NEXT: 0x10050 R_AARCH64_RELATIVE - 0x2 | |
| 254 | // ANDROID64-NEXT: 0x10058 R_AARCH64_RELATIVE - 0x3 | |
| 255 | // ANDROID64-NEXT: 0x10060 R_AARCH64_RELATIVE - 0x4 | |
| 256 | // ANDROID64-NEXT: 0x10068 R_AARCH64_RELATIVE - 0x5 | |
| 257 | // ANDROID64-NEXT: 0x10070 R_AARCH64_RELATIVE - 0x6 | |
| 258 | // ANDROID64-NEXT: 0x10078 R_AARCH64_RELATIVE - 0x7 | |
| 259 | ||
| 260 | // ANDROID64-NEXT: 0x100D1 R_AARCH64_RELATIVE - 0xA | |
| 261 | // ANDROID64-NEXT: 0x10040 R_AARCH64_ABS64 bar2 0x1 | |
| 262 | // ANDROID64-NEXT: 0x10080 R_AARCH64_ABS64 zed2 0x0 | |
| 233 | // ANDROID64-NEXT: 0x20000 R_AARCH64_RELATIVE - 0x1 | |
| 234 | // ANDROID64-NEXT: 0x20008 R_AARCH64_RELATIVE - 0x2 | |
| 235 | // ANDROID64-NEXT: 0x20010 R_AARCH64_RELATIVE - 0x3 | |
| 236 | // ANDROID64-NEXT: 0x20018 R_AARCH64_RELATIVE - 0x4 | |
| 237 | // ANDROID64-NEXT: 0x20020 R_AARCH64_RELATIVE - 0x5 | |
| 238 | // ANDROID64-NEXT: 0x20028 R_AARCH64_RELATIVE - 0x6 | |
| 239 | // ANDROID64-NEXT: 0x20030 R_AARCH64_RELATIVE - 0x7 | |
| 240 | // ANDROID64-NEXT: 0x20038 R_AARCH64_RELATIVE - 0x8 | |
| 241 | ||
| 242 | // ANDROID64-NEXT: 0x20088 R_AARCH64_RELATIVE - 0x1 | |
| 243 | // ANDROID64-NEXT: 0x20090 R_AARCH64_RELATIVE - 0x2 | |
| 244 | // ANDROID64-NEXT: 0x20098 R_AARCH64_RELATIVE - 0x3 | |
| 245 | // ANDROID64-NEXT: 0x200A0 R_AARCH64_RELATIVE - 0x4 | |
| 246 | // ANDROID64-NEXT: 0x200A8 R_AARCH64_RELATIVE - 0x5 | |
| 247 | // ANDROID64-NEXT: 0x200B0 R_AARCH64_RELATIVE - 0x6 | |
| 248 | // ANDROID64-NEXT: 0x200B8 R_AARCH64_RELATIVE - 0x7 | |
| 249 | // ANDROID64-NEXT: 0x200C0 R_AARCH64_RELATIVE - 0x8 | |
| 250 | // ANDROID64-NEXT: 0x200C8 R_AARCH64_RELATIVE - 0x9 | |
| 251 | ||
| 252 | // ANDROID64-NEXT: 0x20048 R_AARCH64_RELATIVE - 0x1 | |
| 253 | // ANDROID64-NEXT: 0x20050 R_AARCH64_RELATIVE - 0x2 | |
| 254 | // ANDROID64-NEXT: 0x20058 R_AARCH64_RELATIVE - 0x3 | |
| 255 | // ANDROID64-NEXT: 0x20060 R_AARCH64_RELATIVE - 0x4 | |
| 256 | // ANDROID64-NEXT: 0x20068 R_AARCH64_RELATIVE - 0x5 | |
| 257 | // ANDROID64-NEXT: 0x20070 R_AARCH64_RELATIVE - 0x6 | |
| 258 | // ANDROID64-NEXT: 0x20078 R_AARCH64_RELATIVE - 0x7 | |
| 259 | ||
| 260 | // ANDROID64-NEXT: 0x200D1 R_AARCH64_RELATIVE - 0xA | |
| 261 | // ANDROID64-NEXT: 0x20040 R_AARCH64_ABS64 bar2 0x1 | |
| 262 | // ANDROID64-NEXT: 0x20080 R_AARCH64_ABS64 zed2 0x0 | |
| 263 | 263 | // ANDROID64-NEXT: } |
| 264 | 264 | |
| 265 | 265 | // RUN: ld.lld -pie --pack-dyn-relocs=relr %t.a64 %t.a64.so -o %t4.a64 |
| 266 | // RUN: llvm-readobj -s -dynamic-table %t4.a64 | FileCheck --check-prefix=RELR64-HEADERS %s | |
| 267 | // RUN: llvm-readobj -relocations -raw-relr %t4.a64 | FileCheck --check-prefix=RAW-RELR64 %s | |
| 268 | // RUN: llvm-readobj -relocations %t4.a64 | FileCheck --check-prefix=RELR64 %s | |
| 266 | // RUN: llvm-readobj -S --dynamic-table %t4.a64 | FileCheck --check-prefix=RELR64-HEADERS %s | |
| 267 | // RUN: llvm-readobj -r --raw-relr %t4.a64 | FileCheck --check-prefix=RAW-RELR64 %s | |
| 268 | // RUN: llvm-readobj -r %t4.a64 | FileCheck --check-prefix=RELR64 %s | |
| 269 | 269 | |
| 270 | 270 | // RELR64-HEADERS: Index: 1 |
| 271 | 271 | // RELR64-HEADERS-NEXT: Name: .dynsym |
| ... | ... | @@ -290,7 +290,7 @@ |
| 290 | 290 | // SHT_RELR section contains address/bitmap entries |
| 291 | 291 | // encoding the offsets for relative relocation. |
| 292 | 292 | // RAW-RELR64: Section ({{.+}}) .relr.dyn { |
| 293 | // RAW-RELR64-NEXT: 0x10000 | |
| 293 | // RAW-RELR64-NEXT: 0x20000 | |
| 294 | 294 | // RAW-RELR64-NEXT: 0x3FEFEFF |
| 295 | 295 | // RAW-RELR64-NEXT: } |
| 296 | 296 | |
| ... | ... | @@ -298,37 +298,37 @@ |
| 298 | 298 | // but contains only the relative relocations. |
| 299 | 299 | // Any relative relocations with odd offset stay in SHT_RELA. |
| 300 | 300 | // RELR64: Section ({{.+}}) .rela.dyn { |
| 301 | // RELR64-NEXT: 0x100D1 R_AARCH64_RELATIVE - 0xA | |
| 302 | // RELR64-NEXT: 0x10040 R_AARCH64_ABS64 bar2 0x1 | |
| 303 | // RELR64-NEXT: 0x10080 R_AARCH64_ABS64 zed2 0x0 | |
| 301 | // RELR64-NEXT: 0x200D1 R_AARCH64_RELATIVE - 0xA | |
| 302 | // RELR64-NEXT: 0x20040 R_AARCH64_ABS64 bar2 0x1 | |
| 303 | // RELR64-NEXT: 0x20080 R_AARCH64_ABS64 zed2 0x0 | |
| 304 | 304 | // RELR64-NEXT: } |
| 305 | 305 | // RELR64-NEXT: Section ({{.+}}) .relr.dyn { |
| 306 | // RELR64-NEXT: 0x10000 R_AARCH64_RELATIVE - 0x0 | |
| 307 | // RELR64-NEXT: 0x10008 R_AARCH64_RELATIVE - 0x0 | |
| 308 | // RELR64-NEXT: 0x10010 R_AARCH64_RELATIVE - 0x0 | |
| 309 | // RELR64-NEXT: 0x10018 R_AARCH64_RELATIVE - 0x0 | |
| 310 | // RELR64-NEXT: 0x10020 R_AARCH64_RELATIVE - 0x0 | |
| 311 | // RELR64-NEXT: 0x10028 R_AARCH64_RELATIVE - 0x0 | |
| 312 | // RELR64-NEXT: 0x10030 R_AARCH64_RELATIVE - 0x0 | |
| 313 | // RELR64-NEXT: 0x10038 R_AARCH64_RELATIVE - 0x0 | |
| 314 | ||
| 315 | // RELR64-NEXT: 0x10048 R_AARCH64_RELATIVE - 0x0 | |
| 316 | // RELR64-NEXT: 0x10050 R_AARCH64_RELATIVE - 0x0 | |
| 317 | // RELR64-NEXT: 0x10058 R_AARCH64_RELATIVE - 0x0 | |
| 318 | // RELR64-NEXT: 0x10060 R_AARCH64_RELATIVE - 0x0 | |
| 319 | // RELR64-NEXT: 0x10068 R_AARCH64_RELATIVE - 0x0 | |
| 320 | // RELR64-NEXT: 0x10070 R_AARCH64_RELATIVE - 0x0 | |
| 321 | // RELR64-NEXT: 0x10078 R_AARCH64_RELATIVE - 0x0 | |
| 322 | ||
| 323 | // RELR64-NEXT: 0x10088 R_AARCH64_RELATIVE - 0x0 | |
| 324 | // RELR64-NEXT: 0x10090 R_AARCH64_RELATIVE - 0x0 | |
| 325 | // RELR64-NEXT: 0x10098 R_AARCH64_RELATIVE - 0x0 | |
| 326 | // RELR64-NEXT: 0x100A0 R_AARCH64_RELATIVE - 0x0 | |
| 327 | // RELR64-NEXT: 0x100A8 R_AARCH64_RELATIVE - 0x0 | |
| 328 | // RELR64-NEXT: 0x100B0 R_AARCH64_RELATIVE - 0x0 | |
| 329 | // RELR64-NEXT: 0x100B8 R_AARCH64_RELATIVE - 0x0 | |
| 330 | // RELR64-NEXT: 0x100C0 R_AARCH64_RELATIVE - 0x0 | |
| 331 | // RELR64-NEXT: 0x100C8 R_AARCH64_RELATIVE - 0x0 | |
| 306 | // RELR64-NEXT: 0x20000 R_AARCH64_RELATIVE - 0x0 | |
| 307 | // RELR64-NEXT: 0x20008 R_AARCH64_RELATIVE - 0x0 | |
| 308 | // RELR64-NEXT: 0x20010 R_AARCH64_RELATIVE - 0x0 | |
| 309 | // RELR64-NEXT: 0x20018 R_AARCH64_RELATIVE - 0x0 | |
| 310 | // RELR64-NEXT: 0x20020 R_AARCH64_RELATIVE - 0x0 | |
| 311 | // RELR64-NEXT: 0x20028 R_AARCH64_RELATIVE - 0x0 | |
| 312 | // RELR64-NEXT: 0x20030 R_AARCH64_RELATIVE - 0x0 | |
| 313 | // RELR64-NEXT: 0x20038 R_AARCH64_RELATIVE - 0x0 | |
| 314 | ||
| 315 | // RELR64-NEXT: 0x20048 R_AARCH64_RELATIVE - 0x0 | |
| 316 | // RELR64-NEXT: 0x20050 R_AARCH64_RELATIVE - 0x0 | |
| 317 | // RELR64-NEXT: 0x20058 R_AARCH64_RELATIVE - 0x0 | |
| 318 | // RELR64-NEXT: 0x20060 R_AARCH64_RELATIVE - 0x0 | |
| 319 | // RELR64-NEXT: 0x20068 R_AARCH64_RELATIVE - 0x0 | |
| 320 | // RELR64-NEXT: 0x20070 R_AARCH64_RELATIVE - 0x0 | |
| 321 | // RELR64-NEXT: 0x20078 R_AARCH64_RELATIVE - 0x0 | |
| 322 | ||
| 323 | // RELR64-NEXT: 0x20088 R_AARCH64_RELATIVE - 0x0 | |
| 324 | // RELR64-NEXT: 0x20090 R_AARCH64_RELATIVE - 0x0 | |
| 325 | // RELR64-NEXT: 0x20098 R_AARCH64_RELATIVE - 0x0 | |
| 326 | // RELR64-NEXT: 0x200A0 R_AARCH64_RELATIVE - 0x0 | |
| 327 | // RELR64-NEXT: 0x200A8 R_AARCH64_RELATIVE - 0x0 | |
| 328 | // RELR64-NEXT: 0x200B0 R_AARCH64_RELATIVE - 0x0 | |
| 329 | // RELR64-NEXT: 0x200B8 R_AARCH64_RELATIVE - 0x0 | |
| 330 | // RELR64-NEXT: 0x200C0 R_AARCH64_RELATIVE - 0x0 | |
| 331 | // RELR64-NEXT: 0x200C8 R_AARCH64_RELATIVE - 0x0 | |
| 332 | 332 | // RELR64-NEXT: } |
| 333 | 333 | |
| 334 | 334 | .data |
deps/lld/test/ELF/pack-dyn-relocs2.s+36-36| ... | ... | @@ -5,46 +5,46 @@ |
| 5 | 5 | |
| 6 | 6 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o |
| 7 | 7 | // RUN: ld.lld -pie --pack-dyn-relocs=relr %t.o %t.so -o %t.exe |
| 8 | // RUN: llvm-readobj -relocations %t.exe | FileCheck %s | |
| 8 | // RUN: llvm-readobj -r %t.exe | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | // CHECK: Section (5) .relr.dyn { |
| 11 | // CHECK-NEXT: 0x1000 R_ARM_RELATIVE - 0x0 | |
| 12 | // CHECK-NEXT: 0x1004 R_ARM_RELATIVE - 0x0 | |
| 13 | // CHECK-NEXT: 0x1008 R_ARM_RELATIVE - 0x0 | |
| 14 | // CHECK-NEXT: 0x100C R_ARM_RELATIVE - 0x0 | |
| 15 | // CHECK-NEXT: 0x1010 R_ARM_RELATIVE - 0x0 | |
| 16 | // CHECK-NEXT: 0x1014 R_ARM_RELATIVE - 0x0 | |
| 17 | // CHECK-NEXT: 0x1018 R_ARM_RELATIVE - 0x0 | |
| 18 | // CHECK-NEXT: 0x101C R_ARM_RELATIVE - 0x0 | |
| 19 | // CHECK-NEXT: 0x1020 R_ARM_RELATIVE - 0x0 | |
| 20 | // CHECK-NEXT: 0x1024 R_ARM_RELATIVE - 0x0 | |
| 21 | // CHECK-NEXT: 0x1028 R_ARM_RELATIVE - 0x0 | |
| 22 | // CHECK-NEXT: 0x102C R_ARM_RELATIVE - 0x0 | |
| 23 | // CHECK-NEXT: 0x1030 R_ARM_RELATIVE - 0x0 | |
| 24 | // CHECK-NEXT: 0x1034 R_ARM_RELATIVE - 0x0 | |
| 25 | // CHECK-NEXT: 0x1038 R_ARM_RELATIVE - 0x0 | |
| 26 | // CHECK-NEXT: 0x103C R_ARM_RELATIVE - 0x0 | |
| 27 | // CHECK-NEXT: 0x1040 R_ARM_RELATIVE - 0x0 | |
| 28 | // CHECK-NEXT: 0x1044 R_ARM_RELATIVE - 0x0 | |
| 29 | // CHECK-NEXT: 0x1048 R_ARM_RELATIVE - 0x0 | |
| 30 | // CHECK-NEXT: 0x104C R_ARM_RELATIVE - 0x0 | |
| 31 | // CHECK-NEXT: 0x1050 R_ARM_RELATIVE - 0x0 | |
| 32 | // CHECK-NEXT: 0x1054 R_ARM_RELATIVE - 0x0 | |
| 33 | // CHECK-NEXT: 0x1058 R_ARM_RELATIVE - 0x0 | |
| 34 | // CHECK-NEXT: 0x105C R_ARM_RELATIVE - 0x0 | |
| 35 | // CHECK-NEXT: 0x1060 R_ARM_RELATIVE - 0x0 | |
| 36 | // CHECK-NEXT: 0x1064 R_ARM_RELATIVE - 0x0 | |
| 37 | // CHECK-NEXT: 0x1068 R_ARM_RELATIVE - 0x0 | |
| 38 | // CHECK-NEXT: 0x106C R_ARM_RELATIVE - 0x0 | |
| 39 | // CHECK-NEXT: 0x1070 R_ARM_RELATIVE - 0x0 | |
| 40 | // CHECK-NEXT: 0x1074 R_ARM_RELATIVE - 0x0 | |
| 41 | // CHECK-NEXT: 0x1078 R_ARM_RELATIVE - 0x0 | |
| 42 | // CHECK-NEXT: 0x107C R_ARM_RELATIVE - 0x0 | |
| 43 | // CHECK-NEXT: 0x1080 R_ARM_RELATIVE - 0x0 | |
| 44 | // CHECK-NEXT: 0x1084 R_ARM_RELATIVE - 0x0 | |
| 11 | // CHECK-NEXT: 0x2000 R_ARM_RELATIVE - 0x0 | |
| 12 | // CHECK-NEXT: 0x2004 R_ARM_RELATIVE - 0x0 | |
| 13 | // CHECK-NEXT: 0x2008 R_ARM_RELATIVE - 0x0 | |
| 14 | // CHECK-NEXT: 0x200C R_ARM_RELATIVE - 0x0 | |
| 15 | // CHECK-NEXT: 0x2010 R_ARM_RELATIVE - 0x0 | |
| 16 | // CHECK-NEXT: 0x2014 R_ARM_RELATIVE - 0x0 | |
| 17 | // CHECK-NEXT: 0x2018 R_ARM_RELATIVE - 0x0 | |
| 18 | // CHECK-NEXT: 0x201C R_ARM_RELATIVE - 0x0 | |
| 19 | // CHECK-NEXT: 0x2020 R_ARM_RELATIVE - 0x0 | |
| 20 | // CHECK-NEXT: 0x2024 R_ARM_RELATIVE - 0x0 | |
| 21 | // CHECK-NEXT: 0x2028 R_ARM_RELATIVE - 0x0 | |
| 22 | // CHECK-NEXT: 0x202C R_ARM_RELATIVE - 0x0 | |
| 23 | // CHECK-NEXT: 0x2030 R_ARM_RELATIVE - 0x0 | |
| 24 | // CHECK-NEXT: 0x2034 R_ARM_RELATIVE - 0x0 | |
| 25 | // CHECK-NEXT: 0x2038 R_ARM_RELATIVE - 0x0 | |
| 26 | // CHECK-NEXT: 0x203C R_ARM_RELATIVE - 0x0 | |
| 27 | // CHECK-NEXT: 0x2040 R_ARM_RELATIVE - 0x0 | |
| 28 | // CHECK-NEXT: 0x2044 R_ARM_RELATIVE - 0x0 | |
| 29 | // CHECK-NEXT: 0x2048 R_ARM_RELATIVE - 0x0 | |
| 30 | // CHECK-NEXT: 0x204C R_ARM_RELATIVE - 0x0 | |
| 31 | // CHECK-NEXT: 0x2050 R_ARM_RELATIVE - 0x0 | |
| 32 | // CHECK-NEXT: 0x2054 R_ARM_RELATIVE - 0x0 | |
| 33 | // CHECK-NEXT: 0x2058 R_ARM_RELATIVE - 0x0 | |
| 34 | // CHECK-NEXT: 0x205C R_ARM_RELATIVE - 0x0 | |
| 35 | // CHECK-NEXT: 0x2060 R_ARM_RELATIVE - 0x0 | |
| 36 | // CHECK-NEXT: 0x2064 R_ARM_RELATIVE - 0x0 | |
| 37 | // CHECK-NEXT: 0x2068 R_ARM_RELATIVE - 0x0 | |
| 38 | // CHECK-NEXT: 0x206C R_ARM_RELATIVE - 0x0 | |
| 39 | // CHECK-NEXT: 0x2070 R_ARM_RELATIVE - 0x0 | |
| 40 | // CHECK-NEXT: 0x2074 R_ARM_RELATIVE - 0x0 | |
| 41 | // CHECK-NEXT: 0x2078 R_ARM_RELATIVE - 0x0 | |
| 42 | // CHECK-NEXT: 0x207C R_ARM_RELATIVE - 0x0 | |
| 43 | // CHECK-NEXT: 0x2080 R_ARM_RELATIVE - 0x0 | |
| 44 | // CHECK-NEXT: 0x2084 R_ARM_RELATIVE - 0x0 | |
| 45 | 45 | // CHECK-NEXT: } |
| 46 | 46 | |
| 47 | // RUN: llvm-readobj -s -dynamic-table %t.exe | FileCheck --check-prefix=HEADER %s | |
| 47 | // RUN: llvm-readobj -S --dynamic-table %t.exe | FileCheck --check-prefix=HEADER %s | |
| 48 | 48 | // HEADER: 0x00000023 RELRSZ 0xC |
| 49 | 49 | |
| 50 | 50 | .data |
deps/lld/test/ELF/partition-errors.s created+23| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | // REQUIRES: x86, mips | |
| 2 | // RUN: llvm-mc -triple=x86_64-unknown-linux -filetype=obj -o %t.o %s | |
| 3 | // RUN: echo "SECTIONS {}" > %t.script | |
| 4 | // RUN: not ld.lld --export-dynamic %t.o %t.script 2>&1 | FileCheck %s | |
| 5 | // RUN: echo "PHDRS { text PT_LOAD; }" > %t2.script | |
| 6 | // RUN: not ld.lld --export-dynamic %t.o %t2.script 2>&1 | FileCheck %s | |
| 7 | // RUN: not ld.lld --export-dynamic %t.o --section-start .text=0 2>&1 | FileCheck %s | |
| 8 | // RUN: not ld.lld --export-dynamic %t.o -Ttext=0 2>&1 | FileCheck %s | |
| 9 | // RUN: not ld.lld --export-dynamic %t.o -Tdata=0 2>&1 | FileCheck %s | |
| 10 | // RUN: not ld.lld --export-dynamic %t.o -Tbss=0 2>&1 | FileCheck %s | |
| 11 | ||
| 12 | // RUN: llvm-mc -triple=mipsel-unknown-linux -filetype=obj -o %t2.o %s | |
| 13 | // RUN: not ld.lld --export-dynamic %t2.o 2>&1 | FileCheck %s | |
| 14 | ||
| 15 | // CHECK: error: {{.*}}.o: partitions cannot be used | |
| 16 | ||
| 17 | .section .llvm_sympart.f1,"",@llvm_sympart | |
| 18 | .asciz "part1" | |
| 19 | .quad f1 | |
| 20 | ||
| 21 | .text | |
| 22 | .globl f1 | |
| 23 | f1: |
deps/lld/test/ELF/partition-exidx.s created+49| ... | ... | @@ -0,0 +1,49 @@ |
| 1 | // Test that exidx output sections are created correctly for each partition. | |
| 2 | ||
| 3 | // REQUIRES: arm | |
| 4 | // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o | |
| 5 | // RUN: ld.lld %t.o -o %t -shared --gc-sections | |
| 6 | ||
| 7 | // RUN: llvm-objcopy --extract-main-partition %t %t0 | |
| 8 | // RUN: llvm-objcopy --extract-partition=part1 %t %t1 | |
| 9 | ||
| 10 | // Change upper case to lower case so that we can match unwind info (which is dumped | |
| 11 | // in upper case) against program headers (which are dumped in lower case). | |
| 12 | // RUN: llvm-readelf -l --unwind %t0 | tr A-Z a-z | FileCheck %s | |
| 13 | // RUN: llvm-readelf -l --unwind %t1 | tr A-Z a-z | FileCheck %s | |
| 14 | ||
| 15 | // Each file should have one exidx section for its text section and one sentinel. | |
| 16 | // CHECK: sectionoffset: 0x[[EXIDX_OFFSET:.*]] | |
| 17 | // CHECK-NEXT: entries [ | |
| 18 | // CHECK-NEXT: entry { | |
| 19 | // CHECK-NEXT: functionaddress: 0x[[TEXT_ADDR:.*]] | |
| 20 | // CHECK-NEXT: model: cantunwind | |
| 21 | // CHECK-NEXT: } | |
| 22 | // CHECK-NEXT: entry { | |
| 23 | // CHECK-NEXT: functionaddress: | |
| 24 | // CHECK-NEXT: model: cantunwind | |
| 25 | // CHECK-NEXT: } | |
| 26 | // CHECK-NEXT: ] | |
| 27 | ||
| 28 | // CHECK: load {{[^ ]*}} 0x{{0*}}[[TEXT_ADDR]] {{.*}} r e | |
| 29 | // CHECK: exidx 0x{{0*}}[[EXIDX_OFFSET]] {{.*}} 0x00010 0x00010 r | |
| 30 | ||
| 31 | .section .llvm_sympart,"",%llvm_sympart | |
| 32 | .asciz "part1" | |
| 33 | .4byte p1 | |
| 34 | ||
| 35 | .section .text.p0,"ax",%progbits | |
| 36 | .globl p0 | |
| 37 | p0: | |
| 38 | .fnstart | |
| 39 | bx lr | |
| 40 | .cantunwind | |
| 41 | .fnend | |
| 42 | ||
| 43 | .section .text.p1,"ax",%progbits | |
| 44 | .globl p1 | |
| 45 | p1: | |
| 46 | .fnstart | |
| 47 | bx lr | |
| 48 | .cantunwind | |
| 49 | .fnend |
deps/lld/test/ELF/partition-icf.s created+50| ... | ... | @@ -0,0 +1,50 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux | |
| 3 | // RUN: ld.lld %t.o -o %t --export-dynamic --gc-sections --icf=all | |
| 4 | // RUN: llvm-readelf -S -s %t | FileCheck %s | |
| 5 | ||
| 6 | // CHECK: [[MAIN:[0-9]+]]] .text | |
| 7 | // CHECK: [[P1:[0-9]+]]] .text | |
| 8 | // CHECK: [[P2:[0-9]+]]] .text | |
| 9 | ||
| 10 | // CHECK: Symbol table '.symtab' | |
| 11 | // CHECK: [[P1]] f1 | |
| 12 | // CHECK: [[P2]] f2 | |
| 13 | // CHECK: [[MAIN]] g1 | |
| 14 | // CHECK: [[MAIN]] g2 | |
| 15 | ||
| 16 | .section .llvm_sympart.f1,"",@llvm_sympart | |
| 17 | .asciz "part1" | |
| 18 | .quad f1 | |
| 19 | ||
| 20 | .section .llvm_sympart.f2,"",@llvm_sympart | |
| 21 | .asciz "part2" | |
| 22 | .quad f2 | |
| 23 | ||
| 24 | .section .llvm_sympart.g1,"",@llvm_sympart | |
| 25 | .asciz "part1" | |
| 26 | .quad g1 | |
| 27 | ||
| 28 | .section .llvm_sympart.g2,"",@llvm_sympart | |
| 29 | .asciz "part2" | |
| 30 | .quad g2 | |
| 31 | ||
| 32 | .section .text.f1,"ax",@progbits | |
| 33 | .globl f1 | |
| 34 | f1: | |
| 35 | .byte 1 | |
| 36 | ||
| 37 | .section .text.f2,"ax",@progbits | |
| 38 | .globl f2 | |
| 39 | f2: | |
| 40 | .byte 2 | |
| 41 | ||
| 42 | .section .text.g1,"ax",@progbits | |
| 43 | .globl g1 | |
| 44 | g1: | |
| 45 | .byte 3 | |
| 46 | ||
| 47 | .section .text.g2,"ax",@progbits | |
| 48 | .globl g2 | |
| 49 | g2: | |
| 50 | .byte 3 |
deps/lld/test/ELF/partition-move-to-main.s created+44| ... | ... | @@ -0,0 +1,44 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux | |
| 3 | // RUN: ld.lld %t.o -o %t --export-dynamic --gc-sections | |
| 4 | // RUN: llvm-readelf -S -s %t | FileCheck %s | |
| 5 | ||
| 6 | // Ordinarily, the TLS and IFUNC sections would be split into partitions. | |
| 7 | // Make sure that that didn't happen by checking that there is only one | |
| 8 | // of each section. | |
| 9 | ||
| 10 | // CHECK: .ifunc | |
| 11 | // CHECK: .tdata | |
| 12 | ||
| 13 | // CHECK-NOT: .ifunc | |
| 14 | // CHECK-NOT: .tdata | |
| 15 | ||
| 16 | .section .llvm_sympart.f1,"",@llvm_sympart | |
| 17 | .asciz "part1" | |
| 18 | .quad f1 | |
| 19 | ||
| 20 | .section .text._start,"ax",@progbits | |
| 21 | .globl _start | |
| 22 | _start: | |
| 23 | call tls1 | |
| 24 | call ifunc1 | |
| 25 | ||
| 26 | .section .text.f1,"ax",@progbits | |
| 27 | .globl f1 | |
| 28 | f1: | |
| 29 | call tls2 | |
| 30 | call ifunc2 | |
| 31 | ||
| 32 | .section .ifunc,"ax",@progbits,unique,1 | |
| 33 | .type ifunc1 STT_GNU_IFUNC | |
| 34 | ifunc1: | |
| 35 | ||
| 36 | .section .ifunc,"ax",@progbits,unique,2 | |
| 37 | .type ifunc2 STT_GNU_IFUNC | |
| 38 | ifunc2: | |
| 39 | ||
| 40 | .section .tdata,"awT",@progbits,unique,1 | |
| 41 | tls1: | |
| 42 | ||
| 43 | .section .tdata,"awT",@progbits,unique,2 | |
| 44 | tls2: |
deps/lld/test/ELF/partition-notes.s created+45| ... | ... | @@ -0,0 +1,45 @@ |
| 1 | // Test that notes (both from object files and synthetic) are duplicated into | |
| 2 | // each partition. | |
| 3 | ||
| 4 | // REQUIRES: x86 | |
| 5 | ||
| 6 | // RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux | |
| 7 | // RUN: ld.lld %t.o -o %t --shared --gc-sections --build-id=sha1 | |
| 8 | ||
| 9 | // RUN: llvm-objcopy --extract-main-partition %t %t0 | |
| 10 | // RUN: llvm-objcopy --extract-partition=part1 %t %t1 | |
| 11 | ||
| 12 | // RUN: llvm-readelf --all %t0 | FileCheck --check-prefixes=CHECK,PART0 %s | |
| 13 | // RUN: llvm-readelf --all %t1 | FileCheck --check-prefixes=CHECK,PART1 %s | |
| 14 | ||
| 15 | // CHECK: Program Headers: | |
| 16 | // CHECK: NOTE 0x{{0*}}[[NOTE_OFFSET:[^ ]*]] | |
| 17 | ||
| 18 | // CHECK: Displaying notes found at file offset 0x{{0*}}[[NOTE_OFFSET]] | |
| 19 | // CHECK-NEXT: Owner | |
| 20 | // CHECK-NEXT: foo 0x00000004	NT_VERSION (version) | |
| 21 | // CHECK-NEXT: Displaying notes | |
| 22 | // CHECK-NEXT: Owner | |
| 23 | // CHECK-NEXT: GNU 0x00000014	NT_GNU_BUILD_ID (unique build ID bitstring) | |
| 24 | // CHECK-NEXT: Build ID: 0f4d5297cbbe52e4bea558eeb792944670de22e1 | |
| 25 | ||
| 26 | .section .llvm_sympart,"",@llvm_sympart | |
| 27 | .asciz "part1" | |
| 28 | .quad p1 | |
| 29 | ||
| 30 | .section .data.p0,"aw",@progbits | |
| 31 | .globl p0 | |
| 32 | p0: | |
| 33 | ||
| 34 | .section .data.p1,"aw",@progbits | |
| 35 | .globl p1 | |
| 36 | p1: | |
| 37 | ||
| 38 | .section .note.obj,"a",@note | |
| 39 | .align 4 | |
| 40 | .long 2f-1f | |
| 41 | .long 3f-2f | |
| 42 | .long 1 | |
| 43 | 1: .asciz "foo" | |
| 44 | 2: .asciz "bar" | |
| 45 | 3: |
deps/lld/test/ELF/partition-pack-dyn-relocs.s created+51| ... | ... | @@ -0,0 +1,51 @@ |
| 1 | // Test that both Android and RELR packed relocation sections are created | |
| 2 | // correctly for each partition. | |
| 3 | ||
| 4 | // REQUIRES: x86 | |
| 5 | ||
| 6 | // RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux | |
| 7 | // RUN: ld.lld %t.o -o %t --shared --gc-sections --pack-dyn-relocs=android+relr | |
| 8 | ||
| 9 | // RUN: llvm-objcopy --extract-main-partition %t %t0 | |
| 10 | // RUN: llvm-objcopy --extract-partition=part1 %t %t1 | |
| 11 | ||
| 12 | // RUN: llvm-readelf --all %t0 | FileCheck --check-prefixes=CHECK,PART0 %s | |
| 13 | // RUN: llvm-readelf --all %t1 | FileCheck --check-prefixes=CHECK,PART1 %s | |
| 14 | ||
| 15 | // CHECK: Section Headers: | |
| 16 | // CHECK: .rela.dyn ANDROID_RELA {{0*}}[[ANDROID_RELA_ADDR:[^ ]*]] | |
| 17 | // CHECK: .relr.dyn RELR {{0*}}[[RELR_ADDR:[^ ]*]] | |
| 18 | // CHECK: .data PROGBITS 000000000000[[DATA_SEGMENT:.]]000 | |
| 19 | ||
| 20 | // CHECK: Relocation section '.rela.dyn' | |
| 21 | // CHECK-NEXT: Offset | |
| 22 | // PART0-NEXT: 000000000000[[DATA_SEGMENT]]008 {{.*}} R_X86_64_64 000000000000[[DATA_SEGMENT]]000 p0 + 0 | |
| 23 | // PART1-NEXT: 000000000000[[DATA_SEGMENT]]008 {{.*}} R_X86_64_64 000000000000[[DATA_SEGMENT]]000 p1 + 0 | |
| 24 | // CHECK-EMPTY: | |
| 25 | ||
| 26 | // CHECK: Relocation section '.relr.dyn' | |
| 27 | // CHECK-NEXT: Offset | |
| 28 | // CHECK-NEXT: 000000000000[[DATA_SEGMENT]]000 {{.*}} R_X86_64_RELATIVE | |
| 29 | // CHECK-EMPTY: | |
| 30 | ||
| 31 | // CHECK: Dynamic section | |
| 32 | // CHECK: 0x0000000060000011 (ANDROID_RELA) 0x[[ANDROID_RELA_ADDR]] | |
| 33 | // CHECK: 0x0000000000000024 (RELR) 0x[[RELR_ADDR]] | |
| 34 | ||
| 35 | .section .llvm_sympart,"",@llvm_sympart | |
| 36 | .asciz "part1" | |
| 37 | .quad p1 | |
| 38 | ||
| 39 | .section .data.p0,"aw",@progbits | |
| 40 | .align 8 | |
| 41 | .globl p0 | |
| 42 | p0: | |
| 43 | .quad __ehdr_start | |
| 44 | .quad p0 | |
| 45 | ||
| 46 | .section .data.p1,"aw",@progbits | |
| 47 | .align 8 | |
| 48 | .globl p1 | |
| 49 | p1: | |
| 50 | .quad __ehdr_start | |
| 51 | .quad p1 |
deps/lld/test/ELF/partition-synthetic-sections.s created+241| ... | ... | @@ -0,0 +1,241 @@ |
| 1 | // Test that synthetic sections are created correctly for each partition. | |
| 2 | ||
| 3 | // REQUIRES: x86 | |
| 4 | ||
| 5 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/verneed1.s -o %t1.o | |
| 6 | // RUN: echo "v1 {}; v2 {}; v3 { local: *; };" > %t1.script | |
| 7 | // RUN: ld.lld -shared %t1.o --version-script %t1.script -o %t1.so -soname verneed1.so.0 | |
| 8 | ||
| 9 | // RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux | |
| 10 | // RUN: echo "x1 { global: p0; }; x2 { global: p1; p1alias; };" > %t.script | |
| 11 | // RUN: ld.lld %t.o %t1.so --version-script %t.script -o %t --shared --gc-sections --eh-frame-hdr -soname main.so | |
| 12 | ||
| 13 | // RUN: llvm-objcopy --extract-main-partition %t %t0 | |
| 14 | // RUN: llvm-objcopy --extract-partition=part1 %t %t1 | |
| 15 | ||
| 16 | // RUN: llvm-readelf --all --unwind %t0 | FileCheck --check-prefixes=CHECK,PART0 %s | |
| 17 | // RUN: llvm-readelf --all --unwind %t1 | FileCheck --check-prefixes=CHECK,PART1 %s | |
| 18 | ||
| 19 | // FIXME: llvm-objcopy does not preserve padding (see pr42145) so for now we | |
| 20 | // check the combined output file. | |
| 21 | // RUN: od -Ax -x %t | FileCheck %s -check-prefix=FILL | |
| 22 | ||
| 23 | // RUN: llvm-objdump -s -j .rodata -j .dynstr %t0 | FileCheck --check-prefix=PART-INDEX %s | |
| 24 | ||
| 25 | // CHECK: Section Headers: | |
| 26 | // CHECK-NEXT: Name | |
| 27 | // CHECK-NEXT: NULL | |
| 28 | // CHECK-NEXT: .dynsym DYNSYM {{0*}}[[DYNSYM_ADDR:[^ ]*]] | |
| 29 | // CHECK-NEXT: .gnu.version VERSYM {{0*}}[[VERSYM_ADDR:[^ ]*]] | |
| 30 | // CHECK-NEXT: .gnu.version_d VERDEF {{0*}}[[VERDEF_ADDR:[^ ]*]] | |
| 31 | // CHECK-NEXT: .gnu.version_r VERNEED {{0*}}[[VERNEED_ADDR:[^ ]*]] | |
| 32 | // CHECK-NEXT: .gnu.hash GNU_HASH {{0*}}[[GNU_HASH_ADDR:[^ ]*]] | |
| 33 | // CHECK-NEXT: .hash HASH {{0*}}[[HASH_ADDR:[^ ]*]] | |
| 34 | // CHECK-NEXT: .dynstr STRTAB {{0*}}[[DYNSTR_ADDR:[^ ]*]] | |
| 35 | // CHECK-NEXT: .rela.dyn RELA {{0*}}[[RELA_DYN_ADDR:[^ ]*]] | |
| 36 | // PART0-NEXT: .rela.plt RELA {{0*}}[[RELA_PLT_ADDR:[^ ]*]] | |
| 37 | // CHECK-NEXT: .eh_frame_hdr PROGBITS {{0*}}[[EH_FRAME_HDR_ADDR:[^ ]*]] | |
| 38 | // CHECK-NEXT: .eh_frame PROGBITS {{0*}}[[EH_FRAME_ADDR:[^ ]*]] | |
| 39 | // PART0-NEXT: .rodata PROGBITS | |
| 40 | // CHECK-NEXT: .text PROGBITS {{0*}}[[TEXT_ADDR:[^ ]*]] | |
| 41 | // PART0-NEXT: .plt PROGBITS | |
| 42 | // PART0-NEXT: .init_array INIT_ARRAY {{0*}}[[INIT_ARRAY_ADDR:[^ ]*]] | |
| 43 | // CHECK-NEXT: .dynamic DYNAMIC {{0*}}[[DYNAMIC_ADDR:[^ ]*]] | |
| 44 | // CHECK-NEXT: .data PROGBITS 000000000000[[DATA_SEGMENT:.]]000 | |
| 45 | // PART0-NEXT: .got.plt PROGBITS {{0*}}[[GOT_PLT_ADDR:[^ ]*]] | |
| 46 | // PART0-NEXT: .part.end NOBITS {{0*}}[[PART_END_ADDR:[^ ]*]] | |
| 47 | // CHECK-NEXT: .comment PROGBITS | |
| 48 | // CHECK-NEXT: .symtab SYMTAB | |
| 49 | // CHECK-NEXT: .shstrtab STRTAB | |
| 50 | // CHECK-NEXT: .strtab STRTAB | |
| 51 | // CHECK-NEXT: Key to Flags | |
| 52 | ||
| 53 | // CHECK: Relocation section '.rela.dyn' | |
| 54 | // CHECK-NEXT: Offset | |
| 55 | // PART0-NEXT: 000000000000[[DATA_SEGMENT]]000 {{.*}} R_X86_64_64 {{.*}} f1@v3 + 0 | |
| 56 | // PART0-NEXT: {{0*}}[[INIT_ARRAY_ADDR]] {{.*}} R_X86_64_64 {{.*}} p0@@x1 + 0 | |
| 57 | // PART1-NEXT: 000000000000[[DATA_SEGMENT]]018 {{.*}} R_X86_64_RELATIVE 3000 | |
| 58 | // PART1-NEXT: 000000000000[[DATA_SEGMENT]]000 {{.*}} R_X86_64_64 {{.*}} f2@v2 + 0 | |
| 59 | // PART1-NEXT: 000000000000[[DATA_SEGMENT]]008 {{.*}} R_X86_64_64 {{.*}} p0@@x1 + 0 | |
| 60 | // PART1-NEXT: 000000000000[[DATA_SEGMENT]]010 {{.*}} R_X86_64_64 {{.*}} p0@@x1 + 0 | |
| 61 | // CHECK-EMPTY: | |
| 62 | ||
| 63 | // PART0: Relocation section '.rela.plt' | |
| 64 | // PART0-NEXT: Offset | |
| 65 | // PART0-NEXT: 000000000000[[DATA_SEGMENT]]020 {{.*}} R_X86_64_JUMP_SLOT {{.*}} f1@v3 + 0 | |
| 66 | // PART0-NEXT: 000000000000[[DATA_SEGMENT]]028 {{.*}} R_X86_64_JUMP_SLOT {{.*}} f2@v2 + 0 | |
| 67 | // PART0-EMPTY: | |
| 68 | ||
| 69 | // CHECK: Symbol table '.dynsym' | |
| 70 | // PART0: 1: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND f1@v3 | |
| 71 | // PART0: 2: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND f2@v2 | |
| 72 | // PART0: 3: {{0*}}[[TEXT_ADDR]] 0 NOTYPE GLOBAL DEFAULT {{.*}} p0@@x1 | |
| 73 | // PART1: 1: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND f2@v2 | |
| 74 | // PART1: 2: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND p0@@x1 | |
| 75 | // PART1: 3: {{0*}}[[TEXT_ADDR]] 0 NOTYPE GLOBAL DEFAULT {{.*}} p1@@x2 | |
| 76 | // PART1: 4: {{0*}}[[TEXT_ADDR]] 0 NOTYPE GLOBAL DEFAULT {{.*}} p1alias@@x2 | |
| 77 | // CHECK-EMPTY: | |
| 78 | ||
| 79 | // PART0: Symbol table '.symtab' | |
| 80 | // PART0: 000000000000048c 0 NOTYPE LOCAL HIDDEN {{.*}} __part_index_begin | |
| 81 | // PART0: 0000000000000498 0 NOTYPE LOCAL HIDDEN {{.*}} __part_index_end | |
| 82 | ||
| 83 | // PART-INDEX: Contents of section .dynstr: | |
| 84 | // PART-INDEX-NEXT: 03a8 00663100 66320070 30007061 72743100 .f1.f2.p0.part1. | |
| 85 | // PART-INDEX: Contents of section .rodata: | |
| 86 | // 0x48c + 0xffffff26 = 0x3b2 | |
| 87 | // 0x490 + 0x3b70 = 0x4000 | |
| 88 | // PART-INDEX-NEXT: 048c 26ffffff 703b0000 00400000 | |
| 89 | ||
| 90 | // CHECK: {{.*}}EH_FRAME Header | |
| 91 | // CHECK: Address: 0x[[EH_FRAME_HDR_ADDR]] | |
| 92 | // CHECK: eh_frame_ptr: 0x[[EH_FRAME_ADDR]] | |
| 93 | // CHECK: initial_location: 0x[[TEXT_ADDR]] | |
| 94 | // CHECK: address: 0x[[FDE_ADDR:.*]] | |
| 95 | ||
| 96 | // CHECK: .eh_frame section | |
| 97 | // CHECK: 0x[[EH_FRAME_ADDR]]] CIE length=20 | |
| 98 | // CHECK-NOT: FDE | |
| 99 | // CHECK: 0x[[FDE_ADDR]]] FDE length=20 cie={{.}}0x[[EH_FRAME_ADDR]] | |
| 100 | // CHECK-NEXT: initial_location: 0x[[TEXT_ADDR]] | |
| 101 | // CHECK-NOT: FDE | |
| 102 | // CHECK: CIE length=0 | |
| 103 | ||
| 104 | // CHECK: Dynamic section | |
| 105 | // CHECK-NEXT: Tag | |
| 106 | // CHECK-NEXT: 0x0000000000000001 (NEEDED) Shared library: [verneed1.so.0] | |
| 107 | // PART0-NEXT: 0x000000000000000e (SONAME) Library soname: [main.so] | |
| 108 | // PART1-NEXT: 0x0000000000000001 (NEEDED) Shared library: [main.so] | |
| 109 | // PART1-NEXT: 0x000000000000000e (SONAME) Library soname: [part1] | |
| 110 | // CHECK-NEXT: 0x0000000000000007 (RELA) 0x[[RELA_DYN_ADDR]] | |
| 111 | // CHECK-NEXT: 0x0000000000000008 (RELASZ) | |
| 112 | // CHECK-NEXT: 0x0000000000000009 (RELAENT) 24 (bytes) | |
| 113 | // PART1-NEXT: 0x000000006ffffff9 (RELACOUNT) 1 | |
| 114 | // PART0-NEXT: 0x0000000000000017 (JMPREL) 0x[[RELA_PLT_ADDR]] | |
| 115 | // PART0-NEXT: 0x0000000000000002 (PLTRELSZ) 48 (bytes) | |
| 116 | // PART0-NEXT: 0x0000000000000003 (PLTGOT) 0x[[GOT_PLT_ADDR]] | |
| 117 | // PART0-NEXT: 0x0000000000000014 (PLTREL) RELA | |
| 118 | // CHECK-NEXT: 0x0000000000000006 (SYMTAB) 0x[[DYNSYM_ADDR]] | |
| 119 | // CHECK-NEXT: 0x000000000000000b (SYMENT) 24 (bytes) | |
| 120 | // CHECK-NEXT: 0x0000000000000005 (STRTAB) 0x[[DYNSTR_ADDR]] | |
| 121 | // CHECK-NEXT: 0x000000000000000a (STRSZ) | |
| 122 | // CHECK-NEXT: 0x000000006ffffef5 (GNU_HASH) 0x[[GNU_HASH_ADDR]] | |
| 123 | // CHECK-NEXT: 0x0000000000000004 (HASH) 0x[[HASH_ADDR]] | |
| 124 | // PART0-NEXT: 0x0000000000000019 (INIT_ARRAY) 0x[[INIT_ARRAY_ADDR]] | |
| 125 | // PART0-NEXT: 0x000000000000001b (INIT_ARRAYSZ) 8 (bytes) | |
| 126 | // CHECK-NEXT: 0x000000006ffffff0 (VERSYM) 0x[[VERSYM_ADDR]] | |
| 127 | // CHECK-NEXT: 0x000000006ffffffc (VERDEF) 0x[[VERDEF_ADDR]] | |
| 128 | // CHECK-NEXT: 0x000000006ffffffd (VERDEFNUM) 3 | |
| 129 | // CHECK-NEXT: 0x000000006ffffffe (VERNEED) 0x[[VERNEED_ADDR]] | |
| 130 | // CHECK-NEXT: 0x000000006fffffff (VERNEEDNUM) 1 | |
| 131 | // PART0-NEXT: 0x0000000000000000 (NULL) 0x0 | |
| 132 | ||
| 133 | // CHECK: Program Headers: | |
| 134 | // CHECK-NEXT: Type | |
| 135 | // PART0-NEXT: PHDR {{.*}} 0x000230 0x000230 R | |
| 136 | // PART1-NEXT: PHDR {{.*}} 0x0001f8 0x0001f8 R | |
| 137 | // PART0-NEXT: LOAD 0x000000 0x0000000000000000 0x0000000000000000 {{.*}} R 0x1000 | |
| 138 | // PART0-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 {{.*}} R E 0x1000 | |
| 139 | // PART0-NEXT: LOAD 0x002000 0x0000000000002000 0x0000000000002000 {{.*}} RW 0x1000 | |
| 140 | // PART0-NEXT: LOAD 0x003000 0x0000000000003000 0x0000000000003000 {{.*}} RW 0x1000 | |
| 141 | // PART0-NEXT: LOAD 0x004000 0x0000000000008000 0x0000000000008000 0x000000 0x001000 RW 0x1000 | |
| 142 | // PART1-NEXT: LOAD 0x000000 0x0000000000004000 0x0000000000004000 {{.*}} R 0x1000 | |
| 143 | // PART1-NEXT: LOAD 0x001000 0x0000000000005000 0x0000000000005000 {{.*}} R E 0x1000 | |
| 144 | // PART1-NEXT: LOAD 0x002000 0x0000000000006000 0x0000000000006000 {{.*}} RW 0x1000 | |
| 145 | // PART1-NEXT: LOAD 0x003000 0x0000000000007000 0x0000000000007000 {{.*}} RW 0x1000 | |
| 146 | // CHECK-NEXT: DYNAMIC {{.*}} 0x{{0*}}[[DYNAMIC_ADDR]] 0x{{0*}}[[DYNAMIC_ADDR]] {{.*}} RW 0x8 | |
| 147 | // PART0-NEXT: GNU_RELRO 0x002000 0x0000000000002000 0x0000000000002000 {{.*}} R 0x1 | |
| 148 | // PART1-NEXT: GNU_RELRO 0x002000 0x0000000000006000 0x0000000000006000 {{.*}} R 0x1 | |
| 149 | // CHECK-NEXT: GNU_EH_FRAME {{.*}} 0x{{0*}}[[EH_FRAME_HDR_ADDR]] 0x{{0*}}[[EH_FRAME_HDR_ADDR]] {{.*}} R 0x4 | |
| 150 | // CHECK-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x0 | |
| 151 | // CHECK-EMPTY: | |
| 152 | ||
| 153 | // CHECK: Version symbols section '.gnu.version' | |
| 154 | // CHECK-NEXT: Addr: | |
| 155 | // PART0-NEXT: 000: 0 (*local*) 4 (v3) 5 (v2) 2 (x1) | |
| 156 | // PART1-NEXT: 000: 0 (*local*) 5 (v2) 2 (x1) 3 (x2) | |
| 157 | ||
| 158 | // CHECK: Version definition section '.gnu.version_d' | |
| 159 | // CHECK-NEXT: Addr: | |
| 160 | // PART0-NEXT: 0x0000: Rev: 1 Flags: BASE Index: 1 Cnt: 1 Name: main.so | |
| 161 | // PART1-NEXT: 0x0000: Rev: 1 Flags: BASE Index: 1 Cnt: 1 Name: part1 | |
| 162 | // CHECK-NEXT: 0x001c: Rev: 1 Flags: none Index: 2 Cnt: 1 Name: x1 | |
| 163 | // CHECK-NEXT: 0x0038: Rev: 1 Flags: none Index: 3 Cnt: 1 Name: x2 | |
| 164 | ||
| 165 | // CHECK: Version needs section '.gnu.version_r' | |
| 166 | // CHECK-NEXT: Addr: | |
| 167 | // CHECK-NEXT: 0x0000: Version: 1 File: verneed1.so.0 Cnt: 2 | |
| 168 | // CHECK-NEXT: 0x0010: Name: v2 Flags: none Version: 5 | |
| 169 | // CHECK-NEXT: 0x0020: Name: v3 Flags: none Version: 4 | |
| 170 | ||
| 171 | // PART0: Histogram for bucket list length (total of 4 buckets) | |
| 172 | // PART0-NEXT: Length Number % of total Coverage | |
| 173 | // PART0-NEXT: 0 1 ( 25.0%) 0.0% | |
| 174 | // PART0-NEXT: 1 3 ( 75.0%) 100.0% | |
| 175 | // PART0-NEXT: Histogram for `.gnu.hash' bucket list length (total of 1 buckets) | |
| 176 | // PART0-NEXT: Length Number % of total Coverage | |
| 177 | // PART0-NEXT: 0 0 ( 0.0%) 0.0% | |
| 178 | // PART0-NEXT: 1 1 (100.0%) 100.0% | |
| 179 | ||
| 180 | // PART1: Histogram for bucket list length (total of 5 buckets) | |
| 181 | // PART1-NEXT: Length Number % of total Coverage | |
| 182 | // PART1-NEXT: 0 3 ( 60.0%) 0.0% | |
| 183 | // PART1-NEXT: 1 2 ( 40.0%) 100.0% | |
| 184 | // PART1-NEXT: Histogram for `.gnu.hash' bucket list length (total of 1 buckets) | |
| 185 | // PART1-NEXT: Length Number % of total Coverage | |
| 186 | // PART1-NEXT: 0 0 ( 0.0%) 0.0% | |
| 187 | // PART1-NEXT: 1 0 ( 0.0%) 0.0% | |
| 188 | // PART1-NEXT: 2 1 (100.0%) 100.0% | |
| 189 | ||
| 190 | // FILL: 001040 cccc cccc cccc cccc cccc cccc cccc cccc | |
| 191 | // FILL-NEXT: * | |
| 192 | // FILL-NEXT: 002000 | |
| 193 | ||
| 194 | // FILL: 005010 cccc cccc cccc cccc cccc cccc cccc cccc | |
| 195 | // FILL-NEXT: * | |
| 196 | // FILL-NEXT: 006000 | |
| 197 | ||
| 198 | .section .llvm_sympart,"",@llvm_sympart | |
| 199 | .asciz "part1" | |
| 200 | .quad p1 | |
| 201 | ||
| 202 | .section .llvm_sympart2,"",@llvm_sympart | |
| 203 | .asciz "part1" | |
| 204 | .quad p1alias | |
| 205 | ||
| 206 | .section .text.p0,"ax",@progbits | |
| 207 | .globl p0 | |
| 208 | p0: | |
| 209 | .cfi_startproc | |
| 210 | lea d0(%rip), %rax | |
| 211 | call f1 | |
| 212 | ret | |
| 213 | .cfi_endproc | |
| 214 | ||
| 215 | .section .data.d0,"aw",@progbits | |
| 216 | d0: | |
| 217 | .quad f1 | |
| 218 | ||
| 219 | .section .text.p1,"ax",@progbits | |
| 220 | .globl p1 | |
| 221 | p1: | |
| 222 | .globl p1alias | |
| 223 | p1alias: | |
| 224 | .cfi_startproc | |
| 225 | lea d1(%rip), %rax | |
| 226 | call f2 | |
| 227 | ret | |
| 228 | .cfi_endproc | |
| 229 | ||
| 230 | .section .data.d1,"aw",@progbits | |
| 231 | d1: | |
| 232 | .quad f2 | |
| 233 | .quad p0 | |
| 234 | .quad p0 | |
| 235 | .quad d0 | |
| 236 | ||
| 237 | .section .init_array,"aw",@init_array | |
| 238 | .quad p0 | |
| 239 | ||
| 240 | .globl __part_index_begin | |
| 241 | .globl __part_index_end |
deps/lld/test/ELF/partition-thunk-reuse.s created+45| ... | ... | @@ -0,0 +1,45 @@ |
| 1 | // REQUIRES: arm | |
| 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj --triple=armv7-unknown-linux -arm-add-build-attributes | |
| 3 | // RUN: ld.lld %t.o -o %t --export-dynamic --gc-sections | |
| 4 | // RUN: llvm-nm %t | FileCheck %s | |
| 5 | ||
| 6 | // CHECK: __Thumbv7ABSLongThunk__start | |
| 7 | // CHECK: __Thumbv7ABSLongThunk__start | |
| 8 | ||
| 9 | // CHECK: __Thumbv7ABSLongThunk_foo | |
| 10 | // CHECK-NOT: __Thumbv7ABSLongThunk_foo | |
| 11 | ||
| 12 | .thumb | |
| 13 | ||
| 14 | .section .llvm_sympart.g1,"",%llvm_sympart | |
| 15 | .asciz "part1" | |
| 16 | .4byte f1 | |
| 17 | ||
| 18 | .section .llvm_sympart.g2,"",%llvm_sympart | |
| 19 | .asciz "part2" | |
| 20 | .4byte f2 | |
| 21 | ||
| 22 | .section .text._start,"ax",%progbits | |
| 23 | .globl _start | |
| 24 | _start: | |
| 25 | bx lr | |
| 26 | foo: | |
| 27 | b f0 | |
| 28 | .zero 17*1048576 | |
| 29 | ||
| 30 | .section .text.f0,"ax",%progbits | |
| 31 | .globl f0 | |
| 32 | f0: | |
| 33 | b foo | |
| 34 | ||
| 35 | .section .text.f1,"aw",%progbits | |
| 36 | .globl f1 | |
| 37 | f1: | |
| 38 | b _start | |
| 39 | b foo | |
| 40 | ||
| 41 | .section .text.f2,"ax",%progbits | |
| 42 | .globl f2 | |
| 43 | f2: | |
| 44 | b _start | |
| 45 | b foo |
deps/lld/test/ELF/partitions.s created+63| ... | ... | @@ -0,0 +1,63 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux | |
| 3 | // RUN: ld.lld %t.o -o %t --export-dynamic --gc-sections | |
| 4 | // RUN: llvm-readelf -S -s %t | FileCheck %s | |
| 5 | ||
| 6 | // This is basically lld/docs/partitions.dot in object file form. | |
| 7 | // Test that the sections are correctly allocated to partitions. | |
| 8 | ||
| 9 | // CHECK: [[MAIN:[0-9]+]]] .text | |
| 10 | // CHECK: [[P1:[0-9]+]]] .text | |
| 11 | // CHECK: [[P2:[0-9]+]]] .text | |
| 12 | ||
| 13 | // CHECK: Symbol table '.symtab' | |
| 14 | // CHECK: [[MAIN]] f3 | |
| 15 | // CHECK: [[P1]] f4 | |
| 16 | // CHECK: [[MAIN]] f5 | |
| 17 | // CHECK: [[P2]] f6 | |
| 18 | // CHECK: [[MAIN]] _start | |
| 19 | // CHECK: [[P1]] f1 | |
| 20 | // CHECK: [[P2]] f2 | |
| 21 | ||
| 22 | .section .llvm_sympart.f1,"",@llvm_sympart | |
| 23 | .asciz "part1" | |
| 24 | .quad f1 | |
| 25 | ||
| 26 | .section .llvm_sympart.f2,"",@llvm_sympart | |
| 27 | .asciz "part2" | |
| 28 | .quad f2 | |
| 29 | ||
| 30 | .section .text._start,"ax",@progbits | |
| 31 | .globl _start | |
| 32 | _start: | |
| 33 | call f3 | |
| 34 | ||
| 35 | .section .text.f1,"ax",@progbits | |
| 36 | .globl f1 | |
| 37 | f1: | |
| 38 | call f3 | |
| 39 | call f4 | |
| 40 | call f5 | |
| 41 | ||
| 42 | .section .text.f2,"ax",@progbits | |
| 43 | .globl f2 | |
| 44 | f2: | |
| 45 | call f3 | |
| 46 | call f5 | |
| 47 | call f6 | |
| 48 | ||
| 49 | .section .text.f3,"ax",@progbits | |
| 50 | f3: | |
| 51 | ret | |
| 52 | ||
| 53 | .section .text.f4,"ax",@progbits | |
| 54 | f4: | |
| 55 | ret | |
| 56 | ||
| 57 | .section .text.f5,"ax",@progbits | |
| 58 | f5: | |
| 59 | ret | |
| 60 | ||
| 61 | .section .text.f6,"ax",@progbits | |
| 62 | f6: | |
| 63 | ret |
deps/lld/test/ELF/phdr-align.s+1-1| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | # RUN: .data : { *(.data) } \ |
| 8 | 8 | # RUN: .text : { *(.text) } }" > %t.script |
| 9 | 9 | # RUN: ld.lld %t.o --script %t.script -o %t |
| 10 | # RUN: llvm-readobj -sections -symbols %t | FileCheck %s | |
| 10 | # RUN: llvm-readobj --sections --symbols %t | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | # CHECK: Sections [ |
| 13 | 13 | # CHECK-NEXT: Section { |
deps/lld/test/ELF/pie-weak.s+4-2| ... | ... | @@ -1,6 +1,8 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/dummy-shared.s -o %t1.o | |
| 3 | # RUN: ld.lld %t1.o -shared -o %t1.so | |
| 2 | 4 | # RUN: llvm-mc -filetype=obj -relax-relocations=false -triple=x86_64-unknown-linux %s -o %t.o |
| 3 | # RUN: ld.lld --hash-style=sysv -pie %t.o -o %t | |
| 5 | # RUN: ld.lld --hash-style=sysv -pie %t.o %t1.so -o %t | |
| 4 | 6 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOCS %s |
| 5 | 7 | # RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s |
| 6 | 8 | |
| ... | ... | @@ -15,6 +17,6 @@ |
| 15 | 17 | .globl _start |
| 16 | 18 | _start: |
| 17 | 19 | # DISASM: _start: |
| 18 | # DISASM-NEXT: 1000: 48 8b 05 99 10 00 00 movq 4249(%rip), %rax | |
| 20 | # DISASM-NEXT: 1000: 48 8b 05 a9 10 00 00 movq 4265(%rip), %rax | |
| 19 | 21 | # ^ .got - (.text + 7) |
| 20 | 22 | mov foo@gotpcrel(%rip), %rax |
deps/lld/test/ELF/pie.s+5-5| ... | ... | @@ -3,16 +3,16 @@ |
| 3 | 3 | |
| 4 | 4 | ## Default is no PIE. |
| 5 | 5 | # RUN: ld.lld %t1.o -o %t |
| 6 | # RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t \ | |
| 6 | # RUN: llvm-readobj --file-headers --sections -l --symbols -r %t \ | |
| 7 | 7 | # RUN: | FileCheck %s --check-prefix=NOPIE |
| 8 | 8 | |
| 9 | 9 | ## Check -pie. |
| 10 | 10 | # RUN: ld.lld -pie %t1.o -o %t |
| 11 | # RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s | |
| 11 | # RUN: llvm-readobj --file-headers --sections -l --symbols -r %t | FileCheck %s | |
| 12 | 12 | |
| 13 | 13 | ## Test --pic-executable alias |
| 14 | 14 | # RUN: ld.lld --pic-executable %t1.o -o %t |
| 15 | # RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s | |
| 15 | # RUN: llvm-readobj --file-headers --sections -l --symbols -r %t | FileCheck %s | |
| 16 | 16 | |
| 17 | 17 | # CHECK: ElfHeader { |
| 18 | 18 | # CHECK-NEXT: Ident { |
| ... | ... | @@ -49,9 +49,9 @@ |
| 49 | 49 | |
| 50 | 50 | ## Check -nopie |
| 51 | 51 | # RUN: ld.lld -no-pie %t1.o -o %t2 |
| 52 | # RUN: llvm-readobj -file-headers -r %t2 | FileCheck %s --check-prefix=NOPIE | |
| 52 | # RUN: llvm-readobj --file-headers -r %t2 | FileCheck %s --check-prefix=NOPIE | |
| 53 | 53 | # RUN: ld.lld -no-pic-executable %t1.o -o %t2 |
| 54 | # RUN: llvm-readobj -file-headers -r %t2 | FileCheck %s --check-prefix=NOPIE | |
| 54 | # RUN: llvm-readobj --file-headers -r %t2 | FileCheck %s --check-prefix=NOPIE | |
| 55 | 55 | # NOPIE-NOT: Type: SharedObject |
| 56 | 56 | |
| 57 | 57 | .globl _start |
deps/lld/test/ELF/plt-aarch64.s+36-34| ... | ... | @@ -4,10 +4,10 @@ |
| 4 | 4 | // RUN: ld.lld -shared %t2.o -o %t2.so |
| 5 | 5 | // RUN: ld.lld -shared %t.o %t2.so -o %t.so |
| 6 | 6 | // RUN: ld.lld %t.o %t2.so -o %t.exe |
| 7 | // RUN: llvm-readobj -s -r %t.so | FileCheck --check-prefix=CHECKDSO %s | |
| 7 | // RUN: llvm-readobj -S -r %t.so | FileCheck --check-prefix=CHECKDSO %s | |
| 8 | 8 | // RUN: llvm-objdump -s -section=.got.plt %t.so | FileCheck --check-prefix=DUMPDSO %s |
| 9 | 9 | // RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASMDSO %s |
| 10 | // RUN: llvm-readobj -s -r %t.exe | FileCheck --check-prefix=CHECKEXE %s | |
| 10 | // RUN: llvm-readobj -S -r %t.exe | FileCheck --check-prefix=CHECKEXE %s | |
| 11 | 11 | // RUN: llvm-objdump -s -section=.got.plt %t.exe | FileCheck --check-prefix=DUMPEXE %s |
| 12 | 12 | // RUN: llvm-objdump -d %t.exe | FileCheck --check-prefix=DISASMEXE %s |
| 13 | 13 | |
| ... | ... | @@ -30,7 +30,7 @@ |
| 30 | 30 | // CHECKDSO-NEXT: SHF_ALLOC |
| 31 | 31 | // CHECKDSO-NEXT: SHF_WRITE |
| 32 | 32 | // CHECKDSO-NEXT: ] |
| 33 | // CHECKDSO-NEXT: Address: 0x20000 | |
| 33 | // CHECKDSO-NEXT: Address: 0x30000 | |
| 34 | 34 | // CHECKDSO-NEXT: Offset: |
| 35 | 35 | // CHECKDSO-NEXT: Size: 48 |
| 36 | 36 | // CHECKDSO-NEXT: Link: |
| ... | ... | @@ -40,23 +40,23 @@ |
| 40 | 40 | // CHECKDSO: Relocations [ |
| 41 | 41 | // CHECKDSO-NEXT: Section ({{.*}}) .rela.plt { |
| 42 | 42 | |
| 43 | // &(.got.plt[3]) = 0x20000 + 3 * 8 = 0x30018 | |
| 44 | // CHECKDSO-NEXT: 0x20018 R_AARCH64_JUMP_SLOT foo | |
| 43 | // &(.got.plt[3]) = 0x30000 + 3 * 8 = 0x30018 | |
| 44 | // CHECKDSO-NEXT: 0x30018 R_AARCH64_JUMP_SLOT foo | |
| 45 | 45 | |
| 46 | // &(.got.plt[4]) = 0x20000 + 4 * 8 = 0x30020 | |
| 47 | // CHECKDSO-NEXT: 0x20020 R_AARCH64_JUMP_SLOT bar | |
| 46 | // &(.got.plt[4]) = 0x30000 + 4 * 8 = 0x30020 | |
| 47 | // CHECKDSO-NEXT: 0x30020 R_AARCH64_JUMP_SLOT bar | |
| 48 | 48 | |
| 49 | // &(.got.plt[5]) = 0x20000 + 5 * 8 = 0x30028 | |
| 50 | // CHECKDSO-NEXT: 0x20028 R_AARCH64_JUMP_SLOT weak | |
| 49 | // &(.got.plt[5]) = 0x30000 + 5 * 8 = 0x30028 | |
| 50 | // CHECKDSO-NEXT: 0x30028 R_AARCH64_JUMP_SLOT weak | |
| 51 | 51 | // CHECKDSO-NEXT: } |
| 52 | 52 | // CHECKDSO-NEXT: ] |
| 53 | 53 | |
| 54 | 54 | // DUMPDSO: Contents of section .got.plt: |
| 55 | 55 | // .got.plt[0..2] = 0 (reserved) |
| 56 | 56 | // .got.plt[3..5] = .plt = 0x10010 |
| 57 | // DUMPDSO-NEXT: 20000 00000000 00000000 00000000 00000000 ................ | |
| 58 | // DUMPDSO-NEXT: 20010 00000000 00000000 10000100 00000000 ................ | |
| 59 | // DUMPDSO-NEXT: 20020 10000100 00000000 10000100 00000000 ................ | |
| 57 | // DUMPDSO-NEXT: 30000 00000000 00000000 00000000 00000000 ................ | |
| 58 | // DUMPDSO-NEXT: 30010 00000000 00000000 10000100 00000000 ................ | |
| 59 | // DUMPDSO-NEXT: 30020 10000100 00000000 10000100 00000000 ................ | |
| 60 | 60 | |
| 61 | 61 | // DISASMDSO: _start: |
| 62 | 62 | // 0x10030 - 0x10000 = 0x30 = 48 |
| ... | ... | @@ -70,11 +70,12 @@ |
| 70 | 70 | // DISASMDSO-NEXT: 1000c:	1f 20 03 d5 	nop |
| 71 | 71 | |
| 72 | 72 | // DISASMDSO: Disassembly of section .plt: |
| 73 | // DISASMDSO-EMPTY: | |
| 73 | 74 | // DISASMDSO-NEXT: .plt: |
| 74 | 75 | // DISASMDSO-NEXT: 10010:	f0 7b bf a9 	stp	x16, x30, [sp, #-16]! |
| 75 | 76 | // &(.got.plt[2]) = 0x3000 + 2 * 8 = 0x3010 |
| 76 | // Page(0x20010) - Page(0x10014) = 0x20000 - 0x10000 = 0x10000 = 65536 | |
| 77 | // DISASMDSO-NEXT: 10014:	90 00 00 90 	adrp	x16, #65536 | |
| 77 | // Page(0x30010) - Page(0x10014) = 0x30000 - 0x10000 = 0x20000 = 131072 | |
| 78 | // DISASMDSO-NEXT: 10014:	10 01 00 90 	adrp	x16, #131072 | |
| 78 | 79 | // 0x3010 & 0xFFF = 0x10 = 16 |
| 79 | 80 | // DISASMDSO-NEXT: 10018:	11 0a 40 f9 ldr x17, [x16, #16] |
| 80 | 81 | // DISASMDSO-NEXT: 1001c:	10 42 00 91 	add	x16, x16, #16 |
| ... | ... | @@ -84,30 +85,30 @@ |
| 84 | 85 | // DISASMDSO-NEXT: 1002c:	1f 20 03 d5 	nop |
| 85 | 86 | |
| 86 | 87 | // foo@plt |
| 87 | // Page(0x30018) - Page(0x10030) = 0x20000 - 0x10000 = 0x10000 = 65536 | |
| 88 | // Page(0x30018) - Page(0x10030) = 0x30000 - 0x10000 = 0x20000 = 131072 | |
| 88 | 89 | // DISASMDSO-EMPTY: |
| 89 | 90 | // DISASMDSO-NEXT: foo@plt: |
| 90 | // DISASMDSO-NEXT: 10030:	90 00 00 90 	adrp	x16, #65536 | |
| 91 | // DISASMDSO-NEXT: 10030:	10 01 00 90 	adrp	x16, #131072 | |
| 91 | 92 | // 0x3018 & 0xFFF = 0x18 = 24 |
| 92 | 93 | // DISASMDSO-NEXT: 10034:	11 0e 40 f9 	ldr	x17, [x16, #24] |
| 93 | 94 | // DISASMDSO-NEXT: 10038:	10 62 00 91 	add	x16, x16, #24 |
| 94 | 95 | // DISASMDSO-NEXT: 1003c:	20 02 1f d6 	br	x17 |
| 95 | 96 | |
| 96 | 97 | // bar@plt |
| 97 | // Page(0x30020) - Page(0x10040) = 0x20000 - 0x10000 = 0x10000 = 65536 | |
| 98 | // Page(0x30020) - Page(0x10040) = 0x30000 - 0x10000 = 0x20000 = 131072 | |
| 98 | 99 | // DISASMDSO-EMPTY: |
| 99 | 100 | // DISASMDSO-NEXT: bar@plt: |
| 100 | // DISASMDSO-NEXT: 10040:	90 00 00 90 	adrp	x16, #65536 | |
| 101 | // DISASMDSO-NEXT: 10040:	10 01 00 90 	adrp	x16, #131072 | |
| 101 | 102 | // 0x3020 & 0xFFF = 0x20 = 32 |
| 102 | 103 | // DISASMDSO-NEXT: 10044:	11 12 40 f9 	ldr	x17, [x16, #32] |
| 103 | 104 | // DISASMDSO-NEXT: 10048:	10 82 00 91 	add	x16, x16, #32 |
| 104 | 105 | // DISASMDSO-NEXT: 1004c:	20 02 1f d6 	br	x17 |
| 105 | 106 | |
| 106 | 107 | // weak@plt |
| 107 | // Page(0x30028) - Page(0x10050) = 0x20000 - 0x10000 = 0x10000 = 65536 | |
| 108 | // Page(0x30028) - Page(0x10050) = 0x30000 - 0x10000 = 0x20000 = 131072 | |
| 108 | 109 | // DISASMDSO-EMPTY: |
| 109 | 110 | // DISASMDSO-NEXT: weak@plt: |
| 110 | // DISASMDSO-NEXT: 10050:	90 00 00 90 	adrp	x16, #65536 | |
| 111 | // DISASMDSO-NEXT: 10050:	10 01 00 90 	adrp	x16, #131072 | |
| 111 | 112 | // 0x3028 & 0xFFF = 0x28 = 40 |
| 112 | 113 | // DISASMDSO-NEXT: 10054:	11 16 40 f9 	ldr	x17, [x16, #40] |
| 113 | 114 | // DISASMDSO-NEXT: 10058:	10 a2 00 91 	add	x16, x16, #40 |
| ... | ... | @@ -132,7 +133,7 @@ |
| 132 | 133 | // CHECKEXE-NEXT: SHF_ALLOC |
| 133 | 134 | // CHECKEXE-NEXT: SHF_WRITE |
| 134 | 135 | // CHECKEXE-NEXT: ] |
| 135 | // CHECKEXE-NEXT: Address: 0x220000 | |
| 136 | // CHECKEXE-NEXT: Address: 0x230000 | |
| 136 | 137 | // CHECKEXE-NEXT: Offset: |
| 137 | 138 | // CHECKEXE-NEXT: Size: 40 |
| 138 | 139 | // CHECKEXE-NEXT: Link: |
| ... | ... | @@ -142,20 +143,20 @@ |
| 142 | 143 | // CHECKEXE: Relocations [ |
| 143 | 144 | // CHECKEXE-NEXT: Section ({{.*}}) .rela.plt { |
| 144 | 145 | |
| 145 | // &(.got.plt[3]) = 0x220000 + 3 * 8 = 0x220018 | |
| 146 | // CHECKEXE-NEXT: 0x220018 R_AARCH64_JUMP_SLOT bar 0x0 | |
| 146 | // &(.got.plt[3]) = 0x230000 + 3 * 8 = 0x230018 | |
| 147 | // CHECKEXE-NEXT: 0x230018 R_AARCH64_JUMP_SLOT bar 0x0 | |
| 147 | 148 | |
| 148 | // &(.got.plt[4]) = 0x220000 + 4 * 8 = 0x220020 | |
| 149 | // CHECKEXE-NEXT: 0x220020 R_AARCH64_JUMP_SLOT weak 0x0 | |
| 149 | // &(.got.plt[4]) = 0x230000 + 4 * 8 = 0x230020 | |
| 150 | // CHECKEXE-NEXT: 0x230020 R_AARCH64_JUMP_SLOT weak 0x0 | |
| 150 | 151 | // CHECKEXE-NEXT: } |
| 151 | 152 | // CHECKEXE-NEXT: ] |
| 152 | 153 | |
| 153 | 154 | // DUMPEXE: Contents of section .got.plt: |
| 154 | 155 | // .got.plt[0..2] = 0 (reserved) |
| 155 | 156 | // .got.plt[3..4] = .plt = 0x40010 |
| 156 | // DUMPEXE-NEXT: 220000 00000000 00000000 00000000 00000000 | |
| 157 | // DUMPEXE-NEXT: 220010 00000000 00000000 10002100 00000000 | |
| 158 | // DUMPEXE-NEXT: 220020 10002100 00000000 | |
| 157 | // DUMPEXE-NEXT: 230000 00000000 00000000 00000000 00000000 | |
| 158 | // DUMPEXE-NEXT: 230010 00000000 00000000 10002100 00000000 | |
| 159 | // DUMPEXE-NEXT: 230020 10002100 00000000 | |
| 159 | 160 | |
| 160 | 161 | // DISASMEXE: _start: |
| 161 | 162 | // 0x21000c - 0x210000 = 0xc = 12 |
| ... | ... | @@ -169,11 +170,12 @@ |
| 169 | 170 | // DISASMEXE-NEXT: 21000c:	1f 20 03 d5 	nop |
| 170 | 171 | |
| 171 | 172 | // DISASMEXE: Disassembly of section .plt: |
| 173 | // DISASMEXE-EMPTY: | |
| 172 | 174 | // DISASMEXE-NEXT: .plt: |
| 173 | 175 | // DISASMEXE-NEXT: 210010:	f0 7b bf a9 	stp	x16, x30, [sp, #-16]! |
| 174 | 176 | // &(.got.plt[2]) = 0x2200B0 + 2 * 8 = 0x2200C0 |
| 175 | // Page(0x220010) - Page(0x210014) = 0x220000 - 0x210000 = 0x10000 = 65536 | |
| 176 | // DISASMEXE-NEXT: 210014:	90 00 00 90 	adrp	x16, #65536 | |
| 177 | // Page(0x230010) - Page(0x210014) = 0x230000 - 0x210000 = 0x20000 = 131072 | |
| 178 | // DISASMEXE-NEXT: 210014:	10 01 00 90 	adrp	x16, #131072 | |
| 177 | 179 | // 0x120c0 & 0xFFF = 0xC0 = 192 |
| 178 | 180 | // DISASMEXE-NEXT: 210018:	11 0a 40 f9 	ldr	x17, [x16, #16] |
| 179 | 181 | // DISASMEXE-NEXT: 21001c:	10 42 00 91 	add	x16, x16, #16 |
| ... | ... | @@ -183,19 +185,19 @@ |
| 183 | 185 | // DISASMEXE-NEXT: 21002c:	1f 20 03 d5 	nop |
| 184 | 186 | |
| 185 | 187 | // bar@plt |
| 186 | // Page(0x40018) - Page(0x210030) = 0x220000 - 0x210000 = 0x10000 = 65536 | |
| 188 | // Page(0x230018) - Page(0x210030) = 0x230000 - 0x210000 = 0x20000 = 131072 | |
| 187 | 189 | // DISASMEXE-EMPTY: |
| 188 | 190 | // DISASMEXE-NEXT: bar@plt: |
| 189 | // DISASMEXE-NEXT: 210030:	90 00 00 90 	adrp	x16, #65536 | |
| 191 | // DISASMEXE-NEXT: 210030:	10 01 00 90 	adrp	x16, #131072 | |
| 190 | 192 | // DISASMEXE-NEXT: 210034:	11 0e 40 f9 	ldr	x17, [x16, #24] |
| 191 | 193 | // DISASMEXE-NEXT: 210038:	10 62 00 91 	add	x16, x16, #24 |
| 192 | 194 | // DISASMEXE-NEXT: 21003c:	20 02 1f d6 	br	x17 |
| 193 | 195 | |
| 194 | 196 | // weak@plt |
| 195 | // Page(0x40020) - Page(0x210040) = 0x220000 - 0x210000 = 0x10000 = 65536 | |
| 197 | // Page(0x230020) - Page(0x210040) = 0x230000 - 0x210000 = 0x20000 = 131072 | |
| 196 | 198 | // DISASMEXE-EMPTY: |
| 197 | 199 | // DISASMEXE-NEXT: weak@plt: |
| 198 | // DISASMEXE-NEXT: 210040:	90 00 00 90 	adrp	x16, #65536 | |
| 200 | // DISASMEXE-NEXT: 210040:	10 01 00 90 	adrp	x16, #131072 | |
| 199 | 201 | // DISASMEXE-NEXT: 210044:	11 12 40 f9 	ldr	x17, [x16, #32] |
| 200 | 202 | // DISASMEXE-NEXT: 210048:	10 82 00 91 	add	x16, x16, #32 |
| 201 | 203 | // DISASMEXE-NEXT: 21004c:	20 02 1f d6 	br	x17 |
deps/lld/test/ELF/plt-i686.s+36-28| ... | ... | @@ -3,10 +3,10 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld -shared %t2.o -o %t2.so |
| 5 | 5 | // RUN: ld.lld %t.o %t2.so -o %t |
| 6 | // RUN: llvm-readobj -s -r %t | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S -r %t | FileCheck %s | |
| 7 | 7 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s |
| 8 | 8 | // RUN: ld.lld -shared %t.o %t2.so -o %t |
| 9 | // RUN: llvm-readobj -s -r %t | FileCheck --check-prefix=CHECKSHARED %s | |
| 9 | // RUN: llvm-readobj -S -r %t | FileCheck --check-prefix=CHECKSHARED %s | |
| 10 | 10 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASMSHARED %s |
| 11 | 11 | // RUN: ld.lld -pie %t.o %t2.so -o %t |
| 12 | 12 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASMPIE %s |
| ... | ... | @@ -30,8 +30,8 @@ |
| 30 | 30 | // CHECK-NEXT: SHF_ALLOC |
| 31 | 31 | // CHECK-NEXT: SHF_WRITE |
| 32 | 32 | // CHECK-NEXT: ] |
| 33 | // CHECK-NEXT: Address: 0x402000 | |
| 34 | // CHECK-NEXT: Offset: 0x2000 | |
| 33 | // CHECK-NEXT: Address: 0x403000 | |
| 34 | // CHECK-NEXT: Offset: 0x3000 | |
| 35 | 35 | // CHECK-NEXT: Size: 20 |
| 36 | 36 | // CHECK-NEXT: Link: 0 |
| 37 | 37 | // CHECK-NEXT: Info: 0 |
| ... | ... | @@ -42,8 +42,8 @@ |
| 42 | 42 | // 0x12000 + got.plt.reserved(12) + 4 = 0x12010 |
| 43 | 43 | // CHECK: Relocations [ |
| 44 | 44 | // CHECK-NEXT: Section ({{.*}}) .rel.plt { |
| 45 | // CHECK-NEXT: 0x40200C R_386_JUMP_SLOT bar 0x0 | |
| 46 | // CHECK-NEXT: 0x402010 R_386_JUMP_SLOT zed 0x0 | |
| 45 | // CHECK-NEXT: 0x40300C R_386_JUMP_SLOT bar 0x0 | |
| 46 | // CHECK-NEXT: 0x403010 R_386_JUMP_SLOT zed 0x0 | |
| 47 | 47 | // CHECK-NEXT: } |
| 48 | 48 | // CHECK-NEXT: ] |
| 49 | 49 | |
| ... | ... | @@ -67,26 +67,27 @@ |
| 67 | 67 | |
| 68 | 68 | // 0x401010 - 0x40102b - 5 = -32 |
| 69 | 69 | // 0x401010 - 0x40103b - 5 = -48 |
| 70 | // 4202500 = 0x402004 = .got.plt (0x402000) + 4 | |
| 71 | // 4202504 = 0x402008 = .got.plt (0x402000) + 8 | |
| 72 | // 4202508 = 0x40200C = .got.plt (0x402000) + got.plt.reserved(12) | |
| 73 | // 4202512 = 0x402010 = .got.plt (0x402000) + got.plt.reserved(12) + 4 | |
| 70 | // 4206596 = 0x403004 = .got.plt (0x403000) + 4 | |
| 71 | // 4206600 = 0x403008 = .got.plt (0x403000) + 8 | |
| 72 | // 4206604 = 0x40300C = .got.plt (0x403000) + got.plt.reserved(12) | |
| 73 | // 4206608 = 0x403010 = .got.plt (0x403000) + got.plt.reserved(12) + 4 | |
| 74 | 74 | // DISASM: Disassembly of section .plt: |
| 75 | // DISASM-EMPTY: | |
| 75 | 76 | // DISASM-NEXT: .plt: |
| 76 | // DISASM-NEXT: 401020: ff 35 04 20 40 00 pushl 4202500 | |
| 77 | // DISASM-NEXT: 401026: ff 25 08 20 40 00 jmpl *4202504 | |
| 77 | // DISASM-NEXT: 401020: ff 35 04 30 40 00 pushl 4206596 | |
| 78 | // DISASM-NEXT: 401026: ff 25 08 30 40 00 jmpl *4206600 | |
| 78 | 79 | // DISASM-NEXT: 40102c: 90 nop |
| 79 | 80 | // DISASM-NEXT: 40102d: 90 nop |
| 80 | 81 | // DISASM-NEXT: 40102e: 90 nop |
| 81 | 82 | // DISASM-NEXT: 40102f: 90 nop |
| 82 | 83 | // DISASM-EMPTY: |
| 83 | 84 | // DISASM-NEXT: bar@plt: |
| 84 | // DISASM-NEXT: 401030: ff 25 0c 20 40 00 jmpl *4202508 | |
| 85 | // DISASM-NEXT: 401030: ff 25 0c 30 40 00 jmpl *4206604 | |
| 85 | 86 | // DISASM-NEXT: 401036: 68 00 00 00 00 pushl $0 |
| 86 | 87 | // DISASM-NEXT: 40103b: e9 e0 ff ff ff jmp -32 <.plt> |
| 87 | 88 | // DISASM-EMPTY: |
| 88 | 89 | // DISASM-NEXT: zed@plt: |
| 89 | // DISASM-NEXT: 401040: ff 25 10 20 40 00 jmpl *4202512 | |
| 90 | // DISASM-NEXT: 401040: ff 25 10 30 40 00 jmpl *4206608 | |
| 90 | 91 | // DISASM-NEXT: 401046: 68 08 00 00 00 pushl $8 |
| 91 | 92 | // DISASM-NEXT: 40104b: e9 d0 ff ff ff jmp -48 <.plt> |
| 92 | 93 | |
| ... | ... | @@ -110,8 +111,8 @@ |
| 110 | 111 | // CHECKSHARED-NEXT: SHF_ALLOC |
| 111 | 112 | // CHECKSHARED-NEXT: SHF_WRITE |
| 112 | 113 | // CHECKSHARED-NEXT: ] |
| 113 | // CHECKSHARED-NEXT: Address: 0x2000 | |
| 114 | // CHECKSHARED-NEXT: Offset: 0x2000 | |
| 114 | // CHECKSHARED-NEXT: Address: 0x3000 | |
| 115 | // CHECKSHARED-NEXT: Offset: 0x3000 | |
| 115 | 116 | // CHECKSHARED-NEXT: Size: 20 |
| 116 | 117 | // CHECKSHARED-NEXT: Link: 0 |
| 117 | 118 | // CHECKSHARED-NEXT: Info: 0 |
| ... | ... | @@ -119,12 +120,12 @@ |
| 119 | 120 | // CHECKSHARED-NEXT: EntrySize: 0 |
| 120 | 121 | // CHECKSHARED-NEXT: } |
| 121 | 122 | |
| 122 | // 0x2000 + got.plt.reserved(12) = 0x200C | |
| 123 | // 0x2000 + got.plt.reserved(12) + 4 = 0x2010 | |
| 123 | // 0x3000 + got.plt.reserved(12) = 0x300C | |
| 124 | // 0x3000 + got.plt.reserved(12) + 4 = 0x3010 | |
| 124 | 125 | // CHECKSHARED: Relocations [ |
| 125 | 126 | // CHECKSHARED-NEXT: Section ({{.*}}) .rel.plt { |
| 126 | // CHECKSHARED-NEXT: 0x200C R_386_JUMP_SLOT bar 0x0 | |
| 127 | // CHECKSHARED-NEXT: 0x2010 R_386_JUMP_SLOT zed 0x0 | |
| 127 | // CHECKSHARED-NEXT: 0x300C R_386_JUMP_SLOT bar 0x0 | |
| 128 | // CHECKSHARED-NEXT: 0x3010 R_386_JUMP_SLOT zed 0x0 | |
| 128 | 129 | // CHECKSHARED-NEXT: } |
| 129 | 130 | // CHECKSHARED-NEXT: ] |
| 130 | 131 | |
| ... | ... | @@ -137,33 +138,40 @@ |
| 137 | 138 | // DISASMSHARED-NEXT: 1009: e9 22 00 00 00 jmp 34 |
| 138 | 139 | // DISASMSHARED-NEXT: 100e: e9 2d 00 00 00 jmp 45 |
| 139 | 140 | // DISASMSHARED-NEXT: 1013: e9 e8 ff ff ff jmp -24 |
| 141 | // DISASMSHARED-EMPTY: | |
| 140 | 142 | // DISASMSHARED-NEXT: Disassembly of section .plt: |
| 143 | // DISASMSHARED-EMPTY: | |
| 141 | 144 | // DISASMSHARED-NEXT: .plt: |
| 142 | // DISASMSHARED-NEXT: 1020: ff b3 04 20 00 00 pushl 8196(%ebx) | |
| 143 | // DISASMSHARED-NEXT: 1026: ff a3 08 20 00 00 jmpl *8200(%ebx) | |
| 145 | // DISASMSHARED-NEXT: 1020: ff b3 04 00 00 00 pushl 4(%ebx) | |
| 146 | // DISASMSHARED-NEXT: 1026: ff a3 08 00 00 00 jmpl *8(%ebx) | |
| 144 | 147 | // DISASMSHARED-NEXT: 102c: 90 nop |
| 145 | 148 | // DISASMSHARED-NEXT: 102d: 90 nop |
| 146 | 149 | // DISASMSHARED-NEXT: 102e: 90 nop |
| 147 | 150 | // DISASMSHARED-NEXT: 102f: 90 nop |
| 148 | // DISASMSHARED-NEXT: 1030: ff a3 0c 20 00 00 jmpl *8204(%ebx) | |
| 151 | // DISASMSHARED: bar@plt: | |
| 152 | // DISASMSHARED-NEXT: 1030: ff a3 0c 00 00 00 jmpl *12(%ebx) | |
| 149 | 153 | // DISASMSHARED-NEXT: 1036: 68 00 00 00 00 pushl $0 |
| 150 | 154 | // DISASMSHARED-NEXT: 103b: e9 e0 ff ff ff jmp -32 <.plt> |
| 151 | // DISASMSHARED-NEXT: 1040: ff a3 10 20 00 00 jmpl *8208(%ebx) | |
| 155 | // DISASMSHARED: zed@plt: | |
| 156 | // DISASMSHARED-NEXT: 1040: ff a3 10 00 00 00 jmpl *16(%ebx) | |
| 152 | 157 | // DISASMSHARED-NEXT: 1046: 68 08 00 00 00 pushl $8 |
| 153 | 158 | // DISASMSHARED-NEXT: 104b: e9 d0 ff ff ff jmp -48 <.plt> |
| 154 | 159 | |
| 155 | 160 | // DISASMPIE: Disassembly of section .plt: |
| 161 | // DISASMPIE-EMPTY: | |
| 156 | 162 | // DISASMPIE-NEXT: .plt: |
| 157 | // DISASMPIE-NEXT: 1020:	ff b3 04 20 00 00 pushl 8196(%ebx) | |
| 158 | // DISASMPIE-NEXT: 1026:	ff a3 08 20 00 00 jmpl *8200(%ebx) | |
| 163 | // DISASMPIE-NEXT: 1020:	ff b3 04 00 00 00 pushl 4(%ebx) | |
| 164 | // DISASMPIE-NEXT: 1026:	ff a3 08 00 00 00 jmpl *8(%ebx) | |
| 159 | 165 | // DISASMPIE-NEXT: 102c:	90 nop |
| 160 | 166 | // DISASMPIE-NEXT: 102d:	90 nop |
| 161 | 167 | // DISASMPIE-NEXT: 102e:	90 nop |
| 162 | 168 | // DISASMPIE-NEXT: 102f:	90 nop |
| 163 | // DISASMPIE-NEXT: 1030:	ff a3 0c 20 00 00 jmpl *8204(%ebx) | |
| 169 | // DISASMPIE: bar@plt: | |
| 170 | // DISASMPIE-NEXT: 1030:	ff a3 0c 00 00 00 jmpl *12(%ebx) | |
| 164 | 171 | // DISASMPIE-NEXT: 1036:	68 00 00 00 00 pushl $0 |
| 165 | 172 | // DISASMPIE-NEXT: 103b:	e9 e0 ff ff ff jmp -32 <.plt> |
| 166 | // DISASMPIE-NEXT: 1040:	ff a3 10 20 00 00 jmpl *8208(%ebx) | |
| 173 | // DISASMPIE: zed@plt: | |
| 174 | // DISASMPIE-NEXT: 1040:	ff a3 10 00 00 00 jmpl *16(%ebx) | |
| 167 | 175 | // DISASMPIE-NEXT: 1046:	68 08 00 00 00 pushl $8 |
| 168 | 176 | // DISASMPIE-NEXT: 104b:	e9 d0 ff ff ff jmp -48 <.plt> |
| 169 | 177 |
deps/lld/test/ELF/plt.s+21-19| ... | ... | @@ -4,9 +4,9 @@ |
| 4 | 4 | // RUN: ld.lld -shared %t2.o -o %t2.so |
| 5 | 5 | // RUN: ld.lld -shared %t.o %t2.so -o %t |
| 6 | 6 | // RUN: ld.lld %t.o %t2.so -o %t3 |
| 7 | // RUN: llvm-readobj -s -r %t | FileCheck %s | |
| 7 | // RUN: llvm-readobj -S -r %t | FileCheck %s | |
| 8 | 8 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s |
| 9 | // RUN: llvm-readobj -s -r %t3 | FileCheck --check-prefix=CHECK2 %s | |
| 9 | // RUN: llvm-readobj -S -r %t3 | FileCheck --check-prefix=CHECK2 %s | |
| 10 | 10 | // RUN: llvm-objdump -d %t3 | FileCheck --check-prefix=DISASM2 %s |
| 11 | 11 | |
| 12 | 12 | // CHECK: Name: .plt |
| ... | ... | @@ -24,9 +24,9 @@ |
| 24 | 24 | |
| 25 | 25 | // CHECK: Relocations [ |
| 26 | 26 | // CHECK-NEXT: Section ({{.*}}) .rela.plt { |
| 27 | // CHECK-NEXT: 0x2018 R_X86_64_JUMP_SLOT bar 0x0 | |
| 28 | // CHECK-NEXT: 0x2020 R_X86_64_JUMP_SLOT zed 0x0 | |
| 29 | // CHECK-NEXT: 0x2028 R_X86_64_JUMP_SLOT _start 0x0 | |
| 27 | // CHECK-NEXT: 0x3018 R_X86_64_JUMP_SLOT bar 0x0 | |
| 28 | // CHECK-NEXT: 0x3020 R_X86_64_JUMP_SLOT zed 0x0 | |
| 29 | // CHECK-NEXT: 0x3028 R_X86_64_JUMP_SLOT _start 0x0 | |
| 30 | 30 | // CHECK-NEXT: } |
| 31 | 31 | // CHECK-NEXT: ] |
| 32 | 32 | |
| ... | ... | @@ -45,8 +45,8 @@ |
| 45 | 45 | |
| 46 | 46 | // CHECK2: Relocations [ |
| 47 | 47 | // CHECK2-NEXT: Section ({{.*}}) .rela.plt { |
| 48 | // CHECK2-NEXT: 0x202018 R_X86_64_JUMP_SLOT bar 0x0 | |
| 49 | // CHECK2-NEXT: 0x202020 R_X86_64_JUMP_SLOT zed 0x0 | |
| 48 | // CHECK2-NEXT: 0x203018 R_X86_64_JUMP_SLOT bar 0x0 | |
| 49 | // CHECK2-NEXT: 0x203020 R_X86_64_JUMP_SLOT zed 0x0 | |
| 50 | 50 | // CHECK2-NEXT: } |
| 51 | 51 | // CHECK2-NEXT: ] |
| 52 | 52 | |
| ... | ... | @@ -64,28 +64,29 @@ |
| 64 | 64 | // DISASM-NEXT: 100a: e9 {{.*}} jmp 49 |
| 65 | 65 | // DISASM-NEXT: 100f: e9 {{.*}} jmp 60 |
| 66 | 66 | |
| 67 | // 0x2018 - 0x1036 = 4066 | |
| 68 | // 0x2020 - 0x1046 = 4058 | |
| 69 | // 0x2028 - 0x1056 = 4050 | |
| 67 | // 0x3018 - 0x1036 = 8162 | |
| 68 | // 0x3020 - 0x1046 = 8154 | |
| 69 | // 0x3028 - 0x1056 = 8146 | |
| 70 | 70 | |
| 71 | 71 | // DISASM: Disassembly of section .plt: |
| 72 | // DISASM-EMPTY: | |
| 72 | 73 | // DISASM-NEXT: .plt: |
| 73 | // DISASM-NEXT: 1020: ff 35 e2 0f 00 00 pushq 4066(%rip) | |
| 74 | // DISASM-NEXT: 1026: ff 25 e4 0f 00 00 jmpq *4068(%rip) | |
| 74 | // DISASM-NEXT: 1020: ff 35 e2 1f 00 00 pushq 8162(%rip) | |
| 75 | // DISASM-NEXT: 1026: ff 25 e4 1f 00 00 jmpq *8164(%rip) | |
| 75 | 76 | // DISASM-NEXT: 102c: 0f 1f 40 00 nopl (%rax) |
| 76 | 77 | // DISASM-EMPTY: |
| 77 | 78 | // DISASM-NEXT: bar@plt: |
| 78 | // DISASM-NEXT: 1030: ff 25 e2 0f 00 00 jmpq *4066(%rip) | |
| 79 | // DISASM-NEXT: 1030: ff 25 e2 1f 00 00 jmpq *8162(%rip) | |
| 79 | 80 | // DISASM-NEXT: 1036: 68 00 00 00 00 pushq $0 |
| 80 | 81 | // DISASM-NEXT: 103b: e9 e0 ff ff ff jmp -32 <.plt> |
| 81 | 82 | // DISASM-EMPTY: |
| 82 | 83 | // DISASM-NEXT: zed@plt: |
| 83 | // DISASM-NEXT: 1040: ff 25 da 0f 00 00 jmpq *4058(%rip) | |
| 84 | // DISASM-NEXT: 1040: ff 25 da 1f 00 00 jmpq *8154(%rip) | |
| 84 | 85 | // DISASM-NEXT: 1046: 68 01 00 00 00 pushq $1 |
| 85 | 86 | // DISASM-NEXT: 104b: e9 d0 ff ff ff jmp -48 <.plt> |
| 86 | 87 | // DISASM-EMPTY: |
| 87 | 88 | // DISASM-NEXT: _start@plt: |
| 88 | // DISASM-NEXT: 1050: ff 25 d2 0f 00 00 jmpq *4050(%rip) | |
| 89 | // DISASM-NEXT: 1050: ff 25 d2 1f 00 00 jmpq *8146(%rip) | |
| 89 | 90 | // DISASM-NEXT: 1056: 68 02 00 00 00 pushq $2 |
| 90 | 91 | // DISASM-NEXT: 105b: e9 c0 ff ff ff jmp -64 <.plt> |
| 91 | 92 | |
| ... | ... | @@ -104,18 +105,19 @@ |
| 104 | 105 | // 0x202020 - 0x201046 = 4058 |
| 105 | 106 | |
| 106 | 107 | // DISASM2: Disassembly of section .plt: |
| 108 | // DISASM2-EMPTY: | |
| 107 | 109 | // DISASM2-NEXT: .plt: |
| 108 | // DISASM2-NEXT: 201020: ff 35 e2 0f 00 00 pushq 4066(%rip) | |
| 109 | // DISASM2-NEXT: 201026: ff 25 e4 0f 00 00 jmpq *4068(%rip) | |
| 110 | // DISASM2-NEXT: 201020: ff 35 e2 1f 00 00 pushq 8162(%rip) | |
| 111 | // DISASM2-NEXT: 201026: ff 25 e4 1f 00 00 jmpq *8164(%rip) | |
| 110 | 112 | // DISASM2-NEXT: 20102c: 0f 1f 40 00 nopl (%rax) |
| 111 | 113 | // DISASM2-EMPTY: |
| 112 | 114 | // DISASM2-NEXT: bar@plt: |
| 113 | // DISASM2-NEXT: 201030: ff 25 e2 0f 00 00 jmpq *4066(%rip) | |
| 115 | // DISASM2-NEXT: 201030: ff 25 e2 1f 00 00 jmpq *8162(%rip) | |
| 114 | 116 | // DISASM2-NEXT: 201036: 68 00 00 00 00 pushq $0 |
| 115 | 117 | // DISASM2-NEXT: 20103b: e9 e0 ff ff ff jmp -32 <.plt> |
| 116 | 118 | // DISASM2-EMPTY: |
| 117 | 119 | // DISASM2-NEXT: zed@plt: |
| 118 | // DISASM2-NEXT: 201040: ff 25 da 0f 00 00 jmpq *4058(%rip) | |
| 120 | // DISASM2-NEXT: 201040: ff 25 da 1f 00 00 jmpq *8154(%rip) | |
| 119 | 121 | // DISASM2-NEXT: 201046: 68 01 00 00 00 pushq $1 |
| 120 | 122 | // DISASM2-NEXT: 20104b: e9 d0 ff ff ff jmp -48 <.plt> |
| 121 | 123 | // DISASM2-NOT: 2010C0 |
deps/lld/test/ELF/ppc-rela.s+1-1| ... | ... | @@ -7,5 +7,5 @@ |
| 7 | 7 | .long foo |
| 8 | 8 | |
| 9 | 9 | // CHECK: Section ({{.*}}) .rela.dyn { |
| 10 | // CHECK-NEXT: 0x1000 R_PPC_ADDR32 foo 0x0 | |
| 10 | // CHECK-NEXT: 0x20000 R_PPC_ADDR32 foo 0x0 | |
| 11 | 11 | // CHECK-NEXT: } |
deps/lld/test/ELF/ppc-relocs.s deleted-101| ... | ... | @@ -1,101 +0,0 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t | |
| 3 | # RUN: ld.lld %t -o %t2 | |
| 4 | # RUN: llvm-objdump -d %t2 | FileCheck %s | |
| 5 | ||
| 6 | .section .R_PPC_ADDR16_HA,"ax",@progbits | |
| 7 | .globl _start | |
| 8 | _start: | |
| 9 | lis 4, msg@ha | |
| 10 | msg: | |
| 11 | .string "foo" | |
| 12 | len = . - msg | |
| 13 | ||
| 14 | # CHECK: Disassembly of section .R_PPC_ADDR16_HA: | |
| 15 | # CHECK: _start: | |
| 16 | # CHECK: 11000: 3c 80 00 01 lis 4, 1 | |
| 17 | # CHECK: msg: | |
| 18 | # CHECK: 11004: 66 6f 6f 00 oris 15, 19, 28416 | |
| 19 | ||
| 20 | .section .R_PPC_ADDR16_HI,"ax",@progbits | |
| 21 | .globl _starti | |
| 22 | _starti: | |
| 23 | lis 4,msgi@h | |
| 24 | msgi: | |
| 25 | .string "foo" | |
| 26 | leni = . - msgi | |
| 27 | ||
| 28 | # CHECK: Disassembly of section .R_PPC_ADDR16_HI: | |
| 29 | # CHECK: _starti: | |
| 30 | # CHECK: 11008: 3c 80 00 01 lis 4, 1 | |
| 31 | # CHECK: msgi: | |
| 32 | # CHECK: 1100c: 66 6f 6f 00 oris 15, 19, 28416 | |
| 33 | ||
| 34 | .section .R_PPC_ADDR16_LO,"ax",@progbits | |
| 35 | addi 4, 4, msg@l | |
| 36 | mystr: | |
| 37 | .asciz "blah" | |
| 38 | len = . - mystr | |
| 39 | ||
| 40 | # CHECK: Disassembly of section .R_PPC_ADDR16_LO: | |
| 41 | # CHECK: .R_PPC_ADDR16_LO: | |
| 42 | # CHECK: 11010: 38 84 10 04 addi 4, 4, 4100 | |
| 43 | # CHECK: mystr: | |
| 44 | # CHECK: 11014: 62 6c 61 68 ori 12, 19, 24936 | |
| 45 | ||
| 46 | .align 2 | |
| 47 | .section .R_PPC_REL24,"ax",@progbits | |
| 48 | .globl .FR_PPC_REL24 | |
| 49 | .FR_PPC_REL24: | |
| 50 | b .Lfoox | |
| 51 | .section .R_PPC_REL24_2,"ax",@progbits | |
| 52 | .Lfoox: | |
| 53 | ||
| 54 | # CHECK: Disassembly of section .R_PPC_REL24: | |
| 55 | # CHECK: .FR_PPC_REL24: | |
| 56 | # CHECK: 1101c: 48 00 00 04 b .+4 | |
| 57 | ||
| 58 | .section .R_PPC_REL14,"ax",@progbits | |
| 59 | .globl .FR_PPC_REL14 | |
| 60 | .FR_PPC_REL14: | |
| 61 | beq .Lfooy | |
| 62 | .section .R_PPC_REL14_2,"ax",@progbits | |
| 63 | .Lfooy: | |
| 64 | ||
| 65 | # CHECK: Disassembly of section .R_PPC_REL14: | |
| 66 | # CHECK: .FR_PPC_REL14: | |
| 67 | # CHECK: 11020: {{.*}} bt 2, .+4 | |
| 68 | ||
| 69 | .section .R_PPC_REL32,"ax",@progbits | |
| 70 | .globl .FR_PPC_REL32 | |
| 71 | .FR_PPC_REL32: | |
| 72 | .long .Lfoox3 - . | |
| 73 | .section .R_PPC_REL32_2,"ax",@progbits | |
| 74 | .Lfoox3: | |
| 75 | ||
| 76 | # CHECK: Disassembly of section .R_PPC_REL32: | |
| 77 | # CHECK: .FR_PPC_REL32: | |
| 78 | # CHECK: 11024: 00 00 00 04 | |
| 79 | ||
| 80 | .section .R_PPC_ADDR32,"ax",@progbits | |
| 81 | .globl .FR_PPC_ADDR32 | |
| 82 | .FR_PPC_ADDR32: | |
| 83 | .long .Lfoox2 | |
| 84 | .section .R_PPC_ADDR32_2,"ax",@progbits | |
| 85 | .Lfoox2: | |
| 86 | ||
| 87 | # CHECK: Disassembly of section .R_PPC_ADDR32: | |
| 88 | # CHECK: .FR_PPC_ADDR32: | |
| 89 | # CHECK: 11028: 00 01 10 2c | |
| 90 | ||
| 91 | .align 2 | |
| 92 | .section .R_PPC_PLTREL24,"ax",@progbits | |
| 93 | .globl .R_PPC_PLTREL24 | |
| 94 | .FR_PPC_PLTREL24: | |
| 95 | b .Lfoox4@PLT | |
| 96 | .section .R_PPC_PLTREL24_2,"ax",@progbits | |
| 97 | .Lfoox4: | |
| 98 | ||
| 99 | # CHECK: Disassembly of section .R_PPC_PLTREL24: | |
| 100 | # CHECK: .R_PPC_PLTREL24: | |
| 101 | # CHECK: 1102c: 48 00 00 04 b .+4 |
deps/lld/test/ELF/ppc32-abs-pic.s created+23| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o | |
| 3 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 4 | # RUN: llvm-nm %t.so | FileCheck --check-prefix=NM %s | |
| 5 | # RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=RELOC %s | |
| 6 | ||
| 7 | ## R_PPC_ADDR32 is an absolute relocation type. | |
| 8 | ## In PIC mode, it creates a relative relocation if the symbol is non-preemptable. | |
| 9 | ||
| 10 | # NM: 00020004 d b | |
| 11 | ||
| 12 | # RELOC: .rela.dyn { | |
| 13 | # RELOC-NEXT: 0x20004 R_PPC_RELATIVE - 0x20004 | |
| 14 | # RELOC-NEXT: 0x20000 R_PPC_ADDR32 a 0 | |
| 15 | # RELOC-NEXT: } | |
| 16 | ||
| 17 | .globl a, b | |
| 18 | .hidden b | |
| 19 | ||
| 20 | .data | |
| 21 | .long a | |
| 22 | b: | |
| 23 | .long b |
deps/lld/test/ELF/ppc32-call-stub-nopic.s created+81| ... | ... | @@ -0,0 +1,81 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o | |
| 3 | # RUN: echo '.globl f, g, h; f: g: h:' | llvm-mc -filetype=obj -triple=powerpc - -o %t1.o | |
| 4 | # RUN: ld.lld -shared %t1.o -soname t1.so -o %t1.so | |
| 5 | ||
| 6 | ## Check we can create PLT entries for -fno-PIE executable. | |
| 7 | # RUN: ld.lld %t.o %t1.so -o %t | |
| 8 | # RUN: llvm-readobj -r -d %t | FileCheck --check-prefix=RELOC %s | |
| 9 | # RUN: llvm-readelf -S %t | FileCheck --check-prefix=SEC %s | |
| 10 | # RUN: llvm-readelf -x .plt %t | FileCheck --check-prefix=HEX %s | |
| 11 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 12 | ||
| 13 | # RELOC: .rela.plt { | |
| 14 | # RELOC-NEXT: 0x10030000 R_PPC_JMP_SLOT f 0x0 | |
| 15 | # RELOC-NEXT: 0x10030004 R_PPC_JMP_SLOT g 0x0 | |
| 16 | # RELOC-NEXT: } | |
| 17 | ||
| 18 | # SEC: .got PROGBITS 10020070 | |
| 19 | # RELOC: PPC_GOT 0x10020070 | |
| 20 | ||
| 21 | ## .got2+0x8000-0x10004 = 0x30000+0x8000-0x10004 = 65536*2+32764 | |
| 22 | # CHECK-LABEL: _start: | |
| 23 | # CHECK-NEXT: bl .+16 | |
| 24 | # CHECK-NEXT: bl .+12 | |
| 25 | # CHECK-NEXT: bl .+24 | |
| 26 | # CHECK-NEXT: bl .+20 | |
| 27 | # CHECK-EMPTY: | |
| 28 | ||
| 29 | ## -fno-PIC call stubs of f and g. | |
| 30 | ## .plt[0] = 0x10030000 = 65536*4099+0 | |
| 31 | ## .plt[1] = 0x10030004 = 65536*4099+4 | |
| 32 | # CHECK-NEXT: 00000000.plt_call32.f: | |
| 33 | # CHECK-NEXT: lis 11, 4099 | |
| 34 | # CHECK-NEXT: lwz 11, 0(11) | |
| 35 | # CHECK-NEXT: mtctr 11 | |
| 36 | # CHECK-NEXT: bctr | |
| 37 | # CHECK-EMPTY: | |
| 38 | # CHECK-NEXT: 00000000.plt_call32.g: | |
| 39 | # CHECK-NEXT: lis 11, 4099 | |
| 40 | # CHECK-NEXT: lwz 11, 4(11) | |
| 41 | # CHECK-NEXT: mtctr 11 | |
| 42 | # CHECK-NEXT: bctr | |
| 43 | # CHECK-EMPTY: | |
| 44 | ||
| 45 | ## In Secure PLT ABI, .plt stores function pointers to first instructions of .glink | |
| 46 | # HEX: 0x10030000 10010040 10010044 | |
| 47 | ||
| 48 | ## These instructions are referenced by .plt entries. | |
| 49 | # CHECK: 10010040 .glink: | |
| 50 | # CHECK-NEXT: b .+8 | |
| 51 | # CHECK-NEXT: b .+4 | |
| 52 | ||
| 53 | ## PLTresolve | |
| 54 | ## Operands of lis & lwz: .got+4 = 0x10020070+4 = 65536*4098+116 | |
| 55 | ## Operands of addis & addi: -.glink = -0x10010040 = 65536*-4097-48 | |
| 56 | # CHECK-NEXT: lis 12, 4098 | |
| 57 | # CHECK-NEXT: addis 11, 11, -4097 | |
| 58 | # CHECK-NEXT: lwz 0, 116(12) | |
| 59 | # CHECK-NEXT: addi 11, 11, -64 | |
| 60 | ||
| 61 | # CHECK-NEXT: mtctr 0 | |
| 62 | # CHECK-NEXT: add 0, 11, 11 | |
| 63 | # CHECK-NEXT: lwz 12, 120(12) | |
| 64 | # CHECK-NEXT: add 11, 0, 11 | |
| 65 | # CHECK-NEXT: bctr | |
| 66 | ||
| 67 | ## glibc crti.o references _GLOBAL_OFFSET_TABLE_. | |
| 68 | .section .init | |
| 69 | bcl 20, 31, .+4 | |
| 70 | .L: | |
| 71 | mflr 30 | |
| 72 | addis 30, 30, _GLOBAL_OFFSET_TABLE_-.L@ha | |
| 73 | addi 30, 30, _GLOBAL_OFFSET_TABLE_-.L@l | |
| 74 | ||
| 75 | .text | |
| 76 | .globl _start | |
| 77 | _start: | |
| 78 | bl f | |
| 79 | bl f | |
| 80 | bl g | |
| 81 | bl g |
deps/lld/test/ELF/ppc32-call-stub-pic.s created+151| ... | ... | @@ -0,0 +1,151 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o | |
| 3 | # RUN: echo '.globl f, g, h; f: g: h:' | llvm-mc -filetype=obj -triple=powerpc - -o %t1.o | |
| 4 | # RUN: ld.lld -shared %t1.o -soname t1.so -o %t1.so | |
| 5 | # RUN: echo 'bl f+0x8000@plt' | llvm-mc -filetype=obj -triple=powerpc - -o %t2.o | |
| 6 | ||
| 7 | ## Check we can create PLT entries for -fPIE or -fpie executable. | |
| 8 | # RUN: ld.lld -pie %t.o %t1.so %t2.o -o %t | |
| 9 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s | |
| 10 | # RUN: llvm-readobj -d %t | FileCheck --check-prefix=DYN %s | |
| 11 | # RUN: llvm-readelf -S %t | FileCheck --check-prefix=SEC %s | |
| 12 | # RUN: llvm-readelf -x .plt %t | FileCheck --check-prefix=HEX %s | |
| 13 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefixes=CHECK,PIE %s | |
| 14 | ||
| 15 | ## Check we can create PLT entries for -fPIC or -fpic DSO. | |
| 16 | # RUN: ld.lld -shared %t.o %t1.so %t2.o -o %t | |
| 17 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s | |
| 18 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefixes=CHECK,SHARED %s | |
| 19 | ||
| 20 | # RELOC: .rela.dyn { | |
| 21 | # RELOC-NEXT: R_PPC_ADDR32 f 0x0 | |
| 22 | # RELOC-NEXT: R_PPC_ADDR32 g 0x0 | |
| 23 | # RELOC-NEXT: R_PPC_ADDR32 h 0x0 | |
| 24 | # RELOC-NEXT: } | |
| 25 | # RELOC-NEXT: .rela.plt { | |
| 26 | # RELOC-NEXT: R_PPC_JMP_SLOT f 0x0 | |
| 27 | # RELOC-NEXT: R_PPC_JMP_SLOT g 0x0 | |
| 28 | # RELOC-NEXT: R_PPC_JMP_SLOT h 0x0 | |
| 29 | # RELOC-NEXT: } | |
| 30 | ||
| 31 | # SEC: .got PROGBITS 00020088 | |
| 32 | # DYN: PPC_GOT 0x20088 | |
| 33 | ||
| 34 | ## .got2+0x8000-0x10004 = 0x30000+0x8000-0x10004 = 65536*2+32764 | |
| 35 | # CHECK-LABEL: _start: | |
| 36 | # CHECK-NEXT: bcl 20, 31, .+4 | |
| 37 | # CHECK-NEXT: 10004: mflr 30 | |
| 38 | # CHECK-NEXT: addis 30, 30, 2 | |
| 39 | # CHECK-NEXT: addi 30, 30, 32764 | |
| 40 | ||
| 41 | ## Two bl 00008000.got2.plt_pic32.f | |
| 42 | # CHECK-NEXT: bl .+40 | |
| 43 | # CHECK-NEXT: bl .+36 | |
| 44 | ## Two bl 00008000.got2.plt_pic32.g | |
| 45 | # CHECK-NEXT: bl .+48 | |
| 46 | # CHECK-NEXT: bl .+44 | |
| 47 | ## Two bl 00008000.got2.plt_pic32.h | |
| 48 | # CHECK-NEXT: bl .+56 | |
| 49 | # CHECK-NEXT: bl .+52 | |
| 50 | # CHECK-NEXT: addis 30, 30, {{.*}} | |
| 51 | # CHECK-NEXT: addi 30, 30, {{.*}} | |
| 52 | ## bl 00008000.plt_pic32.f | |
| 53 | # CHECK-NEXT: bl .+56 | |
| 54 | ## bl 00008000.plt_pic32.f | |
| 55 | # CHECK-NEXT: bl .+68 | |
| 56 | # CHECK-EMPTY: | |
| 57 | ||
| 58 | ## -fPIC call stubs of f and g. | |
| 59 | # CHECK-NEXT: 00008000.got2.plt_pic32.f: | |
| 60 | # CHECK-NEXT: lwz 11, 32760(30) | |
| 61 | # CHECK-NEXT: mtctr 11 | |
| 62 | # CHECK-NEXT: bctr | |
| 63 | # CHECK-NEXT: nop | |
| 64 | # CHECK-EMPTY: | |
| 65 | # CHECK-NEXT: 00008000.got2.plt_pic32.g: | |
| 66 | # CHECK-NEXT: lwz 11, 32764(30) | |
| 67 | # CHECK-NEXT: mtctr 11 | |
| 68 | # CHECK-NEXT: bctr | |
| 69 | # CHECK-NEXT: nop | |
| 70 | # CHECK-EMPTY: | |
| 71 | ||
| 72 | ## The -fPIC call stub of h needs two instructions addis+lwz to represent the offset 65536*1-32768. | |
| 73 | # CHECK-NEXT: 00008000.got2.plt_pic32.h: | |
| 74 | # CHECK-NEXT: addis 11, 30, 1 | |
| 75 | # CHECK-NEXT: lwz 11, -32768(11) | |
| 76 | # CHECK-NEXT: mtctr 11 | |
| 77 | # CHECK-NEXT: bctr | |
| 78 | # CHECK-EMPTY: | |
| 79 | ||
| 80 | ## -fpic call stub of f. | |
| 81 | # CHECK-NEXT: 00000000.plt_pic32.f: | |
| 82 | # CHECK-NEXT: addis 11, 30, 2 | |
| 83 | # PIE-NEXT: lwz 11, -144(11) | |
| 84 | # SHARED-NEXT: lwz 11, -136(11) | |
| 85 | # CHECK-NEXT: mtctr 11 | |
| 86 | # CHECK-NEXT: bctr | |
| 87 | # CHECK-EMPTY: | |
| 88 | ||
| 89 | ## Another -fPIC call stub of f from another object file %t2.o | |
| 90 | ## .got2 may have different addresses in different object files, | |
| 91 | ## so the call stub cannot be shared. | |
| 92 | # CHECK-NEXT: 00008000.got2.plt_pic32.f: | |
| 93 | ||
| 94 | ## In Secure PLT ABI, .plt stores function pointers to first instructions of .glink | |
| 95 | # HEX: 0x0003fff8 00010090 00010094 00010098 | |
| 96 | ||
| 97 | ## These instructions are referenced by .plt entries. | |
| 98 | # CHECK: 00010090 .glink: | |
| 99 | # CHECK-NEXT: b .+12 | |
| 100 | # CHECK-NEXT: b .+8 | |
| 101 | # CHECK-NEXT: b .+4 | |
| 102 | ||
| 103 | ## PLTresolve | |
| 104 | ## Operand of addi: 0x100a8-.glink = 24 | |
| 105 | # CHECK-NEXT: addis 11, 11, 0 | |
| 106 | # CHECK-NEXT: mflr 0 | |
| 107 | # CHECK-NEXT: bcl 20, 31, .+4 | |
| 108 | # CHECK-NEXT: 100a8: addi 11, 11, 24 | |
| 109 | ||
| 110 | # CHECK-NEXT: mflr 12 | |
| 111 | # CHECK-NEXT: mtlr 0 | |
| 112 | # CHECK-NEXT: subf 11, 12, 11 | |
| 113 | ||
| 114 | ## Operand of lwz in -pie mode: &.got[1] - 0x100a8 = 0x20088+4 - 0x100a8 = 65536*1-28 | |
| 115 | # CHECK-NEXT: addis 12, 12, 1 | |
| 116 | # PIE-NEXT: lwz 0, -28(12) | |
| 117 | # SHARED-NEXT: lwz 0, -36(12) | |
| 118 | ||
| 119 | # PIE-NEXT: lwz 12, -24(12) | |
| 120 | # SHARED-NEXT: lwz 12, -32(12) | |
| 121 | # CHECK-NEXT: mtctr 0 | |
| 122 | # CHECK-NEXT: add 0, 11, 11 | |
| 123 | # CHECK-NEXT: add 11, 0, 11 | |
| 124 | # CHECK-NEXT: bctr | |
| 125 | ||
| 126 | .section .got2,"aw" | |
| 127 | .space 65516 | |
| 128 | .long f | |
| 129 | .long g | |
| 130 | .long h | |
| 131 | ||
| 132 | .text | |
| 133 | .globl _start | |
| 134 | _start: | |
| 135 | bcl 20,31,.L | |
| 136 | .L: | |
| 137 | mflr 30 | |
| 138 | addis 30, 30, .got2+0x8000-.L@ha | |
| 139 | addi 30, 30, .got2+0x8000-.L@l | |
| 140 | bl f+0x8000@plt | |
| 141 | bl f+0x8000@plt | |
| 142 | bl g+0x8000@plt | |
| 143 | bl g+0x8000@plt | |
| 144 | bl h+0x8000@plt | |
| 145 | bl h+0x8000@plt | |
| 146 | ||
| 147 | ## An addend of 0 indicates r30 is stored in _GLOBAL_OFFSET_TABLE_. | |
| 148 | ## The existing thunk is incompatible, thus it cannot be reused. | |
| 149 | addis 30, 30, _GLOBAL_OFFSET_TABLE_-.L@ha | |
| 150 | addi 30, 30, _GLOBAL_OFFSET_TABLE_-.L@l | |
| 151 | bl f@plt |
deps/lld/test/ELF/ppc32-gnu-ifunc-nonpreemptable.s created+45| ... | ... | @@ -0,0 +1,45 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -o %t | |
| 4 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s | |
| 5 | # RUN: llvm-readelf -s %t | FileCheck --check-prefix=SYM %s | |
| 6 | # RUN: llvm-readelf -x .got2 %t | FileCheck --check-prefix=HEX %s | |
| 7 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 8 | ||
| 9 | # RELOC: .rela.plt { | |
| 10 | # RELOC-NEXT: 0x10020004 R_PPC_IRELATIVE - 0x10010000 | |
| 11 | # RELOC-NEXT: } | |
| 12 | ||
| 13 | # SYM: 10010020 0 FUNC GLOBAL DEFAULT {{.*}} func | |
| 14 | # HEX: 0x10020000 10010020 | |
| 15 | ||
| 16 | .section .got2,"aw" | |
| 17 | .long func | |
| 18 | ||
| 19 | # CHECK: func_resolver: | |
| 20 | # CHECK-NEXT: 10010000: blr | |
| 21 | # CHECK: _start: | |
| 22 | # CHECK-NEXT: bl .+12 | |
| 23 | # CHECK-NEXT: lis 9, 4097 | |
| 24 | # CHECK-NEXT: addi 9, 9, 32 | |
| 25 | # CHECK-EMPTY: | |
| 26 | # CHECK-NEXT: 00000000.plt_call32.func: | |
| 27 | ## 10020004 = 65536*4098+4 | |
| 28 | # CHECK-NEXT: lis 11, 4098 | |
| 29 | # CHECK-NEXT: lwz 11, 4(11) | |
| 30 | ||
| 31 | .text | |
| 32 | .globl func | |
| 33 | .type func, @gnu_indirect_function | |
| 34 | func: | |
| 35 | .globl func_resolver | |
| 36 | .type func_resolver, @function | |
| 37 | func_resolver: | |
| 38 | blr | |
| 39 | ||
| 40 | .globl _start | |
| 41 | _start: | |
| 42 | bl func | |
| 43 | ||
| 44 | lis 9, func@ha | |
| 45 | la 9, func@l(9) |
deps/lld/test/ELF/ppc32-gnu-ifunc.s created+41| ... | ... | @@ -0,0 +1,41 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -o %t | |
| 4 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s | |
| 5 | # RUN: llvm-readelf -S -s %t | FileCheck --check-prefixes=SEC,SYM %s | |
| 6 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 7 | ||
| 8 | # RELOC: .rela.plt { | |
| 9 | # RELOC-NEXT: 0x10020000 R_PPC_IRELATIVE - 0x10010000 | |
| 10 | # RELOC-NEXT: } | |
| 11 | ||
| 12 | # SEC: .rela.plt RELA 100000d4 0000d4 00000c | |
| 13 | # SYM: 10010000 0 FUNC GLOBAL DEFAULT {{.*}} func | |
| 14 | ||
| 15 | # CHECK: func_resolver: | |
| 16 | # CHECK-NEXT: 10010000: | |
| 17 | # CHECK: _start: | |
| 18 | # CHECK-NEXT: bl .+20 | |
| 19 | ## .rela.plt = 0x100000d4 = 65536*4096+212 | |
| 20 | ## end(.rela.plt) = 0x100000d4+0xc = 65536*4096+224 | |
| 21 | # CHECK-NEXT: lis 9, 4096 | |
| 22 | # CHECK-NEXT: lis 8, 4096 | |
| 23 | # CHECK-NEXT: addi 9, 9, 212 | |
| 24 | # CHECK-NEXT: addi 8, 8, 224 | |
| 25 | ||
| 26 | .globl func | |
| 27 | .type func, @gnu_indirect_function | |
| 28 | func: | |
| 29 | .globl func_resolver | |
| 30 | .type func_resolver, @function | |
| 31 | func_resolver: | |
| 32 | blr | |
| 33 | ||
| 34 | .globl _start | |
| 35 | _start: | |
| 36 | bl func | |
| 37 | ||
| 38 | lis 9, __rela_iplt_start@ha | |
| 39 | lis 8, __rela_iplt_end@ha | |
| 40 | la 9, __rela_iplt_start@l(9) | |
| 41 | la 8, __rela_iplt_end@l(8) |
deps/lld/test/ELF/ppc32-local-branch.s created+21| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o | |
| 3 | # RUN: echo '.globl foo; foo: blr' | llvm-mc -filetype=obj -triple=powerpc - -o %t1.o | |
| 4 | # RUN: ld.lld %t.o %t1.o -o %t | |
| 5 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 6 | ||
| 7 | ## R_PPC_REL24 and R_PPC_PLTREL24 are converted to PC relative relocations if the | |
| 8 | ## symbol is non-preemptable. The addend of R_PPC_PLTREL24 should be ignored. | |
| 9 | ||
| 10 | # CHECK: _start: | |
| 11 | # CHECK-NEXT: b .+12 | |
| 12 | # CHECK-NEXT: b .+8 | |
| 13 | # CHECK-NEXT: b .+4 | |
| 14 | # CHECK-EMPTY: | |
| 15 | # CHECK-NEXT: foo: | |
| 16 | ||
| 17 | .globl _start | |
| 18 | _start: | |
| 19 | b foo # R_PPC_REL24 | |
| 20 | b foo@plt # R_PPC_PLTREL24 | |
| 21 | b foo+32768@plt #_PPC_PLTREL24 with addend |
deps/lld/test/ELF/ppc32-reloc-addr.s created+26| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o --defsym=a=0x1234 --defsym=b=0xbcdef -o %t | |
| 4 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 5 | # RUN: llvm-objdump -s --no-show-raw-insn %t | FileCheck --check-prefix=HEX %s | |
| 6 | ||
| 7 | .section .R_PPC_ADDR16_HA,"ax",@progbits | |
| 8 | lis 4, a@ha | |
| 9 | # CHECK-LABEL: section .R_PPC_ADDR16_HA: | |
| 10 | # CHECK: lis 4, 0 | |
| 11 | ||
| 12 | .section .R_PPC_ADDR16_HI,"ax",@progbits | |
| 13 | lis 4, a@h | |
| 14 | # CHECK-LABEL: section .R_PPC_ADDR16_HI: | |
| 15 | # CHECK: lis 4, 0 | |
| 16 | ||
| 17 | .section .R_PPC_ADDR16_LO,"ax",@progbits | |
| 18 | addi 4, 4, a@l | |
| 19 | # CHECK-LABEL: section .R_PPC_ADDR16_LO: | |
| 20 | # CHECK: addi 4, 4, 4660 | |
| 21 | ||
| 22 | .section .R_PPC_ADDR32,"a",@progbits | |
| 23 | .long a | |
| 24 | .long b | |
| 25 | # HEX-LABEL: section .R_PPC_ADDR32: | |
| 26 | # HEX-NEXT: 100000b4 00001234 000bcdef |
deps/lld/test/ELF/ppc32-reloc-got.s created+36| ... | ... | @@ -0,0 +1,36 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o | |
| 3 | # RUN: echo '.globl b; b:' | llvm-mc -filetype=obj -triple=powerpc - -o %t1.o | |
| 4 | # RUN: ld.lld -shared %t1.o -o %t1.so | |
| 5 | ||
| 6 | # RUN: ld.lld %t.o %t1.so -o %t | |
| 7 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s | |
| 8 | # RUN: llvm-nm %t | FileCheck --check-prefix=NM %s | |
| 9 | # RUN: llvm-readobj -x .got %t | FileCheck --check-prefix=HEX %s | |
| 10 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 11 | ||
| 12 | ## Check we can handle R_PPC_GOT16, which may be generated by -fpic code. | |
| 13 | ||
| 14 | # SEC: .got PROGBITS 00020068 020068 000014 | |
| 15 | ||
| 16 | # RELOC: .rela.dyn { | |
| 17 | # RELOC-NEXT: 0x10020078 R_PPC_GLOB_DAT b 0x0 | |
| 18 | # RELOC-NEXT: } | |
| 19 | ||
| 20 | # NM: 10030000 d a | |
| 21 | ||
| 22 | ## The GOT slot of a can be filled at link time. | |
| 23 | # HEX: section '.got': | |
| 24 | # HEX: 0x10020068 {{[0-9a-f]+}} 00000000 00000000 10030000 | |
| 25 | ||
| 26 | ## a: &.got[3] - _GLOBAL_OFFSET_TABLE_ = 12 | |
| 27 | ## b: &.got[4] - _GLOBAL_OFFSET_TABLE_ = 16 | |
| 28 | # CHECK: lwz 3, 12(30) | |
| 29 | # CHECK: lwz 4, 16(30) | |
| 30 | ||
| 31 | lwz 3,a@got(30) | |
| 32 | lwz 4,b@got(30) | |
| 33 | ||
| 34 | .data | |
| 35 | a: | |
| 36 | .long _GLOBAL_OFFSET_TABLE_ |
deps/lld/test/ELF/ppc32-reloc-rel.s created+34| ... | ... | @@ -0,0 +1,34 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -o %t | |
| 4 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 5 | ||
| 6 | .section .R_PPC_REL14,"ax",@progbits | |
| 7 | beq 1f | |
| 8 | 1: | |
| 9 | # CHECK-LABEL: section .R_PPC_REL14: | |
| 10 | # CHECK: bt 2, .+4 | |
| 11 | ||
| 12 | .section .R_PPC_REL24,"ax",@progbits | |
| 13 | b 1f | |
| 14 | 1: | |
| 15 | # CHECK-LABEL: section .R_PPC_REL24: | |
| 16 | # CHECK: b .+4 | |
| 17 | ||
| 18 | .section .R_PPC_REL32,"ax",@progbits | |
| 19 | .long 1f - . | |
| 20 | 1: | |
| 21 | # HEX-LABEL: section .R_PPC_REL32: | |
| 22 | # HEX-NEXT: 10010008 00000004 | |
| 23 | ||
| 24 | .section .R_PPC_PLTREL24,"ax",@progbits | |
| 25 | b 1f@PLT+32768 | |
| 26 | 1: | |
| 27 | # CHECK-LABEL: section .R_PPC_PLTREL24: | |
| 28 | # CHECK: b .+4 | |
| 29 | ||
| 30 | .section .R_PPC_LOCAL24PC,"ax",@progbits | |
| 31 | b 1f@local | |
| 32 | 1: | |
| 33 | # CHECK-LABEL: section .R_PPC_LOCAL24PC: | |
| 34 | # CHECK: b .+4 |
deps/lld/test/ELF/ppc32-tls-gd.s created+98| ... | ... | @@ -0,0 +1,98 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o | |
| 3 | # RUN: echo '.tbss; .globl b, c; b: .zero 4; c:' | llvm-mc -filetype=obj -triple=powerpc - -o %t1.o | |
| 4 | # RUN: ld.lld -shared -soname=t1.so %t1.o -o %t1.so | |
| 5 | # RUN: echo '.globl __tls_get_addr; __tls_get_addr:' | llvm-mc -filetype=obj -triple=powerpc - -o %tga.o | |
| 6 | ||
| 7 | # RUN: ld.lld -shared %t.o %t1.o -o %t.so | |
| 8 | # RUN: llvm-readobj -d %t.so | FileCheck --check-prefix=GD-DYN %s | |
| 9 | # RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=GD-REL %s | |
| 10 | # RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=GD %s | |
| 11 | ||
| 12 | # RUN: ld.lld %t.o %t1.o %tga.o -o %t | |
| 13 | # RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s | |
| 14 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s | |
| 15 | ||
| 16 | # RUN: ld.lld %t.o %t1.so -o %t | |
| 17 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=IE-REL %s | |
| 18 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=IE %s | |
| 19 | ||
| 20 | ## DT_PPC_GOT represents the address of _GLOBAL_OFFSET_TABLE_. | |
| 21 | # GD-DYN: PPC_GOT 0x20078 | |
| 22 | ||
| 23 | # GD-REL: .rela.dyn { | |
| 24 | # GD-REL-NEXT: 0x20078 R_PPC_DTPMOD32 a 0x0 | |
| 25 | # GD-REL-NEXT: 0x2007C R_PPC_DTPREL32 a 0x0 | |
| 26 | # GD-REL-NEXT: 0x20080 R_PPC_DTPMOD32 b 0x0 | |
| 27 | # GD-REL-NEXT: 0x20084 R_PPC_DTPREL32 b 0x0 | |
| 28 | # GD-REL-NEXT: 0x20088 R_PPC_DTPMOD32 c 0x0 | |
| 29 | # GD-REL-NEXT: 0x2008C R_PPC_DTPREL32 c 0x0 | |
| 30 | # GD-REL-NEXT: } | |
| 31 | ||
| 32 | ## &DTPMOD(a) - _GLOBAL_OFFSET_TABLE_ = 0x20078 - 0x20078 = 0 | |
| 33 | # GD: addi 3, 31, 0 | |
| 34 | # GD-NEXT: bl .+32 | |
| 35 | # GD-NEXT: lwz 3, 0(3) | |
| 36 | ||
| 37 | ## &DTPMOD(b) - _GLOBAL_OFFSET_TABLE_ = 0x20080 - 0x20078 = 8 | |
| 38 | # GD-NEXT: addi 3, 31, 8 | |
| 39 | # GD-NEXT: bl .+20 | |
| 40 | # GD-NEXT: lwz 3, 0(3) | |
| 41 | ||
| 42 | ## &DTPMOD(c) - _GLOBAL_OFFSET_TABLE_ = 0x20088 - 0x20078 = 16 | |
| 43 | # GD-NEXT: addi 3, 9, 16 | |
| 44 | # GD-NEXT: bl .+8 | |
| 45 | # GD-NEXT: lwz 3, 0(3) | |
| 46 | ||
| 47 | # NOREL: no relocations | |
| 48 | ||
| 49 | ## a@tprel = 8-0x7000 = -28664 | |
| 50 | # LE: addis 3, 2, 0 | |
| 51 | # LE-NEXT: addi 3, 3, -28664 | |
| 52 | # LE-NEXT: lwz 3, 0(3) | |
| 53 | ## b@tprel = 12-0x7000 = -28660 | |
| 54 | # LE-NEXT: addis 3, 2, 0 | |
| 55 | # LE-NEXT: addi 3, 3, -28660 | |
| 56 | # LE-NEXT: lwz 3, 0(3) | |
| 57 | ## c@tprel = 16-0x7000 = -28656 | |
| 58 | # LE-NEXT: addis 3, 2, 0 | |
| 59 | # LE-NEXT: addi 3, 3, -28656 | |
| 60 | # LE-NEXT: lwz 3, 0(3) | |
| 61 | ||
| 62 | # IE-REL: .rela.dyn { | |
| 63 | # IE-REL-NEXT: 0x10020068 R_PPC_TPREL32 b 0x0 | |
| 64 | # IE-REL-NEXT: 0x1002006C R_PPC_TPREL32 c 0x0 | |
| 65 | # IE-REL-NEXT: } | |
| 66 | ||
| 67 | ## a is relaxed to use LE. | |
| 68 | ## a@tprel = st_value(a)-0x8000 = -28664 | |
| 69 | # IE: addis 3, 2, 0 | |
| 70 | # IE-NEXT: addi 3, 3, -28664 | |
| 71 | # IE-NEXT: lwz 3, 0(3) | |
| 72 | ## &.got[0] - _GLOBAL_OFFSET_TABLE_ = 0 | |
| 73 | # IE-NEXT: lwz 3, 0(31) | |
| 74 | # IE-NEXT: add 3, 3, 2 | |
| 75 | # IE-NEXT: lwz 3, 0(3) | |
| 76 | ## &.got[1] - _GLOBAL_OFFSET_TABLE_ = 4 | |
| 77 | # IE-NEXT: lwz 3, 4(9) | |
| 78 | # IE-NEXT: add 3, 3, 2 | |
| 79 | # IE-NEXT: lwz 3, 0(3) | |
| 80 | ||
| 81 | addi 3, 31, a@got@tlsgd | |
| 82 | bl __tls_get_addr(a@tlsgd) | |
| 83 | lwz 3, 0(3) | |
| 84 | ||
| 85 | addi 3, 31, b@got@tlsgd | |
| 86 | bl __tls_get_addr(b@tlsgd) | |
| 87 | lwz 3, 0(3) | |
| 88 | ||
| 89 | ## -fpic may use a different register (e.g. r9). | |
| 90 | addi 3, 9, c@got@tlsgd | |
| 91 | bl __tls_get_addr(c@tlsgd) | |
| 92 | lwz 3, 0(3) | |
| 93 | ||
| 94 | .section .tbss | |
| 95 | .globl a | |
| 96 | .zero 8 | |
| 97 | a: | |
| 98 | .zero 4 |
deps/lld/test/ELF/ppc32-tls-ie.s created+67| ... | ... | @@ -0,0 +1,67 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o | |
| 3 | ||
| 4 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 5 | # RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=IE-REL %s | |
| 6 | # RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=IE %s | |
| 7 | ||
| 8 | # RUN: ld.lld %t.o -o %t | |
| 9 | # RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s | |
| 10 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s | |
| 11 | ||
| 12 | ## A non-preemptable symbol (b) has 0 st_shndx. | |
| 13 | # IE-REL: .rela.dyn { | |
| 14 | # IE-REL-NEXT: 0x2005C R_PPC_TPREL32 - 0xC | |
| 15 | # IE-REL-NEXT: 0x20058 R_PPC_TPREL32 a 0x0 | |
| 16 | # IE-REL-NEXT: } | |
| 17 | ||
| 18 | ## &.got[0] - _GLOBAL_OFFSET_TABLE_ = 0 | |
| 19 | # IE: lwz 10, 0(9) | |
| 20 | # IE-NEXT: add 10, 10, 2 | |
| 21 | ## &.got[1] - _GLOBAL_OFFSET_TABLE_ = 4 | |
| 22 | # IE-NEXT: lwz 8, 4(7) | |
| 23 | # IE-NEXT: lbzx 10, 8, 2 | |
| 24 | ||
| 25 | # NOREL: no relocations | |
| 26 | ||
| 27 | ## a@tprel = st_value(a)-0x7000 = -28664 | |
| 28 | ## b@tprel = st_value(b)-0x7000 = -28660 | |
| 29 | # LE: addis 10, 2, 0 | |
| 30 | # LE-NEXT: addi 10, 10, -28664 | |
| 31 | # LE-NEXT: addis 8, 2, 0 | |
| 32 | # LE-NEXT: lbz 10, -28660(8) | |
| 33 | ||
| 34 | lwz 10, a@got@tprel(9) | |
| 35 | add 10, 10, a@tls | |
| 36 | ||
| 37 | lwz 8, c@got@tprel(7) | |
| 38 | lbzx 10, 8, c@tls | |
| 39 | ||
| 40 | ## In IE, these instructions (op rT, rA, x@tls) are not changed. | |
| 41 | # IE-NEXT: lhzx 12, 2, 2 | |
| 42 | # IE-NEXT: lwzx 13, 3, 2 | |
| 43 | # IE-NEXT: stbx 14, 4, 2 | |
| 44 | # IE-NEXT: sthx 15, 5, 2 | |
| 45 | # IE-NEXT: stwx 16, 6, 2 | |
| 46 | ||
| 47 | ## In LE, these X-Form instructions are changed to their corresponding D-Form. | |
| 48 | # LE-NEXT: lhz 12, -28660(2) | |
| 49 | # LE-NEXT: lwz 13, -28660(3) | |
| 50 | # LE-NEXT: stb 14, -28660(4) | |
| 51 | # LE-NEXT: sth 15, -28660(5) | |
| 52 | # LE-NEXT: stw 16, -28660(6) | |
| 53 | ||
| 54 | lhzx 12, 2, s@tls | |
| 55 | lwzx 13, 3, i@tls | |
| 56 | stbx 14, 4, c@tls | |
| 57 | sthx 15, 5, s@tls | |
| 58 | stwx 16, 6, i@tls | |
| 59 | ||
| 60 | .section .tbss | |
| 61 | .globl a | |
| 62 | .zero 8 | |
| 63 | a: | |
| 64 | .zero 4 | |
| 65 | c: | |
| 66 | s: | |
| 67 | i: |
deps/lld/test/ELF/ppc32-tls-ld.s created+82| ... | ... | @@ -0,0 +1,82 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o | |
| 3 | # RUN: echo '.globl __tls_get_addr; __tls_get_addr:' | llvm-mc -filetype=obj -triple=powerpc - -o %tga.o | |
| 4 | ||
| 5 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 6 | # RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=LD-REL %s | |
| 7 | # RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=LD %s | |
| 8 | ||
| 9 | # RUN: ld.lld %t.o %tga.o -o %t | |
| 10 | # RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s | |
| 11 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s | |
| 12 | ||
| 13 | # LD-REL: .rela.dyn { | |
| 14 | # LD-REL-NEXT: 0x20078 R_PPC_DTPMOD32 - 0x0 | |
| 15 | # LD-REL-NEXT: } | |
| 16 | ||
| 17 | ## .got - _GLOBAL_OFFSET_TABLE_ = 0 | |
| 18 | # LD: addi 3, 30, 0 | |
| 19 | # LD-NEXT: bl .+40 | |
| 20 | ## a@dtprel = st_value(a)-0x8000 = 65540-0x8000 = 65536*1-32764 | |
| 21 | ## b@dtprel = st_value(a)-0x8000 = 131080-0x8000 = 65536*2-32760 | |
| 22 | # LD-NEXT: addis 9, 3, 1 | |
| 23 | # LD-NEXT: addis 10, 3, 2 | |
| 24 | # LD-NEXT: addi 9, 9, -32764 | |
| 25 | # LD-NEXT: addi 10, 10, -32760 | |
| 26 | ## small@dtprel = st_value(small)-0x8000 = 4-0x8000 = -32764 | |
| 27 | # LD-NEXT: addi 9, 3, -32764 | |
| 28 | ||
| 29 | ## Check that b@got@tlsld does not allocate another GOT entry. | |
| 30 | ## It shares In.Got->TlsIndexOff allocated when processing a@got@tlsld. | |
| 31 | ## .got - _GLOBAL_OFFSET_TABLE_ = 0 | |
| 32 | # LD-NEXT: addi 3, 9, 0 | |
| 33 | # LD-NEXT: bl .+12 | |
| 34 | ## b@dtprel = st_value(a)-0x8000 = 131080-0x8000 = 65536*2-32760 | |
| 35 | # LD-NEXT: addis 29, 3, 2 | |
| 36 | # LD-NEXT: addi 29, 29, -32760 | |
| 37 | ||
| 38 | ## When producing an executable, the LD code sequence can be relaxed to LE. | |
| 39 | ## It is the same as GD->LE. | |
| 40 | ## tpoff(_TLS_MODULE_BASE_) = 0, tpoff(a) = -8, tpoff(b) = -4 | |
| 41 | ||
| 42 | # NOREL: no relocations | |
| 43 | ||
| 44 | ## Set r3 to r2+4096 | |
| 45 | # LE: addis 3, 2, 0 | |
| 46 | # LE-NEXT: addi 3, 3, 4096 | |
| 47 | ## a@tprel = 65540-0x7000 = 65536*1-32764 | |
| 48 | ## b@tprel = 131080-0x7000 = 65536*2-32760 | |
| 49 | # LE-NEXT: addis 9, 3, 1 | |
| 50 | # LE-NEXT: addis 10, 3, 2 | |
| 51 | # LE-NEXT: addi 9, 9, -32764 | |
| 52 | # LE-NEXT: addi 10, 10, -32760 | |
| 53 | ## small@tprel = 4-0x7000 = -32764 | |
| 54 | # LE-NEXT: addi 9, 3, -32764 | |
| 55 | ||
| 56 | ## Set r3 to r2+4096 | |
| 57 | # LE-NEXT: addis 3, 2, 0 | |
| 58 | # LE-NEXT: addi 3, 3, 4096 | |
| 59 | ## b@tprel = 131080-0x7000 = 65536*2-32760 | |
| 60 | # LE-NEXT: addis 29, 3, 2 | |
| 61 | # LE-NEXT: addi 29, 29, -32760 | |
| 62 | ||
| 63 | addi 3, 30, a@got@tlsld | |
| 64 | bl __tls_get_addr(a@tlsld) | |
| 65 | addis 9, 3, a@dtprel@ha | |
| 66 | addis 10, 3, b@dtprel@ha | |
| 67 | addi 9, 9, a@dtprel@l | |
| 68 | addi 10, 10, b@dtprel@l | |
| 69 | addi 9, 3, small@dtprel | |
| 70 | ||
| 71 | addi 3, 9, b@got@tlsld | |
| 72 | bl __tls_get_addr(b@tlsld) | |
| 73 | addis 29, 3, b@dtprel@ha | |
| 74 | addi 29, 29, b@dtprel@l | |
| 75 | ||
| 76 | .section .tbss | |
| 77 | .zero 4 | |
| 78 | small: | |
| 79 | .zero 65536 | |
| 80 | a: | |
| 81 | .zero 65540 | |
| 82 | b: |
deps/lld/test/ELF/ppc32-tls-le.s created+24| ... | ... | @@ -0,0 +1,24 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -o %t | |
| 4 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s | |
| 5 | ||
| 6 | ## a@tprel = st_value(a)-0x7000 = -28664 | |
| 7 | ## b@tprel = st_value(b)-0x7000 = -28660 | |
| 8 | # LE: addis 9, 2, 0 | |
| 9 | # LE-NEXT: addi 9, 9, -28664 | |
| 10 | # LE-NEXT: addis 10, 2, 0 | |
| 11 | # LE-NEXT: lwz 9, -28660(10) | |
| 12 | ||
| 13 | addis 9, 2, a@tprel@ha | |
| 14 | addi 9, 9, a@tprel@l | |
| 15 | ||
| 16 | addis 10, 2, b@tprel@ha | |
| 17 | lwz 9,b@tprel@l(10) | |
| 18 | ||
| 19 | .section .tbss | |
| 20 | .globl a | |
| 21 | .zero 8 | |
| 22 | a: | |
| 23 | .zero 4 | |
| 24 | b: |
deps/lld/test/ELF/ppc32-weak-undef-call.s created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -o %t | |
| 4 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=EXE %s | |
| 5 | # RUN: ld.lld -pie %t.o -o %t | |
| 6 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=EXE %s | |
| 7 | # RUN: ld.lld -shared %t.o -o %t | |
| 8 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=SHARED %s | |
| 9 | ||
| 10 | ## It does not really matter how we fixup it, but we cannot overflow and | |
| 11 | ## should not generate a call stub (this would waste space). | |
| 12 | # EXE: bl .+0 | |
| 13 | ||
| 14 | ## With -shared, create a call stub. ld.bfd produces bl .+0 | |
| 15 | # SHARED: bl .+4 | |
| 16 | # SHARED: 00000000.plt_pic32.foo: | |
| 17 | ||
| 18 | .weak foo | |
| 19 | bl foo |
deps/lld/test/ELF/ppc64-abs32-dyn.s created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le %s -o %t.o | |
| 3 | # RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s | |
| 4 | ||
| 5 | ## Test we don't create R_AARCH64_RELATIVE. | |
| 6 | ||
| 7 | # CHECK: error: relocation R_PPC64_ADDR32 cannot be used against symbol hidden; recompile with -fPIC | |
| 8 | ||
| 9 | .globl hidden | |
| 10 | .hidden hidden | |
| 11 | hidden: | |
| 12 | ||
| 13 | .data | |
| 14 | .long hidden |
deps/lld/test/ELF/ppc64-abs64-dyn.s created+29| ... | ... | @@ -0,0 +1,29 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 3 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 4 | # RUN: llvm-readobj -r %t.so | FileCheck %s | |
| 5 | ||
| 6 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o | |
| 7 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 8 | # RUN: llvm-readobj -r %t.so | FileCheck %s | |
| 9 | ||
| 10 | ## Test that we create R_PPC64_RELATIVE for R_PPC64_ADDR64 to non-preemptable | |
| 11 | ## symbols and R_PPC64_TOC in writable sections. | |
| 12 | ||
| 13 | ## FIXME the addend for offset 0x20000 should be TOC base+0x8000+1, not 0x80001. | |
| 14 | # CHECK: .rela.dyn { | |
| 15 | # CHECK-NEXT: 0x20000 R_PPC64_RELATIVE - 0x8001 | |
| 16 | # CHECK-NEXT: 0x20008 R_PPC64_RELATIVE - 0x20001 | |
| 17 | # CHECK-NEXT: 0x20010 R_PPC64_ADDR64 external 0x1 | |
| 18 | # CHECK-NEXT: 0x20018 R_PPC64_ADDR64 global 0x1 | |
| 19 | # CHECK-NEXT: } | |
| 20 | ||
| 21 | .data | |
| 22 | .globl global | |
| 23 | global: | |
| 24 | local: | |
| 25 | ||
| 26 | .quad .TOC.@tocbase + 1 | |
| 27 | .quad local + 1 | |
| 28 | .quad external + 1 | |
| 29 | .quad global + 1 |
deps/lld/test/ELF/ppc64-addr16-error.s deleted-13| ... | ... | @@ -1,13 +0,0 @@ |
| 1 | // REQUIRES: ppc | |
| 2 | ||
| 3 | // RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t | |
| 4 | // RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-addr16-error.s -o %t2 | |
| 5 | // RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck %s | |
| 6 | ||
| 7 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t | |
| 8 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-addr16-error.s -o %t2 | |
| 9 | // RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck %s | |
| 10 | ||
| 11 | .short sym+65539 | |
| 12 | ||
| 13 | // CHECK: relocation R_PPC64_ADDR16 out of range: 65539 is not in [-32768, 32767] |
deps/lld/test/ELF/ppc64-bsymbolic-toc-restore.s+2-2| ... | ... | @@ -53,7 +53,7 @@ caller: |
| 53 | 53 | # CHECK-LABEL: caller |
| 54 | 54 | # CHECK: bl .+44 |
| 55 | 55 | # CHECK-NEXT: mr 31, 3 |
| 56 | # CHECK-NEXT: bl .+67108816 | |
| 56 | # CHECK-NEXT: bl .+44 | |
| 57 | 57 | # CHECK-NEXT: ld 2, 24(1) |
| 58 | 58 | # CHECK-NEXT: add 3, 3, 31 |
| 59 | 59 | # CHECK-NEXT: addi 1, 1, 32 |
| ... | ... | @@ -63,6 +63,6 @@ caller: |
| 63 | 63 | # CHECK-EMPTY: |
| 64 | 64 | # CHECK-NEXT: def: |
| 65 | 65 | # CHECK-NEXT: addis 2, 12, 2 |
| 66 | # CHECK-NEXT: addi 2, 2, -32636 | |
| 66 | # CHECK-NEXT: addi 2, 2, -32616 | |
| 67 | 67 | # CHECK-NEXT: li 3, 55 |
| 68 | 68 | # CHECK-NEXT: blr |
deps/lld/test/ELF/ppc64-call-reach.s+26-30| ... | ... | @@ -3,16 +3,16 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o |
| 4 | 4 | # RUN: ld.lld --defsym callee=0x12010010 --defsym tail_callee=0x12010020 \ |
| 5 | 5 | # RUN: %t.o -o %t |
| 6 | # RUN: llvm-objdump -d %t | FileCheck %s | |
| 6 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 7 | 7 | # RUN: ld.lld --defsym callee=0x12010010 --defsym tail_callee=0x12010020 \ |
| 8 | 8 | # RUN: %t.o -o %t |
| 9 | # RUN: llvm-objdump -d %t | FileCheck %s | |
| 9 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 10 | 10 | # RUN: ld.lld --defsym callee=0xE010014 --defsym tail_callee=0xE010024 \ |
| 11 | 11 | # RUN: %t.o -o %t |
| 12 | # RUN: llvm-objdump -d %t | FileCheck --check-prefix=NEGOFFSET %s | |
| 12 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=NEGOFFSET %s | |
| 13 | 13 | # RUN: ld.lld --defsym callee=0x12010018 --defsym tail_callee=0x12010028 \ |
| 14 | 14 | # RUN: %t.o -o %t |
| 15 | # RUN: llvm-objdump -d %t | FileCheck --check-prefix=THUNK %s | |
| 15 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=THUNK %s | |
| 16 | 16 | # RUN: llvm-readelf --sections %t | FileCheck --check-prefix=BRANCHLT %s |
| 17 | 17 | # RUN: not ld.lld --defsym callee=0x1001002D --defsym tail_callee=0x1001002F \ |
| 18 | 18 | # RUN: %t.o -o %t 2>&1 | FileCheck --check-prefix=MISSALIGNED %s |
| ... | ... | @@ -20,16 +20,16 @@ |
| 20 | 20 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o |
| 21 | 21 | # RUN: ld.lld --defsym callee=0x12010010 --defsym tail_callee=0x12010020 \ |
| 22 | 22 | # RUN: %t.o -o %t |
| 23 | # RUN: llvm-objdump -d %t | FileCheck %s | |
| 23 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 24 | 24 | # RUN: ld.lld --defsym callee=0x12010010 --defsym tail_callee=0x12010020 \ |
| 25 | 25 | # RUN: %t.o -o %t |
| 26 | # RUN: llvm-objdump -d %t | FileCheck %s | |
| 26 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 27 | 27 | # RUN: ld.lld --defsym callee=0xE010014 --defsym tail_callee=0xE010024 \ |
| 28 | 28 | # RUN: %t.o -o %t |
| 29 | # RUN: llvm-objdump -d %t | FileCheck --check-prefix=NEGOFFSET %s | |
| 29 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=NEGOFFSET %s | |
| 30 | 30 | # RUN: ld.lld --defsym callee=0x12010018 --defsym tail_callee=0x12010028 \ |
| 31 | 31 | # RUN: %t.o -o %t |
| 32 | # RUN: llvm-objdump -d %t | FileCheck --check-prefix=THUNK %s | |
| 32 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=THUNK %s | |
| 33 | 33 | # RUN: llvm-readelf --sections %t | FileCheck --check-prefix=BRANCHLT %s |
| 34 | 34 | # RUN: not ld.lld --defsym callee=0x1001002D --defsym tail_callee=0x1001002F \ |
| 35 | 35 | # RUN: %t.o -o %t 2>&1 | FileCheck --check-prefix=MISSALIGNED %s |
| ... | ... | @@ -58,37 +58,33 @@ test: |
| 58 | 58 | # Check that we are branching to the definitions, and not range-extending |
| 59 | 59 | # thunks. |
| 60 | 60 | # CHECK-LABEL: test |
| 61 | # CHECK: 10010014: {{.*}} bl .+33554428 | |
| 62 | # CHECK: 10010024: {{.*}} b .+33554428 | |
| 61 | # CHECK: 10010014: bl .+33554428 | |
| 62 | # CHECK: 10010024: b .+33554428 | |
| 63 | 63 | |
| 64 | 64 | # NEGOFFSET-LABEL: test |
| 65 | # NEGOFFSET: 10010014: {{.*}} bl .+33554432 | |
| 66 | # NEGOFFSET: 10010024: {{.*}} b .+33554432 | |
| 65 | # NEGOFFSET: 10010014: bl .-33554432 | |
| 66 | # NEGOFFSET: 10010024: b .+33554432 | |
| 67 | ||
| 68 | # THUNK-LABEL: test: | |
| 69 | # THUNK: 10010014: bl .+20 | |
| 70 | # THUNK: 10010024: b .+20 | |
| 67 | 71 | |
| 68 | 72 | # .branch_lt[0] |
| 69 | 73 | # THUNK-LABEL: __long_branch_callee: |
| 70 | # THUNK-NEXT: 10010000: {{.*}} addis 12, 2, -1 | |
| 71 | # THUNK-NEXT: ld 12, -32768(12) | |
| 72 | # THUNK-NEXT: mtctr 12 | |
| 73 | # THUNK-NEXT: bctr | |
| 74 | # THUNK-NEXT: 10010028: addis 12, 2, 1 | |
| 75 | # THUNK-NEXT: ld 12, -32768(12) | |
| 76 | # THUNK-NEXT: mtctr 12 | |
| 77 | # THUNK-NEXT: bctr | |
| 74 | 78 | |
| 75 | 79 | # .branch_lt[1] |
| 76 | 80 | # THUNK-LABEL: __long_branch_tail_callee: |
| 77 | # THUNK-NEXT: 10010010: {{.*}} addis 12, 2, -1 | |
| 78 | # THUNK-NEXT: ld 12, -32760(12) | |
| 79 | # THUNK-NEXT: mtctr 12 | |
| 80 | # THUNK-NEXT: bctr | |
| 81 | ||
| 82 | # Each call now branches to a thunk, and although it is printed as positive | |
| 83 | # the offset is interpreted as a signed 26 bit value so 67108812 is actually | |
| 84 | # -52. | |
| 85 | # THUNK-LABEL: test: | |
| 86 | # THUNK: 10010034: {{.*}} bl .+67108812 | |
| 87 | # THUNK: 10010044: {{.*}} b .+67108812 | |
| 81 | # THUNK-NEXT: 10010038: addis 12, 2, 1 | |
| 82 | # THUNK-NEXT: ld 12, -32760(12) | |
| 83 | # THUNK-NEXT: mtctr 12 | |
| 84 | # THUNK-NEXT: bctr | |
| 88 | 85 | |
| 89 | 86 | # The offset from the TOC to the .branch_lt section is (-1 << 16) - 32768. |
| 90 | 87 | # Name Type Address Off Size |
| 91 | # BRANCHLT: .branch_lt PROGBITS 0000000010020000 020000 000010 | |
| 92 | # BRANCHLT: .got PROGBITS 0000000010030000 030000 000008 | |
| 88 | # BRANCHLT: .got PROGBITS 0000000010020000 020000 000008 | |
| 89 | # BRANCHLT: .branch_lt PROGBITS 0000000010030000 030000 000010 | |
| 93 | 90 | # BRANCHLT-NOT: .plt |
| 94 |
deps/lld/test/ELF/ppc64-dtprel.s+17-46| ... | ... | @@ -4,15 +4,15 @@ |
| 4 | 4 | // RUN: ld.lld -shared %t.o -o %t.so |
| 5 | 5 | // RUN: llvm-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s |
| 6 | 6 | // RUN: llvm-readelf -r %t.so | FileCheck --check-prefix=OutputRelocs %s |
| 7 | // RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s | |
| 8 | // RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=GotDisLE %s | |
| 7 | // RUN: llvm-readelf -x .got %t.so | FileCheck --check-prefix=HEX-LE %s | |
| 8 | // RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=Dis %s | |
| 9 | 9 | |
| 10 | 10 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o |
| 11 | 11 | // RUN: ld.lld -shared %t.o -o %t.so |
| 12 | 12 | // RUN: llvm-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s |
| 13 | 13 | // RUN: llvm-readelf -r %t.so | FileCheck --check-prefix=OutputRelocs %s |
| 14 | // RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s | |
| 15 | // RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=GotDisBE %s | |
| 14 | // RUN: llvm-readelf -x .got %t.so | FileCheck --check-prefix=HEX-BE %s | |
| 15 | // RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=Dis %s | |
| 16 | 16 | |
| 17 | 17 | .text |
| 18 | 18 | .abiversion 2 |
| ... | ... | @@ -97,15 +97,6 @@ test_not_adjusted: |
| 97 | 97 | mtlr 0 |
| 98 | 98 | blr |
| 99 | 99 | |
| 100 | .globl test_got_dtprel | |
| 101 | .p2align 4 | |
| 102 | .type test_got_dtprel,@function | |
| 103 | test_got_dtprel: | |
| 104 | addis 3, 2, i@got@dtprel@ha | |
| 105 | ld 3, i@got@dtprel@l(3) | |
| 106 | addis 3, 2, i@got@dtprel@h | |
| 107 | addi 3, 2, i@got@dtprel | |
| 108 | ||
| 109 | 100 | .section .debug_addr,"",@progbits |
| 110 | 101 | .quad i@dtprel+32768 |
| 111 | 102 | |
| ... | ... | @@ -137,10 +128,6 @@ k: |
| 137 | 128 | // InputRelocs: R_PPC64_DTPREL16_HIGHER {{[0-9a-f]+}} k + 0 |
| 138 | 129 | // InputRelocs: R_PPC64_DTPREL16_HI {{[0-9a-f]+}} k + 0 |
| 139 | 130 | // InputRelocs: R_PPC64_DTPREL16_LO {{[0-9a-f]+}} k + 0 |
| 140 | // InputRelocs: R_PPC64_GOT_DTPREL16_HA {{[0-9a-f]+}} i + 0 | |
| 141 | // InputRelocs: R_PPC64_GOT_DTPREL16_LO_DS {{[0-9a-f]+}} i + 0 | |
| 142 | // InputRelocs: R_PPC64_GOT_DTPREL16_HI {{[0-9a-f]+}} i + 0 | |
| 143 | // InputRelocs: R_PPC64_GOT_DTPREL16_DS {{[0-9a-f]+}} i + 0 | |
| 144 | 131 | // InputRelocs: Relocation section '.rela.debug_addr' |
| 145 | 132 | // InputRelocs: R_PPC64_DTPREL64 {{[0-9a-f]+}} i + 8000 |
| 146 | 133 | |
| ... | ... | @@ -150,10 +137,19 @@ k: |
| 150 | 137 | // OutputRelocs-NEXT: R_PPC64_DTPMOD64 |
| 151 | 138 | |
| 152 | 139 | |
| 153 | // i@dtprel --> (1024 - 0x8000) = -31744 | |
| 154 | // Dis: test: | |
| 155 | // Dis: addi 4, 3, -31744 | |
| 156 | // Dis: lwa 4, -31744(3) | |
| 140 | // The got entry for i is at .got+8*3 = 0x420510 | |
| 141 | // i@dtprel = 1024 - 0x8000 = -31744 = 0xffffffffffff8400 | |
| 142 | // HEX-LE: section '.got': | |
| 143 | // HEX-LE-NEXT: 4204f8 f8844200 00000000 00000000 00000000 | |
| 144 | // HEX-LE-NEXT: 420508 00000000 00000000 | |
| 145 | ||
| 146 | // HEX-BE: section '.got': | |
| 147 | // HEX-BE-NEXT: 4204f8 00000000 004284f8 00000000 00000000 | |
| 148 | // HEX-BE-NEXT: 420508 00000000 00000000 | |
| 149 | ||
| 150 | // Dis: test: | |
| 151 | // Dis: addi 4, 3, -31744 | |
| 152 | // Dis-NEXT: lwa 4, -31744(3) | |
| 157 | 153 | |
| 158 | 154 | // #k@dtprel(1024 + 4 + 1024 * 1024 * 4) = 0x400404 |
| 159 | 155 | |
| ... | ... | @@ -177,28 +173,3 @@ k: |
| 177 | 173 | // Dis: oris 4, 4, 63 |
| 178 | 174 | // Dis: ori 4, 4, 33796 |
| 179 | 175 | |
| 180 | // Check for GOT entry for i. There should be a got entry which holds the offset | |
| 181 | // of i relative to the dynamic thread pointer. | |
| 182 | // i@dtprel -> (1024 - 0x8000) = 0xffff8400 | |
| 183 | // GotDisBE: Disassembly of section .got: | |
| 184 | // GotDisBE: 4204f8: 00 00 00 00 | |
| 185 | // GotDisBE: 4204fc: 00 42 84 f8 | |
| 186 | // GotDisBE: 420510: ff ff ff ff | |
| 187 | // GotDisBE: 420514: ff ff 84 00 | |
| 188 | ||
| 189 | // GotDisLE: Disassembly of section .got: | |
| 190 | // GotDisLE: 4204f8: f8 84 42 00 | |
| 191 | // GotDisLE: 420510: 00 84 ff ff | |
| 192 | // GotDisLE: 420514: ff ff ff ff | |
| 193 | ||
| 194 | // Check that we have the correct offset to the got entry for i@got@dtprel | |
| 195 | // The got entry for i is 0x420510, and the TOC pointer is 0x4284f8. | |
| 196 | // #ha(i@got@dtprel) --> ((0x420510 - 0x4284f8 + 0x8000) >> 16) & 0xffff = 0 | |
| 197 | // #lo(i@got@dtprel) --> (0x420510 - 0x4284f8) & 0xffff = -32744 | |
| 198 | // #hi(i@got@dtprel) --> ((0x420510 - 0x4284f8) >> 16) & 0xffff = -1 | |
| 199 | // i@got@dtprel --> 0x420510 - 0x4284f8 = -32744 | |
| 200 | // Dis: test_got_dtprel: | |
| 201 | // Dis: addis 3, 2, 0 | |
| 202 | // Dis: ld 3, -32744(3) | |
| 203 | // Dis: addis 3, 2, -1 | |
| 204 | // Dis: addi 3, 2, -32744 |
deps/lld/test/ELF/ppc64-dynamic-relocations.s deleted-50| ... | ... | @@ -1,50 +0,0 @@ |
| 1 | // REQUIRES: ppc | |
| 2 | ||
| 3 | // RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 4 | // RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o | |
| 5 | // RUN: ld.lld -shared %t2.o -o %t2.so | |
| 6 | // RUN: ld.lld %t.o %t2.so -o %t | |
| 7 | // RUN: llvm-readobj -dyn-relocations %t | FileCheck %s | |
| 8 | // RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=DIS %s | |
| 9 | // RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s | |
| 10 | ||
| 11 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o | |
| 12 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o | |
| 13 | // RUN: ld.lld -shared %t2.o -o %t2.so | |
| 14 | // RUN: ld.lld %t.o %t2.so -o %t | |
| 15 | // RUN: llvm-readobj -dyn-relocations %t | FileCheck %s | |
| 16 | // RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=DIS %s | |
| 17 | // RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s | |
| 18 | ||
| 19 | ||
| 20 | // The dynamic relocation for foo should point to 16 bytes past the start of | |
| 21 | // the .plt section. | |
| 22 | // CHECK: Dynamic Relocations { | |
| 23 | // CHECK-NEXT: 0x10030010 R_PPC64_JMP_SLOT foo 0x0 | |
| 24 | ||
| 25 | // There should be 2 reserved doublewords before the first entry. The dynamic | |
| 26 | // linker will fill those in with the address of the resolver entry point and | |
| 27 | // the dynamic object identifier. | |
| 28 | // DIS: Idx Name Size Address Type | |
| 29 | // DIS: .plt 00000018 0000000010030000 BSS | |
| 30 | ||
| 31 | // DT_PLTGOT should point to the start of the .plt section. | |
| 32 | // DT: 0x0000000000000003 PLTGOT 0x10030000 | |
| 33 | ||
| 34 | .text | |
| 35 | .abiversion 2 | |
| 36 | .globl _start | |
| 37 | .p2align 4 | |
| 38 | .type _start,@function | |
| 39 | _start: | |
| 40 | .Lfunc_begin0: | |
| 41 | .Lfunc_gep0: | |
| 42 | addis 2, 12, .TOC.-.Lfunc_gep0@ha | |
| 43 | addi 2, 2, .TOC.-.Lfunc_gep0@l | |
| 44 | .Lfunc_lep0: | |
| 45 | .localentry _start, .Lfunc_lep0-.Lfunc_gep0 | |
| 46 | bl foo | |
| 47 | nop | |
| 48 | li 0, 1 | |
| 49 | sc | |
| 50 | .size _start, .-.Lfunc_begin0 |
deps/lld/test/ELF/ppc64-entry-point.s+18-22| ... | ... | @@ -1,14 +1,14 @@ |
| 1 | 1 | # REQUIRES: ppc |
| 2 | 2 | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t | |
| 4 | # RUN: ld.lld %t -o %t2 | |
| 5 | # RUN: llvm-objdump -D %t2 | FileCheck %s | |
| 6 | # RUN: llvm-objdump -D %t2 | FileCheck -check-prefix=CHECK-LE %s | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 4 | # RUN: ld.lld %t.o -o %t | |
| 5 | # RUN: llvm-nm %t | FileCheck --check-prefix=NM %s | |
| 6 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 7 | 7 | |
| 8 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t | |
| 9 | # RUN: ld.lld %t -o %t2 | |
| 10 | # RUN: llvm-objdump -D %t2 | FileCheck %s | |
| 11 | # RUN: llvm-objdump -D %t2 | FileCheck -check-prefix=CHECK-BE %s | |
| 8 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o | |
| 9 | # RUN: ld.lld %t.o -o %t | |
| 10 | # RUN: llvm-nm %t | FileCheck --check-prefix=NM %s | |
| 11 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 12 | 12 | |
| 13 | 13 | .text |
| 14 | 14 | .abiversion 2 |
| ... | ... | @@ -23,8 +23,8 @@ _start: |
| 23 | 23 | addi 4, 4, .Lfunc_gep0@l |
| 24 | 24 | # now r4 should contain the address of _start |
| 25 | 25 | |
| 26 | lis 5, .TOC.-.Lfunc_gep0@ha | |
| 27 | addi 5, 5, .TOC.-.Lfunc_gep0@l | |
| 26 | lis 5, .TOC.-.Lfunc_gep0@ha # R_PPC64_REL16_HA | |
| 27 | addi 5, 5, .TOC.-.Lfunc_gep0@l # R_PPC64_REL16_LO | |
| 28 | 28 | # now r5 should contain the offset s.t. r4 + r5 = TOC base |
| 29 | 29 | |
| 30 | 30 | # exit 55 |
| ... | ... | @@ -34,16 +34,12 @@ _start: |
| 34 | 34 | .Lfunc_end0: |
| 35 | 35 | .size _start, .Lfunc_end0-.Lfunc_begin0 |
| 36 | 36 | |
| 37 | // CHECK: 10010000: {{.*}} lis 4, 4097 | |
| 38 | // CHECK-NEXT: 10010004: {{.*}} addi 4, 4, 0 | |
| 39 | // CHECK-NEXT: 10010008: {{.*}} lis 5, 2 | |
| 40 | // CHECK-NEXT: 1001000c: {{.*}} addi 5, 5, -32768 | |
| 37 | # NM-DAG: 0000000010028000 d .TOC. | |
| 38 | # NM-DAG: 0000000010010000 T _start | |
| 41 | 39 | |
| 42 | // CHECK-LE: Disassembly of section .got: | |
| 43 | // CHECK-LE-NEXT: .got: | |
| 44 | // CHECK-LE-NEXT: 10020000: 00 80 02 10 | |
| 45 | ||
| 46 | // CHECK-BE: Disassembly of section .got: | |
| 47 | // CHECK-BE-NEXT: .got: | |
| 48 | // CHECK-BE-NEXT: 10020000: 00 00 00 00 {{.*}} | |
| 49 | // CHECK-BE-NEXT: 10020004: 10 02 80 00 {{.*}} | |
| 40 | # 0x10010000 = (4097<<16) + 0 | |
| 41 | # CHECK: 10010000: lis 4, 4097 | |
| 42 | # CHECK-NEXT: 10010004: addi 4, 4, 0 | |
| 43 | # .TOC. - _start = (2<<16) - 32768 | |
| 44 | # CHECK-NEXT: 10010008: lis 5, 2 | |
| 45 | # CHECK-NEXT: 1001000c: addi 5, 5, -32768 |
deps/lld/test/ELF/ppc64-func-entry-points.s+2-2| ... | ... | @@ -73,8 +73,8 @@ glob: |
| 73 | 73 | // CHECK: 10010020: {{.*}} bl .+144 |
| 74 | 74 | // CHECK: 10010034: {{.*}} bl .+84 |
| 75 | 75 | // CHECK: foo_external_diff: |
| 76 | // CHECK-NEXT: 10010080: {{.*}} addis 2, 12, 2 | |
| 76 | // CHECK-NEXT: 10010080: {{.*}} addis 2, 12, 1 | |
| 77 | 77 | // CHECK-NEXT: 10010084: {{.*}} addi 2, 2, 32640 |
| 78 | // CHECK-NEXT: 10010088: {{.*}} nop | |
| 78 | // CHECK-NEXT: 10010088: {{.*}} addis 5, 2, 1 | |
| 79 | 79 | // CHECK: foo_external_same: |
| 80 | 80 | // CHECK-NEXT: 100100b0: {{.*}} add 3, 4, 3 |
deps/lld/test/ELF/ppc64-gd-to-ie.s deleted-104| ... | ... | @@ -1,104 +0,0 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o | |
| 5 | # RUN: ld.lld -shared %t2.o -o %t3.so | |
| 6 | # RUN: ld.lld %t.o %t3.so -o %t | |
| 7 | # RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s | |
| 8 | # RUN: llvm-objdump -d %t | FileCheck --check-prefix=Dis %s | |
| 9 | # RUN: llvm-readelf -r %t | FileCheck --check-prefix=OutputRelocs %s | |
| 10 | ||
| 11 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o | |
| 12 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o | |
| 13 | # RUN: ld.lld -shared %t2.o -o %t3.so | |
| 14 | # RUN: ld.lld %t.o %t3.so -o %t | |
| 15 | # RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s | |
| 16 | # RUN: llvm-objdump -d %t | FileCheck --check-prefix=Dis %s | |
| 17 | # RUN: llvm-readelf -r %t | FileCheck --check-prefix=OutputRelocs %s | |
| 18 | ||
| 19 | .text | |
| 20 | .abiversion 2 | |
| 21 | .globl _start | |
| 22 | .p2align 4 | |
| 23 | .type _start,@function | |
| 24 | _start: | |
| 25 | .Lfunc_gep0: | |
| 26 | addis 2, 12, .TOC.-.Lfunc_gep0@ha | |
| 27 | addi 2, 2, .TOC.-.Lfunc_gep0@l | |
| 28 | .Lfunc_lep0: | |
| 29 | .localentry _start, .Lfunc_lep0-.Lfunc_gep0 | |
| 30 | mflr 0 | |
| 31 | std 0, 16(1) | |
| 32 | stdu 1, -32(1) | |
| 33 | addis 3, 2, a@got@tlsgd@ha | |
| 34 | addi 3, 3, a@got@tlsgd@l | |
| 35 | bl __tls_get_addr(a@tlsgd) | |
| 36 | nop | |
| 37 | lwa 3, 0(3) | |
| 38 | addi 1, 1, 32 | |
| 39 | ld 0, 16(1) | |
| 40 | mtlr 0 | |
| 41 | blr | |
| 42 | ||
| 43 | ||
| 44 | .globl other_reg | |
| 45 | .p2align 4 | |
| 46 | .type other_reg,@function | |
| 47 | other_reg: | |
| 48 | .Lfunc_gep1: | |
| 49 | addis 2, 12, .TOC.-.Lfunc_gep1@ha | |
| 50 | addi 2, 2, .TOC.-.Lfunc_gep1@l | |
| 51 | .Lfunc_lep1: | |
| 52 | .localentry other_reg, .Lfunc_lep1-.Lfunc_gep1 | |
| 53 | mflr 0 | |
| 54 | std 0, 16(1) | |
| 55 | stdu 1, -32(1) | |
| 56 | addis 5, 2, a@got@tlsgd@ha | |
| 57 | addi 3, 5, a@got@tlsgd@l | |
| 58 | bl __tls_get_addr(a@tlsgd) | |
| 59 | nop | |
| 60 | lwa 4, 0(3) | |
| 61 | addis 30, 2, b@got@tlsgd@ha | |
| 62 | addi 3, 30, b@got@tlsgd@l | |
| 63 | bl __tls_get_addr(b@tlsgd) | |
| 64 | nop | |
| 65 | lwa 3, 0(3) | |
| 66 | add 3, 4, 3 | |
| 67 | addi 1, 1, 32 | |
| 68 | ld 0, 16(1) | |
| 69 | mtlr 0 | |
| 70 | blr | |
| 71 | ||
| 72 | .globl __tls_get_addr | |
| 73 | .type __tls_get_addr,@function | |
| 74 | __tls_get_addr: | |
| 75 | ||
| 76 | ||
| 77 | # CheckGot: .got 00000018 00000000100200c0 DATA | |
| 78 | # .got is at 0x100200c0 so the toc-base is 100280c0. | |
| 79 | # `a` is at .got[1], we expect the offsets to be: | |
| 80 | # Ha(a) = ((0x100200c8 - 0x100280c0) + 0x8000) >> 16 = 0 | |
| 81 | # Lo(a) = (0x100200c8 - 0x100280c0) = -32760 | |
| 82 | ||
| 83 | # Dis-LABEL: _start | |
| 84 | # Dis: addis 3, 2, 0 | |
| 85 | # Dis-NEXT: ld 3, -32760(3) | |
| 86 | # Dis-NEXT: nop | |
| 87 | # Dis-NEXT: add 3, 3, 13 | |
| 88 | ||
| 89 | # Dis-LABEL: other_reg | |
| 90 | # Dis: addis 5, 2, 0 | |
| 91 | # Dis-NEXT: ld 3, -32760(5) | |
| 92 | # Dis-NEXT: nop | |
| 93 | # Dis-NEXT: add 3, 3, 13 | |
| 94 | # Dis: addis 30, 2, 0 | |
| 95 | # Dis: ld 3, -32752(30) | |
| 96 | # Dis-NEXT: nop | |
| 97 | # Dis-NEXT: add 3, 3, 13 | |
| 98 | ||
| 99 | # Verify that the only dynamic relocations we emit are TPREL ones rather then | |
| 100 | # the DTPMOD64/DTPREL64 pair for general-dynamic. | |
| 101 | # OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 2 entries: | |
| 102 | # OutputRelocs-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend | |
| 103 | # OutputRelocs-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_TPREL64 {{[0-9a-f]+}} a + 0 | |
| 104 | # OutputRelocs-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_TPREL64 {{[0-9a-f]+}} b + 0 |
deps/lld/test/ELF/ppc64-general-dynamic-tls.s deleted-112| ... | ... | @@ -1,112 +0,0 @@ |
| 1 | // REQUIRES: ppc | |
| 2 | ||
| 3 | // RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 4 | // RUN: ld.lld -shared %t.o -o %t.so | |
| 5 | // RUN: llvm-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s | |
| 6 | // RUN: llvm-readelf -r %t.so | FileCheck --check-prefix=OutputRelocs %s | |
| 7 | // RUN: llvm-objdump --section-headers %t.so | FileCheck --check-prefix=CheckGot %s | |
| 8 | // RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=Dis %s | |
| 9 | ||
| 10 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o | |
| 11 | // RUN: ld.lld -shared %t.o -o %t.so | |
| 12 | // RUN: llvm-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s | |
| 13 | // RUN: llvm-readelf -r %t.so | FileCheck --check-prefix=OutputRelocs %s | |
| 14 | // RUN: llvm-objdump --section-headers %t.so | FileCheck --check-prefix=CheckGot %s | |
| 15 | // RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=Dis %s | |
| 16 | ||
| 17 | 	.text | |
| 18 | 	.abiversion 2 | |
| 19 | 	.globl	test | |
| 20 | 	.p2align	4 | |
| 21 | 	.type	test,@function | |
| 22 | test: | |
| 23 | .Lfunc_gep0: | |
| 24 | 	addis 2, 12, .TOC.-.Lfunc_gep0@ha | |
| 25 | 	addi 2, 2, .TOC.-.Lfunc_gep0@l | |
| 26 | .Lfunc_lep0: | |
| 27 | 	.localentry	test, .Lfunc_lep0-.Lfunc_gep0 | |
| 28 | 	mflr 0 | |
| 29 | 	std 31, -8(1) | |
| 30 | 	std 0, 16(1) | |
| 31 | 	stdu 1, -48(1) | |
| 32 | 	mr 31, 1 | |
| 33 | 	std 30, 32(31) | |
| 34 | 	addis 3, 2, i@got@tlsgd@ha | |
| 35 | 	addi 3, 3, i@got@tlsgd@l | |
| 36 | 	bl __tls_get_addr(i@tlsgd) | |
| 37 | 	nop | |
| 38 | 	lwz 30, 0(3) | |
| 39 | 	extsw 3, 30 | |
| 40 | 	ld 30, 32(31) | |
| 41 | 	addi 1, 1, 48 | |
| 42 | 	ld 0, 16(1) | |
| 43 | 	ld 31, -8(1) | |
| 44 | 	mtlr 0 | |
| 45 | 	blr | |
| 46 | ||
| 47 | ||
| 48 | test_hi: | |
| 49 | .Lfunc_gep1: | |
| 50 | addis 2, 12, .TOC.-.Lfunc_gep1@ha | |
| 51 | addi 2, 2, .TOC.-.Lfunc_gep1@l | |
| 52 | .Lfunc_lep1: | |
| 53 | .localentry test2, .Lfunc_lep1-.Lfunc_gep1 | |
| 54 | addis 3, 0, j@got@tlsgd@h | |
| 55 | blr | |
| 56 | ||
| 57 | test_16: | |
| 58 | .Lfunc_gep2: | |
| 59 | addis 2, 12, .TOC.-.Lfunc_gep2@ha | |
| 60 | addi 2, 2, .TOC.-.Lfunc_gep2@l | |
| 61 | .Lfunc_lep2: | |
| 62 | .localentry test16, .Lfunc_lep2-.Lfunc_gep2 | |
| 63 | addi 3, 0, k@got@tlsgd | |
| 64 | blr | |
| 65 | ||
| 66 | // Verify that the input has every general-dynamic tls relocation type. | |
| 67 | // InputRelocs: Relocation section '.rela.text' | |
| 68 | // InputRelocs: R_PPC64_GOT_TLSGD16_HA {{0+}} i + 0 | |
| 69 | // InputRelocs: R_PPC64_GOT_TLSGD16_LO {{0+}} i + 0 | |
| 70 | // InputRelocs: R_PPC64_TLSGD {{0+}} i + 0 | |
| 71 | // InputRelocs: R_PPC64_GOT_TLSGD16_HI {{0+}} j + 0 | |
| 72 | // InputRelocs: R_PPC64_GOT_TLSGD16 {{0+}} k + 0 | |
| 73 | ||
| 74 | // There is 2 got entries for each tls variable that is accessed with the | |
| 75 | // general-dynamic model. The entries can be though of as a structure to be | |
| 76 | // filled in by the dynamic linker: | |
| 77 | // typedef struct { | |
| 78 | // unsigned long int ti_module; --> R_PPC64_DTPMOD64 | |
| 79 | // unsigned long int ti_offset; --> R_PPC64_DTPREL64 | |
| 80 | //} tls_index; | |
| 81 | // OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 6 entries: | |
| 82 | // OutputRelocs: R_PPC64_DTPMOD64 {{0+}} i + 0 | |
| 83 | // OutputRelocs: R_PPC64_DTPREL64 {{0+}} i + 0 | |
| 84 | // OutputRelocs: R_PPC64_DTPMOD64 {{0+}} j + 0 | |
| 85 | // OutputRelocs: R_PPC64_DTPREL64 {{0+}} j + 0 | |
| 86 | // OutputRelocs: R_PPC64_DTPMOD64 {{0+}} k + 0 | |
| 87 | // OutputRelocs: R_PPC64_DTPREL64 {{0+}} k + 0 | |
| 88 | ||
| 89 | // Check that the got has 7 entires. (1 for the TOC and 3 structures of | |
| 90 | // 2 entries for the tls variables). Also verify the address so we can check | |
| 91 | // the offsets we calculated for each relocation type. | |
| 92 | // CheckGot: got 00000038 00000000000200f0 | |
| 93 | ||
| 94 | // got starts at 0x200f0, so .TOC. will be 0x280f0. | |
| 95 | ||
| 96 | // We are building the address of the first tls_index in the got which starts at | |
| 97 | // 0x200f8 (got[1]). | |
| 98 | // #ha(i@got@tlsgd) --> (0x200f8 - 0x280f0 + 0x8000) >> 16 = 0 | |
| 99 | // #lo(i@got@tlsgd) --> (0x200f8 - 0x280f0) & 0xFFFF = -7ff8 = -32760 | |
| 100 | // Dis: test: | |
| 101 | // Dis: addis 3, 2, 0 | |
| 102 | // Dis: addi 3, 3, -32760 | |
| 103 | ||
| 104 | // Second tls_index starts at got[3]. | |
| 105 | // #hi(j@got@tlsgd) --> (0x20108 - 0x280f0) >> 16 = -1 | |
| 106 | // Dis: test_hi: | |
| 107 | // Dis: lis 3, -1 | |
| 108 | ||
| 109 | // Third tls index is at got[5]. | |
| 110 | // k@got@tlsgd --> (0x20118 - 0x280f0) = -0x7fd8 = -32728 | |
| 111 | // Dis: test_16: | |
| 112 | // Dis: li 3, -32728 |
deps/lld/test/ELF/ppc64-got-indirect.s deleted-115| ... | ... | @@ -1,115 +0,0 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 4 | # RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS-LE %s | |
| 5 | # RUN: ld.lld %t.o -o %t2 | |
| 6 | # RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=CHECK-LE | |
| 7 | # RUN: llvm-objdump -D %t2 | FileCheck %s | |
| 8 | ||
| 9 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o | |
| 10 | # RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS-BE %s | |
| 11 | # RUN: ld.lld %t.o -o %t2 | |
| 12 | # RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=CHECK-BE | |
| 13 | # RUN: llvm-objdump -D %t2 | FileCheck %s | |
| 14 | ||
| 15 | # Make sure we calculate the offset correctly for a got-indirect access to a | |
| 16 | # global variable as described by the PPC64 ELF V2 abi. | |
| 17 | .text | |
| 18 | .abiversion 2 | |
| 19 | .globl _start # -- Begin function _start | |
| 20 | .p2align 4 | |
| 21 | .type _start,@function | |
| 22 | _start: # @_start | |
| 23 | .Lfunc_begin0: | |
| 24 | .Lfunc_gep0: | |
| 25 | addis 2, 12, .TOC.-.Lfunc_gep0@ha | |
| 26 | addi 2, 2, .TOC.-.Lfunc_gep0@l | |
| 27 | .Lfunc_lep0: | |
| 28 | .localentry _start, .Lfunc_lep0-.Lfunc_gep0 | |
| 29 | # %bb.0: # %entry | |
| 30 | addis 3, 2, .LC0@toc@ha | |
| 31 | ld 3, .LC0@toc@l(3) | |
| 32 | li 4, 0 | |
| 33 | stw 4, -12(1) | |
| 34 | li 0,1 | |
| 35 | lwa 3, 0(3) | |
| 36 | sc | |
| 37 | .long 0 | |
| 38 | .quad 0 | |
| 39 | .Lfunc_end0: | |
| 40 | .size _start, .Lfunc_end0-.Lfunc_begin0 | |
| 41 | # -- End function | |
| 42 | .section .toc,"aw",@progbits | |
| 43 | .LC0: | |
| 44 | .tc glob[TC],glob | |
| 45 | .type glob,@object # @glob | |
| 46 | .data | |
| 47 | .globl glob | |
| 48 | .p2align 2 | |
| 49 | glob: | |
| 50 | .long 55 # 0x37 | |
| 51 | .size glob, 4 | |
| 52 | ||
| 53 | # Verify the relocations emitted for glob are through the .toc | |
| 54 | ||
| 55 | # RELOCS-LE: Relocations [ | |
| 56 | # RELOCS-LE: .rela.text { | |
| 57 | # RELOCS-LE: 0x0 R_PPC64_REL16_HA .TOC. 0x0 | |
| 58 | # RELOCS-LE: 0x4 R_PPC64_REL16_LO .TOC. 0x4 | |
| 59 | # RELOCS-LE: 0x8 R_PPC64_TOC16_HA .toc 0x0 | |
| 60 | # RELOCS-LE: 0xC R_PPC64_TOC16_LO_DS .toc 0x0 | |
| 61 | # RELOCS-LE: } | |
| 62 | # RELOCS-LE: .rela.toc { | |
| 63 | # RELOCS-LE: 0x0 R_PPC64_ADDR64 glob 0x0 | |
| 64 | # RELOCS-LE: } | |
| 65 | ||
| 66 | # RELOCS-BE: Relocations [ | |
| 67 | # RELOCS-BE: .rela.text { | |
| 68 | # RELOCS-BE: 0x2 R_PPC64_REL16_HA .TOC. 0x2 | |
| 69 | # RELOCS-BE: 0x6 R_PPC64_REL16_LO .TOC. 0x6 | |
| 70 | # RELOCS-BE: 0xA R_PPC64_TOC16_HA .toc 0x0 | |
| 71 | # RELOCS-BE: 0xE R_PPC64_TOC16_LO_DS .toc 0x0 | |
| 72 | # RELOCS-BE: } | |
| 73 | # RELOCS-BE: .rela.toc { | |
| 74 | # RELOCS-BE: 0x0 R_PPC64_ADDR64 glob 0x0 | |
| 75 | # RELOCS-BE: } | |
| 76 | # RELOCS-BE:] | |
| 77 | ||
| 78 | # Verify that the global variable access is done through the correct | |
| 79 | # toc entry: | |
| 80 | # r2 = .TOC. = 0x10038000. | |
| 81 | # r3 = r2 - 32760 = 0x10030008 -> .toc entry for glob. | |
| 82 | ||
| 83 | # CHECK: _start: | |
| 84 | # CHECK-NEXT: 10010000: {{.*}} addis 2, 12, 3 | |
| 85 | # CHECK-NEXT: 10010004: {{.*}} addi 2, 2, -32768 | |
| 86 | # CHECK-NEXT: 10010008: {{.*}} nop | |
| 87 | # CHECK-NEXT: 1001000c: {{.*}} ld 3, -32760(2) | |
| 88 | # CHECK: 1001001c: {{.*}} lwa 3, 0(3) | |
| 89 | ||
| 90 | # CHECK-LE: Disassembly of section .data: | |
| 91 | # CHECK-LE-NEXT: glob: | |
| 92 | # CHECK-LE-NEXT: 10020000: 37 00 00 00 | |
| 93 | ||
| 94 | # CHECK-LE: Disassembly of section .got: | |
| 95 | # CHECK-LE-NEXT: .got: | |
| 96 | # CHECK-LE-NEXT: 10030000: 00 80 03 10 | |
| 97 | # CHECK-LE-NEXT: 10030004: 00 00 00 00 | |
| 98 | ||
| 99 | # Verify that .toc comes right after .got | |
| 100 | # CHECK-LE: Disassembly of section .toc: | |
| 101 | # CHECK-LE: 10030008: 00 00 02 10 | |
| 102 | ||
| 103 | # CHECK-BE: Disassembly of section .data: | |
| 104 | # CHECK-BE-NEXT: glob: | |
| 105 | # CHECK-BE-NEXT: 10020000: 00 00 00 37 | |
| 106 | ||
| 107 | # CHECK-BE: Disassembly of section .got: | |
| 108 | # CHECK-BE-NEXT: .got: | |
| 109 | # CHECK-BE-NEXT: 10030000: 00 00 00 00 | |
| 110 | # CHECK-BE-NEXT: 10030004: 10 03 80 00 | |
| 111 | ||
| 112 | # Verify that .toc comes right after .got | |
| 113 | # CHECK-BE: Disassembly of section .toc: | |
| 114 | # CHECK-BE: 10030008: 00 00 00 00 | |
| 115 | # CHECK-BE: 1003000c: 10 02 00 00 |
deps/lld/test/ELF/ppc64-ifunc.s+46-58| ... | ... | @@ -1,79 +1,67 @@ |
| 1 | 1 | # REQUIRES: ppc |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o |
| 4 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o | |
| 5 | # RUN: ld.lld -shared %t2.o -o %t2.so | |
| 6 | # RUN: ld.lld %t.o %t2.so -o %t | |
| 7 | # RUN: llvm-objdump -D %t | FileCheck %s | |
| 8 | # RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s | |
| 9 | # RUN: llvm-readelf -dyn-relocations %t | FileCheck --check-prefix=DYNREL %s | |
| 4 | # RUN: ld.lld %t.o -o %t | |
| 5 | # RUN: llvm-nm %t | FileCheck --check-prefix=NM %s | |
| 6 | # RUN: llvm-readelf -S %t | FileCheck --check-prefix=SECTIONS %s | |
| 7 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 8 | # RUN: llvm-readelf -r %t | FileCheck --check-prefix=DYNREL %s | |
| 10 | 9 | |
| 11 | 10 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o |
| 12 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o | |
| 13 | # RUN: ld.lld -shared %t2.o -o %t2.so | |
| 14 | # RUN: ld.lld %t.o %t2.so -o %t | |
| 15 | # RUN: llvm-objdump -D %t | FileCheck %s | |
| 16 | # RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s | |
| 17 | # RUN: llvm-readelf -dyn-relocations %t | FileCheck --check-prefix=DYNREL %s | |
| 11 | # RUN: ld.lld %t.o -o %t | |
| 12 | # RUN: llvm-nm %t | FileCheck --check-prefix=NM %s | |
| 13 | # RUN: llvm-readelf -S %t | FileCheck --check-prefix=SECTIONS %s | |
| 14 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 15 | # RUN: llvm-readelf -r %t | FileCheck --check-prefix=DYNREL %s | |
| 18 | 16 | |
| 19 | # CHECK: Disassembly of section .text: | |
| 17 | # NM-DAG: 0000000010028000 d .TOC. | |
| 18 | # NM-DAG: 0000000010010000 T ifunc | |
| 19 | # NM-DAG: 0000000010010004 T ifunc2 | |
| 20 | 20 | |
| 21 | # Tocbase + (0 << 16) + 32560 | |
| 22 | # 0x100280e0 + 0 + 32560 = 0x10030010 (.plt[2]) | |
| 23 | # CHECK: __plt_foo: | |
| 21 | # SECTIONS: .plt NOBITS 0000000010030000 | |
| 22 | ||
| 23 | # __plt_ifunc - . = 0x10010020 - 0x10010010 = 16 | |
| 24 | # __plt_ifunc2 - . = 0x10010044 - 0x10010018 = 28 | |
| 25 | # CHECK: _start: | |
| 26 | # CHECK-NEXT: addis 2, 12, 1 | |
| 27 | # CHECK-NEXT: addi 2, 2, 32760 | |
| 28 | # CHECK-NEXT: 10010010: bl .+16 | |
| 29 | # CHECK-NEXT: ld 2, 24(1) | |
| 30 | # CHECK-NEXT: 10010018: bl .+28 | |
| 31 | # CHECK-NEXT: ld 2, 24(1) | |
| 32 | ||
| 33 | # .plt[0] - .TOC. = 0x10030000 - 0x10028000 = (1<<16) - 32768 | |
| 34 | # CHECK: __plt_ifunc: | |
| 24 | 35 | # CHECK-NEXT: std 2, 24(1) |
| 25 | # CHECK-NEXT: addis 12, 2, 0 | |
| 26 | # CHECK-NEXT: ld 12, 32560(12) | |
| 36 | # CHECK-NEXT: addis 12, 2, 1 | |
| 37 | # CHECK-NEXT: ld 12, -32768(12) | |
| 27 | 38 | # CHECK-NEXT: mtctr 12 |
| 28 | 39 | # CHECK-NEXT: bctr |
| 29 | 40 | |
| 30 | # Tocbase + (0 << 16) + 32568 | |
| 31 | # 0x100280e0 + 0 + 32568 = 0x1003018 (.plt[3]) | |
| 32 | # CHECK: __plt_ifunc: | |
| 41 | # .plt[1] - .TOC. = 0x10030000+8 - 0x10028000 = (1<<16) - 32760 | |
| 42 | # CHECK: __plt_ifunc2: | |
| 33 | 43 | # CHECK-NEXT: std 2, 24(1) |
| 34 | # CHECK-NEXT: addis 12, 2, 0 | |
| 35 | # CHECK-NEXT: ld 12, 32568(12) | |
| 44 | # CHECK-NEXT: addis 12, 2, 1 | |
| 45 | # CHECK-NEXT: ld 12, -32760(12) | |
| 36 | 46 | # CHECK-NEXT: mtctr 12 |
| 37 | 47 | # CHECK-NEXT: bctr |
| 38 | 48 | |
| 39 | # CHECK: ifunc: | |
| 40 | # CHECK-NEXT: 10010028: {{.*}} nop | |
| 41 | ||
| 42 | # CHECK: _start: | |
| 43 | # CHECK-NEXT: addis 2, 12, 2 | |
| 44 | # CHECK-NEXT: addi 2, 2, -32588 | |
| 45 | # CHECK-NEXT: bl .+67108812 | |
| 46 | # CHECK-NEXT: ld 2, 24(1) | |
| 47 | # CHECK-NEXT: bl .+67108824 | |
| 48 | # CHECK-NEXT: ld 2, 24(1) | |
| 49 | ||
| 50 | # Check tocbase | |
| 51 | # CHECK: Disassembly of section .got: | |
| 52 | # CHECK-NEXT: .got: | |
| 53 | # CHECK-NEXT: 100200e0 | |
| 54 | ||
| 55 | # Check .plt address | |
| 56 | # DT_PLTGOT should point to the start of the .plt section. | |
| 57 | # DT: 0x0000000000000003 PLTGOT 0x10030000 | |
| 58 | ||
| 59 | # Check that we emit the correct dynamic relocation type for an ifunc | |
| 60 | # DYNREL: 'PLT' relocation section at offset 0x{{[0-9a-f]+}} contains 48 bytes: | |
| 61 | # 48 bytes --> 2 Elf64_Rela relocations | |
| 62 | # DYNREL-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend | |
| 63 | # DYNREL-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_JMP_SLOT {{0+}} foo + 0 | |
| 64 | # DYNREL-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_IRELATIVE 10010028 | |
| 65 | ||
| 66 | ||
| 67 | .text | |
| 68 | .abiversion 2 | |
| 49 | # Check that we emit 2 R_PPC64_IRELATIVE. | |
| 50 | # DYNREL: R_PPC64_IRELATIVE 10010000 | |
| 51 | # DYNREL: R_PPC64_IRELATIVE 10010004 | |
| 69 | 52 | |
| 70 | 53 | .type ifunc STT_GNU_IFUNC |
| 71 | 54 | .globl ifunc |
| 72 | 55 | ifunc: |
| 73 | nop | |
| 56 | nop | |
| 74 | 57 | |
| 75 | .global _start | |
| 76 | .type _start,@function | |
| 58 | .type ifunc2 STT_GNU_IFUNC | |
| 59 | .globl ifunc2 | |
| 60 | ifunc2: | |
| 61 | nop | |
| 62 | ||
| 63 | .global _start | |
| 64 | .type _start,@function | |
| 77 | 65 | |
| 78 | 66 | _start: |
| 79 | 67 | .Lfunc_gep0: |
| ... | ... | @@ -81,7 +69,7 @@ _start: |
| 81 | 69 | addi 2, 2, .TOC.-.Lfunc_gep0@l |
| 82 | 70 | .Lfunc_lep0: |
| 83 | 71 | .localentry _start, .Lfunc_lep0-.Lfunc_gep0 |
| 84 | bl foo | |
| 85 | nop | |
| 86 | 72 | bl ifunc |
| 87 | 73 | nop |
| 74 | bl ifunc2 | |
| 75 | nop |
deps/lld/test/ELF/ppc64-initial-exec-tls.s deleted-102| ... | ... | @@ -1,102 +0,0 @@ |
| 1 | // REQUIRES: ppc | |
| 2 | ||
| 3 | // RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 4 | // RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o | |
| 5 | // RUN: ld.lld -shared %t2.o -o %t2.so | |
| 6 | // RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.so -o %t | |
| 7 | // RUN: llvm-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s | |
| 8 | // RUN: llvm-readelf -r %t | FileCheck --check-prefix=OutputRelocs %s | |
| 9 | // RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s | |
| 10 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=Dis %s | |
| 11 | ||
| 12 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o | |
| 13 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o | |
| 14 | // RUN: ld.lld -shared %t2.o -o %t2.so | |
| 15 | // RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.so -o %t | |
| 16 | // RUN: llvm-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s | |
| 17 | // RUN: llvm-readelf -r %t | FileCheck --check-prefix=OutputRelocs %s | |
| 18 | // RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s | |
| 19 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=Dis %s | |
| 20 | ||
| 21 | 	.text | |
| 22 | 	.abiversion 2 | |
| 23 | 	.file	"intial_exec.c" | |
| 24 | 	.globl	test_initial_exec # -- Begin function test_initial_exec | |
| 25 | 	.p2align	4 | |
| 26 | 	.type	test_initial_exec,@function | |
| 27 | test_initial_exec: # @test_initial_exec | |
| 28 | .Lfunc_begin0: | |
| 29 | .Lfunc_gep0: | |
| 30 | 	addis 2, 12, .TOC.-.Lfunc_gep0@ha | |
| 31 | 	addi 2, 2, .TOC.-.Lfunc_gep0@l | |
| 32 | .Lfunc_lep0: | |
| 33 | 	.localentry	test_initial_exec, .Lfunc_lep0-.Lfunc_gep0 | |
| 34 | # %bb.0: # %entry | |
| 35 | 	li 3, 0 | |
| 36 | 	stw 3, -12(1) | |
| 37 | 	addis 3, 2, a@got@tprel@ha | |
| 38 | 	ld 3, a@got@tprel@l(3) | |
| 39 | 	lwzx 4, 3, a@tls | |
| 40 | 	extsw 3, 4 | |
| 41 | 	blr | |
| 42 | ||
| 43 | ||
| 44 | test_hi: | |
| 45 | .Lfunc_gep1: | |
| 46 | addis 2, 12, .TOC.-.Lfunc_gep1@ha | |
| 47 | addi 2, 2, .TOC.-.Lfunc_gep1@l | |
| 48 | .Lfunc_lep1: | |
| 49 | .localentry test2, .Lfunc_lep1-.Lfunc_gep1 | |
| 50 | addis 3, 0, b@got@tprel@h | |
| 51 | blr | |
| 52 | ||
| 53 | test_ds: | |
| 54 | .Lfunc_gep2: | |
| 55 | addis 2, 12, .TOC.-.Lfunc_gep2@ha | |
| 56 | addi 2, 2, .TOC.-.Lfunc_gep2@l | |
| 57 | .Lfunc_lep2: | |
| 58 | .localentry test16, .Lfunc_lep2-.Lfunc_gep2 | |
| 59 | addi 3, 0, c@got@tprel | |
| 60 | blr | |
| 61 | ||
| 62 | // Verify that the input has every initial-exec tls relocation type. | |
| 63 | // InputRelocs: Relocation section '.rela.text' | |
| 64 | // InputRelocs: R_PPC64_GOT_TPREL16_HA {{0+}} a + 0 | |
| 65 | // InputRelocs: R_PPC64_GOT_TPREL16_LO_DS {{0+}} a + 0 | |
| 66 | // InputRelocs: R_PPC64_TLS {{0+}} a + 0 | |
| 67 | // InputRelocs: R_PPC64_GOT_TPREL16_HI {{0+}} b + 0 | |
| 68 | // InputRelocs: R_PPC64_GOT_TPREL16_DS {{0+}} c + 0 | |
| 69 | ||
| 70 | // There is a got entry for each tls variable that is accessed with the | |
| 71 | // initial-exec model to be filled in by the dynamic linker. | |
| 72 | // OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 3 entries: | |
| 73 | // OutputRelocs: R_PPC64_TPREL64 {{0+}} a + 0 | |
| 74 | // OutputRelocs: R_PPC64_TPREL64 {{0+}} b + 0 | |
| 75 | // OutputRelocs: R_PPC64_TPREL64 {{0+}} c + 0 | |
| 76 | ||
| 77 | // Check that the got has 4 entires. (1 for the TOC and 3 entries for TLS | |
| 78 | // variables). Also verify the address so we can check | |
| 79 | // the offsets we calculated for each relocation type. | |
| 80 | // CheckGot: got 00000020 00000000100200c0 | |
| 81 | ||
| 82 | // GOT stats at 0x100200c0, so TOC will be 0x100280c0 | |
| 83 | ||
| 84 | // We are building the address of the first TLS got entry which contains the | |
| 85 | // offset of the tls variable relative to the thread pointer. | |
| 86 | // 0x100200c8 (got[1]). | |
| 87 | // #ha(a@got@tprel) --> (0x100200c8 - 0x100280c0 + 0x8000) >> 16 = 0 | |
| 88 | // #lo(a@got@tprel)) --> (0x100200c8 - 0x100280c0) & 0xFFFF = -7ff8 = -32760 | |
| 89 | // Dis: test_initial_exec: | |
| 90 | // Dis: addis 3, 2, 0 | |
| 91 | // Dis: ld 3, -32760(3) | |
| 92 | // Dis: lwzx 4, 3, 13 | |
| 93 | ||
| 94 | // Second TLS got entry starts at got[2] 0x100200d0 | |
| 95 | // #hi(b@got@tprel) --> (0x100200d0 - 0x100280c0) >> 16 = -1 | |
| 96 | // Dis: test_hi: | |
| 97 | // Dis: lis 3, -1 | |
| 98 | ||
| 99 | // Third TLS got entry starts at got[3] 0x100200d8. | |
| 100 | // c@got@tprel--> (0x100200d8. - 0x100280c0) = -0x7fe8 = 32744 | |
| 101 | // Dis: test_ds: | |
| 102 | // Dis: li 3, -32744 |
deps/lld/test/ELF/ppc64-ld-got-dtprel.s created+44| ... | ... | @@ -0,0 +1,44 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le %s -o %t.o | |
| 4 | # RUN: llvm-readobj -r %t.o | FileCheck --check-prefix=RELOCS %s | |
| 5 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 6 | # RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck %s | |
| 7 | ## Check LD->LE relaxation does not affect R_PPC64_GOT_DTPREL16*. | |
| 8 | # RUN: ld.lld %t.o -o %t | |
| 9 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 10 | ||
| 11 | # RUN: llvm-mc -filetype=obj -triple=powerpc64 %s -o %t.o | |
| 12 | # RUN: llvm-readobj -r %t.o | FileCheck --check-prefix=RELOCS %s | |
| 13 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 14 | # RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck %s | |
| 15 | # RUN: ld.lld %t.o -o %t | |
| 16 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 17 | ||
| 18 | # RELOCS: .rela.text { | |
| 19 | # RELOCS-NEXT: R_PPC64_GOT_DTPREL16_HA i 0x0 | |
| 20 | # RELOCS-NEXT: R_PPC64_GOT_DTPREL16_LO_DS i 0x0 | |
| 21 | # RELOCS-NEXT: R_PPC64_GOT_DTPREL16_HI j 0x0 | |
| 22 | # RELOCS-NEXT: R_PPC64_GOT_DTPREL16_DS j 0x0 | |
| 23 | # RELOCS-NEXT: } | |
| 24 | ||
| 25 | ## ha(i@got@dtprel) = (&.got[0] - (.got+0x8000) + 0x8000 >> 16) & 0xffff = 0 | |
| 26 | ## lo(i@got@dtprel) = &.got[0] - (.got+0x8000) & 0xffff = -32768 | |
| 27 | ## hi(j@got@dtprel) = (&.got[1] - (.got+0x8000) >> 16) & 0xffff = -1 | |
| 28 | ## j@got@dtprel = &.got[1] - (.got+0x8000) = -32760 | |
| 29 | # CHECK: addis 3, 2, 0 | |
| 30 | # CHECK-NEXT: ld 3, -32768(3) | |
| 31 | # CHECK-NEXT: addis 3, 2, -1 | |
| 32 | # CHECK-NEXT: addi 3, 2, -32760 | |
| 33 | ||
| 34 | addis 3, 2, i@got@dtprel@ha | |
| 35 | ld 3, i@got@dtprel@l(3) | |
| 36 | addis 3, 2, j@got@dtprel@h | |
| 37 | addi 3, 2, j@got@dtprel | |
| 38 | ||
| 39 | .section .tbss,"awT",@progbits | |
| 40 | .p2align 2 | |
| 41 | i: | |
| 42 | .long 0 | |
| 43 | j: | |
| 44 | .long 0 |
deps/lld/test/ELF/ppc64-local-dynamic.s+1-1| ... | ... | @@ -113,7 +113,7 @@ k: |
| 113 | 113 | // Dis: test: |
| 114 | 114 | // Dis: addis 3, 2, 0 |
| 115 | 115 | // Dis-NEXT: addi 3, 3, -32760 |
| 116 | // Dis-NEXT: bl .+67108804 | |
| 116 | // Dis-NEXT: bl .+60 | |
| 117 | 117 | // Dis-NEXT: ld 2, 24(1) |
| 118 | 118 | // Dis-NEXT: addis 3, 3, 0 |
| 119 | 119 | // Dis-NEXT: lwa 3, -32768(3) |
deps/lld/test/ELF/ppc64-local-entry.s created+47| ... | ... | @@ -0,0 +1,47 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64 %s -o %t | |
| 4 | # RUN: ld.lld -r %t -o %t2 | |
| 5 | # RUN: llvm-objdump -s -section=.symtab %t2 | FileCheck %s | |
| 6 | ||
| 7 | .text | |
| 8 | .abiversion 2 | |
| 9 | .globl _start | |
| 10 | .p2align	2 | |
| 11 | .type _start,@function | |
| 12 | ||
| 13 | _start: | |
| 14 | .Lfunc_begin0: | |
| 15 | .Lfunc_gep0: | |
| 16 | 	addis 2, 12, .TOC.-.Lfunc_gep0@ha | |
| 17 | 	addi 2, 2, .TOC.-.Lfunc_gep0@l | |
| 18 | .Lfunc_lep0: | |
| 19 | 	.localentry	_start, .Lfunc_lep0-.Lfunc_gep0 | |
| 20 | 	# The code below is not important, it just needs to access some | |
| 21 | 	# global data or function, in order to use the TOC. | |
| 22 | 	# In this case, it performs the following: | |
| 23 | 	# g += 10; | |
| 24 | 	# Also note that this code is not intended to be run, but only | |
| 25 | 	# to check if the linker will preserve the localentry info. | |
| 26 | 	addis 3, 2, g@toc@ha | |
| 27 | 	addi 3, 3, g@toc@l | |
| 28 | 	lwz 4, 0(3) | |
| 29 | 	addi 4, 4, 10 | |
| 30 | 	stw 4, 0(3) | |
| 31 | 	blr | |
| 32 | 	.long	0 | |
| 33 | 	.quad	0 | |
| 34 | .Lfunc_end0: | |
| 35 | 	.size _start, .Lfunc_end0-.Lfunc_begin0 | |
| 36 | ||
| 37 | 	.type	g,@object # @g | |
| 38 | 	.lcomm	g,4,4 | |
| 39 | ||
| 40 | // We expect the st_other byte to be 0x60: | |
| 41 | // localentry = 011 (gep + 2 instructions), reserved = 000, | |
| 42 | // visibility = 00 (STV_DEFAULT) | |
| 43 | // Currently, llvm-objdump does not support displaying | |
| 44 | // st_other's PPC64 specific flags, thus we check the | |
| 45 | // result of the hexdump of .symtab section. | |
| 46 | ||
| 47 | // CHECK: 0070 00000000 00000000 00000009 12600001 |
deps/lld/test/ELF/ppc64-long-branch-init.s created+44| ... | ... | @@ -0,0 +1,44 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-pc-freebsd13.0 %s -o %t.o | |
| 4 | # RUN: ld.lld %t.o -o %t | |
| 5 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 6 | ||
| 7 | ## .init consists of sections from several object files. Sections other than the | |
| 8 | ## last one do not have a terminator. Check we do not create a long branch stub | |
| 9 | ## in the middle. | |
| 10 | ## We currently use thunk section spacing to ensure the stub is in the end. This | |
| 11 | ## is not foolproof but good enough to not break in practice. | |
| 12 | ||
| 13 | # CHECK: Disassembly of section .init: | |
| 14 | # CHECK-EMPTY: | |
| 15 | # CHECK-LABEL: _init: | |
| 16 | # CHECK: blr | |
| 17 | # CHECK-EMPTY: | |
| 18 | # CHECK-LABEL: __long_branch_foo: | |
| 19 | ||
| 20 | .globl foo | |
| 21 | foo: | |
| 22 | .space 0x2000000 | |
| 23 | blr | |
| 24 | ||
| 25 | .section .init,"ax",@progbits,unique,0 | |
| 26 | .globl _init | |
| 27 | _init: | |
| 28 | stdu 1, -48(1) | |
| 29 | mflr 0 | |
| 30 | std 0, 64(1) | |
| 31 | ||
| 32 | .section .init,"ax",@progbits,unique,1 | |
| 33 | bl foo | |
| 34 | nop | |
| 35 | ||
| 36 | .section .init,"ax",@progbits,unique,2 | |
| 37 | bl foo | |
| 38 | nop | |
| 39 | ||
| 40 | .section .init,"ax",@progbits,unique,3 | |
| 41 | ld 1, 0(1) | |
| 42 | ld 0, 16(1) | |
| 43 | mtlr 0 | |
| 44 | blr |
deps/lld/test/ELF/ppc64-long-branch-localentry-offset.s created+30| ... | ... | @@ -0,0 +1,30 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=ppc64le %s -o %t.o | |
| 4 | # RUN: ld.lld %t.o -o %t | |
| 5 | # RUN: llvm-nm %t | FileCheck %s | |
| 6 | ||
| 7 | # CHECK-DAG: 0000000010010000 t __long_branch_callee | |
| 8 | # CHECK-DAG: 0000000010010010 T _start | |
| 9 | # CHECK-DAG: 0000000012010008 T callee | |
| 10 | ||
| 11 | # The bl instruction jumps to the local entry. The distance requires a long branch stub: | |
| 12 | # localentry(callee) - _start = 0x12010008+8 - 0x10010010 = 0x2000000 | |
| 13 | ||
| 14 | # We used to compute globalentry(callee) - _start and caused a "R_PPC64_REL24 | |
| 15 | # out of range" error because we didn't create the stub. | |
| 16 | ||
| 17 | .globl _start | |
| 18 | _start: | |
| 19 | bl callee | |
| 20 | ||
| 21 | .space 0x1fffff4 | |
| 22 | ||
| 23 | .globl callee | |
| 24 | callee: | |
| 25 | .Lgep0: | |
| 26 | addis 2, 12, .TOC.-.Lgep0@ha | |
| 27 | addi 2, 2, .TOC.-.Lgep0@l | |
| 28 | .Llep0: | |
| 29 | .localentry callee, .Llep0-.Lgep0 | |
| 30 | blr |
deps/lld/test/ELF/ppc64-long-branch.s+37-64| ... | ... | @@ -1,22 +1,16 @@ |
| 1 | 1 | # REQUIRES: ppc |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o |
| 4 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func-global-entry.s -o %t2.o | |
| 5 | # RUN: ld.lld -shared %t2.o -o %t3.so | |
| 6 | # RUN: ld.lld --no-toc-optimize %t.o %t3.so -o %t | |
| 7 | # RUN: llvm-objdump -d -start-address=0x10010000 -stop-address=0x10010018 %t | FileCheck %s -check-prefix=CALLEE_DUMP | |
| 8 | # RUN: llvm-objdump -d -start-address=0x12010020 -stop-address=0x12010084 %t | FileCheck %s -check-prefix=CALLER_DUMP | |
| 9 | # RUN: llvm-objdump -D -start-address=0x12020008 -stop-address=0x12020010 %t | FileCheck %s -check-prefix=BRANCH_LT_LE | |
| 10 | # RUN: llvm-readelf --sections %t | FileCheck %s -check-prefix=SECTIONS | |
| 4 | # RUN: ld.lld --no-toc-optimize %t.o -o %t | |
| 5 | # RUN: llvm-nm %t | FileCheck --check-prefix=NM %s | |
| 6 | # RUN: llvm-readelf -x .branch_lt %t | FileCheck %s -check-prefix=BRANCH-LE | |
| 7 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 11 | 8 | |
| 12 | 9 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o |
| 13 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-func-global-entry.s -o %t2.o | |
| 14 | # RUN: ld.lld -shared %t2.o -o %t3.so | |
| 15 | # RUN: ld.lld --no-toc-optimize %t.o %t3.so -o %t | |
| 16 | # RUN: llvm-objdump -d -start-address=0x10010000 -stop-address=0x10010018 %t | FileCheck %s -check-prefix=CALLEE_DUMP | |
| 17 | # RUN: llvm-objdump -d -start-address=0x12010020 -stop-address=0x12010084 %t | FileCheck %s -check-prefix=CALLER_DUMP | |
| 18 | # RUN: llvm-objdump -D -start-address=0x12020008 -stop-address=0x12020010 %t | FileCheck %s -check-prefix=BRANCH_LT_BE | |
| 19 | # RUN: llvm-readelf --sections %t | FileCheck %s -check-prefix=SECTIONS | |
| 10 | # RUN: ld.lld --no-toc-optimize %t.o -o %t | |
| 11 | # RUN: llvm-nm %t | FileCheck --check-prefix=NM %s | |
| 12 | # RUN: llvm-readelf -x .branch_lt %t | FileCheck %s -check-prefix=BRANCH-BE | |
| 13 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 20 | 14 | |
| 21 | 15 | .text |
| 22 | 16 | .abiversion 2 |
| ... | ... | @@ -52,24 +46,14 @@ _start: |
| 52 | 46 | std 0, 16(1) |
| 53 | 47 | stdu 1, -32(1) |
| 54 | 48 | bl callee |
| 55 | bl foo_external_diff | |
| 56 | nop | |
| 49 | bl callee | |
| 57 | 50 | addi 1, 1, 32 |
| 58 | 51 | ld 0, 16(1) |
| 59 | 52 | mtlr 0 |
| 60 | 53 | |
| 61 | addis 4, 2, .LC1@toc@ha | |
| 62 | ld 4, .LC1@toc@l(4) | |
| 63 | lwz 4, 0(4) | |
| 64 | add 3, 3, 4 | |
| 65 | blr | |
| 66 | ||
| 67 | ||
| 68 | 54 | .section .toc,"aw",@progbits |
| 69 | 55 | .LC0: |
| 70 | 56 | .tc a[TC],a |
| 71 | .LC1: | |
| 72 | .tc b[TC],b | |
| 73 | 57 | |
| 74 | 58 | |
| 75 | 59 | .data |
| ... | ... | @@ -80,42 +64,31 @@ a: |
| 80 | 64 | .long 11 |
| 81 | 65 | .size a, 4 |
| 82 | 66 | |
| 83 | .type b,@object | |
| 84 | .global b | |
| 85 | .p2align 2 | |
| 86 | b: | |
| 87 | .long 33 | |
| 88 | .size b, 4 | |
| 89 | ||
| 90 | # Verify address of the callee | |
| 91 | # CALLEE_DUMP: callee: | |
| 92 | # CALLEE_DUMP: 10010000: {{.*}} addis 2, 12, 515 | |
| 93 | # CALLEE_DUMP: 10010004: {{.*}} addi 2, 2, -32544 | |
| 94 | # CALLEE_DUMP: 10010008: {{.*}} addis 4, 2, 0 | |
| 95 | ||
| 96 | # Verify the address of _start, and the call to the long-branch thunk. | |
| 97 | # CALLER_DUMP: _start: | |
| 98 | # CALLER_DUMP: 12010020: {{.*}} addis 2, 12, 3 | |
| 99 | # CALLER_DUMP: 12010038: {{.*}} bl .+56 | |
| 100 | ||
| 101 | # Verify the thunks contents: TOC-pointer + offset = .branch_lt[0] | |
| 102 | # 0x120380e8 + (-2 << 16 + 32552) = 0x12020008 | |
| 103 | # CALLER_DUMP: __long_branch_callee: | |
| 104 | # CALLER_DUMP: 12010060: {{.*}} addis 12, 2, -2 | |
| 105 | # CALLER_DUMP: 12010064: {{.*}} ld 12, 32552(12) | |
| 106 | # CALLER_DUMP: 12010068: {{.*}} mtctr 12 | |
| 107 | # CALLER_DUMP: 1201006c: {{.*}} bctr | |
| 108 | ||
| 109 | # BRANCH_LT_LE: Disassembly of section .branch_lt: | |
| 110 | # BRANCH_LT_LE-NEXT: .branch_lt: | |
| 111 | # BRANCH_LT_LE-NEXT: 12020008: 08 00 01 10 | |
| 112 | # BRANCH_LT_LE-NEXT: 1202000c: 00 00 00 00 | |
| 113 | ||
| 114 | # BRANCH_LT_BE: Disassembly of section .branch_lt: | |
| 115 | # BRANCH_LT_BE-NEXT: .branch_lt: | |
| 116 | # BRANCH_LT_BE-NEXT: 12020008: 00 00 00 00 | |
| 117 | # BRANCH_LT_BE-NEXT: 1202000c: 10 01 00 08 | |
| 118 | ||
| 119 | # [Nr] Name Type Address Off Size | |
| 120 | # SECTIONS: [ 9] .branch_lt PROGBITS 0000000012020008 2020008 000008 | |
| 121 | # SECTIONS: [11] .got PROGBITS 00000000120300e0 20300e0 000008 | |
| 67 | # NM: 0000000012028000 d .TOC. | |
| 68 | ||
| 69 | # Without --toc-optimize, compute the address of .toc[0] first. .toc[0] stores | |
| 70 | # the address of a. | |
| 71 | # .TOC. - callee = 0x12030000 - 0x10010000 = (514<<16) - 32768 | |
| 72 | # CHECK: callee: | |
| 73 | # CHECK: 10010000: addis 2, 12, 514 | |
| 74 | # CHECK: 10010004: addi 2, 2, -32768 | |
| 75 | # CHECK: 10010008: addis 4, 2, 0 | |
| 76 | ||
| 77 | # __long_branch_callee - . = 0x12010050 - 0x12010034 = 20 | |
| 78 | # __long_branch_callee is not a PLT call stub. Calling it does not need TOC | |
| 79 | # restore, so it doesn't have to be followed by a nop. | |
| 80 | # CHECK: _start: | |
| 81 | # CHECK: 12010034: bl .+20 | |
| 82 | # CHECK: 12010038: bl .+16 | |
| 83 | ||
| 84 | # BRANCH-LE: section '.branch_lt': | |
| 85 | # BRANCH-LE-NEXT: 0x12030008 08000110 00000000 | |
| 86 | # BRANCH-BE: section '.branch_lt': | |
| 87 | # BRANCH-BE-NEXT: 0x12030008 00000000 10010008 | |
| 88 | ||
| 89 | # .branch_lt - .TOC. = 0x12030008 - 0x12028000 = (1<<16) - 32760 | |
| 90 | # CHECK: __long_branch_callee: | |
| 91 | # CHECK-NEXT: 12010048: addis 12, 2, 1 | |
| 92 | # CHECK-NEXT: ld 12, -32760(12) | |
| 93 | # CHECK-NEXT: mtctr 12 | |
| 94 | # CHECK-NEXT: bctr |
deps/lld/test/ELF/ppc64-plt-stub.s+36-25| ... | ... | @@ -1,28 +1,39 @@ |
| 1 | // REQUIRES: ppc | |
| 2 | ||
| 3 | // RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 4 | // RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o | |
| 5 | // RUN: ld.lld -shared %t2.o -o %t2.so | |
| 6 | // RUN: ld.lld %t.o %t2.so -o %t | |
| 7 | // RUN: llvm-objdump -d %t | FileCheck %s | |
| 8 | ||
| 9 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o | |
| 10 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o | |
| 11 | // RUN: ld.lld -shared %t2.o -o %t2.so | |
| 12 | // RUN: ld.lld %t.o %t2.so -o %t | |
| 13 | // RUN: llvm-objdump -d %t | FileCheck %s | |
| 14 | ||
| 15 | // CHECK: Disassembly of section .text: | |
| 16 | // CHECK-NEXT: __plt_foo: | |
| 17 | // CHECK-NEXT: std 2, 24(1) | |
| 18 | // CHECK-NEXT: addis 12, 2, 0 | |
| 19 | // CHECK-NEXT: ld 12, 32560(12) | |
| 20 | // CHECK-NEXT: mtctr 12 | |
| 21 | // CHECK-NEXT: bctr | |
| 22 | ||
| 23 | ||
| 24 | // CHECK: _start: | |
| 25 | // CHECK: bl .+67108824 | |
| 1 | # REQUIRES: ppc | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o | |
| 5 | # RUN: ld.lld -shared %t2.o -soname=t2.so -o %t2.so | |
| 6 | # RUN: ld.lld %t.o %t2.so -o %t | |
| 7 | # RUN: llvm-readelf -S -d %t | FileCheck --check-prefix=SEC %s | |
| 8 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 9 | ||
| 10 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o | |
| 11 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o | |
| 12 | # RUN: ld.lld -shared %t2.o -soname=t2.so -o %t2.so | |
| 13 | # RUN: ld.lld %t.o %t2.so -o %t | |
| 14 | # RUN: llvm-readelf -S -d %t | FileCheck --check-prefix=SEC %s | |
| 15 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 16 | ||
| 17 | ## DT_PLTGOT points to .plt | |
| 18 | # SEC: .plt NOBITS 0000000010030000 030000 000018 | |
| 19 | # SEC: 0x0000000000000003 (PLTGOT) 0x10030000 | |
| 20 | ||
| 21 | ## .plt[0] holds the address of _dl_runtime_resolve. | |
| 22 | ## .plt[1] holds the link map. | |
| 23 | ## The JMP_SLOT relocation is stored at .plt[2] | |
| 24 | # RELOC: 0x10030010 R_PPC64_JMP_SLOT foo 0x0 | |
| 25 | ||
| 26 | # CHECK: _start: | |
| 27 | # CHECK: 10010008: bl .+16 | |
| 28 | ||
| 29 | # CHECK-LABEL: 0000000010010018 __plt_foo: | |
| 30 | # CHECK-NEXT: std 2, 24(1) | |
| 31 | # CHECK-NEXT: addis 12, 2, 0 | |
| 32 | # CHECK-NEXT: ld 12, 32560(12) | |
| 33 | # CHECK-NEXT: mtctr 12 | |
| 34 | # CHECK-NEXT: bctr | |
| 35 | ||
| 36 | ||
| 26 | 37 | .text |
| 27 | 38 | .abiversion 2 |
| 28 | 39 | .globl _start |
deps/lld/test/ELF/ppc64-rel-calls.s+3-3| ... | ... | @@ -9,6 +9,7 @@ |
| 9 | 9 | # RUN: llvm-objdump -d %t2 | FileCheck %s |
| 10 | 10 | |
| 11 | 11 | # CHECK: Disassembly of section .text: |
| 12 | # CHECK-EMPTY: | |
| 12 | 13 | |
| 13 | 14 | .text |
| 14 | 15 | .global _start |
| ... | ... | @@ -30,9 +31,8 @@ bar: |
| 30 | 31 | nop |
| 31 | 32 | blr |
| 32 | 33 | |
| 33 | # FIXME: The printing here is misleading, the branch offset here is negative. | |
| 34 | # CHECK: 1001000c: {{.*}} bl .+67108852 | |
| 34 | # CHECK: 1001000c: {{.*}} bl .-12 | |
| 35 | 35 | # CHECK: 10010010: {{.*}} nop |
| 36 | # CHECK: 10010014: {{.*}} bl .+67108844 | |
| 36 | # CHECK: 10010014: {{.*}} bl .-20 | |
| 37 | 37 | # CHECK: 10010018: {{.*}} nop |
| 38 | 38 | # CHECK: 1001001c: {{.*}} blr |
deps/lld/test/ELF/ppc64-reloc-addr.s created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le %s -o %t.o | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le %S/Inputs/abs255.s -o %t255.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le %S/Inputs/abs256.s -o %t256.o | |
| 5 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le %S/Inputs/abs257.s -o %t257.o | |
| 6 | ||
| 7 | # RUN: ld.lld %t.o %t256.o -o %t | |
| 8 | # RUN: llvm-readelf -x .data %t | FileCheck %s | |
| 9 | # CHECK: 0x{{[0-9a-f]+}} ffff0080 ffffffff 00000080 | |
| 10 | ||
| 11 | # RUN: not ld.lld %t.o %t255.o -o /dev/null 2>&1 | FileCheck --check-prefix=OVERFLOW1 %s | |
| 12 | # OVERFLOW1: relocation R_PPC64_ADDR16 out of range: -32769 is not in [-32768, 65535] | |
| 13 | # OVERFLOW1: relocation R_PPC64_ADDR32 out of range: -2147483649 is not in [-2147483648, 4294967295] | |
| 14 | ||
| 15 | # RUN: not ld.lld %t.o %t257.o -o /dev/null 2>&1 | FileCheck --check-prefix=OVERFLOW2 %s | |
| 16 | # OVERFLOW2: relocation R_PPC64_ADDR16 out of range: 65536 is not in [-32768, 65535] | |
| 17 | # OVERFLOW2: relocation R_PPC64_ADDR32 out of range: 4294967296 is not in [-2147483648, 4294967295] | |
| 18 | ||
| 19 | .globl _start | |
| 20 | _start: | |
| 21 | .data | |
| 22 | .word foo + 0xfeff | |
| 23 | .word foo - 0x8100 | |
| 24 | .long foo + 0xfffffeff | |
| 25 | .long foo - 0x80000100 |
deps/lld/test/ELF/ppc64-relocs.s+66-106| ... | ... | @@ -1,14 +1,14 @@ |
| 1 | 1 | # REQUIRES: ppc |
| 2 | 2 | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t | |
| 4 | # RUN: ld.lld %t -o %t2 | |
| 5 | # RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=DATALE | |
| 6 | # RUN: llvm-objdump -D %t2 | FileCheck %s | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 4 | # RUN: ld.lld --no-toc-optimize %t.o -o %t | |
| 5 | # RUN: llvm-readelf -x .rodata -x .R_PPC64_TOC -x .eh_frame %t | FileCheck %s --check-prefix=DATALE | |
| 6 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 7 | 7 | |
| 8 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t | |
| 9 | # RUN: ld.lld %t -o %t2 | |
| 10 | # RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=DATABE | |
| 11 | # RUN: llvm-objdump -D %t2 | FileCheck %s | |
| 8 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o | |
| 9 | # RUN: ld.lld --no-toc-optimize %t.o -o %t | |
| 10 | # RUN: llvm-readelf -x .rodata -x .R_PPC64_TOC -x .eh_frame %t | FileCheck %s --check-prefix=DATABE | |
| 11 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 12 | 12 | |
| 13 | 13 | .text |
| 14 | 14 | .global _start |
| ... | ... | @@ -30,154 +30,106 @@ _start: |
| 30 | 30 | .tc .LJTI0_0[TC],.LJTI0_0 |
| 31 | 31 | |
| 32 | 32 | .section .R_PPC64_TOC16_LO_DS,"ax",@progbits |
| 33 | .globl .FR_PPC64_TOC16_LO_DS | |
| 34 | .FR_PPC64_TOC16_LO_DS: | |
| 35 | 33 | ld 1, .L1@toc@l(2) |
| 36 | 34 | |
| 37 | # CHECK: Disassembly of section .R_PPC64_TOC16_LO_DS: | |
| 38 | # CHECK: .FR_PPC64_TOC16_LO_DS: | |
| 39 | # CHECK: 1001000c: {{.*}} ld 1, -32768(2) | |
| 35 | # CHECK-LABEL: Disassembly of section .R_PPC64_TOC16_LO_DS: | |
| 36 | # CHECK: 1001000c: ld 1, -32768(2) | |
| 40 | 37 | |
| 41 | 38 | .section .R_PPC64_TOC16_LO,"ax",@progbits |
| 42 | .globl .FR_PPC64_TOC16_LO | |
| 43 | .FR_PPC64_TOC16_LO: | |
| 44 | 39 | addi 1, 2, .L1@toc@l |
| 45 | 40 | |
| 46 | # CHECK: Disassembly of section .R_PPC64_TOC16_LO: | |
| 47 | # CHECK: .FR_PPC64_TOC16_LO: | |
| 48 | # CHECK: 10010010: {{.*}} addi 1, 2, -32768 | |
| 41 | # CHECK-LABEL: Disassembly of section .R_PPC64_TOC16_LO: | |
| 42 | # CHECK: 10010010: addi 1, 2, -32768 | |
| 49 | 43 | |
| 50 | 44 | .section .R_PPC64_TOC16_HI,"ax",@progbits |
| 51 | .globl .FR_PPC64_TOC16_HI | |
| 52 | .FR_PPC64_TOC16_HI: | |
| 53 | 45 | addis 1, 2, .L1@toc@h |
| 54 | 46 | |
| 55 | # CHECK: Disassembly of section .R_PPC64_TOC16_HI: | |
| 56 | # CHECK: .FR_PPC64_TOC16_HI: | |
| 57 | # CHECK: 10010014: {{.*}} addis 1, 2, -1 | |
| 47 | # CHECK-LABEL: Disassembly of section .R_PPC64_TOC16_HI: | |
| 48 | # CHECK: 10010014: addis 1, 2, -1 | |
| 58 | 49 | |
| 59 | 50 | .section .R_PPC64_TOC16_HA,"ax",@progbits |
| 60 | .globl .FR_PPC64_TOC16_HA | |
| 61 | .FR_PPC64_TOC16_HA: | |
| 62 | 51 | addis 1, 2, .L1@toc@ha |
| 63 | 52 | |
| 64 | # CHECK: Disassembly of section .R_PPC64_TOC16_HA: | |
| 65 | # CHECK: .FR_PPC64_TOC16_HA: | |
| 66 | # CHECK: 10010018: {{.*}} nop | |
| 53 | # CHECK-LABEL: Disassembly of section .R_PPC64_TOC16_HA: | |
| 54 | # CHECK: 10010018: addis 1, 2, 0 | |
| 67 | 55 | |
| 68 | 56 | .section .R_PPC64_REL24,"ax",@progbits |
| 69 | .globl .FR_PPC64_REL24 | |
| 70 | .FR_PPC64_REL24: | |
| 71 | b .Lfoox | |
| 72 | .section .R_PPC64_REL24_2,"ax",@progbits | |
| 73 | .Lfoox: | |
| 57 | b 1f | |
| 58 | 1: | |
| 74 | 59 | |
| 75 | # CHECK: Disassembly of section .R_PPC64_REL24: | |
| 76 | # CHECK: .FR_PPC64_REL24: | |
| 77 | # CHECK: 1001001c: {{.*}} b .+4 | |
| 60 | # CHECK-LABEL: Disassembly of section .R_PPC64_REL24: | |
| 61 | # CHECK: 1001001c: b .+4 | |
| 78 | 62 | |
| 79 | 63 | .section .R_PPC64_REL14,"ax",@progbits |
| 80 | .globl .FR_PPC64_REL14 | |
| 81 | .FR_PPC64_REL14: | |
| 82 | beq .Lfooy | |
| 83 | .section .R_PPC64_REL14_2,"ax",@progbits | |
| 84 | .Lfooy: | |
| 64 | beq 1f | |
| 65 | 1: | |
| 85 | 66 | |
| 86 | # CHECK: Disassembly of section .R_PPC64_REL14: | |
| 87 | # CHECK: .FR_PPC64_REL14: | |
| 88 | # CHECK: 10010020: {{.*}} bt 2, .+4 | |
| 67 | # CHECK-LABEL: Disassembly of section .R_PPC64_REL14: | |
| 68 | # CHECK: 10010020: bt 2, .+4 | |
| 89 | 69 | |
| 90 | 70 | .section .R_PPC64_ADDR16_LO,"ax",@progbits |
| 91 | .globl .FR_PPC64_ADDR16_LO | |
| 92 | .FR_PPC64_ADDR16_LO: | |
| 93 | 71 | li 1, .Lfoo@l |
| 94 | 72 | |
| 95 | # CHECK: Disassembly of section .R_PPC64_ADDR16_LO: | |
| 96 | # CHECK: .FR_PPC64_ADDR16_LO: | |
| 97 | # CHECK: 10010024: {{.*}} li 1, 0 | |
| 73 | # CHECK-LABEL: Disassembly of section .R_PPC64_ADDR16_LO: | |
| 74 | # CHECK: 10010024: li 1, 0 | |
| 98 | 75 | |
| 99 | 76 | .section .R_PPC64_ADDR16_HI,"ax",@progbits |
| 100 | .globl .FR_PPC64_ADDR16_HI | |
| 101 | .FR_PPC64_ADDR16_HI: | |
| 102 | 77 | li 1, .Lfoo@h |
| 103 | 78 | |
| 104 | # CHECK: Disassembly of section .R_PPC64_ADDR16_HI: | |
| 105 | # CHECK: .FR_PPC64_ADDR16_HI: | |
| 106 | # CHECK: 10010028: {{.*}} li 1, 4097 | |
| 79 | # CHECK-LABEL: Disassembly of section .R_PPC64_ADDR16_HI: | |
| 80 | # CHECK: 10010028: li 1, 4097 | |
| 107 | 81 | |
| 108 | 82 | .section .R_PPC64_ADDR16_HA,"ax",@progbits |
| 109 | .globl .FR_PPC64_ADDR16_HA | |
| 110 | .FR_PPC64_ADDR16_HA: | |
| 111 | 83 | li 1, .Lfoo@ha |
| 112 | 84 | |
| 113 | # CHECK: Disassembly of section .R_PPC64_ADDR16_HA: | |
| 114 | # CHECK: .FR_PPC64_ADDR16_HA: | |
| 115 | # CHECK: 1001002c: {{.*}} li 1, 4097 | |
| 85 | # CHECK-LABEL: Disassembly of section .R_PPC64_ADDR16_HA: | |
| 86 | # CHECK: 1001002c: li 1, 4097 | |
| 116 | 87 | |
| 117 | 88 | .section .R_PPC64_ADDR16_HIGHER,"ax",@progbits |
| 118 | .globl .FR_PPC64_ADDR16_HIGHER | |
| 119 | .FR_PPC64_ADDR16_HIGHER: | |
| 120 | 89 | li 1, .Lfoo@higher |
| 121 | 90 | |
| 122 | # CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHER: | |
| 123 | # CHECK: .FR_PPC64_ADDR16_HIGHER: | |
| 124 | # CHECK: 10010030: {{.*}} li 1, 0 | |
| 91 | # CHECK-LABEL: Disassembly of section .R_PPC64_ADDR16_HIGHER: | |
| 92 | # CHECK: 10010030: li 1, 0 | |
| 125 | 93 | |
| 126 | 94 | .section .R_PPC64_ADDR16_HIGHERA,"ax",@progbits |
| 127 | .globl .FR_PPC64_ADDR16_HIGHERA | |
| 128 | .FR_PPC64_ADDR16_HIGHERA: | |
| 129 | 95 | li 1, .Lfoo@highera |
| 130 | 96 | |
| 131 | # CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHERA: | |
| 132 | # CHECK: .FR_PPC64_ADDR16_HIGHERA: | |
| 133 | # CHECK: 10010034: {{.*}} li 1, 0 | |
| 97 | # CHECK-LABEL: Disassembly of section .R_PPC64_ADDR16_HIGHERA: | |
| 98 | # CHECK: 10010034: li 1, 0 | |
| 134 | 99 | |
| 135 | 100 | .section .R_PPC64_ADDR16_HIGHEST,"ax",@progbits |
| 136 | .globl .FR_PPC64_ADDR16_HIGHEST | |
| 137 | .FR_PPC64_ADDR16_HIGHEST: | |
| 138 | 101 | li 1, .Lfoo@highest |
| 139 | 102 | |
| 140 | # CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHEST: | |
| 141 | # CHECK: .FR_PPC64_ADDR16_HIGHEST: | |
| 142 | # CHECK: 10010038: {{.*}} li 1, 0 | |
| 103 | # CHECK-LABEL: Disassembly of section .R_PPC64_ADDR16_HIGHEST: | |
| 104 | # CHECK: 10010038: li 1, 0 | |
| 143 | 105 | |
| 144 | 106 | .section .R_PPC64_ADDR16_HIGHESTA,"ax",@progbits |
| 145 | .globl .FR_PPC64_ADDR16_HIGHESTA | |
| 146 | .FR_PPC64_ADDR16_HIGHESTA: | |
| 147 | 107 | li 1, .Lfoo@highesta |
| 148 | 108 | |
| 149 | # CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHESTA: | |
| 150 | # CHECK: .FR_PPC64_ADDR16_HIGHESTA: | |
| 151 | # CHECK: 1001003c: {{.*}} li 1, 0 | |
| 109 | # CHECK-LABEL: Disassembly of section .R_PPC64_ADDR16_HIGHESTA: | |
| 110 | # CHECK: 1001003c: li 1, 0 | |
| 152 | 111 | |
| 153 | 112 | .section .R_PPC64_REL32, "ax",@progbits |
| 154 | .globl .FR_PPC64_REL32 | |
| 155 | .FR_PPC64_REL32: | |
| 156 | 113 | addis 5, 2, .LC0@toc@ha |
| 157 | 114 | ld 5, .LC0@toc@l(5) |
| 158 | 115 | .LBB0_2: |
| 159 | 116 | add 3, 3, 4 |
| 160 | 117 | |
| 161 | # DATALE: Disassembly of section .rodata: | |
| 162 | # DATALE: .rodata: | |
| 163 | # DATALE: 10000190: b8 fe 00 00 | |
| 118 | # DATALE: '.rodata': | |
| 119 | # DATALE: 0x100001c8 80fe0000 | |
| 164 | 120 | |
| 165 | # DATABE: Disassembly of section .rodata: | |
| 166 | # DATABE: .rodata: | |
| 167 | # DATABE: 10000190: 00 00 fe b8 | |
| 121 | # DATABE: '.rodata': | |
| 122 | # DATABE: 0x100001c8 0000fe80 | |
| 168 | 123 | |
| 169 | 124 | # Address of rodata + value stored at rodata entry |
| 170 | 125 | # should equal address of LBB0_2. |
| 171 | 126 | # 0x10000190 + 0xfeb4 = 0x10010044 |
| 172 | # CHECK: Disassembly of section .R_PPC64_REL32: | |
| 173 | # CHECK: .FR_PPC64_REL32: | |
| 174 | # CHECK: 10010040: {{.*}} nop | |
| 175 | # CHECK: 10010044: {{.*}} ld 5, -32736(2) | |
| 176 | # CHECK: 10010048: {{.*}} add 3, 3, 4 | |
| 127 | # CHECK-LABEL: Disassembly of section .R_PPC64_REL32: | |
| 128 | # CHECK: 10010040: addis 5, 2, 0 | |
| 129 | # CHECK: 10010044: ld 5, -32736(5) | |
| 130 | # CHECK: 10010048: add 3, 3, 4 | |
| 177 | 131 | |
| 178 | 132 | .section .R_PPC64_REL64, "ax",@progbits |
| 179 | .globl .FR_PPC64_REL64 | |
| 180 | .FR_PPC64_REL64: | |
| 181 | 133 | .cfi_startproc |
| 182 | 134 | .cfi_personality 148, __foo |
| 183 | 135 | li 0, 1 |
| ... | ... | @@ -187,18 +139,26 @@ _start: |
| 187 | 139 | __foo: |
| 188 | 140 | li 3,0 |
| 189 | 141 | |
| 190 | # Check that address of eh_frame entry + value stored | |
| 191 | # should equal the address of foo. Since it is not aligned, | |
| 192 | # the entry is not stored exactly at 10000198. It starts at | |
| 193 | # address 0x1000019a and has the value 0xfeaa. | |
| 194 | # 0x100001aa + 0xfeae = 0x10010058 | |
| 195 | # DATALE: Disassembly of section .eh_frame: | |
| 196 | # DATALE: .eh_frame: | |
| 197 | # DATALE: 100001a8: {{.*}} ae fe | |
| 142 | .section .R_PPC64_TOC,"a",@progbits | |
| 143 | .quad .TOC.@tocbase | |
| 198 | 144 | |
| 199 | # DATABE: Disassembly of section .eh_frame: | |
| 200 | # DATABE: .eh_frame: | |
| 201 | # DATABE: 100001b0: fe ae {{.*}} | |
| 145 | # SEC: .got PROGBITS 0000000010020000 | |
| 146 | ||
| 147 | ## tocbase = .got+0x8000 = 0x10028000 | |
| 148 | # DATALE-LABEL: section '.R_PPC64_TOC': | |
| 149 | # DATALE: 00800210 00000000 | |
| 150 | ||
| 151 | # DATABE-LABEL: section '.R_PPC64_TOC': | |
| 152 | # DATABE: 00000000 10028000 | |
| 153 | ||
| 154 | # Check that the personality (relocated by R_PPC64_REL64) in the .eh_frame | |
| 155 | # equals the address of __foo. | |
| 156 | # 0x100001ea + 0xfe6e = 0x10010058 | |
| 157 | # DATALE: section '.eh_frame': | |
| 158 | # DATALE: 0x100001e8 {{....}}6efe | |
| 159 | ||
| 160 | # DATABE: section '.eh_frame': | |
| 161 | # DATABE: 0x100001e8 {{[0-9a-f]+ [0-9a-f]+}} fe6e{{....}} | |
| 202 | 162 | |
| 203 | 163 | # CHECK: __foo |
| 204 | # CHECK-NEXT: 10010058: {{.*}} li 3, 0 | |
| 164 | # CHECK-NEXT: 10010058: li 3, 0 |
deps/lld/test/ELF/ppc64-shared-long_branch.s+8-8| ... | ... | @@ -83,32 +83,32 @@ b: |
| 83 | 83 | |
| 84 | 84 | # Verify address of the callee |
| 85 | 85 | # CALLEE_DUMP: callee: |
| 86 | # CALLEE_DUMP: 10000: {{.*}} addis 2, 12, 515 | |
| 86 | # CALLEE_DUMP: 10000: {{.*}} addis 2, 12, 514 | |
| 87 | 87 | # CALLEE_DUMP: 10004: {{.*}} addi 2, 2, -32528 |
| 88 | 88 | # CALLEE_DUMP: 10008: {{.*}} addis 4, 2, 0 |
| 89 | 89 | |
| 90 | 90 | # Verify the address of _start, and the call to the long-branch thunk. |
| 91 | 91 | # CALLER_DUMP: _start: |
| 92 | # CALLER_DUMP: 2010020: {{.*}} addis 2, 12, 3 | |
| 92 | # CALLER_DUMP: 2010020: {{.*}} addis 2, 12, 2 | |
| 93 | 93 | # CALLER_DUMP: 2010038: {{.*}} bl .+56 |
| 94 | 94 | |
| 95 | 95 | # Verify the thunks contents: TOC-pointer + offset = .branch_lt[0] |
| 96 | # 0x20380F0 + 32552 = 0x2040018 | |
| 96 | # 0x20280F0 + 32560 = 0x2030020 | |
| 97 | 97 | # CALLER_DUMP: __long_branch_callee: |
| 98 | 98 | # CALLER_DUMP: 2010060: {{.*}} addis 12, 2, 0 |
| 99 | # CALLER_DUMP: 2010064: {{.*}} ld 12, 32552(12) | |
| 99 | # CALLER_DUMP: 2010064: {{.*}} ld 12, 32560(12) | |
| 100 | 100 | # CALLER_DUMP: 2010068: {{.*}} mtctr 12 |
| 101 | 101 | # CALLER_DUMP: 201006c: {{.*}} bctr |
| 102 | 102 | |
| 103 | 103 | # .got section is at address 0x20300f0 so TOC pointer points to 0x20400F0. |
| 104 | 104 | # .plt section has a 2 entry header and a single entry for the long branch. |
| 105 | 105 | # [Nr] Name Type Address Off Size |
| 106 | # SECTIONS: [11] .got PROGBITS 00000000020300f0 20300f0 000008 | |
| 107 | # SECTIONS: [13] .plt NOBITS 0000000002040000 2030108 000018 | |
| 108 | # SECTIONS: [14] .branch_lt NOBITS 0000000002040018 2030108 000008 | |
| 106 | # SECTIONS: [10] .got PROGBITS 00000000020200f0 20200f0 000008 | |
| 107 | # SECTIONS: [13] .plt NOBITS 0000000002030008 2030008 000018 | |
| 108 | # SECTIONS: [14] .branch_lt NOBITS 0000000002030020 2030008 000008 | |
| 109 | 109 | |
| 110 | 110 | # There is a relative dynamic relocation for (.plt + 16 bytes), with a base |
| 111 | 111 | # address equal to callees local entry point (0x10000 + 8). |
| 112 | 112 | # DYNRELOC: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 3 entries: |
| 113 | 113 | # DYNRELOC: Offset Info Type Symbol's Value |
| 114 | # DYNRELOC: 0000000002040018 0000000000000016 R_PPC64_RELATIVE 10008 | |
| 114 | # DYNRELOC: 0000000002030020 0000000000000016 R_PPC64_RELATIVE 10008 |
deps/lld/test/ELF/ppc64-sort-small-cm-relocs.s created+108| ... | ... | @@ -0,0 +1,108 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t1.o | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-sort-small-cm-relocs-input2.s -o %t2.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-sort-small-cm-relocs-input3.s -o %t3.o | |
| 5 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-sort-small-cm-relocs-input4.s -o %t4.o | |
| 6 | ||
| 7 | # RUN: ld.lld %t1.o %t2.o %t3.o %t4.o -o %t -Map=%t.map | |
| 8 | # RUN: FileCheck %s < %t.map | |
| 9 | ||
| 10 | # Test an alternate link order. | |
| 11 | # RUN: ld.lld %t2.o %t3.o %t4.o %t1.o -o %t -Map=%t.map | |
| 12 | # RUN: FileCheck %s -check-prefix=ALTERNATE < %t.map | |
| 13 | ||
| 14 | # If a linker script has a sections command then allow that to override the | |
| 15 | # default sorting behavior. | |
| 16 | # RUN: echo "SECTIONS { \ | |
| 17 | # RUN: .toc : { \ | |
| 18 | # RUN: *ppc64-sort-small-cm-relocs.s.tmp4.o(.toc*) \ | |
| 19 | # RUN: *ppc64-sort-small-cm-relocs.s.tmp1.o(.toc*) \ | |
| 20 | # RUN: *(.toc*) \ | |
| 21 | # RUN: } \ | |
| 22 | # RUN: } " > %t.script | |
| 23 | # RUN: ld.lld %t1.o %t2.o %t3.o %t4.o -o %t -script %t.script -Map=%t.map | |
| 24 | # RUN: FileCheck %s -check-prefix=SEC-CMD < %t.map | |
| 25 | ||
| 26 | # RUN: echo "SECTIONS { .text : {*(.text*)} } " > %t.script | |
| 27 | # RUN: ld.lld %t1.o %t2.o %t3.o %t4.o -o %t -script %t.script -Map=%t.map | |
| 28 | # RUN: FileCheck %s -check-prefix=SEC-CMD2 < %t.map | |
| 29 | ||
| 30 | # Default sort if the linker script does not have a sections command. | |
| 31 | # RUN: echo "" > %t.script | |
| 32 | # RUN: ld.lld %t1.o %t2.o %t3.o %t4.o -o %t -script %t.script -Map=%t.map | |
| 33 | # RUN: FileCheck %s -check-prefix=NOSEC < %t.map | |
| 34 | .text | |
| 35 | ||
| 36 | .global _start | |
| 37 | .type _start,@function | |
| 38 | _start: | |
| 39 | li 3, 55 | |
| 40 | blr | |
| 41 | ||
| 42 | .type a,@object | |
| 43 | .data | |
| 44 | .global a | |
| 45 | a: | |
| 46 | .long 10 | |
| 47 | .size a, 4 | |
| 48 | ||
| 49 | .type c,@object | |
| 50 | .data | |
| 51 | .global c | |
| 52 | c: | |
| 53 | .long 55 | |
| 54 | .size c, 4 | |
| 55 | ||
| 56 | .type d,@object | |
| 57 | .global d | |
| 58 | d: | |
| 59 | .long 33 | |
| 60 | .size d, 4 | |
| 61 | ||
| 62 | # .toc section contains only some constants. | |
| 63 | .section .toc,"aw",@progbits | |
| 64 | .quad 0xa1a1a1a1a1a1a1a1 | |
| 65 | .quad 0xb2b2b2b2b2b2b2b2 | |
| 66 | ||
| 67 | # Input files tmp3.o and tmp4.o contain small code model relocs. | |
| 68 | ||
| 69 | # CHECK: .got | |
| 70 | # CHECK-NEXT: <internal>:(.got) | |
| 71 | # CHECK-NEXT: .toc | |
| 72 | # CHECK-NEXT: {{.*}}3.o:(.toc) | |
| 73 | # CHECK-NEXT: {{.*}}4.o:(.toc) | |
| 74 | # CHECK-NEXT: {{.*}}1.o:(.toc) | |
| 75 | # CHECK-NEXT: {{.*}}2.o:(.toc) | |
| 76 | ||
| 77 | # ALTERNATE: .got | |
| 78 | # ALTERNATE-NEXT: <internal>:(.got) | |
| 79 | # ALTERNATE-NEXT: .toc | |
| 80 | # ALTERNATE-NEXT: {{.*}}3.o:(.toc) | |
| 81 | # ALTERNATE-NEXT: {{.*}}4.o:(.toc) | |
| 82 | # ALTERNATE-NEXT: {{.*}}2.o:(.toc) | |
| 83 | # ALTERNATE-NEXT: {{.*}}1.o:(.toc) | |
| 84 | ||
| 85 | # SEC-CMD: .got | |
| 86 | # SEC-CMD-NEXT: <internal>:(.got) | |
| 87 | # SEC-CMD-NEXT: .toc | |
| 88 | # SEC-CMD-NEXT: {{.*}}4.o:(.toc) | |
| 89 | # SEC-CMD-NEXT: {{.*}}1.o:(.toc) | |
| 90 | # SEC-CMD-NEXT: {{.*}}2.o:(.toc) | |
| 91 | # SEC-CMD-NEXT: {{.*}}3.o:(.toc) | |
| 92 | ||
| 93 | # SEC-CMD2: .got | |
| 94 | # SEC-CMD2-NEXT: <internal>:(.got) | |
| 95 | # SEC-CMD2-NEXT: .toc | |
| 96 | # SEC-CMD2-NEXT: {{.*}}1.o:(.toc) | |
| 97 | # SEC-CMD2-NEXT: {{.*}}2.o:(.toc) | |
| 98 | # SEC-CMD2-NEXT: {{.*}}3.o:(.toc) | |
| 99 | # SEC-CMD2-NEXT: {{.*}}4.o:(.toc) | |
| 100 | ||
| 101 | # NOSEC: .got | |
| 102 | # NOSEC-NEXT: <internal>:(.got) | |
| 103 | # NOSEC-NEXT: .toc | |
| 104 | # NOSEC-NEXT: {{.*}}3.o:(.toc) | |
| 105 | # NOSEC-NEXT: {{.*}}4.o:(.toc) | |
| 106 | # NOSEC-NEXT: {{.*}}1.o:(.toc) | |
| 107 | # NOSEC-NEXT: {{.*}}2.o:(.toc) | |
| 108 |
deps/lld/test/ELF/ppc64-tls-gd-le-small.s deleted-61| ... | ... | @@ -1,61 +0,0 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 4 | # RUN: llvm-objdump -d -r %t.o | FileCheck --check-prefix=CHECK-INPUT %s | |
| 5 | # RUN: ld.lld --defsym __tls_get_addr=0x10001000 %t.o -o %t | |
| 6 | # RUN: llvm-objdump -d %t | FileCheck --check-prefix=CHECK-DIS %s | |
| 7 | # RUN: llvm-readelf -relocations %t | FileCheck --check-prefix=DYN-RELOCS %s | |
| 8 | ||
| 9 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o | |
| 10 | # RUN: llvm-objdump -d -r %t.o | FileCheck --check-prefix=CHECK-INPUT %s | |
| 11 | # RUN: ld.lld --defsym __tls_get_addr=0x10001000 %t.o -o %t | |
| 12 | # RUN: llvm-objdump -d %t | FileCheck --check-prefix=CHECK-DIS %s | |
| 13 | # RUN: llvm-readelf -relocations %t | FileCheck --check-prefix=DYN-RELOCS %s | |
| 14 | ||
| 15 | # Test checks the relaxation of a 'small' general-dynamic tls access into a | |
| 16 | # local-exec tls access. | |
| 17 | ||
| 18 | .text | |
| 19 | .abiversion 2 | |
| 20 | ||
| 21 | .global test | |
| 22 | .p2align 4 | |
| 23 | .type test, @function | |
| 24 | ||
| 25 | test: | |
| 26 | .Lgep: | |
| 27 | addis 2, 12, .TOC.-.Lgep@ha | |
| 28 | addi 2, 2, .TOC.-.Lgep@l | |
| 29 | .localentry test, .-test | |
| 30 | mflr 0 | |
| 31 | std 0, 16(1) | |
| 32 | stdu 1, -32(1) | |
| 33 | addi 3, 2, a@got@tlsgd | |
| 34 | bl __tls_get_addr(a@tlsgd) | |
| 35 | nop | |
| 36 | lwz 3, 0(3) | |
| 37 | addi 1, 1, 32 | |
| 38 | ld 0, 16(1) | |
| 39 | mtlr 0 | |
| 40 | blr | |
| 41 | ||
| 42 | .type a, @object | |
| 43 | .section .tdata,"awT",@progbits | |
| 44 | .global a | |
| 45 | .p2align 2 | |
| 46 | a: | |
| 47 | .long 55 | |
| 48 | .size a, 4 | |
| 49 | ||
| 50 | # CHECK-INPUT: addi 3, 2, 0 | |
| 51 | # CHECK-INPUT-NEXT: R_PPC64_GOT_TLSGD16 a | |
| 52 | # CHECK-INPUT-NEXT: bl .+0 | |
| 53 | # CHECK-INPUT-NEXT: R_PPC64_TLSGD a | |
| 54 | # CHECK-INPUT-NEXT: R_PPC64_REL24 __tls_get_addr | |
| 55 | ||
| 56 | # CHECK-DIS: addis 3, 13, 0 | |
| 57 | # CHECK-DIS-NEXT: nop | |
| 58 | # CHECK-DIS-NEXT: addi 3, 3, -28672 | |
| 59 | # CHECK-DIS-NEXT: lwz 3, 0(3) | |
| 60 | ||
| 61 | # DYN-RELOCS: There are no relocations in this file |
deps/lld/test/ELF/ppc64-tls-gd-le.s deleted-83| ... | ... | @@ -1,83 +0,0 @@ |
| 1 | // REQUIRES: ppc | |
| 2 | ||
| 3 | // RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 4 | // RUN: llvm-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s | |
| 5 | // RUN: ld.lld %t.o -o %t | |
| 6 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=Dis %s | |
| 7 | // RUN: llvm-readelf -r %t | FileCheck --check-prefix=OutputRelocs %s | |
| 8 | ||
| 9 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o | |
| 10 | // RUN: llvm-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s | |
| 11 | // RUN: ld.lld %t.o -o %t | |
| 12 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=Dis %s | |
| 13 | // RUN: llvm-readelf -r %t | FileCheck --check-prefix=OutputRelocs %s | |
| 14 | ||
| 15 | 	.text | |
| 16 | 	.abiversion 2 | |
| 17 | 	.globl	_start # -- Begin function _start | |
| 18 | 	.p2align	4 | |
| 19 | 	.type	_start,@function | |
| 20 | _start: # @_start | |
| 21 | .Lfunc_begin0: | |
| 22 | .Lfunc_gep0: | |
| 23 | 	addis 2, 12, .TOC.-.Lfunc_gep0@ha | |
| 24 | 	addi 2, 2, .TOC.-.Lfunc_gep0@l | |
| 25 | .Lfunc_lep0: | |
| 26 | 	.localentry	_start, .Lfunc_lep0-.Lfunc_gep0 | |
| 27 | # %bb.0: # %entry | |
| 28 | 	mflr 0 | |
| 29 | 	std 31, -8(1) | |
| 30 | 	std 0, 16(1) | |
| 31 | 	stdu 1, -64(1) | |
| 32 | 	mr 31, 1 | |
| 33 | 	std 30, 48(31) # 8-byte Folded Spill | |
| 34 | 	li 3, 0 | |
| 35 | 	stw 3, 44(31) | |
| 36 | 	addis 3, 2, a@got@tlsgd@ha | |
| 37 | 	addi 3, 3, a@got@tlsgd@l | |
| 38 | 	bl __tls_get_addr(a@tlsgd) | |
| 39 | 	nop | |
| 40 | 	lwz 30, 0(3) | |
| 41 | 	extsw 3, 30 | |
| 42 | 	ld 30, 48(31) # 8-byte Folded Reload | |
| 43 | 	addi 1, 1, 64 | |
| 44 | 	ld 0, 16(1) | |
| 45 | 	ld 31, -8(1) | |
| 46 | 	mtlr 0 | |
| 47 | 	blr | |
| 48 | 	.long	0 | |
| 49 | 	.quad	0 | |
| 50 | .Lfunc_end0: | |
| 51 | 	.size	_start, .Lfunc_end0-.Lfunc_begin0 | |
| 52 | ||
| 53 | .globl __tls_get_addr | |
| 54 | .type __tls_get_addr,@function | |
| 55 | __tls_get_addr: | |
| 56 | ||
| 57 | # -- End function | |
| 58 | 	.type	a,@object # @a | |
| 59 | 	.section	.tdata,"awT",@progbits | |
| 60 | 	.globl	a | |
| 61 | 	.p2align	2 | |
| 62 | a: | |
| 63 | 	.long	55 # 0x37 | |
| 64 | 	.size	a, 4 | |
| 65 | ||
| 66 | // Verify that the input has general-dynamic tls relocation types | |
| 67 | // InputRelocs: Relocation section '.rela.text' | |
| 68 | // InputRelocs: R_PPC64_GOT_TLSGD16_HA {{0+}} a + 0 | |
| 69 | // InputRelocs: R_PPC64_GOT_TLSGD16_LO {{0+}} a + 0 | |
| 70 | // InputRelocs: R_PPC64_TLSGD {{0+}} a + 0 | |
| 71 | ||
| 72 | // Verify that the general-dynamic sequence is relaxed to local exec. | |
| 73 | // #ha(a@tprel) --> (0 - 0x7000 + 0x8000) >> 16 = 0 | |
| 74 | // #lo(a@tprel)) --> (0 - 0x7000) & 0xFFFF = -0x7000 = -28672 | |
| 75 | // Dis: _start: | |
| 76 | // Dis: nop | |
| 77 | // Dis: addis 3, 13, 0 | |
| 78 | // Dis: nop | |
| 79 | // Dis: addi 3, 3, -28672 | |
| 80 | ||
| 81 | // Verify that no general-dynamic relocations exist for the dynamic linker. | |
| 82 | // OutputRelocs-NOT: R_PPC64_DTPMOD64 | |
| 83 | // OutputRelocs-NOT: R_PPC64_DTPREL64 |
deps/lld/test/ELF/ppc64-tls-gd.s created+102| ... | ... | @@ -0,0 +1,102 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le %s -o %t.o | |
| 3 | # RUN: echo '.tbss; .globl b, c; b: .zero 4; c:' | llvm-mc -filetype=obj -triple=powerpc64le - -o %t1.o | |
| 4 | # RUN: ld.lld -shared -soname=t1.so %t1.o -o %t1.so | |
| 5 | ||
| 6 | # RUN: ld.lld -shared %t.o %t1.o -o %t.so | |
| 7 | # RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=GD-REL %s | |
| 8 | # RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=GD %s | |
| 9 | ||
| 10 | # RUN: ld.lld %t.o %t1.o -o %t | |
| 11 | # RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s | |
| 12 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s | |
| 13 | ||
| 14 | # RUN: ld.lld %t.o %t1.so -o %t | |
| 15 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=IE-REL %s | |
| 16 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=IE %s | |
| 17 | ||
| 18 | # GD-REL: .rela.dyn { | |
| 19 | # GD-REL-NEXT: 0x200F0 R_PPC64_DTPMOD64 a 0x0 | |
| 20 | # GD-REL-NEXT: 0x200F8 R_PPC64_DTPREL64 a 0x0 | |
| 21 | # GD-REL-NEXT: 0x20100 R_PPC64_DTPMOD64 b 0x0 | |
| 22 | # GD-REL-NEXT: 0x20108 R_PPC64_DTPREL64 b 0x0 | |
| 23 | # GD-REL-NEXT: 0x20110 R_PPC64_DTPMOD64 c 0x0 | |
| 24 | # GD-REL-NEXT: 0x20118 R_PPC64_DTPREL64 c 0x0 | |
| 25 | # GD-REL-NEXT: } | |
| 26 | ||
| 27 | ## &DTPMOD(a) - .TOC. = &.got[0] - (.got+0x8000) = -32768 | |
| 28 | # GD: addis 3, 2, 0 | |
| 29 | # GD-NEXT: addi 3, 3, -32768 | |
| 30 | # GD-NEXT: bl .+40 | |
| 31 | # GD-NEXT: ld 2, 24(1) | |
| 32 | ||
| 33 | ## &DTPMOD(b) - .TOC. = &.got[2] - (.got+0x8000) = -32752 | |
| 34 | # GD-NEXT: addis 3, 2, 0 | |
| 35 | # GD-NEXT: addi 3, 3, -32752 | |
| 36 | # GD-NEXT: bl .+24 | |
| 37 | # GD-NEXT: ld 2, 24(1) | |
| 38 | ||
| 39 | ## &DTPMOD(b) - .TOC. = &.got[4] - (.got+0x8000) = -32736 | |
| 40 | # GD-NEXT: li 3, -32736 | |
| 41 | # GD-NEXT: bl .+12 | |
| 42 | # GD-NEXT: ld 2, 24(1) | |
| 43 | ||
| 44 | # NOREL: no relocations | |
| 45 | ||
| 46 | ## a@tprel = st_value(a)-0x7000 = -28664 | |
| 47 | # LE: nop | |
| 48 | # LE-NEXT: addis 3, 13, 0 | |
| 49 | # LE-NEXT: nop | |
| 50 | # LE-NEXT: addi 3, 3, -28664 | |
| 51 | ## b@tprel = st_value(b)-0x7000 = -28660 | |
| 52 | # LE: nop | |
| 53 | # LE-NEXT: addis 3, 13, 0 | |
| 54 | # LE-NEXT: nop | |
| 55 | # LE-NEXT: addi 3, 3, -28660 | |
| 56 | ## c@tprel = st_value(c)-0x7000 = -28656 | |
| 57 | # LE-NEXT: addis 3, 13, 0 | |
| 58 | # LE-NEXT: nop | |
| 59 | # LE-NEXT: addi 3, 3, -28656 | |
| 60 | ||
| 61 | # IE-REL: .rela.dyn { | |
| 62 | # IE-REL-NEXT: 0x100200C0 R_PPC64_TPREL64 b 0x0 | |
| 63 | # IE-REL-NEXT: 0x100200C8 R_PPC64_TPREL64 c 0x0 | |
| 64 | # IE-REL-NEXT: } | |
| 65 | ||
| 66 | ## a is relaxed to use LE. | |
| 67 | ## a@tprel = st_value(a)-0x7000 = -28664 | |
| 68 | # IE: nop | |
| 69 | # IE-NEXT: addis 3, 13, 0 | |
| 70 | # IE-NEXT: nop | |
| 71 | # IE-NEXT: addi 3, 3, -28664 | |
| 72 | ## &DTPMOD(b) - .TOC. = &.got[0] - (.got+0x8000) = -32768 | |
| 73 | # IE-NEXT: addis 3, 2, 0 | |
| 74 | # IE-NEXT: ld 3, -32768(3) | |
| 75 | # IE-NEXT: nop | |
| 76 | # IE-NEXT: add 3, 3, 13 | |
| 77 | ## &DTPMOD(c) - .TOC. = &.got[1] - (.got+0x8000) = -32760 | |
| 78 | ## r0 is wrong. R_PPC64_GOT_TLS16 cannot be relaxed to IE but the behavior is | |
| 79 | ## consistent with ld.bfd | |
| 80 | # IE-NEXT: ld 3, -32760(0) | |
| 81 | # IE-NEXT: nop | |
| 82 | # IE-NEXT: add 3, 3, 13 | |
| 83 | ||
| 84 | addis 3, 2, a@got@tlsgd@ha | |
| 85 | addi 3, 3, a@got@tlsgd@l | |
| 86 | bl __tls_get_addr(a@tlsgd) | |
| 87 | nop | |
| 88 | ||
| 89 | addis 3, 2, b@got@tlsgd@ha | |
| 90 | addi 3, 3, b@got@tlsgd@l | |
| 91 | bl __tls_get_addr(b@tlsgd) | |
| 92 | nop | |
| 93 | ||
| 94 | addi 3, 0, c@got@tlsgd | |
| 95 | bl __tls_get_addr(c@tlsgd) | |
| 96 | nop | |
| 97 | ||
| 98 | .section .tbss | |
| 99 | .globl a | |
| 100 | .zero 8 | |
| 101 | a: | |
| 102 | .zero 4 |
deps/lld/test/ELF/ppc64-tls-ie-le.s deleted-140| ... | ... | @@ -1,140 +0,0 @@ |
| 1 | // REQUIRES: ppc | |
| 2 | ||
| 3 | // RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 4 | // RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-tls-ie-le.s -o %t2.o | |
| 5 | // RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.o -o %t | |
| 6 | // RUN: llvm-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s | |
| 7 | // RUN: llvm-readelf -r %t | FileCheck --check-prefix=OutputRelocs %s | |
| 8 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=Dis %s | |
| 9 | ||
| 10 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o | |
| 11 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-tls-ie-le.s -o %t2.o | |
| 12 | // RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.o -o %t | |
| 13 | // RUN: llvm-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s | |
| 14 | // RUN: llvm-readelf -r %t | FileCheck --check-prefix=OutputRelocs %s | |
| 15 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=Dis %s | |
| 16 | ||
| 17 | 	.text | |
| 18 | 	.abiversion 2 | |
| 19 | test1: # @test1 | |
| 20 | 	addis 3, 2, c@got@tprel@ha | |
| 21 | 	ld 3, c@got@tprel@l(3) | |
| 22 | 	lbzx 3, 3, c@tls | |
| 23 | 	blr | |
| 24 | test2: # @test2 | |
| 25 | 	addis 3, 2, s@got@tprel@ha | |
| 26 | 	ld 3, s@got@tprel@l(3) | |
| 27 | 	lhzx 3, 3, s@tls | |
| 28 | 	blr | |
| 29 | test3: # @test3 | |
| 30 | 	addis 3, 2, i@got@tprel@ha | |
| 31 | 	ld 3, i@got@tprel@l(3) | |
| 32 | 	lwzx 3, 3, i@tls | |
| 33 | 	blr | |
| 34 | test4: # @test4 | |
| 35 | 	addis 3, 2, l@got@tprel@ha | |
| 36 | 	ld 3, l@got@tprel@l(3) | |
| 37 | 	ldx 3, 3, l@tls | |
| 38 | 	blr | |
| 39 | test5: # @test5 | |
| 40 | 	addis 4, 2, c@got@tprel@ha | |
| 41 | 	ld 4, c@got@tprel@l(4) | |
| 42 | 	stbx 3, 4, c@tls | |
| 43 | 	blr | |
| 44 | test6: # @test6 | |
| 45 | 	addis 4, 2, s@got@tprel@ha | |
| 46 | 	ld 4, s@got@tprel@l(4) | |
| 47 | 	sthx 3, 4, s@tls | |
| 48 | 	blr | |
| 49 | test7: # @test7 | |
| 50 | 	addis 4, 2, i@got@tprel@ha | |
| 51 | 	ld 4, i@got@tprel@l(4) | |
| 52 | 	stwx 3, 4, i@tls | |
| 53 | 	blr | |
| 54 | test8: # @test8 | |
| 55 | 	addis 4, 2, l@got@tprel@ha | |
| 56 | 	ld 4, l@got@tprel@l(4) | |
| 57 | 	stdx 3, 4, l@tls | |
| 58 | 	blr | |
| 59 | test9: # @test9 | |
| 60 | 	addis 3, 2, i@got@tprel@ha | |
| 61 | 	ld 3, i@got@tprel@l(3) | |
| 62 | 	add 3, 3, i@tls | |
| 63 | 	blr | |
| 64 | test_ds: # @test_ds | |
| 65 | 	ld 4, l@got@tprel(2) | |
| 66 | 	stdx 3, 4, l@tls | |
| 67 | 	blr | |
| 68 | ||
| 69 | ||
| 70 | // Verify that the input has initial-exec tls relocation types. | |
| 71 | // InputRelocs: Relocation section '.rela.text' | |
| 72 | // InputRelocs: R_PPC64_GOT_TPREL16_HA {{0+}} c + 0 | |
| 73 | // InputRelocs: R_PPC64_GOT_TPREL16_LO_DS {{0+}} c + 0 | |
| 74 | // InputRelocs: R_PPC64_TLS {{0+}} c + 0 | |
| 75 | // InputRelocs: R_PPC64_GOT_TPREL16_HA {{0+}} s + 0 | |
| 76 | // InputRelocs: R_PPC64_GOT_TPREL16_LO_DS {{0+}} s + 0 | |
| 77 | // InputRelocs: R_PPC64_TLS {{0+}} s + 0 | |
| 78 | // InputRelocs: R_PPC64_GOT_TPREL16_HA {{0+}} i + 0 | |
| 79 | // InputRelocs: R_PPC64_GOT_TPREL16_LO_DS {{0+}} i + 0 | |
| 80 | // InputRelocs: R_PPC64_TLS {{0+}} i + 0 | |
| 81 | // InputRelocs: R_PPC64_GOT_TPREL16_HA {{0+}} l + 0 | |
| 82 | // InputRelocs: R_PPC64_GOT_TPREL16_LO_DS {{0+}} l + 0 | |
| 83 | // InputRelocs: R_PPC64_TLS {{0+}} l + 0 | |
| 84 | // InputRelocs: R_PPC64_GOT_TPREL16_DS {{0+}} l + 0 | |
| 85 | // InputRelocs: R_PPC64_TLS {{0+}} l + 0 | |
| 86 | ||
| 87 | // Verify that no initial-exec relocations exist for the dynamic linker. | |
| 88 | // OutputRelocs-NOT: R_PPC64_TPREL64 {{0+}} c + 0 | |
| 89 | // OutputRelocs-NPT: R_PPC64_TPREL64 {{0+}} s + 0 | |
| 90 | // OutputRelocs-NOT: R_PPC64_TPREL64 {{0+}} i + 0 | |
| 91 | // OutputRelocs-NOT: R_PPC64_TPREL64 {{0+}} l + 0 | |
| 92 | ||
| 93 | // Dis: test1: | |
| 94 | // Dis: nop | |
| 95 | // Dis: addis 3, 13, 0 | |
| 96 | // Dis: lbz 3, -28672(3) | |
| 97 | ||
| 98 | // Dis: test2: | |
| 99 | // Dis: nop | |
| 100 | // Dis: addis 3, 13, 0 | |
| 101 | // Dis: lhz 3, -28670(3) | |
| 102 | ||
| 103 | // Dis: test3: | |
| 104 | // Dis: nop | |
| 105 | // Dis: addis 3, 13, 0 | |
| 106 | // Dis: lwz 3, -28668(3) | |
| 107 | ||
| 108 | // Dis: test4: | |
| 109 | // Dis: nop | |
| 110 | // Dis: addis 3, 13, 0 | |
| 111 | // Dis: ld 3, -28664(3) | |
| 112 | ||
| 113 | // Dis: test5: | |
| 114 | // Dis: nop | |
| 115 | // Dis: addis 4, 13, 0 | |
| 116 | // Dis: stb 3, -28672(4) | |
| 117 | ||
| 118 | // Dis: test6: | |
| 119 | // Dis: nop | |
| 120 | // Dis: addis 4, 13, 0 | |
| 121 | // Dis: sth 3, -28670(4) | |
| 122 | ||
| 123 | // Dis: test7: | |
| 124 | // Dis: nop | |
| 125 | // Dis: addis 4, 13, 0 | |
| 126 | // Dis: stw 3, -28668(4) | |
| 127 | ||
| 128 | // Dis: test8: | |
| 129 | // Dis: nop | |
| 130 | // Dis: addis 4, 13, 0 | |
| 131 | // Dis: std 3, -28664(4) | |
| 132 | ||
| 133 | // Dis: test9: | |
| 134 | // Dis: nop | |
| 135 | // Dis: addis 3, 13, 0 | |
| 136 | // Dis: addi 3, 3, -28668 | |
| 137 | ||
| 138 | // Dis: test_ds: | |
| 139 | // Dis: addis 4, 13, 0 | |
| 140 | // Dis: std 3, -28664(4) |
deps/lld/test/ELF/ppc64-tls-ie.s created+171| ... | ... | @@ -0,0 +1,171 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le %s -o %t.o | |
| 4 | # RUN: llvm-readobj -r %t.o | FileCheck --check-prefix=INPUT-REL %s | |
| 5 | ## IE | |
| 6 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 7 | # RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=IE-REL %s | |
| 8 | # RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=IE %s | |
| 9 | ## IE -> LE | |
| 10 | # RUN: ld.lld %t.o -o %t | |
| 11 | # RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s | |
| 12 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s | |
| 13 | ||
| 14 | # RUN: llvm-mc -filetype=obj -triple=powerpc64 %s -o %t.o | |
| 15 | # RUN: llvm-readobj -r %t.o | FileCheck --check-prefix=INPUT-REL %s | |
| 16 | ## IE | |
| 17 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 18 | # RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=IE-REL %s | |
| 19 | # RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=IE %s | |
| 20 | ## IE -> LE | |
| 21 | # RUN: ld.lld %t.o -o %t | |
| 22 | # RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s | |
| 23 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s | |
| 24 | ||
| 25 | # IE-REL: .rela.dyn { | |
| 26 | # IE-REL-NEXT: 0x200B0 R_PPC64_TPREL64 c 0x0 | |
| 27 | # IE-REL-NEXT: 0x200C0 R_PPC64_TPREL64 i 0x0 | |
| 28 | # IE-REL-NEXT: 0x200C8 R_PPC64_TPREL64 l 0x0 | |
| 29 | # IE-REL-NEXT: 0x200B8 R_PPC64_TPREL64 s 0x0 | |
| 30 | # IE-REL-NEXT: } | |
| 31 | ||
| 32 | # INPUT-REL: R_PPC64_GOT_TPREL16_HA c 0x0 | |
| 33 | # INPUT-REL: R_PPC64_GOT_TPREL16_LO_DS c 0x0 | |
| 34 | # INPUT-REL: R_PPC64_TLS c 0x0 | |
| 35 | ## &.got[0] - .TOC. = -32768 | |
| 36 | # IE-LABEL: test1: | |
| 37 | # IE-NEXT: addis 3, 2, 0 | |
| 38 | # IE-NEXT: ld 3, -32768(3) | |
| 39 | # IE-NEXT: lbzx 3, 3, 13 | |
| 40 | # LE-LABEL: test1: | |
| 41 | # LE-NEXT: nop | |
| 42 | # LE-NEXT: addis 3, 13, 0 | |
| 43 | # LE-NEXT: lbz 3, -28672(3) | |
| 44 | test1: | |
| 45 | addis 3, 2, c@got@tprel@ha | |
| 46 | ld 3, c@got@tprel@l(3) | |
| 47 | lbzx 3, 3, c@tls | |
| 48 | ||
| 49 | # INPUT-REL: R_PPC64_GOT_TPREL16_HA s 0x0 | |
| 50 | # INPUT-REL: R_PPC64_GOT_TPREL16_LO_DS s 0x0 | |
| 51 | # INPUT-REL: R_PPC64_TLS s 0x0 | |
| 52 | ## &.got[1] - .TOC. = -32760 | |
| 53 | # IE-LABEL: test2: | |
| 54 | # IE-NEXT: addis 3, 2, 0 | |
| 55 | # IE-NEXT: ld 3, -32760(3) | |
| 56 | # IE-NEXT: lhzx 3, 3, 13 | |
| 57 | # LE-LABEL: test2: | |
| 58 | # LE-NEXT: nop | |
| 59 | # LE-NEXT: addis 3, 13, 0 | |
| 60 | # LE-NEXT: lhz 3, -28670(3) | |
| 61 | test2: | |
| 62 | addis 3, 2, s@got@tprel@ha | |
| 63 | ld 3, s@got@tprel@l(3) | |
| 64 | lhzx 3, 3, s@tls | |
| 65 | ||
| 66 | # INPUT-REL: R_PPC64_GOT_TPREL16_HA i 0x0 | |
| 67 | # INPUT-REL: R_PPC64_GOT_TPREL16_LO_DS i 0x0 | |
| 68 | # INPUT-REL: R_PPC64_TLS i 0x0 | |
| 69 | ## &.got[2] - .TOC. = -32752 | |
| 70 | # IE-LABEL: test3: | |
| 71 | # IE-NEXT: addis 3, 2, 0 | |
| 72 | # IE-NEXT: ld 3, -32752(3) | |
| 73 | # IE-NEXT: lwzx 3, 3, 13 | |
| 74 | # LE-LABEL: test3: | |
| 75 | # LE-NEXT: nop | |
| 76 | # LE-NEXT: addis 3, 13, 0 | |
| 77 | # LE-NEXT: lwz 3, -28668(3) | |
| 78 | test3: | |
| 79 | addis 3, 2, i@got@tprel@ha | |
| 80 | ld 3, i@got@tprel@l(3) | |
| 81 | lwzx 3, 3, i@tls | |
| 82 | ||
| 83 | # INPUT-REL: R_PPC64_GOT_TPREL16_HA l 0x0 | |
| 84 | # INPUT-REL: R_PPC64_GOT_TPREL16_LO_DS l 0x0 | |
| 85 | # INPUT-REL: R_PPC64_TLS l 0x0 | |
| 86 | ## &.got[3] - .TOC. = -32744 | |
| 87 | # IE-LABEL: test4: | |
| 88 | # IE-NEXT: addis 3, 2, 0 | |
| 89 | # IE-NEXT: ld 3, -32744(3) | |
| 90 | # IE-NEXT: ldx 3, 3, 13 | |
| 91 | # LE-LABEL: test4: | |
| 92 | # LE-NEXT: nop | |
| 93 | # LE-NEXT: addis 3, 13, 0 | |
| 94 | # LE-NEXT: ld 3, -28664(3) | |
| 95 | test4: | |
| 96 | addis 3, 2, l@got@tprel@ha | |
| 97 | ld 3, l@got@tprel@l(3) | |
| 98 | ldx 3, 3, l@tls | |
| 99 | ||
| 100 | # LE-LABEL: test5: | |
| 101 | # LE-NEXT: nop | |
| 102 | # LE-NEXT: addis 4, 13, 0 | |
| 103 | # LE-NEXT: stb 3, -28672(4) | |
| 104 | test5: | |
| 105 | addis 4, 2, c@got@tprel@ha | |
| 106 | ld 4, c@got@tprel@l(4) | |
| 107 | stbx 3, 4, c@tls | |
| 108 | ||
| 109 | ||
| 110 | # LE-LABEL: test6: | |
| 111 | # LE-NEXT: nop | |
| 112 | # LE-NEXT: addis 4, 13, 0 | |
| 113 | # LE-NEXT: sth 3, -28670(4) | |
| 114 | test6: | |
| 115 | addis 4, 2, s@got@tprel@ha | |
| 116 | ld 4, s@got@tprel@l(4) | |
| 117 | sthx 3, 4, s@tls | |
| 118 | ||
| 119 | ||
| 120 | # LE-LABEL: test7: | |
| 121 | # LE-NEXT: nop | |
| 122 | # LE-NEXT: addis 4, 13, 0 | |
| 123 | # LE-NEXT: stw 3, -28668(4) | |
| 124 | test7: | |
| 125 | addis 4, 2, i@got@tprel@ha | |
| 126 | ld 4, i@got@tprel@l(4) | |
| 127 | stwx 3, 4, i@tls | |
| 128 | ||
| 129 | # LE-LABEL: test8: | |
| 130 | # LE-NEXT: nop | |
| 131 | # LE-NEXT: addis 4, 13, 0 | |
| 132 | # LE-NEXT: std 3, -28664(4) | |
| 133 | test8: | |
| 134 | addis 4, 2, l@got@tprel@ha | |
| 135 | ld 4, l@got@tprel@l(4) | |
| 136 | stdx 3, 4, l@tls | |
| 137 | ||
| 138 | # LE-LABEL: test9: | |
| 139 | # LE-NEXT: nop | |
| 140 | # LE-NEXT: addis 3, 13, 0 | |
| 141 | # LE-NEXT: addi 3, 3, -28668 | |
| 142 | test9: | |
| 143 | addis 3, 2, i@got@tprel@ha | |
| 144 | ld 3, i@got@tprel@l(3) | |
| 145 | add 3, 3, i@tls | |
| 146 | ||
| 147 | # LE-LABEL: test_ds: | |
| 148 | # LE-NEXT: addis 4, 13, 0 | |
| 149 | # LE-NEXT: std 3, -28664(4) | |
| 150 | test_ds: | |
| 151 | ld 4, l@got@tprel(2) | |
| 152 | stdx 3, 4, l@tls | |
| 153 | ||
| 154 | # NOREL: There are no relocations in this file. | |
| 155 | ||
| 156 | .section .tdata,"awT",@progbits | |
| 157 | .globl c, s, i, l | |
| 158 | c: | |
| 159 | .byte 97 | |
| 160 | ||
| 161 | .p2align 1 | |
| 162 | s: | |
| 163 | .short 55 | |
| 164 | ||
| 165 | .p2align 2 | |
| 166 | i: | |
| 167 | .long 55 | |
| 168 | ||
| 169 | .p2align 3 | |
| 170 | l: | |
| 171 | .quad 55 |
deps/lld/test/ELF/ppc64-tls-ld-le.s+3-5| ... | ... | @@ -3,13 +3,13 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o |
| 4 | 4 | // RUN: llvm-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s |
| 5 | 5 | // RUN: ld.lld %t.o -o %t |
| 6 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=Dis %s | |
| 6 | // RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=Dis %s | |
| 7 | 7 | // RUN: llvm-readelf -r %t | FileCheck --check-prefix=OutputRelocs %s |
| 8 | 8 | |
| 9 | 9 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o |
| 10 | 10 | // RUN: llvm-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s |
| 11 | 11 | // RUN: ld.lld %t.o -o %t |
| 12 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=Dis %s | |
| 12 | // RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=Dis %s | |
| 13 | 13 | // RUN: llvm-readelf -r %t | FileCheck --check-prefix=OutputRelocs %s |
| 14 | 14 | |
| 15 | 15 | 	.text |
| ... | ... | @@ -52,9 +52,7 @@ _start: # @_start |
| 52 | 52 | .Lfunc_end0: |
| 53 | 53 | 	.size	_start, .Lfunc_end0-.Lfunc_begin0 |
| 54 | 54 | # -- End function |
| 55 | .globl __tls_get_addr | |
| 56 | .type __tls_get_addr,@function | |
| 57 | __tls_get_addr: | |
| 55 | ||
| 58 | 56 | 	.type	a,@object # @a |
| 59 | 57 | 	.section	.tdata,"awT",@progbits |
| 60 | 58 | 	.p2align	2 |
deps/lld/test/ELF/ppc64-tls-ld-preemptable.s created+35| ... | ... | @@ -0,0 +1,35 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=ppc64le %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -shared -o %t.so | |
| 4 | # RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck %s | |
| 5 | # RUN: llvm-nm %t.so | FileCheck --check-prefix=NM %s | |
| 6 | # RUN: llvm-readelf -x .rodata %t.so | FileCheck --check-prefix=RODATA %s | |
| 7 | ||
| 8 | # 0x2a - 0x8000 = -32726 | |
| 9 | # CHECK: addis 4, 3, 0 | |
| 10 | # CHECK-NEXT: addi 4, 4, -32726 | |
| 11 | # CHECK-NEXT: lis 5, 0 | |
| 12 | # CHECK-NEXT: ori 5, 5, 0 | |
| 13 | ||
| 14 | # NM: 000000000000002a B i | |
| 15 | # RODATA: 2a000000 00000000 | |
| 16 | ||
| 17 | # We used to error on R_PPC64_DTPREL* to preemptable symbols. | |
| 18 | # i is STB_GLOBAL and preemptable. | |
| 19 | .globl foo | |
| 20 | foo: | |
| 21 | addis 4, 3, i@dtprel@ha # R_PPC64_DTPREL16_HA | |
| 22 | addi 4, 4, i@dtprel@l # R_PPC64_DTPREL16_LO | |
| 23 | ||
| 24 | lis 5, i@dtprel@highesta # R_PPC64_DTPREL16_HIGHESTA | |
| 25 | ori 5, 5, i@dtprel@highera # R_PPC64_DTPREL16_HIGHERA | |
| 26 | ||
| 27 | .section .rodata,"a",@progbits | |
| 28 | .quad i@dtprel+32768 | |
| 29 | ||
| 30 | .section .tbss,"awT",@nobits | |
| 31 | .space 0x2a | |
| 32 | .globl i | |
| 33 | i: | |
| 34 | .long 0 | |
| 35 | .size i, 4 |
deps/lld/test/ELF/ppc64-toc-addis-nop-lqsq.s+2-3| ... | ... | @@ -6,10 +6,10 @@ |
| 6 | 6 | # RUN: ld.lld -shared %t2.o -o %t2.so |
| 7 | 7 | |
| 8 | 8 | # RUN: ld.lld %t2.so %p/Inputs/ppc64le-quadword-ldst.o -o %t |
| 9 | # RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s | |
| 9 | # RUN: llvm-objdump -d %t | FileCheck --check-prefix=Dis %s | |
| 10 | 10 | |
| 11 | 11 | # RUN: ld.lld --no-toc-optimize %t2.so %p/Inputs/ppc64le-quadword-ldst.o -o %t |
| 12 | # RUN: llvm-objdump -D %t | FileCheck --check-prefix=NoOpt %s | |
| 12 | # RUN: llvm-objdump -d %t | FileCheck --check-prefix=NoOpt %s | |
| 13 | 13 | |
| 14 | 14 | # QuadInputRelocs: Relocation section '.rela.text' |
| 15 | 15 | # QuadInputRelocs: R_PPC64_TOC16_LO_DS 0000000000000000 quadLd |
| ... | ... | @@ -70,4 +70,3 @@ |
| 70 | 70 | # NoOpt-NEXT: addis 3, 2, 0 |
| 71 | 71 | # NoOpt-NEXT: 82 7f 83 f8 <unknown> |
| 72 | 72 | # NoOpt-NEXT: blr |
| 73 |
deps/lld/test/ELF/ppc64-toc-addis-nop.s+11-11| ... | ... | @@ -1,16 +1,16 @@ |
| 1 | 1 | # REQUIRES: ppc |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o |
| 4 | # RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s | |
| 4 | # RUN: llvm-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s | |
| 5 | 5 | |
| 6 | 6 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o |
| 7 | 7 | # RUN: ld.lld -shared %t2.o -o %t2.so |
| 8 | 8 | # |
| 9 | 9 | # RUN: ld.lld %t2.so %t.o -o %t |
| 10 | # RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s | |
| 10 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=Dis %s | |
| 11 | 11 | # |
| 12 | 12 | # RUN: ld.lld --no-toc-optimize %t2.so %t.o -o %t |
| 13 | # RUN: llvm-objdump -D %t | FileCheck --check-prefix=NoOpt %s | |
| 13 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=NoOpt %s | |
| 14 | 14 | |
| 15 | 15 | # InputRelocs: Relocation section '.rela.text' |
| 16 | 16 | # InputRelocs: R_PPC64_TOC16_HA |
| ... | ... | @@ -35,7 +35,7 @@ bytes: |
| 35 | 35 | addis 4, 2, byteSt@toc@ha |
| 36 | 36 | stb 3, byteSt@toc@l(4) |
| 37 | 37 | blr |
| 38 | # Dis-LABEL: bytes | |
| 38 | # Dis-LABEL: bytes: | |
| 39 | 39 | # Dis-NEXT: addis |
| 40 | 40 | # Dis-NEXT: addi |
| 41 | 41 | # Dis-NEXT: nop |
| ... | ... | @@ -44,7 +44,7 @@ bytes: |
| 44 | 44 | # Dis-NEXT: stb 3, 32625(2) |
| 45 | 45 | # Dis-NEXT: blr |
| 46 | 46 | |
| 47 | # NoOpt-LABEL: bytes | |
| 47 | # NoOpt-LABEL: bytes: | |
| 48 | 48 | # NoOpt-NEXT: addis |
| 49 | 49 | # NoOpt-NEXT: addi |
| 50 | 50 | # NoOpt-NEXT: addis 3, 2, 0 |
| ... | ... | @@ -69,7 +69,7 @@ halfs: |
| 69 | 69 | addis 5, 2, halfSt@toc@ha |
| 70 | 70 | sth 4, halfSt@toc@l(5) |
| 71 | 71 | blr |
| 72 | # Dis-LABEL: halfs | |
| 72 | # Dis-LABEL: halfs: | |
| 73 | 73 | # Dis-NEXT: addis |
| 74 | 74 | # Dis-NEXT: addi |
| 75 | 75 | # Dis-NEXT: nop |
| ... | ... | @@ -80,7 +80,7 @@ halfs: |
| 80 | 80 | # Dis-NEXT: sth 4, 32628(2) |
| 81 | 81 | # Dis-NEXT: blr |
| 82 | 82 | |
| 83 | # NoOpt-LABEL: halfs | |
| 83 | # NoOpt-LABEL: halfs: | |
| 84 | 84 | # NoOpt-NEXT: addis |
| 85 | 85 | # NoOpt-NEXT: addi |
| 86 | 86 | # NoOpt-NEXT: addis 3, 2, 0 |
| ... | ... | @@ -178,7 +178,7 @@ vec_dq: |
| 178 | 178 | stxv 3, vecSt@toc@l(3) |
| 179 | 179 | blr |
| 180 | 180 | |
| 181 | # Dis-LABEL: vec_dq | |
| 181 | # Dis-LABEL: vec_dq: | |
| 182 | 182 | # Dis-NEXT: addis |
| 183 | 183 | # Dis-NEXT: addi |
| 184 | 184 | # Dis-NEXT: nop |
| ... | ... | @@ -187,7 +187,7 @@ vec_dq: |
| 187 | 187 | # Dis-NEXT: stxv 3, 32672(2) |
| 188 | 188 | # Dis-NEXT: blr |
| 189 | 189 | |
| 190 | # NoOpt-LABEL: vec_dq | |
| 190 | # NoOpt-LABEL: vec_dq: | |
| 191 | 191 | # NoOpt-NEXT: addis |
| 192 | 192 | # NoOpt-NEXT: addi |
| 193 | 193 | # NoOpt-NEXT: addis 3, 2, 0 |
| ... | ... | @@ -214,7 +214,7 @@ vec_ds: |
| 214 | 214 | addis 3, 2, vecSt@toc@ha |
| 215 | 215 | stxssp 3, vecSt@toc@l(3) |
| 216 | 216 | blr |
| 217 | # Dis-LABEL: vec_ds | |
| 217 | # Dis-LABEL: vec_ds: | |
| 218 | 218 | # Dis-NEXT: addis |
| 219 | 219 | # Dis-NEXT: addi |
| 220 | 220 | # Dis-NEXT: nop |
| ... | ... | @@ -227,7 +227,7 @@ vec_ds: |
| 227 | 227 | # Dis-NEXT: stxssp 3, 32672(2) |
| 228 | 228 | # Dis-NEXT: blr |
| 229 | 229 | |
| 230 | # NoOpt-LABEL: vec_ds | |
| 230 | # NoOpt-LABEL: vec_ds: | |
| 231 | 231 | # NoOpt-NEXT: addis |
| 232 | 232 | # NoOpt-NEXT: addi |
| 233 | 233 | # NoOpt-NEXT: addis 3, 2, 0 |
deps/lld/test/ELF/ppc64-toc-rel.s+25-30| ... | ... | @@ -1,16 +1,18 @@ |
| 1 | 1 | # REQUIRES: ppc |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o |
| 4 | # RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS-LE %s | |
| 5 | # RUN: ld.lld %t.o -o %t2 | |
| 6 | # RUN: llvm-objdump -D %t2 | FileCheck %s | |
| 7 | # RUN: llvm-objdump -D %t2 | FileCheck -check-prefix=CHECK-LE %s | |
| 4 | # RUN: llvm-readobj -r %t.o | FileCheck -check-prefix=RELOCS-LE %s | |
| 5 | # RUN: ld.lld %t.o -o %t | |
| 6 | # RUN: llvm-nm %t | FileCheck --check-prefix=NM %s | |
| 7 | # RUN: llvm-readelf -x .got %t | FileCheck --check-prefix=HEX-LE %s | |
| 8 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=CHECK %s | |
| 8 | 9 | |
| 9 | 10 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o |
| 10 | # RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS-BE %s | |
| 11 | # RUN: ld.lld %t.o -o %t2 | |
| 12 | # RUN: llvm-objdump -D %t2 | FileCheck %s | |
| 13 | # RUN: llvm-objdump -D %t2 | FileCheck -check-prefix=CHECK-BE %s | |
| 11 | # RUN: llvm-readobj -r %t.o | FileCheck -check-prefix=RELOCS-BE %s | |
| 12 | # RUN: ld.lld %t.o -o %t | |
| 13 | # RUN: llvm-nm %t | FileCheck --check-prefix=NM %s | |
| 14 | # RUN: llvm-readelf -x .got %t | FileCheck --check-prefix=HEX-BE %s | |
| 15 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=CHECK %s | |
| 14 | 16 | |
| 15 | 17 | # Make sure we calculate the offset correctly for a toc-relative access to a |
| 16 | 18 | # global variable as described by the PPC64 Elf V2 abi. |
| ... | ... | @@ -57,26 +59,19 @@ _start: |
| 57 | 59 | # RELOCS-BE: 0xA R_PPC64_TOC16_HA global_a 0x0 |
| 58 | 60 | # RELOCS-BE: 0xE R_PPC64_TOC16_LO global_a 0x0 |
| 59 | 61 | |
| 60 | # Want to check _start for the values used to build the offset from the TOC base | |
| 61 | # to global_a. The .TOC. symbol is expected at address 0x10030000, and the | |
| 62 | # TOC base is address-of(.TOC.) + 0x8000. The expected offset is: | |
| 63 | # 0x10020000(global_a) - 0x10038000(Toc base) = -0x18000(Offset) | |
| 64 | # which gets materialized into r3 as ((-1 << 16) - 32768). | |
| 62 | # The .TOC. symbol represents the TOC base address: .got + 0x8000 = 0x10028000, | |
| 63 | # which is stored in the first entry of .got | |
| 64 | # NM: 0000000010028000 d .TOC. | |
| 65 | # NM: 0000000010030000 D global_a | |
| 66 | # HEX-LE: section '.got': | |
| 67 | # HEX-LE-NEXT: 0x10020000 00800210 00000000 | |
| 68 | # HEX-BE: section '.got': | |
| 69 | # HEX-BE-NEXT: 0x10020000 00000000 10028000 | |
| 65 | 70 | |
| 66 | # CHECK: Disassembly of section .text: | |
| 67 | # CHECK-NEXT: _start: | |
| 68 | # CHECK: 10010008: {{.*}} addis 3, 2, -1 | |
| 69 | # CHECK-NEXT: 1001000c: {{.*}} addi 3, 3, -32768 | |
| 70 | ||
| 71 | # CHECK: Disassembly of section .data: | |
| 72 | # CHECK-NEXT: global_a: | |
| 73 | # CHECK-NEXT: 10020000: {{.*}} | |
| 74 | ||
| 75 | # CHECK-LE: Disassembly of section .got: | |
| 76 | # CHECK-LE-NEXT: .got: | |
| 77 | # CHECK-LE-NEXT: 10030000: 00 80 03 10 | |
| 78 | ||
| 79 | # CHECK-BE: Disassembly of section .got: | |
| 80 | # CHECK-BE-NEXT: .got: | |
| 81 | # CHECK-BE-NEXT: 10030000: 00 00 00 00 | |
| 82 | # CHECK-BE-NEXT: 10030004: 10 03 80 00 | |
| 71 | # r2 stores the TOC base address. To access global_a with r3, it | |
| 72 | # computes the address with TOC plus an offset. | |
| 73 | # The offset global_a - .TOC. = 0x10030000 - 0x10028000 = 0x8000 | |
| 74 | # gets materialized as (1 << 16) - 32768. | |
| 75 | # CHECK: _start: | |
| 76 | # CHECK: 10010008: addis 3, 2, 1 | |
| 77 | # CHECK-NEXT: 1001000c: addi 3, 3, -32768 |
deps/lld/test/ELF/ppc64-toc-relax-constants.s created+61| ... | ... | @@ -0,0 +1,61 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unkown-linux %p/Inputs/ppc64-toc-relax-shared.s -o %t.o | |
| 4 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 5 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t1.o | |
| 6 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-toc-relax.s -o %t2.o | |
| 7 | # RUN: llvm-readobj -r %t1.o | FileCheck --check-prefix=RELOCS %s | |
| 8 | # RUN: ld.lld %t1.o %t2.o %t.so -o %t | |
| 9 | # RUN: llvm-readelf -S %t | FileCheck --check-prefix=SECTIONS %s | |
| 10 | # RUN: llvm-nm %t | FileCheck --check-prefix=NM %s | |
| 11 | # RUN: llvm-objdump -D %t | FileCheck %s | |
| 12 | ||
| 13 | # In most cases, .toc contains exclusively addresses relocated by R_PPC64_ADDR16. | |
| 14 | # Rarely .toc contain constants or variables. | |
| 15 | # Test we can still perform toc-indirect to toc-relative relaxation. | |
| 16 | ||
| 17 | # RELOCS: .rela.text { | |
| 18 | # RELOCS-NEXT: 0x0 R_PPC64_TOC16_HA .toc 0x0 | |
| 19 | # RELOCS-NEXT: 0x4 R_PPC64_TOC16_LO_DS .toc 0x0 | |
| 20 | # RELOCS-NEXT: 0x8 R_PPC64_TOC16_HA .toc 0x8 | |
| 21 | # RELOCS-NEXT: 0xC R_PPC64_TOC16_LO_DS .toc 0x8 | |
| 22 | # RELOCS-NEXT: 0x10 R_PPC64_TOC16_HA .toc 0x10 | |
| 23 | # RELOCS-NEXT: 0x14 R_PPC64_TOC16_LO_DS .toc 0x10 | |
| 24 | # RELOCS-NEXT: } | |
| 25 | ||
| 26 | # SECTIONS: .got PROGBITS 0000000010020090 | |
| 27 | # SECTIONS: .toc PROGBITS 0000000010020090 | |
| 28 | ||
| 29 | # NM: 0000000010030000 D default | |
| 30 | ||
| 31 | # .LCONST1 is .toc[0]. | |
| 32 | # .LCONST1 - (.got+0x8000) = 0x10020090 - (0x10020090+0x8000) = -32768 | |
| 33 | # CHECK: nop | |
| 34 | # CHECK: lwa 3, -32768(2) | |
| 35 | addis 3, 2, .LCONST1@toc@ha | |
| 36 | lwa 3, .LCONST1@toc@l(3) | |
| 37 | ||
| 38 | # .LCONST2 is .toc[1] | |
| 39 | # .LCONST2 - (.got+0x8000) = 0x10020098 - (0x10020090+0x8000) = -32760 | |
| 40 | # CHECK: nop | |
| 41 | # CHECK: ld 4, -32760(2) | |
| 42 | addis 4, 2, .LCONST2@toc@ha | |
| 43 | ld 4, .LCONST2@toc@l(4) | |
| 44 | ||
| 45 | # .Ldefault is .toc[2]. `default` is not preemptable when producing an executable. | |
| 46 | # After toc-indirection to toc-relative relaxation, it is loaded using an | |
| 47 | # offset relative to r2. | |
| 48 | # CHECK: nop | |
| 49 | # CHECK: addi 5, 2, 32624 | |
| 50 | # CHECK: lwa 5, 0(5) | |
| 51 | addis 5, 2, .Ldefault@toc@ha | |
| 52 | ld 5, .Ldefault@toc@l(5) | |
| 53 | lwa 5, 0(5) | |
| 54 | ||
| 55 | .section .toc,"aw",@progbits | |
| 56 | .LCONST1: | |
| 57 | .quad 11 | |
| 58 | .LCONST2: | |
| 59 | .quad 22 | |
| 60 | .Ldefault: | |
| 61 | .tc default[TC],default |
deps/lld/test/ELF/ppc64-toc-relax-jumptable.s created+73| ... | ... | @@ -0,0 +1,73 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -o %t | |
| 4 | # RUN: llvm-readelf -S %t | FileCheck --check-prefixes=SECTIONS %s | |
| 5 | # RUN: llvm-readelf -x .toc %t | FileCheck --check-prefixes=HEX-LE %s | |
| 6 | # RUN: llvm-objdump -d %t | FileCheck --check-prefixes=CHECK %s | |
| 7 | ||
| 8 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o | |
| 9 | # RUN: ld.lld %t.o -o %t | |
| 10 | # RUN: llvm-readelf -S %t | FileCheck --check-prefixes=SECTIONS %s | |
| 11 | # RUN: llvm-readelf -x .toc %t | FileCheck --check-prefixes=HEX-BE %s | |
| 12 | # RUN: llvm-objdump -d %t | FileCheck --check-prefixes=CHECK %s | |
| 13 | ||
| 14 | # .LJT is a local symbol (non-preemptable). | |
| 15 | # Test we can perform the toc-indirect to toc-relative relaxation. | |
| 16 | ||
| 17 | # SECTIONS: .rodata PROGBITS 00000000100001c8 | |
| 18 | ||
| 19 | # HEX-LE: section '.toc': | |
| 20 | # HEX-LE-NEXT: 10020008 c8010010 00000000 | |
| 21 | ||
| 22 | # HEX-BE: section '.toc': | |
| 23 | # HEX-BE-NEXT: 10020008 00000000 100001c8 | |
| 24 | ||
| 25 | # CHECK-LABEL: _start | |
| 26 | # CHECK: clrldi 3, 3, 62 | |
| 27 | # CHECK-NEXT: addis 4, 2, -2 | |
| 28 | # CHECK-NEXT: addi 4, 4, -32312 | |
| 29 | # CHECK-NEXT: sldi 3, 3, 2 | |
| 30 | ||
| 31 | .text | |
| 32 | .global _start | |
| 33 | .type _start, @function | |
| 34 | _start: | |
| 35 | .Lstart_gep: | |
| 36 | addis 2, 12, .TOC.-.Lstart_gep@ha | |
| 37 | addi 2, 2, .TOC.-.Lstart_gep@l | |
| 38 | .Lstart_lep: | |
| 39 | .localentry _start, .Lstart_lep-.Lstart_gep | |
| 40 | rldicl 3, 3, 0, 62 | |
| 41 | addis 4, 2, .LJTI_TE@toc@ha | |
| 42 | ld 4, .LJTI_TE@toc@l(4) | |
| 43 | sldi 3, 3, 2 | |
| 44 | lwax 3, 3, 4 | |
| 45 | add 3, 3, 4 | |
| 46 | mtctr 3 | |
| 47 | bctr | |
| 48 | ||
| 49 | .LBB1: | |
| 50 | li 3, 0 | |
| 51 | blr | |
| 52 | .LBB2: | |
| 53 | li 3, 10 | |
| 54 | blr | |
| 55 | .LBB3: | |
| 56 | li 3, 55 | |
| 57 | blr | |
| 58 | .LBB4: | |
| 59 | li 3, 255 | |
| 60 | blr | |
| 61 | ||
| 62 | .section .rodata,"a",@progbits | |
| 63 | .p2align 2 | |
| 64 | .LJT: | |
| 65 | .long .LBB1-.LJT | |
| 66 | .long .LBB2-.LJT | |
| 67 | .long .LBB3-.LJT | |
| 68 | .long .LBB4-.LJT | |
| 69 | ||
| 70 | .section .toc,"aw",@progbits | |
| 71 | # TOC entry for the jumptable address. | |
| 72 | .LJTI_TE: | |
| 73 | .tc .LJT[TC],.LJT |
deps/lld/test/ELF/ppc64-toc-relax.s created+105| ... | ... | @@ -0,0 +1,105 @@ |
| 1 | # REQUIRES: ppc | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-toc-relax-shared.s -o %t.o | |
| 3 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t1.o | |
| 5 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-toc-relax.s -o %t2.o | |
| 6 | # RUN: llvm-readobj -r %t1.o | FileCheck --check-prefixes=RELOCS-LE,RELOCS %s | |
| 7 | # RUN: ld.lld %t1.o %t2.o %t.so -o %t | |
| 8 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefixes=COMMON,EXE %s | |
| 9 | ||
| 10 | # RUN: ld.lld -shared %t1.o %t2.o %t.so -o %t2.so | |
| 11 | # RUN: llvm-objdump -d --no-show-raw-insn %t2.so | FileCheck --check-prefixes=COMMON,SHARED %s | |
| 12 | ||
| 13 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-toc-relax-shared.s -o %t.o | |
| 14 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 15 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t1.o | |
| 16 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-toc-relax.s -o %t2.o | |
| 17 | # RUN: llvm-readobj -r %t1.o | FileCheck --check-prefixes=RELOCS-BE,RELOCS %s | |
| 18 | # RUN: ld.lld %t1.o %t2.o %t.so -o %t | |
| 19 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefixes=COMMON,EXE %s | |
| 20 | ||
| 21 | # RUN: ld.lld -shared %t1.o %t2.o %t.so -o %t2.so | |
| 22 | # RUN: llvm-objdump -d --no-show-raw-insn %t2.so | FileCheck --check-prefixes=COMMON,SHARED %s | |
| 23 | ||
| 24 | # RELOCS-LE: .rela.text { | |
| 25 | # RELOCS-LE-NEXT: 0x0 R_PPC64_TOC16_HA .toc 0x0 | |
| 26 | # RELOCS-LE-NEXT: 0x4 R_PPC64_TOC16_LO_DS .toc 0x0 | |
| 27 | # RELOCS-LE-NEXT: 0xC R_PPC64_TOC16_HA .toc 0x8 | |
| 28 | # RELOCS-LE-NEXT: 0x10 R_PPC64_TOC16_LO_DS .toc 0x8 | |
| 29 | # RELOCS-LE-NEXT: 0x18 R_PPC64_TOC16_HA .toc 0x10 | |
| 30 | # RELOCS-LE-NEXT: 0x1C R_PPC64_TOC16_LO_DS .toc 0x10 | |
| 31 | # RELOCS-LE-NEXT: 0x24 R_PPC64_TOC16_HA .toc 0x18 | |
| 32 | # RELOCS-LE-NEXT: 0x28 R_PPC64_TOC16_LO_DS .toc 0x18 | |
| 33 | # RELOCS-LE-NEXT: } | |
| 34 | ||
| 35 | # RELOCS-BE: .rela.text { | |
| 36 | # RELOCS-BE-NEXT: 0x2 R_PPC64_TOC16_HA .toc 0x0 | |
| 37 | # RELOCS-BE-NEXT: 0x6 R_PPC64_TOC16_LO_DS .toc 0x0 | |
| 38 | # RELOCS-BE-NEXT: 0xE R_PPC64_TOC16_HA .toc 0x8 | |
| 39 | # RELOCS-BE-NEXT: 0x12 R_PPC64_TOC16_LO_DS .toc 0x8 | |
| 40 | # RELOCS-BE-NEXT: 0x1A R_PPC64_TOC16_HA .toc 0x10 | |
| 41 | # RELOCS-BE-NEXT: 0x1E R_PPC64_TOC16_LO_DS .toc 0x10 | |
| 42 | # RELOCS-BE-NEXT: 0x26 R_PPC64_TOC16_HA .toc 0x18 | |
| 43 | # RELOCS-BE-NEXT: 0x2A R_PPC64_TOC16_LO_DS .toc 0x18 | |
| 44 | # RELOCS-BE-NEXT: } | |
| 45 | ||
| 46 | # RELOCS: .rela.toc { | |
| 47 | # RELOCS-NEXT: 0x0 R_PPC64_ADDR64 hidden 0x0 | |
| 48 | # RELOCS-NEXT: 0x8 R_PPC64_ADDR64 hidden2 0x0 | |
| 49 | # RELOCS-NEXT: 0x10 R_PPC64_ADDR64 shared 0x0 | |
| 50 | # RELOCS-NEXT: 0x18 R_PPC64_ADDR64 default 0x0 | |
| 51 | # RELOCS-NEXT: } | |
| 52 | ||
| 53 | # NM-DAG: 0000000010030000 D default | |
| 54 | # NM-DAG: 0000000010030000 d hidden | |
| 55 | # NM-DAG: 0000000010040000 d hidden2 | |
| 56 | ||
| 57 | # 'hidden' is non-preemptable. It is relaxed. | |
| 58 | # address(hidden) - (.got+0x8000) = 0x10030000 - (0x100200c0+0x8000) = 32576 | |
| 59 | # COMMON: nop | |
| 60 | # COMMON: addi 3, 2, 32576 | |
| 61 | # COMMON: lwa 3, 0(3) | |
| 62 | addis 3, 2, .Lhidden@toc@ha | |
| 63 | ld 3, .Lhidden@toc@l(3) | |
| 64 | lwa 3, 0(3) | |
| 65 | ||
| 66 | # address(hidden2) - (.got+0x8000) = 0x10040000 - (0x100200c0+0x8000) = (1<<16)+32576 | |
| 67 | # COMMON: addis 3, 2, 1 | |
| 68 | # COMMON: addi 3, 3, 32576 | |
| 69 | # COMMON: lwa 3, 0(3) | |
| 70 | addis 3, 2, .Lhidden2@toc@ha | |
| 71 | ld 3, .Lhidden2@toc@l(3) | |
| 72 | lwa 3, 0(3) | |
| 73 | ||
| 74 | # 'shared' is not defined in an object file. Its definition is determined at | |
| 75 | # runtime by the dynamic linker, so the extra indirection cannot be relaxed. | |
| 76 | # The first addis can still be relaxed to nop, though. | |
| 77 | # COMMON: nop | |
| 78 | # COMMON: ld 4, -32752(2) | |
| 79 | # COMMON: lwa 4, 0(4) | |
| 80 | addis 4, 2, .Lshared@toc@ha | |
| 81 | ld 4, .Lshared@toc@l(4) | |
| 82 | lwa 4, 0(4) | |
| 83 | ||
| 84 | # 'default' has default visibility. It is non-preemptable when producing an executable. | |
| 85 | # address(default) - (.got+0x8000) = 0x10030000 - (0x100200c0+0x8000) = 32576 | |
| 86 | # EXE: nop | |
| 87 | # EXE: addi 5, 2, 32576 | |
| 88 | # EXE: lwa 5, 0(5) | |
| 89 | ||
| 90 | # SHARED: nop | |
| 91 | # SHARED: ld 5, -32744(2) | |
| 92 | # SHARED: lwa 5, 0(5) | |
| 93 | addis 5, 2, .Ldefault@toc@ha | |
| 94 | ld 5, .Ldefault@toc@l(5) | |
| 95 | lwa 5, 0(5) | |
| 96 | ||
| 97 | .section .toc,"aw",@progbits | |
| 98 | .Lhidden: | |
| 99 | .tc hidden[TC], hidden | |
| 100 | .Lhidden2: | |
| 101 | .tc hidden2[TC], hidden2 | |
| 102 | .Lshared: | |
| 103 | .tc shared[TC], shared | |
| 104 | .Ldefault: | |
| 105 | .tc default[TC], default |
deps/lld/test/ELF/ppc64-toc-restore-recursive-call.s+8-9| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | 1 | # REQUIRES: ppc |
| 2 | 2 | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t1.o | |
| 4 | # RUN: ld.lld -shared %t1.o -o %t | |
| 5 | # RUN: llvm-objdump -d -r %t | FileCheck %s | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 4 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 5 | # RUN: llvm-objdump -d --no-show-raw-insn -r %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # For a recursive call that is interposable the linker calls the plt-stub rather |
| 8 | 8 | # then calling the function directly. Since the call is through a plt stub and |
| ... | ... | @@ -14,12 +14,11 @@ |
| 14 | 14 | # for recursive calls as well as keeps the logic for recursive calls consistent |
| 15 | 15 | # with non-recursive calls. |
| 16 | 16 | |
| 17 | # CHECK-LABEL: __plt_recursive_func: | |
| 18 | # CHECK-NEXT: 10000: | |
| 19 | # CHECK-LABEL: recursive_func | |
| 20 | # CHECK-NEXT: 10014: | |
| 21 | # CHECK: 1003c: {{[0-9a-fA-F ]+}} bl .+67108804 | |
| 22 | # CHECK-NEXT: ld 2, 24(1) | |
| 17 | # CHECK-LABEL: 0000000000010000 recursive_func: | |
| 18 | # CHECK: 10028: bl .+32 | |
| 19 | # CHECK-NEXT: ld 2, 24(1) | |
| 20 | ||
| 21 | # CHECK-LABEL: 0000000000010048 __plt_recursive_func: | |
| 23 | 22 | |
| 24 | 23 | .abiversion 2 |
| 25 | 24 | .section ".text" |
deps/lld/test/ELF/ppc64-toc-restore.s+17-24| ... | ... | @@ -5,14 +5,14 @@ |
| 5 | 5 | // RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func.s -o %t3.o |
| 6 | 6 | // RUN: ld.lld -shared %t2.o -o %t2.so |
| 7 | 7 | // RUN: ld.lld %t.o %t2.so %t3.o -o %t |
| 8 | // RUN: llvm-objdump -d %t | FileCheck %s | |
| 8 | // RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o |
| 11 | 11 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o |
| 12 | 12 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-func.s -o %t3.o |
| 13 | 13 | // RUN: ld.lld -shared %t2.o -o %t2.so |
| 14 | 14 | // RUN: ld.lld %t.o %t2.so %t3.o -o %t |
| 15 | // RUN: llvm-objdump -d %t | FileCheck %s | |
| 15 | // RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 16 | 16 | |
| 17 | 17 | .text |
| 18 | 18 | .abiversion 2 |
| ... | ... | @@ -28,16 +28,11 @@ _start: |
| 28 | 28 | bl foo |
| 29 | 29 | nop |
| 30 | 30 | bl bar_local |
| 31 | ||
| 32 | ||
| 33 | // CHECK: Disassembly of section .text: | |
| 34 | // CHECK: _start: | |
| 35 | // CHECK: 1001001c: {{.*}} bl .+67108836 | |
| 36 | // CHECK-NOT: 10010020: {{.*}} nop | |
| 37 | // CHECK: 10010020: {{.*}} ld 2, 24(1) | |
| 38 | // CHECK: 10010024: {{.*}} bl .+67108848 | |
| 39 | // CHECK-NOT: 10010028: {{.*}} nop | |
| 40 | // CHECK-NOT: 10010028: {{.*}} ld 2, 24(1) | |
| 31 | // CHECK-LABEL: _start: | |
| 32 | // CHECK-NEXT: 10010008: bl .+64 | |
| 33 | // CHECK-NEXT: 1001000c: ld 2, 24(1) | |
| 34 | // CHECK-NEXT: 10010010: bl .-16 | |
| 35 | // CHECK-EMPTY: | |
| 41 | 36 | |
| 42 | 37 | # Calling a function in another object file which will have same |
| 43 | 38 | # TOC base does not need a nop. If nop present, do not rewrite to |
| ... | ... | @@ -47,26 +42,24 @@ _diff_object: |
| 47 | 42 | bl foo_not_shared |
| 48 | 43 | bl foo_not_shared |
| 49 | 44 | nop |
| 50 | ||
| 51 | // CHECK: _diff_object: | |
| 52 | // CHECK-NEXT: 10010028: {{.*}} bl .+24 | |
| 53 | // CHECK-NEXT: 1001002c: {{.*}} bl .+20 | |
| 54 | // CHECK-NEXT: 10010030: {{.*}} nop | |
| 45 | // CHECK-LABEL: _diff_object: | |
| 46 | // CHECK-NEXT: 10010014: bl .+28 | |
| 47 | // CHECK-NEXT: 10010018: bl .+24 | |
| 48 | // CHECK-NEXT: 1001001c: nop | |
| 55 | 49 | |
| 56 | 50 | # Branching to a local function does not need a nop |
| 57 | 51 | .global noretbranch |
| 58 | 52 | noretbranch: |
| 59 | 53 | b bar_local |
| 60 | // CHECK: noretbranch: | |
| 61 | // CHECK: 10010034: {{.*}} b .+67108832 | |
| 62 | // CHECK-NOT: 10010038: {{.*}} nop | |
| 63 | // CHECK-NOT: 1001003c: {{.*}} ld 2, 24(1) | |
| 54 | // CHECK-LABEL: noretbranch: | |
| 55 | // CHECK: 10010020: b .+67108832 | |
| 56 | // CHECK-EMPTY: | |
| 64 | 57 | |
| 65 | 58 | // This should come last to check the end-of-buffer condition. |
| 66 | 59 | .global last |
| 67 | 60 | last: |
| 68 | 61 | bl foo |
| 69 | 62 | nop |
| 70 | // CHECK: last: | |
| 71 | // CHECK: 10010038: {{.*}} bl .+67108808 | |
| 72 | // CHECK-NEXT: 1001003c: {{.*}} ld 2, 24(1) | |
| 63 | // CHECK-LABEL: last: | |
| 64 | // CHECK-NEXT: 10010024: bl .+36 | |
| 65 | // CHECK-NEXT: 10010028: ld 2, 24(1) |
deps/lld/test/ELF/ppc64-weak-undef-call-shared.s+2-2| ... | ... | @@ -2,11 +2,11 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o |
| 4 | 4 | # RUN: ld.lld -shared %t.o -o %t.so |
| 5 | # RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s | |
| 5 | # RUN: llvm-readobj --symbols -r --dyn-syms %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o |
| 8 | 8 | # RUN: ld.lld -shared %t.o -o %t.so |
| 9 | # RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s | |
| 9 | # RUN: llvm-readobj --symbols -r --dyn-syms %t.so | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | .section ".toc","aw" |
| 12 | 12 | .quad weakfunc |
deps/lld/test/ELF/ppc64-weak-undef-call.s+6-5| ... | ... | @@ -2,13 +2,14 @@ |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t |
| 4 | 4 | # RUN: ld.lld %t -o %t2 |
| 5 | # RUN: llvm-objdump -d %t2 | FileCheck %s | |
| 5 | # RUN: llvm-objdump -d --no-show-raw-insn %t2 | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t |
| 8 | 8 | # RUN: ld.lld %t -o %t2 |
| 9 | # RUN: llvm-objdump -d %t2 | FileCheck %s | |
| 9 | # RUN: llvm-objdump -d --no-show-raw-insn %t2 | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | # CHECK: Disassembly of section .text: |
| 12 | # CHECK-EMPTY: | |
| 12 | 13 | |
| 13 | 14 | .text |
| 14 | 15 | .global _start |
| ... | ... | @@ -23,6 +24,6 @@ _start: |
| 23 | 24 | # be unreachable. But, we should link successfully. We should not, however, |
| 24 | 25 | # generate a .plt entry (this would be wasted space). For now, we do nothing |
| 25 | 26 | # (leaving the zero relative offset present in the input). |
| 26 | # CHECK: 10010000: {{.*}} bl .+0 | |
| 27 | # CHECK: 10010004: {{.*}} nop | |
| 28 | # CHECK: 10010008: {{.*}} blr | |
| 27 | # CHECK: 10010000: bl .+0 | |
| 28 | # CHECK: 10010004: nop | |
| 29 | # CHECK: 10010008: blr |
deps/lld/test/ELF/pr34660.s+3-2| ... | ... | @@ -13,11 +13,12 @@ |
| 13 | 13 | # correct symbol. |
| 14 | 14 | |
| 15 | 15 | # DISASM: Disassembly of section .text: |
| 16 | # DISASM-EMPTY: | |
| 16 | 17 | # DISASM-NEXT: $x.0: |
| 17 | # DISASM-NEXT: 10000: 28 00 08 58 ldr x8, #65540 | |
| 18 | # DISASM-NEXT: 10000: 28 00 10 58 ldr x8, #131076 | |
| 18 | 19 | |
| 19 | 20 | # SYM: Symbol table '.symtab' |
| 20 | # SYM: 0000000000020004 0 NOTYPE LOCAL DEFAULT 5 patatino | |
| 21 | # SYM: 0000000000030004 0 NOTYPE LOCAL DEFAULT 6 patatino | |
| 21 | 22 | |
| 22 | 23 | ldr x8, patatino |
| 23 | 24 | .data |
deps/lld/test/ELF/pr34872.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: llvm-mc %p/Inputs/undefined-error.s -filetype=obj \ |
| 4 | 4 | # RUN: -triple=x86_64-pc-linux -o %t2.o |
| 5 | 5 | # RUN: ld.lld -shared %t2.o -o %t2.so |
| 6 | # RUN: not ld.lld %t2.so %t.o -o /dev/null 2>&1 | FileCheck %s | |
| 6 | # RUN: not ld.lld --allow-shlib-undefined %t2.so %t.o -o /dev/null 2>&1 | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | # CHECK: undefined symbol: fmod |
| 9 | 9 | # Check we're not emitting other diagnostics for this symbol. |
deps/lld/test/ELF/pr36475.s+1-1| ... | ... | @@ -10,7 +10,7 @@ |
| 10 | 10 | # RUN: echo " .got.plt : { BYTE(42); *(.got); } : ph_data" >> %t.script |
| 11 | 11 | # RUN: echo "}" >> %t.script |
| 12 | 12 | # RUN: ld.lld -T %t.script %t.o -o %t.elf |
| 13 | # RUN: llvm-readobj -l -elf-output-style=GNU %t.elf | FileCheck %s | |
| 13 | # RUN: llvm-readelf -l %t.elf | FileCheck %s | |
| 14 | 14 | |
| 15 | 15 | # CHECK: Section to Segment mapping: |
| 16 | 16 | # CHECK-NEXT: Segment Sections... |
deps/lld/test/ELF/pre_init_fini_array.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2 |
| 4 | 4 | // RUN: ld.lld %t2 -o %t2.so -shared |
| 5 | 5 | // RUN: ld.lld %t %t2.so -o %t2 |
| 6 | // RUN: llvm-readobj -r -symbols -sections -dynamic-table %t2 | FileCheck %s | |
| 6 | // RUN: llvm-readobj -r --symbols --sections --dynamic-table %t2 | FileCheck %s | |
| 7 | 7 | // RUN: llvm-objdump -d %t2 | FileCheck --check-prefix=DISASM %s |
| 8 | 8 | |
| 9 | 9 | .globl _start |
deps/lld/test/ELF/pre_init_fini_array_missing.s+2| ... | ... | @@ -20,6 +20,7 @@ _start: |
| 20 | 20 | // ... |
| 21 | 21 | |
| 22 | 22 | // CHECK: Disassembly of section .text: |
| 23 | // CHECK-EMPTY: | |
| 23 | 24 | // CHECK-NEXT: _start: |
| 24 | 25 | // CHECK-NEXT: 201000: e8 fb ff ff ff callq -5 |
| 25 | 26 | // CHECK-NEXT: 201005: e8 f6 ff ff ff callq -10 |
| ... | ... | @@ -31,6 +32,7 @@ _start: |
| 31 | 32 | // In position-independent binaries, they resolve to .text too. |
| 32 | 33 | |
| 33 | 34 | // PIE: Disassembly of section .text: |
| 35 | // PIE-EMPTY: | |
| 34 | 36 | // PIE-NEXT: _start: |
| 35 | 37 | // PIE-NEXT: 1000: e8 fb ff ff ff callq -5 |
| 36 | 38 | // PIE-NEXT: 1005: e8 f6 ff ff ff callq -10 |
deps/lld/test/ELF/progname.s+3-3| ... | ... | @@ -4,18 +4,18 @@ |
| 4 | 4 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t2.s -o %t2.o |
| 5 | 5 | // RUN: ld.lld -shared %t2.o -o %t2.so |
| 6 | 6 | // RUN: ld.lld -o %t %t.o %t2.so |
| 7 | // RUN: llvm-readobj -dyn-symbols %t | FileCheck %s | |
| 7 | // RUN: llvm-readobj --dyn-syms %t | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | // RUN: echo "VER_1 { global: bar; };" > %t.script |
| 10 | 10 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux \ |
| 11 | 11 | // RUN: %p/Inputs/progname-ver.s -o %t-ver.o |
| 12 | 12 | // RUN: ld.lld -shared -o %t.so -version-script %t.script %t-ver.o |
| 13 | 13 | // RUN: ld.lld -o %t %t.o %t.so |
| 14 | // RUN: llvm-readobj -dyn-symbols %t | FileCheck %s | |
| 14 | // RUN: llvm-readobj --dyn-syms %t | FileCheck %s | |
| 15 | 15 | |
| 16 | 16 | // RUN: echo "{ _start; };" > %t.dynlist |
| 17 | 17 | // RUN: ld.lld -dynamic-list %t.dynlist -o %t %t.o %t.so |
| 18 | // RUN: llvm-readobj -dyn-symbols %t | FileCheck %s | |
| 18 | // RUN: llvm-readobj --dyn-syms %t | FileCheck %s | |
| 19 | 19 | |
| 20 | 20 | // CHECK: Name: __progname |
| 21 | 21 | // CHECK-NEXT: Value: 0x201000 |
deps/lld/test/ELF/program-header-layout.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | # RUN: ld.lld %t -o %t2 |
| 4 | # RUN: llvm-readobj -sections -program-headers %t2 | FileCheck %s | |
| 4 | # RUN: llvm-readobj --sections -l %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # Check that different output sections with the same flags are merged into a |
| 7 | 7 | # single Read/Write PT_LOAD. |
deps/lld/test/ELF/protected-shared.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/protected-shared.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld -shared %t2.o -o %t2.so |
| 5 | 5 | // RUN: ld.lld %t.o %t2.so -o %t |
| 6 | // RUN: llvm-readobj -t --dyn-symbols %t | FileCheck %s | |
| 6 | // RUN: llvm-readobj --symbols --dyn-symbols %t | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | .global _start |
| 9 | 9 | _start: |
deps/lld/test/ELF/push-state.s+2-2| ... | ... | @@ -19,11 +19,11 @@ |
| 19 | 19 | // RUN: ld.lld -shared %t3.o -soname libfoo -o %t.so |
| 20 | 20 | |
| 21 | 21 | // RUN: ld.lld -o %t.exe -push-state -as-needed %t.so %t1.o |
| 22 | // RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=AS-NEEDED %s | |
| 22 | // RUN: llvm-readobj --dynamic-table %t.exe | FileCheck -check-prefix=AS-NEEDED %s | |
| 23 | 23 | // AS-NEEDED-NOT: NEEDED Shared library: [libfoo] |
| 24 | 24 | |
| 25 | 25 | // RUN: ld.lld -o %t.exe -push-state -as-needed -pop-state %t.so %t1.o |
| 26 | // RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=NO-AS-NEEDED %s | |
| 26 | // RUN: llvm-readobj --dynamic-table %t.exe | FileCheck -check-prefix=NO-AS-NEEDED %s | |
| 27 | 27 | // NO-AS-NEEDED: NEEDED Shared library: [libfoo] |
| 28 | 28 | |
| 29 | 29 |
deps/lld/test/ELF/rel-addend-with-rela-input.s+2-2| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # uses Elf_Rela |
| 4 | 4 | |
| 5 | 5 | # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t-rela.o |
| 6 | # RUN: llvm-readobj -h -s -section-data -relocations %t-rela.o | FileCheck -check-prefix INPUT-RELA %s | |
| 6 | # RUN: llvm-readobj -h -S --section-data -r %t-rela.o | FileCheck -check-prefix INPUT-RELA %s | |
| 7 | 7 | # INPUT-RELA: ElfHeader { |
| 8 | 8 | # INPUT-RELA: Class: 64-bit |
| 9 | 9 | # INPUT-RELA: DataEncoding: BigEndian |
| ... | ... | @@ -21,7 +21,7 @@ |
| 21 | 21 | # Previously the addend to the dynamic relocation in the .data section was not copied if |
| 22 | 22 | # the input file used RELA and the output uses REL. Check that it works now: |
| 23 | 23 | # RUN: ld.lld -shared -o %t.so %t-rela.o -verbose |
| 24 | # RUN: llvm-readobj -h -s -section-data -relocations %t.so | FileCheck -check-prefix RELA-TO-REL %s | |
| 24 | # RUN: llvm-readobj -h -S --section-data -r %t.so | FileCheck -check-prefix RELA-TO-REL %s | |
| 25 | 25 | # RELA-TO-REL: ElfHeader { |
| 26 | 26 | # RELA-TO-REL: Class: 64-bit |
| 27 | 27 | # RELA-TO-REL: DataEncoding: BigEndian |
deps/lld/test/ELF/rel-offset.s+2-2| ... | ... | @@ -10,6 +10,6 @@ |
| 10 | 10 | .quad foo |
| 11 | 11 | |
| 12 | 12 | // CHECK: Section ({{.*}}) .rela.dyn { |
| 13 | // CHECK-NEXT: 0x1000 R_X86_64_64 foo 0x0 | |
| 14 | // CHECK-NEXT: 0x1008 R_X86_64_64 foo 0x0 | |
| 13 | // CHECK-NEXT: 0x2000 R_X86_64_64 foo 0x0 | |
| 14 | // CHECK-NEXT: 0x2008 R_X86_64_64 foo 0x0 | |
| 15 | 15 | // CHECK-NEXT: } |
deps/lld/test/ELF/relative-dynamic-reloc-pie.s+4-4| ... | ... | @@ -1,14 +1,14 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld -pie %t.o -o %t.pie |
| 4 | # RUN: llvm-readobj -r -dyn-symbols %t.pie | FileCheck %s | |
| 4 | # RUN: llvm-readobj -r --dyn-syms %t.pie | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | ## Test that we create R_X86_64_RELATIVE relocations with -pie. |
| 7 | 7 | # CHECK: Relocations [ |
| 8 | 8 | # CHECK-NEXT: Section ({{.*}}) .rela.dyn { |
| 9 | # CHECK-NEXT: 0x2000 R_X86_64_RELATIVE - 0x2000 | |
| 10 | # CHECK-NEXT: 0x2008 R_X86_64_RELATIVE - 0x2008 | |
| 11 | # CHECK-NEXT: 0x2010 R_X86_64_RELATIVE - 0x2009 | |
| 9 | # CHECK-NEXT: 0x3000 R_X86_64_RELATIVE - 0x3000 | |
| 10 | # CHECK-NEXT: 0x3008 R_X86_64_RELATIVE - 0x3008 | |
| 11 | # CHECK-NEXT: 0x3010 R_X86_64_RELATIVE - 0x3009 | |
| 12 | 12 | # CHECK-NEXT: } |
| 13 | 13 | # CHECK-NEXT: ] |
| 14 | 14 |
deps/lld/test/ELF/relative-dynamic-reloc-ppc64.s deleted-71| ... | ... | @@ -1,71 +0,0 @@ |
| 1 | // REQUIRES: ppc | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o | |
| 3 | // RUN: ld.lld -shared %t.o -o %t.so | |
| 4 | // RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s | |
| 5 | ||
| 6 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o | |
| 7 | // RUN: ld.lld -shared %t.o -o %t.so | |
| 8 | // RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s | |
| 9 | ||
| 10 | // Test that we create R_PPC64_RELATIVE relocations but don't put any | |
| 11 | // symbols in the dynamic symbol table. | |
| 12 | ||
| 13 | // CHECK: Relocations [ | |
| 14 | // CHECK-NEXT: Section ({{.*}}) .rela.dyn { | |
| 15 | // CHECK-NEXT: 0x[[FOO_ADDR:.*]] R_PPC64_RELATIVE - 0x[[FOO_ADDR]] | |
| 16 | // CHECK-NEXT: 0x[[BAR_ADDR:.*]] R_PPC64_RELATIVE - 0x[[BAR_ADDR]] | |
| 17 | // CHECK-NEXT: 0x10010 R_PPC64_RELATIVE - 0x10009 | |
| 18 | // CHECK-NEXT: 0x{{.*}} R_PPC64_RELATIVE - 0x[[ZED_ADDR:.*]] | |
| 19 | // CHECK-NEXT: 0x{{.*}} R_PPC64_RELATIVE - 0x[[FOO_ADDR]] | |
| 20 | // CHECK-NEXT: 0x10028 R_PPC64_ADDR64 external 0x0 | |
| 21 | // CHECK-NEXT: } | |
| 22 | // CHECK-NEXT: ] | |
| 23 | ||
| 24 | // CHECK: Symbols [ | |
| 25 | // CHECK: Name: foo | |
| 26 | // CHECK-NEXT: Value: 0x[[FOO_ADDR]] | |
| 27 | // CHECK: Name: bar | |
| 28 | // CHECK-NEXT: Value: 0x[[BAR_ADDR]] | |
| 29 | // CHECK: Name: zed | |
| 30 | // CHECK-NEXT: Value: 0x[[ZED_ADDR]] | |
| 31 | // CHECK: ] | |
| 32 | ||
| 33 | // CHECK: DynamicSymbols [ | |
| 34 | // CHECK-NEXT: Symbol { | |
| 35 | // CHECK-NEXT: Name: | |
| 36 | // CHECK-NEXT: Value: 0x0 | |
| 37 | // CHECK-NEXT: Size: 0 | |
| 38 | // CHECK-NEXT: Binding: Local | |
| 39 | // CHECK-NEXT: Type: None | |
| 40 | // CHECK-NEXT: Other: 0 | |
| 41 | // CHECK-NEXT: Section: Undefined | |
| 42 | // CHECK-NEXT: } | |
| 43 | // CHECK-NEXT: Symbol { | |
| 44 | // CHECK-NEXT: Name: external | |
| 45 | // CHECK-NEXT: Value: 0x0 | |
| 46 | // CHECK-NEXT: Size: 0 | |
| 47 | // CHECK-NEXT: Binding: Global | |
| 48 | // CHECK-NEXT: Type: None | |
| 49 | // CHECK-NEXT: Other: 0 | |
| 50 | // CHECK-NEXT: Section: Undefined | |
| 51 | // CHECK-NEXT: } | |
| 52 | // CHECK-NEXT: ] | |
| 53 | ||
| 54 | .data | |
| 55 | foo: | |
| 56 | .quad foo | |
| 57 | ||
| 58 | .hidden bar | |
| 59 | .global bar | |
| 60 | bar: | |
| 61 | .quad bar | |
| 62 | .quad bar + 1 | |
| 63 | ||
| 64 | .hidden zed | |
| 65 | .comm zed,1 | |
| 66 | .quad zed | |
| 67 | ||
| 68 | .section abc,"aw" | |
| 69 | .quad foo | |
| 70 | ||
| 71 | .quad external |
deps/lld/test/ELF/relative-dynamic-reloc.s+3-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld -shared %t.o -o %t.so |
| 4 | // RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols -r --dyn-syms %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // Test that we create R_X86_64_RELATIVE relocations but don't put any |
| 7 | 7 | // symbols in the dynamic symbol table. |
| ... | ... | @@ -10,10 +10,10 @@ |
| 10 | 10 | // CHECK-NEXT: Section ({{.*}}) .rela.dyn { |
| 11 | 11 | // CHECK-NEXT: 0x[[FOO_ADDR:.*]] R_X86_64_RELATIVE - 0x[[FOO_ADDR]] |
| 12 | 12 | // CHECK-NEXT: 0x[[BAR_ADDR:.*]] R_X86_64_RELATIVE - 0x[[BAR_ADDR]] |
| 13 | // CHECK-NEXT: 0x1010 R_X86_64_RELATIVE - 0x1009 | |
| 13 | // CHECK-NEXT: 0x2010 R_X86_64_RELATIVE - 0x2009 | |
| 14 | 14 | // CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x[[ZED_ADDR:.*]] |
| 15 | 15 | // CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x[[FOO_ADDR]] |
| 16 | // CHECK-NEXT: 0x1028 R_X86_64_64 external 0x0 | |
| 16 | // CHECK-NEXT: 0x2028 R_X86_64_64 external 0x0 | |
| 17 | 17 | // CHECK-NEXT: } |
| 18 | 18 | // CHECK-NEXT: ] |
| 19 | 19 |
deps/lld/test/ELF/relocatable-bss.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o |
| 3 | 3 | # RUN: ld.lld -r %t1.o -o %t |
| 4 | # RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj --file-headers --sections -l --symbols -r %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | ## We check here that .bss does not occupy the space in file. |
| 7 | 7 | ## If it would, the SectionHeaderOffset would have offset about 5 megabytes. |
deps/lld/test/ELF/relocatable-comdat-multiple.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/relocatable-comdat-multiple.s -o %t2.o |
| 4 | 4 | # RUN: ld.lld -r %t.o %t2.o -o %t |
| 5 | # RUN: llvm-readobj -elf-section-groups %t | FileCheck %s | |
| 5 | # RUN: llvm-readobj --elf-section-groups %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: Groups { |
| 8 | 8 | # CHECK-NEXT: Group { |
deps/lld/test/ELF/relocatable-comdat.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld -r %t.o %t.o -o %t |
| 4 | # RUN: llvm-readobj -elf-section-groups -sections %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj --elf-section-groups --sections %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: Name: .text.bar |
| 7 | 7 | # CHECK-NEXT: Type: SHT_PROGBITS |
deps/lld/test/ELF/relocatable-comdat2.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld -r %t.o -o %t |
| 4 | # RUN: llvm-readobj -elf-section-groups -s %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj --elf-section-groups -S %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | ## Check .foo was not merged. |
| 7 | 7 | # CHECK: Sections [ |
deps/lld/test/ELF/relocatable-comment.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o |
| 3 | 3 | # RUN: ld.lld -r %t1.o -o %t |
| 4 | # RUN: llvm-readobj -s -section-data %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj -S --section-data %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: Name: .comment |
| 7 | 7 | # CHECK-NEXT: Type: SHT_PROGBITS |
deps/lld/test/ELF/relocatable-common.s+6-6| ... | ... | @@ -1,17 +1,17 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o |
| 3 | 3 | # RUN: ld.lld -r %t1.o -o %t |
| 4 | # RUN: llvm-readobj -symbols -r %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj --symbols -r %t | FileCheck %s | |
| 5 | 5 | # RUN: ld.lld -r --no-define-common %t1.o -o %t |
| 6 | # RUN: llvm-readobj -symbols -r %t | FileCheck %s | |
| 6 | # RUN: llvm-readobj --symbols -r %t | FileCheck %s | |
| 7 | 7 | # RUN: ld.lld -r --define-common %t1.o -o %t |
| 8 | # RUN: llvm-readobj -symbols -r %t | FileCheck -check-prefix=DEFCOMM %s | |
| 8 | # RUN: llvm-readobj --symbols -r %t | FileCheck -check-prefix=DEFCOMM %s | |
| 9 | 9 | # RUN: ld.lld -r -d %t1.o -o %t |
| 10 | # RUN: llvm-readobj -symbols -r %t | FileCheck -check-prefix=DEFCOMM %s | |
| 10 | # RUN: llvm-readobj --symbols -r %t | FileCheck -check-prefix=DEFCOMM %s | |
| 11 | 11 | # RUN: ld.lld -r -dc %t1.o -o %t |
| 12 | # RUN: llvm-readobj -symbols -r %t | FileCheck -check-prefix=DEFCOMM %s | |
| 12 | # RUN: llvm-readobj --symbols -r %t | FileCheck -check-prefix=DEFCOMM %s | |
| 13 | 13 | # RUN: ld.lld -r -dp %t1.o -o %t |
| 14 | # RUN: llvm-readobj -symbols -r %t | FileCheck -check-prefix=DEFCOMM %s | |
| 14 | # RUN: llvm-readobj --symbols -r %t | FileCheck -check-prefix=DEFCOMM %s | |
| 15 | 15 | |
| 16 | 16 | # CHECK: Symbol { |
| 17 | 17 | # CHECK: Name: common |
deps/lld/test/ELF/relocatable-compressed-input.s+2-2| ... | ... | @@ -1,11 +1,11 @@ |
| 1 | 1 | # REQUIRES: x86, zlib |
| 2 | 2 | |
| 3 | 3 | # RUN: llvm-mc -compress-debug-sections=zlib-gnu -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 |
| 4 | # RUN: llvm-readobj -sections %t1 | FileCheck -check-prefix=GNU %s | |
| 4 | # RUN: llvm-readobj --sections %t1 | FileCheck -check-prefix=GNU %s | |
| 5 | 5 | # GNU: Name: .zdebug_str |
| 6 | 6 | |
| 7 | 7 | # RUN: ld.lld %t1 -o %t2 -r |
| 8 | # RUN: llvm-readobj -sections -section-data %t2 | FileCheck %s | |
| 8 | # RUN: llvm-readobj --sections --section-data %t2 | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | ## Check we uncompress section and remove ".z" prefix specific for zlib-gnu compression. |
| 11 | 11 | # CHECK: Section { |
deps/lld/test/ELF/relocatable-eh-frame-hdr.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld --eh-frame-hdr -r %t.o -o %t |
| 4 | # RUN: llvm-readobj -s %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj -S %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: Sections [ |
| 7 | 7 | # CHECK-NOT: Name: .eh_frame_hdr |
deps/lld/test/ELF/relocatable-eh-frame.s deleted-19| ... | ... | @@ -1,19 +0,0 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o | |
| 3 | # RUN: ld.lld -r %t.o %t.o -o %t | |
| 4 | # RUN: llvm-readobj -r %t | FileCheck %s | |
| 5 | # RUN: ld.lld %t -o %t.so -shared | |
| 6 | # RUN: llvm-objdump -h %t.so | FileCheck --check-prefix=DSO %s | |
| 7 | ||
| 8 | # DSO: .eh_frame 00000034 | |
| 9 | ||
| 10 | # CHECK: Relocations [ | |
| 11 | # CHECK-NEXT: Section ({{.*}}) .rela.eh_frame { | |
| 12 | # CHECK-NEXT: 0x20 R_X86_64_PC32 .foo 0x0 | |
| 13 | # CHECK-NEXT: 0x50 R_X86_64_NONE - 0x0 | |
| 14 | # CHECK-NEXT: } | |
| 15 | # CHECK-NEXT: ] | |
| 16 | ||
| 17 | .section .foo,"aG",@progbits,bar,comdat | |
| 18 | .cfi_startproc | |
| 19 | .cfi_endproc |
deps/lld/test/ELF/relocatable-ehframe.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocatable-ehframe.s -o %t2.o |
| 4 | 4 | # RUN: ld.lld -r %t1.o %t2.o -o %t |
| 5 | # RUN: llvm-readobj -r -s -section-data %t | FileCheck %s | |
| 5 | # RUN: llvm-readobj -r -S --section-data %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: Name: .strtab |
| 8 | 8 | # CHECK-NEXT: Type: SHT_STRTAB |
deps/lld/test/ELF/relocatable-empty-archive.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: rm -f %t.a |
| 3 | 3 | # RUN: llvm-ar rc %t.a |
| 4 | 4 | # RUN: ld.lld -m elf_x86_64 %t.a -o %t -r |
| 5 | # RUN: llvm-readobj -file-headers %t | FileCheck %s | |
| 5 | # RUN: llvm-readobj --file-headers %t | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: Format: ELF64-x86-64 |
| 8 | 8 | # CHECK: Arch: x86_64 |
deps/lld/test/ELF/relocatable-many-sections.s+8-8| ... | ... | @@ -7,25 +7,25 @@ |
| 7 | 7 | |
| 8 | 8 | ## Check we emit a valid ELF header when |
| 9 | 9 | ## sections amount is greater than SHN_LORESERVE. |
| 10 | # RUN: llvm-readobj -file-headers %t | FileCheck %s --check-prefix=HDR | |
| 10 | # RUN: llvm-readobj --file-headers %t | FileCheck %s --check-prefix=HDR | |
| 11 | 11 | # HDR: ElfHeader { |
| 12 | 12 | # HDR: SectionHeaderCount: 0 (65544) |
| 13 | 13 | # HDR-NEXT: StringTableSectionIndex: 65535 (65542) |
| 14 | 14 | |
| 15 | 15 | ## Check that: |
| 16 | 16 | ## 1) 65541 is the index of .shstrtab section. |
| 17 | ## 2) .symtab_shndxr is linked with .symtab. | |
| 18 | ## 3) .symtab_shndxr entry size and alignment == 4. | |
| 19 | ## 4) .symtab_shndxr has size equal to | |
| 20 | ## (sizeof(.symtab) / entsize(.symtab)) * entsize(.symtab_shndxr) = 0x4 * 0x180048 / 0x18 == 0x04000c | |
| 17 | ## 2) .symtab_shndx is linked with .symtab. | |
| 18 | ## 3) .symtab_shndx entry size and alignment == 4. | |
| 19 | ## 4) .symtab_shndx has size equal to | |
| 20 | ## (sizeof(.symtab) / entsize(.symtab)) * entsize(.symtab_shndx) = 0x4 * 0x180078 / 0x18 == 0x040014 | |
| 21 | 21 | |
| 22 | 22 | # RUN: llvm-readelf -sections -symbols %t | FileCheck %s |
| 23 | 23 | # [Nr] Name Type Address Off Size ES Flg Lk Inf Al |
| 24 | 24 | # CHECK: [65539] .note.GNU-stack PROGBITS 0000000000000000 000040 000000 00 0 0 1 |
| 25 | 25 | # CHECK: [65540] .symtab SYMTAB 0000000000000000 000040 180078 18 65543 65539 8 |
| 26 | # CHECK: [65541] .symtab_shndxr SYMTAB SECTION INDICES 0000000000000000 1800b8 040014 04 65540 0 4 | |
| 27 | # CHECK: [65542] .shstrtab STRTAB 0000000000000000 1c00cc 0f0045 00 0 0 1 | |
| 28 | # CHECK: [65543] .strtab STRTAB 0000000000000000 2b0111 00000c 00 0 0 1 | |
| 26 | # CHECK: [65541] .symtab_shndx SYMTAB SECTION INDICES 0000000000000000 1800b8 040014 04 65540 0 4 | |
| 27 | # CHECK: [65542] .shstrtab STRTAB 0000000000000000 1c00cc 0f0044 00 0 0 1 | |
| 28 | # CHECK: [65543] .strtab STRTAB 0000000000000000 2b0110 00000c 00 0 0 1 | |
| 29 | 29 | |
| 30 | 30 | # 5) Check we are able to represent symbol foo with section (.bar) index > 0xFF00 (SHN_LORESERVE). |
| 31 | 31 | # CHECK: GLOBAL DEFAULT 65538 foo |
deps/lld/test/ELF/relocatable-rel-iplt.s+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=i686-- %s -o %t1.o |
| 3 | 3 | # RUN: ld.lld -r %t1.o -o %t2.o |
| 4 | # RUN: llvm-readobj -t %t2.o | FileCheck %s | |
| 4 | # RUN: llvm-readobj --symbols %t2.o | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // CHECK: Symbols [ |
| 7 | 7 | // CHECK-NEXT: Symbol { |
| ... | ... | @@ -14,7 +14,7 @@ |
| 14 | 14 | // CHECK-NEXT: Section: Undefined (0x0) |
| 15 | 15 | // CHECK-NEXT: } |
| 16 | 16 | // CHECK-NEXT: Symbol { |
| 17 | // CHECK-NEXT: Name: (0) | |
| 17 | // CHECK-NEXT: Name: .text (0) | |
| 18 | 18 | // CHECK-NEXT: Value: 0x0 |
| 19 | 19 | // CHECK-NEXT: Size: 0 |
| 20 | 20 | // CHECK-NEXT: Binding: Local (0x0) |
deps/lld/test/ELF/relocatable-script.s+1-1| ... | ... | @@ -2,6 +2,6 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux -o %t1.o %s |
| 3 | 3 | # RUN: echo "SECTIONS { .foo : { BYTE(0x0) } }" > %t.script |
| 4 | 4 | # RUN: ld.lld -r %t1.o -script %t.script -o %t2.o |
| 5 | # RUN: llvm-readobj -sections %t2.o | FileCheck %s | |
| 5 | # RUN: llvm-readobj --sections %t2.o | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: Name: .foo |
deps/lld/test/ELF/relocatable-section-symbol.s+1-1| ... | ... | @@ -13,7 +13,7 @@ |
| 13 | 13 | |
| 14 | 14 | # RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o |
| 15 | 15 | # RUN: ld.lld -r -o %t %t.o %t.o |
| 16 | # RUN: llvm-readobj -r -s -section-data %t | FileCheck --check-prefix=REL %s | |
| 16 | # RUN: llvm-readobj -r -S --section-data %t | FileCheck --check-prefix=REL %s | |
| 17 | 17 | |
| 18 | 18 | |
| 19 | 19 | # REL: Section { |
deps/lld/test/ELF/relocatable-symbol-name.s+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld -r %t.o -o %t |
| 4 | # RUN: llvm-readobj -t %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj --symbols %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # Test that the section symbol has st_name equal to zero. GNU objdump |
| 7 | 7 | # requires this to print relocations against the section. |
| ... | ... | @@ -17,7 +17,7 @@ |
| 17 | 17 | # CHECK-NEXT: Section: |
| 18 | 18 | # CHECK-NEXT: } |
| 19 | 19 | # CHECK-NEXT: Symbol { |
| 20 | # CHECK-NEXT: Name: (0) | |
| 20 | # CHECK-NEXT: Name: .text (0) | |
| 21 | 21 | # CHECK-NEXT: Value: |
| 22 | 22 | # CHECK-NEXT: Size: |
| 23 | 23 | # CHECK-NEXT: Binding: |
deps/lld/test/ELF/relocatable-symbols.s+5-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: ld.lld -r %t -o %tout |
| 4 | 4 | # RUN: llvm-objdump -d %tout | FileCheck -check-prefix=DISASM %s |
| 5 | 5 | # RUN: llvm-readobj -r %t | FileCheck -check-prefix=RELOC %s |
| 6 | # RUN: llvm-readobj -symbols -r %tout | FileCheck -check-prefix=SYMBOL %s | |
| 6 | # RUN: llvm-readobj --symbols -r %tout | FileCheck -check-prefix=SYMBOL %s | |
| 7 | 7 | |
| 8 | 8 | # DISASM: _start: |
| 9 | 9 | # DISASM-NEXT: 0: {{.*}} callq 0 |
| ... | ... | @@ -18,12 +18,16 @@ |
| 18 | 18 | # DISASM-NEXT: 2d: {{.*}} callq 0 |
| 19 | 19 | # DISASM-NEXT: 32: {{.*}} callq 0 |
| 20 | 20 | # DISASM-NEXT: 37: {{.*}} callq 0 |
| 21 | # DISASM-EMPTY: | |
| 21 | 22 | # DISASM-NEXT: Disassembly of section foo: |
| 23 | # DISASM-EMPTY: | |
| 22 | 24 | # DISASM-NEXT: foo: |
| 23 | 25 | # DISASM-NEXT: 0: 90 nop |
| 24 | 26 | # DISASM-NEXT: 1: 90 nop |
| 25 | 27 | # DISASM-NEXT: 2: 90 nop |
| 28 | # DISASM-EMPTY: | |
| 26 | 29 | # DISASM-NEXT: Disassembly of section bar: |
| 30 | # DISASM-EMPTY: | |
| 27 | 31 | # DISASM-NEXT: bar: |
| 28 | 32 | # DISASM-NEXT: 0: 90 nop |
| 29 | 33 | # DISASM-NEXT: 1: 90 nop |
deps/lld/test/ELF/relocatable-visibility.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld -r %t.o -o %t1 |
| 4 | # RUN: llvm-readobj -t %t1 | FileCheck --check-prefix=RELOCATABLE %s | |
| 4 | # RUN: llvm-readobj --symbols %t1 | FileCheck --check-prefix=RELOCATABLE %s | |
| 5 | 5 | |
| 6 | 6 | # RELOCATABLE: Name: foo |
| 7 | 7 | # RELOCATABLE-NEXT: Value: 0x0 |
deps/lld/test/ELF/relocatable.s+5-4| ... | ... | @@ -3,18 +3,18 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocatable.s -o %t2.o |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocatable2.s -o %t3.o |
| 5 | 5 | # RUN: ld.lld -r %t1.o %t2.o %t3.o -o %t |
| 6 | # RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s | |
| 6 | # RUN: llvm-readobj --file-headers --sections -l --symbols -r %t | FileCheck %s | |
| 7 | 7 | # RUN: llvm-objdump -section-headers %t | FileCheck -check-prefix=SECTION %s |
| 8 | 8 | # RUN: llvm-objdump -s -d %t | FileCheck -check-prefix=CHECKTEXT %s |
| 9 | 9 | |
| 10 | 10 | ## Test --relocatable alias |
| 11 | 11 | # RUN: ld.lld --relocatable %t1.o %t2.o %t3.o -o %t |
| 12 | # RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s | |
| 12 | # RUN: llvm-readobj --file-headers --sections -l --symbols -r %t | FileCheck %s | |
| 13 | 13 | # RUN: llvm-objdump -s -d %t | FileCheck -check-prefix=CHECKTEXT %s |
| 14 | 14 | |
| 15 | 15 | ## Verify that we can use our relocation output as input to produce executable |
| 16 | 16 | # RUN: ld.lld -e main %t -o %texec |
| 17 | # RUN: llvm-readobj -file-headers %texec | FileCheck -check-prefix=CHECKEXE %s | |
| 17 | # RUN: llvm-readobj --file-headers %texec | FileCheck -check-prefix=CHECKEXE %s | |
| 18 | 18 | |
| 19 | 19 | # CHECK: ElfHeader { |
| 20 | 20 | # CHECK-NEXT: Ident { |
| ... | ... | @@ -53,7 +53,7 @@ |
| 53 | 53 | # CHECK-NEXT: } |
| 54 | 54 | |
| 55 | 55 | # SECTION: Sections: |
| 56 | # SECTION: Idx Name Size Address Type | |
| 56 | # SECTION: Idx Name Size VMA Type | |
| 57 | 57 | # SECTION: 0 00000000 0000000000000000 |
| 58 | 58 | # SECTION: 1 .text 00000056 0000000000000000 TEXT |
| 59 | 59 | # SECTION: 2 .rela.text 00000090 0000000000000000 |
| ... | ... | @@ -64,6 +64,7 @@ |
| 64 | 64 | # SECTION: 7 .strtab 0000002d 0000000000000000 |
| 65 | 65 | |
| 66 | 66 | # CHECKTEXT: Disassembly of section .text: |
| 67 | # CHECKTEXT-EMPTY: | |
| 67 | 68 | # CHECKTEXT-NEXT: main: |
| 68 | 69 | # CHECKTEXT-NEXT: 0: c7 04 25 00 00 00 00 05 00 00 00 movl $5, 0 |
| 69 | 70 | # CHECKTEXT-NEXT: b: c7 04 25 00 00 00 00 07 00 00 00 movl $7, 0 |
deps/lld/test/ELF/relocation-b-aarch64.test+9-9| ... | ... | @@ -8,6 +8,7 @@ |
| 8 | 8 | # immediate. We use this property to overwrite instructions with a branch. |
| 9 | 9 | |
| 10 | 10 | # CHECK: Disassembly of section .text: |
| 11 | # CHECK-EMPTY: | |
| 11 | 12 | # CHECK-NEXT: foo: |
| 12 | 13 | # CHECK-NEXT: 210000: 01 00 00 14 b #4 |
| 13 | 14 | # CHECK: bar: |
| ... | ... | @@ -37,12 +38,11 @@ Sections: |
| 37 | 38 | Type: R_AARCH64_JUMP26 |
| 38 | 39 | |
| 39 | 40 | Symbols: |
| 40 | Local: | |
| 41 | - Type: STT_FUNC | |
| 42 | Section: .text | |
| 43 | Name: foo | |
| 44 | Value: 0 | |
| 45 | - Type: STT_FUNC | |
| 46 | Section: .text | |
| 47 | Name: bar | |
| 48 | Value: 4 | |
| 41 | - Type: STT_FUNC | |
| 42 | Section: .text | |
| 43 | Name: foo | |
| 44 | Value: 0 | |
| 45 | - Type: STT_FUNC | |
| 46 | Section: .text | |
| 47 | Name: bar | |
| 48 | Value: 4 |
deps/lld/test/ELF/relocation-before-merge-start.s+1-1| ... | ... | @@ -4,6 +4,6 @@ |
| 4 | 4 | // CHECK: relocation-before-merge-start.s.tmp.o:(.foo): offset is outside the section |
| 5 | 5 | |
| 6 | 6 | .data |
| 7 | .long .foo - 1 | |
| 7 | .quad .foo - 1 | |
| 8 | 8 | .section	.foo,"aM",@progbits,4 |
| 9 | 9 | .quad 0 |
deps/lld/test/ELF/relocation-copy-align-common.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: %p/Inputs/relocation-copy-align-common.s -o %t2.o |
| 5 | 5 | # RUN: ld.lld -shared %t2.o -o %t.so |
| 6 | 6 | # RUN: ld.lld --hash-style=sysv %t.o %t.so -o %t3 |
| 7 | # RUN: llvm-readobj -s -r --expand-relocs %t3 | FileCheck %s | |
| 7 | # RUN: llvm-readobj -S -r --expand-relocs %t3 | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | # CHECK: Section { |
| 10 | 10 | # CHECK: Index: |
deps/lld/test/ELF/relocation-copy-align.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy-align.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld -shared %t2.o -o %t.so |
| 5 | 5 | // RUN: ld.lld %t.o %t.so -o %t3 |
| 6 | // RUN: llvm-readobj -s -r --expand-relocs %t3 | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S -r --expand-relocs %t3 | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | .global _start |
| 9 | 9 | _start: |
deps/lld/test/ELF/relocation-copy-flags.s+7-7| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy.s -o %t2.o |
| 5 | 5 | // RUN: ld.lld %t2.o -o %t2.so -shared |
| 6 | 6 | // RUN: ld.lld --hash-style=sysv %t.o %t2.so -o %t.exe |
| 7 | // RUN: llvm-readobj -s -section-data -r %t.exe | FileCheck %s | |
| 7 | // RUN: llvm-readobj -S --section-data -r %t.exe | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | .global _start |
| 10 | 10 | _start: |
| ... | ... | @@ -30,7 +30,7 @@ _start: |
| 30 | 30 | // CHECK-NEXT: AddressAlignment: 4 |
| 31 | 31 | // CHECK-NEXT: EntrySize: 0 |
| 32 | 32 | // CHECK-NEXT: SectionData ( |
| 33 | // CHECK-NEXT: 0000: 00402000 | |
| 33 | // CHECK-NEXT: 0000: 10302000 | |
| 34 | 34 | // CHECK-NEXT: ) |
| 35 | 35 | |
| 36 | 36 | // CHECK: Name: bar |
| ... | ... | @@ -39,8 +39,8 @@ _start: |
| 39 | 39 | // CHECK-NEXT: SHF_ALLOC |
| 40 | 40 | // CHECK-NEXT: SHF_WRITE |
| 41 | 41 | // CHECK-NEXT: ] |
| 42 | // CHECK-NEXT: Address: 0x202000 | |
| 43 | // CHECK-NEXT: Offset: 0x2000 | |
| 42 | // CHECK-NEXT: Address: 0x203000 | |
| 43 | // CHECK-NEXT: Offset: 0x3000 | |
| 44 | 44 | // CHECK-NEXT: Size: 8 |
| 45 | 45 | // CHECK-NEXT: Link: 0 |
| 46 | 46 | // CHECK-NEXT: Info: 0 |
| ... | ... | @@ -55,7 +55,7 @@ _start: |
| 55 | 55 | // CHECK-NEXT: Flags [ |
| 56 | 56 | // CHECK-NEXT: ] |
| 57 | 57 | // CHECK-NEXT: Address: 0x0 |
| 58 | // CHECK-NEXT: Offset: 0x30B0 | |
| 58 | // CHECK-NEXT: Offset: 0x3008 | |
| 59 | 59 | // CHECK-NEXT: Size: 8 |
| 60 | 60 | // CHECK-NEXT: Link: 0 |
| 61 | 61 | // CHECK-NEXT: Info: 0 |
| ... | ... | @@ -67,7 +67,7 @@ _start: |
| 67 | 67 | |
| 68 | 68 | // CHECK: Relocations [ |
| 69 | 69 | // CHECK-NEXT: Section (4) .rela.dyn { |
| 70 | // CHECK-NEXT: 0x204000 R_X86_64_COPY x 0x0 | |
| 71 | // CHECK-NEXT: 0x202000 R_X86_64_64 z 0x0 | |
| 70 | // CHECK-NEXT: 0x203010 R_X86_64_COPY x 0x0 | |
| 71 | // CHECK-NEXT: 0x203000 R_X86_64_64 z 0x0 | |
| 72 | 72 | // CHECK-NEXT: } |
| 73 | 73 | // CHECK-NEXT: ] |
deps/lld/test/ELF/relocation-copy-i686.s+2-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %p/Inputs/relocation-copy.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld -shared %t2.o -o %t.so |
| 5 | 5 | // RUN: ld.lld -e main %t.o %t.so -o %t3 |
| 6 | // RUN: llvm-readobj -s -r --expand-relocs %t3 | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S -r --expand-relocs %t3 | FileCheck %s | |
| 7 | 7 | // RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=CODE %s |
| 8 | 8 | |
| 9 | 9 | .text |
| ... | ... | @@ -57,6 +57,7 @@ movl $9, z |
| 57 | 57 | // 4206608 = 0x403000 + 16 |
| 58 | 58 | // 4206612 = 0x403000 + 16 + 4 |
| 59 | 59 | // CODE: Disassembly of section .text: |
| 60 | // CODE-EMPTY: | |
| 60 | 61 | // CODE-NEXT: main: |
| 61 | 62 | // CODE-NEXT: 401000: c7 05 00 30 40 00 05 00 00 00 movl $5, 4206592 |
| 62 | 63 | // CODE-NEXT: 40100a: c7 05 10 30 40 00 07 00 00 00 movl $7, 4206608 |
deps/lld/test/ELF/relocation-copy-relro.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy-relro.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld -shared %t2.o -o %t.so |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv %t.o %t.so -o %t3 |
| 6 | // RUN: llvm-readobj -program-headers -s -r %t3 | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S -l -r %t3 | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | // CHECK: Name: .bss.rel.ro (48) |
| 9 | 9 | // CHECK-NEXT: Type: SHT_NOBITS (0x8) |
deps/lld/test/ELF/relocation-copy.s+2-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld -shared %t2.o -o %t.so |
| 5 | 5 | // RUN: ld.lld %t.o %t.so -o %t3 |
| 6 | // RUN: llvm-readobj -s -r --expand-relocs %t3 | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S -r --expand-relocs %t3 | FileCheck %s | |
| 7 | 7 | // RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=CODE %s |
| 8 | 8 | |
| 9 | 9 | .text |
| ... | ... | @@ -58,6 +58,7 @@ movl $z, %edx |
| 58 | 58 | // 2109456 = 0x203000 + 16 |
| 59 | 59 | // 2109460 = 0x203000 + 16 + 4 |
| 60 | 60 | // CODE: Disassembly of section .text: |
| 61 | // CODE-EMPTY: | |
| 61 | 62 | // CODE-NEXT: _start: |
| 62 | 63 | // CODE-NEXT: 201000: {{.*}} movl $5, 2109440 |
| 63 | 64 | // CODE-NEXT: 20100b: {{.*}} movl $7, 2109456 |
deps/lld/test/ELF/relocation-dtrace.test deleted-24| ... | ... | @@ -1,24 +0,0 @@ |
| 1 | # RUN: yaml2obj %s -o %t.o | |
| 2 | # RUN: ld.lld -shared %t.o -o /dev/null | |
| 3 | ||
| 4 | # Test that we can handle R_X86_64_NONE as produced by dtrace. | |
| 5 | ||
| 6 | !ELF | |
| 7 | FileHeader: | |
| 8 | Class: ELFCLASS64 | |
| 9 | Data: ELFDATA2LSB | |
| 10 | OSABI: ELFOSABI_FREEBSD | |
| 11 | Type: ET_REL | |
| 12 | Machine: EM_X86_64 | |
| 13 | Sections: | |
| 14 | - Name: .text | |
| 15 | Type: SHT_PROGBITS | |
| 16 | Flags: [ SHF_ALLOC ] | |
| 17 | - Name: .rela.text | |
| 18 | Type: SHT_RELA | |
| 19 | Link: .symtab | |
| 20 | Info: .text | |
| 21 | Relocations: | |
| 22 | - Offset: 0x0000000000000000 | |
| 23 | Symbol: '' | |
| 24 | Type: R_X86_64_NONE |
deps/lld/test/ELF/relocation-group.test+3-3| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: yaml2obj %s -o %t.o |
| 2 | 2 | # RUN: ld.lld %t.o %t.o -o %t -r |
| 3 | # RUN: llvm-readobj -s %t | FileCheck %s | |
| 3 | # RUN: llvm-readobj -S %t | FileCheck %s | |
| 4 | 4 | |
| 5 | 5 | # CHECK: Name: .text.foo |
| 6 | 6 | # CHECK: Name: .rela.text.foo |
| ... | ... | @@ -39,5 +39,5 @@ Sections: |
| 39 | 39 | Symbol: foo |
| 40 | 40 | Type: R_X86_64_64 |
| 41 | 41 | Symbols: |
| 42 | Global: | |
| 43 | - Name: foo | |
| 42 | - Name: foo | |
| 43 | Binding: STB_GLOBAL |
deps/lld/test/ELF/relocation-i686.s+17-14| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld -shared %t2.o -o %t2.so |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv %t %t2.so -o %t2 |
| 6 | // RUN: llvm-readobj -s %t2 | FileCheck --check-prefix=ADDR %s | |
| 6 | // RUN: llvm-readobj -S %t2 | FileCheck --check-prefix=ADDR %s | |
| 7 | 7 | // RUN: llvm-objdump -d %t2 | FileCheck %s |
| 8 | 8 | |
| 9 | 9 | .global _start |
| ... | ... | @@ -26,10 +26,12 @@ R_386_PC32_2: |
| 26 | 26 | nop |
| 27 | 27 | |
| 28 | 28 | // CHECK: Disassembly of section .R_386_32: |
| 29 | // CHECK-EMPTY: | |
| 29 | 30 | // CHECK-NEXT: R_386_32: |
| 30 | 31 | // CHECK-NEXT: 401000: {{.*}} movl $4198401, %edx |
| 31 | 32 | |
| 32 | 33 | // CHECK: Disassembly of section .R_386_PC32: |
| 34 | // CHECK-EMPTY: | |
| 33 | 35 | // CHECK-NEXT: R_386_PC32: |
| 34 | 36 | // CHECK-NEXT: 401005: e8 04 00 00 00 calll 4 |
| 35 | 37 | |
| ... | ... | @@ -49,30 +51,32 @@ movl bar@GOT, %eax |
| 49 | 51 | // ADDR-NEXT: Offset: 0x1040 |
| 50 | 52 | // ADDR-NEXT: Size: 32 |
| 51 | 53 | |
| 52 | // ADDR: Name: .got ( | |
| 54 | // ADDR: Name: .got.plt ( | |
| 53 | 55 | // ADDR-NEXT: Type: SHT_PROGBITS |
| 54 | 56 | // ADDR-NEXT: Flags [ |
| 55 | 57 | // ADDR-NEXT: SHF_ALLOC |
| 56 | 58 | // ADDR-NEXT: SHF_WRITE |
| 57 | 59 | // ADDR-NEXT: ] |
| 58 | // ADDR-NEXT: Address: 0x403078 | |
| 60 | // ADDR-NEXT: Address: 0x403000 | |
| 59 | 61 | // ADDR-NEXT: Offset: |
| 60 | // ADDR-NEXT: Size: 8 | |
| 62 | // ADDR-NEXT: Size: | |
| 61 | 63 | |
| 62 | 64 | .section .R_386_GOTPC,"ax",@progbits |
| 63 | 65 | R_386_GOTPC: |
| 64 | 66 | movl $_GLOBAL_OFFSET_TABLE_, %eax |
| 65 | 67 | |
| 66 | // 0x402078 + 8 - 0x401014 = 4204 | |
| 68 | // 0x403000 (.got.plt) - 0x401014 = 8300 | |
| 67 | 69 | |
| 68 | 70 | // CHECK: Disassembly of section .R_386_GOTPC: |
| 71 | // CHECK-EMPTY: | |
| 69 | 72 | // CHECK-NEXT: R_386_GOTPC: |
| 70 | // CHECK-NEXT: 401014: {{.*}} movl $8300, %eax | |
| 73 | // CHECK-NEXT: 401014: {{.*}} movl $8172, %eax | |
| 71 | 74 | |
| 72 | 75 | .section .dynamic_reloc, "ax",@progbits |
| 73 | 76 | call bar |
| 74 | 77 | // addr(.plt) + 16 - (0x401019 + 5) = 50 |
| 75 | 78 | // CHECK: Disassembly of section .dynamic_reloc: |
| 79 | // CHECK-EMPTY: | |
| 76 | 80 | // CHECK-NEXT: .dynamic_reloc: |
| 77 | 81 | // CHECK-NEXT: 401019: e8 32 00 00 00 calll 50 |
| 78 | 82 | |
| ... | ... | @@ -84,13 +88,12 @@ R_386_GOT32: |
| 84 | 88 | movl bar+8@GOT, %eax |
| 85 | 89 | movl zed+4@GOT, %eax |
| 86 | 90 | |
| 87 | // 4294967288 = 0xFFFFFFF8 = got[0](0x402070) - .got(0x402070) - sizeof(.got)(8) | |
| 88 | // 4294967292 = 0xFFFFFFFC = got[1](0x402074) - .got(0x402070) - sizeof(.got)(8) | |
| 89 | // 0xFFFFFFF8 + 8 = 0 | |
| 90 | // 0xFFFFFFFC + 4 = 0 | |
| 91 | // 4294963320 = 0xfffff078 = got[0](0x402078) - .got.plt(0x403000) | |
| 92 | // 4294963324 = 0xfffff07c = got[1](0x40207c) - .got(0x403000) | |
| 91 | 93 | // CHECK: Disassembly of section .R_386_GOT32: |
| 94 | // CHECK-EMPTY: | |
| 92 | 95 | // CHECK-NEXT: R_386_GOT32: |
| 93 | // CHECK-NEXT: 40101e: a1 f8 ff ff ff movl 4294967288, %eax | |
| 94 | // CHECK-NEXT: 401023: a1 fc ff ff ff movl 4294967292, %eax | |
| 95 | // CHECK-NEXT: 401028: a1 00 00 00 00 movl 0, %eax | |
| 96 | // CHECK-NEXT: 40102d: a1 00 00 00 00 movl 0, %eax | |
| 96 | // CHECK-NEXT: 40101e: a1 78 f0 ff ff movl 4294963320, %eax | |
| 97 | // CHECK-NEXT: 401023: a1 7c f0 ff ff movl 4294963324, %eax | |
| 98 | // CHECK-NEXT: 401028: a1 80 f0 ff ff movl 4294963328, %eax | |
| 99 | // CHECK-NEXT: 40102d: a1 80 f0 ff ff movl 4294963328, %eax |
deps/lld/test/ELF/relocation-local.s+2| ... | ... | @@ -19,6 +19,7 @@ R_X86_64_32: |
| 19 | 19 | // FIXME: this would be far more self evident if llvm-objdump printed |
| 20 | 20 | // constants in hex. |
| 21 | 21 | // CHECK: Disassembly of section .text2: |
| 22 | // CHECK-EMPTY: | |
| 22 | 23 | // CHECK-NEXT: R_X86_64_32: |
| 23 | 24 | // CHECK-NEXT: 201009: {{.*}} movl $2101257, %edx |
| 24 | 25 | |
| ... | ... | @@ -27,6 +28,7 @@ R_X86_64_32S: |
| 27 | 28 | movq lulz - 0x100000, %rdx |
| 28 | 29 | |
| 29 | 30 | // CHECK: Disassembly of section .R_X86_64_32S: |
| 31 | // CHECK-EMPTY: | |
| 30 | 32 | // CHECK-NEXT: R_X86_64_32S: |
| 31 | 33 | // CHECK-NEXT: {{.*}}: {{.*}} movq 1052681, %rdx |
| 32 | 34 |
deps/lld/test/ELF/relocation-non-alloc.s+12-12| ... | ... | @@ -2,12 +2,12 @@ |
| 2 | 2 | |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t |
| 4 | 4 | // RUN: ld.lld %t -o %t2 -shared --apply-dynamic-relocs |
| 5 | // RUN: llvm-readobj -s -section-data -r %t2 | FileCheck -check-prefix CHECK -check-prefix APPLYDYNREL %s | |
| 5 | // RUN: llvm-readobj -S --section-data -r %t2 | FileCheck -check-prefix CHECK -check-prefix APPLYDYNREL %s | |
| 6 | 6 | |
| 7 | 7 | // RUN: ld.lld %t -o %t2 -shared |
| 8 | // RUN: llvm-readobj -s -section-data -r %t2 | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s | |
| 8 | // RUN: llvm-readobj -S --section-data -r %t2 | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s | |
| 9 | 9 | // RUN: ld.lld %t -o %t2 -shared --no-apply-dynamic-relocs |
| 10 | // RUN: llvm-readobj -s -section-data -r %t2 | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s | |
| 10 | // RUN: llvm-readobj -S --section-data -r %t2 | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s | |
| 11 | 11 | |
| 12 | 12 | // APPLYDYNREL: Name: .data |
| 13 | 13 | // APPLYDYNREL-NEXT: Type: SHT_PROGBITS |
| ... | ... | @@ -15,15 +15,15 @@ |
| 15 | 15 | // APPLYDYNREL-NEXT: SHF_ALLOC |
| 16 | 16 | // APPLYDYNREL-NEXT: SHF_WRITE |
| 17 | 17 | // APPLYDYNREL-NEXT: ] |
| 18 | // APPLYDYNREL-NEXT: Address: 0x1000 | |
| 19 | // APPLYDYNREL-NEXT: Offset: 0x1000 | |
| 18 | // APPLYDYNREL-NEXT: Address: 0x2000 | |
| 19 | // APPLYDYNREL-NEXT: Offset: 0x2000 | |
| 20 | 20 | // APPLYDYNREL-NEXT: Size: 16 |
| 21 | 21 | // APPLYDYNREL-NEXT: Link: 0 |
| 22 | 22 | // APPLYDYNREL-NEXT: Info: 0 |
| 23 | 23 | // APPLYDYNREL-NEXT: AddressAlignment: 1 |
| 24 | 24 | // APPLYDYNREL-NEXT: EntrySize: 0 |
| 25 | 25 | // APPLYDYNREL-NEXT: SectionData ( |
| 26 | // APPLYDYNREL-NEXT: 0000: 00100000 00000000 00000000 00000000 | |
| 26 | // APPLYDYNREL-NEXT: 0000: 00200000 00000000 00000000 00000000 | |
| 27 | 27 | // APPLYDYNREL-NEXT: ) |
| 28 | 28 | |
| 29 | 29 | // NOAPPLYDYNREL: Name: .data |
| ... | ... | @@ -32,8 +32,8 @@ |
| 32 | 32 | // NOAPPLYDYNREL-NEXT: SHF_ALLOC |
| 33 | 33 | // NOAPPLYDYNREL-NEXT: SHF_WRITE |
| 34 | 34 | // NOAPPLYDYNREL-NEXT: ] |
| 35 | // NOAPPLYDYNREL-NEXT: Address: 0x1000 | |
| 36 | // NOAPPLYDYNREL-NEXT: Offset: 0x1000 | |
| 35 | // NOAPPLYDYNREL-NEXT: Address: 0x2000 | |
| 36 | // NOAPPLYDYNREL-NEXT: Offset: 0x2000 | |
| 37 | 37 | // NOAPPLYDYNREL-NEXT: Size: 16 |
| 38 | 38 | // NOAPPLYDYNREL-NEXT: Link: 0 |
| 39 | 39 | // NOAPPLYDYNREL-NEXT: Info: 0 |
| ... | ... | @@ -55,14 +55,14 @@ |
| 55 | 55 | // CHECK-NEXT: AddressAlignment: 1 |
| 56 | 56 | // CHECK-NEXT: EntrySize: 0 |
| 57 | 57 | // CHECK-NEXT: SectionData ( |
| 58 | // CHECK-NEXT: 0000: 00100000 00000000 00100000 00000000 | |
| 59 | // CHECK-NEXT: 0010: 00100000 00000000 00100000 00000000 | |
| 58 | // CHECK-NEXT: 0000: 00200000 00000000 00200000 00000000 | |
| 59 | // CHECK-NEXT: 0010: 00200000 00000000 00200000 00000000 | |
| 60 | 60 | // CHECK-NEXT: ) |
| 61 | 61 | |
| 62 | 62 | // CHECK: Relocations [ |
| 63 | 63 | // CHECK-NEXT: Section ({{.}}) .rela.dyn { |
| 64 | // CHECK-NEXT: 0x1000 R_X86_64_RELATIVE - 0x1000 | |
| 65 | // CHECK-NEXT: 0x1008 R_X86_64_64 zed 0x0 | |
| 64 | // CHECK-NEXT: 0x2000 R_X86_64_RELATIVE - 0x2000 | |
| 65 | // CHECK-NEXT: 0x2008 R_X86_64_64 zed 0x0 | |
| 66 | 66 | // CHECK-NEXT: } |
| 67 | 67 | // CHECK-NEXT: ] |
| 68 | 68 |
deps/lld/test/ELF/relocation-none-aarch64.s created+26| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | # REQUIRES: aarch64 | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-musl %s -o %t.o | |
| 4 | # RUN: ld.lld --gc-sections %t.o -o %t | |
| 5 | # RUN: llvm-readelf -S -r %t | FileCheck %s | |
| 6 | ||
| 7 | # Test that we discard R_AARCH64_NONE, but respect the references it creates | |
| 8 | # among sections. | |
| 9 | ||
| 10 | # CHECK: .data | |
| 11 | # CHECK: There are no relocations in this file. | |
| 12 | ||
| 13 | # RUN: ld.lld -r %t.o -o %t | |
| 14 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s | |
| 15 | ||
| 16 | # RELOC: Section ({{.*}}) .rela.text { | |
| 17 | # RELOC-NEXT: 0x0 R_AARCH64_NONE .data 0x0 | |
| 18 | # RELOC-NEXT: } | |
| 19 | ||
| 20 | .globl _start | |
| 21 | _start: | |
| 22 | ret | |
| 23 | .reloc 0, R_AARCH64_NONE, .data | |
| 24 | ||
| 25 | .data | |
| 26 | .long 0 |
deps/lld/test/ELF/relocation-none-aarch64.test deleted-24| ... | ... | @@ -1,24 +0,0 @@ |
| 1 | # REQUIRES: aarch64 | |
| 2 | ||
| 3 | # RUN: yaml2obj %s -o %t.o | |
| 4 | # RUN: ld.lld %t.o -o /dev/null | |
| 5 | ||
| 6 | !ELF | |
| 7 | FileHeader: | |
| 8 | Class: ELFCLASS64 | |
| 9 | Data: ELFDATA2LSB | |
| 10 | Type: ET_REL | |
| 11 | Machine: EM_AARCH64 | |
| 12 | Sections: | |
| 13 | - Type: SHT_PROGBITS | |
| 14 | Name: .text | |
| 15 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 16 | Content: "00000000" | |
| 17 | - Type: SHT_RELA | |
| 18 | Name: .rela.text | |
| 19 | Link: .symtab | |
| 20 | Info: .text | |
| 21 | Relocations: | |
| 22 | - Offset: 0 | |
| 23 | Symbol: '' | |
| 24 | Type: R_AARCH64_NONE |
deps/lld/test/ELF/relocation-none-arm.s created+26| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | # REQUIRES: arm | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=armv7-linux-musl %s -o %t.o | |
| 4 | # RUN: ld.lld --gc-sections %t.o -o %t | |
| 5 | # RUN: llvm-readelf -S -r %t | FileCheck %s | |
| 6 | ||
| 7 | # Test that we discard R_ARM_NONE, but respect the references it creates among | |
| 8 | # sections. | |
| 9 | ||
| 10 | # CHECK: .data | |
| 11 | # CHECK: There are no relocations in this file. | |
| 12 | ||
| 13 | # RUN: ld.lld -r %t.o -o %t | |
| 14 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s | |
| 15 | ||
| 16 | # RELOC: Section ({{.*}}) .rel.text { | |
| 17 | # RELOC-NEXT: 0x0 R_ARM_NONE .data 0x0 | |
| 18 | # RELOC-NEXT: } | |
| 19 | ||
| 20 | .globl _start | |
| 21 | _start: | |
| 22 | nop | |
| 23 | .reloc 0, R_ARM_NONE, .data | |
| 24 | ||
| 25 | .data | |
| 26 | .long 0 |
deps/lld/test/ELF/relocation-none-i386.s created+26| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=i386-linux-musl %s -o %t.o | |
| 4 | # RUN: ld.lld --gc-sections %t.o -o %t | |
| 5 | # RUN: llvm-readelf -S -r %t | FileCheck %s | |
| 6 | ||
| 7 | # Test that we discard R_386_NONE, but respect the | |
| 8 | # references it creates among sections. | |
| 9 | ||
| 10 | # CHECK: .data | |
| 11 | # CHECK: There are no relocations in this file. | |
| 12 | ||
| 13 | # RUN: ld.lld -r %t.o -o %t | |
| 14 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s | |
| 15 | ||
| 16 | # RELOC: Section ({{.*}}) .rel.text { | |
| 17 | # RELOC-NEXT: 0x0 R_386_NONE .data 0x0 | |
| 18 | # RELOC-NEXT: } | |
| 19 | ||
| 20 | .globl _start | |
| 21 | _start: | |
| 22 | ret | |
| 23 | .reloc 0, R_386_NONE, .data | |
| 24 | ||
| 25 | .data | |
| 26 | .long 0 |
deps/lld/test/ELF/relocation-none-i686.test deleted-23| ... | ... | @@ -1,23 +0,0 @@ |
| 1 | # RUN: yaml2obj %s -o %t.o | |
| 2 | # RUN: ld.lld %t.o -o /dev/null | |
| 3 | ||
| 4 | # Test that we can handle R_386_NONE. | |
| 5 | ||
| 6 | !ELF | |
| 7 | FileHeader: | |
| 8 | Class: ELFCLASS32 | |
| 9 | Data: ELFDATA2LSB | |
| 10 | Type: ET_REL | |
| 11 | Machine: EM_386 | |
| 12 | Sections: | |
| 13 | - Name: .text | |
| 14 | Type: SHT_PROGBITS | |
| 15 | Flags: [ SHF_ALLOC ] | |
| 16 | - Name: .rel.text | |
| 17 | Type: SHT_RELA | |
| 18 | Link: .symtab | |
| 19 | Info: .text | |
| 20 | Relocations: | |
| 21 | - Offset: 0x0000000000000000 | |
| 22 | Symbol: '' | |
| 23 | Type: R_386_NONE |
deps/lld/test/ELF/relocation-none-x86-64.s created+26| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-linux-musl %s -o %t.o | |
| 4 | # RUN: ld.lld --gc-sections %t.o -o %t | |
| 5 | # RUN: llvm-readelf -S -r %t | FileCheck %s | |
| 6 | ||
| 7 | # Test that we discard R_X86_64_NONE, but respect the | |
| 8 | # references it creates among sections. | |
| 9 | ||
| 10 | # CHECK: .data | |
| 11 | # CHECK: There are no relocations in this file. | |
| 12 | ||
| 13 | # RUN: ld.lld -r %t.o -o %t | |
| 14 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s | |
| 15 | ||
| 16 | # RELOC: Section ({{.*}}) .rela.text { | |
| 17 | # RELOC-NEXT: 0x0 R_X86_64_NONE .data 0x0 | |
| 18 | # RELOC-NEXT: } | |
| 19 | ||
| 20 | .globl _start | |
| 21 | _start: | |
| 22 | ret | |
| 23 | .reloc 0, R_X86_64_NONE, .data | |
| 24 | ||
| 25 | .data | |
| 26 | .long 0 |
deps/lld/test/ELF/relocation-past-merge-end.s+1-1| ... | ... | @@ -4,6 +4,6 @@ |
| 4 | 4 | // CHECK: relocation-past-merge-end.s.tmp.o:(.foo): offset is outside the section |
| 5 | 5 | |
| 6 | 6 | .data |
| 7 | .long .foo + 10 | |
| 7 | .quad .foo + 10 | |
| 8 | 8 | .section	.foo,"aM",@progbits,4 |
| 9 | 9 | .quad 0 |
deps/lld/test/ELF/relocation-relative-synthetic.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld %t.o -o %t -pie |
| 4 | # RUN: llvm-readobj -dyn-relocations %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj --dyn-relocations %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: Dynamic Relocations { |
| 7 | 7 | # CHECK-NEXT: } |
deps/lld/test/ELF/relocation-relative-weak.s+5-3| ... | ... | @@ -1,10 +1,12 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/dummy-shared.s -o %t1.o | |
| 3 | # RUN: ld.lld %t1.o -shared -o %t1.so | |
| 2 | 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | # RUN: ld.lld %t.o -o %t -pie | |
| 4 | # RUN: llvm-readobj -dyn-relocations %t | FileCheck %s | |
| 5 | # RUN: ld.lld %t.o %t1.so -o %t -pie | |
| 6 | # RUN: llvm-readobj --dyn-relocations %t | FileCheck %s | |
| 5 | 7 | |
| 6 | 8 | # CHECK: Dynamic Relocations { |
| 7 | # CHECK-NEXT: 0x2018 R_X86_64_JUMP_SLOT w 0x0 | |
| 9 | # CHECK-NEXT: 0x3018 R_X86_64_JUMP_SLOT w 0x0 | |
| 8 | 10 | # CHECK-NEXT: } |
| 9 | 11 | |
| 10 | 12 | .globl _start |
deps/lld/test/ELF/relocation-shared.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -shared -o %t.so |
| 4 | // RUN: llvm-readobj -r -s -section-data %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -r -S --section-data %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // CHECK: Name: foo |
| 7 | 7 | // CHECK-NEXT: Type: SHT_PROGBITS |
deps/lld/test/ELF/relocation-size-shared.s+1| ... | ... | @@ -18,6 +18,7 @@ |
| 18 | 18 | // RELOCSHARED-NEXT:] |
| 19 | 19 | |
| 20 | 20 | // DISASM: Disassembly of section test |
| 21 | // DISASM-EMPTY: | |
| 21 | 22 | // DISASM: _data: |
| 22 | 23 | // DISASM-NEXT: 201000: 19 00 |
| 23 | 24 | // DISASM-NEXT: 201002: 00 00 |
deps/lld/test/ELF/relocation-size.s+2| ... | ... | @@ -11,6 +11,7 @@ |
| 11 | 11 | // NORELOC-NEXT: ] |
| 12 | 12 | |
| 13 | 13 | // DISASM: Disassembly of section test: |
| 14 | // DISASM-EMPTY: | |
| 14 | 15 | // DISASM-NEXT: _data: |
| 15 | 16 | // DISASM-NEXT: 201000: 19 00 |
| 16 | 17 | // DISASM-NEXT: 201002: 00 00 |
| ... | ... | @@ -56,6 +57,7 @@ |
| 56 | 57 | // RELOCSHARED-NEXT: ] |
| 57 | 58 | |
| 58 | 59 | // DISASMSHARED: Disassembly of section test: |
| 60 | // DISASMSHARED-EMPTY: | |
| 59 | 61 | // DISASMSHARED-NEXT: _data: |
| 60 | 62 | // DISASMSHARED-NEXT: ... |
| 61 | 63 | // DISASMSHARED-NEXT: 1018: 19 00 |
deps/lld/test/ELF/relocation-undefined-weak.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld %t -o %tout |
| 4 | // RUN: llvm-readobj -sections %tout | FileCheck %s | |
| 4 | // RUN: llvm-readobj --sections %tout | FileCheck %s | |
| 5 | 5 | // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix DISASM |
| 6 | 6 | |
| 7 | 7 | // Check that undefined weak symbols are treated as having a VA of 0. |
deps/lld/test/ELF/relocation.s+21-16| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t2 |
| 4 | 4 | // RUN: ld.lld %t2 -soname fixed-length-string.so -o %t2.so -shared |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv %t %t2.so -o %t3 |
| 6 | // RUN: llvm-readobj -s %t3 | FileCheck --check-prefix=SEC %s | |
| 6 | // RUN: llvm-readobj -S %t3 | FileCheck --check-prefix=SEC %s | |
| 7 | 7 | // RUN: llvm-objdump -s -d %t3 | FileCheck %s |
| 8 | 8 | |
| 9 | 9 | // SEC: Name: .plt |
| ... | ... | @@ -16,35 +16,35 @@ |
| 16 | 16 | // SEC-NEXT: Offset: 0x1030 |
| 17 | 17 | // SEC-NEXT: Size: 48 |
| 18 | 18 | |
| 19 | // SEC: Name: .got.plt | |
| 19 | // SEC: Name: .got | |
| 20 | 20 | // SEC-NEXT: Type: SHT_PROGBITS |
| 21 | 21 | // SEC-NEXT: Flags [ |
| 22 | 22 | // SEC-NEXT: SHF_ALLOC |
| 23 | 23 | // SEC-NEXT: SHF_WRITE |
| 24 | 24 | // SEC-NEXT: ] |
| 25 | // SEC-NEXT: Address: 0x202000 | |
| 26 | // SEC-NEXT: Offset: 0x2000 | |
| 27 | // SEC-NEXT: Size: 40 | |
| 25 | // SEC-NEXT: Address: 0x2020F0 | |
| 26 | // SEC-NEXT: Offset: | |
| 27 | // SEC-NEXT: Size: 8 | |
| 28 | 28 | // SEC-NEXT: Link: 0 |
| 29 | 29 | // SEC-NEXT: Info: 0 |
| 30 | 30 | // SEC-NEXT: AddressAlignment: 8 |
| 31 | 31 | // SEC-NEXT: EntrySize: 0 |
| 32 | // SEC-NEXT: } | |
| 32 | // SEC-NEXT: } | |
| 33 | 33 | |
| 34 | // SEC: Name: .got | |
| 34 | // SEC: Name: .got.plt | |
| 35 | 35 | // SEC-NEXT: Type: SHT_PROGBITS |
| 36 | 36 | // SEC-NEXT: Flags [ |
| 37 | 37 | // SEC-NEXT: SHF_ALLOC |
| 38 | 38 | // SEC-NEXT: SHF_WRITE |
| 39 | 39 | // SEC-NEXT: ] |
| 40 | // SEC-NEXT: Address: 0x2030F0 | |
| 41 | // SEC-NEXT: Offset: | |
| 42 | // SEC-NEXT: Size: 8 | |
| 40 | // SEC-NEXT: Address: 0x203000 | |
| 41 | // SEC-NEXT: Offset: 0x3000 | |
| 42 | // SEC-NEXT: Size: 40 | |
| 43 | 43 | // SEC-NEXT: Link: 0 |
| 44 | 44 | // SEC-NEXT: Info: 0 |
| 45 | 45 | // SEC-NEXT: AddressAlignment: 8 |
| 46 | 46 | // SEC-NEXT: EntrySize: 0 |
| 47 | // SEC-NEXT: } | |
| 47 | // SEC-NEXT: } | |
| 48 | 48 | |
| 49 | 49 | .section .text,"ax",@progbits,unique,1 |
| 50 | 50 | .global _start |
| ... | ... | @@ -58,6 +58,7 @@ lulz: |
| 58 | 58 | nop |
| 59 | 59 | |
| 60 | 60 | // CHECK: Disassembly of section .text: |
| 61 | // CHECK-EMPTY: | |
| 61 | 62 | // CHECK-NEXT: _start: |
| 62 | 63 | // CHECK-NEXT: 201000: e8 04 00 00 00 callq 4 |
| 63 | 64 | // CHECK-NEXT: 201005: |
| ... | ... | @@ -74,6 +75,7 @@ R_X86_64_32: |
| 74 | 75 | // FIXME: this would be far more self evident if llvm-objdump printed |
| 75 | 76 | // constants in hex. |
| 76 | 77 | // CHECK: Disassembly of section .text2: |
| 78 | // CHECK-EMPTY: | |
| 77 | 79 | // CHECK-NEXT: R_X86_64_32: |
| 78 | 80 | // CHECK-NEXT: 20100a: {{.*}} movl $2101258, %edx |
| 79 | 81 | |
| ... | ... | @@ -83,6 +85,7 @@ R_X86_64_32S: |
| 83 | 85 | movq lulz - 0x100000, %rdx |
| 84 | 86 | |
| 85 | 87 | // CHECK: Disassembly of section .R_X86_64_32S: |
| 88 | // CHECK-EMPTY: | |
| 86 | 89 | // CHECK-NEXT: R_X86_64_32S: |
| 87 | 90 | // CHECK-NEXT: {{.*}}: {{.*}} movq 1052681, %rdx |
| 88 | 91 | |
| ... | ... | @@ -94,6 +97,7 @@ R_X86_64_PC32: |
| 94 | 97 | //16 is a size of PLT[0] |
| 95 | 98 | // 0x201030 + 16 - (0x201017 + 5) = 20 |
| 96 | 99 | // CHECK: Disassembly of section .R_X86_64_PC32: |
| 100 | // CHECK-EMPTY: | |
| 97 | 101 | // CHECK-NEXT: R_X86_64_PC32: |
| 98 | 102 | // CHECK-NEXT: 201017: {{.*}} callq 36 |
| 99 | 103 | // CHECK-NEXT: 20101c: {{.*}} movl $2101312, %eax |
| ... | ... | @@ -104,6 +108,7 @@ R_X86_64_32S_2: |
| 104 | 108 | mov bar2, %eax |
| 105 | 109 | // plt is at 0x201030. The second plt entry is at 0x201050 == 69712 |
| 106 | 110 | // CHECK: Disassembly of section .R_X86_64_32S_2: |
| 111 | // CHECK-EMPTY: | |
| 107 | 112 | // CHECK-NEXT: R_X86_64_32S_2: |
| 108 | 113 | // CHECK-NEXT: 201021: {{.*}} movl 2101328, %eax |
| 109 | 114 | |
| ... | ... | @@ -113,16 +118,16 @@ R_X86_64_64: |
| 113 | 118 | .quad R_X86_64_64 |
| 114 | 119 | |
| 115 | 120 | // CHECK: Contents of section .R_X86_64_64: |
| 116 | // CHECK-NEXT: 2002c0 c0022000 00000000 | |
| 121 | // CHECK-NEXT: 2002f8 f8022000 00000000 | |
| 117 | 122 | |
| 118 | 123 | .section .R_X86_64_GOTPCREL,"a",@progbits |
| 119 | 124 | .global R_X86_64_GOTPCREL |
| 120 | 125 | R_X86_64_GOTPCREL: |
| 121 | 126 | .long zed@gotpcrel |
| 122 | 127 | |
| 123 | // 0x2030F0(.got) - 0x2002c8(.R_X86_64_GOTPCREL) = 0x2e28 | |
| 128 | // 0x2020F0(.got) - 0x2002c8(.R_X86_64_GOTPCREL) = 0x1e28 | |
| 124 | 129 | // CHECK: Contents of section .R_X86_64_GOTPCREL |
| 125 | // CHECK-NEXT: 2002c8 282e0000 | |
| 130 | // CHECK-NEXT: 200300 f01d0000 | |
| 126 | 131 | |
| 127 | 132 | .section .R_X86_64_GOT32,"a",@progbits |
| 128 | 133 | .global R_X86_64_GOT32 |
| ... | ... | @@ -130,11 +135,11 @@ R_X86_64_GOT32: |
| 130 | 135 | .long zed@got |
| 131 | 136 | |
| 132 | 137 | // CHECK: Contents of section .R_X86_64_GOT32: |
| 133 | // CHECK-NEXT: f8ffffff | |
| 138 | // CHECK-NEXT: f0f0ffff | |
| 134 | 139 | |
| 135 | 140 | |
| 136 | 141 | // CHECK: Contents of section .R_X86_64_GOT64: |
| 137 | // CHECK-NEXT: f8ffffff ffffffff | |
| 142 | // CHECK-NEXT: f0f0ffff ffffffff | |
| 138 | 143 | .section .R_X86_64_GOT64,"a",@progbits |
| 139 | 144 | .global R_X86_64_GOT64 |
| 140 | 145 | R_X86_64_GOT64: |
deps/lld/test/ELF/relro-bss.s created+44| ... | ... | @@ -0,0 +1,44 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -o %t | |
| 4 | # RUN: llvm-readelf -l %t | FileCheck --check-prefix=SEG %s | |
| 5 | # RUN: llvm-readelf -S %t | FileCheck %s | |
| 6 | ||
| 7 | # We have 2 RW PT_LOAD segments. p_offset p_vaddr p_paddr p_filesz of the first | |
| 8 | # should match PT_GNU_RELRO. | |
| 9 | # Because .bss.rel.ro (nobits) doesn't take space, p_filesz < p_memsz. | |
| 10 | ||
| 11 | # Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align | |
| 12 | # SEG: LOAD 0x001000 0x0000000000201000 0x0000000000201000 0x000001 0x000001 R E 0x1000 | |
| 13 | # SEG-NEXT: LOAD 0x002000 0x0000000000202000 0x0000000000202000 0x000001 0x002001 RW 0x1000 | |
| 14 | # SEG-NEXT: LOAD 0x003000 0x0000000000205000 0x0000000000205000 0x000001 0x000002 RW 0x1000 | |
| 15 | # SEG-NEXT: GNU_RELRO 0x002000 0x0000000000202000 0x0000000000202000 0x000001 0x003000 R 0x1 | |
| 16 | # SEG-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x0 | |
| 17 | ||
| 18 | # SEG: .text | |
| 19 | # SEG-NEXT: .data.rel.ro .bss.rel.ro | |
| 20 | # SEG-NEXT: .data .bss | |
| 21 | ||
| 22 | # And .data is placed in the next page (sh_offset = alignTo(0x2001, 4096) = 0x3000). | |
| 23 | ||
| 24 | # [Nr] Name Type Address Off Size | |
| 25 | # CHECK: .data.rel.ro PROGBITS 0000000000202000 002000 000001 | |
| 26 | # CHECK-NEXT: .bss.rel.ro NOBITS 0000000000202001 002001 002000 | |
| 27 | # CHECK-NEXT: .data PROGBITS 0000000000205000 003000 000001 | |
| 28 | # CHECK-NEXT: .bss NOBITS 0000000000205001 003001 000001 | |
| 29 | ||
| 30 | .globl _start | |
| 31 | _start: | |
| 32 | ret | |
| 33 | ||
| 34 | .section .data.rel.ro, "aw" | |
| 35 | .space 1 | |
| 36 | ||
| 37 | .section .bss.rel.ro, "aw", @nobits | |
| 38 | .space 8192 | |
| 39 | ||
| 40 | .section .data, "aw" | |
| 41 | .space 1 | |
| 42 | ||
| 43 | .section .bss, "aw" | |
| 44 | .space 1 |
deps/lld/test/ELF/relro-non-contiguous.s+3-3| ... | ... | @@ -3,12 +3,12 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/copy-in-shared.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld -shared %t.o %t2.o -o %t.so |
| 5 | 5 | |
| 6 | // Place the .got.plt (non relro) immediately after .dynamic. This is the | |
| 7 | // reverse order of the non-linker script case. The linker created .bss.rel.ro | |
| 8 | // section will be placed after .got.plt causing the relro to be non-contiguous. | |
| 6 | // Separate RelRo sections .dynamic .bss.rel.ro with non RelRo .got.plt. | |
| 7 | // This causes the RelRo sections to be non-contiguous. | |
| 9 | 8 | // RUN: echo "SECTIONS { \ |
| 10 | 9 | // RUN: .dynamic : { *(.dynamic) } \ |
| 11 | 10 | // RUN: .got.plt : { *(.got.plt) } \ |
| 11 | // RUN: .bss.rel.ro : { *(.bss.rel.o) } \ | |
| 12 | 12 | // RUN: } " > %t.script |
| 13 | 13 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t3.o |
| 14 | 14 |
deps/lld/test/ELF/relro-omagic.s+2-2| ... | ... | @@ -2,12 +2,12 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o |
| 4 | 4 | # RUN: ld.lld -shared %t2.o -o %t2.so -soname relro-omagic.s.tmp2.so |
| 5 | # RUN: ld.lld --hash-style=sysv -N %t.o %t2.so -o %t | |
| 5 | # RUN: ld.lld --hash-style=sysv -N %t.o -Bdynamic %t2.so -o %t | |
| 6 | 6 | # RUN: llvm-objdump -section-headers %t | FileCheck --check-prefix=NORELRO %s |
| 7 | 7 | # RUN: llvm-readobj --program-headers %t | FileCheck --check-prefix=NOPHDRS %s |
| 8 | 8 | |
| 9 | 9 | # NORELRO: Sections: |
| 10 | # NORELRO-NEXT: Idx Name Size Address Type | |
| 10 | # NORELRO-NEXT: Idx Name Size VMA Type | |
| 11 | 11 | # NORELRO-NEXT: 0 00000000 0000000000000000 |
| 12 | 12 | # NORELRO-NEXT: 1 .dynsym 00000048 0000000000200120 |
| 13 | 13 | # NORELRO-NEXT: 2 .hash 00000020 0000000000200168 |
deps/lld/test/ELF/relro-tls.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld %t -o %tout |
| 4 | // RUN: llvm-readobj -program-headers %tout | FileCheck %s | |
| 4 | // RUN: llvm-readobj -l %tout | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // CHECK: Type: PT_GNU_RELRO |
| 7 | 7 | // CHECK-NEXT: Offset: |
deps/lld/test/ELF/relro.s+6-5| ... | ... | @@ -5,13 +5,13 @@ |
| 5 | 5 | // RUN: ld.lld -shared %t2.o -o %t2.so |
| 6 | 6 | |
| 7 | 7 | // RUN: ld.lld %t.o %t2.so -z now -z norelro -z relro -o %t |
| 8 | // RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=CHECK --check-prefix=FULLRELRO %s | |
| 8 | // RUN: llvm-readelf -l %t | FileCheck --check-prefix=CHECK --check-prefix=FULLRELRO %s | |
| 9 | 9 | |
| 10 | 10 | // RUN: ld.lld %t.o %t2.so -z norelro -z relro -o %t |
| 11 | // RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=CHECK --check-prefix=PARTRELRO %s | |
| 11 | // RUN: llvm-readelf -l %t | FileCheck --check-prefix=CHECK --check-prefix=PARTRELRO %s | |
| 12 | 12 | |
| 13 | 13 | // RUN: ld.lld %t.o %t2.so -z norelro -o %t |
| 14 | // RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=NORELRO %s | |
| 14 | // RUN: llvm-readelf -l %t | FileCheck --check-prefix=NORELRO %s | |
| 15 | 15 | |
| 16 | 16 | // CHECK: Program Headers: |
| 17 | 17 | // CHECK-NEXT: Type |
| ... | ... | @@ -19,12 +19,13 @@ |
| 19 | 19 | // CHECK-NEXT: LOAD |
| 20 | 20 | // CHECK-NEXT: LOAD |
| 21 | 21 | // CHECK-NEXT: LOAD |
| 22 | // CHECK-NEXT: LOAD | |
| 22 | 23 | // CHECK-NEXT: DYNAMIC |
| 23 | 24 | // CHECK-NEXT: GNU_RELRO |
| 24 | 25 | // CHECK: Section to Segment mapping: |
| 25 | 26 | |
| 26 | // FULLRELRO: 05 .openbsd.randomdata .dynamic .got .got.plt {{$}} | |
| 27 | // PARTRELRO: 05 .openbsd.randomdata .dynamic .got {{$}} | |
| 27 | // FULLRELRO: 03 .openbsd.randomdata .dynamic .got .got.plt {{$}} | |
| 28 | // PARTRELRO: 03 .openbsd.randomdata .dynamic .got {{$}} | |
| 28 | 29 | |
| 29 | 30 | |
| 30 | 31 | // NORELRO-NOT: GNU_RELRO |
deps/lld/test/ELF/resolution-end.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/resolution-end.s -o %t2.o |
| 4 | 4 | # RUN: ld.lld -shared -o %t2.so %t2.o |
| 5 | 5 | # RUN: ld.lld --hash-style=sysv %t1.o %t2.so -o %t |
| 6 | # RUN: llvm-readobj -t -s -section-data %t | FileCheck %s | |
| 6 | # RUN: llvm-readobj --symbols -S --section-data %t | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | # Test that we resolve _end to the this executable. |
| 9 | 9 |
deps/lld/test/ELF/resolution-shared.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/resolution-shared.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld %t2.o -o %t2.so -shared |
| 5 | 5 | // RUN: ld.lld %t.o %t2.so -o %t3 -shared |
| 6 | // RUN: llvm-readobj -t %t3 | FileCheck %s | |
| 6 | // RUN: llvm-readobj --symbols %t3 | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | .weak foo |
| 9 | 9 | foo: |
deps/lld/test/ELF/resolution.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/resolution.s -o %t2 |
| 4 | 4 | // RUN: ld.lld -discard-all %t %t2 -o %t3 |
| 5 | // RUN: llvm-readobj -t %t3 | FileCheck %s | |
| 5 | // RUN: llvm-readobj --symbols %t3 | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // This is an exhaustive test for checking which symbol is kept when two |
| 8 | 8 | // have the same name. Each symbol has a different size which is used |
deps/lld/test/ELF/riscv-branch.s created+32| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=-relax %s -o %t.rv32.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=-relax %s -o %t.rv64.o | |
| 5 | ||
| 6 | # RUN: ld.lld %t.rv32.o --defsym foo=_start+4 --defsym bar=_start -o %t.rv32 | |
| 7 | # RUN: ld.lld %t.rv64.o --defsym foo=_start+4 --defsym bar=_start -o %t.rv64 | |
| 8 | # RUN: llvm-objdump -d %t.rv32 | FileCheck %s | |
| 9 | # RUN: llvm-objdump -d %t.rv64 | FileCheck %s | |
| 10 | # CHECK: 63 02 00 00 beqz zero, 4 | |
| 11 | # CHECK: e3 1e 00 fe bnez zero, -4 | |
| 12 | # | |
| 13 | # RUN: ld.lld %t.rv32.o --defsym foo=_start+0xffe --defsym bar=_start+4-0x1000 -o %t.rv32.limits | |
| 14 | # RUN: ld.lld %t.rv64.o --defsym foo=_start+0xffe --defsym bar=_start+4-0x1000 -o %t.rv64.limits | |
| 15 | # RUN: llvm-objdump -d %t.rv32.limits | FileCheck --check-prefix=LIMITS %s | |
| 16 | # RUN: llvm-objdump -d %t.rv64.limits | FileCheck --check-prefix=LIMITS %s | |
| 17 | # LIMITS: e3 0f 00 7e beqz zero, 4094 | |
| 18 | # LIMITS-NEXT: 63 10 00 80 bnez zero, -4096 | |
| 19 | ||
| 20 | # RUN: not ld.lld %t.rv32.o --defsym foo=_start+0x1000 --defsym bar=_start+4-0x1002 -o %t 2>&1 | FileCheck --check-prefix=ERROR-RANGE %s | |
| 21 | # RUN: not ld.lld %t.rv64.o --defsym foo=_start+0x1000 --defsym bar=_start+4-0x1002 -o %t 2>&1 | FileCheck --check-prefix=ERROR-RANGE %s | |
| 22 | # ERROR-RANGE: relocation R_RISCV_BRANCH out of range: 2048 is not in [-2048, 2047] | |
| 23 | # ERROR-RANGE-NEXT: relocation R_RISCV_BRANCH out of range: -2049 is not in [-2048, 2047] | |
| 24 | ||
| 25 | # RUN: not ld.lld %t.rv32.o --defsym foo=_start+1 --defsym bar=_start-1 -o %t 2>&1 | FileCheck --check-prefix=ERROR-ALIGN %s | |
| 26 | # RUN: not ld.lld %t.rv64.o --defsym foo=_start+1 --defsym bar=_start-1 -o %t 2>&1 | FileCheck --check-prefix=ERROR-ALIGN %s | |
| 27 | # ERROR-ALIGN: improper alignment for relocation R_RISCV_BRANCH: 0x1 is not aligned to 2 bytes | |
| 28 | ||
| 29 | .global _start | |
| 30 | _start: | |
| 31 | beq x0, x0, foo | |
| 32 | bne x0, x0, bar |
deps/lld/test/ELF/riscv-branch.test deleted-119| ... | ... | @@ -1,119 +0,0 @@ |
| 1 | # .option norelax | |
| 2 | # .global _start | |
| 3 | # _start: | |
| 4 | # beq x0, x0, _start | |
| 5 | # | |
| 6 | # .section .reloc_max, "ax", @progbits | |
| 7 | # L1: | |
| 8 | # beq x0, x0, L1 + 0xffe | |
| 9 | # | |
| 10 | # .section .reloc_min, "ax", @progbits | |
| 11 | # L2: | |
| 12 | # beq x0, x0, L2 - 0x1000 | |
| 13 | # | |
| 14 | # REQUIRES: riscv | |
| 15 | # RUN: yaml2obj %s -o %t.o | |
| 16 | # RUN: ld.lld %t.o -o %t | |
| 17 | # RUN: obj2yaml %t | FileCheck %s | |
| 18 | # | |
| 19 | # CHECK: - Name: .text | |
| 20 | # CHECK: Content: '63000000' | |
| 21 | # 11000: 00000063 beqz zero,11000 <_start> | |
| 22 | # | |
| 23 | # CHECK: - Name: .reloc_max | |
| 24 | # CHECK: Content: E30F007E | |
| 25 | # 11004: 7e000fe3 beqz zero,12002 | |
| 26 | # | |
| 27 | # CHECK: - Name: .reloc_min | |
| 28 | # CHECK: Content: '63000080' | |
| 29 | # 11008: 80000063 beqz zero,10008 | |
| 30 | ||
| 31 | --- !ELF | |
| 32 | FileHeader: | |
| 33 | Class: ELFCLASS32 | |
| 34 | Data: ELFDATA2LSB | |
| 35 | Type: ET_REL | |
| 36 | Machine: EM_RISCV | |
| 37 | Flags: [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ] | |
| 38 | Sections: | |
| 39 | - Name: .text | |
| 40 | Type: SHT_PROGBITS | |
| 41 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 42 | AddressAlign: 0x0000000000000002 | |
| 43 | Content: '63000000' | |
| 44 | - Name: .rela.text | |
| 45 | Type: SHT_RELA | |
| 46 | Flags: [ SHF_INFO_LINK ] | |
| 47 | Link: .symtab | |
| 48 | AddressAlign: 0x0000000000000004 | |
| 49 | Info: .text | |
| 50 | Relocations: | |
| 51 | - Offset: 0x0000000000000000 | |
| 52 | Symbol: _start | |
| 53 | Type: R_RISCV_BRANCH | |
| 54 | - Name: .data | |
| 55 | Type: SHT_PROGBITS | |
| 56 | Flags: [ SHF_WRITE, SHF_ALLOC ] | |
| 57 | AddressAlign: 0x0000000000000001 | |
| 58 | Content: '' | |
| 59 | - Name: .bss | |
| 60 | Type: SHT_NOBITS | |
| 61 | Flags: [ SHF_WRITE, SHF_ALLOC ] | |
| 62 | AddressAlign: 0x0000000000000001 | |
| 63 | - Name: .reloc_max | |
| 64 | Type: SHT_PROGBITS | |
| 65 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 66 | AddressAlign: 0x0000000000000001 | |
| 67 | Content: E30F007E | |
| 68 | - Name: .rela.reloc_max | |
| 69 | Type: SHT_RELA | |
| 70 | Flags: [ SHF_INFO_LINK ] | |
| 71 | Link: .symtab | |
| 72 | AddressAlign: 0x0000000000000004 | |
| 73 | Info: .reloc_max | |
| 74 | Relocations: | |
| 75 | - Offset: 0x0000000000000000 | |
| 76 | Symbol: L1 | |
| 77 | Type: R_RISCV_BRANCH | |
| 78 | Addend: 4094 | |
| 79 | - Name: .reloc_min | |
| 80 | Type: SHT_PROGBITS | |
| 81 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 82 | AddressAlign: 0x0000000000000001 | |
| 83 | Content: '63000080' | |
| 84 | - Name: .rela.reloc_min | |
| 85 | Type: SHT_RELA | |
| 86 | Flags: [ SHF_INFO_LINK ] | |
| 87 | Link: .symtab | |
| 88 | AddressAlign: 0x0000000000000004 | |
| 89 | Info: .reloc_min | |
| 90 | Relocations: | |
| 91 | - Offset: 0x0000000000000000 | |
| 92 | Symbol: L2 | |
| 93 | Type: R_RISCV_BRANCH | |
| 94 | Addend: -4096 | |
| 95 | Symbols: | |
| 96 | Local: | |
| 97 | - Name: .text | |
| 98 | Type: STT_SECTION | |
| 99 | Section: .text | |
| 100 | - Name: .data | |
| 101 | Type: STT_SECTION | |
| 102 | Section: .data | |
| 103 | - Name: .bss | |
| 104 | Type: STT_SECTION | |
| 105 | Section: .bss | |
| 106 | - Name: .reloc_max | |
| 107 | Type: STT_SECTION | |
| 108 | Section: .reloc_max | |
| 109 | - Name: L1 | |
| 110 | Section: .reloc_max | |
| 111 | - Name: .reloc_min | |
| 112 | Type: STT_SECTION | |
| 113 | Section: .reloc_min | |
| 114 | - Name: L2 | |
| 115 | Section: .reloc_min | |
| 116 | Global: | |
| 117 | - Name: _start | |
| 118 | Section: .text | |
| 119 | ... |
deps/lld/test/ELF/riscv-call.s created+32| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=-relax %s -o %t.rv32.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=-relax %s -o %t.rv64.o | |
| 5 | ||
| 6 | # RUN: ld.lld %t.rv32.o --defsym foo=_start+8 --defsym bar=_start -o %t.rv32 | |
| 7 | # RUN: ld.lld %t.rv64.o --defsym foo=_start+8 --defsym bar=_start -o %t.rv64 | |
| 8 | # RUN: llvm-objdump -d %t.rv32 | FileCheck %s | |
| 9 | # RUN: llvm-objdump -d %t.rv64 | FileCheck %s | |
| 10 | # CHECK: 97 00 00 00 auipc ra, 0 | |
| 11 | # CHECK-NEXT: e7 80 80 00 jalr 8(ra) | |
| 12 | # CHECK: 97 00 00 00 auipc ra, 0 | |
| 13 | # CHECK-NEXT: e7 80 80 ff jalr -8(ra) | |
| 14 | ||
| 15 | # RUN: ld.lld %t.rv32.o --defsym foo=_start+0x7ffff7ff --defsym bar=_start+8-0x80000800 -o %t.rv32.limits | |
| 16 | # RUN: ld.lld %t.rv64.o --defsym foo=_start+0x7ffff7ff --defsym bar=_start+8-0x80000800 -o %t.rv64.limits | |
| 17 | # RUN: llvm-objdump -d %t.rv32.limits | FileCheck --check-prefix=LIMITS %s | |
| 18 | # RUN: llvm-objdump -d %t.rv64.limits | FileCheck --check-prefix=LIMITS %s | |
| 19 | # LIMITS: 97 f0 ff 7f auipc ra, 524287 | |
| 20 | # LIMITS-NEXT: e7 80 f0 7f jalr 2047(ra) | |
| 21 | # LIMITS-NEXT: 97 00 00 80 auipc ra, 524288 | |
| 22 | # LIMITS-NEXT: e7 80 00 80 jalr -2048(ra) | |
| 23 | ||
| 24 | # RUN: ld.lld %t.rv32.o --defsym foo=_start+0x7ffff800 --defsym bar=_start+8-0x80000801 -o %t | |
| 25 | # RUN: not ld.lld %t.rv64.o --defsym foo=_start+0x7ffff800 --defsym bar=_start+8-0x80000801 -o %t 2>&1 | FileCheck --check-prefix=ERROR %s | |
| 26 | # ERROR: relocation R_RISCV_CALL out of range: 524288 is not in [-524288, 524287] | |
| 27 | # ERROR-NEXT: relocation R_RISCV_CALL out of range: -524289 is not in [-524288, 524287] | |
| 28 | ||
| 29 | .global _start | |
| 30 | _start: | |
| 31 | call foo | |
| 32 | call bar |
deps/lld/test/ELF/riscv-call.test deleted-95| ... | ... | @@ -1,95 +0,0 @@ |
| 1 | # .option norelax | |
| 2 | # .global _start | |
| 3 | # _start: | |
| 4 | # call _start + 4 | |
| 5 | # | |
| 6 | # .section .reloc_neg, "ax", @progbits | |
| 7 | # L1: | |
| 8 | # call L1 - 4 | |
| 9 | # | |
| 10 | # REQUIRES: riscv | |
| 11 | # RUN: yaml2obj %s -o %t.o | |
| 12 | # RUN: ld.lld %t.o -o %t | |
| 13 | # RUN: obj2yaml %t | FileCheck %s | |
| 14 | # | |
| 15 | # CHECK: - Name: .text | |
| 16 | # CHECK: Content: '97000000E7804000' | |
| 17 | # | |
| 18 | # 11000: 00000097 auipc ra,0x0 | |
| 19 | # 11004: 004080e7 jalr 4(ra) | |
| 20 | # | |
| 21 | # CHECK: - Name: .reloc_neg | |
| 22 | # CHECK: Content: 97000000E780C0FF | |
| 23 | # | |
| 24 | # 11008: 00000097 auipc ra,0x0 | |
| 25 | # 1100c: ffc080e7 jalr -4(ra) | |
| 26 | ||
| 27 | --- !ELF | |
| 28 | FileHeader: | |
| 29 | Class: ELFCLASS32 | |
| 30 | Data: ELFDATA2LSB | |
| 31 | Type: ET_REL | |
| 32 | Machine: EM_RISCV | |
| 33 | Flags: [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ] | |
| 34 | Sections: | |
| 35 | - Name: .text | |
| 36 | Type: SHT_PROGBITS | |
| 37 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 38 | AddressAlign: 0x0000000000000002 | |
| 39 | Content: '97000000E7800000' | |
| 40 | - Name: .rela.text | |
| 41 | Type: SHT_RELA | |
| 42 | Flags: [ SHF_INFO_LINK ] | |
| 43 | Link: .symtab | |
| 44 | AddressAlign: 0x0000000000000004 | |
| 45 | Info: .text | |
| 46 | Relocations: | |
| 47 | - Offset: 0x0000000000000000 | |
| 48 | Symbol: _start | |
| 49 | Type: R_RISCV_CALL | |
| 50 | Addend: 4 | |
| 51 | - Name: .data | |
| 52 | Type: SHT_PROGBITS | |
| 53 | Flags: [ SHF_WRITE, SHF_ALLOC ] | |
| 54 | AddressAlign: 0x0000000000000001 | |
| 55 | Content: '' | |
| 56 | - Name: .bss | |
| 57 | Type: SHT_NOBITS | |
| 58 | Flags: [ SHF_WRITE, SHF_ALLOC ] | |
| 59 | AddressAlign: 0x0000000000000001 | |
| 60 | - Name: .reloc_neg | |
| 61 | Type: SHT_PROGBITS | |
| 62 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 63 | AddressAlign: 0x0000000000000001 | |
| 64 | Content: '97000000E7800000' | |
| 65 | - Name: .rela.reloc_neg | |
| 66 | Type: SHT_RELA | |
| 67 | Flags: [ SHF_INFO_LINK ] | |
| 68 | Link: .symtab | |
| 69 | AddressAlign: 0x0000000000000004 | |
| 70 | Info: .reloc_neg | |
| 71 | Relocations: | |
| 72 | - Offset: 0x0000000000000000 | |
| 73 | Symbol: L1 | |
| 74 | Type: R_RISCV_CALL | |
| 75 | Addend: -4 | |
| 76 | Symbols: | |
| 77 | Local: | |
| 78 | - Name: .text | |
| 79 | Type: STT_SECTION | |
| 80 | Section: .text | |
| 81 | - Name: .data | |
| 82 | Type: STT_SECTION | |
| 83 | Section: .data | |
| 84 | - Name: .bss | |
| 85 | Type: STT_SECTION | |
| 86 | Section: .bss | |
| 87 | - Name: .reloc_neg | |
| 88 | Type: STT_SECTION | |
| 89 | Section: .reloc_neg | |
| 90 | - Name: L1 | |
| 91 | Section: .reloc_neg | |
| 92 | Global: | |
| 93 | - Name: _start | |
| 94 | Section: .text | |
| 95 | ... |
deps/lld/test/ELF/riscv-gp-dummy-sdata.s created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.32.o | |
| 3 | # RUN: ld.lld -pie %t.32.o -o %t.32 | |
| 4 | # RUN: llvm-readelf -S %t.32 | FileCheck --check-prefix=SEC %s | |
| 5 | # RUN: llvm-readelf -s %t.32 | FileCheck --check-prefix=SYM %s | |
| 6 | ||
| 7 | # RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.64.o | |
| 8 | # RUN: ld.lld -pie %t.64.o -o %t.64 | |
| 9 | # RUN: llvm-readelf -S %t.64 | FileCheck --check-prefix=SEC %s | |
| 10 | # RUN: llvm-readelf -s %t.64 | FileCheck --check-prefix=SYM %s | |
| 11 | ||
| 12 | ## If there is an undefined reference to __global_pointer$ but .sdata doesn't | |
| 13 | ## exist, create a dummy one. | |
| 14 | ||
| 15 | ## __global_pointer$ = .sdata+0x800 | |
| 16 | # SEC: [ 7] .sdata PROGBITS {{0*}}00003000 | |
| 17 | # SYM: {{0*}}00003800 0 NOTYPE GLOBAL DEFAULT 7 __global_pointer$ | |
| 18 | ||
| 19 | ## If __global_pointer$ is not used, don't create .sdata . | |
| 20 | ||
| 21 | # RUN: llvm-mc -filetype=obj -triple=riscv32 /dev/null -o %t.32.o | |
| 22 | # RUN: ld.lld -pie %t.32.o -o %t.32 | |
| 23 | # RUN: llvm-readelf -S %t.32 | FileCheck --implicit-check-not=.sdata /dev/null | |
| 24 | ||
| 25 | lla gp, __global_pointer$ |
deps/lld/test/ELF/riscv-gp.s created+26| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.32.o | |
| 3 | # RUN: ld.lld -pie %t.32.o -o %t.32 | |
| 4 | # RUN: llvm-readelf -s %t.32 | FileCheck --check-prefix=SYM %s | |
| 5 | # RUN: llvm-readelf -S %t.32 | FileCheck --check-prefix=SEC %s | |
| 6 | # RUN: not ld.lld -shared %t.32.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s | |
| 7 | ||
| 8 | # RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.64.o | |
| 9 | # RUN: ld.lld -pie %t.64.o -o %t.64 | |
| 10 | # RUN: llvm-readelf -s %t.64 | FileCheck --check-prefix=SYM %s | |
| 11 | # RUN: llvm-readelf -S %t.64 | FileCheck --check-prefix=SEC %s | |
| 12 | # RUN: not ld.lld -shared %t.64.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s | |
| 13 | ||
| 14 | ## __global_pointer$ = .sdata+0x800 = 0x3800 | |
| 15 | # SEC: [ 7] .sdata PROGBITS {{0*}}00003000 | |
| 16 | # SYM: {{0*}}00003800 0 NOTYPE GLOBAL DEFAULT 7 __global_pointer$ | |
| 17 | ||
| 18 | ## __global_pointer$ - 0x1000 = 4096*3-2048 | |
| 19 | # DIS: 1000: auipc gp, 3 | |
| 20 | # DIS-NEXT: addi gp, gp, -2048 | |
| 21 | ||
| 22 | # ERR: error: relocation R_RISCV_PCREL_HI20 cannot be used against symbol __global_pointer$; recompile with -fPIC | |
| 23 | ||
| 24 | lla gp, __global_pointer$ | |
| 25 | ||
| 26 | .section .sdata,"aw" |
deps/lld/test/ELF/riscv-hi20-lo12.s created+40| ... | ... | @@ -0,0 +1,40 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=-relax %s -o %t.rv32.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=-relax %s -o %t.rv64.o | |
| 5 | ||
| 6 | # RUN: ld.lld %t.rv32.o --defsym foo=0 --defsym bar=42 -o %t.rv32 | |
| 7 | # RUN: ld.lld %t.rv64.o --defsym foo=0 --defsym bar=42 -o %t.rv64 | |
| 8 | # RUN: llvm-objdump -d %t.rv32 | FileCheck %s | |
| 9 | # RUN: llvm-objdump -d %t.rv64 | FileCheck %s | |
| 10 | # CHECK: 37 05 00 00 lui a0, 0 | |
| 11 | # CHECK-NEXT: 13 05 05 00 mv a0, a0 | |
| 12 | # CHECK-NEXT: 23 20 a5 00 sw a0, 0(a0) | |
| 13 | # CHECK-NEXT: b7 05 00 00 lui a1, 0 | |
| 14 | # CHECK-NEXT: 93 85 a5 02 addi a1, a1, 42 | |
| 15 | # CHECK-NEXT: 23 a5 b5 02 sw a1, 42(a1) | |
| 16 | ||
| 17 | # RUN: ld.lld %t.rv32.o --defsym foo=0x7ffff7ff --defsym bar=0x7ffff800 -o %t.rv32.limits | |
| 18 | # RUN: ld.lld %t.rv64.o --defsym foo=0x7ffff7ff --defsym bar=0xffffffff7ffff800 -o %t.rv64.limits | |
| 19 | # RUN: llvm-objdump -d %t.rv32.limits | FileCheck --check-prefix=LIMITS %s | |
| 20 | # RUN: llvm-objdump -d %t.rv64.limits | FileCheck --check-prefix=LIMITS %s | |
| 21 | # LIMITS: 37 f5 ff 7f lui a0, 524287 | |
| 22 | # LIMITS-NEXT: 13 05 f5 7f addi a0, a0, 2047 | |
| 23 | # LIMITS-NEXT: a3 2f a5 7e sw a0, 2047(a0) | |
| 24 | # LIMITS-NEXT: b7 05 00 80 lui a1, 524288 | |
| 25 | # LIMITS-NEXT: 93 85 05 80 addi a1, a1, -2048 | |
| 26 | # LIMITS-NEXT: 23 a0 b5 80 sw a1, -2048(a1) | |
| 27 | ||
| 28 | # RUN: not ld.lld %t.rv64.o --defsym foo=0x7ffff800 --defsym bar=0xffffffff7ffff7ff -o %t 2>&1 | FileCheck --check-prefix ERROR %s | |
| 29 | # ERROR: relocation R_RISCV_HI20 out of range: 524288 is not in [-524288, 524287] | |
| 30 | # ERROR-NEXT: relocation R_RISCV_HI20 out of range: -524289 is not in [-524288, 524287] | |
| 31 | ||
| 32 | .global _start | |
| 33 | ||
| 34 | _start: | |
| 35 | lui a0, %hi(foo) | |
| 36 | addi a0, a0, %lo(foo) | |
| 37 | sw a0, %lo(foo)(a0) | |
| 38 | lui a1, %hi(bar) | |
| 39 | addi a1, a1, %lo(bar) | |
| 40 | sw a1, %lo(bar)(a1) |
deps/lld/test/ELF/riscv-hi20-lo12.test deleted-86| ... | ... | @@ -1,86 +0,0 @@ |
| 1 | # .option norelax | |
| 2 | # .global _start | |
| 3 | # | |
| 4 | # .section .reloc_12345678, "ax", @progbits | |
| 5 | # _start: | |
| 6 | # foo = 0x12345678 | |
| 7 | # lui a0, %hi(foo) | |
| 8 | # addi a0, a0, %lo(foo) | |
| 9 | # lw a0, %lo(foo)(a0) | |
| 10 | # | |
| 11 | # .section .reloc_fedcba98, "ax", @progbits | |
| 12 | # foo = 0xfedcba98 | |
| 13 | # lui a0, %hi(foo) | |
| 14 | # addi a0, a0, %lo(foo) | |
| 15 | # | |
| 16 | # REQUIRES: riscv | |
| 17 | # RUN: yaml2obj %s -o %t.o | |
| 18 | # RUN: ld.lld %t.o -o %t | |
| 19 | # RUN: obj2yaml %t | FileCheck %s | |
| 20 | # | |
| 21 | # CHECK: - Name: .reloc_12345678 | |
| 22 | # CHECK: Content: '375534121305856703258567' | |
| 23 | # 11000: 12345537 lui a0,0x12345 | |
| 24 | # 11004: 67850513 addi a0,a0,1656 # 12345678 <__global_pointer$+0x12332e78> | |
| 25 | # 11008: 67852503 lw a0,1656(a0) | |
| 26 | # | |
| 27 | # CHECK: - Name: .reloc_fedcba98 | |
| 28 | # CHECK: Content: 37C5DCFE130585A9 | |
| 29 | # 1100c: fedcc537 lui a0,0xfedcc | |
| 30 | # 11010: a9850513 addi a0,a0,-1384 # fedcba98 <__global_pointer$+0xfedb9298> | |
| 31 | ||
| 32 | --- !ELF | |
| 33 | FileHeader: | |
| 34 | Class: ELFCLASS32 | |
| 35 | Data: ELFDATA2LSB | |
| 36 | Type: ET_REL | |
| 37 | Machine: EM_RISCV | |
| 38 | Flags: [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ] | |
| 39 | Sections: | |
| 40 | - Name: .text | |
| 41 | Type: SHT_PROGBITS | |
| 42 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 43 | AddressAlign: 0x0000000000000002 | |
| 44 | Content: '' | |
| 45 | - Name: .data | |
| 46 | Type: SHT_PROGBITS | |
| 47 | Flags: [ SHF_WRITE, SHF_ALLOC ] | |
| 48 | AddressAlign: 0x0000000000000001 | |
| 49 | Content: '' | |
| 50 | - Name: .bss | |
| 51 | Type: SHT_NOBITS | |
| 52 | Flags: [ SHF_WRITE, SHF_ALLOC ] | |
| 53 | AddressAlign: 0x0000000000000001 | |
| 54 | - Name: .reloc_12345678 | |
| 55 | Type: SHT_PROGBITS | |
| 56 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 57 | AddressAlign: 0x0000000000000001 | |
| 58 | Content: '375534121305856703258567' | |
| 59 | - Name: .reloc_fedcba98 | |
| 60 | Type: SHT_PROGBITS | |
| 61 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 62 | AddressAlign: 0x0000000000000001 | |
| 63 | Content: 37C5DCFE130585A9 | |
| 64 | Symbols: | |
| 65 | Local: | |
| 66 | - Name: .text | |
| 67 | Type: STT_SECTION | |
| 68 | Section: .text | |
| 69 | - Name: .data | |
| 70 | Type: STT_SECTION | |
| 71 | Section: .data | |
| 72 | - Name: .bss | |
| 73 | Type: STT_SECTION | |
| 74 | Section: .bss | |
| 75 | - Name: .reloc_12345678 | |
| 76 | Type: STT_SECTION | |
| 77 | Section: .reloc_12345678 | |
| 78 | - Name: foo | |
| 79 | Value: 0x00000000FEDCBA98 | |
| 80 | - Name: .reloc_fedcba98 | |
| 81 | Type: STT_SECTION | |
| 82 | Section: .reloc_fedcba98 | |
| 83 | Global: | |
| 84 | - Name: _start | |
| 85 | Section: .reloc_12345678 | |
| 86 | ... |
deps/lld/test/ELF/riscv-jal-error.test deleted-93| ... | ... | @@ -1,93 +0,0 @@ |
| 1 | # .option norelax | |
| 2 | # .global _start | |
| 3 | # | |
| 4 | # _start: | |
| 5 | # L1: | |
| 6 | # jal x0, L1 + 0x100000 | |
| 7 | # L2: | |
| 8 | # jal x0, L2 - 0x100002 | |
| 9 | # L3: | |
| 10 | # jal x0, L3 + 1 | |
| 11 | # L4: | |
| 12 | # c.jal L4 + 1 | |
| 13 | # | |
| 14 | # REQUIRES: riscv | |
| 15 | # RUN: yaml2obj %s -o %t.o | |
| 16 | # RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s | |
| 17 | # | |
| 18 | # CHECK: {{.*}}(.text+0x0): relocation R_RISCV_JAL out of range | |
| 19 | # CHECK: {{.*}}(.text+0x4): relocation R_RISCV_JAL out of range | |
| 20 | # CHECK: {{.*}}(.text+0x8): improper alignment for relocation R_RISCV_JAL | |
| 21 | # CHECK: {{.*}}(.text+0xC): improper alignment for relocation R_RISCV_RVC_JUMP | |
| 22 | ||
| 23 | --- !ELF | |
| 24 | FileHeader: | |
| 25 | Class: ELFCLASS32 | |
| 26 | Data: ELFDATA2LSB | |
| 27 | Type: ET_REL | |
| 28 | Machine: EM_RISCV | |
| 29 | Flags: [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ] | |
| 30 | Sections: | |
| 31 | - Name: .text | |
| 32 | Type: SHT_PROGBITS | |
| 33 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 34 | AddressAlign: 0x0000000000000002 | |
| 35 | Content: 6F0000806FF0FF7F6F0000000120 | |
| 36 | - Name: .rela.text | |
| 37 | Type: SHT_RELA | |
| 38 | Flags: [ SHF_INFO_LINK ] | |
| 39 | Link: .symtab | |
| 40 | AddressAlign: 0x0000000000000004 | |
| 41 | Info: .text | |
| 42 | Relocations: | |
| 43 | - Offset: 0x0000000000000000 | |
| 44 | Symbol: L1 | |
| 45 | Type: R_RISCV_JAL | |
| 46 | Addend: 1048576 | |
| 47 | - Offset: 0x0000000000000004 | |
| 48 | Symbol: L2 | |
| 49 | Type: R_RISCV_JAL | |
| 50 | Addend: -1048578 | |
| 51 | - Offset: 0x0000000000000008 | |
| 52 | Symbol: L3 | |
| 53 | Type: R_RISCV_JAL | |
| 54 | Addend: 1 | |
| 55 | - Offset: 0x000000000000000C | |
| 56 | Symbol: L4 | |
| 57 | Type: R_RISCV_RVC_JUMP | |
| 58 | Addend: 1 | |
| 59 | - Name: .data | |
| 60 | Type: SHT_PROGBITS | |
| 61 | Flags: [ SHF_WRITE, SHF_ALLOC ] | |
| 62 | AddressAlign: 0x0000000000000001 | |
| 63 | Content: '' | |
| 64 | - Name: .bss | |
| 65 | Type: SHT_NOBITS | |
| 66 | Flags: [ SHF_WRITE, SHF_ALLOC ] | |
| 67 | AddressAlign: 0x0000000000000001 | |
| 68 | Symbols: | |
| 69 | Local: | |
| 70 | - Name: .text | |
| 71 | Type: STT_SECTION | |
| 72 | Section: .text | |
| 73 | - Name: .data | |
| 74 | Type: STT_SECTION | |
| 75 | Section: .data | |
| 76 | - Name: .bss | |
| 77 | Type: STT_SECTION | |
| 78 | Section: .bss | |
| 79 | - Name: L1 | |
| 80 | Section: .text | |
| 81 | - Name: L2 | |
| 82 | Section: .text | |
| 83 | Value: 0x0000000000000004 | |
| 84 | - Name: L3 | |
| 85 | Section: .text | |
| 86 | Value: 0x0000000000000008 | |
| 87 | - Name: L4 | |
| 88 | Section: .text | |
| 89 | Value: 0x000000000000000C | |
| 90 | Global: | |
| 91 | - Name: _start | |
| 92 | Section: .text | |
| 93 | ... |
deps/lld/test/ELF/riscv-jal.s created+34| ... | ... | @@ -0,0 +1,34 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=-relax %s -o %t.rv32.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=-relax %s -o %t.rv64.o | |
| 5 | ||
| 6 | # RUN: ld.lld %t.rv32.o --defsym foo=_start+4 --defsym bar=_start -o %t.rv32 | |
| 7 | # RUN: ld.lld %t.rv64.o --defsym foo=_start+4 --defsym bar=_start -o %t.rv64 | |
| 8 | # RUN: llvm-objdump -d %t.rv32 | FileCheck %s | |
| 9 | # RUN: llvm-objdump -d %t.rv64 | FileCheck %s | |
| 10 | # CHECK: 6f 00 40 00 j 4 | |
| 11 | # CHECK: ef f0 df ff jal -4 | |
| 12 | ||
| 13 | # RUN: ld.lld %t.rv32.o --defsym foo=_start+0xffffe --defsym bar=_start+4-0x100000 -o %t.rv32.limits | |
| 14 | # RUN: ld.lld %t.rv64.o --defsym foo=_start+0xffffe --defsym bar=_start+4-0x100000 -o %t.rv64.limits | |
| 15 | # RUN: llvm-objdump -d %t.rv32.limits | FileCheck --check-prefix=LIMITS %s | |
| 16 | # RUN: llvm-objdump -d %t.rv64.limits | FileCheck --check-prefix=LIMITS %s | |
| 17 | # LIMITS: 6f f0 ff 7f j 1048574 | |
| 18 | # LIMITS-NEXT: ef 00 00 80 jal -1048576 | |
| 19 | ||
| 20 | # RUN: not ld.lld %t.rv32.o --defsym foo=_start+0x100000 --defsym bar=_start+4-0x100002 -o %t 2>&1 | FileCheck --check-prefix=ERROR-RANGE %s | |
| 21 | # RUN: not ld.lld %t.rv64.o --defsym foo=_start+0x100000 --defsym bar=_start+4-0x100002 -o %t 2>&1 | FileCheck --check-prefix=ERROR-RANGE %s | |
| 22 | # ERROR-RANGE: relocation R_RISCV_JAL out of range: 524288 is not in [-524288, 524287] | |
| 23 | # ERROR-RANGE-NEXT: relocation R_RISCV_JAL out of range: -524289 is not in [-524288, 524287] | |
| 24 | ||
| 25 | # RUN: not ld.lld %t.rv32.o --defsym foo=_start+1 --defsym bar=_start+4+3 -o %t 2>&1 | FileCheck --check-prefix=ERROR-ALIGN %s | |
| 26 | # RUN: not ld.lld %t.rv64.o --defsym foo=_start+1 --defsym bar=_start+4+3 -o %t 2>&1 | FileCheck --check-prefix=ERROR-ALIGN %s | |
| 27 | # ERROR-ALIGN: improper alignment for relocation R_RISCV_JAL: 0x1 is not aligned to 2 bytes | |
| 28 | # ERROR-ALIGN-NEXT: improper alignment for relocation R_RISCV_JAL: 0x3 is not aligned to 2 bytes | |
| 29 | ||
| 30 | .global _start | |
| 31 | ||
| 32 | _start: | |
| 33 | jal x0, foo | |
| 34 | jal x1, bar |
deps/lld/test/ELF/riscv-jal.test deleted-161| ... | ... | @@ -1,161 +0,0 @@ |
| 1 | # .option norelax | |
| 2 | # .global _start | |
| 3 | # | |
| 4 | # .section .reloc_zero, "ax", @progbits | |
| 5 | # _start: | |
| 6 | # L1: | |
| 7 | # jal x0, L1 | |
| 8 | # L2: | |
| 9 | # c.jal L2 | |
| 10 | # | |
| 11 | # .section .reloc_max, "ax", @progbits | |
| 12 | # L3: | |
| 13 | # jal x0, L3 + 0xffffe | |
| 14 | # L4: | |
| 15 | # c.jal L4 + 0x7fe | |
| 16 | # | |
| 17 | # .section .reloc_min, "ax", @progbits | |
| 18 | # L5: | |
| 19 | # jal x0, L5 - 0x100000 | |
| 20 | # L6: | |
| 21 | # c.jal L6 - 0x800 | |
| 22 | # | |
| 23 | # REQUIRES: riscv | |
| 24 | # RUN: yaml2obj %s -o %t.o | |
| 25 | # RUN: ld.lld %t.o -o %t | |
| 26 | # RUN: obj2yaml %t | FileCheck %s | |
| 27 | # | |
| 28 | # CHECK: - Name: .reloc_zero | |
| 29 | # CHECK: Content: 6F0000000120 | |
| 30 | # 11000: 0000006f j 11000 | |
| 31 | # 11004: 2001 jal 11004 | |
| 32 | # | |
| 33 | # CHECK: - Name: .reloc_max | |
| 34 | # CHECK: Content: 6FF0FF7FFD2F | |
| 35 | # 11006: 7ffff06f j 111004 | |
| 36 | # 1100a: 2ffd jal 11808 | |
| 37 | # | |
| 38 | # CHECK: - Name: .reloc_min | |
| 39 | # CHECK: Content: 6F0000800130 | |
| 40 | # 1100c: 8000006f j fff1100c | |
| 41 | # 11010: 3001 jal 10810 | |
| 42 | ||
| 43 | --- !ELF | |
| 44 | FileHeader: | |
| 45 | Class: ELFCLASS32 | |
| 46 | Data: ELFDATA2LSB | |
| 47 | Type: ET_REL | |
| 48 | Machine: EM_RISCV | |
| 49 | Flags: [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ] | |
| 50 | Sections: | |
| 51 | - Name: .text | |
| 52 | Type: SHT_PROGBITS | |
| 53 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 54 | AddressAlign: 0x0000000000000002 | |
| 55 | Content: '' | |
| 56 | - Name: .data | |
| 57 | Type: SHT_PROGBITS | |
| 58 | Flags: [ SHF_WRITE, SHF_ALLOC ] | |
| 59 | AddressAlign: 0x0000000000000001 | |
| 60 | Content: '' | |
| 61 | - Name: .bss | |
| 62 | Type: SHT_NOBITS | |
| 63 | Flags: [ SHF_WRITE, SHF_ALLOC ] | |
| 64 | AddressAlign: 0x0000000000000001 | |
| 65 | - Name: .reloc_zero | |
| 66 | Type: SHT_PROGBITS | |
| 67 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 68 | AddressAlign: 0x0000000000000001 | |
| 69 | Content: 6F0000000120 | |
| 70 | - Name: .rela.reloc_zero | |
| 71 | Type: SHT_RELA | |
| 72 | Flags: [ SHF_INFO_LINK ] | |
| 73 | Link: .symtab | |
| 74 | AddressAlign: 0x0000000000000004 | |
| 75 | Info: .reloc_zero | |
| 76 | Relocations: | |
| 77 | - Offset: 0x0000000000000000 | |
| 78 | Symbol: L1 | |
| 79 | Type: R_RISCV_JAL | |
| 80 | - Offset: 0x0000000000000004 | |
| 81 | Symbol: L2 | |
| 82 | Type: R_RISCV_RVC_JUMP | |
| 83 | - Name: .reloc_max | |
| 84 | Type: SHT_PROGBITS | |
| 85 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 86 | AddressAlign: 0x0000000000000001 | |
| 87 | Content: 6FF0FF7FFD2F | |
| 88 | - Name: .rela.reloc_max | |
| 89 | Type: SHT_RELA | |
| 90 | Flags: [ SHF_INFO_LINK ] | |
| 91 | Link: .symtab | |
| 92 | AddressAlign: 0x0000000000000004 | |
| 93 | Info: .reloc_max | |
| 94 | Relocations: | |
| 95 | - Offset: 0x0000000000000000 | |
| 96 | Symbol: L3 | |
| 97 | Type: R_RISCV_JAL | |
| 98 | Addend: 1048574 | |
| 99 | - Offset: 0x0000000000000004 | |
| 100 | Symbol: L4 | |
| 101 | Type: R_RISCV_RVC_JUMP | |
| 102 | Addend: 2046 | |
| 103 | - Name: .reloc_min | |
| 104 | Type: SHT_PROGBITS | |
| 105 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 106 | AddressAlign: 0x0000000000000001 | |
| 107 | Content: 6F0000800130 | |
| 108 | - Name: .rela.reloc_min | |
| 109 | Type: SHT_RELA | |
| 110 | Flags: [ SHF_INFO_LINK ] | |
| 111 | Link: .symtab | |
| 112 | AddressAlign: 0x0000000000000004 | |
| 113 | Info: .reloc_min | |
| 114 | Relocations: | |
| 115 | - Offset: 0x0000000000000000 | |
| 116 | Symbol: L5 | |
| 117 | Type: R_RISCV_JAL | |
| 118 | Addend: -1048576 | |
| 119 | - Offset: 0x0000000000000004 | |
| 120 | Symbol: L6 | |
| 121 | Type: R_RISCV_RVC_JUMP | |
| 122 | Addend: -2048 | |
| 123 | Symbols: | |
| 124 | Local: | |
| 125 | - Name: .text | |
| 126 | Type: STT_SECTION | |
| 127 | Section: .text | |
| 128 | - Name: .data | |
| 129 | Type: STT_SECTION | |
| 130 | Section: .data | |
| 131 | - Name: .bss | |
| 132 | Type: STT_SECTION | |
| 133 | Section: .bss | |
| 134 | - Name: .reloc_zero | |
| 135 | Type: STT_SECTION | |
| 136 | Section: .reloc_zero | |
| 137 | - Name: L1 | |
| 138 | Section: .reloc_zero | |
| 139 | - Name: L2 | |
| 140 | Section: .reloc_zero | |
| 141 | Value: 0x0000000000000004 | |
| 142 | - Name: .reloc_max | |
| 143 | Type: STT_SECTION | |
| 144 | Section: .reloc_max | |
| 145 | - Name: L3 | |
| 146 | Section: .reloc_max | |
| 147 | - Name: L4 | |
| 148 | Section: .reloc_max | |
| 149 | Value: 0x0000000000000004 | |
| 150 | - Name: .reloc_min | |
| 151 | Type: STT_SECTION | |
| 152 | Section: .reloc_min | |
| 153 | - Name: L5 | |
| 154 | Section: .reloc_min | |
| 155 | - Name: L6 | |
| 156 | Section: .reloc_min | |
| 157 | Value: 0x0000000000000004 | |
| 158 | Global: | |
| 159 | - Name: _start | |
| 160 | Section: .reloc_zero | |
| 161 | ... |
deps/lld/test/ELF/riscv-pcrel-hilo-error.s created+7| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.o | |
| 3 | # RUN: not ld.lld %t.o --defsym external=0 2>&1 | FileCheck %s | |
| 4 | ||
| 5 | # CHECK: error: R_RISCV_PCREL_LO12 relocation points to an absolute symbol: external | |
| 6 | ||
| 7 | addi sp,sp,%pcrel_lo(external) |
deps/lld/test/ELF/riscv-pcrel-hilo.s created+45| ... | ... | @@ -0,0 +1,45 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=-relax %s -o %t.rv32.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=-relax %s -o %t.rv64.o | |
| 5 | ||
| 6 | # RUN: ld.lld %t.rv32.o --defsym foo=_start+12 --defsym bar=_start -o %t.rv32 | |
| 7 | # RUN: ld.lld %t.rv64.o --defsym foo=_start+12 --defsym bar=_start -o %t.rv64 | |
| 8 | # RUN: llvm-objdump -d --no-show-raw-insn %t.rv32 | FileCheck %s | |
| 9 | # RUN: llvm-objdump -d --no-show-raw-insn %t.rv64 | FileCheck %s | |
| 10 | # RUN: ld.lld -pie %t.rv32.o --defsym foo=_start+12 --defsym bar=_start -o %t.rv32 | |
| 11 | # RUN: ld.lld -pie %t.rv64.o --defsym foo=_start+12 --defsym bar=_start -o %t.rv64 | |
| 12 | # RUN: llvm-objdump -d --no-show-raw-insn %t.rv32 | FileCheck %s | |
| 13 | # RUN: llvm-objdump -d --no-show-raw-insn %t.rv64 | FileCheck %s | |
| 14 | # CHECK: auipc a0, 0 | |
| 15 | # CHECK-NEXT: addi a0, a0, 12 | |
| 16 | # CHECK-NEXT: sw zero, 12(a0) | |
| 17 | # CHECK: auipc a0, 0 | |
| 18 | # CHECK-NEXT: addi a0, a0, -12 | |
| 19 | # CHECK-NEXT: sw zero, -12(a0) | |
| 20 | ||
| 21 | # RUN: ld.lld %t.rv32.o --defsym foo=_start+0x7ffff7ff --defsym bar=_start+12-0x80000800 -o %t.rv32.limits | |
| 22 | # RUN: ld.lld %t.rv64.o --defsym foo=_start+0x7ffff7ff --defsym bar=_start+12-0x80000800 -o %t.rv64.limits | |
| 23 | # RUN: llvm-objdump -d --no-show-raw-insn %t.rv32.limits | FileCheck --check-prefix=LIMITS %s | |
| 24 | # RUN: llvm-objdump -d --no-show-raw-insn %t.rv64.limits | FileCheck --check-prefix=LIMITS %s | |
| 25 | # LIMITS: auipc a0, 524287 | |
| 26 | # LIMITS-NEXT: addi a0, a0, 2047 | |
| 27 | # LIMITS-NEXT: sw zero, 2047(a0) | |
| 28 | # LIMITS: auipc a0, 524288 | |
| 29 | # LIMITS-NEXT: addi a0, a0, -2048 | |
| 30 | # LIMITS-NEXT: sw zero, -2048(a0) | |
| 31 | ||
| 32 | # RUN: ld.lld %t.rv32.o --defsym foo=_start+0x7ffff800 --defsym bar=_start+12-0x80000801 -o %t | |
| 33 | # RUN: not ld.lld %t.rv64.o --defsym foo=_start+0x7ffff800 --defsym bar=_start+12-0x80000801 -o %t 2>&1 | FileCheck --check-prefix=ERROR %s | |
| 34 | # ERROR: relocation R_RISCV_PCREL_HI20 out of range: 524288 is not in [-524288, 524287] | |
| 35 | # ERROR-NEXT: relocation R_RISCV_PCREL_HI20 out of range: -524289 is not in [-524288, 524287] | |
| 36 | ||
| 37 | .global _start | |
| 38 | _start: | |
| 39 | auipc a0, %pcrel_hi(foo) | |
| 40 | addi a0, a0, %pcrel_lo(_start) | |
| 41 | sw x0, %pcrel_lo(_start)(a0) | |
| 42 | .L1: | |
| 43 | auipc a0, %pcrel_hi(bar) | |
| 44 | addi a0, a0, %pcrel_lo(.L1) | |
| 45 | sw x0, %pcrel_lo(.L1)(a0) |
deps/lld/test/ELF/riscv-pcrel-hilo.test deleted-103| ... | ... | @@ -1,103 +0,0 @@ |
| 1 | # .option norelax | |
| 2 | # .global _start | |
| 3 | # | |
| 4 | # _start: | |
| 5 | # auipc a0, %pcrel_hi(_start + 4) | |
| 6 | # addi a0, a0, %pcrel_lo(_start) | |
| 7 | # | |
| 8 | # .section .reloc_neg, "ax", @progbits | |
| 9 | # L1: | |
| 10 | # auipc a0, %pcrel_hi(L1 - 2) | |
| 11 | # addi a0, a0, %pcrel_lo(L1) | |
| 12 | # | |
| 13 | # | |
| 14 | # REQUIRES: riscv | |
| 15 | # RUN: yaml2obj %s -o %t.o | |
| 16 | # RUN: ld.lld %t.o -o %t | |
| 17 | # RUN: obj2yaml %t | FileCheck %s | |
| 18 | # | |
| 19 | # CHECK: - Name: .text | |
| 20 | # CHECK: Content: '1705000013054500' | |
| 21 | # 11000: 00000517 auipc a0,0x0 | |
| 22 | # 11004: 00450513 addi a0,a0,4 # 11004 <_start+0x4> | |
| 23 | # | |
| 24 | # CHECK: - Name: .reloc_neg | |
| 25 | # CHECK: Content: 170500001305E5FF | |
| 26 | # 11008: 00000517 auipc a0,0x0 | |
| 27 | # 1100c: ffe50513 addi a0,a0,-2 # 11006 <_start+0x6> | |
| 28 | ||
| 29 | --- !ELF | |
| 30 | FileHeader: | |
| 31 | Class: ELFCLASS32 | |
| 32 | Data: ELFDATA2LSB | |
| 33 | Type: ET_REL | |
| 34 | Machine: EM_RISCV | |
| 35 | Flags: [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ] | |
| 36 | Sections: | |
| 37 | - Name: .text | |
| 38 | Type: SHT_PROGBITS | |
| 39 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 40 | AddressAlign: 0x0000000000000002 | |
| 41 | Content: '1705000013050500' | |
| 42 | - Name: .rela.text | |
| 43 | Type: SHT_RELA | |
| 44 | Flags: [ SHF_INFO_LINK ] | |
| 45 | Link: .symtab | |
| 46 | AddressAlign: 0x0000000000000004 | |
| 47 | Info: .text | |
| 48 | Relocations: | |
| 49 | - Offset: 0x0000000000000000 | |
| 50 | Symbol: _start | |
| 51 | Type: R_RISCV_PCREL_HI20 | |
| 52 | Addend: 4 | |
| 53 | - Offset: 0x0000000000000004 | |
| 54 | Symbol: _start | |
| 55 | Type: R_RISCV_PCREL_LO12_I | |
| 56 | - Name: .data | |
| 57 | Type: SHT_PROGBITS | |
| 58 | Flags: [ SHF_WRITE, SHF_ALLOC ] | |
| 59 | AddressAlign: 0x0000000000000001 | |
| 60 | Content: '' | |
| 61 | - Name: .bss | |
| 62 | Type: SHT_NOBITS | |
| 63 | Flags: [ SHF_WRITE, SHF_ALLOC ] | |
| 64 | AddressAlign: 0x0000000000000001 | |
| 65 | - Name: .reloc_neg | |
| 66 | Type: SHT_PROGBITS | |
| 67 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] | |
| 68 | AddressAlign: 0x0000000000000001 | |
| 69 | Content: '1705000013050500' | |
| 70 | - Name: .rela.reloc_neg | |
| 71 | Type: SHT_RELA | |
| 72 | Flags: [ SHF_INFO_LINK ] | |
| 73 | Link: .symtab | |
| 74 | AddressAlign: 0x0000000000000004 | |
| 75 | Info: .reloc_neg | |
| 76 | Relocations: | |
| 77 | - Offset: 0x0000000000000000 | |
| 78 | Symbol: L1 | |
| 79 | Type: R_RISCV_PCREL_HI20 | |
| 80 | Addend: -2 | |
| 81 | - Offset: 0x0000000000000004 | |
| 82 | Symbol: L1 | |
| 83 | Type: R_RISCV_PCREL_LO12_I | |
| 84 | Symbols: | |
| 85 | Local: | |
| 86 | - Name: .text | |
| 87 | Type: STT_SECTION | |
| 88 | Section: .text | |
| 89 | - Name: .data | |
| 90 | Type: STT_SECTION | |
| 91 | Section: .data | |
| 92 | - Name: .bss | |
| 93 | Type: STT_SECTION | |
| 94 | Section: .bss | |
| 95 | - Name: .reloc_neg | |
| 96 | Type: STT_SECTION | |
| 97 | Section: .reloc_neg | |
| 98 | - Name: L1 | |
| 99 | Section: .reloc_neg | |
| 100 | Global: | |
| 101 | - Name: _start | |
| 102 | Section: .text | |
| 103 | ... |
deps/lld/test/ELF/riscv-plt.s created+103| ... | ... | @@ -0,0 +1,103 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | # RUN: echo '.globl bar, weak; .type bar,@function; .type weak,@function; bar: weak:' > %t1.s | |
| 3 | ||
| 4 | # RUN: llvm-mc -filetype=obj -triple=riscv32 %t1.s -o %t1.32.o | |
| 5 | # RUN: ld.lld -shared %t1.32.o -o %t1.32.so | |
| 6 | # RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.32.o | |
| 7 | # RUN: ld.lld %t.32.o %t1.32.so -o %t.32 | |
| 8 | # RUN: llvm-readelf -S -s %t.32 | FileCheck --check-prefixes=SEC,NM %s | |
| 9 | # RUN: llvm-readobj -r %t.32 | FileCheck --check-prefix=RELOC32 %s | |
| 10 | # RUN: llvm-readelf -x .got.plt %t.32 | FileCheck --check-prefix=GOTPLT32 %s | |
| 11 | # RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=DIS,DIS32 %s | |
| 12 | ||
| 13 | # RUN: llvm-mc -filetype=obj -triple=riscv64 %t1.s -o %t1.64.o | |
| 14 | # RUN: ld.lld -shared %t1.64.o -o %t1.64.so | |
| 15 | # RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.64.o | |
| 16 | # RUN: ld.lld %t.64.o %t1.64.so -o %t.64 | |
| 17 | # RUN: llvm-readelf -S -s %t.64 | FileCheck --check-prefixes=SEC,NM %s | |
| 18 | # RUN: llvm-readobj -r %t.64 | FileCheck --check-prefix=RELOC64 %s | |
| 19 | # RUN: llvm-readelf -x .got.plt %t.64 | FileCheck --check-prefix=GOTPLT64 %s | |
| 20 | # RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=DIS,DIS64 %s | |
| 21 | ||
| 22 | # SEC: .plt PROGBITS {{0*}}00011030 | |
| 23 | ||
| 24 | ## A canonical PLT has a non-zero st_value. bar and weak are called but their | |
| 25 | ## addresses are not taken, so a canonical PLT is not necessary. | |
| 26 | # NM: {{0*}}00000000 0 FUNC GLOBAL DEFAULT UND bar | |
| 27 | # NM: {{0*}}00000000 0 FUNC WEAK DEFAULT UND weak | |
| 28 | ||
| 29 | ## The .got.plt slots relocated by .rela.plt point to .plt | |
| 30 | ## This is required by glibc. | |
| 31 | # RELOC32: .rela.plt { | |
| 32 | # RELOC32-NEXT: 0x13008 R_RISCV_JUMP_SLOT bar 0x0 | |
| 33 | # RELOC32-NEXT: 0x1300C R_RISCV_JUMP_SLOT weak 0x0 | |
| 34 | # RELOC32-NEXT: } | |
| 35 | # GOTPLT32: section '.got.plt' | |
| 36 | # GOTPLT32-NEXT: 0x00013000 00000000 00000000 30100100 30100100 | |
| 37 | ||
| 38 | # RELOC64: .rela.plt { | |
| 39 | # RELOC64-NEXT: 0x13010 R_RISCV_JUMP_SLOT bar 0x0 | |
| 40 | # RELOC64-NEXT: 0x13018 R_RISCV_JUMP_SLOT weak 0x0 | |
| 41 | # RELOC64-NEXT: } | |
| 42 | # GOTPLT64: section '.got.plt' | |
| 43 | # GOTPLT64-NEXT: 0x00013000 00000000 00000000 00000000 00000000 | |
| 44 | # GOTPLT64-NEXT: 0x00013010 30100100 00000000 30100100 00000000 | |
| 45 | ||
| 46 | # DIS: _start: | |
| 47 | ## Direct call | |
| 48 | ## foo - . = 0x11020-0x11000 = 32 | |
| 49 | # DIS-NEXT: auipc ra, 0 | |
| 50 | # DIS-NEXT: 11004: jalr 32(ra) | |
| 51 | ## bar@plt - . = 0x11050-0x1100c = 72 | |
| 52 | # DIS-NEXT: auipc ra, 0 | |
| 53 | # DIS-NEXT: 1100c: jalr 72(ra) | |
| 54 | ## bar@plt - . = 0x11050-0x11014 = 64 | |
| 55 | # DIS-NEXT: auipc ra, 0 | |
| 56 | # DIS-NEXT: 11014: jalr 64(ra) | |
| 57 | ## weak@plt - . = 0x11060-0x1101c = 72 | |
| 58 | # DIS-NEXT: auipc ra, 0 | |
| 59 | # DIS-NEXT: 1101c: jalr 72(ra) | |
| 60 | # DIS: foo: | |
| 61 | # DIS-NEXT: 11020: | |
| 62 | ||
| 63 | # DIS: Disassembly of section .plt: | |
| 64 | # DIS: .plt: | |
| 65 | # DIS-NEXT: auipc t2, 2 | |
| 66 | # DIS-NEXT: sub t1, t1, t3 | |
| 67 | ## .got.plt - .plt = 0x13000 - 0x11030 = 4096*2-48 | |
| 68 | # DIS32-NEXT: lw t3, -48(t2) | |
| 69 | # DIS64-NEXT: ld t3, -48(t2) | |
| 70 | # DIS-NEXT: addi t1, t1, -44 | |
| 71 | # DIS-NEXT: addi t0, t2, -48 | |
| 72 | # DIS32-NEXT: srli t1, t1, 2 | |
| 73 | # DIS64-NEXT: srli t1, t1, 1 | |
| 74 | # DIS32-NEXT: lw t0, 4(t0) | |
| 75 | # DIS64-NEXT: ld t0, 8(t0) | |
| 76 | # DIS-NEXT: jr t3 | |
| 77 | ||
| 78 | ## 32-bit: &.got.plt[bar]-. = 0x13008-0x11050 = 4096*2-72 | |
| 79 | # DIS: 11050: auipc t3, 2 | |
| 80 | # DIS32-NEXT: lw t3, -72(t3) | |
| 81 | # DIS64-NEXT: ld t3, -64(t3) | |
| 82 | # DIS-NEXT: jalr t1, t3 | |
| 83 | # DIS-NEXT: nop | |
| 84 | ||
| 85 | ## 32-bit: &.got.plt[weak]-. = 0x1300c-0x11060 = 4096*2-84 | |
| 86 | # DIS: 11060: auipc t3, 2 | |
| 87 | # DIS32-NEXT: lw t3, -84(t3) | |
| 88 | # DIS64-NEXT: ld t3, -72(t3) | |
| 89 | # DIS-NEXT: jalr t1, t3 | |
| 90 | # DIS-NEXT: nop | |
| 91 | ||
| 92 | .global _start, foo, bar | |
| 93 | .weak weak | |
| 94 | ||
| 95 | _start: | |
| 96 | call foo | |
| 97 | call bar | |
| 98 | call bar@plt | |
| 99 | call weak | |
| 100 | ||
| 101 | ## foo is local and non-preemptale, no PLT is generated. | |
| 102 | foo: | |
| 103 | ret |
deps/lld/test/ELF/riscv-reloc-64-pic.s created+10| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.o | |
| 3 | # RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s | |
| 4 | ||
| 5 | # CHECK: error: relocation R_RISCV_32 cannot be used against symbol a | |
| 6 | ||
| 7 | .globl a | |
| 8 | ||
| 9 | .data | |
| 10 | .long a |
deps/lld/test/ELF/riscv-reloc-add.s created+32| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax %s -o %t.32.o | |
| 3 | # RUN: ld.lld -pie %t.32.o -o %t.32 | |
| 4 | # RUN: llvm-readelf -x .rodata %t.32 | FileCheck --check-prefix=HEX %s | |
| 5 | ||
| 6 | # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax %s -o %t.64.o | |
| 7 | # RUN: ld.lld -shared %t.64.o -o %t.64 | |
| 8 | # RUN: llvm-readelf -x .rodata %t.64 | FileCheck --check-prefix=HEX %s | |
| 9 | ||
| 10 | # HEX: section '.rodata': | |
| 11 | # HEX-NEXT: 0x{{[0-9a-f]+}} 04000000 00000000 04000000 040004 | |
| 12 | ||
| 13 | ## R_RISCV_ADD* and R_RISCV_SUB* are link-time constants, otherwise they are | |
| 14 | ## not allowed in -pie/-shared mode. | |
| 15 | ||
| 16 | .global _start | |
| 17 | _start: | |
| 18 | .L0: | |
| 19 | ret | |
| 20 | .L1: | |
| 21 | ||
| 22 | .rodata | |
| 23 | .dword .L1 - .L0 | |
| 24 | .word .L1 - .L0 | |
| 25 | .half .L1 - .L0 | |
| 26 | .byte .L1 - .L0 | |
| 27 | ||
| 28 | ## Debug section may use R_RISCV_ADD64/R_RISCV_SUB64 pairs to measure lengths | |
| 29 | ## of code ranges (e.g. DW_AT_high_pc). Check we allow R_RISCV_ADD*/R_RISCV_SUB* | |
| 30 | ## in such non-SHF_ALLOC sections in -pie/-shared mode. | |
| 31 | .section .debug_info | |
| 32 | .quad .L1 - .L0 |
deps/lld/test/ELF/riscv-reloc-copy.s created+23| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=riscv32 %p/Inputs/relocation-copy.s -o %t1.o | |
| 3 | # RUN: ld.lld -shared %t1.o -o %t1.so | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.o | |
| 5 | # RUN: ld.lld %t.o %t1.so -o %t | |
| 6 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s | |
| 7 | # RUN: llvm-nm -S %t | FileCheck --check-prefix=NM32 %s | |
| 8 | ||
| 9 | # RUN: llvm-mc -filetype=obj -triple=riscv64 %p/Inputs/relocation-copy.s -o %t1.o | |
| 10 | # RUN: ld.lld -shared %t1.o -o %t1.so | |
| 11 | # RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.o | |
| 12 | # RUN: ld.lld %t.o %t1.so -o %t | |
| 13 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s | |
| 14 | # RUN: llvm-nm -S %t | FileCheck --check-prefix=NM64 %s | |
| 15 | ||
| 16 | # RELOC: .rela.dyn { | |
| 17 | # RELOC-NEXT: 0x13000 R_RISCV_COPY x 0x0 | |
| 18 | # RELOC-NEXT: } | |
| 19 | ||
| 20 | # NM32: 00013000 00000004 B x | |
| 21 | # NM64: 0000000000013000 0000000000000004 B x | |
| 22 | ||
| 23 | la a0, x |
deps/lld/test/ELF/riscv-reloc-got.s created+65| ... | ... | @@ -0,0 +1,65 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | # RUN: echo '.globl b; b:' | llvm-mc -filetype=obj -triple=riscv32 - -o %t1.o | |
| 3 | # RUN: ld.lld -shared %t1.o -o %t1.so | |
| 4 | ||
| 5 | # RUN: llvm-mc -filetype=obj -triple=riscv32 -position-independent %s -o %t.o | |
| 6 | # RUN: ld.lld %t.o %t1.so -o %t | |
| 7 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC32 %s | |
| 8 | # RUN: llvm-nm %t | FileCheck --check-prefix=NM %s | |
| 9 | # RUN: llvm-readobj -x .got %t | FileCheck --check-prefix=HEX32 %s | |
| 10 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=DIS32 %s | |
| 11 | ||
| 12 | # RUN: echo '.globl b; b:' | llvm-mc -filetype=obj -triple=riscv64 - -o %t1.o | |
| 13 | # RUN: ld.lld -shared %t1.o -o %t1.so | |
| 14 | ||
| 15 | # RUN: llvm-mc -filetype=obj -triple=riscv64 -position-independent %s -o %t.o | |
| 16 | # RUN: ld.lld %t.o %t1.so -o %t | |
| 17 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC64 %s | |
| 18 | # RUN: llvm-nm %t | FileCheck --check-prefix=NM %s | |
| 19 | # RUN: llvm-readobj -x .got %t | FileCheck --check-prefix=HEX64 %s | |
| 20 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=DIS64 %s | |
| 21 | ||
| 22 | # SEC: .got PROGBITS 00012060 020060 00000c | |
| 23 | ||
| 24 | # RELOC32: .rela.dyn { | |
| 25 | # RELOC32-NEXT: 0x12068 R_RISCV_32 b 0x0 | |
| 26 | # RELOC32-NEXT: } | |
| 27 | ||
| 28 | # RELOC64: .rela.dyn { | |
| 29 | # RELOC64-NEXT: 0x120D0 R_RISCV_64 b 0x0 | |
| 30 | # RELOC64-NEXT: } | |
| 31 | ||
| 32 | # NM: 00013000 d a | |
| 33 | ||
| 34 | ## .got[0] = _DYNAMIC | |
| 35 | ## .got[1] = a (filled at link time) | |
| 36 | ## .got[2] = 0 (relocated by R_RISCV_64 at runtime) | |
| 37 | # HEX32: section '.got': | |
| 38 | # HEX32: 0x00012060 00200100 00300100 00000000 | |
| 39 | ||
| 40 | # HEX64: section '.got': | |
| 41 | # HEX64: 0x000120c0 00200100 00000000 00300100 00000000 | |
| 42 | # HEX64: 0x000120d0 00000000 00000000 | |
| 43 | ||
| 44 | ## &.got[1]-. = 0x12060-0x11000 = 4096*1+100 | |
| 45 | # DIS32: 11000: auipc a0, 1 | |
| 46 | # DIS32-NEXT: lw a0, 100(a0) | |
| 47 | ## &.got[2]-. = 0x12064-0x11008 = 4096*1+96 | |
| 48 | # DIS32: 11008: auipc a0, 1 | |
| 49 | # DIS32-NEXT: lw a0, 96(a0) | |
| 50 | ||
| 51 | ## &.got[1]-. = 0x120c8-0x11000 = 4096*1+100 | |
| 52 | # DIS64: 11000: auipc a0, 1 | |
| 53 | # DIS64-NEXT: ld a0, 200(a0) | |
| 54 | ## &.got[2]-. = 0x120d0-0x11008 = 4096*1+200 | |
| 55 | # DIS64: 11008: auipc a0, 1 | |
| 56 | # DIS64-NEXT: ld a0, 200(a0) | |
| 57 | ||
| 58 | la a0,a | |
| 59 | la a0,b | |
| 60 | ||
| 61 | .data | |
| 62 | a: | |
| 63 | ## An undefined reference of _GLOBAL_OFFSET_TABLE_ causes .got[0] to be | |
| 64 | ## allocated to store _DYNAMIC. | |
| 65 | .long _GLOBAL_OFFSET_TABLE_ - . |
deps/lld/test/ELF/riscv-tls-gd.s created+124| ... | ... | @@ -0,0 +1,124 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | # RUN: echo '.tbss; .globl b, c; b: .zero 4; c:' > %t.s | |
| 3 | # RUN: echo '.globl __tls_get_addr; __tls_get_addr:' > %tga.s | |
| 4 | ||
| 5 | ## RISC-V psABI doesn't specify TLS relaxation. Though the code sequences are not | |
| 6 | ## relaxed, dynamic relocations can be omitted for GD->LE relaxation. | |
| 7 | ||
| 8 | # RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.32.o | |
| 9 | # RUN: llvm-mc -filetype=obj -triple=riscv32 %t.s -o %t1.32.o | |
| 10 | # RUN: ld.lld -shared -soname=t1.so %t1.32.o -o %t1.32.so | |
| 11 | # RUN: llvm-mc -filetype=obj -triple=riscv32 %tga.s -o %tga.32.o | |
| 12 | ## rv32 GD | |
| 13 | # RUN: ld.lld -shared %t.32.o %t1.32.o -o %t.32.so | |
| 14 | # RUN: llvm-readobj -r %t.32.so | FileCheck --check-prefix=GD32-REL %s | |
| 15 | # RUN: llvm-objdump -d --no-show-raw-insn %t.32.so | FileCheck --check-prefix=GD32 %s | |
| 16 | ## rv32 GD -> LE | |
| 17 | # RUN: ld.lld %t.32.o %t1.32.o %tga.32.o -o %t.32 | |
| 18 | # RUN: llvm-readelf -r %t.32 | FileCheck --check-prefix=NOREL %s | |
| 19 | # RUN: llvm-readelf -x .got %t.32 | FileCheck --check-prefix=LE32-GOT %s | |
| 20 | # RUN: ld.lld -pie %t.32.o %t1.32.o %tga.32.o -o %t.32 | |
| 21 | # RUN: llvm-readelf -r %t.32 | FileCheck --check-prefix=NOREL %s | |
| 22 | # RUN: llvm-readelf -x .got %t.32 | FileCheck --check-prefix=LE32-GOT %s | |
| 23 | ## rv32 GD -> IE | |
| 24 | # RUN: ld.lld %t.32.o %t1.32.so %tga.32.o -o %t.32 | |
| 25 | # RUN: llvm-readobj -r %t.32 | FileCheck --check-prefix=IE32-REL %s | |
| 26 | # RUN: llvm-readelf -x .got %t.32 | FileCheck --check-prefix=IE32-GOT %s | |
| 27 | ||
| 28 | # RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.64.o | |
| 29 | # RUN: llvm-mc -filetype=obj -triple=riscv64 %t.s -o %t1.64.o | |
| 30 | # RUN: ld.lld -shared -soname=t1.so %t1.64.o -o %t1.64.so | |
| 31 | # RUN: llvm-mc -filetype=obj -triple=riscv64 %tga.s -o %tga.64.o | |
| 32 | ## rv64 GD | |
| 33 | # RUN: ld.lld -shared %t.64.o %t1.64.o -o %t.64.so | |
| 34 | # RUN: llvm-readobj -r %t.64.so | FileCheck --check-prefix=GD64-REL %s | |
| 35 | # RUN: llvm-objdump -d --no-show-raw-insn %t.64.so | FileCheck --check-prefix=GD64 %s | |
| 36 | ## rv64 GD -> LE | |
| 37 | # RUN: ld.lld %t.64.o %t1.64.o %tga.64.o -o %t.64 | |
| 38 | # RUN: llvm-readelf -r %t.64 | FileCheck --check-prefix=NOREL %s | |
| 39 | # RUN: llvm-readelf -x .got %t.64 | FileCheck --check-prefix=LE64-GOT %s | |
| 40 | # RUN: ld.lld -pie %t.64.o %t1.64.o %tga.64.o -o %t.64 | |
| 41 | # RUN: llvm-readelf -r %t.64 | FileCheck --check-prefix=NOREL %s | |
| 42 | # RUN: llvm-readelf -x .got %t.64 | FileCheck --check-prefix=LE64-GOT %s | |
| 43 | ## rv64 GD -> IE | |
| 44 | # RUN: ld.lld %t.64.o %t1.64.so %tga.64.o -o %t.64 | |
| 45 | # RUN: llvm-readobj -r %t.64 | FileCheck --check-prefix=IE64-REL %s | |
| 46 | # RUN: llvm-readelf -x .got %t.64 | FileCheck --check-prefix=IE64-GOT %s | |
| 47 | ||
| 48 | # GD32-REL: .rela.dyn { | |
| 49 | # GD32-REL-NEXT: 0x2070 R_RISCV_TLS_DTPMOD32 a 0x0 | |
| 50 | # GD32-REL-NEXT: 0x2074 R_RISCV_TLS_DTPREL32 a 0x0 | |
| 51 | # GD32-REL-NEXT: 0x2078 R_RISCV_TLS_DTPMOD32 b 0x0 | |
| 52 | # GD32-REL-NEXT: 0x207C R_RISCV_TLS_DTPREL32 b 0x0 | |
| 53 | # GD32-REL-NEXT: } | |
| 54 | ||
| 55 | ## &DTPMOD(a) - . = 0x2070 - 0x1000 = 4096*1+112 | |
| 56 | # GD32: 1000: auipc a0, 1 | |
| 57 | # GD32-NEXT: addi a0, a0, 112 | |
| 58 | # GD32-NEXT: auipc ra, 0 | |
| 59 | # GD32-NEXT: jalr 56(ra) | |
| 60 | ||
| 61 | ## &DTPMOD(b) - . = 0x2078 - 0x1010 = 4096*1+104 | |
| 62 | # GD32: 1010: auipc a0, 1 | |
| 63 | # GD32-NEXT: addi a0, a0, 104 | |
| 64 | # GD32-NEXT: auipc ra, 0 | |
| 65 | # GD32-NEXT: jalr 40(ra) | |
| 66 | ||
| 67 | # GD64-REL: .rela.dyn { | |
| 68 | # GD64-REL-NEXT: 0x20E0 R_RISCV_TLS_DTPMOD64 a 0x0 | |
| 69 | # GD64-REL-NEXT: 0x20E8 R_RISCV_TLS_DTPREL64 a 0x0 | |
| 70 | # GD64-REL-NEXT: 0x20F0 R_RISCV_TLS_DTPMOD64 b 0x0 | |
| 71 | # GD64-REL-NEXT: 0x20F8 R_RISCV_TLS_DTPREL64 b 0x0 | |
| 72 | # GD64-REL-NEXT: } | |
| 73 | ||
| 74 | ## &DTPMOD(a) - . = 0x20e0 - 0x1000 = 4096*1+224 | |
| 75 | # GD64: 1000: auipc a0, 1 | |
| 76 | # GD64-NEXT: addi a0, a0, 224 | |
| 77 | # GD64-NEXT: auipc ra, 0 | |
| 78 | # GD64-NEXT: jalr 56(ra) | |
| 79 | ||
| 80 | ## &DTPMOD(b) - . = 0x20f0 - 0x1010 = 4096*1+224 | |
| 81 | # GD64: 1010: auipc a0, 1 | |
| 82 | # GD64-NEXT: addi a0, a0, 224 | |
| 83 | # GD64-NEXT: auipc ra, 0 | |
| 84 | # GD64-NEXT: jalr 40(ra) | |
| 85 | ||
| 86 | # NOREL: no relocations | |
| 87 | ||
| 88 | ## .got contains pre-populated values: [a@dtpmod, a@dtprel, b@dtpmod, b@dtprel] | |
| 89 | ## a@dtprel = st_value(a)-0x800 = 0xfffff808 | |
| 90 | ## b@dtprel = st_value(b)-0x800 = 0xfffff80c | |
| 91 | # LE32-GOT: section '.got': | |
| 92 | # LE32-GOT-NEXT: 0x{{[0-9a-f]+}} 01000000 08f8ffff 01000000 0cf8ffff | |
| 93 | # LE64-GOT: section '.got': | |
| 94 | # LE64-GOT-NEXT: 0x{{[0-9a-f]+}} 01000000 00000000 08f8ffff ffffffff | |
| 95 | # LE64-GOT-NEXT: 0x{{[0-9a-f]+}} 01000000 00000000 0cf8ffff ffffffff | |
| 96 | ||
| 97 | ## a is local - relaxed to LE - its DTPMOD/DTPREL slots are link-time constants. | |
| 98 | ## b is external - DTPMOD/DTPREL dynamic relocations are required. | |
| 99 | # IE32-REL: .rela.dyn { | |
| 100 | # IE32-REL-NEXT: 0x12068 R_RISCV_TLS_DTPMOD32 b 0x0 | |
| 101 | # IE32-REL-NEXT: 0x1206C R_RISCV_TLS_DTPREL32 b 0x0 | |
| 102 | # IE32-REL-NEXT: } | |
| 103 | # IE32-GOT: section '.got': | |
| 104 | # IE32-GOT-NEXT: 0x00012060 01000000 08f8ffff 00000000 00000000 | |
| 105 | ||
| 106 | # IE64-REL: .rela.dyn { | |
| 107 | # IE64-REL-NEXT: 0x120D0 R_RISCV_TLS_DTPMOD64 b 0x0 | |
| 108 | # IE64-REL-NEXT: 0x120D8 R_RISCV_TLS_DTPREL64 b 0x0 | |
| 109 | # IE64-REL-NEXT: } | |
| 110 | # IE64-GOT: section '.got': | |
| 111 | # IE64-GOT-NEXT: 0x000120c0 01000000 00000000 08f8ffff ffffffff | |
| 112 | # IE64-GOT-NEXT: 0x000120d0 00000000 00000000 00000000 00000000 | |
| 113 | ||
| 114 | la.tls.gd a0,a | |
| 115 | call __tls_get_addr@plt | |
| 116 | ||
| 117 | la.tls.gd a0,b | |
| 118 | call __tls_get_addr@plt | |
| 119 | ||
| 120 | .section .tbss | |
| 121 | .globl a | |
| 122 | .zero 8 | |
| 123 | a: | |
| 124 | .zero 4 |
deps/lld/test/ELF/riscv-tls-ie.s created+82| ... | ... | @@ -0,0 +1,82 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.32.o | |
| 4 | ## rv32 IE | |
| 5 | # RUN: ld.lld -shared %t.32.o -o %t.32.so | |
| 6 | # RUN: llvm-readobj -r -d %t.32.so | FileCheck --check-prefix=IE32-REL %s | |
| 7 | # RUN: llvm-objdump -d --no-show-raw-insn %t.32.so | FileCheck --check-prefixes=IE,IE32 %s | |
| 8 | ## rv32 IE -> LE | |
| 9 | # RUN: ld.lld %t.32.o -o %t.32 | |
| 10 | # RUN: llvm-readelf -r %t.32 | FileCheck --check-prefix=NOREL %s | |
| 11 | # RUN: llvm-readelf -x .got %t.32 | FileCheck --check-prefix=LE32-GOT %s | |
| 12 | # RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=LE,LE32 %s | |
| 13 | ||
| 14 | # RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.64.o | |
| 15 | ## rv64 IE | |
| 16 | # RUN: ld.lld -shared %t.64.o -o %t.64.so | |
| 17 | # RUN: llvm-readobj -r -d %t.64.so | FileCheck --check-prefix=IE64-REL %s | |
| 18 | # RUN: llvm-objdump -d --no-show-raw-insn %t.64.so | FileCheck --check-prefixes=IE,IE64 %s | |
| 19 | ## rv64 IE -> LE | |
| 20 | # RUN: ld.lld %t.64.o -o %t.64 | |
| 21 | # RUN: llvm-readelf -r %t.64 | FileCheck --check-prefix=NOREL %s | |
| 22 | # RUN: llvm-readelf -x .got %t.64 | FileCheck --check-prefix=LE64-GOT %s | |
| 23 | # RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=LE,LE64 %s | |
| 24 | ||
| 25 | # IE32-REL: .rela.dyn { | |
| 26 | # IE32-REL-NEXT: 0x205C R_RISCV_TLS_TPREL32 - 0xC | |
| 27 | # IE32-REL-NEXT: 0x2058 R_RISCV_TLS_TPREL32 a 0x0 | |
| 28 | # IE32-REL-NEXT: } | |
| 29 | # IE32-REL: FLAGS STATIC_TLS | |
| 30 | ||
| 31 | # IE64-REL: .rela.dyn { | |
| 32 | # IE64-REL-NEXT: 0x20B8 R_RISCV_TLS_TPREL64 - 0xC | |
| 33 | # IE64-REL-NEXT: 0x20B0 R_RISCV_TLS_TPREL64 a 0x0 | |
| 34 | # IE64-REL-NEXT: } | |
| 35 | # IE64-REL: FLAGS STATIC_TLS | |
| 36 | ||
| 37 | ## rv32: &.got[1] - . = 0x2058 - . = 4096*1+88 | |
| 38 | ## rv64: &.got[1] - . = 0x20B0 - . = 4096*1+176 | |
| 39 | # IE: 1000: auipc a4, 1 | |
| 40 | # IE32-NEXT: lw a4, 88(a4) | |
| 41 | # IE64-NEXT: ld a4, 176(a4) | |
| 42 | # IE-NEXT: add a4, a4, tp | |
| 43 | ## rv32: &.got[0] - . = 0x205C - . = 4096*1+80 | |
| 44 | ## rv64: &.got[0] - . = 0x20B8 - . = 4096*1+172 | |
| 45 | # IE: 100c: auipc a5, 1 | |
| 46 | # IE32-NEXT: lw a5, 80(a5) | |
| 47 | # IE64-NEXT: ld a5, 172(a5) | |
| 48 | # IE-NEXT: add a5, a5, tp | |
| 49 | ||
| 50 | # NOREL: no relocations | |
| 51 | ||
| 52 | # a@tprel = st_value(a) = 0x8 | |
| 53 | # b@tprel = st_value(a) = 0xc | |
| 54 | # LE32-GOT: section '.got': | |
| 55 | # LE32-GOT-NEXT: 0x00012000 08000000 0c000000 | |
| 56 | # LE64-GOT: section '.got': | |
| 57 | # LE64-GOT-NEXT: 0x00012000 08000000 00000000 0c000000 00000000 | |
| 58 | ||
| 59 | ## rv32: &.got[0] - . = 0x12000 - 0x11000 = 4096*1+0 | |
| 60 | ## rv64: &.got[0] - . = 0x12000 - 0x11000 = 4096*1+0 | |
| 61 | # LE: 11000: auipc a4, 1 | |
| 62 | # LE32-NEXT: lw a4, 0(a4) | |
| 63 | # LE64-NEXT: ld a4, 0(a4) | |
| 64 | # LE-NEXT: add a4, a4, tp | |
| 65 | ## rv32: &.got[1] - . = 0x12004 - 0x1100c = 4096*1-8 | |
| 66 | ## rv64: &.got[1] - . = 0x12008 - 0x1100c = 4096*1-4 | |
| 67 | # LE: 1100c: auipc a5, 1 | |
| 68 | # LE32-NEXT: lw a5, -8(a5) | |
| 69 | # LE64-NEXT: ld a5, -4(a5) | |
| 70 | # LE-NEXT: add a5, a5, tp | |
| 71 | ||
| 72 | la.tls.ie a4,a | |
| 73 | add a4,a4,tp | |
| 74 | la.tls.ie a5,b | |
| 75 | add a5,a5,tp | |
| 76 | ||
| 77 | .section .tbss | |
| 78 | .globl a | |
| 79 | .zero 8 | |
| 80 | a: | |
| 81 | .zero 4 | |
| 82 | b: |
deps/lld/test/ELF/riscv-tls-ld.s created+90| ... | ... | @@ -0,0 +1,90 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | # RUN: echo '.tbss; .globl b, c; b: .zero 4; c:' > %t.s | |
| 3 | # RUN: echo '.globl __tls_get_addr; __tls_get_addr:' > %tga.s | |
| 4 | ||
| 5 | ## RISC-V psABI doesn't specify TLS relaxation. Though the code sequences are not | |
| 6 | ## relaxed, dynamic relocations can be omitted for LD->LE relaxation. | |
| 7 | ## LD uses the same relocation as GD: R_RISCV_GD_HI20, the difference is that it | |
| 8 | ## references a local symbol (.LANCHOR0). | |
| 9 | ||
| 10 | # RUN: llvm-mc -filetype=obj -triple=riscv32 -position-independent %s -o %t.32.o | |
| 11 | # RUN: llvm-mc -filetype=obj -triple=riscv32 %tga.s -o %tga.o | |
| 12 | ## rv32 LD | |
| 13 | # RUN: ld.lld -shared %t.32.o -o %t.32.so | |
| 14 | # RUN: llvm-readobj -r %t.32.so | FileCheck --check-prefix=LD32-REL %s | |
| 15 | # RUN: llvm-readelf -x .got %t.32.so | FileCheck --check-prefix=LD32-GOT %s | |
| 16 | # RUN: llvm-objdump -d --no-show-raw-insn %t.32.so | FileCheck --check-prefixes=LD,LD32 %s | |
| 17 | ## rv32 LD -> LE | |
| 18 | # RUN: ld.lld %t.32.o %tga.o -o %t.32 | |
| 19 | # RUN: llvm-readelf -r %t.32 | FileCheck --check-prefix=NOREL %s | |
| 20 | # RUN: llvm-readelf -x .got %t.32 | FileCheck --check-prefix=LE32-GOT %s | |
| 21 | # RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=LE,LE32 %s | |
| 22 | ||
| 23 | # RUN: llvm-mc -filetype=obj -triple=riscv64 -position-independent %s -o %t.64.o | |
| 24 | # RUN: llvm-mc -filetype=obj -triple=riscv64 %tga.s -o %tga.o | |
| 25 | ## rv64 LD | |
| 26 | # RUN: ld.lld -shared %t.64.o -o %t.64.so | |
| 27 | # RUN: llvm-readobj -r %t.64.so | FileCheck --check-prefix=LD64-REL %s | |
| 28 | # RUN: llvm-readelf -x .got %t.64.so | FileCheck --check-prefix=LD64-GOT %s | |
| 29 | # RUN: llvm-objdump -d --no-show-raw-insn %t.64.so | FileCheck --check-prefixes=LD,LD64 %s | |
| 30 | ## rv64 LD -> LE | |
| 31 | # RUN: ld.lld %t.64.o %tga.o -o %t.64 | |
| 32 | # RUN: llvm-readelf -r %t.64 | FileCheck --check-prefix=NOREL %s | |
| 33 | # RUN: llvm-readelf -x .got %t.64 | FileCheck --check-prefix=LE64-GOT %s | |
| 34 | # RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=LE,LE64 %s | |
| 35 | ||
| 36 | ## a@dtprel = st_value(a)-0x800 = 0xfffff808 is a link-time constant. | |
| 37 | # LD32-REL: .rela.dyn { | |
| 38 | # LD32-REL-NEXT: 0x2084 | |
| 39 | # LD32-REL-NEXT: 0x207C R_RISCV_TLS_DTPMOD32 - 0x0 | |
| 40 | # LD32-REL-NEXT: } | |
| 41 | # LD32-GOT: section '.got': | |
| 42 | # LD32-GOT-NEXT: 0x00002078 00200000 00000000 00f8ffff 00000000 | |
| 43 | ||
| 44 | # LD64-REL: .rela.dyn { | |
| 45 | # LD64-REL-NEXT: 0x2108 | |
| 46 | # LD64-REL-NEXT: 0x20F8 R_RISCV_TLS_DTPMOD64 - 0x0 | |
| 47 | # LD64-REL-NEXT: } | |
| 48 | # LD64-GOT: section '.got': | |
| 49 | # LD64-GOT-NEXT: 0x000020f0 00200000 00000000 00000000 00000000 | |
| 50 | # LD64-GOT-NEXT: 0x00002100 00f8ffff ffffffff 00000000 00000000 | |
| 51 | ||
| 52 | ## rv32: &DTPMOD(a) - . = 0x207c - 0x1000 = 4096*1+124 | |
| 53 | ## rv64: &DTPMOD(a) - . = 0x20e0 - 0x1000 = 4096*1+248 | |
| 54 | # LD: 1000: auipc a0, 1 | |
| 55 | # LD32-NEXT: addi a0, a0, 124 | |
| 56 | # LD64-NEXT: addi a0, a0, 248 | |
| 57 | # LD-NEXT: auipc ra, 0 | |
| 58 | # LD-NEXT: jalr 56(ra) | |
| 59 | ||
| 60 | # NOREL: no relocations | |
| 61 | ||
| 62 | ## a is local - its DTPMOD/DTPREL slots are link-time constants. | |
| 63 | ## a@dtpmod = 1 (main module) | |
| 64 | # LE32-GOT: section '.got': | |
| 65 | # LE32-GOT-NEXT: 0x00012000 00000000 01000000 00f8ffff 00200100 | |
| 66 | ||
| 67 | # LE64-GOT: section '.got': | |
| 68 | # LE64-GOT-NEXT: 0x00012000 00000000 00000000 01000000 00000000 | |
| 69 | # LE64-GOT-NEXT: 0x00012010 00f8ffff ffffffff 00200100 00000000 | |
| 70 | ||
| 71 | ## rv32: DTPMOD(.LANCHOR0) - . = 0x12004 - 0x11000 = 4096*1+4 | |
| 72 | ## rv64: DTPMOD(.LANCHOR0) - . = 0x12008 - 0x11000 = 4096*1+8 | |
| 73 | # LE: 11000: auipc a0, 1 | |
| 74 | # LE32-NEXT: addi a0, a0, 4 | |
| 75 | # LE64-NEXT: addi a0, a0, 8 | |
| 76 | # LE-NEXT: auipc ra, 0 | |
| 77 | # LE-NEXT: jalr 24(ra) | |
| 78 | ||
| 79 | la.tls.gd a0, .LANCHOR0 | |
| 80 | call __tls_get_addr@plt | |
| 81 | lw a4, 0(a0) | |
| 82 | lh a0, 4(a0) | |
| 83 | ||
| 84 | ## This is irrelevant to TLS. We use it to take 2 GOT slots to check DTPREL | |
| 85 | ## offsets are correct. | |
| 86 | la a5, _GLOBAL_OFFSET_TABLE_ | |
| 87 | ||
| 88 | .section .tbss,"awT",@nobits | |
| 89 | .set .LANCHOR0, . + 0 | |
| 90 | .zero 8 |
deps/lld/test/ELF/riscv-tls-le.s created+41| ... | ... | @@ -0,0 +1,41 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.32.o | |
| 4 | # RUN: ld.lld %t.32.o -o %t.32 | |
| 5 | # RUN: llvm-nm -p %t.32 | FileCheck --check-prefixes=NM %s | |
| 6 | # RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=LE %s | |
| 7 | # RUN: ld.lld -pie %t.32.o -o %t.32 | |
| 8 | # RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=LE %s | |
| 9 | ||
| 10 | # RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.64.o | |
| 11 | # RUN: ld.lld %t.64.o -o %t.64 | |
| 12 | # RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=LE %s | |
| 13 | # RUN: ld.lld -pie %t.64.o -o %t.64 | |
| 14 | # RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=LE %s | |
| 15 | ||
| 16 | # NM: {{0*}}00000008 b .LANCHOR0 | |
| 17 | # NM: {{0*}}0000000c B a | |
| 18 | ||
| 19 | ## .LANCHOR0@tprel = 8 | |
| 20 | ## a@tprel = 12 | |
| 21 | # LE: lui a5, 0 | |
| 22 | # LE-NEXT: add a5, a5, tp | |
| 23 | # LE-NEXT: addi a5, a5, 8 | |
| 24 | # LE-NEXT: lui a5, 0 | |
| 25 | # LE-NEXT: add a5, a5, tp | |
| 26 | # LE-NEXT: sw a0, 12(a5) | |
| 27 | ||
| 28 | lui a5, %tprel_hi(.LANCHOR0) | |
| 29 | add a5, a5, tp, %tprel_add(.LANCHOR0) | |
| 30 | addi a5, a5, %tprel_lo(.LANCHOR0) | |
| 31 | ||
| 32 | lui a5, %tprel_hi(a) | |
| 33 | add a5, a5, tp, %tprel_add(a) | |
| 34 | sw a0, %tprel_lo(a)(a5) | |
| 35 | ||
| 36 | .section .tbss | |
| 37 | .space 8 | |
| 38 | .LANCHOR0: | |
| 39 | .zero 4 | |
| 40 | .globl a | |
| 41 | a: |
deps/lld/test/ELF/riscv32-reloc-32-pic.s created+23| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.o | |
| 3 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 4 | # RUN: llvm-nm %t.so | FileCheck --check-prefix=NM %s | |
| 5 | # RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=RELOC %s | |
| 6 | ||
| 7 | ## R_RISCV_32 is an absolute relocation type. | |
| 8 | ## In PIC mode, it creates a relative relocation if the symbol is non-preemptable. | |
| 9 | ||
| 10 | # NM: 00002004 d b | |
| 11 | ||
| 12 | # RELOC: .rela.dyn { | |
| 13 | # RELOC-NEXT: 0x2004 R_RISCV_RELATIVE - 0x2004 | |
| 14 | # RELOC-NEXT: 0x2000 R_RISCV_32 a 0 | |
| 15 | # RELOC-NEXT: } | |
| 16 | ||
| 17 | .globl a, b | |
| 18 | .hidden b | |
| 19 | ||
| 20 | .data | |
| 21 | .long a | |
| 22 | b: | |
| 23 | .long b |
deps/lld/test/ELF/riscv64-reloc-64-pic.s created+23| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | # REQUIRES: riscv | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.o | |
| 3 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 4 | # RUN: llvm-nm %t.so | FileCheck --check-prefix=NM %s | |
| 5 | # RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=RELOC %s | |
| 6 | ||
| 7 | ## R_RISCV_64 is an absolute relocation type. | |
| 8 | ## In PIC mode, it creates a relative relocation if the symbol is non-preemptable. | |
| 9 | ||
| 10 | # NM: 0000000000002008 d b | |
| 11 | ||
| 12 | # RELOC: .rela.dyn { | |
| 13 | # RELOC-NEXT: 0x2008 R_RISCV_RELATIVE - 0x2008 | |
| 14 | # RELOC-NEXT: 0x2000 R_RISCV_64 a 0 | |
| 15 | # RELOC-NEXT: } | |
| 16 | ||
| 17 | .globl a, b | |
| 18 | .hidden b | |
| 19 | ||
| 20 | .data | |
| 21 | .quad a | |
| 22 | b: | |
| 23 | .quad b |
deps/lld/test/ELF/rodynamic.s+4-4| ... | ... | @@ -4,13 +4,13 @@ |
| 4 | 4 | |
| 5 | 5 | # RUN: ld.lld -shared %t.so.o -o %t.so |
| 6 | 6 | # RUN: ld.lld %t.o %t.so -o %t.exe |
| 7 | # RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=DEFDEBUG %s | |
| 8 | # RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=DEFSEC %s | |
| 7 | # RUN: llvm-readobj --dynamic-table %t.exe | FileCheck -check-prefix=DEFDEBUG %s | |
| 8 | # RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=DEFSEC %s | |
| 9 | 9 | |
| 10 | 10 | # RUN: ld.lld -shared -z rodynamic %t.so.o -o %t.so |
| 11 | 11 | # RUN: ld.lld -z rodynamic %t.o %t.so -o %t.exe |
| 12 | # RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=RODEBUG %s | |
| 13 | # RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=ROSEC %s | |
| 12 | # RUN: llvm-readobj --dynamic-table %t.exe | FileCheck -check-prefix=RODEBUG %s | |
| 13 | # RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=ROSEC %s | |
| 14 | 14 | |
| 15 | 15 | .globl _start |
| 16 | 16 | _start: |
deps/lld/test/ELF/section-align-0.test+3-3| ... | ... | @@ -15,6 +15,6 @@ Sections: |
| 15 | 15 | AddressAlign: 0 |
| 16 | 16 | |
| 17 | 17 | Symbols: |
| 18 | Global: | |
| 19 | - Name: _start | |
| 20 | Section: .text | |
| 18 | - Name: _start | |
| 19 | Section: .text | |
| 20 | Binding: STB_GLOBAL |
deps/lld/test/ELF/section-layout.s+5-4| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | # RUN: ld.lld %t -o %tout |
| 4 | # RUN: llvm-readobj -sections %tout | FileCheck %s | |
| 4 | # RUN: llvm-readobj --sections %tout | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # Check that sections are laid out in the correct order. |
| 7 | 7 | |
| ... | ... | @@ -32,6 +32,7 @@ _start: |
| 32 | 32 | // For non-executable and non-writable sections, PROGBITS appear after others. |
| 33 | 33 | // CHECK: Name: a |
| 34 | 34 | // CHECK: Name: b |
| 35 | ||
| 35 | 36 | // CHECK: Name: c |
| 36 | 37 | // CHECK: Name: d |
| 37 | 38 | |
| ... | ... | @@ -40,13 +41,13 @@ _start: |
| 40 | 41 | // CHECK: Name: k |
| 41 | 42 | // CHECK: Name: l |
| 42 | 43 | |
| 43 | // Writable sections appear before TLS and other relro sections. | |
| 44 | // CHECK: Name: i | |
| 45 | ||
| 46 | 44 | // TLS sections are only sorted on NOBITS. |
| 47 | 45 | // CHECK: Name: e |
| 48 | 46 | // CHECK: Name: g |
| 49 | 47 | |
| 48 | // Writable sections appear after TLS and other relro sections. | |
| 49 | // CHECK: Name: i | |
| 50 | ||
| 50 | 51 | // CHECK: Name: j |
| 51 | 52 | |
| 52 | 53 | // Non allocated sections are in input order. |
deps/lld/test/ELF/section-name.s+6-6| ... | ... | @@ -45,12 +45,12 @@ _start: |
| 45 | 45 | // CHECK: 1 .rodata 00000002 |
| 46 | 46 | // CHECK: 2 .gcc_except_table 00000001 |
| 47 | 47 | // CHECK: 3 .text 00000002 |
| 48 | // CHECK: 4 .data 00000002 | |
| 49 | // CHECK: 5 .foo.a 00000001 | |
| 50 | // CHECK: 6 .foo 00000001 | |
| 51 | // CHECK: 7 .tdata 00000001 | |
| 52 | // CHECK: 8 .tbss 00000001 | |
| 53 | // CHECK: 9 .data.rel.ro 00000004 | |
| 48 | // CHECK: 4 .tdata 00000001 | |
| 49 | // CHECK: 5 .tbss 00000001 | |
| 50 | // CHECK: 6 .data.rel.ro 00000004 | |
| 51 | // CHECK: 7 .data 00000002 | |
| 52 | // CHECK: 8 .foo.a 00000001 | |
| 53 | // CHECK: 9 .foo 00000001 | |
| 54 | 54 | // CHECK: 10 .bss 00000002 |
| 55 | 55 | // CHECK: 11 .comment 00000008 |
| 56 | 56 | // CHECK: 12 .symtab 00000030 |
deps/lld/test/ELF/section-symbol.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld %t -o %t.so -shared -discard-none |
| 4 | // RUN: llvm-readobj -t %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // Test that we don't include the section symbols from the .o in the .so |
| 7 | 7 |
deps/lld/test/ELF/section-symbols.test+8-9| ... | ... | @@ -24,12 +24,11 @@ Sections: |
| 24 | 24 | Info: .text |
| 25 | 25 | Relocations: |
| 26 | 26 | Symbols: |
| 27 | Local: | |
| 28 | - Type: STT_SECTION | |
| 29 | Section: .rela.text | |
| 30 | - Type: STT_SECTION | |
| 31 | Section: .shstrtab | |
| 32 | - Type: STT_SECTION | |
| 33 | Section: .symtab | |
| 34 | - Type: STT_SECTION | |
| 35 | Section: .strtab | |
| 27 | - Type: STT_SECTION | |
| 28 | Section: .rela.text | |
| 29 | - Type: STT_SECTION | |
| 30 | Section: .shstrtab | |
| 31 | - Type: STT_SECTION | |
| 32 | Section: .symtab | |
| 33 | - Type: STT_SECTION | |
| 34 | Section: .strtab |
deps/lld/test/ELF/sectionstart-noallochdr.s+1-1| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | # RUN: llvm-objdump -section-headers %t1 | FileCheck %s |
| 6 | 6 | |
| 7 | 7 | # CHECK: Sections: |
| 8 | # CHECK-NEXT: Idx Name Size Address Type | |
| 8 | # CHECK-NEXT: Idx Name Size VMA Type | |
| 9 | 9 | # CHECK-NEXT: 0 00000000 0000000000000000 |
| 10 | 10 | # CHECK-NEXT: 1 .text 00000001 0000000000000010 TEXT |
| 11 | 11 | # CHECK-NEXT: 2 .data 00000004 0000000000000020 DATA |
deps/lld/test/ELF/sectionstart.s+4-4| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | # RUN: llvm-objdump -section-headers %t | FileCheck %s |
| 6 | 6 | |
| 7 | 7 | # CHECK: Sections: |
| 8 | # CHECK-NEXT: Idx Name Size Address Type | |
| 8 | # CHECK-NEXT: Idx Name Size VMA Type | |
| 9 | 9 | # CHECK-NEXT: 0 00000000 0000000000000000 |
| 10 | 10 | # CHECK-NEXT: 1 .text 00000001 0000000000100000 TEXT |
| 11 | 11 | # CHECK-NEXT: 2 .data 00000004 0000000000110000 DATA |
| ... | ... | @@ -45,15 +45,15 @@ |
| 45 | 45 | |
| 46 | 46 | # RUN: not ld.lld %t.o -Ttext=1w0000 -o %t6 2>&1 \ |
| 47 | 47 | # RUN: | FileCheck -check-prefix=ERR3 %s |
| 48 | # ERR3: invalid argument: --Ttext 1w0000 | |
| 48 | # ERR3: invalid argument: -Ttext=1w0000 | |
| 49 | 49 | |
| 50 | 50 | # RUN: not ld.lld %t.o -Tbss=1w0000 -o %t6 2>&1 \ |
| 51 | 51 | # RUN: | FileCheck -check-prefix=ERR4 %s |
| 52 | # ERR4: invalid argument: --Tbss 1w0000 | |
| 52 | # ERR4: invalid argument: -Tbss=1w0000 | |
| 53 | 53 | |
| 54 | 54 | # RUN: not ld.lld %t.o -Tdata=1w0000 -o %t6 2>&1 \ |
| 55 | 55 | # RUN: | FileCheck -check-prefix=ERR5 %s |
| 56 | # ERR5: invalid argument: --Tdata 1w0000 | |
| 56 | # ERR5: invalid argument: -Tdata=1w0000 | |
| 57 | 57 | |
| 58 | 58 | .text |
| 59 | 59 | .globl _start |
deps/lld/test/ELF/segments.s+46-2| ... | ... | @@ -84,7 +84,7 @@ |
| 84 | 84 | |
| 85 | 85 | # OMAGIC: ProgramHeader { |
| 86 | 86 | # OMAGIC: Type: PT_LOAD |
| 87 | # OMAGIC-NEXT: Offset: 0x0 | |
| 87 | # OMAGIC-NEXT: Offset: 0xE8 | |
| 88 | 88 | # OMAGIC-NEXT: VirtualAddress: |
| 89 | 89 | # OMAGIC-NEXT: PhysicalAddress: |
| 90 | 90 | # OMAGIC-NEXT: FileSize: |
| ... | ... | @@ -94,11 +94,55 @@ |
| 94 | 94 | # OMAGIC-NEXT: PF_W |
| 95 | 95 | # OMAGIC-NEXT: PF_X |
| 96 | 96 | # OMAGIC-NEXT: ] |
| 97 | # OMAGIC-NEXT: Alignment: 4096 | |
| 97 | # OMAGIC-NEXT: Alignment: 8 | |
| 98 | 98 | # OMAGIC-NEXT: } |
| 99 | 99 | # OMAGIC-NEXT: ProgramHeader { |
| 100 | 100 | # OMAGIC-NEXT: Type: PT_GNU_STACK |
| 101 | 101 | |
| 102 | # RUN: ld.lld -n %t -o %t4 | |
| 103 | # RUN: llvm-readobj --program-headers %t4 | FileCheck --check-prefix=NMAGIC %s | |
| 104 | # RUN: ld.lld --nmagic %t -o %t4 | |
| 105 | # RUN: llvm-readobj --program-headers %t4 | FileCheck --check-prefix=NMAGIC %s | |
| 106 | ||
| 107 | # NMAGIC: ProgramHeader { | |
| 108 | # NMAGIC-NEXT: Type: PT_LOAD | |
| 109 | # NMAGIC-NEXT: Offset: 0x158 | |
| 110 | # NMAGIC-NEXT: VirtualAddress: | |
| 111 | # NMAGIC-NEXT: PhysicalAddress: | |
| 112 | # NMAGIC-NEXT: FileSize: 1 | |
| 113 | # NMAGIC-NEXT: MemSize: 1 | |
| 114 | # NMAGIC-NEXT: Flags [ | |
| 115 | # NMAGIC-NEXT: PF_R | |
| 116 | # NMAGIC-NEXT: ] | |
| 117 | # NMAGIC-NEXT: Alignment: 8 | |
| 118 | # NMAGIC-NEXT: } | |
| 119 | # NMAGIC-NEXT: ProgramHeader { | |
| 120 | # NMAGIC-NEXT: Type: PT_LOAD | |
| 121 | # NMAGIC-NEXT: Offset: 0x15C | |
| 122 | # NMAGIC-NEXT: VirtualAddress: | |
| 123 | # NMAGIC-NEXT: PhysicalAddress: | |
| 124 | # NMAGIC-NEXT: FileSize: 2 | |
| 125 | # NMAGIC-NEXT: MemSize: 2 | |
| 126 | # NMAGIC-NEXT: Flags [ | |
| 127 | # NMAGIC-NEXT: PF_R | |
| 128 | # NMAGIC-NEXT: PF_X | |
| 129 | # NMAGIC-NEXT: ] | |
| 130 | # NMAGIC-NEXT: Alignment: 4 | |
| 131 | # NMAGIC-NEXT: } | |
| 132 | # NMAGIC-NEXT: ProgramHeader { | |
| 133 | # NMAGIC-NEXT: Type: PT_LOAD (0x1) | |
| 134 | # NMAGIC-NEXT: Offset: 0x15E | |
| 135 | # NMAGIC-NEXT: VirtualAddress: | |
| 136 | # NMAGIC-NEXT: PhysicalAddress: | |
| 137 | # NMAGIC-NEXT: FileSize: 1 | |
| 138 | # NMAGIC-NEXT: MemSize: 1 | |
| 139 | # NMAGIC-NEXT: Flags [ | |
| 140 | # NMAGIC-NEXT: PF_R | |
| 141 | # NMAGIC-NEXT: PF_W | |
| 142 | # NMAGIC-NEXT: ] | |
| 143 | # NMAGIC-NEXT: Alignment: 1 | |
| 144 | # NMAGIC-NEXT: } | |
| 145 | ||
| 102 | 146 | .global _start |
| 103 | 147 | _start: |
| 104 | 148 | nop |
deps/lld/test/ELF/shared-ppc64.s+5-5| ... | ... | @@ -4,13 +4,13 @@ |
| 4 | 4 | // RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared.s -o %t2.o |
| 5 | 5 | // RUN: ld.lld -shared %t2.o -o %t2.so |
| 6 | 6 | // RUN: ld.lld -dynamic-linker /lib64/ld64.so.1 -rpath foo -rpath bar --export-dynamic %t.o %t2.so -o %t |
| 7 | // RUN: llvm-readobj --dynamic-table -s %t | FileCheck %s | |
| 7 | // RUN: llvm-readobj --dynamic-table -S %t | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o |
| 10 | 10 | // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared.s -o %t2.o |
| 11 | 11 | // RUN: ld.lld -shared %t2.o -o %t2.so |
| 12 | 12 | // RUN: ld.lld -dynamic-linker /lib64/ld64.so.1 -rpath foo -rpath bar --export-dynamic %t.o %t2.so -o %t |
| 13 | // RUN: llvm-readobj --dynamic-table -s %t | FileCheck %s | |
| 13 | // RUN: llvm-readobj --dynamic-table -S %t | FileCheck %s | |
| 14 | 14 | |
| 15 | 15 | // CHECK: Name: .rela.dyn |
| 16 | 16 | // CHECK-NEXT: Type: SHT_REL |
| ... | ... | @@ -27,7 +27,7 @@ |
| 27 | 27 | |
| 28 | 28 | // CHECK: DynamicSection [ |
| 29 | 29 | // CHECK-NEXT: Tag Type Name/Value |
| 30 | // CHECK-NEXT: 0x000000000000001D RUNPATH foo:bar | |
| 30 | // CHECK-NEXT: 0x000000000000001D RUNPATH Library runpath: [foo:bar] | |
| 31 | 31 | // CHECK-NEXT: 0x0000000000000001 NEEDED Shared library: [{{.*}}2.so] |
| 32 | 32 | // CHECK-NEXT: 0x0000000000000015 DEBUG 0x0 |
| 33 | 33 | // CHECK-NEXT: 0x0000000000000007 RELA [[RELADDR]] |
| ... | ... | @@ -39,6 +39,6 @@ |
| 39 | 39 | .global _start |
| 40 | 40 | _start: |
| 41 | 41 | .data |
| 42 | .long bar | |
| 43 | .long zed | |
| 42 | .quad bar | |
| 43 | .quad zed | |
| 44 | 44 |
deps/lld/test/ELF/shared.s+5-5| ... | ... | @@ -2,11 +2,11 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld --hash-style=sysv -shared %t2.o -o %t2.so |
| 5 | // RUN: llvm-readobj -s %t2.so | FileCheck --check-prefix=SO %s | |
| 5 | // RUN: llvm-readobj -S %t2.so | FileCheck --check-prefix=SO %s | |
| 6 | 6 | // RUN: ld.lld --hash-style=sysv -dynamic-linker /lib64/ld-linux-x86-64.so.2 -rpath foo -rpath bar --export-dynamic %t.o %t2.so -o %t |
| 7 | // RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols -section-data -hash-table %t | FileCheck %s | |
| 7 | // RUN: llvm-readobj --program-headers --dynamic-table --symbols -S --dyn-syms --section-data --hash-table %t | FileCheck %s | |
| 8 | 8 | // RUN: ld.lld --hash-style=sysv %t.o %t2.so %t2.so -o %t2 |
| 9 | // RUN: llvm-readobj -dyn-symbols %t2 | FileCheck --check-prefix=DONT_EXPORT %s | |
| 9 | // RUN: llvm-readobj --dyn-syms %t2 | FileCheck --check-prefix=DONT_EXPORT %s | |
| 10 | 10 | |
| 11 | 11 | // Make sure .symtab is properly aligned. |
| 12 | 12 | // SO: Name: .symtab |
| ... | ... | @@ -46,7 +46,7 @@ |
| 46 | 46 | // CHECK-NEXT: SHF_ALLOC |
| 47 | 47 | // CHECK-NEXT: ] |
| 48 | 48 | // CHECK-NEXT: Address: [[DYNSYMADDR:.*]] |
| 49 | // CHECK-NEXT: Offset: 0x150 | |
| 49 | // CHECK-NEXT: Offset: 0x170 | |
| 50 | 50 | // CHECK-NEXT: Size: |
| 51 | 51 | // CHECK-NEXT: Link: [[DYNSTR:.*]] |
| 52 | 52 | // CHECK-NEXT: Info: 1 |
| ... | ... | @@ -250,7 +250,7 @@ |
| 250 | 250 | |
| 251 | 251 | // CHECK: DynamicSection [ |
| 252 | 252 | // CHECK-NEXT: Tag Type Name/Value |
| 253 | // CHECK-NEXT: 0x0000001D RUNPATH foo:bar | |
| 253 | // CHECK-NEXT: 0x0000001D RUNPATH Library runpath: [foo:bar] | |
| 254 | 254 | // CHECK-NEXT: 0x00000001 NEEDED Shared library: [{{.*}}2.so] |
| 255 | 255 | // CHECK-NEXT: 0x00000015 DEBUG 0x0 |
| 256 | 256 | // CHECK-NEXT: 0x00000011 REL [[RELADDR]] |
deps/lld/test/ELF/shf-info-link.test+3-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # RUN: yaml2obj %s -o %t.o |
| 2 | 2 | # RUN: yaml2obj %S/Inputs/shf-info-link.test -o %t2.o |
| 3 | 3 | # RUN: ld.lld %t.o %t2.o -o %t3.o -r |
| 4 | # RUN: llvm-readobj -s %t3.o | FileCheck %s | |
| 4 | # RUN: llvm-readobj -S %t3.o | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK-NOT: Name: .rela.text |
| 7 | 7 | # CHECK: Name: .rela.text |
| ... | ... | @@ -28,5 +28,5 @@ Sections: |
| 28 | 28 | Symbol: foo |
| 29 | 29 | Type: R_X86_64_64 |
| 30 | 30 | Symbols: |
| 31 | Global: | |
| 32 | - Name: foo | |
| 31 | - Name: foo | |
| 32 | Binding: STB_GLOBAL |
deps/lld/test/ELF/sht-group-empty.test+5-5| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: yaml2obj %s -o %t.o |
| 2 | 2 | # RUN: ld.lld %t.o %t.o -o %t -r |
| 3 | # RUN: llvm-readobj -s %t | FileCheck %s | |
| 3 | # RUN: llvm-readobj -S %t | FileCheck %s | |
| 4 | 4 | |
| 5 | 5 | # CHECK: Name: .text.foo |
| 6 | 6 | # CHECK: Name: .rela.text.foo |
| ... | ... | @@ -49,7 +49,7 @@ Sections: |
| 49 | 49 | Symbol: bar |
| 50 | 50 | Type: R_X86_64_64 |
| 51 | 51 | Symbols: |
| 52 | Global: | |
| 53 | - Name: foo | |
| 54 | - Name: bar | |
| 55 | ||
| 52 | - Name: foo | |
| 53 | Binding: STB_GLOBAL | |
| 54 | - Name: bar | |
| 55 | Binding: STB_GLOBAL |
deps/lld/test/ELF/silent-ignore.test+3| ... | ... | @@ -6,8 +6,11 @@ RUN: -no-allow-shlib-undefined \ |
| 6 | 6 | RUN: -no-copy-dt-needed-entries \ |
| 7 | 7 | RUN: -no-ctors-in-init-array \ |
| 8 | 8 | RUN: -no-keep-memory \ |
| 9 | RUN: -no-pipeline-knowledge \ | |
| 9 | 10 | RUN: -no-warn-common \ |
| 10 | 11 | RUN: -no-warn-mismatch \ |
| 12 | RUN: -p \ | |
| 13 | RUN: -secure-plt \ | |
| 11 | 14 | RUN: -sort-common \ |
| 12 | 15 | RUN: -stats \ |
| 13 | 16 | RUN: -warn-execstack \ |
deps/lld/test/ELF/sort-norosegment.s+1-1| ... | ... | @@ -8,8 +8,8 @@ |
| 8 | 8 | # CHECK-NEXT: .hash {{.*}} A |
| 9 | 9 | # CHECK-NEXT: .dynstr {{.*}} A |
| 10 | 10 | # CHECK-NEXT: .text {{.*}} AX |
| 11 | # CHECK-NEXT: foo {{.*}} WA | |
| 12 | 11 | # CHECK-NEXT: .dynamic {{.*}} WA |
| 12 | # CHECK-NEXT: foo {{.*}} WA | |
| 13 | 13 | |
| 14 | 14 | .section foo, "aw" |
| 15 | 15 | .byte 0 |
deps/lld/test/ELF/start-lib-comdat.s+2-2| ... | ... | @@ -4,9 +4,9 @@ |
| 4 | 4 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux \ |
| 5 | 5 | // RUN: %p/Inputs/start-lib-comdat.s -o %t2.o |
| 6 | 6 | // RUN: ld.lld -shared -o %t3 %t1.o --start-lib %t2.o --end-lib |
| 7 | // RUN: llvm-readobj -t %t3 | FileCheck %s | |
| 7 | // RUN: llvm-readobj --symbols %t3 | FileCheck %s | |
| 8 | 8 | // RUN: ld.lld -shared -o %t3 --start-lib %t2.o --end-lib %t1.o |
| 9 | // RUN: llvm-readobj -t %t3 | FileCheck %s | |
| 9 | // RUN: llvm-readobj --symbols %t3 | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | // CHECK: Name: zed |
| 12 | 12 | // CHECK-NEXT: Value: |
deps/lld/test/ELF/startstop-gccollect.s+4| ... | ... | @@ -20,10 +20,14 @@ |
| 20 | 20 | # DISASM: _start: |
| 21 | 21 | # DISASM-NEXT: 201000: e8 05 00 00 00 callq 5 <__start_foo> |
| 22 | 22 | # DISASM-NEXT: 201005: e8 02 00 00 00 callq 2 <__stop_bar> |
| 23 | # DISASM-EMPTY: | |
| 23 | 24 | # DISASM-NEXT: Disassembly of section foo: |
| 25 | # DISASM-EMPTY: | |
| 24 | 26 | # DISASM-NEXT: __start_foo: |
| 25 | 27 | # DISASM-NEXT: 20100a: 90 nop |
| 28 | # DISASM-EMPTY: | |
| 26 | 29 | # DISASM-NEXT: Disassembly of section bar: |
| 30 | # DISASM-EMPTY: | |
| 27 | 31 | # DISASM-NEXT: bar: |
| 28 | 32 | # DISASM-NEXT: 20100b: 90 nop |
| 29 | 33 |
deps/lld/test/ELF/startstop-shared.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -r -t %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -r --symbols %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .data |
| 7 | 7 | .quad __start_foo |
deps/lld/test/ELF/startstop.s+5-3| ... | ... | @@ -2,18 +2,20 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv %t -o %tout -shared |
| 4 | 4 | // RUN: llvm-objdump -d %tout | FileCheck -check-prefix=DISASM %s |
| 5 | // RUN: llvm-readobj -symbols -r %tout | FileCheck -check-prefix=SYMBOL %s | |
| 5 | // RUN: llvm-readobj --symbols -r %tout | FileCheck -check-prefix=SYMBOL %s | |
| 6 | 6 | |
| 7 | 7 | // DISASM: _start: |
| 8 | 8 | // DISASM: 1000: {{.*}} callq 10 |
| 9 | 9 | // DISASM: 1005: {{.*}} callq 8 |
| 10 | 10 | // DISASM: 100a: {{.*}} callq 3 |
| 11 | 11 | // DISASM: Disassembly of section foo: |
| 12 | // DISASM-EMPTY: | |
| 12 | 13 | // DISASM: __start_foo: |
| 13 | 14 | // DISASM: 100f: 90 nop |
| 14 | 15 | // DISASM: 1010: 90 nop |
| 15 | 16 | // DISASM: 1011: 90 nop |
| 16 | 17 | // DISASM: Disassembly of section bar: |
| 18 | // DISASM-EMPTY: | |
| 17 | 19 | // DISASM: __start_bar: |
| 18 | 20 | // DISASM: 1012: 90 nop |
| 19 | 21 | // DISASM: 1013: 90 nop |
| ... | ... | @@ -50,13 +52,13 @@ |
| 50 | 52 | |
| 51 | 53 | // SYMBOL: Symbol { |
| 52 | 54 | // SYMBOL: Name: __stop_zed1 |
| 53 | // SYMBOL: Value: 0x2010 | |
| 55 | // SYMBOL: Value: 0x3010 | |
| 54 | 56 | // SYMBOL: STV_PROTECTED |
| 55 | 57 | // SYMBOL: Section: zed1 |
| 56 | 58 | // SYMBOL: } |
| 57 | 59 | // SYMBOL: Symbol { |
| 58 | 60 | // SYMBOL: Name: __stop_zed2 |
| 59 | // SYMBOL: Value: 0x2020 | |
| 61 | // SYMBOL: Value: 0x3020 | |
| 60 | 62 | // SYMBOL: STV_PROTECTED |
| 61 | 63 | // SYMBOL: Section: zed2 |
| 62 | 64 | // SYMBOL: } |
deps/lld/test/ELF/static-with-export-dynamic.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=i686-unknown-cloudabi %s -o %t.o |
| 3 | 3 | // RUN: ld.lld --export-dynamic %t.o -o %t |
| 4 | // RUN: llvm-readobj -dyn-symbols %t | FileCheck %s | |
| 4 | // RUN: llvm-readobj --dyn-syms %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // Ensure that a dynamic symbol table is present when --export-dynamic |
| 7 | 7 | // is passed in, even when creating statically linked executables. |
deps/lld/test/ELF/stdout.s created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 4 | # RUN: ld.lld %t.o -o - > %t1 | |
| 5 | # RUN: llvm-objdump -d %t1 | FileCheck %s | |
| 6 | ||
| 7 | # CHECK: 0000000000201000 _start: | |
| 8 | # CHECK: 201000: 90 nop | |
| 9 | ||
| 10 | # RUN: ld.lld %t.o -o %t2 | |
| 11 | # RUN: diff %t1 %t2 | |
| 12 | ||
| 13 | .globl _start | |
| 14 | _start: | |
| 15 | nop |
deps/lld/test/ELF/string-gc.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t --gc-sections |
| 4 | // RUN: llvm-readobj -symbols %t | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // CHECK: Symbols [ |
| 7 | 7 | // CHECK-NEXT: Symbol { |
deps/lld/test/ELF/string-table.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld %t -o %t2 |
| 4 | // RUN: llvm-readobj -sections %t2 | FileCheck %s | |
| 4 | // RUN: llvm-readobj --sections %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .global _start |
| 7 | 7 | _start: |
deps/lld/test/ELF/strip-debug.s+3-3| ... | ... | @@ -1,11 +1,11 @@ |
| 1 | 1 | # REQUIRES: x86, zlib |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | # RUN: ld.lld %t -o %t2 --strip-debug |
| 4 | # RUN: llvm-readobj -sections %t2 | FileCheck %s | |
| 4 | # RUN: llvm-readobj --sections %t2 | FileCheck %s | |
| 5 | 5 | # RUN: ld.lld %t -o %t2 -S |
| 6 | # RUN: llvm-readobj -sections %t2 | FileCheck %s | |
| 6 | # RUN: llvm-readobj --sections %t2 | FileCheck %s | |
| 7 | 7 | # RUN: ld.lld %t -o %t2 --strip-all |
| 8 | # RUN: llvm-readobj -sections %t2 | FileCheck %s | |
| 8 | # RUN: llvm-readobj --sections %t2 | FileCheck %s | |
| 9 | 9 | |
| 10 | 10 | # CHECK-NOT: Foo |
| 11 | 11 | # CHECK-NOT: Bar |
deps/lld/test/ELF/symbol-ordering-file-cgprofile-conflicts.s created+66| ... | ... | @@ -0,0 +1,66 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 3 | // RUN: ld.lld -e A %t.o --no-call-graph-profile-sort -o %t | |
| 4 | // RUN: llvm-nm --numeric-sort %t | FileCheck %s --check-prefix=NO_ORDERING | |
| 5 | // NO_ORDERING: 0000000000201000 t D | |
| 6 | // NO_ORDERING-NEXT: 0000000000201001 T C | |
| 7 | // NO_ORDERING-NEXT: 0000000000201002 T B | |
| 8 | // NO_ORDERING-NEXT: 0000000000201003 T A | |
| 9 | ||
| 10 | // RUN: ld.lld -e A %t.o -o %t | |
| 11 | // RUN: llvm-nm --numeric-sort %t | FileCheck %s --check-prefix=CALL_GRAPH | |
| 12 | // CALL_GRAPH:		0000000000201000 T A | |
| 13 | // CALL_GRAPH-NEXT:	0000000000201000 t Aa | |
| 14 | // CALL_GRAPH-NEXT:	0000000000201001 T B | |
| 15 | // CALL_GRAPH-NEXT:	0000000000201002 T C | |
| 16 | // CALL_GRAPH-NEXT:	0000000000201003 t D | |
| 17 | ||
| 18 | // RUN: rm -f %t.symbol_order | |
| 19 | // RUN: echo "C" >> %t.symbol_order | |
| 20 | // RUN: echo "B" >> %t.symbol_order | |
| 21 | // RUN: echo "D" >> %t.symbol_order | |
| 22 | // RUN: echo "A" >> %t.symbol_order | |
| 23 | ||
| 24 | // RUN: ld.lld -e A %t.o --symbol-ordering-file %t.symbol_order -o %t | |
| 25 | // RUN: llvm-nm --numeric-sort %t | FileCheck %s --check-prefix=SYMBOL_ORDER | |
| 26 | // SYMBOL_ORDER:	0000000000201000 T C | |
| 27 | // SYMBOL_ORDER-NEXT:	0000000000201001 T B | |
| 28 | // SYMBOL_ORDER-NEXT:	0000000000201002 t D | |
| 29 | // SYMBOL_ORDER-NEXT:	0000000000201003 T A | |
| 30 | ||
| 31 | // RUN: rm -f %t.call_graph | |
| 32 | // RUN: echo "A B 5" > %t.call_graph | |
| 33 | // RUN: echo "B C 50" >> %t.call_graph | |
| 34 | // RUN: echo "C D 40" >> %t.call_graph | |
| 35 | // RUN: echo "D B 10" >> %t.call_graph | |
| 36 | ||
| 37 | // RUN: not ld.lld -e A %t.o --symbol-ordering-file %t.symbol_order --call-graph-ordering-file %t.call_graph -o %t 2>&1 | FileCheck %s | |
| 38 | // RUN: not ld.lld -e A %t.o --call-graph-ordering-file %t.call_graph --symbol-ordering-file %t.symbol_order -o %t 2>&1 | FileCheck %s | |
| 39 | // CHECK: error: --symbol-ordering-file and --call-graph-order-file may not be used together | |
| 40 | ||
| 41 | .section .text.D,"ax",@progbits | |
| 42 | D: | |
| 43 | retq | |
| 44 | ||
| 45 | .section .text.C,"ax",@progbits | |
| 46 | .globl C | |
| 47 | C: | |
| 48 | retq | |
| 49 | ||
| 50 | .section .text.B,"ax",@progbits | |
| 51 | .globl B | |
| 52 | B: | |
| 53 | retq | |
| 54 | ||
| 55 | .section .text.A,"ax",@progbits | |
| 56 | .globl A | |
| 57 | A: | |
| 58 | Aa: | |
| 59 | retq | |
| 60 | ||
| 61 | .cg_profile A, B, 10 | |
| 62 | .cg_profile A, B, 10 | |
| 63 | .cg_profile Aa, B, 80 | |
| 64 | .cg_profile A, C, 40 | |
| 65 | .cg_profile B, C, 30 | |
| 66 | .cg_profile C, D, 90 |
deps/lld/test/ELF/symbol-override.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/symbol-override.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld -shared %t2.o -o %t2.so |
| 5 | 5 | // RUN: ld.lld %t1.o %t2.so -o %t |
| 6 | // RUN: llvm-readobj -dyn-symbols %t | FileCheck %s | |
| 6 | // RUN: llvm-readobj --dyn-syms %t | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | // CHECK: DynamicSymbols [ |
| 9 | 9 | // CHECK-NEXT: Symbol { |
deps/lld/test/ELF/symbols.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld %t -o %t2 |
| 4 | // RUN: llvm-readobj -symbols -sections %t2 | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols --sections %t2 | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .type _start, @function |
| 7 | 7 | .globl _start |
deps/lld/test/ELF/synthetic-got.s+7-7| ... | ... | @@ -7,13 +7,13 @@ |
| 7 | 7 | # RUN: | FileCheck %s --check-prefix=GOTDATA |
| 8 | 8 | |
| 9 | 9 | # GOT: Sections: |
| 10 | # GOT: 8 .got.plt 00000020 00000000000000e0 DATA | |
| 11 | # GOT: 10 .got 00000008 00000000000001d0 DATA | |
| 12 | # GOTDATA: Contents of section .got.plt: | |
| 13 | # GOTDATA-NEXT: 00e0 00010000 00000000 00000000 00000000 | |
| 14 | # GOTDATA-NEXT: 00f0 00000000 00000000 d6000000 00000000 | |
| 15 | # GOTDATA-NEXT: Contents of section .got: | |
| 16 | # GOTDATA-NEXT: 01d0 00000000 00000000 | |
| 10 | # GOT: 9 .got 00000008 00000000000001b0 DATA | |
| 11 | # GOT: 10 .got.plt 00000020 00000000000001b8 DATA | |
| 12 | # GOTDATA: Contents of section .got: | |
| 13 | # GOTDATA-NEXT: 01b0 00000000 00000000 | |
| 14 | # GOTDATA-NEXT: Contents of section .got.plt: | |
| 15 | # GOTDATA-NEXT: 01b8 e0000000 00000000 00000000 00000000 | |
| 16 | # GOTDATA-NEXT: 01c8 00000000 00000000 d6000000 00000000 | |
| 17 | 17 | |
| 18 | 18 | # RUN: echo "SECTIONS { .mygot : { *(.got) *(.got.plt) } }" > %t1.script |
| 19 | 19 | # RUN: ld.lld --hash-style=sysv -shared %t.o -o %t1.out --script %t1.script |
deps/lld/test/ELF/sysv-hash-no-rosegment.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld -shared --no-rosegment -o %t %t.o |
| 4 | # RUN: llvm-readobj -hash-table %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj --hash-table %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: HashTable { |
| 7 | 7 | # CHECK-NEXT: Num Buckets: 2 |
deps/lld/test/ELF/tail-merge-string-align.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared -O3 |
| 4 | // RUN: llvm-readobj -s -section-data %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S --section-data %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .section .rodata.4a,"aMS",@progbits,1 |
| 7 | 7 | .align 4 |
deps/lld/test/ELF/tls-align.s deleted-21| ... | ... | @@ -1,21 +0,0 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t | |
| 3 | // RUN: ld.lld %t -o %tout -shared | |
| 4 | // RUN: llvm-readobj -program-headers %tout | FileCheck %s | |
| 5 | ||
| 6 | .section .tbss,"awT",@nobits | |
| 7 | .align 8 | |
| 8 | .long 0 | |
| 9 | ||
| 10 | // CHECK: ProgramHeader { | |
| 11 | // CHECK: Type: PT_TLS | |
| 12 | // CHECK-NEXT: Offset: | |
| 13 | // CHECK-NEXT: VirtualAddress: | |
| 14 | // CHECK-NEXT: PhysicalAddress: | |
| 15 | // CHECK-NEXT: FileSize: 0 | |
| 16 | // CHECK-NEXT: MemSize: 8 | |
| 17 | // CHECK-NEXT: Flags [ | |
| 18 | // CHECK-NEXT: PF_R (0x4) | |
| 19 | // CHECK-NEXT: ] | |
| 20 | // CHECK-NEXT: Alignment: 8 | |
| 21 | // CHECK-NEXT: } |
deps/lld/test/ELF/tls-dynamic-i686.s+26-25| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t |
| 3 | // RUN: ld.lld --hash-style=sysv -shared %t -o %tout | |
| 4 | // RUN: llvm-readobj -sections -relocations %tout | FileCheck %s | |
| 3 | // RUN: ld.lld --hash-style=sysv -shared -z norelro %t -o %tout | |
| 4 | // RUN: llvm-readobj --sections -r %tout | FileCheck %s | |
| 5 | 5 | // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS |
| 6 | 6 | |
| 7 | 7 | .type tls0,@object |
| ... | ... | @@ -56,8 +56,8 @@ addl tls1@gotntpoff(%ebx),%eax |
| 56 | 56 | // CHECK-NEXT: SHF_ALLOC |
| 57 | 57 | // CHECK-NEXT: SHF_WRITE |
| 58 | 58 | // CHECK-NEXT: ] |
| 59 | // CHECK-NEXT: Address: 0x3068 | |
| 60 | // CHECK-NEXT: Offset: 0x3068 | |
| 59 | // CHECK-NEXT: Address: 0x2070 | |
| 60 | // CHECK-NEXT: Offset: 0x2070 | |
| 61 | 61 | // CHECK-NEXT: Size: 32 |
| 62 | 62 | // CHECK-NEXT: Link: 0 |
| 63 | 63 | // CHECK-NEXT: Info: 0 |
| ... | ... | @@ -66,34 +66,35 @@ addl tls1@gotntpoff(%ebx),%eax |
| 66 | 66 | |
| 67 | 67 | // CHECK: Relocations [ |
| 68 | 68 | // CHECK: Section ({{.+}}) .rel.dyn { |
| 69 | // CHECK-NEXT: 0x3078 R_386_TLS_DTPMOD32 - 0x0 | |
| 70 | // CHECK-NEXT: 0x3068 R_386_TLS_DTPMOD32 tls0 0x0 | |
| 71 | // CHECK-NEXT: 0x306C R_386_TLS_DTPOFF32 tls0 0x0 | |
| 72 | // CHECK-NEXT: 0x3080 R_386_TLS_TPOFF tls0 0x0 | |
| 73 | // CHECK-NEXT: 0x3070 R_386_TLS_DTPMOD32 tls1 0x0 | |
| 74 | // CHECK-NEXT: 0x3074 R_386_TLS_DTPOFF32 tls1 0x0 | |
| 75 | // CHECK-NEXT: 0x3084 R_386_TLS_TPOFF tls1 0x0 | |
| 69 | // CHECK-NEXT: 0x2080 R_386_TLS_DTPMOD32 - 0x0 | |
| 70 | // CHECK-NEXT: 0x2070 R_386_TLS_DTPMOD32 tls0 0x0 | |
| 71 | // CHECK-NEXT: 0x2074 R_386_TLS_DTPOFF32 tls0 0x0 | |
| 72 | // CHECK-NEXT: 0x2088 R_386_TLS_TPOFF tls0 0x0 | |
| 73 | // CHECK-NEXT: 0x2078 R_386_TLS_DTPMOD32 tls1 0x0 | |
| 74 | // CHECK-NEXT: 0x207C R_386_TLS_DTPOFF32 tls1 0x0 | |
| 75 | // CHECK-NEXT: 0x208C R_386_TLS_TPOFF tls1 0x0 | |
| 76 | 76 | // CHECK-NEXT: } |
| 77 | 77 | |
| 78 | 78 | // DIS: Disassembly of section .text: |
| 79 | // DIS-EMPTY: | |
| 79 | 80 | // DIS-NEXT: _start: |
| 80 | 81 | // General dynamic model: |
| 81 | 82 | // -32 and -24 are first and second GOT entries offsets. |
| 82 | 83 | // Each one is a pair of records. |
| 83 | // DIS-NEXT: 1000: 8d 04 1d e0 ff ff ff leal -32(,%ebx), %eax | |
| 84 | // DIS-NEXT: 1007: e8 64 00 00 00 calll 100 | |
| 85 | // DIS-NEXT: 100c: 8d 04 1d e8 ff ff ff leal -24(,%ebx), %eax | |
| 86 | // DIS-NEXT: 1013: e8 58 00 00 00 calll 88 | |
| 84 | // DIS-NEXT: 1000: {{.*}} leal -32(,%ebx), %eax | |
| 85 | // DIS-NEXT: 1007: {{.*}} calll 100 | |
| 86 | // DIS-NEXT: 100c: {{.*}} leal -24(,%ebx), %eax | |
| 87 | // DIS-NEXT: 1013: {{.*}} calll 88 | |
| 87 | 88 | // Local dynamic model: |
| 88 | 89 | // -16 is a local module tls index offset. |
| 89 | // DIS-NEXT: 1018: 8d 83 f0 ff ff ff leal -16(%ebx), %eax | |
| 90 | // DIS-NEXT: 101e: e8 4d 00 00 00 calll 77 | |
| 91 | // DIS-NEXT: 1023: 8d 90 08 00 00 00 leal 8(%eax), %edx | |
| 92 | // DIS-NEXT: 1029: 8d 83 f0 ff ff ff leal -16(%ebx), %eax | |
| 93 | // DIS-NEXT: 102f: e8 3c 00 00 00 calll 60 | |
| 94 | // DIS-NEXT: 1034: 8d 90 0c 00 00 00 leal 12(%eax), %edx | |
| 90 | // DIS-NEXT: 1018: {{.*}} leal -16(%ebx), %eax | |
| 91 | // DIS-NEXT: 101e: {{.*}} calll 77 | |
| 92 | // DIS-NEXT: 1023: {{.*}} leal 8(%eax), %edx | |
| 93 | // DIS-NEXT: 1029: {{.*}} leal -16(%ebx), %eax | |
| 94 | // DIS-NEXT: 102f: {{.*}} calll 60 | |
| 95 | // DIS-NEXT: 1034: {{.*}} leal 12(%eax), %edx | |
| 95 | 96 | // Initial exec model: |
| 96 | // DIS-NEXT: 103a: 65 a1 00 00 00 00 movl %gs:0, %eax | |
| 97 | // DIS-NEXT: 1040: 03 83 f8 ff ff ff addl -8(%ebx), %eax | |
| 98 | // DIS-NEXT: 1046: 65 a1 00 00 00 00 movl %gs:0, %eax | |
| 99 | // DIS-NEXT: 104c: 03 83 fc ff ff ff addl -4(%ebx), %eax | |
| 97 | // DIS-NEXT: 103a: {{.*}} movl %gs:0, %eax | |
| 98 | // DIS-NEXT: 1040: {{.*}} addl -8(%ebx), %eax | |
| 99 | // DIS-NEXT: 1046: {{.*}} movl %gs:0, %eax | |
| 100 | // DIS-NEXT: 104c: {{.*}} addl -4(%ebx), %eax |
deps/lld/test/ELF/tls-dynamic.s+15-14| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv -shared %t -o %tout |
| 4 | // RUN: llvm-readobj -sections -relocations %tout | FileCheck %s | |
| 4 | // RUN: llvm-readobj --sections -r %tout | FileCheck %s | |
| 5 | 5 | // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS |
| 6 | 6 | |
| 7 | 7 | leaq a@tlsld(%rip), %rdi |
| ... | ... | @@ -48,28 +48,29 @@ c: |
| 48 | 48 | // CHECK-NEXT: SHF_ALLOC |
| 49 | 49 | // CHECK-NEXT: SHF_WRITE |
| 50 | 50 | // CHECK-NEXT: ] |
| 51 | // CHECK-NEXT: Address: 0x30D0 | |
| 51 | // CHECK-NEXT: Address: 0x20E0 | |
| 52 | 52 | // CHECK-NEXT: Offset: |
| 53 | 53 | // CHECK-NEXT: Size: 40 |
| 54 | 54 | |
| 55 | 55 | // CHECK: Relocations [ |
| 56 | 56 | // CHECK: Section ({{.+}}) .rela.dyn { |
| 57 | // CHECK-NEXT: 0x30D0 R_X86_64_DTPMOD64 - 0x0 | |
| 58 | // CHECK-NEXT: 0x30E0 R_X86_64_DTPMOD64 c 0x0 | |
| 59 | // CHECK-NEXT: 0x30E8 R_X86_64_DTPOFF64 c 0x0 | |
| 60 | // CHECK-NEXT: 0x30F0 R_X86_64_TPOFF64 c 0x0 | |
| 57 | // CHECK-NEXT: 0x20E0 R_X86_64_DTPMOD64 - 0x0 | |
| 58 | // CHECK-NEXT: 0x20F0 R_X86_64_DTPMOD64 c 0x0 | |
| 59 | // CHECK-NEXT: 0x20F8 R_X86_64_DTPOFF64 c 0x0 | |
| 60 | // CHECK-NEXT: 0x2100 R_X86_64_TPOFF64 c 0x0 | |
| 61 | 61 | // CHECK-NEXT: } |
| 62 | 62 | |
| 63 | // 4297 = (0x20D0 + -4) - (0x1000 + 3) // PC relative offset to got entry. | |
| 64 | // 4285 = (0x20D0 + -4) - (0x100c + 3) // PC relative offset to got entry. | |
| 65 | // 4267 = (0x20E0 + -4) - (0x102e + 3) // PC relative offset to got entry. | |
| 66 | // 4263 = (0x20F0 + -4) - (0x1042 + 3) // PC relative offset to got entry. | |
| 63 | // 4313 = (0x20E0 + -4) - (0x1000 + 3) // PC relative offset to got entry. | |
| 64 | // 4301 = (0x20F0 + -4) - (0x100c + 3) // PC relative offset to got entry. | |
| 65 | // 4283 = (0x20F8 + -4) - (0x102e + 3) // PC relative offset to got entry. | |
| 66 | // 4279 = (0x2100 + -4) - (0x1042 + 3) // PC relative offset to got entry. | |
| 67 | 67 | |
| 68 | 68 | // DIS: Disassembly of section .text: |
| 69 | // DIS-EMPTY: | |
| 69 | 70 | // DIS-NEXT: .text: |
| 70 | // DIS-NEXT: 1000: {{.+}} leaq 8393(%rip), %rdi | |
| 71 | // DIS-NEXT: 1000: {{.+}} leaq 4313(%rip), %rdi | |
| 71 | 72 | // DIS-NEXT: 1007: {{.+}} callq |
| 72 | // DIS-NEXT: 100c: {{.+}} leaq 8381(%rip), %rdi | |
| 73 | // DIS-NEXT: 100c: {{.+}} leaq 4301(%rip), %rdi | |
| 73 | 74 | // DIS-NEXT: 1013: {{.+}} callq |
| 74 | 75 | // DIS-NEXT: 1018: {{.+}} leaq (%rax), %rcx |
| 75 | 76 | // DIS-NEXT: 101f: {{.+}} leaq 4(%rax), %rcx |
| ... | ... | @@ -77,10 +78,10 @@ c: |
| 77 | 78 | // DIS-NEXT: 1028: 00 00 |
| 78 | 79 | // DIS-NEXT: 102a: 00 00 |
| 79 | 80 | // DIS-NEXT: 102c: 00 00 |
| 80 | // DIS-NEXT: 102e: {{.+}} leaq 8363(%rip), %rdi | |
| 81 | // DIS-NEXT: 102e: {{.+}} leaq 4283(%rip), %rdi | |
| 81 | 82 | // DIS-NEXT: 1035: {{.+}} callq |
| 82 | 83 | // DIS-NEXT: 103b: {{.+}} leaq (%rax), %rcx |
| 83 | // DIS-NEXT: 1042: {{.+}} movq 8359(%rip), %rax | |
| 84 | // DIS-NEXT: 1042: {{.+}} movq 4279(%rip), %rax | |
| 84 | 85 | // DIS-NEXT: 1049: {{.+}} movq %fs:(%rax), %rax |
| 85 | 86 | // DIS-NEXT: 104d: {{.+}} movabsq $0, %rax |
| 86 | 87 | // DIS-NEXT: 1057: {{.+}} movabsq $4, %rax |
deps/lld/test/ELF/tls-got.s+17-16| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/tls-got.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld -shared %t2.o -o %t2.so |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv -e main %t1.o %t2.so -o %t3 |
| 6 | // RUN: llvm-readobj -s -r %t3 | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S -r %t3 | FileCheck %s | |
| 7 | 7 | // RUN: llvm-objdump -d %t3 | FileCheck --check-prefix=DISASM %s |
| 8 | 8 | |
| 9 | 9 | // CHECK: Section { |
| ... | ... | @@ -15,7 +15,7 @@ |
| 15 | 15 | // CHECK-NEXT: SHF_WRITE |
| 16 | 16 | // CHECK-NEXT: ] |
| 17 | 17 | // CHECK-NEXT: Address: [[ADDR:.*]] |
| 18 | // CHECK-NEXT: Offset: 0x20B0 | |
| 18 | // CHECK-NEXT: Offset: 0x20C0 | |
| 19 | 19 | // CHECK-NEXT: Size: 16 |
| 20 | 20 | // CHECK-NEXT: Link: 0 |
| 21 | 21 | // CHECK-NEXT: Info: 0 |
| ... | ... | @@ -25,23 +25,24 @@ |
| 25 | 25 | |
| 26 | 26 | // CHECK: Relocations [ |
| 27 | 27 | // CHECK-NEXT: Section (4) .rela.dyn { |
| 28 | // CHECK-NEXT: 0x2020B8 R_X86_64_TPOFF64 tls0 0x0 | |
| 29 | // CHECK-NEXT: 0x2020B0 R_X86_64_TPOFF64 tls1 0x0 | |
| 28 | // CHECK-NEXT: 0x2020C8 R_X86_64_TPOFF64 tls0 0x0 | |
| 29 | // CHECK-NEXT: [[ADDR]] R_X86_64_TPOFF64 tls1 0x0 | |
| 30 | 30 | // CHECK-NEXT: } |
| 31 | 31 | // CHECK-NEXT: ] |
| 32 | 32 | |
| 33 | //0x201000 + 4265 + 7 = 0x2020B0 | |
| 34 | //0x20100A + 4263 + 7 = 0x2020B8 | |
| 35 | //0x201014 + 4253 + 7 = 0x2020B8 | |
| 36 | //DISASM: Disassembly of section .text: | |
| 37 | //DISASM-NEXT: main: | |
| 38 | //DISASM-NEXT: 201000: 48 8b 05 a9 10 00 00 movq 4265(%rip), %rax | |
| 39 | //DISASM-NEXT: 201007: 64 8b 00 movl %fs:(%rax), %eax | |
| 40 | //DISASM-NEXT: 20100a: 48 8b 05 a7 10 00 00 movq 4263(%rip), %rax | |
| 41 | //DISASM-NEXT: 201011: 64 8b 00 movl %fs:(%rax), %eax | |
| 42 | //DISASM-NEXT: 201014: 48 8b 05 9d 10 00 00 movq 4253(%rip), %rax | |
| 43 | //DISASM-NEXT: 20101b: 64 8b 00 movl %fs:(%rax), %eax | |
| 44 | //DISASM-NEXT: 20101e: c3 retq | |
| 33 | // 0x201000 + 4281 + 7 = 0x2020C0 | |
| 34 | // 0x20100A + 4279 + 7 = 0x2020C8 | |
| 35 | // 0x201014 + 4269 + 7 = 0x2020C8 | |
| 36 | // DISASM: Disassembly of section .text: | |
| 37 | // DISASM-EMPTY: | |
| 38 | // DISASM-NEXT: main: | |
| 39 | // DISASM-NEXT: 201000: {{.*}} movq 4281(%rip), %rax | |
| 40 | // DISASM-NEXT: 201007: {{.*}} movl %fs:(%rax), %eax | |
| 41 | // DISASM-NEXT: 20100a: {{.*}} movq 4279(%rip), %rax | |
| 42 | // DISASM-NEXT: 201011: {{.*}} movl %fs:(%rax), %eax | |
| 43 | // DISASM-NEXT: 201014: {{.*}} movq 4269(%rip), %rax | |
| 44 | // DISASM-NEXT: 20101b: {{.*}} movl %fs:(%rax), %eax | |
| 45 | // DISASM-NEXT: 20101e: {{.*}} retq | |
| 45 | 46 | |
| 46 | 47 | .section .tdata,"awT",@progbits |
| 47 | 48 |
deps/lld/test/ELF/tls-i686.s+2| ... | ... | @@ -31,6 +31,7 @@ _start: |
| 31 | 31 | leal var1@ntpoff+123(%ecx), %eax |
| 32 | 32 | |
| 33 | 33 | // DIS: Disassembly of section test: |
| 34 | // DIS-EMPTY: | |
| 34 | 35 | // DIS-NEXT: _start: |
| 35 | 36 | // DIS-NEXT: 401000: ba 08 00 00 00 movl $8, %edx |
| 36 | 37 | // DIS-NEXT: 401005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx |
| ... | ... | @@ -47,6 +48,7 @@ _start: |
| 47 | 48 | // RELOC-NEXT: ] |
| 48 | 49 | |
| 49 | 50 | // DISSHARED: Disassembly of section test: |
| 51 | // DISSHARED-EMPTY: | |
| 50 | 52 | // DISSHARED-NEXT: _start: |
| 51 | 53 | // DISSHARED-NEXT: 1000: ba 00 00 00 00 movl $0, %edx |
| 52 | 54 | // DISSHARED-NEXT: 1005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx |
deps/lld/test/ELF/tls-initial-exec-local.s+9-8| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv -shared %t.o -o %t |
| 4 | // RUN: llvm-readobj -r -s %t | FileCheck %s | |
| 4 | // RUN: llvm-readobj -r -S %t | FileCheck %s | |
| 5 | 5 | // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s |
| 6 | 6 | |
| 7 | 7 | // CHECK: Name: .got |
| ... | ... | @@ -10,21 +10,22 @@ |
| 10 | 10 | // CHECK-NEXT: SHF_ALLOC (0x2) |
| 11 | 11 | // CHECK-NEXT: SHF_WRITE (0x1) |
| 12 | 12 | // CHECK-NEXT: ] |
| 13 | // CHECK-NEXT: Address: 0x2090 | |
| 13 | // CHECK-NEXT: Address: 0x20A0 | |
| 14 | 14 | |
| 15 | 15 | // CHECK: Relocations [ |
| 16 | 16 | // CHECK-NEXT: Section ({{.*}}) .rela.dyn { |
| 17 | // CHECK-NEXT: 0x2090 R_X86_64_TPOFF64 - 0x0 | |
| 18 | // CHECK-NEXT: 0x2098 R_X86_64_TPOFF64 - 0x4 | |
| 17 | // CHECK-NEXT: 0x20A0 R_X86_64_TPOFF64 - 0x0 | |
| 18 | // CHECK-NEXT: 0x20A8 R_X86_64_TPOFF64 - 0x4 | |
| 19 | 19 | // CHECK-NEXT: } |
| 20 | 20 | // CHECK-NEXT: ] |
| 21 | 21 | |
| 22 | // 0x1007 + 4233 = 0x2090 | |
| 23 | // 0x100e + 4234 = 0x2098 | |
| 22 | // 0x1007 + 4249 = 0x20A0 | |
| 23 | // 0x100e + 4250 = 0x20A8 | |
| 24 | 24 | // DISASM: Disassembly of section .text: |
| 25 | // DISASM-EMPTY: | |
| 25 | 26 | // DISASM-NEXT: .text: |
| 26 | // DISASM-NEXT: 1000: {{.*}} addq 4233(%rip), %rax | |
| 27 | // DISASM-NEXT: 1007: {{.*}} addq 4234(%rip), %rax | |
| 27 | // DISASM-NEXT: 1000: {{.*}} addq 4249(%rip), %rax | |
| 28 | // DISASM-NEXT: 1007: {{.*}} addq 4250(%rip), %rax | |
| 28 | 29 | |
| 29 | 30 | addq foo@GOTTPOFF(%rip), %rax |
| 30 | 31 | addq bar@GOTTPOFF(%rip), %rax |
deps/lld/test/ELF/tls-offset.s+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld %t -o %tout |
| 4 | // RUN: llvm-readobj -s %tout | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S %tout | FileCheck %s | |
| 5 | 5 | // RUN: echo "SECTIONS { \ |
| 6 | 6 | // RUN: . = 0x201000; \ |
| 7 | 7 | // RUN: .text : { *(.text) } \ |
| ... | ... | @@ -12,7 +12,7 @@ |
| 12 | 12 | // RUN: }" > %t.script |
| 13 | 13 | // RUN: ld.lld -T %t.script %t -o %tout2 |
| 14 | 14 | // RUN: echo SCRIPT |
| 15 | // RUN: llvm-readobj -s %tout2 | FileCheck %s | |
| 15 | // RUN: llvm-readobj -S %tout2 | FileCheck %s | |
| 16 | 16 | .global _start |
| 17 | 17 | _start: |
| 18 | 18 | retq |
deps/lld/test/ELF/tls-opt-gdie.s+2-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/tls-opt-gdie.s -o %tso.o |
| 4 | 4 | // RUN: ld.lld -shared %tso.o -o %t.so |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv %t.o %t.so -o %t1 |
| 6 | // RUN: llvm-readobj -s -r %t1 | FileCheck --check-prefix=RELOC %s | |
| 6 | // RUN: llvm-readobj -S -r %t1 | FileCheck --check-prefix=RELOC %s | |
| 7 | 7 | // RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s |
| 8 | 8 | |
| 9 | 9 | //RELOC: Section { |
| ... | ... | @@ -32,6 +32,7 @@ |
| 32 | 32 | //0x201009 + (4256 + 7) = 0x2020B0 |
| 33 | 33 | //0x201019 + (4248 + 7) = 0x2020B8 |
| 34 | 34 | // DISASM: Disassembly of section .text: |
| 35 | // DISASM-EMPTY: | |
| 35 | 36 | // DISASM-NEXT: _start: |
| 36 | 37 | // DISASM-NEXT: 201000: {{.*}} movq %fs:0, %rax |
| 37 | 38 | // DISASM-NEXT: 201009: {{.*}} addq 4256(%rip), %rax |
deps/lld/test/ELF/tls-opt-gdiele-i686.s+4-3| ... | ... | @@ -14,11 +14,12 @@ |
| 14 | 14 | // NORELOC-NEXT: ] |
| 15 | 15 | |
| 16 | 16 | // DISASM: Disassembly of section .text: |
| 17 | // DISASM-EMPTY: | |
| 17 | 18 | // DISASM-NEXT: _start: |
| 18 | 19 | // DISASM-NEXT: 401000: 65 a1 00 00 00 00 movl %gs:0, %eax |
| 19 | // DISASM-NEXT: 401006: 03 83 f8 ff ff ff addl -8(%ebx), %eax | |
| 20 | // DISASM-NEXT: 401006: 03 83 58 f0 ff ff addl -4008(%ebx), %eax | |
| 20 | 21 | // DISASM-NEXT: 40100c: 65 a1 00 00 00 00 movl %gs:0, %eax |
| 21 | // DISASM-NEXT: 401012: 03 83 fc ff ff ff addl -4(%ebx), %eax | |
| 22 | // DISASM-NEXT: 401012: 03 83 5c f0 ff ff addl -4004(%ebx), %eax | |
| 22 | 23 | // DISASM-NEXT: 401018: 65 a1 00 00 00 00 movl %gs:0, %eax |
| 23 | 24 | // DISASM-NEXT: 40101e: 81 e8 08 00 00 00 subl $8, %eax |
| 24 | 25 | // DISASM-NEXT: 401024: 65 a1 00 00 00 00 movl %gs:0, %eax |
| ... | ... | @@ -53,7 +54,7 @@ leal tlsshared0@tlsgd(,%ebx,1),%eax |
| 53 | 54 | call ___tls_get_addr@plt |
| 54 | 55 | leal tlsshared1@tlsgd(,%ebx,1),%eax |
| 55 | 56 | call ___tls_get_addr@plt |
| 56 | //GD->IE | |
| 57 | //GD->LE | |
| 57 | 58 | leal tlsexe1@tlsgd(,%ebx,1),%eax |
| 58 | 59 | call ___tls_get_addr@plt |
| 59 | 60 | leal tlsexe2@tlsgd(,%ebx,1),%eax |
deps/lld/test/ELF/tls-opt-i686.s+1| ... | ... | @@ -8,6 +8,7 @@ |
| 8 | 8 | // NORELOC-NEXT: ] |
| 9 | 9 | |
| 10 | 10 | // DISASM: Disassembly of section .text: |
| 11 | // DISASM-EMPTY: | |
| 11 | 12 | // DISASM-NEXT: _start: |
| 12 | 13 | // LD -> LE: |
| 13 | 14 | // DISASM-NEXT: 401000: 65 a1 00 00 00 00 movl %gs:0, %eax |
deps/lld/test/ELF/tls-opt-iele-i686-nopic.s+24-23| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %p/Inputs/tls-opt-iele-i686-nopic.s -o %tso.o |
| 4 | 4 | // RUN: ld.lld -shared %tso.o -o %tso |
| 5 | 5 | // RUN: ld.lld --hash-style=sysv %t.o %tso -o %t1 |
| 6 | // RUN: llvm-readobj -s -r %t1 | FileCheck --check-prefix=GOTREL %s | |
| 6 | // RUN: llvm-readobj -S -r %t1 | FileCheck --check-prefix=GOTREL %s | |
| 7 | 7 | // RUN: llvm-objdump -d %t1 | FileCheck --check-prefix=DISASM %s |
| 8 | 8 | |
| 9 | 9 | // GOTREL: Section { |
| ... | ... | @@ -14,8 +14,8 @@ |
| 14 | 14 | // GOTREL-NEXT: SHF_ALLOC |
| 15 | 15 | // GOTREL-NEXT: SHF_WRITE |
| 16 | 16 | // GOTREL-NEXT: ] |
| 17 | // GOTREL-NEXT: Address: 0x402058 | |
| 18 | // GOTREL-NEXT: Offset: 0x2058 | |
| 17 | // GOTREL-NEXT: Address: 0x402060 | |
| 18 | // GOTREL-NEXT: Offset: 0x2060 | |
| 19 | 19 | // GOTREL-NEXT: Size: 8 |
| 20 | 20 | // GOTREL-NEXT: Link: 0 |
| 21 | 21 | // GOTREL-NEXT: Info: 0 |
| ... | ... | @@ -24,33 +24,34 @@ |
| 24 | 24 | // GOTREL-NEXT: } |
| 25 | 25 | // GOTREL: Relocations [ |
| 26 | 26 | // GOTREL-NEXT: Section ({{.*}}) .rel.dyn { |
| 27 | // GOTREL-NEXT: 0x402058 R_386_TLS_TPOFF tlsshared0 0x0 | |
| 28 | // GOTREL-NEXT: 0x40205C R_386_TLS_TPOFF tlsshared1 0x0 | |
| 27 | // GOTREL-NEXT: 0x402060 R_386_TLS_TPOFF tlsshared0 0x0 | |
| 28 | // GOTREL-NEXT: 0x402064 R_386_TLS_TPOFF tlsshared1 0x0 | |
| 29 | 29 | // GOTREL-NEXT: } |
| 30 | 30 | // GOTREL-NEXT: ] |
| 31 | 31 | |
| 32 | 32 | // DISASM: Disassembly of section .text: |
| 33 | // DISASM-EMPTY: | |
| 33 | 34 | // DISASM-NEXT: _start: |
| 34 | 35 | // 4294967288 = 0xFFFFFFF8 |
| 35 | 36 | // 4294967292 = 0xFFFFFFFC |
| 36 | // 4202584 = (.got)[0] = 0x402058 | |
| 37 | // 4202588 = (.got)[1] = 0x40205C | |
| 38 | // DISASM-NEXT: 401000: c7 c1 f8 ff ff ff movl $4294967288, %ecx | |
| 39 | // DISASM-NEXT: 401006: 65 8b 01 movl %gs:(%ecx), %eax | |
| 40 | // DISASM-NEXT: 401009: b8 f8 ff ff ff movl $4294967288, %eax | |
| 41 | // DISASM-NEXT: 40100e: 65 8b 00 movl %gs:(%eax), %eax | |
| 42 | // DISASM-NEXT: 401011: 81 c1 f8 ff ff ff addl $4294967288, %ecx | |
| 43 | // DISASM-NEXT: 401017: 65 8b 01 movl %gs:(%ecx), %eax | |
| 44 | // DISASM-NEXT: 40101a: c7 c1 fc ff ff ff movl $4294967292, %ecx | |
| 45 | // DISASM-NEXT: 401020: 65 8b 01 movl %gs:(%ecx), %eax | |
| 46 | // DISASM-NEXT: 401023: b8 fc ff ff ff movl $4294967292, %eax | |
| 47 | // DISASM-NEXT: 401028: 65 8b 00 movl %gs:(%eax), %eax | |
| 48 | // DISASM-NEXT: 40102b: 81 c1 fc ff ff ff addl $4294967292, %ecx | |
| 49 | // DISASM-NEXT: 401031: 65 8b 01 movl %gs:(%ecx), %eax | |
| 50 | // DISASM-NEXT: 401034: 8b 0d 58 20 40 00 movl 4202584, %ecx | |
| 51 | // DISASM-NEXT: 40103a: 65 8b 01 movl %gs:(%ecx), %eax | |
| 52 | // DISASM-NEXT: 40103d: 03 0d 5c 20 40 00 addl 4202588, %ecx | |
| 53 | // DISASM-NEXT: 401043: 65 8b 01 movl %gs:(%ecx), %eax | |
| 37 | // 4202592 = (.got)[0] = 0x402060 | |
| 38 | // 4202596 = (.got)[1] = 0x402064 | |
| 39 | // DISASM-NEXT: 401000: {{.*}} movl $4294967288, %ecx | |
| 40 | // DISASM-NEXT: 401006: {{.*}} movl %gs:(%ecx), %eax | |
| 41 | // DISASM-NEXT: 401009: {{.*}} movl $4294967288, %eax | |
| 42 | // DISASM-NEXT: 40100e: {{.*}} movl %gs:(%eax), %eax | |
| 43 | // DISASM-NEXT: 401011: {{.*}} addl $4294967288, %ecx | |
| 44 | // DISASM-NEXT: 401017: {{.*}} movl %gs:(%ecx), %eax | |
| 45 | // DISASM-NEXT: 40101a: {{.*}} movl $4294967292, %ecx | |
| 46 | // DISASM-NEXT: 401020: {{.*}} movl %gs:(%ecx), %eax | |
| 47 | // DISASM-NEXT: 401023: {{.*}} movl $4294967292, %eax | |
| 48 | // DISASM-NEXT: 401028: {{.*}} movl %gs:(%eax), %eax | |
| 49 | // DISASM-NEXT: 40102b: {{.*}} addl $4294967292, %ecx | |
| 50 | // DISASM-NEXT: 401031: {{.*}} movl %gs:(%ecx), %eax | |
| 51 | // DISASM-NEXT: 401034: {{.*}} movl 4202592, %ecx | |
| 52 | // DISASM-NEXT: 40103a: {{.*}} movl %gs:(%ecx), %eax | |
| 53 | // DISASM-NEXT: 40103d: {{.*}} addl 4202596, %ecx | |
| 54 | // DISASM-NEXT: 401043: {{.*}} movl %gs:(%ecx), %eax | |
| 54 | 55 | |
| 55 | 56 | .type tlslocal0,@object |
| 56 | 57 | .section .tbss,"awT",@nobits |
deps/lld/test/ELF/tls-opt-local.s+1| ... | ... | @@ -8,6 +8,7 @@ |
| 8 | 8 | // NORELOC-NEXT: ] |
| 9 | 9 | |
| 10 | 10 | // DISASM: Disassembly of section .text: |
| 11 | // DISASM-EMPTY: | |
| 11 | 12 | // DISASM-NEXT: _start: |
| 12 | 13 | // DISASM-NEXT: 201000: 48 c7 c0 f8 ff ff ff movq $-8, %rax |
| 13 | 14 | // DISASM-NEXT: 201007: 49 c7 c7 f8 ff ff ff movq $-8, %r15 |
deps/lld/test/ELF/tls-opt-no-plt.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/tls-opt-gdie.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld %t2.o -o %t2.so -shared |
| 5 | 5 | // RUN: ld.lld %t.o %t2.so -o %t.exe |
| 6 | // RUN: llvm-readobj -s %t.exe | FileCheck %s | |
| 6 | // RUN: llvm-readobj -S %t.exe | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | // CHECK-NOT: .plt |
| 9 | 9 |
deps/lld/test/ELF/tls-relocatable.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -r -o %tr.o |
| 4 | 4 | // RUN: ld.lld %tr.o -shared -o %t1 |
| 5 | // RUN: llvm-readobj -t %t1 | FileCheck %s | |
| 5 | // RUN: llvm-readobj --symbols %t1 | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // CHECK: Symbol { |
| 8 | 8 | // CHECK: Name: tls0 |
deps/lld/test/ELF/tls.s+2-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | // RUN: ld.lld %t -o %tout |
| 4 | // RUN: llvm-readobj -symbols -sections -program-headers %tout | FileCheck %s | |
| 4 | // RUN: llvm-readobj --symbols --sections -l %tout | FileCheck %s | |
| 5 | 5 | // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS |
| 6 | 6 | |
| 7 | 7 | .global _start |
| ... | ... | @@ -163,6 +163,7 @@ d: |
| 163 | 163 | // CHECK-NEXT: } |
| 164 | 164 | |
| 165 | 165 | // DIS: Disassembly of section .text: |
| 166 | // DIS-EMPTY: | |
| 166 | 167 | // DIS-NEXT: _start: |
| 167 | 168 | // DIS-NEXT: 201000: {{.+}} movl %fs:-8, %eax |
| 168 | 169 | // DIS-NEXT: 201008: {{.+}} movl %fs:-16, %eax |
deps/lld/test/ELF/trace-symbols.s+16-11| ... | ... | @@ -14,46 +14,51 @@ |
| 14 | 14 | # RUN: llvm-ar rcs %t2.a %t2 |
| 15 | 15 | |
| 16 | 16 | # RUN: ld.lld -y foo -trace-symbol common -trace-symbol=hsymbol \ |
| 17 | # RUN: %t %t1 %t2 -o %t3 2>&1 | FileCheck -check-prefix=OBJECTRFOO %s | |
| 17 | # RUN: %t %t1 %t2 -o %t3 | FileCheck -check-prefix=OBJECTRFOO %s | |
| 18 | 18 | # OBJECTRFOO: trace-symbols.s.tmp: reference to foo |
| 19 | 19 | |
| 20 | 20 | # RUN: ld.lld -y foo -trace-symbol=common -trace-symbol=hsymbol \ |
| 21 | # RUN: %t %t1 %t2 -o %t3 2>&1 | FileCheck -check-prefix=OBJECTDCOMMON %s | |
| 21 | # RUN: %t %t1 %t2 -o %t3 | FileCheck -check-prefix=OBJECTDCOMMON %s | |
| 22 | 22 | # OBJECTDCOMMON: trace-symbols.s.tmp1: common definition of common |
| 23 | 23 | |
| 24 | 24 | # RUN: ld.lld -y foo -trace-symbol=common -trace-symbol=hsymbol \ |
| 25 | # RUN: %t %t1 %t2 -o %t3 2>&1 | FileCheck -check-prefix=OBJECTD1FOO %s | |
| 25 | # RUN: %t %t1 %t2 -o %t3 | FileCheck -check-prefix=OBJECTD1FOO %s | |
| 26 | 26 | # OBJECTD1FOO: trace-symbols.s.tmp: reference to foo |
| 27 | 27 | # OBJECTD1FOO: trace-symbols.s.tmp1: common definition of common |
| 28 | 28 | # OBJECTD1FOO: trace-symbols.s.tmp1: definition of foo |
| 29 | 29 | # OBJECTD1FOO: trace-symbols.s.tmp2: definition of foo |
| 30 | 30 | |
| 31 | # RUN: ld.lld -y foo %t1 %t2 %t -o %t3 | FileCheck -check-prefix=REFLAST %s | |
| 32 | # REFLAST: trace-symbols.s.tmp1: definition of foo | |
| 33 | # REFLAST: trace-symbols.s.tmp2: definition of foo | |
| 34 | # REFLAST: trace-symbols.s.tmp: reference to foo | |
| 35 | ||
| 31 | 36 | # RUN: ld.lld -y foo -trace-symbol=common -trace-symbol=hsymbol \ |
| 32 | # RUN: %t %t1 %t2 -o %t3 2>&1 | FileCheck -check-prefix=OBJECTD2FOO %s | |
| 37 | # RUN: %t %t1 %t2 -o %t3 | FileCheck -check-prefix=OBJECTD2FOO %s | |
| 33 | 38 | # RUN: ld.lld -y foo -y common --trace-symbol=hsymbol \ |
| 34 | # RUN: %t %t2 %t1 -o /dev/null 2>&1 | FileCheck -check-prefix=OBJECTD2FOO %s | |
| 35 | # RUN: ld.lld -y foo -y common %t %t1.so %t2 -o %t3 2>&1 | \ | |
| 39 | # RUN: %t %t2 %t1 -o %t3 | FileCheck -check-prefix=OBJECTD2FOO %s | |
| 40 | # RUN: ld.lld -y foo -y common %t %t1.so %t2 -o %t3 | \ | |
| 36 | 41 | # RUN: FileCheck -check-prefix=OBJECTD2FOO %s |
| 37 | 42 | # OBJECTD2FOO: trace-symbols.s.tmp2: definition of foo |
| 38 | 43 | |
| 39 | # RUN: ld.lld -y foo -y common %t %t2 %t1.a -o %t3 2>&1 | \ | |
| 44 | # RUN: ld.lld -y foo -y common %t %t2 %t1.a -o %t3 | \ | |
| 40 | 45 | # RUN: FileCheck -check-prefix=FOO_AND_COMMON %s |
| 41 | 46 | # FOO_AND_COMMON: trace-symbols.s.tmp: reference to foo |
| 42 | 47 | # FOO_AND_COMMON: trace-symbols.s.tmp2: definition of foo |
| 43 | 48 | # FOO_AND_COMMON: trace-symbols.s.tmp1.a: lazy definition of common |
| 44 | 49 | |
| 45 | # RUN: ld.lld -y foo -y common %t %t1.so %t2 -o %t3 2>&1 | \ | |
| 50 | # RUN: ld.lld -y foo -y common %t %t1.so %t2 -o %t3 | \ | |
| 46 | 51 | # RUN: FileCheck -check-prefix=SHLIBDCOMMON %s |
| 47 | 52 | # SHLIBDCOMMON: trace-symbols.s.tmp1.so: shared definition of common |
| 48 | 53 | |
| 49 | # RUN: ld.lld -y foo -y common %t %t2.so %t1.so -o %t3 2>&1 | \ | |
| 54 | # RUN: ld.lld -y foo -y common %t %t2.so %t1.so -o %t3 | \ | |
| 50 | 55 | # RUN: FileCheck -check-prefix=SHLIBD2FOO %s |
| 51 | 56 | # RUN: ld.lld -y foo %t %t1.a %t2.so -o %t3 | \ |
| 52 | 57 | # RUN: FileCheck -check-prefix=NO-SHLIBD2FOO %s |
| 53 | 58 | # SHLIBD2FOO: trace-symbols.s.tmp2.so: shared definition of foo |
| 54 | 59 | # NO-SHLIBD2FOO-NOT: trace-symbols.s.tmp2.so: definition of foo |
| 55 | 60 | |
| 56 | # RUN: ld.lld -y foo -y common %t %t2 %t1.a -o %t3 2>&1 | \ | |
| 61 | # RUN: ld.lld -y foo -y common %t %t2 %t1.a -o %t3 | \ | |
| 57 | 62 | # RUN: FileCheck -check-prefix=ARCHIVEDCOMMON %s |
| 58 | 63 | # ARCHIVEDCOMMON-NOT: trace-symbols.s.tmp1.a(trace-symbols.s.tmp1): definition of \ |
| 59 | 64 | # common |
| ... | ... | @@ -79,7 +84,7 @@ |
| 79 | 84 | # STARTLIB: trace-symbols.s.tmp1: reference to bar |
| 80 | 85 | |
| 81 | 86 | ## Check we do not crash when trying to trace special symbol. |
| 82 | # RUN: not ld.lld -trace-symbol=_end %t -o /dev/null | |
| 87 | # RUN: ld.lld -trace-symbol=_end %t %t1 %t2 -o /dev/null | |
| 83 | 88 | |
| 84 | 89 | .hidden hsymbol |
| 85 | 90 | .globl	_start |
deps/lld/test/ELF/trace.s+1-1| ... | ... | @@ -6,4 +6,4 @@ |
| 6 | 6 | # CHECK: {{.*}}.foo.o |
| 7 | 7 | |
| 8 | 8 | ## Check --trace alias |
| 9 | # RUN: ld.lld -shared %t.foo.o -o %t.so -t 2>&1 | FileCheck %s | |
| 9 | # RUN: ld.lld -shared %t.foo.o -o %t.so --trace 2>&1 | FileCheck %s |
deps/lld/test/ELF/ttext-tdata-tbss.s+4-4| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | |
| 4 | 4 | ## Show what regular output gives to us. |
| 5 | 5 | # RUN: ld.lld %t.o -o %t1 |
| 6 | # RUN: llvm-readobj --elf-output-style=GNU -l -s %t1 | FileCheck %s | |
| 6 | # RUN: llvm-readelf -S -l %t1 | FileCheck %s | |
| 7 | 7 | # CHECK: .rodata PROGBITS 0000000000200158 000158 000008 |
| 8 | 8 | # CHECK-NEXT: .text PROGBITS 0000000000201000 001000 000001 |
| 9 | 9 | # CHECK-NEXT: .aw PROGBITS 0000000000202000 002000 000008 |
| ... | ... | @@ -15,7 +15,7 @@ |
| 15 | 15 | |
| 16 | 16 | ## With .text at 0 there is no space to allocate the headers. |
| 17 | 17 | # RUN: ld.lld -Ttext 0x0 -Tdata 0x4000 -Tbss 0x8000 %t.o -o %t2 |
| 18 | # RUN: llvm-readobj --elf-output-style=GNU -l -s %t2 | FileCheck %s --check-prefix=USER1 | |
| 18 | # RUN: llvm-readelf -S -l %t2 | FileCheck %s --check-prefix=USER1 | |
| 19 | 19 | # USER1: .text PROGBITS 0000000000000000 001000 000001 |
| 20 | 20 | # USER1-NEXT: .data PROGBITS 0000000000004000 002000 000008 |
| 21 | 21 | # USER1-NEXT: .bss NOBITS 0000000000008000 002008 000008 |
| ... | ... | @@ -26,7 +26,7 @@ |
| 26 | 26 | |
| 27 | 27 | ## With .text at 0x1000 there is space to allocate the headers. |
| 28 | 28 | # RUN: ld.lld -Ttext 0x1000 -Tdata 0x4000 -Tbss 0x8000 %t.o -o %t3 |
| 29 | # RUN: llvm-readobj --elf-output-style=GNU -l -s %t3 | FileCheck %s --check-prefix=USER2 | |
| 29 | # RUN: llvm-readelf -S -l %t3 | FileCheck %s --check-prefix=USER2 | |
| 30 | 30 | # USER2: .text PROGBITS 0000000000001000 001000 000001 |
| 31 | 31 | # USER2-NEXT: .data PROGBITS 0000000000004000 002000 000008 |
| 32 | 32 | # USER2-NEXT: .bss NOBITS 0000000000008000 002008 000008 |
| ... | ... | @@ -38,7 +38,7 @@ |
| 38 | 38 | |
| 39 | 39 | ## With .text well above 200000 we don't need to change the image base |
| 40 | 40 | # RUN: ld.lld -Ttext 0x201000 %t.o -o %t4 |
| 41 | # RUN: llvm-readobj --elf-output-style=GNU -l -s %t4 | FileCheck %s --check-prefix=USER3 | |
| 41 | # RUN: llvm-readelf -S -l %t4 | FileCheck %s --check-prefix=USER3 | |
| 42 | 42 | # USER3: .text PROGBITS 0000000000201000 001000 000001 |
| 43 | 43 | # USER3-NEX: .rodata PROGBITS 0000000000202000 002000 000008 |
| 44 | 44 | # USER3-NEX: .aw PROGBITS 0000000000203000 003000 000008 |
deps/lld/test/ELF/undef-broken-debug.test+16-9| ... | ... | @@ -1,12 +1,12 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: yaml2obj %s -o %t.o |
| 3 | # RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s | |
| 3 | # RUN: not ld.lld %t.o -o /dev/null | |
| 4 | 4 | |
| 5 | # The debug info has a broken relocation. Check that we don't crash | |
| 6 | # and still report the undefined symbol. | |
| 5 | # The debug info has a broken relocation. Check that we don't crash. | |
| 7 | 6 | |
| 8 | # CHECK: error: {{.*}}.o: relocation R_X86_64_64 at 0x29 has unsupported target | |
| 9 | # CHECK: error: undefined symbol: bar | |
| 7 | # We used to dereference null Target in DWARF.cpp:findAux while reporting a duplicate symbol error, | |
| 8 | # because Target wasn't initialized yet. | |
| 9 | # RUN: not ld.lld %t.o %t.o -o /dev/null | |
| 10 | 10 | |
| 11 | 11 | --- !ELF |
| 12 | 12 | FileHeader: |
| ... | ... | @@ -62,7 +62,14 @@ Sections: |
| 62 | 62 | Content: '0111001017000000' |
| 63 | 63 | |
| 64 | 64 | Symbols: |
| 65 | Global: | |
| 66 | - Name: _start | |
| 67 | Section: .text | |
| 68 | - Name: bar | |
| 65 | - Name: .debug_abbrev | |
| 66 | Type: STT_SECTION | |
| 67 | Section: .debug_abbrev | |
| 68 | - Name: .debug_line | |
| 69 | Type: STT_SECTION | |
| 70 | Section: .debug_line | |
| 71 | - Name: _start | |
| 72 | Section: .text | |
| 73 | Binding: STB_GLOBAL | |
| 74 | - Name: bar | |
| 75 | Binding: STB_GLOBAL |
deps/lld/test/ELF/undef-multi.s created+65| ... | ... | @@ -0,0 +1,65 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef.s -o %t2.o | |
| 4 | # RUN: not ld.lld %t.o %t2.o -o /dev/null 2>&1 | FileCheck %s | |
| 5 | ||
| 6 | # CHECK: error: undefined symbol: zed2 | |
| 7 | # CHECK-NEXT: >>> referenced by undef-multi.s | |
| 8 | # CHECK-NEXT: >>> {{.*}}:(.text+0x1) | |
| 9 | # CHECK-NEXT: >>> referenced by undef-multi.s | |
| 10 | # CHECK-NEXT: >>> {{.*}}:(.text+0x6) | |
| 11 | # CHECK-NEXT: >>> referenced by undef-multi.s | |
| 12 | # CHECK-NEXT: >>> {{.*}}:(.text+0xB) | |
| 13 | # CHECK-NEXT: >>> referenced by undef-multi.s | |
| 14 | # CHECK-NEXT: >>> {{.*}}:(.text+0x10) | |
| 15 | # CHECK-NEXT: >>> referenced by {{.*}}tmp2.o:(.text+0x0) | |
| 16 | ||
| 17 | # All references to a single undefined symbol count as a single error -- but | |
| 18 | # at most 10 references are printed. | |
| 19 | # RUN: echo ".globl _bar" > %t.moreref.s | |
| 20 | # RUN: echo "_bar:" >> %t.moreref.s | |
| 21 | # RUN: echo " call zed2" >> %t.moreref.s | |
| 22 | # RUN: echo " call zed2" >> %t.moreref.s | |
| 23 | # RUN: echo " call zed2" >> %t.moreref.s | |
| 24 | # RUN: echo " call zed2" >> %t.moreref.s | |
| 25 | # RUN: echo " call zed2" >> %t.moreref.s | |
| 26 | # RUN: echo " call zed2" >> %t.moreref.s | |
| 27 | # RUN: echo " call zed2" >> %t.moreref.s | |
| 28 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t.moreref.s -o %t3.o | |
| 29 | # RUN: not ld.lld %t.o %t2.o %t3.o -o /dev/null -error-limit=2 2>&1 | \ | |
| 30 | # RUN: FileCheck --check-prefix=LIMIT %s | |
| 31 | ||
| 32 | # LIMIT: error: undefined symbol: zed2 | |
| 33 | # LIMIT-NEXT: >>> referenced by undef-multi.s | |
| 34 | # LIMIT-NEXT: >>> {{.*}}:(.text+0x1) | |
| 35 | # LIMIT-NEXT: >>> referenced by undef-multi.s | |
| 36 | # LIMIT-NEXT: >>> {{.*}}:(.text+0x6) | |
| 37 | # LIMIT-NEXT: >>> referenced by undef-multi.s | |
| 38 | # LIMIT-NEXT: >>> {{.*}}:(.text+0xB) | |
| 39 | # LIMIT-NEXT: >>> referenced by undef-multi.s | |
| 40 | # LIMIT-NEXT: >>> {{.*}}:(.text+0x10) | |
| 41 | # LIMIT-NEXT: >>> referenced by {{.*}}tmp2.o:(.text+0x0) | |
| 42 | # LIMIT-NEXT: >>> referenced by {{.*}}tmp3.o:(.text+0x1) | |
| 43 | # LIMIT-NEXT: >>> referenced by {{.*}}tmp3.o:(.text+0x6) | |
| 44 | # LIMIT-NEXT: >>> referenced by {{.*}}tmp3.o:(.text+0xB) | |
| 45 | # LIMIT-NEXT: >>> referenced by {{.*}}tmp3.o:(.text+0x10) | |
| 46 | # LIMIT-NEXT: >>> referenced by {{.*}}tmp3.o:(.text+0x15) | |
| 47 | # LIMIT-NEXT: >>> referenced 2 more times | |
| 48 | ||
| 49 | .file "undef-multi.s" | |
| 50 | ||
| 51 | .globl _start | |
| 52 | _start: | |
| 53 | call zed2 | |
| 54 | ||
| 55 | .globl _f | |
| 56 | _f: | |
| 57 | call zed2 | |
| 58 | ||
| 59 | .globl _g | |
| 60 | _g: | |
| 61 | call zed2 | |
| 62 | ||
| 63 | .globl _h | |
| 64 | _h: | |
| 65 | call zed2 |
deps/lld/test/ELF/undef-shared.s+3-3| ... | ... | @@ -2,17 +2,17 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 3 | 3 | # RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s |
| 4 | 4 | |
| 5 | # CHECK: error: undefined symbol: hidden | |
| 5 | # CHECK: error: undefined hidden symbol: hidden | |
| 6 | 6 | # CHECK: >>> referenced by {{.*}}:(.data+0x0) |
| 7 | 7 | .global hidden |
| 8 | 8 | .hidden hidden |
| 9 | 9 | |
| 10 | # CHECK: error: undefined symbol: internal | |
| 10 | # CHECK: error: undefined internal symbol: internal | |
| 11 | 11 | # CHECK: >>> referenced by {{.*}}:(.data+0x8) |
| 12 | 12 | .global internal |
| 13 | 13 | .internal internal |
| 14 | 14 | |
| 15 | # CHECK: error: undefined symbol: protected | |
| 15 | # CHECK: error: undefined protected symbol: protected | |
| 16 | 16 | # CHECK: >>> referenced by {{.*}}:(.data+0x10) |
| 17 | 17 | .global protected |
| 18 | 18 | .protected protected |
deps/lld/test/ELF/undef-shared2.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: not ld.lld %t.o %t2.o -o %t.so -shared 2>&1 | FileCheck %s |
| 5 | 5 | # RUN: not ld.lld %t2.o %t.o -o %t.so -shared 2>&1 | FileCheck %s |
| 6 | 6 | |
| 7 | # CHECK: error: undefined symbol: foo | |
| 7 | # CHECK: error: undefined protected symbol: foo | |
| 8 | 8 | |
| 9 | 9 | .data |
| 10 | 10 | .quad foo |
deps/lld/test/ELF/undef-version-script.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 3 | 3 | # RUN: echo "{ local: *; };" > %t.script |
| 4 | 4 | # RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so |
| 5 | # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s | |
| 5 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | # CHECK: DynamicSymbols [ |
| 8 | 8 | # CHECK-NEXT: Symbol { |
deps/lld/test/ELF/undef-with-plt-addr-i686.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/undef-with-plt-addr.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld %t2.o -o %t2.so -shared |
| 5 | 5 | // RUN: ld.lld %t.o %t2.so -o %t3 |
| 6 | // RUN: llvm-readobj -t -s %t3 | FileCheck %s | |
| 6 | // RUN: llvm-readobj --symbols -S %t3 | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | .globl _start |
| 9 | 9 | _start: |
deps/lld/test/ELF/undef-with-plt-addr.s+3-3| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/undef-with-plt-addr.s -o %t2.o |
| 4 | 4 | // RUN: ld.lld %t2.o -o %t2.so -shared |
| 5 | 5 | // RUN: ld.lld %t.o %t2.so -o %t3 |
| 6 | // RUN: llvm-readobj -t -s -r %t3 | FileCheck %s | |
| 6 | // RUN: llvm-readobj --symbols -S -r %t3 | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | // Test that -z nocopyreloc doesn't prevent the plt hack. |
| 9 | 9 | // RUN: ld.lld %t.o %t2.so -o %t3 -z nocopyreloc |
| ... | ... | @@ -25,10 +25,10 @@ movabsq	$set_data, %rax |
| 25 | 25 | // CHECK-NEXT: Address: 0x201010 |
| 26 | 26 | |
| 27 | 27 | // CHECK: Section ({{.*}}) .rela.dyn { |
| 28 | // CHECK-NEXT: 0x202000 R_X86_64_64 foo 0x0 | |
| 28 | // CHECK-NEXT: 0x203000 R_X86_64_64 foo 0x0 | |
| 29 | 29 | // CHECK-NEXT: } |
| 30 | 30 | // CHECK-NEXT: Section ({{.*}}) .rela.plt { |
| 31 | // CHECK-NEXT: 0x202020 R_X86_64_JUMP_SLOT set_data 0x0 | |
| 31 | // CHECK-NEXT: 0x203020 R_X86_64_JUMP_SLOT set_data 0x0 | |
| 32 | 32 | // CHECK-NEXT: } |
| 33 | 33 | |
| 34 | 34 | // CHECK: Name: foo |
deps/lld/test/ELF/undefined-glob.s created+58| ... | ... | @@ -0,0 +1,58 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | # RUN: echo '.globl foo1; foo1:' | \ | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t1.o | |
| 5 | # RUN: echo '.globl foo2; foo2:' | \ | |
| 6 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t2.o | |
| 7 | # RUN: echo '.globl foo32; foo32:' | \ | |
| 8 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t3.o | |
| 9 | # RUN: echo '.globl bar; bar:' | \ | |
| 10 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t4.o | |
| 11 | # RUN: rm -f %t.a | |
| 12 | # RUN: llvm-ar rcs %t.a %t1.o %t2.o %t3.o %t4.o | |
| 13 | ||
| 14 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 15 | ||
| 16 | # RUN: ld.lld -o %t.exe %t.o %t.a | |
| 17 | # RUN: llvm-readobj --symbols %t.exe | FileCheck --check-prefix=NO-OPT %s | |
| 18 | ||
| 19 | # NO-OPT-NOT: foo | |
| 20 | # NO-OPT-NOT: bar | |
| 21 | ||
| 22 | # RUN: ld.lld -o %t.exe %t.o %t.a --undefined-glob foo1 | |
| 23 | # RUN: llvm-readobj --symbols %t.exe | FileCheck --check-prefix=FOO1 %s | |
| 24 | ||
| 25 | # FOO1: foo1 | |
| 26 | # FOO1-NOT: foo2 | |
| 27 | ||
| 28 | # RUN: ld.lld -o %t.exe %t.o %t.a --undefined-glob 'foo*' | |
| 29 | # RUN: llvm-readobj --symbols %t.exe | FileCheck --check-prefix=FOO-STAR %s | |
| 30 | ||
| 31 | # FOO-STAR: foo1 | |
| 32 | # FOO-STAR: foo2 | |
| 33 | # FOO-STAR: foo32 | |
| 34 | # FOO-STAR-NOT: bar | |
| 35 | ||
| 36 | # RUN: ld.lld -o %t.exe %t.o %t.a --undefined-glob 'foo?' | |
| 37 | # RUN: llvm-readobj --symbols %t.exe | FileCheck --check-prefix=FOO-Q %s | |
| 38 | ||
| 39 | # FOO-Q: foo1 | |
| 40 | # FOO-Q: foo2 | |
| 41 | # FOO-Q-NOT: foo32 | |
| 42 | # FOO-Q-NOT: bar | |
| 43 | ||
| 44 | # RUN: ld.lld -o %t.exe %t.o %t.a --undefined-glob 'foo[13]*' | |
| 45 | # RUN: llvm-readobj --symbols %t.exe | FileCheck --check-prefix=FOO13 %s | |
| 46 | ||
| 47 | # FOO13: foo1 | |
| 48 | # FOO13-NOT: foo2 | |
| 49 | # FOO13: foo32 | |
| 50 | # FOO13-NOT: bar | |
| 51 | ||
| 52 | # RUN: not ld.lld -o %t.exe %t.o %t.a --undefined-glob '[' 2>&1 | \ | |
| 53 | # RUN: FileCheck -check-prefix=BAD-PATTERN %s | |
| 54 | ||
| 55 | # BAD-PATTERN: --undefined-glob: invalid glob pattern: [ | |
| 56 | ||
| 57 | .globl _start | |
| 58 | _start: |
deps/lld/test/ELF/undefined-opt.s+1-1| ... | ... | @@ -40,7 +40,7 @@ |
| 40 | 40 | # TWO-UNDEFINED: Name: zed |
| 41 | 41 | # TWO-UNDEFINED: ] |
| 42 | 42 | # Now the same logic but linker script is used to set undefines |
| 43 | # RUN: echo "EXTERN( bar abs )" > %t.script | |
| 43 | # RUN: echo "EXTERN( bar \"abs\" )" > %t.script | |
| 44 | 44 | # RUN: ld.lld -o %t3 %t.o %tar.a %t.script |
| 45 | 45 | # RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TWO-UNDEFINED %s |
| 46 | 46 |
deps/lld/test/ELF/undefined-versioned-symbol.s+6-6| ... | ... | @@ -15,21 +15,21 @@ |
| 15 | 15 | |
| 16 | 16 | // CHECK: Section ({{.*}}) .rela.dyn { |
| 17 | 17 | // CHECK-NEXT: Relocation { |
| 18 | // CHECK-NEXT: Offset: 0x1000 | |
| 18 | // CHECK-NEXT: Offset: 0x2000 | |
| 19 | 19 | // CHECK-NEXT: Type: R_X86_64_64 (1) |
| 20 | // CHECK-NEXT: Symbol: basename (1) | |
| 20 | // CHECK-NEXT: Symbol: basename@FBSD_1.1 (1) | |
| 21 | 21 | // CHECK-NEXT: Addend: 0x0 |
| 22 | 22 | // CHECK-NEXT: } |
| 23 | 23 | // CHECK-NEXT: Relocation { |
| 24 | // CHECK-NEXT: Offset: 0x1008 | |
| 24 | // CHECK-NEXT: Offset: 0x2008 | |
| 25 | 25 | // CHECK-NEXT: Type: R_X86_64_64 (1) |
| 26 | // CHECK-NEXT: Symbol: basename (2) | |
| 26 | // CHECK-NEXT: Symbol: basename@FBSD_1.0 (2) | |
| 27 | 27 | // CHECK-NEXT: Addend: 0x0 |
| 28 | 28 | // CHECK-NEXT: } |
| 29 | 29 | // CHECK-NEXT: Relocation { |
| 30 | // CHECK-NEXT: Offset: 0x1010 | |
| 30 | // CHECK-NEXT: Offset: 0x2010 | |
| 31 | 31 | // CHECK-NEXT: Type: R_X86_64_64 (1) |
| 32 | // CHECK-NEXT: Symbol: basename (3) | |
| 32 | // CHECK-NEXT: Symbol: basename@FBSD_1.1 (3) | |
| 33 | 33 | // CHECK-NEXT: Addend: 0x0 |
| 34 | 34 | // CHECK-NEXT: } |
| 35 | 35 | // CHECK-NEXT: } |
deps/lld/test/ELF/unresolved-symbols.s+3-3| ... | ... | @@ -27,21 +27,21 @@ |
| 27 | 27 | # ERRUND: >>> referenced by {{.*}}:(.text+0x1) |
| 28 | 28 | |
| 29 | 29 | ## Also ignore all should not produce error for symbols from DSOs. |
| 30 | # RUN: ld.lld %t1.o %t.so -o %t1_3 --unresolved-symbols=ignore-all | |
| 30 | # RUN: ld.lld %t1.o %t.so -o %t1_3 --allow-shlib-undefined --unresolved-symbols=ignore-all | |
| 31 | 31 | # RUN: llvm-readobj %t1_3 > /dev/null 2>&1 |
| 32 | 32 | |
| 33 | 33 | ## Ignoring undefines in objects should not produce error for symbol from object. |
| 34 | 34 | # RUN: ld.lld %t1.o %t2.o -o %t2 --unresolved-symbols=ignore-in-object-files |
| 35 | 35 | # RUN: llvm-readobj %t2 > /dev/null 2>&1 |
| 36 | 36 | ## And still should not should produce for undefines from DSOs. |
| 37 | # RUN: ld.lld %t1.o %t.so -o /dev/null --unresolved-symbols=ignore-in-object-files | |
| 37 | # RUN: ld.lld %t1.o %t.so -o /dev/null --allow-shlib-undefined --unresolved-symbols=ignore-in-object-files | |
| 38 | 38 | # RUN: llvm-readobj %t2 > /dev/null 2>&1 |
| 39 | 39 | |
| 40 | 40 | ## Ignoring undefines in shared should produce error for symbol from object. |
| 41 | 41 | # RUN: not ld.lld %t2.o -o /dev/null --unresolved-symbols=ignore-in-shared-libs 2>&1 | \ |
| 42 | 42 | # RUN: FileCheck -check-prefix=ERRUND %s |
| 43 | 43 | ## And should not produce errors for symbols from DSO. |
| 44 | # RUN: ld.lld %t1.o %t.so -o %t3_1 --unresolved-symbols=ignore-in-shared-libs | |
| 44 | # RUN: ld.lld %t1.o %t.so -o %t3_1 --allow-shlib-undefined --unresolved-symbols=ignore-in-shared-libs | |
| 45 | 45 | # RUN: llvm-readobj %t3_1 > /dev/null 2>&1 |
| 46 | 46 | |
| 47 | 47 | ## Ignoring undefines in shared libs should not produce error for symbol from object |
deps/lld/test/ELF/verdef-defaultver.s+18-16| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: echo "V1 { global: a; local: *; };" > %t.script |
| 5 | 5 | # RUN: echo "V2 { global: b; c; } V1;" >> %t.script |
| 6 | 6 | # RUN: ld.lld --hash-style=sysv -shared -soname shared %t1 --version-script %t.script -o %t.so |
| 7 | # RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s | |
| 7 | # RUN: llvm-readobj -V --dyn-syms %t.so | FileCheck --check-prefix=DSO %s | |
| 8 | 8 | |
| 9 | 9 | # DSO: DynamicSymbols [ |
| 10 | 10 | # DSO-NEXT: Symbol { |
| ... | ... | @@ -108,7 +108,7 @@ |
| 108 | 108 | ## Check that we can link against DSO produced. |
| 109 | 109 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2 |
| 110 | 110 | # RUN: ld.lld --hash-style=sysv %t2 %t.so -o %t3 |
| 111 | # RUN: llvm-readobj -V -dyn-symbols %t3 | FileCheck --check-prefix=EXE %s | |
| 111 | # RUN: llvm-readobj -V --dyn-syms %t3 | FileCheck --check-prefix=EXE %s | |
| 112 | 112 | |
| 113 | 113 | # EXE: DynamicSymbols [ |
| 114 | 114 | # EXE-NEXT: Symbol { |
| ... | ... | @@ -150,8 +150,8 @@ |
| 150 | 150 | # EXE-NEXT: ] |
| 151 | 151 | # EXE-NEXT: Version symbols { |
| 152 | 152 | # EXE-NEXT: Section Name: .gnu.version |
| 153 | # EXE-NEXT: Address: 0x200228 | |
| 154 | # EXE-NEXT: Offset: 0x228 | |
| 153 | # EXE-NEXT: Address: 0x200260 | |
| 154 | # EXE-NEXT: Offset: 0x260 | |
| 155 | 155 | # EXE-NEXT: Link: 1 |
| 156 | 156 | # EXE-NEXT: Symbols [ |
| 157 | 157 | # EXE-NEXT: Symbol { |
| ... | ... | @@ -179,18 +179,20 @@ |
| 179 | 179 | # EXE-NEXT: Version: 1 |
| 180 | 180 | # EXE-NEXT: Count: 2 |
| 181 | 181 | # EXE-NEXT: FileName: shared |
| 182 | # EXE-NEXT: Entry { | |
| 183 | # EXE-NEXT: Hash: 1425 | |
| 184 | # EXE-NEXT: Flags: 0x0 | |
| 185 | # EXE-NEXT: Index: 2 | |
| 186 | # EXE-NEXT: Name: V1 | |
| 187 | # EXE-NEXT: } | |
| 188 | # EXE-NEXT: Entry { | |
| 189 | # EXE-NEXT: Hash: 1426 | |
| 190 | # EXE-NEXT: Flags: 0x0 | |
| 191 | # EXE-NEXT: Index: 3 | |
| 192 | # EXE-NEXT: Name: V2 | |
| 193 | # EXE-NEXT: } | |
| 182 | # EXE-NEXT: Entries [ | |
| 183 | # EXE-NEXT: Entry { | |
| 184 | # EXE-NEXT: Hash: 1425 | |
| 185 | # EXE-NEXT: Flags: 0x0 | |
| 186 | # EXE-NEXT: Index: 2 | |
| 187 | # EXE-NEXT: Name: V1 | |
| 188 | # EXE-NEXT: } | |
| 189 | # EXE-NEXT: Entry { | |
| 190 | # EXE-NEXT: Hash: 1426 | |
| 191 | # EXE-NEXT: Flags: 0x0 | |
| 192 | # EXE-NEXT: Index: 3 | |
| 193 | # EXE-NEXT: Name: V2 | |
| 194 | # EXE-NEXT: } | |
| 195 | # EXE-NEXT: ] | |
| 194 | 196 | # EXE-NEXT: } |
| 195 | 197 | # EXE-NEXT: } |
| 196 | 198 |
deps/lld/test/ELF/verdef-dependency.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: echo "LIBSAMPLE_2.0 { global: b; local: *; } LIBSAMPLE_1.0;" >> %t.script |
| 5 | 5 | # RUN: echo "LIBSAMPLE_3.0 { global: c; } LIBSAMPLE_2.0;" >> %t.script |
| 6 | 6 | # RUN: ld.lld --version-script %t.script -shared -soname shared %t.o -o %t.so |
| 7 | # RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s | |
| 7 | # RUN: llvm-readobj -V --dyn-syms %t.so | FileCheck --check-prefix=DSO %s | |
| 8 | 8 | |
| 9 | 9 | # DSO: SHT_GNU_verdef { |
| 10 | 10 | # DSO-NEXT: Definition { |
deps/lld/test/ELF/verdef.s+4-4| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: echo "LIBSAMPLE_2.0 { global: b; local: *; };" >> %t.script |
| 5 | 5 | # RUN: echo "LIBSAMPLE_3.0 { global: c; local: *; };" >> %t.script |
| 6 | 6 | # RUN: ld.lld --hash-style=sysv --version-script %t.script -shared -soname shared %t.o -o %t.so |
| 7 | # RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s | |
| 7 | # RUN: llvm-readobj -V --dyn-syms %t.so | FileCheck --check-prefix=DSO %s | |
| 8 | 8 | |
| 9 | 9 | # DSO: Version symbols { |
| 10 | 10 | # DSO-NEXT: Section Name: .gnu.version |
| ... | ... | @@ -70,8 +70,8 @@ |
| 70 | 70 | |
| 71 | 71 | # MAIN: Version symbols { |
| 72 | 72 | # MAIN-NEXT: Section Name: .gnu.version |
| 73 | # MAIN-NEXT: Address: 0x200228 | |
| 74 | # MAIN-NEXT: Offset: 0x228 | |
| 73 | # MAIN-NEXT: Address: 0x200260 | |
| 74 | # MAIN-NEXT: Offset: 0x260 | |
| 75 | 75 | # MAIN-NEXT: Link: 1 |
| 76 | 76 | # MAIN-NEXT: Symbols [ |
| 77 | 77 | # MAIN-NEXT: Symbol { |
| ... | ... | @@ -101,7 +101,7 @@ |
| 101 | 101 | # RUN: echo "LIBSAMPLE_3.0 { global: c; local: *; };" >> %t.script |
| 102 | 102 | # RUN: echo "}" >> %t.script |
| 103 | 103 | # RUN: ld.lld --hash-style=sysv --script %t.script -shared -soname shared %t.o -o %t2.so |
| 104 | # RUN: llvm-readobj -V -dyn-symbols %t2.so | FileCheck --check-prefix=DSO %s | |
| 104 | # RUN: llvm-readobj -V --dyn-syms %t2.so | FileCheck --check-prefix=DSO %s | |
| 105 | 105 | |
| 106 | 106 | .globl a |
| 107 | 107 | .type a,@function |
deps/lld/test/ELF/verneed.s+31-27| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | |
| 8 | 8 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 9 | 9 | # RUN: ld.lld --hash-style=sysv %t.o %t1.so %t2.so -o %t |
| 10 | # RUN: llvm-readobj -V -sections -section-data -dyn-symbols -dynamic-table %t | FileCheck %s | |
| 10 | # RUN: llvm-readobj -V --sections --section-data --dyn-syms --dynamic-table %t | FileCheck %s | |
| 11 | 11 | |
| 12 | 12 | # CHECK: Section { |
| 13 | 13 | # CHECK: Index: 1 |
| ... | ... | @@ -16,8 +16,8 @@ |
| 16 | 16 | # CHECK-NEXT: Flags [ (0x2) |
| 17 | 17 | # CHECK-NEXT: SHF_ALLOC (0x2) |
| 18 | 18 | # CHECK-NEXT: ] |
| 19 | # CHECK-NEXT: Address: 0x2001C8 | |
| 20 | # CHECK-NEXT: Offset: 0x1C8 | |
| 19 | # CHECK-NEXT: Address: 0x200200 | |
| 20 | # CHECK-NEXT: Offset: 0x200 | |
| 21 | 21 | # CHECK-NEXT: Size: 96 |
| 22 | 22 | # CHECK-NEXT: Link: [[DYNSTR:.*]] |
| 23 | 23 | # CHECK-NEXT: Info: 1 |
| ... | ... | @@ -47,7 +47,7 @@ |
| 47 | 47 | # CHECK-NEXT: SHF_ALLOC (0x2) |
| 48 | 48 | # CHECK-NEXT: ] |
| 49 | 49 | # CHECK-NEXT: Address: [[VERNEED:.*]] |
| 50 | # CHECK-NEXT: Offset: 0x230 | |
| 50 | # CHECK-NEXT: Offset: 0x268 | |
| 51 | 51 | # CHECK-NEXT: Size: 80 |
| 52 | 52 | # CHECK-NEXT: Link: 5 |
| 53 | 53 | # CHECK-NEXT: Info: 2 |
| ... | ... | @@ -60,17 +60,17 @@ |
| 60 | 60 | # CHECK-NEXT: Flags [ (0x2) |
| 61 | 61 | # CHECK-NEXT: SHF_ALLOC (0x2) |
| 62 | 62 | # CHECK-NEXT: ] |
| 63 | # CHECK-NEXT: Address: 0x2002A8 | |
| 64 | # CHECK-NEXT: Offset: 0x2A8 | |
| 63 | # CHECK-NEXT: Address: 0x2002E0 | |
| 64 | # CHECK-NEXT: Offset: 0x2E0 | |
| 65 | 65 | # CHECK-NEXT: Size: 47 |
| 66 | 66 | # CHECK-NEXT: Link: 0 |
| 67 | 67 | # CHECK-NEXT: Info: 0 |
| 68 | 68 | # CHECK-NEXT: AddressAlignment: 1 |
| 69 | 69 | # CHECK-NEXT: EntrySize: 0 |
| 70 | 70 | # CHECK-NEXT: SectionData ( |
| 71 | # CHECK-NEXT: 0000: 00766572 6E656564 312E736F 2E300076 |.verneed1.so.0.v| | |
| 72 | # CHECK-NEXT: 0010: 65726E65 6564322E 736F2E30 00663100 |erneed2.so.0.f1.| | |
| 73 | # CHECK-NEXT: 0020: 76330066 32007632 00673100 763100 |v3.f2.v2.g1.v1.| | |
| 71 | # CHECK-NEXT: 0000: 00663100 66320067 31007665 726E6565 |.f1.f2.g1.vernee| | |
| 72 | # CHECK-NEXT: 0010: 64312E73 6F2E3000 76320076 33007665 |d1.so.0.v2.v3.ve| | |
| 73 | # CHECK-NEXT: 0020: 726E6565 64322E73 6F2E3000 763100 |rneed2.so.0.v1.| | |
| 74 | 74 | # CHECK-NEXT: ) |
| 75 | 75 | # CHECK-NEXT: } |
| 76 | 76 | |
| ... | ... | @@ -148,29 +148,33 @@ |
| 148 | 148 | # CHECK-NEXT: Version: 1 |
| 149 | 149 | # CHECK-NEXT: Count: 2 |
| 150 | 150 | # CHECK-NEXT: FileName: verneed1.so.0 |
| 151 | # CHECK-NEXT: Entry { | |
| 152 | # CHECK-NEXT: Hash: 1938 | |
| 153 | # CHECK-NEXT: Flags: 0x0 | |
| 154 | # CHECK-NEXT: Index: 3 | |
| 155 | # CHECK-NEXT: Name: v2 | |
| 156 | # CHECK-NEXT: } | |
| 157 | # CHECK-NEXT: Entry { | |
| 158 | # CHECK-NEXT: Hash: 1939 | |
| 159 | # CHECK-NEXT: Flags: 0x0 | |
| 160 | # CHECK-NEXT: Index: 2 | |
| 161 | # CHECK-NEXT: Name: v3 | |
| 162 | # CHECK-NEXT: } | |
| 151 | # CHECK-NEXT: Entries [ | |
| 152 | # CHECK-NEXT: Entry { | |
| 153 | # CHECK-NEXT: Hash: 1938 | |
| 154 | # CHECK-NEXT: Flags: 0x0 | |
| 155 | # CHECK-NEXT: Index: 3 | |
| 156 | # CHECK-NEXT: Name: v2 | |
| 157 | # CHECK-NEXT: } | |
| 158 | # CHECK-NEXT: Entry { | |
| 159 | # CHECK-NEXT: Hash: 1939 | |
| 160 | # CHECK-NEXT: Flags: 0x0 | |
| 161 | # CHECK-NEXT: Index: 2 | |
| 162 | # CHECK-NEXT: Name: v3 | |
| 163 | # CHECK-NEXT: } | |
| 164 | # CHECK-NEXT: ] | |
| 163 | 165 | # CHECK-NEXT: } |
| 164 | 166 | # CHECK-NEXT: Dependency { |
| 165 | 167 | # CHECK-NEXT: Version: 1 |
| 166 | 168 | # CHECK-NEXT: Count: 1 |
| 167 | 169 | # CHECK-NEXT: FileName: verneed2.so.0 |
| 168 | # CHECK-NEXT: Entry { | |
| 169 | # CHECK-NEXT: Hash: 1937 | |
| 170 | # CHECK-NEXT: Flags: 0x0 | |
| 171 | # CHECK-NEXT: Index: 4 | |
| 172 | # CHECK-NEXT: Name: v1 | |
| 173 | # CHECK-NEXT: } | |
| 170 | # CHECK-NEXT: Entries [ | |
| 171 | # CHECK-NEXT: Entry { | |
| 172 | # CHECK-NEXT: Hash: 1937 | |
| 173 | # CHECK-NEXT: Flags: 0x0 | |
| 174 | # CHECK-NEXT: Index: 4 | |
| 175 | # CHECK-NEXT: Name: v1 | |
| 176 | # CHECK-NEXT: } | |
| 177 | # CHECK-NEXT: ] | |
| 174 | 178 | # CHECK-NEXT: } |
| 175 | 179 | # CHECK-NEXT: } |
| 176 | 180 |
deps/lld/test/ELF/version-exclude-libs.s+2-2| ... | ... | @@ -4,8 +4,8 @@ |
| 4 | 4 | // RUN: llvm-ar -r %t.a %t.o |
| 5 | 5 | // RUN: llvm-mc %s -o %t2.o -filetype=obj -triple=x86_64-pc-linux |
| 6 | 6 | // RUN: ld.lld %t2.o %t.a --shared --exclude-libs ALL -o %t.so |
| 7 | // RUN: llvm-readobj -symbols %t.so | FileCheck %s | |
| 8 | // RUN: llvm-readobj -dyn-symbols %t.so | FileCheck -check-prefix CHECK-DYN %s | |
| 7 | // RUN: llvm-readobj --symbols %t.so | FileCheck %s | |
| 8 | // RUN: llvm-readobj --dyn-syms %t.so | FileCheck -check-prefix CHECK-DYN %s | |
| 9 | 9 | // RUN: not ld.lld %t2.o %t.a --shared -o %t.so 2>&1 | FileCheck -check-prefix=CHECK-ERR %s |
| 10 | 10 | |
| 11 | 11 | // Test that we do not give an error message for undefined versions when the |
deps/lld/test/ELF/version-script-anonymous-local.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | |
| 4 | 4 | # RUN: echo "{ global: foo; local: bar; };" > %t.script |
| 5 | 5 | # RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so |
| 6 | # RUN: llvm-readobj -dyn-symbols -t %t.so | FileCheck %s | |
| 6 | # RUN: llvm-readobj --dyn-syms --symbols %t.so | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | # CHECK: Symbols [ |
| 9 | 9 | # CHECK: Name: bar |
deps/lld/test/ELF/version-script-copy-rel.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: ld.lld --version-script %t.script -shared %t1.o -o %t.so |
| 5 | 5 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o |
| 6 | 6 | # RUN: ld.lld %t2.o %t.so -o %tout |
| 7 | # RUN: llvm-readobj -dyn-symbols %tout | FileCheck %s | |
| 7 | # RUN: llvm-readobj --dyn-syms %tout | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | # CHECK: DynamicSymbols [ |
| 10 | 10 | # CHECK: Symbol { |
deps/lld/test/ELF/version-script-extern-exact.s+2-2| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 4 | 4 | # RUN: echo "FOO { global: extern \"C++\" { \"aaa*\"; }; };" > %t.script |
| 5 | 5 | # RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so |
| 6 | # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s --check-prefix=NOMATCH | |
| 6 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck %s --check-prefix=NOMATCH | |
| 7 | 7 | |
| 8 | 8 | # NOMATCH: DynamicSymbols [ |
| 9 | 9 | # NOMATCH-NOT: _Z3aaaPf@@FOO |
| ... | ... | @@ -12,7 +12,7 @@ |
| 12 | 12 | |
| 13 | 13 | # RUN: echo "FOO { global: extern \"C++\" { \"aaa*\"; aaa*; }; };" > %t2.script |
| 14 | 14 | # RUN: ld.lld --version-script %t2.script -shared %t.o -o %t2.so |
| 15 | # RUN: llvm-readobj -dyn-symbols %t2.so | FileCheck %s --check-prefix=MATCH | |
| 15 | # RUN: llvm-readobj --dyn-syms %t2.so | FileCheck %s --check-prefix=MATCH | |
| 16 | 16 | # MATCH: DynamicSymbols [ |
| 17 | 17 | # MATCH: _Z3aaaPf@@FOO |
| 18 | 18 | # MATCH: _Z3aaaPi@@FOO |
deps/lld/test/ELF/version-script-extern-wildcards-anon.s+1-1| ... | ... | @@ -12,7 +12,7 @@ |
| 12 | 12 | # RUN: local: *; \ |
| 13 | 13 | # RUN: }; ' > %t.script |
| 14 | 14 | # RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so |
| 15 | # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s | |
| 15 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck %s | |
| 16 | 16 | |
| 17 | 17 | # CHECK: DynamicSymbols [ |
| 18 | 18 | # CHECK-NEXT: Symbol { |
deps/lld/test/ELF/version-script-extern-wildcards.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: echo "FOO { global: extern \"C++\" { foo*; }; };" > %t.script |
| 5 | 5 | # RUN: echo "BAR { global: extern \"C++\" { zed*; bar; }; };" >> %t.script |
| 6 | 6 | # RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so |
| 7 | # RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck %s | |
| 7 | # RUN: llvm-readobj -V --dyn-syms %t.so | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | # CHECK: Version symbols { |
| 10 | 10 | # CHECK: Symbols [ |
deps/lld/test/ELF/version-script-extern.s+1-1| ... | ... | @@ -8,7 +8,7 @@ |
| 8 | 8 | # RUN: echo ' extern "C" { _Z3bari; };' >> %t.script |
| 9 | 9 | # RUN: echo "};" >> %t.script |
| 10 | 10 | # RUN: ld.lld --hash-style=sysv --version-script %t.script -soname fixed-length-string -shared %t.o -o %t.so |
| 11 | # RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s | |
| 11 | # RUN: llvm-readobj -V --dyn-syms %t.so | FileCheck --check-prefix=DSO %s | |
| 12 | 12 | |
| 13 | 13 | # DSO: DynamicSymbols [ |
| 14 | 14 | # DSO-NEXT: Symbol { |
deps/lld/test/ELF/version-script-glob.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: echo "{ global: foo*; bar*; local: *; };" > %t.script |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 5 | 5 | # RUN: ld.lld -shared --version-script %t.script %t.o -o %t.so |
| 6 | # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s | |
| 6 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | .globl foo1 |
| 9 | 9 | foo1: |
deps/lld/test/ELF/version-script-hide-so-symbol.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: ld.lld -shared %t.o -o %t2.so |
| 5 | 5 | # RUN: echo "{ local: *; };" > %t.script |
| 6 | 6 | # RUN: ld.lld --version-script %t.script -shared %t.o %t2.so -o %t.so |
| 7 | # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s | |
| 7 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | # The symbol foo must be hidden. This matches bfd and gold and is |
| 10 | 10 | # required to make it possible for a c++ library to hide its own |
deps/lld/test/ELF/version-script-locals.s+3-3| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | |
| 4 | 4 | # RUN: echo "VERSION_1.0 { local: foo1; };" > %t.script |
| 5 | 5 | # RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so |
| 6 | # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=EXACT %s | |
| 6 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck --check-prefix=EXACT %s | |
| 7 | 7 | # EXACT: DynamicSymbols [ |
| 8 | 8 | # EXACT: _start |
| 9 | 9 | # EXACT-NOT: foo1 |
| ... | ... | @@ -12,7 +12,7 @@ |
| 12 | 12 | |
| 13 | 13 | # RUN: echo "VERSION_1.0 { local: foo*; };" > %t.script |
| 14 | 14 | # RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so |
| 15 | # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=WC %s | |
| 15 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck --check-prefix=WC %s | |
| 16 | 16 | # WC: DynamicSymbols [ |
| 17 | 17 | # WC: _start |
| 18 | 18 | # WC-NOT: foo1 |
| ... | ... | @@ -21,7 +21,7 @@ |
| 21 | 21 | |
| 22 | 22 | # RUN: echo "VERSION_1.0 { global: *; local: foo*; };" > %t.script |
| 23 | 23 | # RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so |
| 24 | # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=MIX %s | |
| 24 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck --check-prefix=MIX %s | |
| 25 | 25 | # MIX: DynamicSymbols [ |
| 26 | 26 | # MIX: _start@@VERSION_1.0 |
| 27 | 27 | # MIX-NOT: foo1 |
deps/lld/test/ELF/version-script-reassign.s created+36| ... | ... | @@ -0,0 +1,36 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | # RUN: echo '{ local: foo; };' > %tl.ver | |
| 4 | # RUN: echo '{ global: foo; local: *; };' > %tg.ver | |
| 5 | # RUN: echo 'V1 { global: foo; };' > %t1.ver | |
| 6 | # RUN: echo 'V2 { global: foo; };' > %t2.ver | |
| 7 | # RUN: echo 'V2 { global: notexist; local: f*; };' > %t2w.ver | |
| 8 | ||
| 9 | ## Note, ld.bfd errors on the two cases. | |
| 10 | # RUN: ld.lld -shared %t.o --version-script %tl.ver --version-script %t1.ver \ | |
| 11 | # RUN: -o %t.so 2>&1 | FileCheck --check-prefix=LOCAL %s | |
| 12 | # RUN: llvm-readelf --dyn-syms %t.so | FileCheck --check-prefix=LOCAL-SYM %s | |
| 13 | # RUN: ld.lld -shared %t.o --version-script %tg.ver --version-script %t1.ver \ | |
| 14 | # RUN: -o %t.so 2>&1 | FileCheck --check-prefix=GLOBAL %s | |
| 15 | # RUN: llvm-readelf --dyn-syms %t.so | FileCheck --check-prefix=GLOBAL-SYM %s | |
| 16 | ||
| 17 | ## Note, ld.bfd silently accepts this case. | |
| 18 | # RUN: ld.lld -shared %t.o --version-script %t1.ver --version-script %t2.ver \ | |
| 19 | # RUN: -o %t.so 2>&1 | FileCheck --check-prefix=V1-WARN %s | |
| 20 | # RUN: llvm-readelf --dyn-syms %t.so | FileCheck --check-prefix=V1-SYM %s | |
| 21 | ||
| 22 | # RUN: ld.lld -shared %t.o --version-script %t1.ver --version-script %t2w.ver \ | |
| 23 | # RUN: -o %t.so --fatal-warnings | |
| 24 | # RUN: llvm-readelf --dyn-syms %t.so | FileCheck --check-prefix=V1-SYM %s | |
| 25 | ||
| 26 | # LOCAL: warning: attempt to reassign symbol 'foo' of VER_NDX_LOCAL to version 'V1' | |
| 27 | # LOCAL-SYM-NOT: foo | |
| 28 | ||
| 29 | # GLOBAL: warning: attempt to reassign symbol 'foo' of VER_NDX_GLOBAL to version 'V1' | |
| 30 | # GLOBAL-SYM: foo{{$}} | |
| 31 | ||
| 32 | # V1-WARN: warning: attempt to reassign symbol 'foo' of version 'V1' to version 'V2' | |
| 33 | # V1-SYM: foo@@V1 | |
| 34 | ||
| 35 | .globl foo | |
| 36 | foo: |
deps/lld/test/ELF/version-script-twice.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: echo "FBSD_1.1 {}; FBSD_1.2 {};" > %t.ver |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 5 | 5 | # RUN: ld.lld -shared %t.o -o %t.so --version-script=%t.ver |
| 6 | # RUN: llvm-readobj --dyn-symbols --elf-output-style=GNU %t.so | FileCheck %s | |
| 6 | # RUN: llvm-readelf --dyn-symbols %t.so | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | .weak	openat |
| 9 | 9 | openat: |
deps/lld/test/ELF/version-script-weak.s+2-2| ... | ... | @@ -6,11 +6,11 @@ |
| 6 | 6 | # RUN: llvm-ar rcs %t.a %tmp.o |
| 7 | 7 | # RUN: echo "{ local: *; };" > %t.script |
| 8 | 8 | # RUN: ld.lld -shared --version-script %t.script %t.o %t.a -o %t.so |
| 9 | # RUN: llvm-readobj -dyn-symbols -r %t.so | FileCheck %s | |
| 9 | # RUN: llvm-readobj --dyn-syms -r %t.so | FileCheck %s | |
| 10 | 10 | |
| 11 | 11 | # CHECK: Relocations [ |
| 12 | 12 | # CHECK-NEXT: Section ({{.*}}) .rela.plt { |
| 13 | # CHECK-NEXT: 0x2018 R_X86_64_JUMP_SLOT foo | |
| 13 | # CHECK-NEXT: 0x3018 R_X86_64_JUMP_SLOT foo | |
| 14 | 14 | # CHECK-NEXT: } |
| 15 | 15 | # CHECK-NEXT: ] |
| 16 | 16 | # CHECK: Symbol { |
deps/lld/test/ELF/version-script.s+6-12| ... | ... | @@ -6,19 +6,19 @@ |
| 6 | 6 | # RUN: echo "{ global: foo1; foo3; local: *; };" > %t.script |
| 7 | 7 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 8 | 8 | # RUN: ld.lld --version-script %t.script -shared %t.o %t2.so -o %t.so |
| 9 | # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s | |
| 9 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck --check-prefix=DSO %s | |
| 10 | 10 | |
| 11 | 11 | # RUN: echo "# comment" > %t3.script |
| 12 | 12 | # RUN: echo "{ local: *; # comment" >> %t3.script |
| 13 | 13 | # RUN: echo -n "}; # comment" >> %t3.script |
| 14 | 14 | # RUN: ld.lld --version-script %t3.script -shared %t.o %t2.so -o %t3.so |
| 15 | # RUN: llvm-readobj -dyn-symbols %t3.so | FileCheck --check-prefix=DSO2 %s | |
| 15 | # RUN: llvm-readobj --dyn-syms %t3.so | FileCheck --check-prefix=DSO2 %s | |
| 16 | 16 | |
| 17 | 17 | ## Also check that both "global:" and "global :" forms are accepted |
| 18 | 18 | # RUN: echo "VERSION_1.0 { global : foo1; local : *; };" > %t4.script |
| 19 | 19 | # RUN: echo "VERSION_2.0 { global: foo3; local: *; };" >> %t4.script |
| 20 | 20 | # RUN: ld.lld --version-script %t4.script -shared %t.o %t2.so -o %t4.so |
| 21 | # RUN: llvm-readobj -dyn-symbols %t4.so | FileCheck --check-prefix=VERDSO %s | |
| 21 | # RUN: llvm-readobj --dyn-syms %t4.so | FileCheck --check-prefix=VERDSO %s | |
| 22 | 22 | |
| 23 | 23 | # RUN: echo "VERSION_1.0 { global: foo1; local: *; };" > %t5.script |
| 24 | 24 | # RUN: echo "{ global: foo3; local: *; };" >> %t5.script |
| ... | ... | @@ -32,12 +32,6 @@ |
| 32 | 32 | # RUN: FileCheck -check-prefix=ERR2 %s |
| 33 | 33 | # ERR2: EOF expected, but got VERSION_2.0 |
| 34 | 34 | |
| 35 | # RUN: echo "VERSION_1.0 { global: foo1; local: *; };" > %t6.script | |
| 36 | # RUN: echo "VERSION_2.0 { global: foo1; local: *; };" >> %t6.script | |
| 37 | # RUN: not ld.lld --version-script %t6.script -shared %t.o %t2.so -o /dev/null 2>&1 | \ | |
| 38 | # RUN: FileCheck -check-prefix=ERR3 %s | |
| 39 | # ERR3: duplicate symbol 'foo1' in version script | |
| 40 | ||
| 41 | 35 | # RUN: echo "{ foo1; foo2; };" > %t.list |
| 42 | 36 | # RUN: ld.lld --version-script %t.script --dynamic-list %t.list %t.o %t2.so -o %t2 |
| 43 | 37 | # RUN: llvm-readobj %t2 > /dev/null |
| ... | ... | @@ -46,7 +40,7 @@ |
| 46 | 40 | # RUN: echo "VERSION_1.0 { global : foo1; local : *; };" > %t7a.script |
| 47 | 41 | # RUN: echo "VERSION_2.0 { global: foo3; local: *; };" > %t7b.script |
| 48 | 42 | # RUN: ld.lld --version-script %t7a.script --version-script %t7b.script -shared %t.o %t2.so -o %t7.so |
| 49 | # RUN: llvm-readobj -dyn-symbols %t7.so | FileCheck --check-prefix=VERDSO %s | |
| 43 | # RUN: llvm-readobj --dyn-syms %t7.so | FileCheck --check-prefix=VERDSO %s | |
| 50 | 44 | |
| 51 | 45 | # DSO: DynamicSymbols [ |
| 52 | 46 | # DSO-NEXT: Symbol { |
| ... | ... | @@ -149,12 +143,12 @@ |
| 149 | 143 | |
| 150 | 144 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 151 | 145 | # RUN: ld.lld --hash-style=sysv -shared %t.o %t2.so -o %t.so |
| 152 | # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=ALL %s | |
| 146 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck --check-prefix=ALL %s | |
| 153 | 147 | |
| 154 | 148 | # RUN: echo "{ global: foo1; foo3; };" > %t2.script |
| 155 | 149 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 156 | 150 | # RUN: ld.lld --hash-style=sysv --version-script %t2.script -shared %t.o %t2.so -o %t.so |
| 157 | # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck --check-prefix=ALL %s | |
| 151 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck --check-prefix=ALL %s | |
| 158 | 152 | |
| 159 | 153 | # ALL: DynamicSymbols [ |
| 160 | 154 | # ALL-NEXT: Symbol { |
deps/lld/test/ELF/version-use.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux |
| 3 | 3 | // RUN: ld.lld %t.o %p/Inputs/version-use.so -o %t.so -shared -z defs |
| 4 | // RUN: llvm-readobj -s %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -S %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | |
| 7 | 7 | call bar@PLT |
deps/lld/test/ELF/version-wildcard.test+2-2| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o |
| 4 | 4 | # RUN: echo "VERSION_1.0 { global: foo*; local: *; };" > %t.script |
| 5 | 5 | # RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so |
| 6 | # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s | |
| 6 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | # CHECK: DynamicSymbols [ |
| 9 | 9 | # CHECK-NEXT: Symbol { |
| ... | ... | @@ -48,7 +48,7 @@ |
| 48 | 48 | # RUN: echo "VERSION_1.0 { global: foo2; local: *; };" > %t2.script |
| 49 | 49 | # RUN: echo "VERSION_2.0 { global: foo*; };" >> %t2.script |
| 50 | 50 | # RUN: ld.lld --version-script %t2.script -shared %t.o -o %t2.so |
| 51 | # RUN: llvm-readobj -dyn-symbols %t2.so | FileCheck --check-prefix=MIX %s | |
| 51 | # RUN: llvm-readobj --dyn-syms %t2.so | FileCheck --check-prefix=MIX %s | |
| 52 | 52 | |
| 53 | 53 | # MIX: DynamicSymbols [ |
| 54 | 54 | # MIX-NEXT: Symbol { |
deps/lld/test/ELF/visibility.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t |
| 3 | 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/visibility.s -o %t2 |
| 4 | 4 | // RUN: ld.lld -shared %t %t2 -o %t3 |
| 5 | // RUN: llvm-readobj -t -dyn-symbols %t3 | FileCheck %s | |
| 5 | // RUN: llvm-readobj --symbols --dyn-syms %t3 | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // CHECK: Symbols [ |
| 8 | 8 | // CHECK-NEXT: Symbol { |
deps/lld/test/ELF/vs-diagnostics-duplicate.s created+63| ... | ... | @@ -0,0 +1,63 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o | |
| 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/vs-diagnostics-duplicate2.s -o %t2.o | |
| 4 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/vs-diagnostics-duplicate3.s -o %t3.o | |
| 5 | // RUN: not ld.lld --vs-diagnostics %t1.o %t2.o %t3.o -o %tout 2>&1 | FileCheck %s | |
| 6 | ||
| 7 | // Case 1. Both symbols have full source location. | |
| 8 | // CHECK: duplicate.s(15): error: duplicate symbol: bar | |
| 9 | // CHECK-NEXT: >>> defined at duplicate.s:15 | |
| 10 | // CHECK-NEXT: >>>{{.*}}1.o:(.text+0x{{.+}}) | |
| 11 | // CHECK: >>> defined at duplicate2.s:20 | |
| 12 | // CHECK: >>>{{.*}}2.o:(.text+0x{{.+}}) | |
| 13 | ||
| 14 | // Case 2. The source locations are unknown for both symbols. | |
| 15 | // CHECK: {{.*}}ld.lld{{.*}}: error: duplicate symbol: foo | |
| 16 | // CHECK-NEXT: >>> defined at {{.*}}1.o:(.text+0x{{.+}}) | |
| 17 | // CHECK-NEXT: >>> defined at {{.*}}2.o:(.text+0x{{.+}}) | |
| 18 | ||
| 19 | // Case 3. For the second definition of `baz` we know only the source file found in a STT_FILE symbol. | |
| 20 | // CHECK: duplicate.s(30): error: duplicate symbol: baz | |
| 21 | // CHECK-NEXT: >>> defined at duplicate.s:30 | |
| 22 | // CHECK-NEXT: >>> {{.*}}1.o:(.text+0x{{.+}}) | |
| 23 | // CHECK-NEXT: >>> defined at duplicate3.s | |
| 24 | // CHECK-NEXT: >>> {{.*}}3.o:(.text+0x{{.+}}) | |
| 25 | ||
| 26 | .global _start, foo, bar, baz | |
| 27 | .text | |
| 28 | _start: | |
| 29 | nop | |
| 30 | ||
| 31 | foo: | |
| 32 | nop | |
| 33 | ||
| 34 | .file 1 "duplicate.s" | |
| 35 | .loc 1 15 | |
| 36 | ||
| 37 | bar: | |
| 38 | nop | |
| 39 | ||
| 40 | .loc 1 30 | |
| 41 | baz: | |
| 42 | nop | |
| 43 | ||
| 44 | .section .debug_abbrev,"",@progbits | |
| 45 | .byte 1 # Abbreviation Code | |
| 46 | .byte 17 # DW_TAG_compile_unit | |
| 47 | .byte 0 # DW_CHILDREN_no | |
| 48 | .byte 16 # DW_AT_stmt_list | |
| 49 | .byte 23 # DW_FORM_sec_offset | |
| 50 | .byte 0 # EOM(1) | |
| 51 | .byte 0 # EOM(2) | |
| 52 | .byte 0 # EOM(3) | |
| 53 | ||
| 54 | .section .debug_info,"",@progbits | |
| 55 | .long .Lend0 - .Lbegin0 # Length of Unit | |
| 56 | .Lbegin0: | |
| 57 | .short 4 # DWARF version number | |
| 58 | .long .debug_abbrev # Offset Into Abbrev. Section | |
| 59 | .byte 8 # Address Size (in bytes) | |
| 60 | .byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit | |
| 61 | .long .debug_line # DW_AT_stmt_list | |
| 62 | .Lend0: | |
| 63 | .section .debug_line,"",@progbits |
deps/lld/test/ELF/vs-diagnostics-dynamic-relocation.s created+35| ... | ... | @@ -0,0 +1,35 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o | |
| 3 | // RUN: not ld.lld -shared --vs-diagnostics %t.o -o /dev/null 2>&1 | FileCheck %s | |
| 4 | ||
| 5 | // CHECK: dyn.s(15): error: can't create dynamic relocation R_X86_64_64 against local symbol in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output | |
| 6 | // CHECK-NEXT: >>> defined in {{.*}}.o | |
| 7 | // CHECK-NEXT: >>> referenced by dyn.s:15 | |
| 8 | // CHECK-NEXT: >>>{{.*}}.o:(.text+0x{{.+}}) | |
| 9 | ||
| 10 | .file 1 "dyn.s" | |
| 11 | .loc 1 15 | |
| 12 | ||
| 13 | foo: | |
| 14 | .quad foo | |
| 15 | ||
| 16 | .section .debug_abbrev,"",@progbits | |
| 17 | .byte 1 # Abbreviation Code | |
| 18 | .byte 17 # DW_TAG_compile_unit | |
| 19 | .byte 0 # DW_CHILDREN_no | |
| 20 | .byte 16 # DW_AT_stmt_list | |
| 21 | .byte 23 # DW_FORM_sec_offset | |
| 22 | .byte 0 # EOM(1) | |
| 23 | .byte 0 # EOM(2) | |
| 24 | .byte 0 # EOM(3) | |
| 25 | ||
| 26 | .section .debug_info,"",@progbits | |
| 27 | .long .Lend0 - .Lbegin0 # Length of Unit | |
| 28 | .Lbegin0: | |
| 29 | .short 4 # DWARF version number | |
| 30 | .long .debug_abbrev # Offset Into Abbrev. Section | |
| 31 | .byte 8 # Address Size (in bytes) | |
| 32 | .byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit | |
| 33 | .long .debug_line # DW_AT_stmt_list | |
| 34 | .Lend0: | |
| 35 | .section .debug_line,"",@progbits |
deps/lld/test/ELF/vs-diagnostics-undefined-symbol-1.s created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o | |
| 3 | // RUN: not ld.lld --vs-diagnostics %t1.o -o %tout 2>&1 \ | |
| 4 | // RUN: | FileCheck -check-prefix=ERR -check-prefix=CHECK -DFILE=%t1.o %s | |
| 5 | // RUN: ld.lld --vs-diagnostics --warn-unresolved-symbols %t1.o -o %tout 2>&1 \ | |
| 6 | // RUN: | FileCheck -check-prefix=WARN -check-prefix=CHECK -DFILE=%t1.o %s | |
| 7 | ||
| 8 | // ERR: [[FILE]]: error: undefined symbol: foo | |
| 9 | // WARN: [[FILE]]: warning: undefined symbol: foo | |
| 10 | // CHECK-NEXT: >>> referenced by {{.*}}1.o:(.text+0x{{.+}}) | |
| 11 | ||
| 12 | .global _start, foo | |
| 13 | .text | |
| 14 | _start: | |
| 15 | jmp foo | |
| \ No newline at end of file |
deps/lld/test/ELF/vs-diagnostics-undefined-symbol-2.s created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o | |
| 3 | // RUN: not ld.lld --vs-diagnostics %t1.o -o %tout 2>&1 \ | |
| 4 | // RUN: | FileCheck -check-prefix=ERR -check-prefix=CHECK %s | |
| 5 | // RUN: ld.lld --vs-diagnostics --warn-unresolved-symbols %t1.o -o %tout 2>&1 \ | |
| 6 | // RUN: | FileCheck -check-prefix=WARN -check-prefix=CHECK %s | |
| 7 | ||
| 8 | // ERR: {{.*}}ld.lld{{.*}}: error: undefined symbol: foo | |
| 9 | // WARN: {{.*}}ld.lld{{.*}}: warning: undefined symbol: foo | |
| 10 | // CHECK-NEXT: >>> referenced by undef2.s | |
| 11 | // CHECK-NEXT: >>> {{.*}}1.o:(.text+0x{{.+}}) | |
| 12 | ||
| 13 | .file "undef2.s" | |
| 14 | ||
| 15 | .global _start, foo | |
| 16 | .text | |
| 17 | _start: | |
| 18 | jmp foo |
deps/lld/test/ELF/vs-diagnostics-undefined-symbol-3.s created+40| ... | ... | @@ -0,0 +1,40 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o | |
| 3 | // RUN: not ld.lld --vs-diagnostics %t1.o -o %tout 2>&1 \ | |
| 4 | // RUN: | FileCheck -check-prefix=ERR -check-prefix=CHECK %s | |
| 5 | // RUN: ld.lld --vs-diagnostics --warn-unresolved-symbols %t1.o -o %tout 2>&1 \ | |
| 6 | // RUN: | FileCheck -check-prefix=WARN -check-prefix=CHECK %s | |
| 7 | ||
| 8 | // ERR: undef3.s(15): error: undefined symbol: foo | |
| 9 | // WARN: undef3.s(15): warning: undefined symbol: foo | |
| 10 | // CHECK: >>> referenced by undef3.s:15 | |
| 11 | // CHECK-NEXT: >>> {{.*}}1.o:(.text+0x{{.+}}) | |
| 12 | ||
| 13 | .file 1 "undef3.s" | |
| 14 | ||
| 15 | .global _start, foo | |
| 16 | .text | |
| 17 | _start: | |
| 18 | .loc 1 15 | |
| 19 | jmp foo | |
| 20 | ||
| 21 | .section .debug_abbrev,"",@progbits | |
| 22 | .byte 1 # Abbreviation Code | |
| 23 | .byte 17 # DW_TAG_compile_unit | |
| 24 | .byte 0 # DW_CHILDREN_no | |
| 25 | .byte 16 # DW_AT_stmt_list | |
| 26 | .byte 23 # DW_FORM_sec_offset | |
| 27 | .byte 0 # EOM(1) | |
| 28 | .byte 0 # EOM(2) | |
| 29 | .byte 0 # EOM(3) | |
| 30 | ||
| 31 | .section .debug_info,"",@progbits | |
| 32 | .long .Lend0 - .Lbegin0 # Length of Unit | |
| 33 | .Lbegin0: | |
| 34 | .short 4 # DWARF version number | |
| 35 | .long .debug_abbrev # Offset Into Abbrev. Section | |
| 36 | .byte 8 # Address Size (in bytes) | |
| 37 | .byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit | |
| 38 | .long .debug_line # DW_AT_stmt_list | |
| 39 | .Lend0: | |
| 40 | .section .debug_line,"",@progbits |
deps/lld/test/ELF/vs-diagnostics-versionscript.s created+5| ... | ... | @@ -0,0 +1,5 @@ |
| 1 | # RUN: echo "\"" > %/terr1.script | |
| 2 | # RUN: not ld.lld --vs-diagnostics --version-script %/terr1.script 2>&1 | \ | |
| 3 | # RUN: FileCheck %s -DSCRIPT="%/terr1.script" | |
| 4 | ||
| 5 | # CHECK: [[SCRIPT]](1): error: [[SCRIPT]]:1: unclosed quote |
deps/lld/test/ELF/warn-unresolved-symbols-hidden.s+2-2| ... | ... | @@ -3,8 +3,8 @@ |
| 3 | 3 | # RUN: not ld.lld -shared %t.o -o /dev/null -z defs --warn-unresolved-symbols 2>&1| FileCheck %s |
| 4 | 4 | |
| 5 | 5 | # CHECK: warning: undefined symbol: foo |
| 6 | # CHECK: error: undefined symbol: bar | |
| 7 | # CHECK: error: undefined symbol: zed | |
| 6 | # CHECK: error: undefined hidden symbol: bar | |
| 7 | # CHECK: error: undefined protected symbol: zed | |
| 8 | 8 | |
| 9 | 9 | .data |
| 10 | 10 | .quad foo |
deps/lld/test/ELF/weak-undef-export.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | |
| 5 | 5 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 6 | 6 | # RUN: ld.lld --export-dynamic %t.o -o %t |
| 7 | # RUN: llvm-readobj -dyn-symbols %t | FileCheck %s | |
| 7 | # RUN: llvm-readobj --dyn-syms %t | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | # CHECK: DynamicSymbols [ |
| 10 | 10 | # CHECK-NEXT: Symbol { |
deps/lld/test/ELF/weak-undef-hidden.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -r -s -section-data %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -r -S --section-data %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .data |
| 7 | 7 | .weak g |
deps/lld/test/ELF/weak-undef-lib.s+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t2.o |
| 5 | 5 | |
| 6 | 6 | # RUN: ld.lld -shared -o %t.so %t1.o --start-lib %t2.o |
| 7 | # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s | |
| 7 | # RUN: llvm-readobj --dyn-syms %t.so | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | # CHECK: Name: foo |
| 10 | 10 | # CHECK-NEXT: Value: 0x0 |
deps/lld/test/ELF/weak-undef-no-shared-libs.s created+28| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 3 | // RUN: ld.lld -pie %t.o -o %t | |
| 4 | // RUN: llvm-readobj -V --dyn-syms %t | FileCheck %s | |
| 5 | ||
| 6 | .globl _start | |
| 7 | _start: | |
| 8 | .type foo,@function | |
| 9 | .weak foo | |
| 10 | .long foo@gotpcrel | |
| 11 | ||
| 12 | // Test that an entry for weak undefined symbols is NOT emitted in .dynsym as | |
| 13 | // the PIE was not linked with any shared libraries. There are other tests which | |
| 14 | // ensure that the weak undefined symbols do get emitted in .dynsym for PIEs | |
| 15 | // linked against dynamic libraries. | |
| 16 | ||
| 17 | ||
| 18 | // CHECK: DynamicSymbols [ | |
| 19 | // CHECK-NEXT: Symbol { | |
| 20 | // CHECK-NEXT: Name: | |
| 21 | // CHECK-NEXT: Value: 0x0 | |
| 22 | // CHECK-NEXT: Size: 0 | |
| 23 | // CHECK-NEXT: Binding: Local (0x0) | |
| 24 | // CHECK-NEXT: Type: None (0x0) | |
| 25 | // CHECK-NEXT: Other: 0 | |
| 26 | // CHECK-NEXT: Section: Undefined (0x0) | |
| 27 | // CHECK-NEXT: } | |
| 28 | // CHECK-NEXT: ] |
deps/lld/test/ELF/weak-undef-rw.s+6-2| ... | ... | @@ -1,9 +1,13 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld %t.o -o %t --export-dynamic |
| 4 | # RUN: llvm-readobj -r %t | FileCheck %s | |
| 4 | # RUN: llvm-readelf -r %t | FileCheck %s | |
| 5 | 5 | |
| 6 | # CHECK: R_X86_64_64 foobar 0x0 | |
| 6 | ## gABI leaves the behavior of weak undefined references implementation defined. | |
| 7 | ## We choose to resolve it statically and not create a dynamic relocation for | |
| 8 | ## implementation simplicity. This also matches ld.bfd and gold. | |
| 9 | ||
| 10 | # CHECK: no relocations | |
| 7 | 11 | |
| 8 | 12 | .global _start |
| 9 | 13 | _start: |
deps/lld/test/ELF/weak-undef-shared.s+35-17| ... | ... | @@ -1,19 +1,37 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux | |
| 3 | // RUN: llvm-mc %p/Inputs/shared.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux | |
| 4 | // RUN: ld.lld %t2.o -o %t2.so -shared | |
| 5 | // RUN: ld.lld %t.o %t2.so -o %t.exe | |
| 6 | // RUN: llvm-readobj -t %t.exe | FileCheck %s | |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 7 | 4 | |
| 8 | // CHECK: Name: bar | |
| 9 | // CHECK-NEXT: Value: 0x201020 | |
| 10 | // CHECK-NEXT: Size: 0 | |
| 11 | // CHECK-NEXT: Binding: Weak | |
| 12 | // CHECK-NEXT: Type: Function | |
| 13 | // CHECK-NEXT: Other: 0 | |
| 14 | // CHECK-NEXT: Section: Undefined | |
| 5 | # RUN: echo '.data; .weak foo; .quad foo' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o | |
| 6 | # RUN: echo '.data; .quad foo' | llvm-mc -filetype=obj -triple=x86_64 - -o %t2.o | |
| 7 | # RUN: ld.lld -shared %t2.o -o %t2.so | |
| 15 | 8 | |
| 16 | .global _start | |
| 17 | _start: | |
| 18 | .weak bar | |
| 19 | .quad bar | |
| 9 | ## If the first undefined reference is weak, the binding changes to | |
| 10 | ## STB_WEAK. | |
| 11 | # RUN: ld.lld %t1.o %t.so -o %t | |
| 12 | # RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=WEAK %s | |
| 13 | # RUN: ld.lld %t.so %t1.o -o %t | |
| 14 | # RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=WEAK %s | |
| 15 | ||
| 16 | ## The binding remains STB_WEAK if there is no STB_GLOBAL undefined reference. | |
| 17 | # RUN: ld.lld %t1.o %t.so %t1.o -o %t | |
| 18 | # RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=WEAK %s | |
| 19 | # RUN: ld.lld %t.so %t1.o %t1.o -o %t | |
| 20 | # RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=WEAK %s | |
| 21 | ||
| 22 | ## The binding changes back to STB_GLOBAL if there is a STB_GLOBAL undefined reference. | |
| 23 | # RUN: ld.lld %t1.o %t.so %t2.o -o %t | |
| 24 | # RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=GLOBAL %s | |
| 25 | # RUN: ld.lld %t2.o %t.so %t1.o -o %t | |
| 26 | # RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=GLOBAL %s | |
| 27 | ||
| 28 | ## Check the binding (weak) is not affected by the STB_GLOBAL undefined | |
| 29 | ## reference in %t2.so | |
| 30 | # RUN: ld.lld %t1.o %t2.so -o %t | |
| 31 | # RUN: llvm-readelf --dyn-syms %t | FileCheck --check-prefix=WEAK %s | |
| 32 | ||
| 33 | # WEAK: NOTYPE WEAK DEFAULT UND foo | |
| 34 | # GLOBAL: NOTYPE GLOBAL DEFAULT UND foo | |
| 35 | ||
| 36 | .globl foo | |
| 37 | foo: |
deps/lld/test/ELF/weak-undef-shared2.s created+21| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | # RUN: echo '.globl f; f:' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o | |
| 4 | # RUN: echo '.weak f; .data; .quad f' | llvm-mc -filetype=obj -triple=x86_64 - -o %t2.o | |
| 5 | # RUN: ld.lld -shared %t1.o -o %t1.so | |
| 6 | # RUN: ld.lld -shared %t2.o -o %t2.so | |
| 7 | ||
| 8 | ## The undefined reference is STB_GLOBAL in %t.o while STB_WEAK in %t2.so. | |
| 9 | ## Check the binding of the result is STB_GLOBAL. | |
| 10 | ||
| 11 | # RUN: ld.lld %t.o %t1.so %t2.so -o %t | |
| 12 | # RUN: llvm-readelf --dyn-syms %t | FileCheck %s | |
| 13 | # RUN: ld.lld %t1.so %t.o %t2.so -o %t | |
| 14 | # RUN: llvm-readelf --dyn-syms %t | FileCheck %s | |
| 15 | # RUN: ld.lld %t1.so %t2.so %t.o -o %t | |
| 16 | # RUN: llvm-readelf --dyn-syms %t | FileCheck %s | |
| 17 | ||
| 18 | # CHECK: NOTYPE GLOBAL DEFAULT UND f | |
| 19 | ||
| 20 | .data | |
| 21 | .quad f |
deps/lld/test/ELF/weak-undef-val.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | # RUN: ld.lld %t.o -o %t --export-dynamic |
| 4 | # RUN: llvm-readobj -s -section-data %t | FileCheck %s | |
| 4 | # RUN: llvm-readobj -S --section-data %t | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | # CHECK: Name: .text |
| 7 | 7 | # CHECK-NEXT: Type: SHT_PROGBITS |
deps/lld/test/ELF/weak-undef.s+4-2| ... | ... | @@ -1,7 +1,9 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/dummy-shared.s -o %t1.o | |
| 3 | # RUN: ld.lld %t1.o -shared -o %t1.so | |
| 2 | 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | # RUN: ld.lld %t.o -o %t -pie | |
| 4 | # RUN: llvm-readobj -dyn-symbols %t | FileCheck %s | |
| 5 | # RUN: ld.lld %t.o -o %t %t1.so -pie | |
| 6 | # RUN: llvm-readobj --dyn-syms %t | FileCheck %s | |
| 5 | 7 | |
| 6 | 8 | # CHECK: DynamicSymbols [ |
| 7 | 9 | # CHECK-NEXT: Symbol { |
deps/lld/test/ELF/wrap-dynamic-undef.s+1-1| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/wrap-dynamic-undef.s -o %t2.o |
| 4 | 4 | # RUN: ld.lld %t2.o -o %t2.so -shared |
| 5 | 5 | # RUN: ld.lld %t1.o %t2.so -o %t --wrap foo |
| 6 | # RUN: llvm-readobj -dyn-symbols --elf-output-style=GNU %t | FileCheck %s | |
| 6 | # RUN: llvm-readelf --dyn-syms %t | FileCheck %s | |
| 7 | 7 | |
| 8 | 8 | # Test that the dynamic relocation uses foo. We used to produce a |
| 9 | 9 | # relocation with __real_foo. |
deps/lld/test/ELF/wrap-entry.s+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | |
| 4 | 4 | // RUN: ld.lld -o %t.exe %t.o -wrap=_start |
| 5 | // RUN: llvm-readobj -file-headers %t.exe | FileCheck %s | |
| 5 | // RUN: llvm-readobj --file-headers %t.exe | FileCheck %s | |
| 6 | 6 | |
| 7 | 7 | // CHECK: Entry: 0x201001 |
| 8 | 8 |
deps/lld/test/ELF/wrap-plt.s+3-3| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t |
| 3 | 3 | |
| 4 | 4 | // RUN: ld.lld -o %t2 %t -wrap foo -shared |
| 5 | // RUN: llvm-readobj -s -r %t2 | FileCheck %s | |
| 5 | // RUN: llvm-readobj -S -r %t2 | FileCheck %s | |
| 6 | 6 | // RUN: llvm-objdump -d %t2 | FileCheck --check-prefix=DISASM %s |
| 7 | 7 | |
| 8 | 8 | // CHECK: Name: .plt |
| ... | ... | @@ -20,8 +20,8 @@ |
| 20 | 20 | |
| 21 | 21 | // CHECK: Relocations [ |
| 22 | 22 | // CHECK-NEXT: Section ({{.*}}) .rela.plt { |
| 23 | // CHECK-NEXT: 0x2018 R_X86_64_JUMP_SLOT __wrap_foo 0x0 | |
| 24 | // CHECK-NEXT: 0x2020 R_X86_64_JUMP_SLOT _start 0x0 | |
| 23 | // CHECK-NEXT: 0x3018 R_X86_64_JUMP_SLOT __wrap_foo 0x0 | |
| 24 | // CHECK-NEXT: 0x3020 R_X86_64_JUMP_SLOT _start 0x0 | |
| 25 | 25 | // CHECK-NEXT: } |
| 26 | 26 | // CHECK-NEXT: ] |
| 27 | 27 |
deps/lld/test/ELF/wrap.s+1-1| ... | ... | @@ -14,7 +14,7 @@ |
| 14 | 14 | // CHECK-NEXT: movl $0x11010, %edx |
| 15 | 15 | // CHECK-NEXT: movl $0x11000, %edx |
| 16 | 16 | |
| 17 | // RUN: llvm-readobj -t %t3 > %t4.dump | |
| 17 | // RUN: llvm-readobj --symbols %t3 > %t4.dump | |
| 18 | 18 | // RUN: FileCheck --check-prefix=SYM1 %s < %t4.dump |
| 19 | 19 | // RUN: FileCheck --check-prefix=SYM2 %s < %t4.dump |
| 20 | 20 | // RUN: FileCheck --check-prefix=SYM3 %s < %t4.dump |
deps/lld/test/ELF/x86-64-cet.s created+48| ... | ... | @@ -0,0 +1,48 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-cet1.s -o %t1.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-cet2.s -o %t2.o | |
| 5 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-cet3.s -o %t3.o | |
| 6 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-cet4.s -o %t4.o | |
| 7 | ||
| 8 | # RUN: ld.lld -e func1 %t.o %t1.o -o %t | |
| 9 | # RUN: llvm-readelf -n %t | FileCheck -check-prefix=CET -match-full-lines %s | |
| 10 | ||
| 11 | # RUN: ld.lld -e func1 %t.o %t2.o -o %t | |
| 12 | # RUN: llvm-readelf -n %t | FileCheck -check-prefix=CET -match-full-lines %s | |
| 13 | ||
| 14 | # CET: Properties: x86 feature: IBT, SHSTK | |
| 15 | ||
| 16 | # RUN: ld.lld -e func1 %t.o %t3.o -o %t | |
| 17 | # RUN: llvm-readelf -S %t | FileCheck -check-prefix=NOCET %s | |
| 18 | ||
| 19 | # NOCET: Section Headers | |
| 20 | # NOCET-NOT: .note.gnu.property | |
| 21 | ||
| 22 | # RUN: not ld.lld -e func1 %t.o %t3.o -o %t --require-cet 2>&1 \ | |
| 23 | # RUN: | FileCheck -check-prefix=ERROR %s | |
| 24 | # ERROR: x86-64-cet.s.tmp3.o: --require-cet: file is not compatible with CET | |
| 25 | ||
| 26 | # RUN: ld.lld -e func1 %t.o %t4.o -o %t | |
| 27 | # RUN: llvm-readelf -n %t | FileCheck -check-prefix=NOSHSTK -match-full-lines %s | |
| 28 | ||
| 29 | # Check .note.gnu.protery without property SHSTK. | |
| 30 | # NOSHSTK: Properties: x86 feature: IBT | |
| 31 | ||
| 32 | .section ".note.gnu.property", "a" | |
| 33 | .long 4 | |
| 34 | .long 0x10 | |
| 35 | .long 0x5 | |
| 36 | .asciz "GNU" | |
| 37 | ||
| 38 | .long 0xc0000002 | |
| 39 | .long 4 | |
| 40 | .long 3 | |
| 41 | .long 0 | |
| 42 | ||
| 43 | .text | |
| 44 | .globl func1 | |
| 45 | .type func1,@function | |
| 46 | func1: | |
| 47 | call func2 | |
| 48 | ret |
deps/lld/test/ELF/x86-64-dyn-rel-error5.s created+26| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | # RUN: not ld.lld -pie %t.o -o /dev/null 2>&1 | FileCheck %s | |
| 4 | # RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s | |
| 5 | ||
| 6 | ## Check we don't create dynamic relocations in a writable section, | |
| 7 | ## if the number of bits is smaller than the wordsize. | |
| 8 | ||
| 9 | .globl hidden | |
| 10 | .hidden hidden | |
| 11 | local: | |
| 12 | hidden: | |
| 13 | ||
| 14 | # CHECK: error: relocation R_X86_64_8 cannot be used against local symbol; recompile with -fPIC | |
| 15 | # CHECK-NEXT: >>> defined in {{.*}}.o | |
| 16 | # CHECK-NEXT: >>> referenced by {{.*}}.o:(.data+0x0) | |
| 17 | # CHECK: error: relocation R_X86_64_16 cannot be used against local symbol; recompile with -fPIC | |
| 18 | # CHECK: error: relocation R_X86_64_32 cannot be used against local symbol; recompile with -fPIC | |
| 19 | # CHECK: error: relocation R_X86_64_32 cannot be used against symbol hidden; recompile with -fPIC | |
| 20 | ||
| 21 | .data | |
| 22 | .byte local # R_X86_64_8 | |
| 23 | .short local # R_X86_64_16 | |
| 24 | .long local # R_X86_64_32 | |
| 25 | ||
| 26 | .long hidden # R_X86_64_32 |
deps/lld/test/ELF/x86-64-pcrel.s created+23| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | ||
| 3 | // This is a test for R_X86_64_PC8 and R_X86_64_PC16. | |
| 4 | ||
| 5 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o | |
| 6 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/x86-64-pcrel.s -o %t2.o | |
| 7 | // RUN: ld.lld -o %t.exe %t1.o %t2.o | |
| 8 | // RUN: llvm-objdump -s %t.exe | FileCheck %s | |
| 9 | ||
| 10 | // CHECK: Contents of section .text: | |
| 11 | // CHECK-NEXT: 2000cccc cccccccc cccccccc cccccccc | |
| 12 | // CHECK-NEXT: 20cccccc cccccccc cccccccc cccccccc | |
| 13 | // CHECK-NEXT: e0ffcccc cccccccc cccccccc cccccccc | |
| 14 | // CHECK-NEXT: e0cccccc cccccccc cccccccc cccccccc | |
| 15 | ||
| 16 | .globl _start | |
| 17 | _start: | |
| 18 | ||
| 19 | .word foo - _start | |
| 20 | .fill 14,1,0xcc | |
| 21 | ||
| 22 | .byte foo - _start | |
| 23 | .fill 15,1,0xcc |
deps/lld/test/ELF/x86-64-plt-high-addr.s+4-4| ... | ... | @@ -8,16 +8,16 @@ |
| 8 | 8 | // RUN: llvm-objdump -s -j .got.plt %t1.exe | FileCheck %s |
| 9 | 9 | |
| 10 | 10 | // CHECK: Contents of section .got.plt: |
| 11 | // CHECK-NEXT: cafe00002000 00300000 feca0000 00000000 00000000 | |
| 12 | // CHECK-NEXT: cafe00002010 00000000 00000000 26100000 feca0000 | |
| 11 | // CHECK-NEXT: cafe00003000 00200000 feca0000 00000000 00000000 | |
| 12 | // CHECK-NEXT: cafe00003010 00000000 00000000 26100000 feca0000 | |
| 13 | 13 | |
| 14 | 14 | // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o |
| 15 | 15 | // RUN: ld.lld -o %t2.exe %t2.o %t.so -image-base=0xcafe00000000 -z retpolineplt |
| 16 | 16 | // RUN: llvm-objdump -s -j .got.plt %t2.exe | FileCheck -check-prefix=RETPOLINE %s |
| 17 | 17 | |
| 18 | 18 | // RETPOLINE: Contents of section .got.plt: |
| 19 | // RETPOLINE-NEXT: cafe00002000 00300000 feca0000 00000000 00000000 | |
| 20 | // RETPOLINE-NEXT: cafe00002010 00000000 00000000 51100000 feca0000 | |
| 19 | // RETPOLINE-NEXT: cafe00003000 00200000 feca0000 00000000 00000000 | |
| 20 | // RETPOLINE-NEXT: cafe00003010 00000000 00000000 51100000 feca0000 | |
| 21 | 21 | |
| 22 | 22 | .global _start |
| 23 | 23 | _start: |
deps/lld/test/ELF/x86-64-rela.s+2-2| ... | ... | @@ -1,10 +1,10 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -dynamic-table %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj --dynamic-table %t.so | FileCheck %s | |
| 5 | 5 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux-gnux32 %s -o %t.o |
| 6 | 6 | // RUN: ld.lld %t.o -o %t.so -shared |
| 7 | // RUN: llvm-readobj -dynamic-table %t.so | FileCheck %s | |
| 7 | // RUN: llvm-readobj --dynamic-table %t.so | FileCheck %s | |
| 8 | 8 | |
| 9 | 9 | call foo@plt |
| 10 | 10 |
deps/lld/test/ELF/x86-64-reloc-16.s deleted-14| ... | ... | @@ -1,14 +0,0 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | ||
| 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-16.s -o %t1 | |
| 4 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-16-error.s -o %t2 | |
| 5 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t | |
| 6 | // RUN: ld.lld -shared %t %t1 -o /dev/null | |
| 7 | ||
| 8 | // CHECK: Contents of section .text: | |
| 9 | // CHECK-NEXT: 200000 42 | |
| 10 | ||
| 11 | // RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck --check-prefix=ERROR %s | |
| 12 | // ERROR: relocation R_X86_64_16 out of range: 65536 is not in [0, 65535] | |
| 13 | ||
| 14 | .short foo |
deps/lld/test/ELF/x86-64-reloc-8-16.s created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %S/Inputs/abs255.s -o %t255.o | |
| 4 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %S/Inputs/abs256.s -o %t256.o | |
| 5 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %S/Inputs/abs257.s -o %t257.o | |
| 6 | ||
| 7 | # RUN: ld.lld %t.o %t256.o -o %t | |
| 8 | # RUN: llvm-readelf -x .data %t | FileCheck %s | |
| 9 | # CHECK: 0x{{[0-9a-f]+}} ff80ffff 0080 | |
| 10 | ||
| 11 | # RUN: not ld.lld %t.o %t255.o -o /dev/null 2>&1 | FileCheck --check-prefix=OVERFLOW1 %s | |
| 12 | # OVERFLOW1: relocation R_X86_64_8 out of range: -129 is not in [-128, 255] | |
| 13 | # OVERFLOW1: relocation R_X86_64_16 out of range: -32769 is not in [-32768, 65535] | |
| 14 | ||
| 15 | # RUN: not ld.lld %t.o %t257.o -o /dev/null 2>&1 | FileCheck --check-prefix=OVERFLOW2 %s | |
| 16 | # OVERFLOW2: relocation R_X86_64_8 out of range: 256 is not in [-128, 255] | |
| 17 | # OVERFLOW2: relocation R_X86_64_16 out of range: 65536 is not in [-32768, 65535] | |
| 18 | ||
| 19 | .globl _start | |
| 20 | _start: | |
| 21 | .data | |
| 22 | .byte foo - 1 | |
| 23 | .byte foo - 384 | |
| 24 | .word foo + 0xfeff | |
| 25 | .word foo - 0x8100 |
deps/lld/test/ELF/x86-64-reloc-8.s deleted-14| ... | ... | @@ -1,14 +0,0 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | ||
| 3 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-8.s -o %t1 | |
| 4 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-8-error.s -o %t2 | |
| 5 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t | |
| 6 | // RUN: ld.lld -shared %t %t1 -o /dev/null | |
| 7 | ||
| 8 | // CHECK: Contents of section .text: | |
| 9 | // CHECK-NEXT: 200000 42 | |
| 10 | ||
| 11 | // RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck --check-prefix=ERROR %s | |
| 12 | // ERROR: relocation R_X86_64_8 out of range: 256 is not in [0, 255] | |
| 13 | ||
| 14 | .byte foo |
deps/lld/test/ELF/x86-64-reloc-gotoff64.s+6-12| ... | ... | @@ -4,14 +4,8 @@ |
| 4 | 4 | // RUN: llvm-readelf -S %t.so | FileCheck %s -check-prefix=SECTION |
| 5 | 5 | // RUN: llvm-objdump -d %t.so | FileCheck %s |
| 6 | 6 | |
| 7 | // SECTION: .dynamic DYNAMIC 0000000000003000 | |
| 8 | // SECTION: .got PROGBITS 0000000000003070 003070 000000 | |
| 9 | ||
| 10 | // All the _GLOBAL_OFFSET_TABLE_ occurrences below refer to the address | |
| 11 | // of GOT base, not the address of the symbol _GLOBAL_OFFSET_TABLE_. These | |
| 12 | // instructions are special and produce GOT base relative relocations. We | |
| 13 | // currently use .got end as the GOT base, which is not equal to | |
| 14 | // the address of the special symbol _GLOBAL_OFFSET_TABLE_. | |
| 7 | // SECTION: .dynamic DYNAMIC 0000000000002000 | |
| 8 | // SECTION: .got.plt PROGBITS 0000000000003000 003000 000018 | |
| 15 | 9 | |
| 16 | 10 | // The assembly is generated by |
| 17 | 11 | // gcc -O2 -S -mcmodel=medium -fPIC a.c |
| ... | ... | @@ -20,10 +14,10 @@ |
| 20 | 14 | // extern long _DYNAMIC[] __attribute__((visibility("hidden"))); |
| 21 | 15 | // long* dynamic() { return _DYNAMIC; } |
| 22 | 16 | |
| 23 | // 0x3070 (.got end) - 0x1007 = 8297 | |
| 24 | // 0x3000 (_DYNAMIC) - 0x3070 (.got end) = -112 | |
| 25 | // CHECK: 1000: {{.*}} leaq 8297(%rip), %rdx | |
| 26 | // CHECK-NEXT: 1007: {{.*}} movabsq $-112, %rax | |
| 17 | // 0x3000 (.got.plt) - 0x1007 = 8185 | |
| 18 | // 0x2000 (_DYNAMIC) - 0x3000 (.got.plt) = -4096 | |
| 19 | // CHECK: 1000: {{.*}} leaq 8185(%rip), %rdx | |
| 20 | // CHECK-NEXT: 1007: {{.*}} movabsq $-4096, %rax | |
| 27 | 21 | .global dynamic |
| 28 | 22 | dynamic: |
| 29 | 23 | leaq _GLOBAL_OFFSET_TABLE_(%rip), %rdx |
deps/lld/test/ELF/x86-64-reloc-gotpc64.s+3-3| ... | ... | @@ -4,11 +4,11 @@ |
| 4 | 4 | // RUN: llvm-readelf -S %t.so | FileCheck %s -check-prefix=SECTION |
| 5 | 5 | // RUN: llvm-objdump -d %t.so | FileCheck %s |
| 6 | 6 | |
| 7 | // SECTION: .got PROGBITS 0000000000003070 003070 000000 | |
| 7 | // SECTION: .got.plt PROGBITS 0000000000003000 003000 000018 | |
| 8 | 8 | |
| 9 | // 0x3070 (.got end) - 0x1000 = 8304 | |
| 9 | // 0x3000 (.got.plt) - 0x1000 = 8192 | |
| 10 | 10 | // CHECK: gotpc64: |
| 11 | // CHECK-NEXT: 1000: {{.*}} movabsq $8304, %r11 | |
| 11 | // CHECK-NEXT: 1000: {{.*}} movabsq $8192, %r11 | |
| 12 | 12 | .global gotpc64 |
| 13 | 13 | gotpc64: |
| 14 | 14 | movabsq $_GLOBAL_OFFSET_TABLE_-., %r11 |
deps/lld/test/ELF/x86-64-retpoline-linkerscript.s+5-4| ... | ... | @@ -13,9 +13,10 @@ |
| 13 | 13 | // RUN: llvm-objdump -d -s %t.exe | FileCheck %s |
| 14 | 14 | |
| 15 | 15 | // CHECK: Disassembly of section .plt: |
| 16 | // CHECK-EMPTY: | |
| 16 | 17 | // CHECK-NEXT: .plt: |
| 17 | // CHECK-NEXT: 10: ff 35 72 00 00 00 pushq 114(%rip) | |
| 18 | // CHECK-NEXT: 16: 4c 8b 1d 73 00 00 00 movq 115(%rip), %r11 | |
| 18 | // CHECK-NEXT: 10: ff 35 32 01 00 00 pushq 306(%rip) | |
| 19 | // CHECK-NEXT: 16: 4c 8b 1d 33 01 00 00 movq 307(%rip), %r11 | |
| 19 | 20 | // CHECK-NEXT: 1d: e8 0e 00 00 00 callq 14 <.plt+0x20> |
| 20 | 21 | // CHECK-NEXT: 22: f3 90 pause |
| 21 | 22 | // CHECK-NEXT: 24: 0f ae e8 lfence |
| ... | ... | @@ -40,7 +41,7 @@ |
| 40 | 41 | // CHECK-NEXT: 3d: cc int3 |
| 41 | 42 | // CHECK-NEXT: 3e: cc int3 |
| 42 | 43 | // CHECK-NEXT: 3f: cc int3 |
| 43 | // CHECK-NEXT: 40: 4c 8b 1d 51 00 00 00 movq 81(%rip), %r11 | |
| 44 | // CHECK-NEXT: 40: 4c 8b 1d 11 01 00 00 movq 273(%rip), %r11 | |
| 44 | 45 | // CHECK-NEXT: 47: e8 e4 ff ff ff callq -28 <.plt+0x20> |
| 45 | 46 | // CHECK-NEXT: 4c: e9 d1 ff ff ff jmp -47 <.plt+0x12> |
| 46 | 47 | // CHECK-NEXT: 51: 68 00 00 00 00 pushq $0 |
| ... | ... | @@ -50,7 +51,7 @@ |
| 50 | 51 | // CHECK-NEXT: 5d: cc int3 |
| 51 | 52 | // CHECK-NEXT: 5e: cc int3 |
| 52 | 53 | // CHECK-NEXT: 5f: cc int3 |
| 53 | // CHECK-NEXT: 60: 4c 8b 1d 39 00 00 00 movq 57(%rip), %r11 | |
| 54 | // CHECK-NEXT: 60: 4c 8b 1d f9 00 00 00 movq 249(%rip), %r11 | |
| 54 | 55 | // CHECK-NEXT: 67: e8 c4 ff ff ff callq -60 <.plt+0x20> |
| 55 | 56 | // CHECK-NEXT: 6c: e9 b1 ff ff ff jmp -79 <.plt+0x12> |
| 56 | 57 | // CHECK-NEXT: 71: 68 01 00 00 00 pushq $1 |
deps/lld/test/ELF/x86-64-retpoline-znow-linkerscript.s+1| ... | ... | @@ -13,6 +13,7 @@ |
| 13 | 13 | // RUN: llvm-objdump -d -s %t.exe | FileCheck %s |
| 14 | 14 | |
| 15 | 15 | // CHECK: Disassembly of section .plt: |
| 16 | // CHECK-EMPTY: | |
| 16 | 17 | // CHECK-NEXT: .plt: |
| 17 | 18 | // CHECK-NEXT: 10:	e8 0b 00 00 00 	callq	11 <.plt+0x10> |
| 18 | 19 | // CHECK-NEXT: 15:	f3 90 	pause |
deps/lld/test/ELF/x86-64-retpoline-znow.s+1| ... | ... | @@ -7,6 +7,7 @@ |
| 7 | 7 | // RUN: llvm-objdump -d -s %t.exe | FileCheck %s |
| 8 | 8 | |
| 9 | 9 | // CHECK: Disassembly of section .plt: |
| 10 | // CHECK-EMPTY: | |
| 10 | 11 | // CHECK-NEXT: .plt: |
| 11 | 12 | // CHECK-NEXT: 1010:	e8 0b 00 00 00 	callq	11 <.plt+0x10> |
| 12 | 13 | // CHECK-NEXT: 1015:	f3 90 	pause |
deps/lld/test/ELF/x86-64-retpoline.s+8-7| ... | ... | @@ -7,9 +7,10 @@ |
| 7 | 7 | // RUN: llvm-objdump -d -s %t.exe | FileCheck %s |
| 8 | 8 | |
| 9 | 9 | // CHECK: Disassembly of section .plt: |
| 10 | // CHECK-EMPTY: | |
| 10 | 11 | // CHECK-NEXT: .plt: |
| 11 | // CHECK-NEXT: 1010: ff 35 f2 0f 00 00 pushq 4082(%rip) | |
| 12 | // CHECK-NEXT: 1016: 4c 8b 1d f3 0f 00 00 movq 4083(%rip), %r11 | |
| 12 | // CHECK-NEXT: 1010: ff 35 f2 1f 00 00 pushq 8178(%rip) | |
| 13 | // CHECK-NEXT: 1016: 4c 8b 1d f3 1f 00 00 movq 8179(%rip), %r11 | |
| 13 | 14 | // CHECK-NEXT: 101d: e8 0e 00 00 00 callq 14 <.plt+0x20> |
| 14 | 15 | // CHECK-NEXT: 1022: f3 90 pause |
| 15 | 16 | // CHECK-NEXT: 1024: 0f ae e8 lfence |
| ... | ... | @@ -34,7 +35,7 @@ |
| 34 | 35 | // CHECK-NEXT: 103d: cc int3 |
| 35 | 36 | // CHECK-NEXT: 103e: cc int3 |
| 36 | 37 | // CHECK-NEXT: 103f: cc int3 |
| 37 | // CHECK-NEXT: 1040: 4c 8b 1d d1 0f 00 00 movq 4049(%rip), %r11 | |
| 38 | // CHECK-NEXT: 1040: 4c 8b 1d d1 1f 00 00 movq 8145(%rip), %r11 | |
| 38 | 39 | // CHECK-NEXT: 1047: e8 e4 ff ff ff callq -28 <.plt+0x20> |
| 39 | 40 | // CHECK-NEXT: 104c: e9 d1 ff ff ff jmp -47 <.plt+0x12> |
| 40 | 41 | // CHECK-NEXT: 1051: 68 00 00 00 00 pushq $0 |
| ... | ... | @@ -44,7 +45,7 @@ |
| 44 | 45 | // CHECK-NEXT: 105d: cc int3 |
| 45 | 46 | // CHECK-NEXT: 105e: cc int3 |
| 46 | 47 | // CHECK-NEXT: 105f: cc int3 |
| 47 | // CHECK-NEXT: 1060: 4c 8b 1d b9 0f 00 00 movq 4025(%rip), %r11 | |
| 48 | // CHECK-NEXT: 1060: 4c 8b 1d b9 1f 00 00 movq 8121(%rip), %r11 | |
| 48 | 49 | // CHECK-NEXT: 1067: e8 c4 ff ff ff callq -60 <.plt+0x20> |
| 49 | 50 | // CHECK-NEXT: 106c: e9 b1 ff ff ff jmp -79 <.plt+0x12> |
| 50 | 51 | // CHECK-NEXT: 1071: 68 01 00 00 00 pushq $1 |
| ... | ... | @@ -56,9 +57,9 @@ |
| 56 | 57 | // CHECK-NEXT: 107f: cc int3 |
| 57 | 58 | |
| 58 | 59 | // CHECK: Contents of section .got.plt: |
| 59 | // CHECK-NEXT: 2000 00300000 00000000 00000000 00000000 | |
| 60 | // CHECK-NEXT: 2010 00000000 00000000 51100000 00000000 | |
| 61 | // CHECK-NEXT: 2020 71100000 00000000 | |
| 60 | // CHECK-NEXT: 3000 00200000 00000000 00000000 00000000 | |
| 61 | // CHECK-NEXT: 3010 00000000 00000000 51100000 00000000 | |
| 62 | // CHECK-NEXT: 3020 71100000 00000000 | |
| 62 | 63 | |
| 63 | 64 | .global _start |
| 64 | 65 | _start: |
deps/lld/test/ELF/x86-64-static-tls-model.s created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | ||
| 3 | ## In this test R_X86_64_GOTTPOFF is a IE relocation (static TLS model), | |
| 4 | ## test check we add STATIC_TLS flag. | |
| 5 | ||
| 6 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 7 | # RUN: ld.lld %t.o -o %t1 -shared | |
| 8 | # RUN: llvm-readobj --dynamic-table %t1 | FileCheck %s | |
| 9 | ||
| 10 | # CHECK: DynamicSection [ | |
| 11 | # CHECK: FLAGS STATIC_TLS | |
| 12 | ||
| 13 | .section ".tdata", "awT", @progbits | |
| 14 | .globl var | |
| 15 | var: | |
| 16 | ||
| 17 | movq var@GOTTPOFF(%rip), %rax # R_X86_64_GOTTPOFF | |
| 18 | movl %fs:0(%rax), %eax |
deps/lld/test/ELF/x86-64-tls-gd-local.s+5-5| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux |
| 3 | 3 | // RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -r -s -section-data %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -r -S --section-data %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | .byte 0x66 |
| 7 | 7 | leaq foo@tlsgd(%rip), %rdi |
| ... | ... | @@ -34,8 +34,8 @@ bar: |
| 34 | 34 | // CHECK-NEXT: SHF_ALLOC (0x2) |
| 35 | 35 | // CHECK-NEXT: SHF_WRITE (0x1) |
| 36 | 36 | // CHECK-NEXT: ] |
| 37 | // CHECK-NEXT: Address: 0x30D0 | |
| 38 | // CHECK-NEXT: Offset: 0x30D0 | |
| 37 | // CHECK-NEXT: Address: 0x20D0 | |
| 38 | // CHECK-NEXT: Offset: 0x20D0 | |
| 39 | 39 | // CHECK-NEXT: Size: 32 |
| 40 | 40 | // CHECK-NEXT: Link: 0 |
| 41 | 41 | // CHECK-NEXT: Info: 0 |
| ... | ... | @@ -47,6 +47,6 @@ bar: |
| 47 | 47 | // CHECK-NEXT: ) |
| 48 | 48 | |
| 49 | 49 | // CHECK: Section ({{.*}}) .rela.dyn { |
| 50 | // CHECK-NEXT: 0x30D0 R_X86_64_DTPMOD64 - 0x0 | |
| 51 | // CHECK-NEXT: 0x30E0 R_X86_64_DTPMOD64 - 0x0 | |
| 50 | // CHECK-NEXT: 0x20D0 R_X86_64_DTPMOD64 - 0x0 | |
| 51 | // CHECK-NEXT: 0x20E0 R_X86_64_DTPMOD64 - 0x0 | |
| 52 | 52 | // CHECK-NEXT: } |
deps/lld/test/ELF/x86-64-tls-ld-local.s+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | // REQUIRES: x86 |
| 2 | 2 | // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux |
| 3 | 3 | // RUN: ld.lld %t.o -o %t.so -shared |
| 4 | // RUN: llvm-readobj -r -s %t.so | FileCheck %s | |
| 4 | // RUN: llvm-readobj -r -S %t.so | FileCheck %s | |
| 5 | 5 | |
| 6 | 6 | // CHECK: Relocations [ |
| 7 | 7 | // CHECK-NEXT: Section ({{.*}}) .rela.dyn { |
deps/lld/test/ELF/x86-64-tls-ld-preemptable.s created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -shared -o %t.so | |
| 4 | # RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck %s | |
| 5 | ||
| 6 | # CHECK: 100c: leaq (%rax), %rax | |
| 7 | # CHECK-NEXT: 1013: movabsq 0, %rax | |
| 8 | ||
| 9 | # We used to error on R_X86_64_DTPOFF{32,64} to preemptable symbols. | |
| 10 | # i is STB_GLOBAL and preemptable. | |
| 11 | leaq i@TLSLD(%rip), %rdi | |
| 12 | callq __tls_get_addr@PLT | |
| 13 | leaq i@DTPOFF(%rax), %rax # R_X86_64_DTPOFF32 | |
| 14 | movabsq i@DTPOFF, %rax # R_X86_64_DTPOFF64 | |
| 15 | ||
| 16 | .section .tbss,"awT",@nobits | |
| 17 | .globl i | |
| 18 | i: | |
| 19 | .long 0 | |
| 20 | .size i, 4 |
deps/lld/test/ELF/x86-64-tls-le-align.s created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | # RUN: ld.lld %t.o -o %t | |
| 4 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s | |
| 5 | ||
| 6 | # -alignTo(p_memsz, p_align) = -alignTo(4, 64) = -64 | |
| 7 | ||
| 8 | # CHECK: movl %fs:-64, %eax | |
| 9 | ||
| 10 | movl %fs:a@TPOFF, %eax | |
| 11 | ||
| 12 | .section .tbss,"awT" | |
| 13 | .align 64 | |
| 14 | a: | |
| 15 | .long 0 | |
| 16 | .size a, 4 |
deps/lld/test/ELF/x86-64-tls-le-undef.s created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | # RUN: ld.lld --noinhibit-exec %t.o -o %t 2>&1 | |
| 4 | # RUN: llvm-objdump -d %t | FileCheck %s | |
| 5 | ||
| 6 | ## Undefined TLS symbols resolve to 0. | |
| 7 | ## In --noinhibit-exec mode, a non-weak undefined symbol is not an error. | |
| 8 | ||
| 9 | # CHECK: leaq 16(%rax), %rdx | |
| 10 | # CHECK-NEXT: leaq 32(%rax), %rdx | |
| 11 | ||
| 12 | .weak weak | |
| 13 | movq %fs:0, %rax | |
| 14 | leaq weak@tpoff+16(%rax), %rdx | |
| 15 | leaq global@tpoff+32(%rax), %rdx |
deps/lld/test/ELF/x86-64-tlsdesc-gd.s created+69| ... | ... | @@ -0,0 +1,69 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | # RUN: echo '.tbss; .globl b; b:' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o | |
| 4 | # RUN: ld.lld -shared -soname=t1.so %t1.o -o %t1.so | |
| 5 | ||
| 6 | # RUN: ld.lld -shared %t.o %t1.o -o %t.so | |
| 7 | # RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=GD-REL %s | |
| 8 | # RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=GD %s | |
| 9 | ||
| 10 | # RUN: ld.lld %t.o %t1.o -o %t | |
| 11 | # RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s | |
| 12 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s | |
| 13 | ||
| 14 | # RUN: ld.lld %t.o %t1.so -o %t | |
| 15 | # RUN: llvm-readobj -r %t | FileCheck --check-prefix=IE-REL %s | |
| 16 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=IE %s | |
| 17 | ||
| 18 | # GD-REL: .rela.dyn { | |
| 19 | # GD-REL-NEXT: 0x20A0 R_X86_64_TLSDESC a 0x0 | |
| 20 | # GD-REL-NEXT: 0x20B0 R_X86_64_TLSDESC b 0x0 | |
| 21 | # GD-REL-NEXT: } | |
| 22 | ||
| 23 | # 0x20a0-0x1007 = 4249 | |
| 24 | # GD: leaq 4249(%rip), %rax | |
| 25 | # GD-NEXT: 1007: callq *(%rax) | |
| 26 | # GD-NEXT: movl %fs:(%rax), %eax | |
| 27 | ||
| 28 | # 0x20b0-0x1013 = 4253 | |
| 29 | # GD-NEXT: leaq 4253(%rip), %rax | |
| 30 | # GD-NEXT: 1013: callq *(%rax) | |
| 31 | # GD-NEXT: movl %fs:(%rax), %eax | |
| 32 | ||
| 33 | # NOREL: no relocations | |
| 34 | ||
| 35 | ## offset(a) = -4 | |
| 36 | # LE: movq $-4, %rax | |
| 37 | # LE-NEXT: nop | |
| 38 | # LE-NEXT: movl %fs:(%rax), %eax | |
| 39 | ## offset(b) = 0 | |
| 40 | # LE: movq $0, %rax | |
| 41 | # LE-NEXT: nop | |
| 42 | # LE-NEXT: movl %fs:(%rax), %eax | |
| 43 | ||
| 44 | # IE-REL: .rela.dyn { | |
| 45 | # IE-REL-NEXT: 0x2020C0 R_X86_64_TPOFF64 b 0x0 | |
| 46 | # IE-REL-NEXT: } | |
| 47 | ||
| 48 | ## a is relaxed to use LE. | |
| 49 | # IE: movq $-4, %rax | |
| 50 | # IE-NEXT: nop | |
| 51 | # IE-NEXT: movl %fs:(%rax), %eax | |
| 52 | ## 0x2020C0 - 0x201013 = 4269 | |
| 53 | # IE-NEXT: movq 4269(%rip), %rax | |
| 54 | # IE-NEXT: 201013: nop | |
| 55 | # IE-NEXT: movl %fs:(%rax), %eax | |
| 56 | ||
| 57 | leaq a@tlsdesc(%rip), %rax | |
| 58 | call *a@tlscall(%rax) | |
| 59 | movl %fs:(%rax), %eax | |
| 60 | ||
| 61 | leaq b@tlsdesc(%rip), %rax | |
| 62 | call *b@tlscall(%rax) | |
| 63 | movl %fs:(%rax), %eax | |
| 64 | ||
| 65 | .section .tbss | |
| 66 | .globl a | |
| 67 | .zero 8 | |
| 68 | a: | |
| 69 | .zero 4 |
deps/lld/test/ELF/x86-64-tlsdesc-ld.s created+45| ... | ... | @@ -0,0 +1,45 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o | |
| 3 | ||
| 4 | # RUN: ld.lld -shared %t.o -o %t.so | |
| 5 | # RUN: llvm-readobj -r %t.so | FileCheck --check-prefix=LD-REL %s | |
| 6 | # RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck --check-prefix=LD %s | |
| 7 | ||
| 8 | # RUN: ld.lld %t.o -o %t | |
| 9 | # RUN: llvm-readelf -r %t | FileCheck --check-prefix=NOREL %s | |
| 10 | # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=LE %s | |
| 11 | ||
| 12 | ## Check _TLS_MODULE_BASE_ used by LD produces a dynamic relocation with a value of 0. | |
| 13 | # LD-REL: .rela.dyn { | |
| 14 | # LD-REL-NEXT: 0x20A0 R_X86_64_TLSDESC - 0x0 | |
| 15 | # LD-REL-NEXT: } | |
| 16 | ||
| 17 | ## 0x20a0-0x1007 = 4249 | |
| 18 | ## dtpoff(a) = 8, dtpoff(b) = 12 | |
| 19 | # LD: leaq 4249(%rip), %rax | |
| 20 | # LD-NEXT: 1007: callq *(%rax) | |
| 21 | # LD-NEXT: movl %fs:8(%rax), %edx | |
| 22 | # LD-NEXT: addl %fs:12(%rax), %edx | |
| 23 | ||
| 24 | ## When producing an executable, the LD code sequence can be relaxed to LE. | |
| 25 | ## It is the same as GD->LE. | |
| 26 | ## tpoff(_TLS_MODULE_BASE_) = 0, tpoff(a) = -8, tpoff(b) = -4 | |
| 27 | ||
| 28 | # NOREL: no relocations | |
| 29 | ||
| 30 | # LE: movq $0, %rax | |
| 31 | # LE-NEXT: nop | |
| 32 | # LE-NEXT: movl %fs:-8(%rax), %edx | |
| 33 | # LE-NEXT: addl %fs:-4(%rax), %edx | |
| 34 | ||
| 35 | leaq _TLS_MODULE_BASE_@tlsdesc(%rip), %rax | |
| 36 | call *_TLS_MODULE_BASE_@tlscall(%rax) | |
| 37 | movl %fs:a@dtpoff(%rax), %edx | |
| 38 | addl %fs:b@dtpoff(%rax), %edx | |
| 39 | ||
| 40 | .section .tbss | |
| 41 | .zero 8 | |
| 42 | a: | |
| 43 | .zero 4 | |
| 44 | b: | |
| 45 | .zero 4 |
deps/lld/test/ELF/x86-property-relocatable.s created+36| ... | ... | @@ -0,0 +1,36 @@ |
| 1 | # REQUIRES: x86 | |
| 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o | |
| 3 | # RUN: ld.lld -r %t.o -o %t2.o | |
| 4 | # RUN: llvm-readelf -n %t2.o | FileCheck -match-full-lines %s | |
| 5 | ||
| 6 | ## Test that .note.gnu.property is passed through -r, and that we can handle | |
| 7 | ## more than one FEATURE_AND in the same object file. This is logically the | |
| 8 | ## same as if the features were combined in a single FEATURE_AND as the rule | |
| 9 | ## states that the bit in the output pr_data field if it is set in all | |
| 10 | .text | |
| 11 | ret | |
| 12 | ||
| 13 | .section ".note.gnu.property", "a" | |
| 14 | .p2align 3 | |
| 15 | .long 4 | |
| 16 | .long 0x10 | |
| 17 | .long 0x5 | |
| 18 | .asciz "GNU" | |
| 19 | ||
| 20 | .long 0xc0000002 // GNU_PROPERTY_X86_FEATURE_1_AND | |
| 21 | .long 4 | |
| 22 | .long 1 // GNU_PROPERTY_X86_FEATURE_1_IBT | |
| 23 | .long 0 | |
| 24 | ||
| 25 | .long 4 | |
| 26 | .long 0x10 | |
| 27 | .long 0x5 | |
| 28 | .asciz "GNU" | |
| 29 | .long 0xc0000002 // GNU_PROPERTY_X86_FEATURE_1_AND | |
| 30 | .long 4 | |
| 31 | .long 2 // GNU_PROPERTY_X86_FEATURE_1_SHSTK | |
| 32 | .long 0 | |
| 33 | ||
| 34 | # CHECK: Owner Data size	Description | |
| 35 | # CHECK-NEXT: GNU 0x00000010	NT_GNU_PROPERTY_TYPE_0 (property note) | |
| 36 | # CHECK-NEXT: Properties: x86 feature: IBT, SHSTK |
deps/lld/test/ELF/znotext-plt-relocations.s+2-1| ... | ... | @@ -16,5 +16,6 @@ |
| 16 | 16 | |
| 17 | 17 | .text |
| 18 | 18 | _start: |
| 19 | callq atexit | |
| 19 | .byte 0xe8 | |
| 20 | .long atexit - . - 4 | |
| 20 | 21 | .quad foo |
deps/lld/test/ELF/zstack-size.s+3-3| ... | ... | @@ -1,13 +1,13 @@ |
| 1 | 1 | # REQUIRES: x86 |
| 2 | 2 | # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t |
| 3 | 3 | # RUN: ld.lld -z stack-size=0x1000 %t -o %t1 |
| 4 | # RUN: llvm-readobj -program-headers %t1 | FileCheck %s -check-prefix=CHECK1 | |
| 4 | # RUN: llvm-readobj -l %t1 | FileCheck %s -check-prefix=CHECK1 | |
| 5 | 5 | |
| 6 | 6 | # RUN: ld.lld -z stack-size=0 %t -o %t2 |
| 7 | # RUN: llvm-readobj -program-headers %t2 | FileCheck %s -check-prefix=CHECK2 | |
| 7 | # RUN: llvm-readobj -l %t2 | FileCheck %s -check-prefix=CHECK2 | |
| 8 | 8 | |
| 9 | 9 | # RUN: ld.lld -z stack-size=0x2000 -z stack-size=0x1000 %t -o %t3 |
| 10 | # RUN: llvm-readobj -program-headers %t3 | FileCheck %s -check-prefix=CHECK1 | |
| 10 | # RUN: llvm-readobj -l %t3 | FileCheck %s -check-prefix=CHECK1 | |
| 11 | 11 | |
| 12 | 12 | .global _start |
| 13 | 13 | _start: |
deps/lld/test/ELF/ztext.s+3-3| ... | ... | @@ -4,11 +4,11 @@ |
| 4 | 4 | # RUN: ld.lld %t2.o -o %t2.so -shared |
| 5 | 5 | |
| 6 | 6 | # RUN: ld.lld -z notext %t.o %t2.so -o %t -shared |
| 7 | # RUN: llvm-readobj -dynamic-table -r %t | FileCheck %s | |
| 7 | # RUN: llvm-readobj --dynamic-table -r %t | FileCheck %s | |
| 8 | 8 | # RUN: ld.lld -z notext %t.o %t2.so -o %t2 -pie |
| 9 | # RUN: llvm-readobj -dynamic-table -r %t2 | FileCheck %s | |
| 9 | # RUN: llvm-readobj --dynamic-table -r %t2 | FileCheck %s | |
| 10 | 10 | # RUN: ld.lld -z notext %t.o %t2.so -o %t3 |
| 11 | # RUN: llvm-readobj -dynamic-table -r %t3 | FileCheck --check-prefix=STATIC %s | |
| 11 | # RUN: llvm-readobj --dynamic-table -r %t3 | FileCheck --check-prefix=STATIC %s | |
| 12 | 12 | |
| 13 | 13 | # RUN: not ld.lld %t.o %t2.so -o %t -shared 2>&1 | FileCheck --check-prefix=ERR %s |
| 14 | 14 | # RUN: not ld.lld -z text %t.o %t2.so -o %t -shared 2>&1 | FileCheck --check-prefix=ERR %s |
deps/lld/test/MinGW/driver.test+49| ... | ... | @@ -4,6 +4,9 @@ X86-SAME: -machine:x86 |
| 4 | 4 | X86-SAME: -alternatename:__image_base__=___ImageBase |
| 5 | 5 | X86-SAME: foo.o |
| 6 | 6 | |
| 7 | RUN: echo "-### foo.o -m i386pe" > %t.rsp | |
| 8 | RUN: ld.lld @%t.rsp | FileCheck -check-prefix=X86 %s | |
| 9 | ||
| 7 | 10 | RUN: ld.lld -### foo.o -m i386pep | FileCheck -check-prefix=X64 %s |
| 8 | 11 | X64: -out:a.exe |
| 9 | 12 | X64-SAME: -machine:x64 |
| ... | ... | @@ -54,8 +57,24 @@ MLLVM: -mllvm:bar -mllvm:baz |
| 54 | 57 | |
| 55 | 58 | RUN: ld.lld -### foo.o -m i386pep -subsystem console | FileCheck -check-prefix=SUBSYSTEM %s |
| 56 | 59 | RUN: ld.lld -### foo.o -m i386pep --subsystem console | FileCheck -check-prefix=SUBSYSTEM %s |
| 60 | RUN: ld.lld -### foo.o -m i386pep -subsystem=console | FileCheck -check-prefix=SUBSYSTEM %s | |
| 61 | RUN: ld.lld -### foo.o -m i386pep --subsystem=console | FileCheck -check-prefix=SUBSYSTEM %s | |
| 57 | 62 | SUBSYSTEM: -subsystem:console |
| 58 | 63 | |
| 64 | RUN: ld.lld -### foo.o -m i386pep --major-os-version 7 --minor-os-version 8 | FileCheck -check-prefix=SUBSYSTEM_VERSION %s | |
| 65 | RUN: ld.lld -### foo.o -m i386pep --major-subsystem-version 7 --minor-subsystem-version 8 | FileCheck -check-prefix=SUBSYSTEM_VERSION %s | |
| 66 | RUN: ld.lld -### foo.o -m i386pep --major-os-version=7 --minor-os-version=8 --major-subsystem-version=7 --minor-subsystem-version=8 | FileCheck -check-prefix=SUBSYSTEM_VERSION %s | |
| 67 | SUBSYSTEM_VERSION: -subsystem:default,7.8 | |
| 68 | ||
| 69 | RUN: ld.lld -### foo.o -m i386pep --minor-subsystem-version 8 | FileCheck -check-prefix=SUBSYSTEM_DEFAULT_MAJOR %s | |
| 70 | SUBSYSTEM_DEFAULT_MAJOR: -subsystem:default,6.8 | |
| 71 | ||
| 72 | RUN: ld.lld -### foo.o -m i386pep --major-subsystem-version 7 | FileCheck -check-prefix=SUBSYSTEM_DEFAULT_MINOR %s | |
| 73 | SUBSYSTEM_DEFAULT_MINOR: -subsystem:default,7 | |
| 74 | ||
| 75 | RUN: ld.lld -### foo.o -m i386pep --subsystem windows --major-os-version 7 --minor-os-version 8 | FileCheck -check-prefix=SUBSYSTEM_WINDOWS %s | |
| 76 | SUBSYSTEM_WINDOWS: -subsystem:windows,7.8 | |
| 77 | ||
| 59 | 78 | RUN: ld.lld -### foo.o -m i386pep -stack 4194304,8192 | FileCheck -check-prefix=STACK %s |
| 60 | 79 | RUN: ld.lld -### foo.o -m i386pep --stack 4194304,8192 | FileCheck -check-prefix=STACK %s |
| 61 | 80 | STACK: -stack:4194304,8192 |
| ... | ... | @@ -74,6 +93,9 @@ WHOLE-ARCHIVE: foo.o -wholearchive:bar.a baz.a |
| 74 | 93 | RUN: ld.lld -### -m i386pep foo.o | FileCheck -check-prefix MINGW-FLAG %s |
| 75 | 94 | MINGW-FLAG: -lldmingw |
| 76 | 95 | |
| 96 | RUN: ld.lld -### -m i386pep foo.o --exclude-all-symbols | FileCheck -check-prefix EXCLUDE-ALL %s | |
| 97 | EXCLUDE-ALL: -exclude-all-symbols | |
| 98 | ||
| 77 | 99 | RUN: ld.lld -### -m i386pep foo.o --export-all-symbols | FileCheck -check-prefix EXPORT-ALL %s |
| 78 | 100 | EXPORT-ALL: -export-all-symbols |
| 79 | 101 | |
| ... | ... | @@ -96,9 +118,14 @@ STRIP-DEBUG: -debug:symtab |
| 96 | 118 | STRIP-DEBUG-NOT: -debug:dwarf |
| 97 | 119 | |
| 98 | 120 | RUN: ld.lld -### -m i386pep foo.o -pdb out.pdb | FileCheck -check-prefix PDB %s |
| 121 | RUN: ld.lld -### -m i386pep foo.o -pdb=out.pdb | FileCheck -check-prefix PDB %s | |
| 99 | 122 | PDB: -debug -pdb:out.pdb |
| 100 | 123 | PDB-NOT: -debug:dwarf |
| 101 | 124 | |
| 125 | RUN: ld.lld -### -m i386pep foo.o -pdb= | FileCheck -check-prefix PDB-DEFAULT %s | |
| 126 | PDB-DEFAULT: -debug | |
| 127 | PDB-DEFAULT-NOT: -pdb:{{.*}} | |
| 128 | ||
| 102 | 129 | RUN: ld.lld -### -m i386pep foo.o --large-address-aware | FileCheck -check-prefix LARGE-ADDRESS-AWARE %s |
| 103 | 130 | LARGE-ADDRESS-AWARE: -largeaddressaware |
| 104 | 131 | |
| ... | ... | @@ -149,5 +176,27 @@ MAP: -lldmap:bar.map |
| 149 | 176 | RUN: ld.lld -### foo.o -m i386pe -require-defined _foo --require-defined _bar -require-defined=_baz --require-defined=_foo2 | FileCheck -check-prefix=REQUIRE-DEFINED %s |
| 150 | 177 | REQUIRE-DEFINED: -include:_foo -include:_bar -include:_baz -include:_foo2 |
| 151 | 178 | |
| 179 | RUN: ld.lld -### foo.o -m i386pe -u _foo --undefined _bar -undefined=_baz --undefined=_foo2 | FileCheck -check-prefix=UNDEFINED %s | |
| 180 | UNDEFINED: -includeoptional:_foo -includeoptional:_bar -includeoptional:_baz -includeoptional:_foo2 | |
| 181 | ||
| 152 | 182 | RUN: ld.lld -### -m i386pep foo.o -Llibpath | FileCheck -check-prefix LIBPATH %s |
| 153 | 183 | LIBPATH: -libpath:libpath |
| 184 | ||
| 185 | RUN: ld.lld -### -m i386pep foo.o --no-insert-timestamp | FileCheck -check-prefix NOTIMESTAMP %s | |
| 186 | RUN: ld.lld -### -m i386pep foo.o --insert-timestamp --no-insert-timestamp | FileCheck -check-prefix NOTIMESTAMP %s | |
| 187 | NOTIMESTAMP: -timestamp:0 | |
| 188 | RUN: ld.lld -### -m i386pep foo.o --no-insert-timestamp --insert-timestamp | FileCheck -check-prefix TIMESTAMP %s | |
| 189 | TIMESTAMP-NOT: -timestamp:0 | |
| 190 | ||
| 191 | RUN: ld.lld -### -m i386pep foo.o -appcontainer | FileCheck -check-prefix APPCONTAINER %s | |
| 192 | RUN: ld.lld -### -m i386pep foo.o --appcontainer | FileCheck -check-prefix APPCONTAINER %s | |
| 193 | APPCONTAINER: -appcontainer | |
| 194 | ||
| 195 | # RUN: ld.lld -m i386pep --version 2>&1 | FileCheck -check-prefix=VERSION %s | |
| 196 | # RUN: ld.lld -m i386pep -v 2>&1 | FileCheck -check-prefix=VERSION %s | |
| 197 | # RUN: not ld.lld -m i386pep -v xyz 2>&1 | FileCheck -check-prefix=VERSION %s | |
| 198 | # VERSION: LLD {{.*}} (compatible with GNU linkers) | |
| 199 | ||
| 200 | # RUN: ld.lld -m i386pep --help 2>&1 | FileCheck -check-prefix=HELP %s | |
| 201 | # HELP: USAGE: | |
| 202 | # HELP: --enable-auto-import |
deps/lld/test/lit.cfg.py+6-3| ... | ... | @@ -87,16 +87,19 @@ config.environment['LLD_IN_TEST'] = '1' |
| 87 | 87 | # Indirectly check if the mt.exe Microsoft utility exists by searching for |
| 88 | 88 | # cvtres, which always accompanies it. Alternatively, check if we can use |
| 89 | 89 | # libxml2 to merge manifests. |
| 90 | if (lit.util.which('cvtres', config.environment['PATH'])) or \ | |
| 91 | (config.llvm_libxml2_enabled == '1'): | |
| 90 | if (lit.util.which('cvtres', config.environment['PATH']) or | |
| 91 | config.llvm_libxml2_enabled): | |
| 92 | 92 | config.available_features.add('manifest_tool') |
| 93 | 93 | |
| 94 | if (config.llvm_libxml2_enabled == '1'): | |
| 94 | if config.llvm_libxml2_enabled: | |
| 95 | 95 | config.available_features.add('libxml2') |
| 96 | 96 | |
| 97 | 97 | if config.have_dia_sdk: |
| 98 | 98 | config.available_features.add("diasdk") |
| 99 | 99 | |
| 100 | if config.sizeof_void_p == 8: | |
| 101 | config.available_features.add("llvm-64-bits") | |
| 102 | ||
| 100 | 103 | tar_executable = lit.util.which('tar', config.environment['PATH']) |
| 101 | 104 | if tar_executable: |
| 102 | 105 | tar_version = subprocess.Popen( |
deps/lld/test/lit.site.cfg.py.in+2-1| ... | ... | @@ -7,7 +7,7 @@ config.llvm_src_root = "@LLVM_SOURCE_DIR@" |
| 7 | 7 | config.llvm_obj_root = "@LLVM_BINARY_DIR@" |
| 8 | 8 | config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" |
| 9 | 9 | config.llvm_libs_dir = "@LLVM_LIBS_DIR@" |
| 10 | config.llvm_libxml2_enabled = "@LLVM_LIBXML2_ENABLED@" | |
| 10 | config.llvm_libxml2_enabled = @LLVM_LIBXML2_ENABLED@ | |
| 11 | 11 | config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@" |
| 12 | 12 | config.lld_obj_root = "@LLD_BINARY_DIR@" |
| 13 | 13 | config.lld_libs_dir = "@LLVM_LIBRARY_OUTPUT_INTDIR@" |
| ... | ... | @@ -15,6 +15,7 @@ config.lld_tools_dir = "@LLVM_RUNTIME_OUTPUT_INTDIR@" |
| 15 | 15 | config.target_triple = "@TARGET_TRIPLE@" |
| 16 | 16 | config.python_executable = "@PYTHON_EXECUTABLE@" |
| 17 | 17 | config.have_zlib = @HAVE_LIBZ@ |
| 18 | config.sizeof_void_p = @CMAKE_SIZEOF_VOID_P@ | |
| 18 | 19 | |
| 19 | 20 | # Support substitution of the tools and libs dirs with user parameters. This is |
| 20 | 21 | # used when we can't determine the tool dir at configuration time. |
deps/lld/test/mach-o/arm-interworking.yaml+1-1| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # RUN: %p/Inputs/arm-interworking.yaml -o %t | FileCheck %s \ |
| 3 | 3 | # RUN: && ld64.lld -arch armv7 -dylib -print_atoms \ |
| 4 | 4 | # RUN: %p/Inputs/armv7/libSystem.yaml %t -o %t2 | FileCheck %s \ |
| 5 | # RUN: && llvm-readobj -s -sd %t2 | FileCheck -check-prefix=CODE %s | |
| 5 | # RUN: && llvm-readobj -S --section-data %t2 | FileCheck -check-prefix=CODE %s | |
| 6 | 6 | # |
| 7 | 7 | # Test thumb and arm branches round trip through -r. |
| 8 | 8 | # Test bl/blx instructions are fixed up properly. |
deps/lld/test/mach-o/arm-shims.yaml+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: ld64.lld -arch armv7 %s %p/Inputs/arm-shims.yaml \ |
| 2 | 2 | # RUN: -dylib %p/Inputs/armv7/libSystem.yaml -o %t |
| 3 | # RUN: llvm-readobj -s -sd %t | FileCheck %s | |
| 3 | # RUN: llvm-readobj -S --section-data %t | FileCheck %s | |
| 4 | 4 | # |
| 5 | 5 | # Test b from arm to thumb or vice versa has shims added.s |
| 6 | 6 | # |
deps/lld/test/mach-o/exe-offsets.yaml+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | # RUN: ld64.lld -arch x86_64 %s -o %t -e start %p/Inputs/x86_64/libSystem.yaml |
| 2 | # RUN: llvm-readobj -sections %t | FileCheck %s | |
| 2 | # RUN: llvm-readobj --sections %t | FileCheck %s | |
| 3 | 3 | |
| 4 | 4 | # Make sure data gets put at offset |
| 5 | 5 |
deps/lld/test/mach-o/exe-segment-overlap.yaml+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | # RUN: ld64.lld -arch x86_64 %s -o %t %p/Inputs/x86_64/libSystem.yaml |
| 2 | # RUN: llvm-readobj -sections -section-data %t | FileCheck %s | |
| 2 | # RUN: llvm-readobj --sections --section-data %t | FileCheck %s | |
| 3 | 3 | |
| 4 | 4 | --- !native |
| 5 | 5 | defined-atoms: |
deps/lld/test/mach-o/executable-exports.yaml+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 \ |
| 2 | 2 | # RUN: %s %p/Inputs/x86_64/libSystem.yaml -o %t && \ |
| 3 | # RUN: llvm-objdump -exports-trie %t | FileCheck %s | |
| 3 | # RUN: llvm-objdump -macho -exports-trie %t | FileCheck %s | |
| 4 | 4 | # |
| 5 | 5 | # |
| 6 | 6 | # Tests that exports trie builds properly. |
deps/lld/test/mach-o/export-trie-order.yaml+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | # RUN: ld64.lld -arch i386 %s %p/Inputs/hello-world-x86.yaml -o %t |
| 2 | # RUN: llvm-objdump -exports-trie %t | FileCheck %s | |
| 2 | # RUN: llvm-objdump -macho -exports-trie %t | FileCheck %s | |
| 3 | 3 | # |
| 4 | 4 | # Test that the export trie is emitted in order. |
| 5 | 5 | # |
deps/lld/test/mach-o/got-order.yaml+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: ld64.lld -arch x86_64 %s %p/Inputs/got-order.yaml \ |
| 2 | 2 | # RUN: %p/Inputs/got-order2.yaml -o %t %p/Inputs/x86_64/libSystem.yaml |
| 3 | # RUN: llvm-objdump -bind %t | FileCheck %s | |
| 3 | # RUN: llvm-objdump -macho -bind %t | FileCheck %s | |
| 4 | 4 | # |
| 5 | 5 | # Test that GOT slots are sorted by name |
| 6 | 6 | # |
deps/lld/test/mach-o/image-base.yaml+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | # RUN: ld64.lld -arch x86_64 -macosx_version_min 10.9 %s -o %t -image_base 31415926000 %p/Inputs/x86_64/libSystem.yaml |
| 2 | # RUN: llvm-readobj -macho-segment %t | FileCheck %s | |
| 2 | # RUN: llvm-readobj --macho-segment %t | FileCheck %s | |
| 3 | 3 | # RUN: not ld64.lld -arch x86_64 -image_base 0x31415926530 %s >/dev/null 2> %t |
| 4 | 4 | # RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-MISPAGED |
| 5 | 5 | # RUN: not ld64.lld -arch x86_64 -image_base 1000 %s >/dev/null 2> %t |
deps/lld/test/mach-o/lazy-bind-x86_64.yaml+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | # RUN: %p/Inputs/lazy-bind-x86_64.yaml %p/Inputs/lazy-bind-x86_64-2.yaml \ |
| 5 | 5 | # RUN: %p/Inputs/lazy-bind-x86_64-3.yaml -o %t \ |
| 6 | 6 | # RUN: %p/Inputs/x86_64/libSystem.yaml |
| 7 | # RUN: llvm-objdump -lazy-bind %t | FileCheck %s | |
| 7 | # RUN: llvm-objdump -macho -lazy-bind %t | FileCheck %s | |
| 8 | 8 | # RUN: llvm-nm -m %t | FileCheck --check-prefix=CHECK-NM %s |
| 9 | 9 | # RUN: llvm-objdump -disassemble %t | FileCheck --check-prefix=CHECK-HELPERS %s |
| 10 | 10 | # RUN: llvm-objdump -private-headers %t | FileCheck --check-prefix=CHECK-DYLIBS %s |
deps/lld/test/mach-o/load-commands-size.yaml created+305| ... | ... | @@ -0,0 +1,305 @@ |
| 1 | # RUN: ld64.lld -arch x86_64 %s -o %t -dylib \ | |
| 2 | # RUN: -macosx_version_min 10.10 -sdk_version 10.10 \ | |
| 3 | # RUN: -install_name /usr/lib/foo.dylib \ | |
| 4 | # RUN: %p/Inputs/x86_64/libSystem.yaml && \ | |
| 5 | # RUN: llvm-readobj %t | |
| 6 | ||
| 7 | # (Tests that lld doesn't crash or produce an invalid file.) | |
| 8 | ||
| 9 | --- !native | |
| 10 | path: '<linker-internal>' | |
| 11 | defined-atoms: | |
| 12 | - name: _foo | |
| 13 | scope: global | |
| 14 | type: unknown | |
| 15 | content: [ 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 16 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 17 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 18 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 19 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 20 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 21 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 22 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 23 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 24 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 25 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 26 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 27 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 28 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 29 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 30 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 31 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 32 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 33 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 34 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 35 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 36 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 37 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 38 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 39 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 40 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 41 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 42 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 43 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 44 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 45 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 46 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 47 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 48 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 49 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 50 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 51 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 52 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 53 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 54 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 55 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 56 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 57 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 58 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 59 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 60 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 61 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 62 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 63 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 64 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 65 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 66 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 67 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 68 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 69 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 70 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 71 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 72 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 73 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 74 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 75 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 76 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 77 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 78 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 79 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 80 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 81 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 82 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 83 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 84 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 85 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 86 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 87 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 88 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 89 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 90 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 91 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 92 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 93 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 94 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 95 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 96 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 97 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 98 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 99 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 100 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 101 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 102 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 103 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 104 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 105 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 106 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 107 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 108 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 109 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 110 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 111 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 112 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 113 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 114 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 115 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 116 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 117 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 118 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 119 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 120 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 121 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 122 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 123 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 124 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 125 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 126 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 127 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 128 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 129 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 130 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 131 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 132 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 133 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 134 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 135 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 136 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 137 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 138 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 139 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 140 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 141 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 142 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 143 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 144 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 145 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 146 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 147 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 148 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 149 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 150 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 151 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 152 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 153 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 154 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 155 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 156 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 157 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 158 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 159 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 160 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 161 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 162 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 163 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 164 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 165 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 166 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 167 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 168 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 169 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 170 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 171 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 172 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 173 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 174 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 175 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 176 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 177 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 178 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 179 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 180 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 181 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 182 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 183 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 184 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 185 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 186 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 187 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 188 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 189 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 190 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 191 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 192 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 193 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 194 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 195 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 196 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 197 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 198 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 199 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 200 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 201 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 202 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 203 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 204 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 205 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 206 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 207 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 208 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 209 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 210 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 211 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 212 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 213 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 214 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 215 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 216 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 217 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 218 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 219 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 220 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 221 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 222 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 223 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 224 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 225 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 226 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 227 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 228 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 229 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 230 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 231 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 232 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 233 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 234 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 235 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 236 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 237 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 238 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 239 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 240 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 241 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 242 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 243 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 244 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 245 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 246 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 247 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 248 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 249 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 250 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 251 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 252 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 253 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 254 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 255 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 256 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 257 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 258 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 259 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 260 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 261 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 262 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 263 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 264 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 265 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 266 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 267 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 268 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 269 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 270 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 271 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 272 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 273 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 274 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 275 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 276 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 277 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 278 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 279 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 280 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 281 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 282 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 283 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 284 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 285 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 286 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 287 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 288 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 289 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 290 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 291 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 292 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 293 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 294 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 295 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 296 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 297 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 298 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 299 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 300 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 301 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, | |
| 302 | 00, 00, 00, 00 ] | |
| 303 | alignment: 16 | |
| 304 | section-choice: custom-required | |
| 305 | section-name: '__TEXT/__foo' |
deps/lld/test/mach-o/sectalign.yaml+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | # RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -dylib \ |
| 2 | 2 | # RUN: -sectalign __DATA __custom 0x800 -sectalign __TEXT __text 0x400 \ |
| 3 | 3 | # RUN: %p/Inputs/x86_64/libSystem.yaml -o %t \ |
| 4 | # RUN: && llvm-readobj -sections %t | FileCheck %s | |
| 4 | # RUN: && llvm-readobj --sections %t | FileCheck %s | |
| 5 | 5 | # |
| 6 | 6 | # Test -sectalign option on __text and a custom section. |
| 7 | 7 | # |
deps/lld/test/mach-o/subsections-via-symbols-default.yaml+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | # RUN: ld64.lld -ios_simulator_version_min 5.0 -arch x86_64 -r %s -o %t |
| 2 | # RUN: llvm-readobj -file-headers %t | FileCheck %s | |
| 2 | # RUN: llvm-readobj --file-headers %t | FileCheck %s | |
| 3 | 3 | |
| 4 | 4 | # Make sure that we have an objc image info in the output. It should have |
| 5 | 5 | # been generated by the objc pass. |
deps/lld/test/mach-o/write-final-sections.yaml+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # RUN: ld64.lld -arch x86_64 %s %p/Inputs/write-final-sections.yaml \ |
| 2 | 2 | # RUN: -o %t -e _foo |
| 3 | # RUN: llvm-readobj -sections -section-data %t | FileCheck %s | |
| 3 | # RUN: llvm-readobj --sections --section-data %t | FileCheck %s | |
| 4 | 4 | |
| 5 | 5 | --- !native |
| 6 | 6 | defined-atoms: |
deps/lld/test/wasm/Inputs/call-ret32.ll created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | target triple = "wasm32-unknown-unknown" | |
| 2 | ||
| 3 | @ret32_address = global i32 (float)* @ret32, align 4 | |
| 4 | ||
| 5 | define hidden i32* @call_ret32() { | |
| 6 | entry: | |
| 7 | %call1 = call i32 @ret32(float 0.000000e+00) | |
| 8 | ret i32* bitcast (i32 (float)** @ret32_address to i32*) | |
| 9 | } | |
| 10 | ||
| 11 | declare i32 @ret32(float) |
deps/lld/test/wasm/Inputs/comdat1.ll+16-7| ... | ... | @@ -1,13 +1,22 @@ |
| 1 | 1 | target triple = "wasm32-unknown-unknown" |
| 2 | 2 | |
| 3 | $inlineFn = comdat any | |
| 4 | @constantData = weak_odr constant [3 x i8] c"abc", comdat($inlineFn) | |
| 5 | define linkonce_odr i32 @inlineFn() comdat { | |
| 6 | entry: | |
| 3 | $foo = comdat any | |
| 4 | ||
| 5 | @constantData = constant [3 x i8] c"abc", comdat($foo) | |
| 6 | ||
| 7 | define i32 @comdatFn() comdat($foo) { | |
| 7 | 8 | ret i32 ptrtoint ([3 x i8]* @constantData to i32) |
| 8 | 9 | } |
| 9 | 10 | |
| 10 | define i32 @callInline1() { | |
| 11 | entry: | |
| 12 | ret i32 ptrtoint (i32 ()* @inlineFn to i32) | |
| 11 | define internal void @do_init() comdat($foo) { | |
| 12 | ret void | |
| 13 | } | |
| 14 | ||
| 15 | %0 = type { i32, void ()*, i8* } | |
| 16 | @llvm.global_ctors = appending global [1 x %0 ] [%0 { i32 65535, void ()* @do_init, i8* null }] | |
| 17 | ||
| 18 | ; Everything above this is part of the `foo` comdat group | |
| 19 | ||
| 20 | define i32 @callComdatFn1() { | |
| 21 | ret i32 ptrtoint (i32 ()* @comdatFn to i32) | |
| 13 | 22 | } |
deps/lld/test/wasm/Inputs/comdat2.ll+16-7| ... | ... | @@ -1,13 +1,22 @@ |
| 1 | 1 | target triple = "wasm32-unknown-unknown" |
| 2 | 2 | |
| 3 | $inlineFn = comdat any | |
| 4 | @constantData = weak_odr constant [3 x i8] c"abc", comdat($inlineFn) | |
| 5 | define linkonce_odr i32 @inlineFn() comdat { | |
| 6 | entry: | |
| 3 | $foo = comdat any | |
| 4 | ||
| 5 | @constantData = constant [3 x i8] c"abc", comdat($foo) | |
| 6 | ||
| 7 | define i32 @comdatFn() comdat($foo) { | |
| 7 | 8 | ret i32 ptrtoint ([3 x i8]* @constantData to i32) |
| 8 | 9 | } |
| 9 | 10 | |
| 10 | define i32 @callInline2() { | |
| 11 | entry: | |
| 12 | ret i32 ptrtoint (i32 ()* @inlineFn to i32) | |
| 11 | define internal void @do_init() comdat($foo) { | |
| 12 | ret void | |
| 13 | } | |
| 14 | ||
| 15 | %0 = type { i32, void ()*, i8* } | |
| 16 | @llvm.global_ctors = appending global [1 x %0] [ %0 { i32 65535, void ()* @do_init, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @constantData, i32 0, i32 0) }] | |
| 17 | ||
| 18 | ; Everything above this is part of the `foo` comdat group | |
| 19 | ||
| 20 | define i32 @callComdatFn2() { | |
| 21 | ret i32 ptrtoint (i32 ()* @comdatFn to i32) | |
| 13 | 22 | } |
deps/lld/test/wasm/Inputs/disallow-feature-foo.yaml created+13| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | --- !WASM | |
| 2 | FileHeader: | |
| 3 | Version: 0x00000001 | |
| 4 | Sections: | |
| 5 | - Type: CUSTOM | |
| 6 | Name: linking | |
| 7 | Version: 2 | |
| 8 | - Type: CUSTOM | |
| 9 | Name: target_features | |
| 10 | Features: | |
| 11 | - Prefix: DISALLOWED | |
| 12 | Name: "foo" | |
| 13 | ... |
deps/lld/test/wasm/Inputs/explicit-section.ll created+4| ... | ... | @@ -0,0 +1,4 @@ |
| 1 | target triple = "wasm32-unknown-unknown" | |
| 2 | ||
| 3 | @var1 = global i32 42, section "mysection", align 4 | |
| 4 | @var2 = global i32 43, section "mysection", align 4 |
deps/lld/test/wasm/Inputs/globals.yaml+1-1| ... | ... | @@ -29,7 +29,7 @@ Sections: |
| 29 | 29 | Locals: |
| 30 | 30 | Body: 2381808080000B |
| 31 | 31 | Relocations: |
| 32 | - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB | |
| 32 | - Type: R_WASM_GLOBAL_INDEX_LEB | |
| 33 | 33 | Index: 1 |
| 34 | 34 | Offset: 0x00000004 |
| 35 | 35 | - Type: CUSTOM |
deps/lld/test/wasm/Inputs/no-feature-foo.yaml created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | --- !WASM | |
| 2 | FileHeader: | |
| 3 | Version: 0x00000001 | |
| 4 | Sections: | |
| 5 | - Type: CUSTOM | |
| 6 | Name: linking | |
| 7 | Version: 2 | |
| 8 | - Type: CUSTOM | |
| 9 | Name: target_features | |
| 10 | Features: [ ] | |
| 11 | ... |
deps/lld/test/wasm/Inputs/require-feature-foo.yaml created+13| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | --- !WASM | |
| 2 | FileHeader: | |
| 3 | Version: 0x00000001 | |
| 4 | Sections: | |
| 5 | - Type: CUSTOM | |
| 6 | Name: linking | |
| 7 | Version: 2 | |
| 8 | - Type: CUSTOM | |
| 9 | Name: target_features | |
| 10 | Features: | |
| 11 | - Prefix: REQUIRED | |
| 12 | Name: "foo" | |
| 13 | ... |
deps/lld/test/wasm/Inputs/undefined-globals.yaml+1-1| ... | ... | @@ -27,7 +27,7 @@ Sections: |
| 27 | 27 | Locals: |
| 28 | 28 | Body: 2381808080000B |
| 29 | 29 | Relocations: |
| 30 | - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB | |
| 30 | - Type: R_WASM_GLOBAL_INDEX_LEB | |
| 31 | 31 | Index: 1 |
| 32 | 32 | Offset: 0x00000004 |
| 33 | 33 | - Type: CUSTOM |
deps/lld/test/wasm/Inputs/use-feature-foo.yaml created+13| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | --- !WASM | |
| 2 | FileHeader: | |
| 3 | Version: 0x00000001 | |
| 4 | Sections: | |
| 5 | - Type: CUSTOM | |
| 6 | Name: linking | |
| 7 | Version: 2 | |
| 8 | - Type: CUSTOM | |
| 9 | Name: target_features | |
| 10 | Features: | |
| 11 | - Prefix: USED | |
| 12 | Name: "foo" | |
| 13 | ... |
deps/lld/test/wasm/alias.ll+3-26| ... | ... | @@ -22,7 +22,7 @@ entry: |
| 22 | 22 | ; CHECK-NEXT: ReturnType: NORESULT |
| 23 | 23 | ; CHECK-NEXT: ParamTypes: |
| 24 | 24 | ; CHECK-NEXT: - Type: FUNCTION |
| 25 | ; CHECK-NEXT: FunctionTypes: [ 0, 0 ] | |
| 25 | ; CHECK-NEXT: FunctionTypes: [ 0 ] | |
| 26 | 26 | ; CHECK-NEXT: - Type: TABLE |
| 27 | 27 | ; CHECK-NEXT: Tables: |
| 28 | 28 | ; CHECK-NEXT: - ElemType: FUNCREF |
| ... | ... | @@ -41,48 +41,25 @@ entry: |
| 41 | 41 | ; CHECK-NEXT: InitExpr: |
| 42 | 42 | ; CHECK-NEXT: Opcode: I32_CONST |
| 43 | 43 | ; CHECK-NEXT: Value: 66560 |
| 44 | ; CHECK-NEXT: - Index: 1 | |
| 45 | ; CHECK-NEXT: Type: I32 | |
| 46 | ; CHECK-NEXT: Mutable: false | |
| 47 | ; CHECK-NEXT: InitExpr: | |
| 48 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 49 | ; CHECK-NEXT: Value: 66560 | |
| 50 | ; CHECK-NEXT: - Index: 2 | |
| 51 | ; CHECK-NEXT: Type: I32 | |
| 52 | ; CHECK-NEXT: Mutable: false | |
| 53 | ; CHECK-NEXT: InitExpr: | |
| 54 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 55 | ; CHECK-NEXT: Value: 1024 | |
| 56 | 44 | ; CHECK-NEXT: - Type: EXPORT |
| 57 | 45 | ; CHECK-NEXT: Exports: |
| 58 | 46 | ; CHECK-NEXT: - Name: memory |
| 59 | 47 | ; CHECK-NEXT: Kind: MEMORY |
| 60 | 48 | ; CHECK-NEXT: Index: 0 |
| 61 | ; CHECK-NEXT: - Name: __heap_base | |
| 62 | ; CHECK-NEXT: Kind: GLOBAL | |
| 63 | ; CHECK-NEXT: Index: 1 | |
| 64 | ; CHECK-NEXT: - Name: __data_end | |
| 65 | ; CHECK-NEXT: Kind: GLOBAL | |
| 66 | ; CHECK-NEXT: Index: 2 | |
| 67 | 49 | ; CHECK-NEXT: - Name: _start |
| 68 | 50 | ; CHECK-NEXT: Kind: FUNCTION |
| 69 | ; CHECK-NEXT: Index: 1 | |
| 51 | ; CHECK-NEXT: Index: 0 | |
| 70 | 52 | ; CHECK-NEXT: - Name: start_alias |
| 71 | 53 | ; CHECK-NEXT: Kind: FUNCTION |
| 72 | ; CHECK-NEXT: Index: 1 | |
| 54 | ; CHECK-NEXT: Index: 0 | |
| 73 | 55 | ; CHECK-NEXT: - Type: CODE |
| 74 | 56 | ; CHECK-NEXT: Functions: |
| 75 | 57 | ; CHECK-NEXT: - Index: 0 |
| 76 | 58 | ; CHECK-NEXT: Locals: |
| 77 | 59 | ; CHECK-NEXT: Body: 0B |
| 78 | ; CHECK-NEXT: - Index: 1 | |
| 79 | ; CHECK-NEXT: Locals: | |
| 80 | ; CHECK-NEXT: Body: 0B | |
| 81 | 60 | ; CHECK-NEXT: - Type: CUSTOM |
| 82 | 61 | ; CHECK-NEXT: Name: name |
| 83 | 62 | ; CHECK-NEXT: FunctionNames: |
| 84 | 63 | ; CHECK-NEXT: - Index: 0 |
| 85 | ; CHECK-NEXT: Name: __wasm_call_ctors | |
| 86 | ; CHECK-NEXT: - Index: 1 | |
| 87 | 64 | ; CHECK-NEXT: Name: _start |
| 88 | 65 | ; CHECK-NEXT: ... |
deps/lld/test/wasm/archive-export.ll+5-17| ... | ... | @@ -14,37 +14,25 @@ CHECK: Exports: |
| 14 | 14 | CHECK-NEXT: - Name: memory |
| 15 | 15 | CHECK-NEXT: Kind: MEMORY |
| 16 | 16 | CHECK-NEXT: Index: 0 |
| 17 | CHECK-NEXT: - Name: __heap_base | |
| 18 | CHECK-NEXT: Kind: GLOBAL | |
| 19 | CHECK-NEXT: Index: 1 | |
| 20 | CHECK-NEXT: - Name: __data_end | |
| 21 | CHECK-NEXT: Kind: GLOBAL | |
| 22 | CHECK-NEXT: Index: 2 | |
| 23 | 17 | CHECK-NEXT: - Name: foo |
| 24 | 18 | CHECK-NEXT: Kind: FUNCTION |
| 25 | CHECK-NEXT: Index: 2 | |
| 19 | CHECK-NEXT: Index: 1 | |
| 26 | 20 | CHECK-NEXT: - Name: bar |
| 27 | 21 | CHECK-NEXT: Kind: FUNCTION |
| 28 | CHECK-NEXT: Index: 3 | |
| 22 | CHECK-NEXT: Index: 2 | |
| 29 | 23 | CHECK-NEXT: - Name: archive2_symbol |
| 30 | 24 | CHECK-NEXT: Kind: FUNCTION |
| 31 | CHECK-NEXT: Index: 4 | |
| 25 | CHECK-NEXT: Index: 3 | |
| 32 | 26 | CHECK-NEXT: - Name: _start |
| 33 | 27 | CHECK-NEXT: Kind: FUNCTION |
| 34 | CHECK-NEXT: Index: 1 | |
| 28 | CHECK-NEXT: Index: 0 | |
| 35 | 29 | CHECK-NEXT: - Type: CODE |
| 36 | 30 | |
| 37 | 31 | NOEXPORT: Exports: |
| 38 | 32 | NOEXPORT-NEXT: - Name: memory |
| 39 | 33 | NOEXPORT-NEXT: Kind: MEMORY |
| 40 | 34 | NOEXPORT-NEXT: Index: 0 |
| 41 | NOEXPORT-NEXT: - Name: __heap_base | |
| 42 | NOEXPORT-NEXT: Kind: GLOBAL | |
| 43 | NOEXPORT-NEXT: Index: 1 | |
| 44 | NOEXPORT-NEXT: - Name: __data_end | |
| 45 | NOEXPORT-NEXT: Kind: GLOBAL | |
| 46 | NOEXPORT-NEXT: Index: 2 | |
| 47 | 35 | NOEXPORT-NEXT: - Name: _start |
| 48 | 36 | NOEXPORT-NEXT: Kind: FUNCTION |
| 49 | NOEXPORT-NEXT: Index: 1 | |
| 37 | NOEXPORT-NEXT: Index: 0 | |
| 50 | 38 | NOEXPORT-NEXT: - Type: CODE |
deps/lld/test/wasm/archive-no-index.ll created+13| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | ; Tests error on archive file without a symbol table | |
| 2 | ; RUN: llvm-as -o %t.o %s | |
| 3 | ; RUN: llvm-as -o %t.archive.o %S/Inputs/archive1.ll | |
| 4 | ; RUN: rm -f %t.a | |
| 5 | ; RUN: llvm-ar crS %t.a %t.archive.o | |
| 6 | ||
| 7 | ; RUN: not wasm-ld -o out.wasm %t.o %t.a 2>&1 | FileCheck %s | |
| 8 | ||
| 9 | define i32 @_start() { | |
| 10 | ret i32 0 | |
| 11 | } | |
| 12 | ||
| 13 | ; CHECK: archive has no index; run ranlib to add one |
deps/lld/test/wasm/archive-weak-undefined.ll created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | ; RUN: llc -filetype=obj %s -o %t.o | |
| 2 | ; RUN: llc -filetype=obj %S/Inputs/ret32.ll -o %t.a1.o | |
| 3 | ; RUN: rm -f %t.a | |
| 4 | ; RUN: llvm-ar rcs %t.a %t.a1.o | |
| 5 | ; RUN: wasm-ld %t.o %t.a -o %t.wasm | |
| 6 | ; RUN: obj2yaml %t.wasm | FileCheck %s | |
| 7 | ||
| 8 | target triple = "wasm32-unknown-unknown" | |
| 9 | ||
| 10 | declare extern_weak i32 @ret32() | |
| 11 | ||
| 12 | define void @_start() { | |
| 13 | entry: | |
| 14 | %call1 = call i32 @ret32() | |
| 15 | ret void | |
| 16 | } | |
| 17 | ||
| 18 | ; CHECK: Name: 'undefined:ret32' | |
| 19 | ; CHECK-NOT: Name: ret32 |
deps/lld/test/wasm/archive.ll+5-3| ... | ... | @@ -33,10 +33,10 @@ entry: |
| 33 | 33 | ; TODO(ncw): Update LLD so that the symbol table is written out for |
| 34 | 34 | ; non-relocatable output (with an option to strip it) |
| 35 | 35 | |
| 36 | ; CHECK: 00000004 T _start | |
| 37 | ; CHECK-NEXT: 00000002 T archive2_symbol | |
| 36 | ; CHECK: 00000016 T _start | |
| 37 | ; CHECK-NEXT: 0000000a T archive2_symbol | |
| 38 | 38 | ; CHECK-NEXT: 00000001 T bar |
| 39 | ; CHECK-NEXT: 00000003 T foo | |
| 39 | ; CHECK-NEXT: 0000000d T foo | |
| 40 | 40 | ; CHECK-NEXT: U missing_func |
| 41 | 41 | |
| 42 | 42 | ; Verify that symbols from unused objects don't appear in the symbol table |
| ... | ... | @@ -47,6 +47,8 @@ entry: |
| 47 | 47 | |
| 48 | 48 | ; Verfiy errors include library name |
| 49 | 49 | ; RUN: not wasm-ld -u archive2_symbol -u archive3_symbol %t.a %t.o -o %t.wasm 2>&1 | FileCheck -check-prefix=CHECK-DUP %s |
| 50 | ; And that this also works with --whole-archive | |
| 51 | ; RUN: not wasm-ld -u archive2_symbol -u archive3_symbol --whole-archive %t.a %t.o -o %t.wasm 2>&1 | FileCheck -check-prefix=CHECK-DUP %s | |
| 50 | 52 | ; CHECK-DUP: error: duplicate symbol: bar |
| 51 | 53 | ; CHECK-DUP: >>> defined in {{.*}}.a({{.*}}.a2.o) |
| 52 | 54 | ; CHECK-DUP: >>> defined in {{.*}}.a({{.*}}.a3.o) |
deps/lld/test/wasm/call-indirect.ll+17-40| ... | ... | @@ -57,7 +57,7 @@ define void @call_ptr(i64 (i64)* %arg) { |
| 57 | 57 | ; CHECK-NEXT: ParamTypes: |
| 58 | 58 | ; CHECK-NEXT: - I32 |
| 59 | 59 | ; CHECK-NEXT: - Type: FUNCTION |
| 60 | ; CHECK-NEXT: FunctionTypes: [ 3, 0, 3, 1, 3, 4 ] | |
| 60 | ; CHECK-NEXT: FunctionTypes: [ 0, 3, 1, 3, 4 ] | |
| 61 | 61 | ; CHECK-NEXT: - Type: TABLE |
| 62 | 62 | ; CHECK-NEXT: Tables: |
| 63 | 63 | ; CHECK-NEXT: - ElemType: FUNCREF |
| ... | ... | @@ -81,80 +81,59 @@ define void @call_ptr(i64 (i64)* %arg) { |
| 81 | 81 | ; CHECK-NEXT: Mutable: false |
| 82 | 82 | ; CHECK-NEXT: InitExpr: |
| 83 | 83 | ; CHECK-NEXT: Opcode: I32_CONST |
| 84 | ; CHECK-NEXT: Value: 66576 | |
| 85 | ; CHECK-NEXT: - Index: 2 | |
| 86 | ; CHECK-NEXT: Type: I32 | |
| 87 | ; CHECK-NEXT: Mutable: false | |
| 88 | ; CHECK-NEXT: InitExpr: | |
| 89 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 90 | ; CHECK-NEXT: Value: 1036 | |
| 91 | ; CHECK-NEXT: - Index: 3 | |
| 92 | ; CHECK-NEXT: Type: I32 | |
| 93 | ; CHECK-NEXT: Mutable: false | |
| 94 | ; CHECK-NEXT: InitExpr: | |
| 95 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 96 | 84 | ; CHECK-NEXT: Value: 1032 |
| 97 | 85 | ; CHECK-NEXT: - Type: EXPORT |
| 98 | 86 | ; CHECK-NEXT: Exports: |
| 99 | 87 | ; CHECK-NEXT: - Name: memory |
| 100 | 88 | ; CHECK-NEXT: Kind: MEMORY |
| 101 | 89 | ; CHECK-NEXT: Index: 0 |
| 102 | ; CHECK-NEXT: - Name: __heap_base | |
| 103 | ; CHECK-NEXT: Kind: GLOBAL | |
| 104 | ; CHECK-NEXT: Index: 1 | |
| 105 | ; CHECK-NEXT: - Name: __data_end | |
| 106 | ; CHECK-NEXT: Kind: GLOBAL | |
| 107 | ; CHECK-NEXT: Index: 2 | |
| 108 | 90 | ; CHECK-NEXT: - Name: bar |
| 109 | 91 | ; CHECK-NEXT: Kind: FUNCTION |
| 110 | ; CHECK-NEXT: Index: 1 | |
| 92 | ; CHECK-NEXT: Index: 0 | |
| 111 | 93 | ; CHECK-NEXT: - Name: call_bar_indirect |
| 112 | 94 | ; CHECK-NEXT: Kind: FUNCTION |
| 113 | ; CHECK-NEXT: Index: 2 | |
| 95 | ; CHECK-NEXT: Index: 1 | |
| 114 | 96 | ; CHECK-NEXT: - Name: foo |
| 115 | 97 | ; CHECK-NEXT: Kind: FUNCTION |
| 116 | ; CHECK-NEXT: Index: 3 | |
| 98 | ; CHECK-NEXT: Index: 2 | |
| 117 | 99 | ; CHECK-NEXT: - Name: _start |
| 118 | 100 | ; CHECK-NEXT: Kind: FUNCTION |
| 119 | ; CHECK-NEXT: Index: 4 | |
| 101 | ; CHECK-NEXT: Index: 3 | |
| 120 | 102 | ; CHECK-NEXT: - Name: indirect_func |
| 121 | 103 | ; CHECK-NEXT: Kind: GLOBAL |
| 122 | ; CHECK-NEXT: Index: 3 | |
| 104 | ; CHECK-NEXT: Index: 1 | |
| 123 | 105 | ; CHECK-NEXT: - Name: call_ptr |
| 124 | 106 | ; CHECK-NEXT: Kind: FUNCTION |
| 125 | ; CHECK-NEXT: Index: 5 | |
| 107 | ; CHECK-NEXT: Index: 4 | |
| 126 | 108 | ; CHECK-NEXT: - Type: ELEM |
| 127 | 109 | ; CHECK-NEXT: Segments: |
| 128 | 110 | ; CHECK-NEXT: - Offset: |
| 129 | 111 | ; CHECK-NEXT: Opcode: I32_CONST |
| 130 | 112 | ; CHECK-NEXT: Value: 1 |
| 131 | ; CHECK-NEXT: Functions: [ 1, 3 ] | |
| 113 | ; CHECK-NEXT: Functions: [ 0, 2 ] | |
| 132 | 114 | ; CHECK-NEXT: - Type: CODE |
| 133 | 115 | ; CHECK-NEXT: Functions: |
| 134 | 116 | ; CHECK-NEXT: - Index: 0 |
| 135 | 117 | ; CHECK-NEXT: Locals: |
| 136 | ; CHECK-NEXT: Body: 0B | |
| 137 | ; CHECK-NEXT: - Index: 1 | |
| 138 | ; CHECK-NEXT: Locals: | |
| 139 | 118 | ; CHECK-NEXT: Body: 42010B |
| 140 | ; CHECK-NEXT: - Index: 2 | |
| 119 | ; CHECK-NEXT: - Index: 1 | |
| 141 | 120 | ; CHECK-NEXT: Locals: |
| 142 | 121 | ; CHECK-NEXT: - Type: I32 |
| 143 | 122 | ; CHECK-NEXT: Count: 1 |
| 144 | 123 | ; CHECK-NEXT: Body: 4100280284888080002100410028028088808000118080808000001A2000118180808000001A0B |
| 145 | ; CHECK-NEXT: - Index: 3 | |
| 124 | ; CHECK-NEXT: - Index: 2 | |
| 146 | 125 | ; CHECK-NEXT: Locals: |
| 147 | 126 | ; CHECK-NEXT: Body: 41020B |
| 148 | ; CHECK-NEXT: - Index: 4 | |
| 127 | ; CHECK-NEXT: - Index: 3 | |
| 149 | 128 | ; CHECK-NEXT: Locals: |
| 150 | 129 | ; CHECK-NEXT: Body: 410028028888808000118180808000001A0B |
| 151 | ; CHECK-NEXT: - Index: 5 | |
| 130 | ; CHECK-NEXT: - Index: 4 | |
| 152 | 131 | ; CHECK-NEXT: Locals: |
| 153 | 132 | ; CHECK-NEXT: Body: 42012000118280808000001A0B |
| 154 | 133 | ; CHECK-NEXT: - Type: DATA |
| 155 | 134 | ; CHECK-NEXT: Segments: |
| 156 | 135 | ; CHECK-NEXT: - SectionOffset: 7 |
| 157 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 136 | ; CHECK-NEXT: InitFlags: 0 | |
| 158 | 137 | ; CHECK-NEXT: Offset: |
| 159 | 138 | ; CHECK-NEXT: Opcode: I32_CONST |
| 160 | 139 | ; CHECK-NEXT: Value: 1024 |
| ... | ... | @@ -163,15 +142,13 @@ define void @call_ptr(i64 (i64)* %arg) { |
| 163 | 142 | ; CHECK-NEXT: Name: name |
| 164 | 143 | ; CHECK-NEXT: FunctionNames: |
| 165 | 144 | ; CHECK-NEXT: - Index: 0 |
| 166 | ; CHECK-NEXT: Name: __wasm_call_ctors | |
| 167 | ; CHECK-NEXT: - Index: 1 | |
| 168 | 145 | ; CHECK-NEXT: Name: bar |
| 169 | ; CHECK-NEXT: - Index: 2 | |
| 146 | ; CHECK-NEXT: - Index: 1 | |
| 170 | 147 | ; CHECK-NEXT: Name: call_bar_indirect |
| 171 | ; CHECK-NEXT: - Index: 3 | |
| 148 | ; CHECK-NEXT: - Index: 2 | |
| 172 | 149 | ; CHECK-NEXT: Name: foo |
| 173 | ; CHECK-NEXT: - Index: 4 | |
| 150 | ; CHECK-NEXT: - Index: 3 | |
| 174 | 151 | ; CHECK-NEXT: Name: _start |
| 175 | ; CHECK-NEXT: - Index: 5 | |
| 152 | ; CHECK-NEXT: - Index: 4 | |
| 176 | 153 | ; CHECK-NEXT: Name: call_ptr |
| 177 | 154 | ; CHECK-NEXT: ... |
deps/lld/test/wasm/comdats.ll+18-31| ... | ... | @@ -6,11 +6,13 @@ |
| 6 | 6 | |
| 7 | 7 | target triple = "wasm32-unknown-unknown" |
| 8 | 8 | |
| 9 | declare i32 @inlineFn() | |
| 9 | declare void @__wasm_call_ctors() | |
| 10 | declare i32 @comdatFn() | |
| 10 | 11 | |
| 11 | define void @_start() local_unnamed_addr { | |
| 12 | define void @_start() { | |
| 12 | 13 | entry: |
| 13 | %call = call i32 @inlineFn() | |
| 14 | call void @__wasm_call_ctors() | |
| 15 | %call = call i32 @comdatFn() | |
| 14 | 16 | ret void |
| 15 | 17 | } |
| 16 | 18 | |
| ... | ... | @@ -27,45 +29,27 @@ entry: |
| 27 | 29 | ; CHECK-NEXT: Mutable: false |
| 28 | 30 | ; CHECK-NEXT: InitExpr: |
| 29 | 31 | ; CHECK-NEXT: Opcode: I32_CONST |
| 30 | ; CHECK-NEXT: Value: 66576 | |
| 31 | ; CHECK-NEXT: - Index: 2 | |
| 32 | ; CHECK-NEXT: Type: I32 | |
| 33 | ; CHECK-NEXT: Mutable: false | |
| 34 | ; CHECK-NEXT: InitExpr: | |
| 35 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 36 | ; CHECK-NEXT: Value: 1027 | |
| 37 | ; CHECK-NEXT: - Index: 3 | |
| 38 | ; CHECK-NEXT: Type: I32 | |
| 39 | ; CHECK-NEXT: Mutable: false | |
| 40 | ; CHECK-NEXT: InitExpr: | |
| 41 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 42 | 32 | ; CHECK-NEXT: Value: 1024 |
| 43 | 33 | ; CHECK-NEXT: - Type: EXPORT |
| 44 | 34 | ; CHECK-NEXT: Exports: |
| 45 | 35 | ; CHECK-NEXT: - Name: memory |
| 46 | 36 | ; CHECK-NEXT: Kind: MEMORY |
| 47 | 37 | ; CHECK-NEXT: Index: 0 |
| 48 | ; CHECK-NEXT: - Name: __heap_base | |
| 49 | ; CHECK-NEXT: Kind: GLOBAL | |
| 50 | ; CHECK-NEXT: Index: 1 | |
| 51 | ; CHECK-NEXT: - Name: __data_end | |
| 52 | ; CHECK-NEXT: Kind: GLOBAL | |
| 53 | ; CHECK-NEXT: Index: 2 | |
| 54 | 38 | ; CHECK-NEXT: - Name: _start |
| 55 | 39 | ; CHECK-NEXT: Kind: FUNCTION |
| 56 | 40 | ; CHECK-NEXT: Index: 1 |
| 57 | ; CHECK-NEXT: - Name: inlineFn | |
| 41 | ; CHECK-NEXT: - Name: comdatFn | |
| 58 | 42 | ; CHECK-NEXT: Kind: FUNCTION |
| 59 | 43 | ; CHECK-NEXT: Index: 2 |
| 60 | 44 | ; CHECK-NEXT: - Name: constantData |
| 61 | 45 | ; CHECK-NEXT: Kind: GLOBAL |
| 62 | ; CHECK-NEXT: Index: 3 | |
| 63 | ; CHECK-NEXT: - Name: callInline1 | |
| 64 | ; CHECK-NEXT: Kind: FUNCTION | |
| 65 | ; CHECK-NEXT: Index: 3 | |
| 66 | ; CHECK-NEXT: - Name: callInline2 | |
| 46 | ; CHECK-NEXT: Index: 1 | |
| 47 | ; CHECK-NEXT: - Name: callComdatFn1 | |
| 67 | 48 | ; CHECK-NEXT: Kind: FUNCTION |
| 68 | 49 | ; CHECK-NEXT: Index: 4 |
| 50 | ; CHECK-NEXT: - Name: callComdatFn2 | |
| 51 | ; CHECK-NEXT: Kind: FUNCTION | |
| 52 | ; CHECK-NEXT: Index: 5 | |
| 69 | 53 | ; CHECK-NEXT: - Type: ELEM |
| 70 | 54 | ; CHECK-NEXT: Segments: |
| 71 | 55 | ; CHECK-NEXT: - Offset: |
| ... | ... | @@ -76,23 +60,26 @@ entry: |
| 76 | 60 | ; CHECK-NEXT: Functions: |
| 77 | 61 | ; CHECK-NEXT: - Index: 0 |
| 78 | 62 | ; CHECK-NEXT: Locals: |
| 79 | ; CHECK-NEXT: Body: 0B | |
| 63 | ; CHECK-NEXT: Body: 10030B | |
| 80 | 64 | ; CHECK-NEXT: - Index: 1 |
| 81 | 65 | ; CHECK-NEXT: Locals: |
| 82 | ; CHECK-NEXT: Body: 1082808080001A0B | |
| 66 | ; CHECK-NEXT: Body: 1080808080001082808080001A0B | |
| 83 | 67 | ; CHECK-NEXT: - Index: 2 |
| 84 | 68 | ; CHECK-NEXT: Locals: |
| 85 | 69 | ; CHECK-NEXT: Body: 4180888080000B |
| 86 | 70 | ; CHECK-NEXT: - Index: 3 |
| 87 | 71 | ; CHECK-NEXT: Locals: |
| 88 | ; CHECK-NEXT: Body: 4181808080000B | |
| 72 | ; CHECK-NEXT: Body: 0B | |
| 89 | 73 | ; CHECK-NEXT: - Index: 4 |
| 90 | 74 | ; CHECK-NEXT: Locals: |
| 91 | 75 | ; CHECK-NEXT: Body: 4181808080000B |
| 76 | ; CHECK-NEXT: - Index: 5 | |
| 77 | ; CHECK-NEXT: Locals: | |
| 78 | ; CHECK-NEXT: Body: 4181808080000B | |
| 92 | 79 | ; CHECK-NEXT: - Type: DATA |
| 93 | 80 | ; CHECK-NEXT: Segments: |
| 94 | 81 | ; CHECK-NEXT: - SectionOffset: 7 |
| 95 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 82 | ; CHECK-NEXT: InitFlags: 0 | |
| 96 | 83 | ; CHECK-NEXT: Offset: |
| 97 | 84 | ; CHECK-NEXT: Opcode: I32_CONST |
| 98 | 85 | ; CHECK-NEXT: Value: 1024 |
deps/lld/test/wasm/corrupted.wasm.test created| Binary files /dev/null and b/deps/lld/test/wasm/corrupted.wasm.test differ |
deps/lld/test/wasm/cxx-mangling.ll+8-19| ... | ... | @@ -26,43 +26,32 @@ define void @_start() { |
| 26 | 26 | ; CHECK-NEXT: - Name: memory |
| 27 | 27 | ; CHECK-NEXT: Kind: MEMORY |
| 28 | 28 | ; CHECK-NEXT: Index: 0 |
| 29 | ; CHECK-NEXT: - Name: __heap_base | |
| 30 | ; CHECK-NEXT: Kind: GLOBAL | |
| 31 | ; CHECK-NEXT: Index: 1 | |
| 32 | ; CHECK-NEXT: - Name: __data_end | |
| 33 | ; CHECK-NEXT: Kind: GLOBAL | |
| 34 | ; CHECK-NEXT: Index: 2 | |
| 35 | 29 | ; CHECK-NEXT: - Name: _Z3fooi |
| 36 | 30 | ; CHECK-NEXT: Kind: FUNCTION |
| 37 | ; CHECK-NEXT: Index: 2 | |
| 31 | ; CHECK-NEXT: Index: 1 | |
| 38 | 32 | ; CHECK-NEXT: - Name: _start |
| 39 | 33 | ; CHECK-NEXT: Kind: FUNCTION |
| 40 | ; CHECK-NEXT: Index: 3 | |
| 34 | ; CHECK-NEXT: Index: 2 | |
| 41 | 35 | ; CHECK-NEXT: - Type: CODE |
| 42 | 36 | ; CHECK-NEXT: Functions: |
| 43 | 37 | ; CHECK-NEXT: - Index: 0 |
| 44 | 38 | ; CHECK-NEXT: Locals: |
| 45 | ; CHECK-NEXT: Body: 0B | |
| 46 | ; CHECK-NEXT: - Index: 1 | |
| 47 | ; CHECK-NEXT: Locals: | |
| 48 | 39 | ; CHECK-NEXT: Body: 000B |
| 49 | ; CHECK-NEXT: - Index: 2 | |
| 40 | ; CHECK-NEXT: - Index: 1 | |
| 50 | 41 | ; CHECK-NEXT: Locals: |
| 51 | 42 | ; CHECK-NEXT: Body: 0B |
| 52 | ; CHECK-NEXT: - Index: 3 | |
| 43 | ; CHECK-NEXT: - Index: 2 | |
| 53 | 44 | ; CHECK-NEXT: Locals: |
| 54 | ; CHECK-NEXT: Body: 410110828080800041011081808080000B | |
| 45 | ; CHECK-NEXT: Body: 410110818080800041011080808080000B | |
| 55 | 46 | ; CHECK-NEXT: - Type: CUSTOM |
| 56 | 47 | ; CHECK-NEXT: Name: name |
| 57 | 48 | ; CHECK-NEXT: FunctionNames: |
| 58 | 49 | ; CHECK-NEXT: - Index: 0 |
| 59 | ; CHECK-NEXT: Name: __wasm_call_ctors | |
| 50 | ; DEMANGLE-NEXT: Name: 'undefined:bar(int)' | |
| 51 | ; MANGLE-NEXT: Name: 'undefined:_Z3bari' | |
| 60 | 52 | ; CHECK-NEXT: - Index: 1 |
| 61 | ; DEMANGLE-NEXT: Name: 'undefined function bar(int)' | |
| 62 | ; MANGLE-NEXT: Name: undefined function _Z3bari | |
| 63 | ; CHECK-NEXT: - Index: 2 | |
| 64 | 53 | ; DEMANGLE-NEXT: Name: 'foo(int)' |
| 65 | 54 | ; MANGLE-NEXT: Name: _Z3fooi |
| 66 | ; CHECK-NEXT: - Index: 3 | |
| 55 | ; CHECK-NEXT: - Index: 2 | |
| 67 | 56 | ; CHECK-NEXT: Name: _start |
| 68 | 57 | ; CHECK-NEXT: ... |
deps/lld/test/wasm/data-layout.ll+23-17| ... | ... | @@ -13,7 +13,7 @@ target triple = "wasm32-unknown-unknown" |
| 13 | 13 | @local_struct = hidden global %struct.s zeroinitializer, align 4 |
| 14 | 14 | @local_struct_internal_ptr = hidden local_unnamed_addr global i32* getelementptr inbounds (%struct.s, %struct.s* @local_struct, i32 0, i32 1), align 4 |
| 15 | 15 | |
| 16 | ; RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry -o %t.wasm %t.o %t.hello.o | |
| 16 | ; RUN: wasm-ld -no-gc-sections --export=__data_end --export=__heap_base --allow-undefined --no-entry -o %t.wasm %t.o %t.hello.o | |
| 17 | 17 | ; RUN: obj2yaml %t.wasm | FileCheck %s |
| 18 | 18 | |
| 19 | 19 | ; CHECK: - Type: MEMORY |
| ... | ... | @@ -32,25 +32,31 @@ target triple = "wasm32-unknown-unknown" |
| 32 | 32 | ; CHECK-NEXT: Mutable: false |
| 33 | 33 | ; CHECK-NEXT: InitExpr: |
| 34 | 34 | ; CHECK-NEXT: Opcode: I32_CONST |
| 35 | ; CHECK-NEXT: Value: 1071 | |
| 36 | ; CHECK-NEXT: - Index: 2 | |
| 37 | ; CHECK-NEXT: Type: I32 | |
| 38 | ; CHECK-NEXT: Mutable: false | |
| 39 | ; CHECK-NEXT: InitExpr: | |
| 40 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 35 | 41 | ; CHECK-NEXT: Value: 66608 |
| 36 | 42 | |
| 37 | ; CHECK: - Type: DATA | |
| 43 | ; CHECK: - Type: DATA | |
| 38 | 44 | ; CHECK-NEXT: Segments: |
| 39 | 45 | ; CHECK-NEXT: - SectionOffset: 7 |
| 40 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 46 | ; CHECK-NEXT: InitFlags: 0 | |
| 41 | 47 | ; CHECK-NEXT: Offset: |
| 42 | 48 | ; CHECK-NEXT: Opcode: I32_CONST |
| 43 | 49 | ; CHECK-NEXT: Value: 1024 |
| 44 | 50 | ; CHECK-NEXT: Content: '0100000000000000000000000000000003000000000000002804000024040000' |
| 45 | 51 | ; CHECK-NEXT: - SectionOffset: 45 |
| 46 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 52 | ; CHECK-NEXT: InitFlags: 0 | |
| 47 | 53 | ; CHECK-NEXT: Offset: |
| 48 | 54 | ; CHECK-NEXT: Opcode: I32_CONST |
| 49 | 55 | ; CHECK-NEXT: Value: 1056 |
| 50 | 56 | ; CHECK-NEXT: Content: '0000000000000000' |
| 51 | 57 | ; CHECK-NEXT: - SectionOffset: 59 |
| 52 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 53 | ; CHECK-NEXT: Offset: | |
| 58 | ; CHECK-NEXT: InitFlags: 0 | |
| 59 | ; CHECK-NEXT: Offset: | |
| 54 | 60 | ; CHECK-NEXT: Opcode: I32_CONST |
| 55 | 61 | ; CHECK-NEXT: Value: 1064 |
| 56 | 62 | ; CHECK-NEXT: Content: 68656C6C6F0A00 |
| ... | ... | @@ -70,7 +76,7 @@ target triple = "wasm32-unknown-unknown" |
| 70 | 76 | |
| 71 | 77 | ; RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry --shared-memory \ |
| 72 | 78 | ; RUN: --initial-memory=131072 --max-memory=131072 -o %t_max.wasm %t.o \ |
| 73 | ; RUN: %t.hello.o | |
| 79 | ; RUN: --active-segments %t.hello.o | |
| 74 | 80 | ; RUN: obj2yaml %t_max.wasm | FileCheck %s -check-prefix=CHECK-SHARED |
| 75 | 81 | |
| 76 | 82 | ; CHECK-SHARED: - Type: MEMORY |
| ... | ... | @@ -84,46 +90,46 @@ target triple = "wasm32-unknown-unknown" |
| 84 | 90 | |
| 85 | 91 | ; RELOC: - Type: DATA |
| 86 | 92 | ; RELOC-NEXT: Relocations: |
| 87 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32 | |
| 93 | ; RELOC-NEXT: - Type: R_WASM_MEMORY_ADDR_I32 | |
| 88 | 94 | ; RELOC-NEXT: Index: 3 |
| 89 | 95 | ; RELOC-NEXT: Offset: 0x00000018 |
| 90 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32 | |
| 96 | ; RELOC-NEXT: - Type: R_WASM_MEMORY_ADDR_I32 | |
| 91 | 97 | ; RELOC-NEXT: Index: 4 |
| 92 | 98 | ; RELOC-NEXT: Offset: 0x0000002E |
| 93 | 99 | ; RELOC-NEXT: Addend: 4 |
| 94 | 100 | ; RELOC-NEXT: Segments: |
| 95 | 101 | ; RELOC-NEXT: - SectionOffset: 6 |
| 96 | ; RELOC-NEXT: MemoryIndex: 0 | |
| 102 | ; RELOC-NEXT: InitFlags: 0 | |
| 97 | 103 | ; RELOC-NEXT: Offset: |
| 98 | 104 | ; RELOC-NEXT: Opcode: I32_CONST |
| 99 | 105 | ; RELOC-NEXT: Value: 0 |
| 100 | 106 | ; RELOC-NEXT: Content: '01000000' |
| 101 | 107 | ; RELOC-NEXT: - SectionOffset: 15 |
| 102 | ; RELOC-NEXT: MemoryIndex: 0 | |
| 108 | ; RELOC-NEXT: InitFlags: 0 | |
| 103 | 109 | ; RELOC-NEXT: Offset: |
| 104 | 110 | ; RELOC-NEXT: Opcode: I32_CONST |
| 105 | 111 | ; RELOC-NEXT: Value: 16 |
| 106 | 112 | ; RELOC-NEXT: Content: '03000000' |
| 107 | 113 | ; RELOC-NEXT: - SectionOffset: 24 |
| 108 | ; RELOC-NEXT: MemoryIndex: 0 | |
| 114 | ; RELOC-NEXT: InitFlags: 0 | |
| 109 | 115 | ; RELOC-NEXT: Offset: |
| 110 | 116 | ; RELOC-NEXT: Opcode: I32_CONST |
| 111 | 117 | ; RELOC-NEXT: Value: 24 |
| 112 | 118 | ; RELOC-NEXT: Content: '28000000' |
| 113 | 119 | ; RELOC-NEXT: - SectionOffset: 33 |
| 114 | ; RELOC-NEXT: MemoryIndex: 0 | |
| 115 | ; RELOC-NEXT: Offset: | |
| 120 | ; RELOC-NEXT: InitFlags: 0 | |
| 121 | ; RELOC-NEXT: Offset: | |
| 116 | 122 | ; RELOC-NEXT: Opcode: I32_CONST |
| 117 | 123 | ; RELOC-NEXT: Value: 28 |
| 118 | 124 | ; RELOC-NEXT: Content: '0000000000000000' |
| 119 | 125 | ; RELOC-NEXT: - SectionOffset: 46 |
| 120 | ; RELOC-NEXT: MemoryIndex: 0 | |
| 121 | ; RELOC-NEXT: Offset: | |
| 126 | ; RELOC-NEXT: InitFlags: 0 | |
| 127 | ; RELOC-NEXT: Offset: | |
| 122 | 128 | ; RELOC-NEXT: Opcode: I32_CONST |
| 123 | 129 | ; RELOC-NEXT: Value: 36 |
| 124 | 130 | ; RELOC-NEXT: Content: '20000000' |
| 125 | 131 | ; RELOC-NEXT: - SectionOffset: 55 |
| 126 | ; RELOC-NEXT: MemoryIndex: 0 | |
| 132 | ; RELOC-NEXT: InitFlags: 0 | |
| 127 | 133 | ; RELOC-NEXT: Offset: |
| 128 | 134 | ; RELOC-NEXT: Opcode: I32_CONST |
| 129 | 135 | ; RELOC-NEXT: Value: 40 |
deps/lld/test/wasm/data-segment-merging.ll+110-17| ... | ... | @@ -8,24 +8,117 @@ target triple = "wasm32-unknown-unknown" |
| 8 | 8 | @e = private constant [9 x i8] c"constant\00", align 1 |
| 9 | 9 | @f = private constant i8 43, align 4 |
| 10 | 10 | |
| 11 | ; RUN: llc -filetype=obj %s -o %t.data-segment-merging.o | |
| 11 | ; RUN: llc -mattr=+bulk-memory -filetype=obj %s -o %t.o | |
| 12 | 12 | |
| 13 | ; RUN: wasm-ld -no-gc-sections --no-entry -o %t.merged.wasm %t.data-segment-merging.o | |
| 13 | ; RUN: wasm-ld -no-gc-sections --no-entry -o %t.merged.wasm %t.o | |
| 14 | 14 | ; RUN: obj2yaml %t.merged.wasm | FileCheck %s --check-prefix=MERGE |
| 15 | ; MERGE: - Type: DATA | |
| 16 | ; MERGE: Segments: | |
| 17 | ; MERGE: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000 | |
| 18 | ; MERGE: Content: 636F6E7374616E74000000002B | |
| 19 | ; MERGE-NOT: Content: | |
| 20 | 15 | |
| 21 | ; RUN: wasm-ld -no-gc-sections --no-entry --no-merge-data-segments -o %t.separate.wasm %t.data-segment-merging.o | |
| 16 | ; MERGE-LABEL: - Type: DATA | |
| 17 | ; MERGE-NEXT: Segments: | |
| 18 | ; MERGE-NEXT: - SectionOffset: 7 | |
| 19 | ; MERGE-NEXT: InitFlags: 0 | |
| 20 | ; MERGE-NEXT: Offset: | |
| 21 | ; MERGE: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000 | |
| 22 | ; MERGE-NEXT: - SectionOffset: 41 | |
| 23 | ; MERGE-NEXT: InitFlags: 0 | |
| 24 | ; MERGE-NEXT: Offset: | |
| 25 | ; MERGE: Content: 636F6E7374616E74000000002B | |
| 26 | ; MERGE-NEXT: - Type: CUSTOM | |
| 27 | ; MERGE-NEXT: Name: name | |
| 28 | ; MERGE-NEXT: FunctionNames: | |
| 29 | ; MERGE-NEXT: - Index: 0 | |
| 30 | ; MERGE-NEXT: Name: __wasm_call_ctors | |
| 31 | ; MERGE-NOT: - Index: | |
| 32 | ||
| 33 | ; RUN: wasm-ld -no-gc-sections --no-entry --no-merge-data-segments -o %t.separate.wasm %t.o | |
| 22 | 34 | ; RUN: obj2yaml %t.separate.wasm | FileCheck %s --check-prefix=SEPARATE |
| 23 | ; SEPARATE: - Type: DATA | |
| 24 | ; SEPARATE: Segments: | |
| 25 | ; SEPARATE: Content: 68656C6C6F00 | |
| 26 | ; SEPARATE: Content: 676F6F6462796500 | |
| 27 | ; SEPARATE: Content: '776861746576657200' | |
| 28 | ; SEPARATE: Content: 2A000000 | |
| 29 | ; SEPARATE: Content: 636F6E7374616E7400 | |
| 30 | ; SEPARATE: Content: 2B | |
| 31 | ; SEPARATE-NOT: Content: | |
| 35 | ||
| 36 | ; SEPARATE-NOT: DATACOUNT | |
| 37 | ; SEPARATE-LABEL: - Type: DATA | |
| 38 | ; SEPARATE-NEXT: Segments: | |
| 39 | ; SEPARATE-NEXT: - SectionOffset: 7 | |
| 40 | ; SEPARATE-NEXT: InitFlags: 0 | |
| 41 | ; SEPARATE-NEXT: Offset: | |
| 42 | ; SEPARATE: Content: 68656C6C6F00 | |
| 43 | ; SEPARATE-NEXT: - SectionOffset: 19 | |
| 44 | ; SEPARATE-NEXT: InitFlags: 0 | |
| 45 | ; SEPARATE-NEXT: Offset: | |
| 46 | ; SEPARATE: Content: 676F6F6462796500 | |
| 47 | ; SEPARATE-NEXT: - SectionOffset: 33 | |
| 48 | ; SEPARATE-NEXT: InitFlags: 0 | |
| 49 | ; SEPARATE-NEXT: Offset: | |
| 50 | ; SEPARATE: Content: '776861746576657200' | |
| 51 | ; SEPARATE-NEXT: - SectionOffset: 48 | |
| 52 | ; SEPARATE-NEXT: InitFlags: 0 | |
| 53 | ; SEPARATE-NEXT: Offset: | |
| 54 | ; SEPARATE: Content: 2A000000 | |
| 55 | ; SEPARATE-NEXT: - SectionOffset: 58 | |
| 56 | ; SEPARATE-NEXT: InitFlags: 0 | |
| 57 | ; SEPARATE-NEXT: Offset: | |
| 58 | ; SEPARATE: Content: 636F6E7374616E7400 | |
| 59 | ; SEPARATE-NEXT: - SectionOffset: 73 | |
| 60 | ; SEPARATE-NEXT: InitFlags: 0 | |
| 61 | ; SEPARATE-NEXT: Offset: | |
| 62 | ; SEPARATE: Content: 2B | |
| 63 | ; SEPARATE-NEXT: - Type: CUSTOM | |
| 64 | ; SEPARATE-NEXT: Name: name | |
| 65 | ; SEPARATE-NEXT: FunctionNames: | |
| 66 | ; SEPARATE-NEXT: - Index: 0 | |
| 67 | ; SEPARATE-NEXT: Name: __wasm_call_ctors | |
| 68 | ; SEPARATE-NOT: - Index: | |
| 69 | ||
| 70 | ; RUN: wasm-ld -no-gc-sections --no-entry --passive-segments -o %t.merged.passive.wasm %t.o | |
| 71 | ; RUN: obj2yaml %t.merged.passive.wasm | FileCheck %s --check-prefix=PASSIVE-MERGE | |
| 72 | ||
| 73 | ; PASSIVE-MERGE-LABEL: - Type: DATACOUNT | |
| 74 | ; PASSIVE-MERGE-NEXT: Count: 2 | |
| 75 | ; PASSIVE-MERGE-LABEL: - Type: DATA | |
| 76 | ; PASSIVE-MERGE-NEXT: Segments: | |
| 77 | ; PASSIVE-MERGE-NEXT: - SectionOffset: 3 | |
| 78 | ; PASSIVE-MERGE-NEXT: InitFlags: 1 | |
| 79 | ; PASSIVE-MERGE-NEXT: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000 | |
| 80 | ; PASSIVE-MERGE-NEXT: - SectionOffset: 33 | |
| 81 | ; PASSIVE-MERGE-NEXT: InitFlags: 1 | |
| 82 | ; PASSIVE-MERGE-NEXT: Content: 636F6E7374616E74000000002B | |
| 83 | ; PASSIVE-MERGE-NEXT: - Type: CUSTOM | |
| 84 | ; PASSIVE-MERGE-NEXT: Name: name | |
| 85 | ; PASSIVE-MERGE-NEXT: FunctionNames: | |
| 86 | ; PASSIVE-MERGE-NEXT: - Index: 0 | |
| 87 | ; PASSIVE-MERGE-NEXT: Name: __wasm_call_ctors | |
| 88 | ; PASSIVE-MERGE-NEXT: - Index: 1 | |
| 89 | ; PASSIVE-MERGE-NEXT: Name: __wasm_init_memory | |
| 90 | ; PASSIVE-MERGE-NOT: - Index: | |
| 91 | ||
| 92 | ; RUN: wasm-ld -no-gc-sections --no-entry --passive-segments -no-merge-data-segments -o %t.separate.passive.wasm %t.o | |
| 93 | ; RUN: obj2yaml %t.separate.passive.wasm | FileCheck %s --check-prefix=PASSIVE-SEPARATE | |
| 94 | ||
| 95 | ; PASSIVE-SEPARATE-LABEL: - Type: DATACOUNT | |
| 96 | ; PASSIVE-SEPARATE-NEXT: Count: 6 | |
| 97 | ; PASSIVE-SEPARATE-LABEL: - Type: DATA | |
| 98 | ; PASSIVE-SEPARATE-NEXT: Segments: | |
| 99 | ; PASSIVE-SEPARATE-NEXT: - SectionOffset: 3 | |
| 100 | ; PASSIVE-SEPARATE-NEXT: InitFlags: 1 | |
| 101 | ; PASSIVE-SEPARATE-NEXT: Content: 68656C6C6F00 | |
| 102 | ; PASSIVE-SEPARATE-NEXT: - SectionOffset: 11 | |
| 103 | ; PASSIVE-SEPARATE-NEXT: InitFlags: 1 | |
| 104 | ; PASSIVE-SEPARATE-NEXT: Content: 676F6F6462796500 | |
| 105 | ; PASSIVE-SEPARATE-NEXT: - SectionOffset: 21 | |
| 106 | ; PASSIVE-SEPARATE-NEXT: InitFlags: 1 | |
| 107 | ; PASSIVE-SEPARATE-NEXT: Content: '776861746576657200' | |
| 108 | ; PASSIVE-SEPARATE-NEXT: - SectionOffset: 32 | |
| 109 | ; PASSIVE-SEPARATE-NEXT: InitFlags: 1 | |
| 110 | ; PASSIVE-SEPARATE-NEXT: Content: 2A000000 | |
| 111 | ; PASSIVE-SEPARATE-NEXT: - SectionOffset: 38 | |
| 112 | ; PASSIVE-SEPARATE-NEXT: InitFlags: 1 | |
| 113 | ; PASSIVE-SEPARATE-NEXT: Content: 636F6E7374616E7400 | |
| 114 | ; PASSIVE-SEPARATE-NEXT: - SectionOffset: 49 | |
| 115 | ; PASSIVE-SEPARATE-NEXT: InitFlags: 1 | |
| 116 | ; PASSIVE-SEPARATE-NEXT: Content: 2B | |
| 117 | ; PASSIVE-SEPARATE-NEXT: - Type: CUSTOM | |
| 118 | ; PASSIVE-SEPARATE-NEXT: Name: name | |
| 119 | ; PASSIVE-SEPARATE-NEXT: FunctionNames: | |
| 120 | ; PASSIVE-SEPARATE-NEXT: - Index: 0 | |
| 121 | ; PASSIVE-SEPARATE-NEXT: Name: __wasm_call_ctors | |
| 122 | ; PASSIVE-SEPARATE-NEXT: - Index: 1 | |
| 123 | ; PASSIVE-SEPARATE-NEXT: Name: __wasm_init_memory | |
| 124 | ; PASSIVE-SEPARATE-NOT: - Index |
deps/lld/test/wasm/data-segments.ll created+119| ... | ... | @@ -0,0 +1,119 @@ |
| 1 | ; RUN: llc -filetype=obj %s -o %t.atomics.o -mattr=+atomics | |
| 2 | ; RUN: llc -filetype=obj %s -o %t.bulk-mem.o -mattr=+bulk-memory | |
| 3 | ; RUN: llc -filetype=obj %s -o %t.atomics.bulk-mem.o -mattr=+atomics,+bulk-memory | |
| 4 | ||
| 5 | ; atomics => error | |
| 6 | ; RUN: not wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.o -o %t.atomics.wasm 2>&1 | FileCheck %s --check-prefix ERROR | |
| 7 | ||
| 8 | ; atomics, active segments => active segments | |
| 9 | ; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --active-segments %t.atomics.o -o %t.atomics.active.wasm | |
| 10 | ; RUN: obj2yaml %t.atomics.active.wasm | FileCheck %s --check-prefixes ACTIVE,ACTIVE-TLS | |
| 11 | ||
| 12 | ; atomics, passive segments => error | |
| 13 | ; RUN: not wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --passive-segments %t.atomics.o -o %t.atomics.passive.wasm 2>&1 | FileCheck %s --check-prefix ERROR | |
| 14 | ||
| 15 | ; bulk memory => active segments | |
| 16 | ; RUN: wasm-ld -no-gc-sections --no-entry %t.bulk-mem.o -o %t.bulk-mem.wasm | |
| 17 | ; RUN: obj2yaml %t.bulk-mem.wasm | FileCheck %s --check-prefix ACTIVE | |
| 18 | ||
| 19 | ; bulk-memory, active segments => active segments | |
| 20 | ; RUN: wasm-ld -no-gc-sections --no-entry --active-segments %t.bulk-mem.o -o %t.bulk-mem.active.wasm | |
| 21 | ; RUN: obj2yaml %t.bulk-mem.active.wasm | FileCheck %s --check-prefix ACTIVE | |
| 22 | ||
| 23 | ; bulk memory, passive segments => passive segments | |
| 24 | ; RUN: wasm-ld -no-gc-sections --no-entry --passive-segments %t.bulk-mem.o -o %t.bulk-mem.passive.wasm | |
| 25 | ; RUN: obj2yaml %t.bulk-mem.passive.wasm | FileCheck %s --check-prefix PASSIVE | |
| 26 | ||
| 27 | ; atomics, bulk memory => passive segments | |
| 28 | ; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.bulk-mem.o -o %t.atomics.bulk-mem.wasm | |
| 29 | ; RUN: obj2yaml %t.atomics.bulk-mem.wasm | FileCheck %s --check-prefixes PASSIVE,PASSIVE-TLS | |
| 30 | ||
| 31 | ; atomics, bulk memory, active segments => active segments | |
| 32 | ; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --active-segments %t.atomics.bulk-mem.o -o %t.atomics.bulk-mem.active.wasm | |
| 33 | ; RUN: obj2yaml %t.atomics.bulk-mem.active.wasm | FileCheck %s --check-prefixes ACTIVE,ACTIVE-TLS | |
| 34 | ||
| 35 | ; atomics, bulk memory, passive segments => passive segments | |
| 36 | ; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --passive-segments %t.atomics.bulk-mem.o -o %t.atomics.bulk-mem.passive.wasm | |
| 37 | ; RUN: obj2yaml %t.atomics.bulk-mem.passive.wasm | FileCheck %s --check-prefixes PASSIVE,PASSIVE-TLS | |
| 38 | ||
| 39 | target triple = "wasm32-unknown-unknown" | |
| 40 | ||
| 41 | @a = hidden global [6 x i8] c"hello\00", align 1 | |
| 42 | @b = hidden global [8 x i8] c"goodbye\00", align 1 | |
| 43 | @c = hidden global [10000 x i8] zeroinitializer, align 1 | |
| 44 | @d = hidden global i32 42, align 4 | |
| 45 | ||
| 46 | @e = private constant [9 x i8] c"constant\00", align 1 | |
| 47 | @f = private constant i8 43, align 4 | |
| 48 | ||
| 49 | ; ERROR: 'bulk-memory' feature must be used in order to emit passive segments | |
| 50 | ||
| 51 | ; ACTIVE-LABEL: - Type: CODE | |
| 52 | ; ACTIVE-NEXT: Functions: | |
| 53 | ; ACTIVE-NEXT: - Index: 0 | |
| 54 | ; ACTIVE-NEXT: Locals: [] | |
| 55 | ; ACTIVE-NEXT: Body: 0B | |
| 56 | ; ACTIVE-TLS-NEXT: - Index: 1 | |
| 57 | ; ACTIVE-TLS-NEXT: Locals: [] | |
| 58 | ; ACTIVE-TLS-NEXT: Body: 0B | |
| 59 | ; ACTIVE-NEXT: - Type: DATA | |
| 60 | ; ACTIVE-NEXT: Segments: | |
| 61 | ; ACTIVE-NEXT: - SectionOffset: 7 | |
| 62 | ; ACTIVE-NEXT: InitFlags: 0 | |
| 63 | ; ACTIVE-NEXT: Offset: | |
| 64 | ; ACTIVE-NEXT: Opcode: I32_CONST | |
| 65 | ; ACTIVE-NEXT: Value: 1024 | |
| 66 | ; ACTIVE-NEXT: Content: 68656C6C6F00676F6F646279650000002A000000 | |
| 67 | ; ACTIVE-NEXT: - SectionOffset: 34 | |
| 68 | ; ACTIVE-NEXT: InitFlags: 0 | |
| 69 | ; ACTIVE-NEXT: Offset: | |
| 70 | ; ACTIVE-NEXT: Opcode: I32_CONST | |
| 71 | ; ACTIVE-NEXT: Value: 1044 | |
| 72 | ; ACTIVE-NEXT: Content: '0000000000 | |
| 73 | ; ACTIVE-SAME: 0000000000' | |
| 74 | ; ACTIVE-NEXT: - SectionOffset: 10041 | |
| 75 | ; ACTIVE-NEXT: InitFlags: 0 | |
| 76 | ; ACTIVE-NEXT: Offset: | |
| 77 | ; ACTIVE-NEXT: Opcode: I32_CONST | |
| 78 | ; ACTIVE-NEXT: Value: 11044 | |
| 79 | ; ACTIVE-NEXT: Content: 636F6E7374616E74000000002B | |
| 80 | ; ACTIVE-NEXT: - Type: CUSTOM | |
| 81 | ; ACTIVE-NEXT: Name: name | |
| 82 | ; ACTIVE-NEXT: FunctionNames: | |
| 83 | ; ACTIVE-NEXT: - Index: 0 | |
| 84 | ; ACTIVE-NEXT: Name: __wasm_call_ctors | |
| 85 | ; ACTIVE-TLS-NEXT: - Index: 1 | |
| 86 | ; ACTIVE-TLS-NEXT: Name: __wasm_init_tls | |
| 87 | ||
| 88 | ; PASSIVE-LABEL: - Type: CODE | |
| 89 | ; PASSIVE-NEXT: Functions: | |
| 90 | ; PASSIVE-NEXT: - Index: 0 | |
| 91 | ; PASSIVE-NEXT: Locals: [] | |
| 92 | ; PASSIVE-NEXT: Body: 10010B | |
| 93 | ; PASSIVE-NEXT: - Index: 1 | |
| 94 | ; PASSIVE-NEXT: Locals: [] | |
| 95 | ; PASSIVE-NEXT: Body: 41800841004114FC080000FC090041940841004190CE00FC080100FC090141A4D6004100410DFC080200FC09020B | |
| 96 | ; PASSIVE-TLS-NEXT: - Index: 2 | |
| 97 | ; PASSIVE-TLS-NEXT: Locals: [] | |
| 98 | ; PASSIVE-TLS-NEXT: Body: 0B | |
| 99 | ; PASSIVE-NEXT: - Type: DATA | |
| 100 | ; PASSIVE-NEXT: Segments: | |
| 101 | ; PASSIVE-NEXT: - SectionOffset: 3 | |
| 102 | ; PASSIVE-NEXT: InitFlags: 1 | |
| 103 | ; PASSIVE-NEXT: Content: 68656C6C6F00676F6F646279650000002A000000 | |
| 104 | ; PASSIVE-NEXT: - SectionOffset: 26 | |
| 105 | ; PASSIVE-NEXT: InitFlags: 1 | |
| 106 | ; PASSIVE-NEXT: Content: '0000000000 | |
| 107 | ; PASSIVE-SAME: 0000000000' | |
| 108 | ; PASSIVE-NEXT: - SectionOffset: 10028 | |
| 109 | ; PASSIVE-NEXT: InitFlags: 1 | |
| 110 | ; PASSIVE-NEXT: Content: 636F6E7374616E74000000002B | |
| 111 | ; PASSIVE-NEXT: - Type: CUSTOM | |
| 112 | ; PASSIVE-NEXT: Name: name | |
| 113 | ; PASSIVE-NEXT: FunctionNames: | |
| 114 | ; PASSIVE-NEXT: - Index: 0 | |
| 115 | ; PASSIVE-NEXT: Name: __wasm_call_ctors | |
| 116 | ; PASSIVE-NEXT: - Index: 1 | |
| 117 | ; PASSIVE-NEXT: Name: __wasm_init_memory | |
| 118 | ; PASSIVE-TLS-NEXT: - Index: 2 | |
| 119 | ; PASSIVE-TLS-NEXT: Name: __wasm_init_tls |
deps/lld/test/wasm/emit-relocs-fpic.s created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | # RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -o %t.o < %s | |
| 2 | # RUN: llc --relocation-model=pic -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o | |
| 3 | # RUN: wasm-ld -pie --export-all --no-gc-sections --no-entry --emit-relocs -o %t.wasm %t.o %t.ret32.o | |
| 4 | # RUN: obj2yaml %t.wasm | FileCheck %s | |
| 5 | ||
| 6 | load_hidden_data: | |
| 7 | .functype load_hidden_data () -> (i32) | |
| 8 | i32.const .L.hidden_data@MBREL | |
| 9 | end_function | |
| 10 | ||
| 11 | .section .rodata.hidden_data,"",@ | |
| 12 | .L.hidden_data: | |
| 13 | .int8 100 | |
| 14 | .size .L.hidden_data, 1 | |
| 15 | ||
| 16 | # We just want to make sure that processing this relocation doesn't | |
| 17 | # cause corrupt output. We get most of the way there, by just checking | |
| 18 | # that obj2yaml doesn't fail. Here we just make sure that the relocation | |
| 19 | # survived the trip. | |
| 20 | # CHECK: R_WASM_MEMORY_ADDR_REL_SLEB |
deps/lld/test/wasm/emit-relocs.ll created+39| ... | ... | @@ -0,0 +1,39 @@ |
| 1 | ; RUN: llc -filetype=obj %s -o %t.o | |
| 2 | ; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o | |
| 3 | ; RUN: wasm-ld --emit-relocs -o %t.wasm %t.o %t.ret32.o | |
| 4 | ; RUN: obj2yaml %t.wasm | FileCheck %s | |
| 5 | ||
| 6 | target triple = "wasm32-unknown-unknown" | |
| 7 | ||
| 8 | declare i32 @ret32(float) | |
| 9 | ||
| 10 | define void @unused_function() { | |
| 11 | ret void | |
| 12 | } | |
| 13 | ||
| 14 | define hidden void @_start() local_unnamed_addr #0 { | |
| 15 | entry: | |
| 16 | call i32 @ret32(float 0.0) | |
| 17 | ret void | |
| 18 | } | |
| 19 | ||
| 20 | ; CHECK: - Type: CODE | |
| 21 | ; CHECK-NEXT: Relocations: | |
| 22 | ; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB | |
| 23 | ; CHECK-NEXT: Index: 1 | |
| 24 | ; CHECK-NEXT: Offset: 0x00000009 | |
| 25 | ||
| 26 | ; CHECK: - Type: CUSTOM | |
| 27 | ; CHECK-NEXT: Name: linking | |
| 28 | ; CHECK-NEXT: Version: 2 | |
| 29 | ; CHECK-NEXT: SymbolTable: | |
| 30 | ; CHECK-NEXT: - Index: 0 | |
| 31 | ; CHECK-NEXT: Kind: FUNCTION | |
| 32 | ; CHECK-NEXT: Name: _start | |
| 33 | ; CHECK-NEXT: Flags: [ ] | |
| 34 | ; CHECK-NEXT: Function: 0 | |
| 35 | ; CHECK-NEXT: - Index: 1 | |
| 36 | ; CHECK-NEXT: Kind: FUNCTION | |
| 37 | ; CHECK-NEXT: Name: ret32 | |
| 38 | ; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] | |
| 39 | ; CHECK-NEXT: Function: 1 |
deps/lld/test/wasm/entry.ll+1-13| ... | ... | @@ -17,15 +17,9 @@ entry: |
| 17 | 17 | ; CHECK-NEXT: - Name: memory |
| 18 | 18 | ; CHECK-NEXT: Kind: MEMORY |
| 19 | 19 | ; CHECK-NEXT: Index: 0 |
| 20 | ; CHECK-NEXT: - Name: __heap_base | |
| 21 | ; CHECK-NEXT: Kind: GLOBAL | |
| 22 | ; CHECK-NEXT: Index: 1 | |
| 23 | ; CHECK-NEXT: - Name: __data_end | |
| 24 | ; CHECK-NEXT: Kind: GLOBAL | |
| 25 | ; CHECK-NEXT: Index: 2 | |
| 26 | 20 | ; CHECK-NEXT: - Name: entry |
| 27 | 21 | ; CHECK-NEXT: Kind: FUNCTION |
| 28 | ; CHECK-NEXT: Index: 1 | |
| 22 | ; CHECK-NEXT: Index: 0 | |
| 29 | 23 | ; CHECK-NEXT: - Type: |
| 30 | 24 | |
| 31 | 25 | ; The __wasm_call_ctors is somewhat special since its created by the linker. |
| ... | ... | @@ -41,10 +35,4 @@ entry: |
| 41 | 35 | ; CHECK-CTOR-NEXT: - Name: __wasm_call_ctors |
| 42 | 36 | ; CHECK-CTOR-NEXT: Kind: FUNCTION |
| 43 | 37 | ; CHECK-CTOR-NEXT: Index: 0 |
| 44 | ; CHECK-CTOR-NEXT: - Name: __heap_base | |
| 45 | ; CHECK-CTOR-NEXT: Kind: GLOBAL | |
| 46 | ; CHECK-CTOR-NEXT: Index: 1 | |
| 47 | ; CHECK-CTOR-NEXT: - Name: __data_end | |
| 48 | ; CHECK-CTOR-NEXT: Kind: GLOBAL | |
| 49 | ; CHECK-CTOR-NEXT: Index: 2 | |
| 50 | 38 | ; CHECK-CTOR-NEXT: - Type: |
deps/lld/test/wasm/export.ll+21-6| ... | ... | @@ -3,13 +3,29 @@ |
| 3 | 3 | ; RUN: wasm-ld --export=hidden_function -o %t.wasm %t.o |
| 4 | 4 | ; RUN: obj2yaml %t.wasm | FileCheck %s |
| 5 | 5 | |
| 6 | @llvm.used = appending global [1 x i8*] [i8* bitcast (i32 ()* @used_function to i8*)], section "llvm.metadata" | |
| 7 | ||
| 6 | 8 | target triple = "wasm32-unknown-unknown" |
| 7 | 9 | |
| 10 | ; Not exported by default, but forced via commandline | |
| 8 | 11 | define hidden i32 @hidden_function() local_unnamed_addr { |
| 9 | 12 | entry: |
| 10 | 13 | ret i32 0 |
| 11 | 14 | } |
| 12 | 15 | |
| 16 | ; Not exported by default | |
| 17 | define i32 @default_function() local_unnamed_addr { | |
| 18 | entry: | |
| 19 | ret i32 0 | |
| 20 | } | |
| 21 | ||
| 22 | ; Exported because its part of llvm.used | |
| 23 | define i32 @used_function() local_unnamed_addr { | |
| 24 | entry: | |
| 25 | ret i32 0 | |
| 26 | } | |
| 27 | ||
| 28 | ; Exported by default | |
| 13 | 29 | define void @_start() local_unnamed_addr { |
| 14 | 30 | entry: |
| 15 | 31 | ret void |
| ... | ... | @@ -17,19 +33,18 @@ entry: |
| 17 | 33 | |
| 18 | 34 | ; CHECK-ERROR: error: symbol exported via --export not found: missing |
| 19 | 35 | |
| 36 | ; CHECK-NOT: - Name: default_function | |
| 37 | ||
| 20 | 38 | ; CHECK: - Type: EXPORT |
| 21 | 39 | ; CHECK-NEXT: Exports: |
| 22 | 40 | ; CHECK-NEXT: - Name: memory |
| 23 | 41 | ; CHECK-NEXT: Kind: MEMORY |
| 24 | 42 | ; CHECK-NEXT: Index: 0 |
| 25 | ; CHECK-NEXT: - Name: __heap_base | |
| 26 | ; CHECK-NEXT: Kind: GLOBAL | |
| 27 | ; CHECK-NEXT: Index: 1 | |
| 28 | ; CHECK-NEXT: - Name: __data_end | |
| 29 | ; CHECK-NEXT: Kind: GLOBAL | |
| 30 | ; CHECK-NEXT: Index: 2 | |
| 31 | 43 | ; CHECK-NEXT: - Name: hidden_function |
| 32 | 44 | ; CHECK-NEXT: Kind: FUNCTION |
| 45 | ; CHECK-NEXT: Index: 0 | |
| 46 | ; CHECK-NEXT: - Name: used_function | |
| 47 | ; CHECK-NEXT: Kind: FUNCTION | |
| 33 | 48 | ; CHECK-NEXT: Index: 1 |
| 34 | 49 | ; CHECK-NEXT: - Name: _start |
| 35 | 50 | ; CHECK-NEXT: Kind: FUNCTION |
deps/lld/test/wasm/fatal-warnings.ll+2-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | ; RUN: llc -filetype=obj %s -o %t.main.o |
| 2 | 2 | ; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o |
| 3 | ; RUN: lld -flavor wasm -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-WARN | |
| 4 | ; RUN: not lld -flavor wasm --fatal-warnings -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-FATAL | |
| 3 | ; RUN: wasm-ld -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-WARN | |
| 4 | ; RUN: not wasm-ld --fatal-warnings -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-FATAL | |
| 5 | 5 | |
| 6 | 6 | ; CHECK-WARN: warning: function signature mismatch: ret32 |
| 7 | 7 | ; CHECK-FATAL: error: function signature mismatch: ret32 |
deps/lld/test/wasm/function-imports-first.ll+3-8| ... | ... | @@ -24,25 +24,20 @@ declare i32 @ret32(float) local_unnamed_addr #1 |
| 24 | 24 | ; CHECK-NEXT: ParamTypes: |
| 25 | 25 | ; CHECK-NEXT: - F32 |
| 26 | 26 | ; CHECK: - Type: FUNCTION |
| 27 | ; CHECK-NEXT: FunctionTypes: [ 0, 0, 1 ] | |
| 27 | ; CHECK-NEXT: FunctionTypes: [ 0, 1 ] | |
| 28 | 28 | ; CHECK: - Type: CODE |
| 29 | 29 | ; CHECK-NEXT: Functions: |
| 30 | 30 | ; CHECK-NEXT: - Index: 0 |
| 31 | 31 | ; CHECK-NEXT: Locals: |
| 32 | ; CHECK-NEXT: Body: 0B | |
| 32 | ; CHECK-NEXT: Body: 43000000001081808080001A0B | |
| 33 | 33 | ; CHECK-NEXT: - Index: 1 |
| 34 | 34 | ; CHECK-NEXT: Locals: |
| 35 | ; CHECK-NEXT: Body: 43000000001082808080001A0B | |
| 36 | ; CHECK-NEXT: - Index: 2 | |
| 37 | ; CHECK-NEXT: Locals: | |
| 38 | 35 | ; CHECK-NEXT: Body: 41000B |
| 39 | 36 | ; CHECK-NEXT: - Type: CUSTOM |
| 40 | 37 | ; CHECK-NEXT: Name: name |
| 41 | 38 | ; CHECK-NEXT: FunctionNames: |
| 42 | 39 | ; CHECK-NEXT: - Index: 0 |
| 43 | ; CHECK-NEXT: Name: __wasm_call_ctors | |
| 44 | ; CHECK-NEXT: - Index: 1 | |
| 45 | 40 | ; CHECK-NEXT: Name: _start |
| 46 | ; CHECK-NEXT: - Index: 2 | |
| 41 | ; CHECK-NEXT: - Index: 1 | |
| 47 | 42 | ; CHECK-NEXT: Name: ret32 |
| 48 | 43 | ; CHECK-NEXT: ... |
deps/lld/test/wasm/function-imports.ll+5-8| ... | ... | @@ -18,25 +18,22 @@ declare i32 @ret32(float) local_unnamed_addr #1 |
| 18 | 18 | ; CHECK: - Type: TYPE |
| 19 | 19 | ; CHECK-NEXT: Signatures: |
| 20 | 20 | ; CHECK-NEXT: - Index: 0 |
| 21 | ; CHECK-NEXT: ReturnType: NORESULT | |
| 22 | ; CHECK-NEXT: ParamTypes: | |
| 23 | ; CHECK-NEXT: - Index: 1 | |
| 24 | 21 | ; CHECK-NEXT: ReturnType: I32 |
| 25 | 22 | ; CHECK-NEXT: ParamTypes: |
| 26 | 23 | ; CHECK-NEXT: - F32 |
| 24 | ; CHECK-NEXT: - Index: 1 | |
| 25 | ; CHECK-NEXT: ReturnType: NORESULT | |
| 26 | ; CHECK-NEXT: ParamTypes: | |
| 27 | 27 | ; CHECK-NEXT: - Type: FUNCTION |
| 28 | ; CHECK-NEXT: FunctionTypes: [ 0, 1, 0 ] | |
| 28 | ; CHECK-NEXT: FunctionTypes: [ 0, 1 ] | |
| 29 | 29 | ; CHECK: - Type: CODE |
| 30 | 30 | ; CHECK-NEXT: Functions: |
| 31 | 31 | ; CHECK: - Index: 0 |
| 32 | 32 | ; CHECK: - Index: 1 |
| 33 | ; CHECK: - Index: 2 | |
| 34 | 33 | ; CHECK: Name: name |
| 35 | 34 | ; CHECK-NEXT: FunctionNames: |
| 36 | 35 | ; CHECK-NEXT: - Index: 0 |
| 37 | ; CHECK-NEXT: Name: __wasm_call_ctors | |
| 38 | ; CHECK-NEXT: - Index: 1 | |
| 39 | 36 | ; CHECK-NEXT: Name: ret32 |
| 40 | ; CHECK-NEXT: - Index: 2 | |
| 37 | ; CHECK-NEXT: - Index: 1 | |
| 41 | 38 | ; CHECK-NEXT: Name: _start |
| 42 | 39 | ; CHECK-NEXT: ... |
deps/lld/test/wasm/gc-imports.ll+1-3| ... | ... | @@ -43,10 +43,8 @@ entry: |
| 43 | 43 | ; CHECK-NEXT: - Index: 0 |
| 44 | 44 | ; CHECK-NEXT: Name: used_undef_function |
| 45 | 45 | ; CHECK-NEXT: - Index: 1 |
| 46 | ; CHECK-NEXT: Name: __wasm_call_ctors | |
| 47 | ; CHECK-NEXT: - Index: 2 | |
| 48 | 46 | ; CHECK-NEXT: Name: _start |
| 49 | ; CHECK-NEXT: - Index: 3 | |
| 47 | ; CHECK-NEXT: - Index: 2 | |
| 50 | 48 | ; CHECK-NEXT: Name: use_undef_global |
| 51 | 49 | ; CHECK-NEXT: ... |
| 52 | 50 |
deps/lld/test/wasm/gc-sections.ll+8-10| ... | ... | @@ -38,10 +38,10 @@ entry: |
| 38 | 38 | ; CHECK: - Type: TYPE |
| 39 | 39 | ; CHECK-NEXT: Signatures: |
| 40 | 40 | ; CHECK-NEXT: - Index: 0 |
| 41 | ; CHECK-NEXT: ReturnType: NORESULT | |
| 41 | ; CHECK-NEXT: ReturnType: I32 | |
| 42 | 42 | ; CHECK-NEXT: ParamTypes: |
| 43 | 43 | ; CHECK-NEXT: - Index: 1 |
| 44 | ; CHECK-NEXT: ReturnType: I32 | |
| 44 | ; CHECK-NEXT: ReturnType: NORESULT | |
| 45 | 45 | ; CHECK-NEXT: ParamTypes: |
| 46 | 46 | ; CHECK-NEXT: - Index: 2 |
| 47 | 47 | ; CHECK-NEXT: ReturnType: I64 |
| ... | ... | @@ -66,8 +66,8 @@ entry: |
| 66 | 66 | ; CHECK: - Type: DATA |
| 67 | 67 | ; CHECK-NEXT: Segments: |
| 68 | 68 | ; CHECK-NEXT: - SectionOffset: 7 |
| 69 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 70 | ; CHECK-NEXT: Offset: | |
| 69 | ; CHECK-NEXT: InitFlags: 0 | |
| 70 | ; CHECK-NEXT: Offset: | |
| 71 | 71 | ; CHECK-NEXT: Opcode: I32_CONST |
| 72 | 72 | ; CHECK-NEXT: Value: 1024 |
| 73 | 73 | ; CHECK-NEXT: Content: '02000000' |
| ... | ... | @@ -75,12 +75,10 @@ entry: |
| 75 | 75 | ; CHECK-NEXT: Name: name |
| 76 | 76 | ; CHECK-NEXT: FunctionNames: |
| 77 | 77 | ; CHECK-NEXT: - Index: 0 |
| 78 | ; CHECK-NEXT: Name: __wasm_call_ctors | |
| 79 | ; CHECK-NEXT: - Index: 1 | |
| 80 | 78 | ; CHECK-NEXT: Name: used_function |
| 81 | ; CHECK-NEXT: - Index: 2 | |
| 79 | ; CHECK-NEXT: - Index: 1 | |
| 82 | 80 | ; CHECK-NEXT: Name: _start |
| 83 | ; CHECK-NEXT: - Index: 3 | |
| 81 | ; CHECK-NEXT: - Index: 2 | |
| 84 | 82 | ; CHECK-NEXT: Name: use_global |
| 85 | 83 | ; CHECK-NEXT: ... |
| 86 | 84 | |
| ... | ... | @@ -129,8 +127,8 @@ entry: |
| 129 | 127 | ; NO-GC: - Type: DATA |
| 130 | 128 | ; NO-GC-NEXT: Segments: |
| 131 | 129 | ; NO-GC-NEXT: - SectionOffset: 7 |
| 132 | ; NO-GC-NEXT: MemoryIndex: 0 | |
| 133 | ; NO-GC-NEXT: Offset: | |
| 130 | ; NO-GC-NEXT: InitFlags: 0 | |
| 131 | ; NO-GC-NEXT: Offset: | |
| 134 | 132 | ; NO-GC-NEXT: Opcode: I32_CONST |
| 135 | 133 | ; NO-GC-NEXT: Value: 1024 |
| 136 | 134 | ; NO-GC-NEXT: Content: '010000000000000002000000' |
deps/lld/test/wasm/global-base.test created+71| ... | ... | @@ -0,0 +1,71 @@ |
| 1 | RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.o | |
| 2 | ||
| 3 | RUN: wasm-ld --export=__global_base --export=__data_end --allow-undefined -o %t.wasm %t.o | |
| 4 | RUN: obj2yaml %t.wasm | FileCheck %s -check-prefix=CHECK-1024 | |
| 5 | CHECK-1024: - Type: GLOBAL | |
| 6 | CHECK-1024-NEXT: Globals: | |
| 7 | CHECK-1024-NEXT: - Index: 0 | |
| 8 | CHECK-1024-NEXT: Type: I32 | |
| 9 | CHECK-1024-NEXT: Mutable: true | |
| 10 | CHECK-1024-NEXT: InitExpr: | |
| 11 | CHECK-1024-NEXT: Opcode: I32_CONST | |
| 12 | CHECK-1024-NEXT: Value: 66560 | |
| 13 | CHECK-1024-NEXT: - Index: 1 | |
| 14 | CHECK-1024-NEXT: Type: I32 | |
| 15 | CHECK-1024-NEXT: Mutable: false | |
| 16 | CHECK-1024-NEXT: InitExpr: | |
| 17 | CHECK-1024-NEXT: Opcode: I32_CONST | |
| 18 | CHECK-1024-NEXT: Value: 1024 | |
| 19 | CHECK-1024-NEXT: - Index: 2 | |
| 20 | CHECK-1024-NEXT: Type: I32 | |
| 21 | CHECK-1024-NEXT: Mutable: false | |
| 22 | CHECK-1024-NEXT: InitExpr: | |
| 23 | CHECK-1024-NEXT: Opcode: I32_CONST | |
| 24 | CHECK-1024-NEXT: Value: 1024 | |
| 25 | ||
| 26 | CHECK-1024: - Type: EXPORT | |
| 27 | CHECK-1024-NEXT: Exports: | |
| 28 | CHECK-1024-NEXT: - Name: memory | |
| 29 | CHECK-1024-NEXT: Kind: MEMORY | |
| 30 | CHECK-1024-NEXT: Index: 0 | |
| 31 | CHECK-1024-NEXT: - Name: __data_end | |
| 32 | CHECK-1024-NEXT: Kind: GLOBAL | |
| 33 | CHECK-1024-NEXT: Index: 1 | |
| 34 | CHECK-1024-NEXT: - Name: __global_base | |
| 35 | CHECK-1024-NEXT: Kind: GLOBAL | |
| 36 | CHECK-1024-NEXT: Index: 2 | |
| 37 | ||
| 38 | RUN: wasm-ld --export=__global_base --export=__data_end --allow-undefined --global-base=16777216 -o %t.wasm %t.o | |
| 39 | RUN: obj2yaml %t.wasm | FileCheck %s -check-prefix=CHECK-16777216 | |
| 40 | CHECK-16777216: - Type: GLOBAL | |
| 41 | CHECK-16777216-NEXT: Globals: | |
| 42 | CHECK-16777216-NEXT: - Index: 0 | |
| 43 | CHECK-16777216-NEXT: Type: I32 | |
| 44 | CHECK-16777216-NEXT: Mutable: true | |
| 45 | CHECK-16777216-NEXT: InitExpr: | |
| 46 | CHECK-16777216-NEXT: Opcode: I32_CONST | |
| 47 | CHECK-16777216-NEXT: Value: 16842752 | |
| 48 | CHECK-16777216-NEXT: - Index: 1 | |
| 49 | CHECK-16777216-NEXT: Type: I32 | |
| 50 | CHECK-16777216-NEXT: Mutable: false | |
| 51 | CHECK-16777216-NEXT: InitExpr: | |
| 52 | CHECK-16777216-NEXT: Opcode: I32_CONST | |
| 53 | CHECK-16777216-NEXT: Value: 16777216 | |
| 54 | CHECK-16777216-NEXT: - Index: 2 | |
| 55 | CHECK-16777216-NEXT: Type: I32 | |
| 56 | CHECK-16777216-NEXT: Mutable: false | |
| 57 | CHECK-16777216-NEXT: InitExpr: | |
| 58 | CHECK-16777216-NEXT: Opcode: I32_CONST | |
| 59 | CHECK-16777216-NEXT: Value: 16777216 | |
| 60 | ||
| 61 | CHECK-16777216: - Type: EXPORT | |
| 62 | CHECK-16777216-NEXT: Exports: | |
| 63 | CHECK-16777216-NEXT: - Name: memory | |
| 64 | CHECK-16777216-NEXT: Kind: MEMORY | |
| 65 | CHECK-16777216-NEXT: Index: 0 | |
| 66 | CHECK-16777216-NEXT: - Name: __data_end | |
| 67 | CHECK-16777216-NEXT: Kind: GLOBAL | |
| 68 | CHECK-16777216-NEXT: Index: 1 | |
| 69 | CHECK-16777216-NEXT: - Name: __global_base | |
| 70 | CHECK-16777216-NEXT: Kind: GLOBAL | |
| 71 | CHECK-16777216-NEXT: Index: 2 |
deps/lld/test/wasm/import-memory.test+2-2| ... | ... | @@ -32,8 +32,8 @@ |
| 32 | 32 | # CHECK-MAX-NEXT: Maximum: 0x00000005 |
| 33 | 33 | # CHECK-MAX-NEXT: - Type: |
| 34 | 34 | |
| 35 | # RUN: wasm-ld --import-memory --shared-memory --initial-memory=262144 \ | |
| 36 | # RUN: --max-memory=327680 -o %t.max.wasm %t.start.o | |
| 35 | # RUN: wasm-ld --import-memory --shared-memory --active-segments \ | |
| 36 | # RUN: --initial-memory=262144 --max-memory=327680 -o %t.max.wasm %t.start.o | |
| 37 | 37 | # RUN: obj2yaml %t.max.wasm | FileCheck -check-prefix=CHECK-SHARED %s |
| 38 | 38 | |
| 39 | 39 | # Verify the --shared-memory flag works with imports |
deps/lld/test/wasm/init-fini-gc.ll created+48| ... | ... | @@ -0,0 +1,48 @@ |
| 1 | ; RUN: llc -filetype=obj -o %t.o %s | |
| 2 | ; RUN: wasm-ld %t.o -o %t.wasm | |
| 3 | ; RUN: obj2yaml %t.wasm | FileCheck %s | |
| 4 | ||
| 5 | ; RUN: wasm-ld %t.o -o %t.wasm | |
| 6 | ; RUN: obj2yaml %t.wasm | FileCheck %s | |
| 7 | ||
| 8 | ; RUN: wasm-ld --export=__wasm_call_ctors %t.o -o %t.export.wasm | |
| 9 | ; RUN: obj2yaml %t.export.wasm | FileCheck %s -check-prefix=EXPORT | |
| 10 | ||
| 11 | ; Test that the __wasm_call_ctor function if not referenced | |
| 12 | ||
| 13 | target triple = "wasm32-unknown-unknown" | |
| 14 | ||
| 15 | define hidden void @_start() { | |
| 16 | entry: | |
| 17 | ret void | |
| 18 | } | |
| 19 | ||
| 20 | define hidden void @func1() { | |
| 21 | entry: | |
| 22 | ret void | |
| 23 | } | |
| 24 | ||
| 25 | define hidden void @func2() { | |
| 26 | entry: | |
| 27 | ret void | |
| 28 | } | |
| 29 | ||
| 30 | define i32 @__cxa_atexit(i32 %func, i32 %arg, i32 %dso_handle) { | |
| 31 | ret i32 0 | |
| 32 | } | |
| 33 | ||
| 34 | @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [ | |
| 35 | { i32, void ()*, i8* } { i32 1, void ()* @func1, i8* null } | |
| 36 | ] | |
| 37 | ||
| 38 | @llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [ | |
| 39 | { i32, void ()*, i8* } { i32 1, void ()* @func2, i8* null } | |
| 40 | ] | |
| 41 | ||
| 42 | ; CHECK-NOT: __cxa_atexit | |
| 43 | ; CHECK-NOT: __wasm_call_ctors | |
| 44 | ||
| 45 | ; EXPORT: __wasm_call_ctors | |
| 46 | ; EXPORT: func1 | |
| 47 | ; EXPORT: func2 | |
| 48 | ; EXPORT: __cxa_atexit |
deps/lld/test/wasm/init-fini.ll+20-198| ... | ... | @@ -25,6 +25,7 @@ entry: |
| 25 | 25 | |
| 26 | 26 | declare hidden void @externCtor() |
| 27 | 27 | declare hidden void @externDtor() |
| 28 | declare hidden void @__wasm_call_ctors() | |
| 28 | 29 | |
| 29 | 30 | define i32 @__cxa_atexit(i32 %func, i32 %arg, i32 %dso_handle) { |
| 30 | 31 | ret i32 0 |
| ... | ... | @@ -32,6 +33,7 @@ define i32 @__cxa_atexit(i32 %func, i32 %arg, i32 %dso_handle) { |
| 32 | 33 | |
| 33 | 34 | define hidden void @_start() { |
| 34 | 35 | entry: |
| 36 | call void @__wasm_call_ctors(); | |
| 35 | 37 | ret void |
| 36 | 38 | } |
| 37 | 39 | |
| ... | ... | @@ -75,7 +77,7 @@ entry: |
| 75 | 77 | ; CHECK-NEXT: Body: 10031004100A100F1012100F10141003100C100F10161001100E0B |
| 76 | 78 | ; CHECK: - Index: 22 |
| 77 | 79 | ; CHECK-NEXT: Locals: |
| 78 | ; CHECK-NEXT: Body: 024041868080800041004180888080001087808080000D000F0B00000B | |
| 80 | ; CHECK-NEXT: Body: 02404186808080004100418088808000108780808000450D0000000B0B | |
| 79 | 81 | ; CHECK-NEXT: - Type: CUSTOM |
| 80 | 82 | ; CHECK-NEXT: Name: name |
| 81 | 83 | ; CHECK-NEXT: FunctionNames: |
| ... | ... | @@ -127,202 +129,22 @@ entry: |
| 127 | 129 | ; CHECK-NEXT: Name: .Lregister_call_dtors.2002 |
| 128 | 130 | ; CHECK-NEXT: ... |
| 129 | 131 | |
| 130 | ||
| 131 | 132 | ; RUN: wasm-ld -r %t.o %t.global-ctor-dtor.o -o %t.reloc.wasm |
| 132 | ; RUN: obj2yaml %t.reloc.wasm | FileCheck -check-prefix=RELOC %s | |
| 133 | ; RUN: llvm-readobj --symbols --sections %t.reloc.wasm | FileCheck -check-prefix=RELOC %s | |
| 133 | 134 | |
| 134 | ; RELOC: SymbolTable: | |
| 135 | ; RELOC-NEXT: - Index: 0 | |
| 136 | ; RELOC-NEXT: Kind: FUNCTION | |
| 137 | ; RELOC-NEXT: Name: func1 | |
| 138 | ; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] | |
| 139 | ; RELOC-NEXT: Function: 2 | |
| 140 | ; RELOC-NEXT: - Index: 1 | |
| 141 | ; RELOC-NEXT: Kind: FUNCTION | |
| 142 | ; RELOC-NEXT: Name: func2 | |
| 143 | ; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] | |
| 144 | ; RELOC-NEXT: Function: 3 | |
| 145 | ; RELOC-NEXT: - Index: 2 | |
| 146 | ; RELOC-NEXT: Kind: FUNCTION | |
| 147 | ; RELOC-NEXT: Name: func3 | |
| 148 | ; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] | |
| 149 | ; RELOC-NEXT: Function: 4 | |
| 150 | ; RELOC-NEXT: - Index: 3 | |
| 151 | ; RELOC-NEXT: Kind: FUNCTION | |
| 152 | ; RELOC-NEXT: Name: func4 | |
| 153 | ; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] | |
| 154 | ; RELOC-NEXT: Function: 5 | |
| 155 | ; RELOC-NEXT: - Index: 4 | |
| 156 | ; RELOC-NEXT: Kind: FUNCTION | |
| 157 | ; RELOC-NEXT: Name: __cxa_atexit | |
| 158 | ; RELOC-NEXT: Flags: [ ] | |
| 159 | ; RELOC-NEXT: Function: 6 | |
| 160 | ; RELOC-NEXT: - Index: 5 | |
| 161 | ; RELOC-NEXT: Kind: FUNCTION | |
| 162 | ; RELOC-NEXT: Name: _start | |
| 163 | ; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] | |
| 164 | ; RELOC-NEXT: Function: 7 | |
| 165 | ; RELOC-NEXT: - Index: 6 | |
| 166 | ; RELOC-NEXT: Kind: DATA | |
| 167 | ; RELOC-NEXT: Name: __dso_handle | |
| 168 | ; RELOC-NEXT: Flags: [ BINDING_WEAK, VISIBILITY_HIDDEN, UNDEFINED ] | |
| 169 | ; RELOC-NEXT: - Index: 7 | |
| 170 | ; RELOC-NEXT: Kind: FUNCTION | |
| 171 | ; RELOC-NEXT: Name: externDtor | |
| 172 | ; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN, UNDEFINED ] | |
| 173 | ; RELOC-NEXT: Function: 0 | |
| 174 | ; RELOC-NEXT: - Index: 8 | |
| 175 | ; RELOC-NEXT: Kind: FUNCTION | |
| 176 | ; RELOC-NEXT: Name: externCtor | |
| 177 | ; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN, UNDEFINED ] | |
| 178 | ; RELOC-NEXT: Function: 1 | |
| 179 | ; RELOC-NEXT: - Index: 9 | |
| 180 | ; RELOC-NEXT: Kind: FUNCTION | |
| 181 | ; RELOC-NEXT: Name: myctor | |
| 182 | ; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] | |
| 183 | ; RELOC-NEXT: Function: 14 | |
| 184 | ; RELOC-NEXT: - Index: 10 | |
| 185 | ; RELOC-NEXT: Kind: FUNCTION | |
| 186 | ; RELOC-NEXT: Name: mydtor | |
| 187 | ; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] | |
| 188 | ; RELOC-NEXT: Function: 15 | |
| 189 | ; RELOC-NEXT: - Index: 11 | |
| 190 | ; RELOC-NEXT: Kind: GLOBAL | |
| 191 | ; RELOC-NEXT: Name: __stack_pointer | |
| 192 | ; RELOC-NEXT: Flags: [ UNDEFINED ] | |
| 193 | ; RELOC-NEXT: Global: 0 | |
| 194 | ; RELOC-NEXT: - Index: 12 | |
| 195 | ; RELOC-NEXT: Kind: FUNCTION | |
| 196 | ; RELOC-NEXT: Name: .Lcall_dtors.101 | |
| 197 | ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] | |
| 198 | ; RELOC-NEXT: Function: 8 | |
| 199 | ; RELOC-NEXT: - Index: 13 | |
| 200 | ; RELOC-NEXT: Kind: FUNCTION | |
| 201 | ; RELOC-NEXT: Name: .Lregister_call_dtors.101 | |
| 202 | ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] | |
| 203 | ; RELOC-NEXT: Function: 9 | |
| 204 | ; RELOC-NEXT: - Index: 14 | |
| 205 | ; RELOC-NEXT: Kind: FUNCTION | |
| 206 | ; RELOC-NEXT: Name: .Lcall_dtors.1001 | |
| 207 | ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] | |
| 208 | ; RELOC-NEXT: Function: 10 | |
| 209 | ; RELOC-NEXT: - Index: 15 | |
| 210 | ; RELOC-NEXT: Kind: FUNCTION | |
| 211 | ; RELOC-NEXT: Name: .Lregister_call_dtors.1001 | |
| 212 | ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] | |
| 213 | ; RELOC-NEXT: Function: 11 | |
| 214 | ; RELOC-NEXT: - Index: 16 | |
| 215 | ; RELOC-NEXT: Kind: FUNCTION | |
| 216 | ; RELOC-NEXT: Name: .Lcall_dtors.4000 | |
| 217 | ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] | |
| 218 | ; RELOC-NEXT: Function: 12 | |
| 219 | ; RELOC-NEXT: - Index: 17 | |
| 220 | ; RELOC-NEXT: Kind: FUNCTION | |
| 221 | ; RELOC-NEXT: Name: .Lregister_call_dtors.4000 | |
| 222 | ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] | |
| 223 | ; RELOC-NEXT: Function: 13 | |
| 224 | ; RELOC-NEXT: - Index: 18 | |
| 225 | ; RELOC-NEXT: Kind: FUNCTION | |
| 226 | ; RELOC-NEXT: Name: .Lcall_dtors.101 | |
| 227 | ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] | |
| 228 | ; RELOC-NEXT: Function: 16 | |
| 229 | ; RELOC-NEXT: - Index: 19 | |
| 230 | ; RELOC-NEXT: Kind: FUNCTION | |
| 231 | ; RELOC-NEXT: Name: .Lregister_call_dtors.101 | |
| 232 | ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] | |
| 233 | ; RELOC-NEXT: Function: 17 | |
| 234 | ; RELOC-NEXT: - Index: 20 | |
| 235 | ; RELOC-NEXT: Kind: FUNCTION | |
| 236 | ; RELOC-NEXT: Name: .Lcall_dtors.202 | |
| 237 | ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] | |
| 238 | ; RELOC-NEXT: Function: 18 | |
| 239 | ; RELOC-NEXT: - Index: 21 | |
| 240 | ; RELOC-NEXT: Kind: FUNCTION | |
| 241 | ; RELOC-NEXT: Name: .Lregister_call_dtors.202 | |
| 242 | ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] | |
| 243 | ; RELOC-NEXT: Function: 19 | |
| 244 | ; RELOC-NEXT: - Index: 22 | |
| 245 | ; RELOC-NEXT: Kind: FUNCTION | |
| 246 | ; RELOC-NEXT: Name: .Lcall_dtors.2002 | |
| 247 | ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] | |
| 248 | ; RELOC-NEXT: Function: 20 | |
| 249 | ; RELOC-NEXT: - Index: 23 | |
| 250 | ; RELOC-NEXT: Kind: FUNCTION | |
| 251 | ; RELOC-NEXT: Name: .Lregister_call_dtors.2002 | |
| 252 | ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] | |
| 253 | ; RELOC-NEXT: Function: 21 | |
| 254 | ; RELOC-NEXT: InitFunctions: | |
| 255 | ; RELOC-NEXT: - Priority: 101 | |
| 256 | ; RELOC-NEXT: Symbol: 0 | |
| 257 | ; RELOC-NEXT: - Priority: 101 | |
| 258 | ; RELOC-NEXT: Symbol: 1 | |
| 259 | ; RELOC-NEXT: - Priority: 101 | |
| 260 | ; RELOC-NEXT: Symbol: 13 | |
| 261 | ; RELOC-NEXT: - Priority: 101 | |
| 262 | ; RELOC-NEXT: Symbol: 9 | |
| 263 | ; RELOC-NEXT: - Priority: 101 | |
| 264 | ; RELOC-NEXT: Symbol: 19 | |
| 265 | ; RELOC-NEXT: - Priority: 202 | |
| 266 | ; RELOC-NEXT: Symbol: 9 | |
| 267 | ; RELOC-NEXT: - Priority: 202 | |
| 268 | ; RELOC-NEXT: Symbol: 21 | |
| 269 | ; RELOC-NEXT: - Priority: 1001 | |
| 270 | ; RELOC-NEXT: Symbol: 0 | |
| 271 | ; RELOC-NEXT: - Priority: 1001 | |
| 272 | ; RELOC-NEXT: Symbol: 15 | |
| 273 | ; RELOC-NEXT: - Priority: 2002 | |
| 274 | ; RELOC-NEXT: Symbol: 9 | |
| 275 | ; RELOC-NEXT: - Priority: 2002 | |
| 276 | ; RELOC-NEXT: Symbol: 23 | |
| 277 | ; RELOC-NEXT: - Priority: 4000 | |
| 278 | ; RELOC-NEXT: Symbol: 8 | |
| 279 | ; RELOC-NEXT: - Priority: 4000 | |
| 280 | ; RELOC-NEXT: Symbol: 17 | |
| 281 | ; RELOC-NEXT: - Type: CUSTOM | |
| 282 | ; RELOC-NEXT: Name: name | |
| 283 | ; RELOC-NEXT: FunctionNames: | |
| 284 | ; RELOC-NEXT: - Index: 0 | |
| 285 | ; RELOC-NEXT: Name: externDtor | |
| 286 | ; RELOC-NEXT: - Index: 1 | |
| 287 | ; RELOC-NEXT: Name: externCtor | |
| 288 | ; RELOC-NEXT: - Index: 2 | |
| 289 | ; RELOC-NEXT: Name: func1 | |
| 290 | ; RELOC-NEXT: - Index: 3 | |
| 291 | ; RELOC-NEXT: Name: func2 | |
| 292 | ; RELOC-NEXT: - Index: 4 | |
| 293 | ; RELOC-NEXT: Name: func3 | |
| 294 | ; RELOC-NEXT: - Index: 5 | |
| 295 | ; RELOC-NEXT: Name: func4 | |
| 296 | ; RELOC-NEXT: - Index: 6 | |
| 297 | ; RELOC-NEXT: Name: __cxa_atexit | |
| 298 | ; RELOC-NEXT: - Index: 7 | |
| 299 | ; RELOC-NEXT: Name: _start | |
| 300 | ; RELOC-NEXT: - Index: 8 | |
| 301 | ; RELOC-NEXT: Name: .Lcall_dtors.101 | |
| 302 | ; RELOC-NEXT: - Index: 9 | |
| 303 | ; RELOC-NEXT: Name: .Lregister_call_dtors.101 | |
| 304 | ; RELOC-NEXT: - Index: 10 | |
| 305 | ; RELOC-NEXT: Name: .Lcall_dtors.1001 | |
| 306 | ; RELOC-NEXT: - Index: 11 | |
| 307 | ; RELOC-NEXT: Name: .Lregister_call_dtors.1001 | |
| 308 | ; RELOC-NEXT: - Index: 12 | |
| 309 | ; RELOC-NEXT: Name: .Lcall_dtors.4000 | |
| 310 | ; RELOC-NEXT: - Index: 13 | |
| 311 | ; RELOC-NEXT: Name: .Lregister_call_dtors.4000 | |
| 312 | ; RELOC-NEXT: - Index: 14 | |
| 313 | ; RELOC-NEXT: Name: myctor | |
| 314 | ; RELOC-NEXT: - Index: 15 | |
| 315 | ; RELOC-NEXT: Name: mydtor | |
| 316 | ; RELOC-NEXT: - Index: 16 | |
| 317 | ; RELOC-NEXT: Name: .Lcall_dtors.101 | |
| 318 | ; RELOC-NEXT: - Index: 17 | |
| 319 | ; RELOC-NEXT: Name: .Lregister_call_dtors.101 | |
| 320 | ; RELOC-NEXT: - Index: 18 | |
| 321 | ; RELOC-NEXT: Name: .Lcall_dtors.202 | |
| 322 | ; RELOC-NEXT: - Index: 19 | |
| 323 | ; RELOC-NEXT: Name: .Lregister_call_dtors.202 | |
| 324 | ; RELOC-NEXT: - Index: 20 | |
| 325 | ; RELOC-NEXT: Name: .Lcall_dtors.2002 | |
| 326 | ; RELOC-NEXT: - Index: 21 | |
| 327 | ; RELOC-NEXT: Name: .Lregister_call_dtors.2002 | |
| 328 | ; RELOC-NEXT: ... | |
| 135 | ; RELOC: Name: linking | |
| 136 | ; RELOC-NEXT: InitFunctions [ | |
| 137 | ; RELOC-NEXT: 0 (priority=101) | |
| 138 | ; RELOC-NEXT: 1 (priority=101) | |
| 139 | ; RELOC-NEXT: 14 (priority=101) | |
| 140 | ; RELOC-NEXT: 10 (priority=101) | |
| 141 | ; RELOC-NEXT: 20 (priority=101) | |
| 142 | ; RELOC-NEXT: 10 (priority=202) | |
| 143 | ; RELOC-NEXT: 22 (priority=202) | |
| 144 | ; RELOC-NEXT: 0 (priority=1001) | |
| 145 | ; RELOC-NEXT: 16 (priority=1001) | |
| 146 | ; RELOC-NEXT: 10 (priority=2002) | |
| 147 | ; RELOC-NEXT: 24 (priority=2002) | |
| 148 | ; RELOC-NEXT: 9 (priority=4000) | |
| 149 | ; RELOC-NEXT: 18 (priority=4000) | |
| 150 | ; RELOC-NEXT: ] |
deps/lld/test/wasm/large-memory.test created+5| ... | ... | @@ -0,0 +1,5 @@ |
| 1 | RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.o | |
| 2 | ||
| 3 | ; Verify we can parse large integers such as when we ask for 2G of total | |
| 4 | ; memory. | |
| 5 | RUN: wasm-ld %t.o -o %t.wasm --max-memory=2147483648 |
deps/lld/test/wasm/lit.local.cfg+1-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | 1 | if 'wasm' not in config.available_features: |
| 2 | 2 | config.unsupported = True |
| 3 | 3 | |
| 4 | config.suffixes = ['.test', '.yaml', '.ll'] | |
| 4 | config.suffixes = ['.test', '.yaml', '.ll', '.s'] |
deps/lld/test/wasm/local-symbols.ll+9-32| ... | ... | @@ -27,13 +27,13 @@ entry: |
| 27 | 27 | ; CHECK-NEXT: - Type: TYPE |
| 28 | 28 | ; CHECK-NEXT: Signatures: |
| 29 | 29 | ; CHECK-NEXT: - Index: 0 |
| 30 | ; CHECK-NEXT: ReturnType: NORESULT | |
| 30 | ; CHECK-NEXT: ReturnType: I32 | |
| 31 | 31 | ; CHECK-NEXT: ParamTypes: |
| 32 | 32 | ; CHECK-NEXT: - Index: 1 |
| 33 | ; CHECK-NEXT: ReturnType: I32 | |
| 33 | ; CHECK-NEXT: ReturnType: NORESULT | |
| 34 | 34 | ; CHECK-NEXT: ParamTypes: |
| 35 | 35 | ; CHECK-NEXT: - Type: FUNCTION |
| 36 | ; CHECK-NEXT: FunctionTypes: [ 0, 1, 0 ] | |
| 36 | ; CHECK-NEXT: FunctionTypes: [ 0, 1 ] | |
| 37 | 37 | ; CHECK-NEXT: - Type: TABLE |
| 38 | 38 | ; CHECK-NEXT: Tables: |
| 39 | 39 | ; CHECK-NEXT: - ElemType: FUNCREF |
| ... | ... | @@ -57,51 +57,30 @@ entry: |
| 57 | 57 | ; CHECK-NEXT: Mutable: false |
| 58 | 58 | ; CHECK-NEXT: InitExpr: |
| 59 | 59 | ; CHECK-NEXT: Opcode: I32_CONST |
| 60 | ; CHECK-NEXT: Value: 66576 | |
| 61 | ; CHECK-NEXT: - Index: 2 | |
| 62 | ; CHECK-NEXT: Type: I32 | |
| 63 | ; CHECK-NEXT: Mutable: false | |
| 64 | ; CHECK-NEXT: InitExpr: | |
| 65 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 66 | ; CHECK-NEXT: Value: 1032 | |
| 67 | ; CHECK-NEXT: - Index: 3 | |
| 68 | ; CHECK-NEXT: Type: I32 | |
| 69 | ; CHECK-NEXT: Mutable: false | |
| 70 | ; CHECK-NEXT: InitExpr: | |
| 71 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 72 | 60 | ; CHECK-NEXT: Value: 1024 |
| 73 | 61 | ; CHECK-NEXT: - Type: EXPORT |
| 74 | 62 | ; CHECK-NEXT: Exports: |
| 75 | 63 | ; CHECK-NEXT: - Name: memory |
| 76 | 64 | ; CHECK-NEXT: Kind: MEMORY |
| 77 | 65 | ; CHECK-NEXT: Index: 0 |
| 78 | ; CHECK-NEXT: - Name: __heap_base | |
| 79 | ; CHECK-NEXT: Kind: GLOBAL | |
| 80 | ; CHECK-NEXT: Index: 1 | |
| 81 | ; CHECK-NEXT: - Name: __data_end | |
| 82 | ; CHECK-NEXT: Kind: GLOBAL | |
| 83 | ; CHECK-NEXT: Index: 2 | |
| 84 | 66 | ; CHECK-NEXT: - Name: _start |
| 85 | 67 | ; CHECK-NEXT: Kind: FUNCTION |
| 86 | ; CHECK-NEXT: Index: 2 | |
| 68 | ; CHECK-NEXT: Index: 1 | |
| 87 | 69 | ; CHECK-NEXT: - Name: foo |
| 88 | 70 | ; CHECK-NEXT: Kind: GLOBAL |
| 89 | ; CHECK-NEXT: Index: 3 | |
| 71 | ; CHECK-NEXT: Index: 1 | |
| 90 | 72 | ; CHECK-NEXT: - Type: CODE |
| 91 | 73 | ; CHECK-NEXT: Functions: |
| 92 | 74 | ; CHECK-NEXT: - Index: 0 |
| 93 | 75 | ; CHECK-NEXT: Locals: |
| 94 | ; CHECK-NEXT: Body: 0B | |
| 95 | ; CHECK-NEXT: - Index: 1 | |
| 96 | ; CHECK-NEXT: Locals: | |
| 97 | 76 | ; CHECK-NEXT: Body: 4100280284888080000B |
| 98 | ; CHECK-NEXT: - Index: 2 | |
| 77 | ; CHECK-NEXT: - Index: 1 | |
| 99 | 78 | ; CHECK-NEXT: Locals: |
| 100 | ; CHECK-NEXT: Body: 1081808080001A0B | |
| 79 | ; CHECK-NEXT: Body: 1080808080001A0B | |
| 101 | 80 | ; CHECK-NEXT: - Type: DATA |
| 102 | 81 | ; CHECK-NEXT: Segments: |
| 103 | 82 | ; CHECK-NEXT: - SectionOffset: 7 |
| 104 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 83 | ; CHECK-NEXT: InitFlags: 0 | |
| 105 | 84 | ; CHECK-NEXT: Offset: |
| 106 | 85 | ; CHECK-NEXT: Opcode: I32_CONST |
| 107 | 86 | ; CHECK-NEXT: Value: 1024 |
| ... | ... | @@ -110,9 +89,7 @@ entry: |
| 110 | 89 | ; CHECK-NEXT: Name: name |
| 111 | 90 | ; CHECK-NEXT: FunctionNames: |
| 112 | 91 | ; CHECK-NEXT: - Index: 0 |
| 113 | ; CHECK-NEXT: Name: __wasm_call_ctors | |
| 114 | ; CHECK-NEXT: - Index: 1 | |
| 115 | 92 | ; CHECK-NEXT: Name: baz |
| 116 | ; CHECK-NEXT: - Index: 2 | |
| 93 | ; CHECK-NEXT: - Index: 1 | |
| 117 | 94 | ; CHECK-NEXT: Name: _start |
| 118 | 95 | ; CHECK-NEXT: ... |
deps/lld/test/wasm/locals-duplicate.test+66-92| ... | ... | @@ -10,14 +10,11 @@ |
| 10 | 10 | ; CHECK-NEXT: - Type: TYPE |
| 11 | 11 | ; CHECK-NEXT: Signatures: |
| 12 | 12 | ; CHECK-NEXT: - Index: 0 |
| 13 | ; CHECK-NEXT: ReturnType: NORESULT | |
| 14 | ; CHECK-NEXT: ParamTypes: | |
| 15 | ; CHECK-NEXT: - Index: 1 | |
| 16 | 13 | ; CHECK-NEXT: ReturnType: I32 |
| 17 | 14 | ; CHECK-NEXT: ParamTypes: |
| 18 | 15 | ; CHECK-NEXT: - Type: FUNCTION |
| 19 | ; CHECK-NEXT: FunctionTypes: [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 20 | ; CHECK-NEXT: 1, 1, 1 ] | |
| 16 | ; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 17 | ; CHECK-NEXT: 0, 0 ] | |
| 21 | 18 | ; CHECK-NEXT: - Type: TABLE |
| 22 | 19 | ; CHECK-NEXT: Tables: |
| 23 | 20 | ; CHECK-NEXT: - ElemType: FUNCREF |
| ... | ... | @@ -41,20 +38,8 @@ |
| 41 | 38 | ; CHECK-NEXT: Mutable: false |
| 42 | 39 | ; CHECK-NEXT: InitExpr: |
| 43 | 40 | ; CHECK-NEXT: Opcode: I32_CONST |
| 44 | ; CHECK-NEXT: Value: 66592 | |
| 45 | ; CHECK-NEXT: - Index: 2 | |
| 46 | ; CHECK-NEXT: Type: I32 | |
| 47 | ; CHECK-NEXT: Mutable: false | |
| 48 | ; CHECK-NEXT: InitExpr: | |
| 49 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 50 | ; CHECK-NEXT: Value: 1048 | |
| 51 | ; CHECK-NEXT: - Index: 3 | |
| 52 | ; CHECK-NEXT: Type: I32 | |
| 53 | ; CHECK-NEXT: Mutable: false | |
| 54 | ; CHECK-NEXT: InitExpr: | |
| 55 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 56 | 41 | ; CHECK-NEXT: Value: 1028 |
| 57 | ; CHECK-NEXT: - Index: 4 | |
| 42 | ; CHECK-NEXT: - Index: 2 | |
| 58 | 43 | ; CHECK-NEXT: Type: I32 |
| 59 | 44 | ; CHECK-NEXT: Mutable: false |
| 60 | 45 | ; CHECK-NEXT: InitExpr: |
| ... | ... | @@ -65,71 +50,65 @@ |
| 65 | 50 | ; CHECK-NEXT: - Name: memory |
| 66 | 51 | ; CHECK-NEXT: Kind: MEMORY |
| 67 | 52 | ; CHECK-NEXT: Index: 0 |
| 68 | ; CHECK-NEXT: - Name: __heap_base | |
| 69 | ; CHECK-NEXT: Kind: GLOBAL | |
| 70 | ; CHECK-NEXT: Index: 1 | |
| 71 | ; CHECK-NEXT: - Name: __data_end | |
| 72 | ; CHECK-NEXT: Kind: GLOBAL | |
| 73 | ; CHECK-NEXT: Index: 2 | |
| 74 | 53 | ; CHECK-NEXT: - Name: colliding_func2 |
| 75 | 54 | ; CHECK-NEXT: Kind: FUNCTION |
| 76 | ; CHECK-NEXT: Index: 2 | |
| 55 | ; CHECK-NEXT: Index: 1 | |
| 77 | 56 | ; CHECK-NEXT: - Name: get_global1A |
| 78 | 57 | ; CHECK-NEXT: Kind: FUNCTION |
| 79 | ; CHECK-NEXT: Index: 4 | |
| 58 | ; CHECK-NEXT: Index: 3 | |
| 80 | 59 | ; CHECK-NEXT: - Name: get_global2A |
| 81 | 60 | ; CHECK-NEXT: Kind: FUNCTION |
| 82 | ; CHECK-NEXT: Index: 5 | |
| 61 | ; CHECK-NEXT: Index: 4 | |
| 83 | 62 | ; CHECK-NEXT: - Name: colliding_global2 |
| 84 | 63 | ; CHECK-NEXT: Kind: GLOBAL |
| 85 | ; CHECK-NEXT: Index: 3 | |
| 64 | ; CHECK-NEXT: Index: 1 | |
| 86 | 65 | ; CHECK-NEXT: - Name: get_global3A |
| 87 | 66 | ; CHECK-NEXT: Kind: FUNCTION |
| 88 | ; CHECK-NEXT: Index: 6 | |
| 67 | ; CHECK-NEXT: Index: 5 | |
| 89 | 68 | ; CHECK-NEXT: - Name: get_func1A |
| 90 | 69 | ; CHECK-NEXT: Kind: FUNCTION |
| 91 | ; CHECK-NEXT: Index: 7 | |
| 70 | ; CHECK-NEXT: Index: 6 | |
| 92 | 71 | ; CHECK-NEXT: - Name: get_func2A |
| 93 | 72 | ; CHECK-NEXT: Kind: FUNCTION |
| 94 | ; CHECK-NEXT: Index: 8 | |
| 73 | ; CHECK-NEXT: Index: 7 | |
| 95 | 74 | ; CHECK-NEXT: - Name: get_func3A |
| 96 | 75 | ; CHECK-NEXT: Kind: FUNCTION |
| 97 | ; CHECK-NEXT: Index: 9 | |
| 76 | ; CHECK-NEXT: Index: 8 | |
| 98 | 77 | ; CHECK-NEXT: - Name: colliding_func1 |
| 99 | 78 | ; CHECK-NEXT: Kind: FUNCTION |
| 100 | ; CHECK-NEXT: Index: 10 | |
| 79 | ; CHECK-NEXT: Index: 9 | |
| 101 | 80 | ; CHECK-NEXT: - Name: get_global1B |
| 102 | 81 | ; CHECK-NEXT: Kind: FUNCTION |
| 103 | ; CHECK-NEXT: Index: 13 | |
| 82 | ; CHECK-NEXT: Index: 12 | |
| 104 | 83 | ; CHECK-NEXT: - Name: colliding_global1 |
| 105 | 84 | ; CHECK-NEXT: Kind: GLOBAL |
| 106 | ; CHECK-NEXT: Index: 4 | |
| 85 | ; CHECK-NEXT: Index: 2 | |
| 107 | 86 | ; CHECK-NEXT: - Name: get_global2B |
| 108 | 87 | ; CHECK-NEXT: Kind: FUNCTION |
| 109 | ; CHECK-NEXT: Index: 14 | |
| 88 | ; CHECK-NEXT: Index: 13 | |
| 110 | 89 | ; CHECK-NEXT: - Name: get_global3B |
| 111 | 90 | ; CHECK-NEXT: Kind: FUNCTION |
| 112 | ; CHECK-NEXT: Index: 15 | |
| 91 | ; CHECK-NEXT: Index: 14 | |
| 113 | 92 | ; CHECK-NEXT: - Name: get_func1B |
| 114 | 93 | ; CHECK-NEXT: Kind: FUNCTION |
| 115 | ; CHECK-NEXT: Index: 16 | |
| 94 | ; CHECK-NEXT: Index: 15 | |
| 116 | 95 | ; CHECK-NEXT: - Name: get_func2B |
| 117 | 96 | ; CHECK-NEXT: Kind: FUNCTION |
| 118 | ; CHECK-NEXT: Index: 17 | |
| 97 | ; CHECK-NEXT: Index: 16 | |
| 119 | 98 | ; CHECK-NEXT: - Name: get_func3B |
| 120 | 99 | ; CHECK-NEXT: Kind: FUNCTION |
| 121 | ; CHECK-NEXT: Index: 18 | |
| 100 | ; CHECK-NEXT: Index: 17 | |
| 122 | 101 | ; CHECK-NEXT: - Type: ELEM |
| 123 | 102 | ; CHECK-NEXT: Segments: |
| 124 | 103 | ; CHECK-NEXT: - Offset: |
| 125 | 104 | ; CHECK-NEXT: Opcode: I32_CONST |
| 126 | 105 | ; CHECK-NEXT: Value: 1 |
| 127 | ; CHECK-NEXT: Functions: [ 1, 2, 3, 10, 11, 12 ] | |
| 106 | ; CHECK-NEXT: Functions: [ 0, 1, 2, 9, 10, 11 ] | |
| 128 | 107 | ; CHECK-NEXT: - Type: CODE |
| 129 | 108 | ; CHECK-NEXT: Functions: |
| 130 | 109 | ; CHECK-NEXT: - Index: 0 |
| 131 | 110 | ; CHECK-NEXT: Locals: |
| 132 | ; CHECK-NEXT: Body: 0B | |
| 111 | ; CHECK-NEXT: Body: 41020B | |
| 133 | 112 | ; CHECK-NEXT: - Index: 1 |
| 134 | 113 | ; CHECK-NEXT: Locals: |
| 135 | 114 | ; CHECK-NEXT: Body: 41020B |
| ... | ... | @@ -138,25 +117,25 @@ |
| 138 | 117 | ; CHECK-NEXT: Body: 41020B |
| 139 | 118 | ; CHECK-NEXT: - Index: 3 |
| 140 | 119 | ; CHECK-NEXT: Locals: |
| 141 | ; CHECK-NEXT: Body: 41020B | |
| 120 | ; CHECK-NEXT: Body: 4180888080000B | |
| 142 | 121 | ; CHECK-NEXT: - Index: 4 |
| 143 | 122 | ; CHECK-NEXT: Locals: |
| 144 | ; CHECK-NEXT: Body: 4180888080000B | |
| 123 | ; CHECK-NEXT: Body: 4184888080000B | |
| 145 | 124 | ; CHECK-NEXT: - Index: 5 |
| 146 | 125 | ; CHECK-NEXT: Locals: |
| 147 | ; CHECK-NEXT: Body: 4184888080000B | |
| 126 | ; CHECK-NEXT: Body: 4188888080000B | |
| 148 | 127 | ; CHECK-NEXT: - Index: 6 |
| 149 | 128 | ; CHECK-NEXT: Locals: |
| 150 | ; CHECK-NEXT: Body: 4188888080000B | |
| 129 | ; CHECK-NEXT: Body: 4181808080000B | |
| 151 | 130 | ; CHECK-NEXT: - Index: 7 |
| 152 | 131 | ; CHECK-NEXT: Locals: |
| 153 | ; CHECK-NEXT: Body: 4181808080000B | |
| 132 | ; CHECK-NEXT: Body: 4182808080000B | |
| 154 | 133 | ; CHECK-NEXT: - Index: 8 |
| 155 | 134 | ; CHECK-NEXT: Locals: |
| 156 | ; CHECK-NEXT: Body: 4182808080000B | |
| 135 | ; CHECK-NEXT: Body: 4183808080000B | |
| 157 | 136 | ; CHECK-NEXT: - Index: 9 |
| 158 | 137 | ; CHECK-NEXT: Locals: |
| 159 | ; CHECK-NEXT: Body: 4183808080000B | |
| 138 | ; CHECK-NEXT: Body: 41020B | |
| 160 | 139 | ; CHECK-NEXT: - Index: 10 |
| 161 | 140 | ; CHECK-NEXT: Locals: |
| 162 | 141 | ; CHECK-NEXT: Body: 41020B |
| ... | ... | @@ -165,29 +144,26 @@ |
| 165 | 144 | ; CHECK-NEXT: Body: 41020B |
| 166 | 145 | ; CHECK-NEXT: - Index: 12 |
| 167 | 146 | ; CHECK-NEXT: Locals: |
| 168 | ; CHECK-NEXT: Body: 41020B | |
| 169 | ; CHECK-NEXT: - Index: 13 | |
| 170 | ; CHECK-NEXT: Locals: | |
| 171 | 147 | ; CHECK-NEXT: Body: 418C888080000B |
| 172 | ; CHECK-NEXT: - Index: 14 | |
| 148 | ; CHECK-NEXT: - Index: 13 | |
| 173 | 149 | ; CHECK-NEXT: Locals: |
| 174 | 150 | ; CHECK-NEXT: Body: 4190888080000B |
| 175 | ; CHECK-NEXT: - Index: 15 | |
| 151 | ; CHECK-NEXT: - Index: 14 | |
| 176 | 152 | ; CHECK-NEXT: Locals: |
| 177 | 153 | ; CHECK-NEXT: Body: 4194888080000B |
| 178 | ; CHECK-NEXT: - Index: 16 | |
| 154 | ; CHECK-NEXT: - Index: 15 | |
| 179 | 155 | ; CHECK-NEXT: Locals: |
| 180 | 156 | ; CHECK-NEXT: Body: 4184808080000B |
| 181 | ; CHECK-NEXT: - Index: 17 | |
| 157 | ; CHECK-NEXT: - Index: 16 | |
| 182 | 158 | ; CHECK-NEXT: Locals: |
| 183 | 159 | ; CHECK-NEXT: Body: 4185808080000B |
| 184 | ; CHECK-NEXT: - Index: 18 | |
| 160 | ; CHECK-NEXT: - Index: 17 | |
| 185 | 161 | ; CHECK-NEXT: Locals: |
| 186 | 162 | ; CHECK-NEXT: Body: 4186808080000B |
| 187 | 163 | ; CHECK-NEXT: - Type: DATA |
| 188 | 164 | ; CHECK-NEXT: Segments: |
| 189 | 165 | ; CHECK-NEXT: - SectionOffset: 7 |
| 190 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 166 | ; CHECK-NEXT: InitFlags: 0 | |
| 191 | 167 | ; CHECK-NEXT: Offset: |
| 192 | 168 | ; CHECK-NEXT: Opcode: I32_CONST |
| 193 | 169 | ; CHECK-NEXT: Value: 1024 |
| ... | ... | @@ -196,42 +172,40 @@ |
| 196 | 172 | ; CHECK-NEXT: Name: name |
| 197 | 173 | ; CHECK-NEXT: FunctionNames: |
| 198 | 174 | ; CHECK-NEXT: - Index: 0 |
| 199 | ; CHECK-NEXT: Name: __wasm_call_ctors | |
| 200 | ; CHECK-NEXT: - Index: 1 | |
| 201 | 175 | ; CHECK-NEXT: Name: colliding_func1 |
| 202 | ; CHECK-NEXT: - Index: 2 | |
| 176 | ; CHECK-NEXT: - Index: 1 | |
| 203 | 177 | ; CHECK-NEXT: Name: colliding_func2 |
| 204 | ; CHECK-NEXT: - Index: 3 | |
| 178 | ; CHECK-NEXT: - Index: 2 | |
| 205 | 179 | ; CHECK-NEXT: Name: colliding_func3 |
| 206 | ; CHECK-NEXT: - Index: 4 | |
| 180 | ; CHECK-NEXT: - Index: 3 | |
| 207 | 181 | ; CHECK-NEXT: Name: get_global1A |
| 208 | ; CHECK-NEXT: - Index: 5 | |
| 182 | ; CHECK-NEXT: - Index: 4 | |
| 209 | 183 | ; CHECK-NEXT: Name: get_global2A |
| 210 | ; CHECK-NEXT: - Index: 6 | |
| 184 | ; CHECK-NEXT: - Index: 5 | |
| 211 | 185 | ; CHECK-NEXT: Name: get_global3A |
| 212 | ; CHECK-NEXT: - Index: 7 | |
| 186 | ; CHECK-NEXT: - Index: 6 | |
| 213 | 187 | ; CHECK-NEXT: Name: get_func1A |
| 214 | ; CHECK-NEXT: - Index: 8 | |
| 188 | ; CHECK-NEXT: - Index: 7 | |
| 215 | 189 | ; CHECK-NEXT: Name: get_func2A |
| 216 | ; CHECK-NEXT: - Index: 9 | |
| 190 | ; CHECK-NEXT: - Index: 8 | |
| 217 | 191 | ; CHECK-NEXT: Name: get_func3A |
| 218 | ; CHECK-NEXT: - Index: 10 | |
| 192 | ; CHECK-NEXT: - Index: 9 | |
| 219 | 193 | ; CHECK-NEXT: Name: colliding_func1 |
| 220 | ; CHECK-NEXT: - Index: 11 | |
| 194 | ; CHECK-NEXT: - Index: 10 | |
| 221 | 195 | ; CHECK-NEXT: Name: colliding_func2 |
| 222 | ; CHECK-NEXT: - Index: 12 | |
| 196 | ; CHECK-NEXT: - Index: 11 | |
| 223 | 197 | ; CHECK-NEXT: Name: colliding_func3 |
| 224 | ; CHECK-NEXT: - Index: 13 | |
| 198 | ; CHECK-NEXT: - Index: 12 | |
| 225 | 199 | ; CHECK-NEXT: Name: get_global1B |
| 226 | ; CHECK-NEXT: - Index: 14 | |
| 200 | ; CHECK-NEXT: - Index: 13 | |
| 227 | 201 | ; CHECK-NEXT: Name: get_global2B |
| 228 | ; CHECK-NEXT: - Index: 15 | |
| 202 | ; CHECK-NEXT: - Index: 14 | |
| 229 | 203 | ; CHECK-NEXT: Name: get_global3B |
| 230 | ; CHECK-NEXT: - Index: 16 | |
| 204 | ; CHECK-NEXT: - Index: 15 | |
| 231 | 205 | ; CHECK-NEXT: Name: get_func1B |
| 232 | ; CHECK-NEXT: - Index: 17 | |
| 206 | ; CHECK-NEXT: - Index: 16 | |
| 233 | 207 | ; CHECK-NEXT: Name: get_func2B |
| 234 | ; CHECK-NEXT: - Index: 18 | |
| 208 | ; CHECK-NEXT: - Index: 17 | |
| 235 | 209 | ; CHECK-NEXT: Name: get_func3B |
| 236 | 210 | ; CHECK-NEXT: ... |
| 237 | 211 | |
| ... | ... | @@ -269,40 +243,40 @@ |
| 269 | 243 | ; RELOC-NEXT: Functions: [ 0, 1, 2, 9, 10, 11 ] |
| 270 | 244 | ; RELOC-NEXT: - Type: CODE |
| 271 | 245 | ; RELOC-NEXT: Relocations: |
| 272 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB | |
| 246 | ; RELOC-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB | |
| 273 | 247 | ; RELOC-NEXT: Index: 18 |
| 274 | 248 | ; RELOC-NEXT: Offset: 0x00000013 |
| 275 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB | |
| 249 | ; RELOC-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB | |
| 276 | 250 | ; RELOC-NEXT: Index: 3 |
| 277 | 251 | ; RELOC-NEXT: Offset: 0x0000001C |
| 278 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB | |
| 252 | ; RELOC-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB | |
| 279 | 253 | ; RELOC-NEXT: Index: 19 |
| 280 | 254 | ; RELOC-NEXT: Offset: 0x00000025 |
| 281 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB | |
| 255 | ; RELOC-NEXT: - Type: R_WASM_TABLE_INDEX_SLEB | |
| 282 | 256 | ; RELOC-NEXT: Index: 16 |
| 283 | 257 | ; RELOC-NEXT: Offset: 0x0000002E |
| 284 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB | |
| 258 | ; RELOC-NEXT: - Type: R_WASM_TABLE_INDEX_SLEB | |
| 285 | 259 | ; RELOC-NEXT: Index: 0 |
| 286 | 260 | ; RELOC-NEXT: Offset: 0x00000037 |
| 287 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB | |
| 261 | ; RELOC-NEXT: - Type: R_WASM_TABLE_INDEX_SLEB | |
| 288 | 262 | ; RELOC-NEXT: Index: 17 |
| 289 | 263 | ; RELOC-NEXT: Offset: 0x00000040 |
| 290 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB | |
| 264 | ; RELOC-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB | |
| 291 | 265 | ; RELOC-NEXT: Index: 10 |
| 292 | 266 | ; RELOC-NEXT: Offset: 0x00000058 |
| 293 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB | |
| 267 | ; RELOC-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB | |
| 294 | 268 | ; RELOC-NEXT: Index: 22 |
| 295 | 269 | ; RELOC-NEXT: Offset: 0x00000061 |
| 296 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB | |
| 270 | ; RELOC-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB | |
| 297 | 271 | ; RELOC-NEXT: Index: 23 |
| 298 | 272 | ; RELOC-NEXT: Offset: 0x0000006A |
| 299 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB | |
| 273 | ; RELOC-NEXT: - Type: R_WASM_TABLE_INDEX_SLEB | |
| 300 | 274 | ; RELOC-NEXT: Index: 8 |
| 301 | 275 | ; RELOC-NEXT: Offset: 0x00000073 |
| 302 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB | |
| 276 | ; RELOC-NEXT: - Type: R_WASM_TABLE_INDEX_SLEB | |
| 303 | 277 | ; RELOC-NEXT: Index: 20 |
| 304 | 278 | ; RELOC-NEXT: Offset: 0x0000007C |
| 305 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB | |
| 279 | ; RELOC-NEXT: - Type: R_WASM_TABLE_INDEX_SLEB | |
| 306 | 280 | ; RELOC-NEXT: Index: 21 |
| 307 | 281 | ; RELOC-NEXT: Offset: 0x00000085 |
| 308 | 282 | ; RELOC-NEXT: Functions: |
| ... | ... | @@ -363,19 +337,19 @@ |
| 363 | 337 | ; RELOC-NEXT: - Type: DATA |
| 364 | 338 | ; RELOC-NEXT: Segments: |
| 365 | 339 | ; RELOC-NEXT: - SectionOffset: 6 |
| 366 | ; RELOC-NEXT: MemoryIndex: 0 | |
| 340 | ; RELOC-NEXT: InitFlags: 0 | |
| 367 | 341 | ; RELOC-NEXT: Offset: |
| 368 | 342 | ; RELOC-NEXT: Opcode: I32_CONST |
| 369 | 343 | ; RELOC-NEXT: Value: 0 |
| 370 | 344 | ; RELOC-NEXT: Content: '0000000000000000' |
| 371 | 345 | ; RELOC-NEXT: - SectionOffset: 19 |
| 372 | ; RELOC-NEXT: MemoryIndex: 0 | |
| 346 | ; RELOC-NEXT: InitFlags: 0 | |
| 373 | 347 | ; RELOC-NEXT: Offset: |
| 374 | 348 | ; RELOC-NEXT: Opcode: I32_CONST |
| 375 | 349 | ; RELOC-NEXT: Value: 8 |
| 376 | 350 | ; RELOC-NEXT: Content: '0000000000000000' |
| 377 | 351 | ; RELOC-NEXT: - SectionOffset: 32 |
| 378 | ; RELOC-NEXT: MemoryIndex: 0 | |
| 352 | ; RELOC-NEXT: InitFlags: 0 | |
| 379 | 353 | ; RELOC-NEXT: Offset: |
| 380 | 354 | ; RELOC-NEXT: Opcode: I32_CONST |
| 381 | 355 | ; RELOC-NEXT: Value: 16 |
deps/lld/test/wasm/lto/archive.ll+1-3| ... | ... | @@ -18,8 +18,6 @@ declare void @f() |
| 18 | 18 | ; CHECK: Name: name |
| 19 | 19 | ; CHECK-NEXT: FunctionNames: |
| 20 | 20 | ; CHECK-NEXT: - Index: 0 |
| 21 | ; CHECK-NEXT: Name: __wasm_call_ctors | |
| 22 | ; CHECK-NEXT: - Index: 1 | |
| 23 | 21 | ; CHECK-NEXT: Name: _start |
| 24 | ; CHECK-NEXT: - Index: 2 | |
| 22 | ; CHECK-NEXT: - Index: 1 | |
| 25 | 23 | ; CHECK-NEXT: Name: f |
deps/lld/test/wasm/lto/atomics.ll+3-2| ... | ... | @@ -1,7 +1,8 @@ |
| 1 | 1 | ; RUN: llvm-as %s -o %t.o |
| 2 | 2 | ; RUN: wasm-ld %t.o -o %t.wasm -lto-O0 |
| 3 | ; Atomic operations with fail to compile if the ThreadModel is not | |
| 4 | ; correctly set to Single (i.e. if atomics are not lowered to regular ops). | |
| 3 | ||
| 4 | ; Atomic operations will not fail to compile if atomics are not | |
| 5 | ; enabled because LLVM atomics will be lowered to regular ops. | |
| 5 | 6 | |
| 6 | 7 | target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" |
| 7 | 8 | target triple = "wasm32-unknown-unknown-wasm" |
deps/lld/test/wasm/lto/comdat.ll created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | ; Verify that comdat symbols can be defined in LTO objects. We had a | |
| 2 | ; regression where the comdat handling code was causing symbol in the lto object | |
| 3 | ; to be ignored. | |
| 4 | ; RUN: llvm-as %s -o %t.bc | |
| 5 | ; RUN: llc -filetype=obj %s -o %t.o | |
| 6 | ; RUN: wasm-ld %t.bc %t.o -o %t.wasm | |
| 7 | ; RUN: wasm-ld %t.o %t.bc -o %t.wasm | |
| 8 | ||
| 9 | target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" | |
| 10 | target triple = "wasm32-unknown-unknown" | |
| 11 | ||
| 12 | $foo = comdat any | |
| 13 | ||
| 14 | define void @_start() comdat($foo) { | |
| 15 | entry: | |
| 16 | ret void | |
| 17 | } |
deps/lld/test/wasm/lto/export.ll+2-8| ... | ... | @@ -23,16 +23,10 @@ entry: |
| 23 | 23 | ; CHECK-NEXT: - Name: memory |
| 24 | 24 | ; CHECK-NEXT: Kind: MEMORY |
| 25 | 25 | ; CHECK-NEXT: Index: 0 |
| 26 | ; CHECK-NEXT: - Name: __heap_base | |
| 27 | ; CHECK-NEXT: Kind: GLOBAL | |
| 28 | ; CHECK-NEXT: Index: 1 | |
| 29 | ; CHECK-NEXT: - Name: __data_end | |
| 30 | ; CHECK-NEXT: Kind: GLOBAL | |
| 31 | ; CHECK-NEXT: Index: 2 | |
| 32 | 26 | ; CHECK-NEXT: - Name: hidden_function |
| 33 | 27 | ; CHECK-NEXT: Kind: FUNCTION |
| 34 | ; CHECK-NEXT: Index: 1 | |
| 28 | ; CHECK-NEXT: Index: 0 | |
| 35 | 29 | ; CHECK-NEXT: - Name: _start |
| 36 | 30 | ; CHECK-NEXT: Kind: FUNCTION |
| 37 | ; CHECK-NEXT: Index: 2 | |
| 31 | ; CHECK-NEXT: Index: 1 | |
| 38 | 32 | ; CHECK-NEXT: - Type: CODE |
deps/lld/test/wasm/lto/lto-start.ll-2| ... | ... | @@ -6,8 +6,6 @@ |
| 6 | 6 | ; CHECK-NEXT: Name: name |
| 7 | 7 | ; CHECK-NEXT: FunctionNames: |
| 8 | 8 | ; CHECK-NEXT: - Index: 0 |
| 9 | ; CHECK-NEXT: Name: __wasm_call_ctors | |
| 10 | ; CHECK-NEXT: - Index: 1 | |
| 11 | 9 | ; CHECK-NEXT: Name: _start |
| 12 | 10 | |
| 13 | 11 | target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" |
deps/lld/test/wasm/lto/opt-level.ll+2-2| ... | ... | @@ -7,11 +7,11 @@ |
| 7 | 7 | ; RUN: obj2yaml %t2a | FileCheck --check-prefix=CHECK-O2 %s |
| 8 | 8 | |
| 9 | 9 | ; Reject invalid optimization levels. |
| 10 | ; RUN: not ld.lld -o %t3 -e main --lto-O6 %t.o 2>&1 | \ | |
| 10 | ; RUN: not wasm-ld -o %t3 -e main --lto-O6 %t.o 2>&1 | \ | |
| 11 | 11 | ; RUN: FileCheck --check-prefix=INVALID %s |
| 12 | 12 | ; INVALID: invalid optimization level for LTO: 6 |
| 13 | 13 | |
| 14 | ; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --lto-O-1 %t.o 2>&1 | \ | |
| 14 | ; RUN: not wasm-ld -o %t3 -m elf_x86_64 -e main --lto-O-1 %t.o 2>&1 | \ | |
| 15 | 15 | ; RUN: FileCheck --check-prefix=INVALIDNEGATIVE %s |
| 16 | 16 | ; INVALIDNEGATIVE: invalid optimization level for LTO: 4294967295 |
| 17 | 17 |
deps/lld/test/wasm/lto/relocatable.ll created+27| ... | ... | @@ -0,0 +1,27 @@ |
| 1 | ; RUN: llvm-as %s -o %t1.o | |
| 2 | ; RUN: wasm-ld %t1.o -r -o %t | |
| 3 | ; RUN: llvm-readobj --symbols %t | FileCheck %s | |
| 4 | ||
| 5 | ; CHECK: Symbols [ | |
| 6 | ; CHECK-NEXT: Symbol { | |
| 7 | ; CHECK-NEXT: Name: foo | |
| 8 | ; CHECK-NEXT: Type: FUNCTION (0x0) | |
| 9 | ; CHECK-NEXT: Flags [ (0x0) | |
| 10 | ; CHECK-NEXT: ] | |
| 11 | ; CHECK-NEXT: ElementIndex: 0x0 | |
| 12 | ; CHECK-NEXT: } | |
| 13 | ; CHECK-NEXT: ] | |
| 14 | ||
| 15 | target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" | |
| 16 | target triple = "wasm32-unknown-unknown" | |
| 17 | ||
| 18 | define void @foo() { | |
| 19 | call void @bar() | |
| 20 | ret void | |
| 21 | } | |
| 22 | ||
| 23 | define internal void @bar() { | |
| 24 | ret void | |
| 25 | } | |
| 26 | ||
| 27 | declare i32 @baz(...) |
deps/lld/test/wasm/lto/signature-mismatch.ll+1| ... | ... | @@ -15,5 +15,6 @@ define void @_start() { |
| 15 | 15 | ret void |
| 16 | 16 | } |
| 17 | 17 | |
| 18 | ; CHECK: error: function signature mismatch: f | |
| 18 | 19 | ; CHECK: >>> defined as (i32) -> void in {{.*}}signature-mismatch.ll.tmp1.o |
| 19 | 20 | ; CHECK: >>> defined as () -> void in lto.tmp |
deps/lld/test/wasm/lto/undef.ll+18-2| ... | ... | @@ -5,10 +5,22 @@ |
| 5 | 5 | target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" |
| 6 | 6 | target triple = "wasm32-unknown-unknown" |
| 7 | 7 | |
| 8 | declare void @bar() | |
| 8 | declare i32 @bar() | |
| 9 | ||
| 10 | ; Symbols such as foo which are only called indirectly are handled slightly | |
| 11 | ; differently with resepect to signature checking. | |
| 12 | declare i32 @foo() | |
| 13 | ||
| 14 | @ptr = global i8* bitcast (i32 ()* @foo to i8*), align 8 | |
| 15 | ; Ensure access to ptr is not inlined below, even under LTO | |
| 16 | @llvm.used = appending global [1 x i8**] [i8** @ptr], section "llvm.metadata" | |
| 9 | 17 | |
| 10 | 18 | define void @_start() { |
| 11 | call void @bar() | |
| 19 | call i32 @bar() | |
| 20 | ||
| 21 | %addr = load i32 ()*, i32 ()** bitcast (i8** @ptr to i32 ()**), align 8 | |
| 22 | call i32 %addr() | |
| 23 | ||
| 12 | 24 | ret void |
| 13 | 25 | } |
| 14 | 26 | |
| ... | ... | @@ -18,3 +30,7 @@ define void @_start() { |
| 18 | 30 | ; CHECK-NEXT: Field: bar |
| 19 | 31 | ; CHECK-NEXT: Kind: FUNCTION |
| 20 | 32 | ; CHECK-NEXT: SigIndex: 0 |
| 33 | ; CHECK-NEXT: - Module: env | |
| 34 | ; CHECK-NEXT: Field: foo | |
| 35 | ; CHECK-NEXT: Kind: FUNCTION | |
| 36 | ; CHECK-NEXT: SigIndex: 0 |
deps/lld/test/wasm/lto/used.ll+2-4| ... | ... | @@ -28,7 +28,7 @@ return: |
| 28 | 28 | ; CHECK: - Type: DATA |
| 29 | 29 | ; CHECK-NEXT: Segments: |
| 30 | 30 | ; CHECK-NEXT: - SectionOffset: 7 |
| 31 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 31 | ; CHECK-NEXT: InitFlags: 0 | |
| 32 | 32 | ; CHECK-NEXT: Offset: |
| 33 | 33 | ; CHECK-NEXT: Opcode: I32_CONST |
| 34 | 34 | ; CHECK-NEXT: Value: 1024 |
| ... | ... | @@ -38,8 +38,6 @@ return: |
| 38 | 38 | ; CHECK-NEXT: Name: name |
| 39 | 39 | ; CHECK-NEXT: FunctionNames: |
| 40 | 40 | ; CHECK-NEXT: - Index: 0 |
| 41 | ; CHECK-NEXT: Name: __wasm_call_ctors | |
| 42 | ; CHECK-NEXT: - Index: 1 | |
| 43 | 41 | ; CHECK-NEXT: Name: _start |
| 44 | ; CHECK-NEXT: - Index: 2 | |
| 42 | ; CHECK-NEXT: - Index: 1 | |
| 45 | 43 | ; CHECK-NEXT: Name: bar |
deps/lld/test/wasm/lto/weak-undefined.ll created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | ; RUN: llvm-as %s -o %t.o | |
| 2 | ; RUN: wasm-ld %t.o -o %t.wasm | |
| 3 | ; RUN: obj2yaml %t.wasm | FileCheck %s | |
| 4 | ||
| 5 | ; Test that undefined weak external functions are handled in the LTO case | |
| 6 | ; We had a bug where stub function generation was failing because functions | |
| 7 | ; that are in bitcode (pre-LTO) don't have signatures assigned. | |
| 8 | ||
| 9 | target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" | |
| 10 | target triple = "wasm32-unknown-unknown" | |
| 11 | ||
| 12 | declare extern_weak i32 @foo() | |
| 13 | ||
| 14 | define void @_start() #0 { | |
| 15 | entry: | |
| 16 | %call2 = call i32 @foo() | |
| 17 | ret void | |
| 18 | } | |
| 19 | ||
| 20 | ; CHECK: Name: 'undefined:foo' |
deps/lld/test/wasm/lto/weak.ll+5-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | ; RUN: llvm-as %s -o %t.o |
| 2 | 2 | ; RUN: wasm-ld %t.o %t.o -o %t.wasm -r |
| 3 | ; RUN: llvm-readobj -t %t.wasm | FileCheck %s | |
| 3 | ; RUN: llvm-readobj --symbols %t.wasm | FileCheck %s | |
| 4 | 4 | |
| 5 | 5 | target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" |
| 6 | 6 | target triple = "wasm32-unknown-unknown-wasm" |
| ... | ... | @@ -12,5 +12,8 @@ define weak void @f() { |
| 12 | 12 | ; CHECK: Symbol { |
| 13 | 13 | ; CHECK-NEXT: Name: f |
| 14 | 14 | ; CHECK-NEXT: Type: FUNCTION (0x0) |
| 15 | ; CHECK-NEXT: Flags: 0x1 | |
| 15 | ; CHECK-NEXT: Flags [ (0x1) | |
| 16 | ; CHECK-NEXT: BINDING_WEAK (0x1) | |
| 17 | ; CHECK-NEXT: ] | |
| 18 | ; CHECK-NEXT: ElementIndex: 0x0 | |
| 16 | 19 | ; CHECK-NEXT: } |
deps/lld/test/wasm/many-functions.ll+132-132| ... | ... | @@ -18,394 +18,394 @@ entry: |
| 18 | 18 | |
| 19 | 19 | ; CHECK: - Type: CODE |
| 20 | 20 | ; CHECK-NEXT: Relocations: |
| 21 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 21 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 22 | 22 | ; CHECK-NEXT: Index: 1 |
| 23 | 23 | ; CHECK-NEXT: Offset: 0x00000008 |
| 24 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 24 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 25 | 25 | ; CHECK-NEXT: Index: 1 |
| 26 | 26 | ; CHECK-NEXT: Offset: 0x00000014 |
| 27 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 27 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 28 | 28 | ; CHECK-NEXT: Index: 1 |
| 29 | 29 | ; CHECK-NEXT: Offset: 0x00000020 |
| 30 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 30 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 31 | 31 | ; CHECK-NEXT: Index: 1 |
| 32 | 32 | ; CHECK-NEXT: Offset: 0x0000002C |
| 33 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 33 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 34 | 34 | ; CHECK-NEXT: Index: 1 |
| 35 | 35 | ; CHECK-NEXT: Offset: 0x00000038 |
| 36 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 36 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 37 | 37 | ; CHECK-NEXT: Index: 1 |
| 38 | 38 | ; CHECK-NEXT: Offset: 0x00000044 |
| 39 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 39 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 40 | 40 | ; CHECK-NEXT: Index: 1 |
| 41 | 41 | ; CHECK-NEXT: Offset: 0x00000050 |
| 42 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 42 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 43 | 43 | ; CHECK-NEXT: Index: 1 |
| 44 | 44 | ; CHECK-NEXT: Offset: 0x0000005C |
| 45 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 45 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 46 | 46 | ; CHECK-NEXT: Index: 1 |
| 47 | 47 | ; CHECK-NEXT: Offset: 0x00000068 |
| 48 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 48 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 49 | 49 | ; CHECK-NEXT: Index: 1 |
| 50 | 50 | ; CHECK-NEXT: Offset: 0x00000074 |
| 51 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 51 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 52 | 52 | ; CHECK-NEXT: Index: 1 |
| 53 | 53 | ; CHECK-NEXT: Offset: 0x00000080 |
| 54 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 54 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 55 | 55 | ; CHECK-NEXT: Index: 1 |
| 56 | 56 | ; CHECK-NEXT: Offset: 0x0000008C |
| 57 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 57 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 58 | 58 | ; CHECK-NEXT: Index: 1 |
| 59 | 59 | ; CHECK-NEXT: Offset: 0x00000098 |
| 60 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 60 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 61 | 61 | ; CHECK-NEXT: Index: 1 |
| 62 | 62 | ; CHECK-NEXT: Offset: 0x000000A4 |
| 63 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 63 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 64 | 64 | ; CHECK-NEXT: Index: 1 |
| 65 | 65 | ; CHECK-NEXT: Offset: 0x000000B0 |
| 66 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 66 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 67 | 67 | ; CHECK-NEXT: Index: 1 |
| 68 | 68 | ; CHECK-NEXT: Offset: 0x000000BC |
| 69 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 69 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 70 | 70 | ; CHECK-NEXT: Index: 1 |
| 71 | 71 | ; CHECK-NEXT: Offset: 0x000000C8 |
| 72 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 72 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 73 | 73 | ; CHECK-NEXT: Index: 1 |
| 74 | 74 | ; CHECK-NEXT: Offset: 0x000000D4 |
| 75 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 75 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 76 | 76 | ; CHECK-NEXT: Index: 1 |
| 77 | 77 | ; CHECK-NEXT: Offset: 0x000000E0 |
| 78 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 78 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 79 | 79 | ; CHECK-NEXT: Index: 1 |
| 80 | 80 | ; CHECK-NEXT: Offset: 0x000000EC |
| 81 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 81 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 82 | 82 | ; CHECK-NEXT: Index: 1 |
| 83 | 83 | ; CHECK-NEXT: Offset: 0x000000F8 |
| 84 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 84 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 85 | 85 | ; CHECK-NEXT: Index: 1 |
| 86 | 86 | ; CHECK-NEXT: Offset: 0x00000104 |
| 87 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 87 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 88 | 88 | ; CHECK-NEXT: Index: 1 |
| 89 | 89 | ; CHECK-NEXT: Offset: 0x00000110 |
| 90 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 90 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 91 | 91 | ; CHECK-NEXT: Index: 1 |
| 92 | 92 | ; CHECK-NEXT: Offset: 0x0000011C |
| 93 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 93 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 94 | 94 | ; CHECK-NEXT: Index: 1 |
| 95 | 95 | ; CHECK-NEXT: Offset: 0x00000128 |
| 96 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 96 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 97 | 97 | ; CHECK-NEXT: Index: 1 |
| 98 | 98 | ; CHECK-NEXT: Offset: 0x00000134 |
| 99 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 99 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 100 | 100 | ; CHECK-NEXT: Index: 1 |
| 101 | 101 | ; CHECK-NEXT: Offset: 0x00000140 |
| 102 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 102 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 103 | 103 | ; CHECK-NEXT: Index: 1 |
| 104 | 104 | ; CHECK-NEXT: Offset: 0x0000014C |
| 105 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 105 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 106 | 106 | ; CHECK-NEXT: Index: 1 |
| 107 | 107 | ; CHECK-NEXT: Offset: 0x00000158 |
| 108 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 108 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 109 | 109 | ; CHECK-NEXT: Index: 1 |
| 110 | 110 | ; CHECK-NEXT: Offset: 0x00000164 |
| 111 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 111 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 112 | 112 | ; CHECK-NEXT: Index: 1 |
| 113 | 113 | ; CHECK-NEXT: Offset: 0x00000170 |
| 114 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 114 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 115 | 115 | ; CHECK-NEXT: Index: 1 |
| 116 | 116 | ; CHECK-NEXT: Offset: 0x0000017C |
| 117 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 117 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 118 | 118 | ; CHECK-NEXT: Index: 1 |
| 119 | 119 | ; CHECK-NEXT: Offset: 0x00000188 |
| 120 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 120 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 121 | 121 | ; CHECK-NEXT: Index: 1 |
| 122 | 122 | ; CHECK-NEXT: Offset: 0x00000194 |
| 123 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 123 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 124 | 124 | ; CHECK-NEXT: Index: 1 |
| 125 | 125 | ; CHECK-NEXT: Offset: 0x000001A0 |
| 126 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 126 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 127 | 127 | ; CHECK-NEXT: Index: 1 |
| 128 | 128 | ; CHECK-NEXT: Offset: 0x000001AC |
| 129 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 129 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 130 | 130 | ; CHECK-NEXT: Index: 1 |
| 131 | 131 | ; CHECK-NEXT: Offset: 0x000001B8 |
| 132 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 132 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 133 | 133 | ; CHECK-NEXT: Index: 1 |
| 134 | 134 | ; CHECK-NEXT: Offset: 0x000001C4 |
| 135 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 135 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 136 | 136 | ; CHECK-NEXT: Index: 1 |
| 137 | 137 | ; CHECK-NEXT: Offset: 0x000001D0 |
| 138 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 138 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 139 | 139 | ; CHECK-NEXT: Index: 1 |
| 140 | 140 | ; CHECK-NEXT: Offset: 0x000001DC |
| 141 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 141 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 142 | 142 | ; CHECK-NEXT: Index: 1 |
| 143 | 143 | ; CHECK-NEXT: Offset: 0x000001E8 |
| 144 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 144 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 145 | 145 | ; CHECK-NEXT: Index: 1 |
| 146 | 146 | ; CHECK-NEXT: Offset: 0x000001F4 |
| 147 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 147 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 148 | 148 | ; CHECK-NEXT: Index: 1 |
| 149 | 149 | ; CHECK-NEXT: Offset: 0x00000200 |
| 150 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 150 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 151 | 151 | ; CHECK-NEXT: Index: 1 |
| 152 | 152 | ; CHECK-NEXT: Offset: 0x0000020C |
| 153 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 153 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 154 | 154 | ; CHECK-NEXT: Index: 1 |
| 155 | 155 | ; CHECK-NEXT: Offset: 0x00000218 |
| 156 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 156 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 157 | 157 | ; CHECK-NEXT: Index: 1 |
| 158 | 158 | ; CHECK-NEXT: Offset: 0x00000224 |
| 159 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 159 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 160 | 160 | ; CHECK-NEXT: Index: 1 |
| 161 | 161 | ; CHECK-NEXT: Offset: 0x00000230 |
| 162 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 162 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 163 | 163 | ; CHECK-NEXT: Index: 1 |
| 164 | 164 | ; CHECK-NEXT: Offset: 0x0000023C |
| 165 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 165 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 166 | 166 | ; CHECK-NEXT: Index: 1 |
| 167 | 167 | ; CHECK-NEXT: Offset: 0x00000248 |
| 168 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 168 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 169 | 169 | ; CHECK-NEXT: Index: 1 |
| 170 | 170 | ; CHECK-NEXT: Offset: 0x00000254 |
| 171 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 171 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 172 | 172 | ; CHECK-NEXT: Index: 1 |
| 173 | 173 | ; CHECK-NEXT: Offset: 0x00000260 |
| 174 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 174 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 175 | 175 | ; CHECK-NEXT: Index: 1 |
| 176 | 176 | ; CHECK-NEXT: Offset: 0x0000026C |
| 177 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 177 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 178 | 178 | ; CHECK-NEXT: Index: 1 |
| 179 | 179 | ; CHECK-NEXT: Offset: 0x00000278 |
| 180 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 180 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 181 | 181 | ; CHECK-NEXT: Index: 1 |
| 182 | 182 | ; CHECK-NEXT: Offset: 0x00000284 |
| 183 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 183 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 184 | 184 | ; CHECK-NEXT: Index: 1 |
| 185 | 185 | ; CHECK-NEXT: Offset: 0x00000290 |
| 186 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 186 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 187 | 187 | ; CHECK-NEXT: Index: 1 |
| 188 | 188 | ; CHECK-NEXT: Offset: 0x0000029C |
| 189 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 189 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 190 | 190 | ; CHECK-NEXT: Index: 1 |
| 191 | 191 | ; CHECK-NEXT: Offset: 0x000002A8 |
| 192 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 192 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 193 | 193 | ; CHECK-NEXT: Index: 1 |
| 194 | 194 | ; CHECK-NEXT: Offset: 0x000002B4 |
| 195 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 195 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 196 | 196 | ; CHECK-NEXT: Index: 1 |
| 197 | 197 | ; CHECK-NEXT: Offset: 0x000002C0 |
| 198 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 198 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 199 | 199 | ; CHECK-NEXT: Index: 1 |
| 200 | 200 | ; CHECK-NEXT: Offset: 0x000002CC |
| 201 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 201 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 202 | 202 | ; CHECK-NEXT: Index: 1 |
| 203 | 203 | ; CHECK-NEXT: Offset: 0x000002D8 |
| 204 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 204 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 205 | 205 | ; CHECK-NEXT: Index: 1 |
| 206 | 206 | ; CHECK-NEXT: Offset: 0x000002E4 |
| 207 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 207 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 208 | 208 | ; CHECK-NEXT: Index: 1 |
| 209 | 209 | ; CHECK-NEXT: Offset: 0x000002F0 |
| 210 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 210 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 211 | 211 | ; CHECK-NEXT: Index: 1 |
| 212 | 212 | ; CHECK-NEXT: Offset: 0x000002FC |
| 213 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 213 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 214 | 214 | ; CHECK-NEXT: Index: 1 |
| 215 | 215 | ; CHECK-NEXT: Offset: 0x00000308 |
| 216 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 216 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 217 | 217 | ; CHECK-NEXT: Index: 1 |
| 218 | 218 | ; CHECK-NEXT: Offset: 0x00000314 |
| 219 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 219 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 220 | 220 | ; CHECK-NEXT: Index: 1 |
| 221 | 221 | ; CHECK-NEXT: Offset: 0x00000320 |
| 222 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 222 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 223 | 223 | ; CHECK-NEXT: Index: 1 |
| 224 | 224 | ; CHECK-NEXT: Offset: 0x0000032C |
| 225 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 225 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 226 | 226 | ; CHECK-NEXT: Index: 1 |
| 227 | 227 | ; CHECK-NEXT: Offset: 0x00000338 |
| 228 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 228 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 229 | 229 | ; CHECK-NEXT: Index: 1 |
| 230 | 230 | ; CHECK-NEXT: Offset: 0x00000344 |
| 231 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 231 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 232 | 232 | ; CHECK-NEXT: Index: 1 |
| 233 | 233 | ; CHECK-NEXT: Offset: 0x00000350 |
| 234 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 234 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 235 | 235 | ; CHECK-NEXT: Index: 1 |
| 236 | 236 | ; CHECK-NEXT: Offset: 0x0000035C |
| 237 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 237 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 238 | 238 | ; CHECK-NEXT: Index: 1 |
| 239 | 239 | ; CHECK-NEXT: Offset: 0x00000368 |
| 240 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 240 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 241 | 241 | ; CHECK-NEXT: Index: 1 |
| 242 | 242 | ; CHECK-NEXT: Offset: 0x00000374 |
| 243 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 243 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 244 | 244 | ; CHECK-NEXT: Index: 1 |
| 245 | 245 | ; CHECK-NEXT: Offset: 0x00000380 |
| 246 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 246 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 247 | 247 | ; CHECK-NEXT: Index: 1 |
| 248 | 248 | ; CHECK-NEXT: Offset: 0x0000038C |
| 249 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 249 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 250 | 250 | ; CHECK-NEXT: Index: 1 |
| 251 | 251 | ; CHECK-NEXT: Offset: 0x00000398 |
| 252 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 252 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 253 | 253 | ; CHECK-NEXT: Index: 1 |
| 254 | 254 | ; CHECK-NEXT: Offset: 0x000003A4 |
| 255 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 255 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 256 | 256 | ; CHECK-NEXT: Index: 1 |
| 257 | 257 | ; CHECK-NEXT: Offset: 0x000003B0 |
| 258 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 258 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 259 | 259 | ; CHECK-NEXT: Index: 1 |
| 260 | 260 | ; CHECK-NEXT: Offset: 0x000003BC |
| 261 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 261 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 262 | 262 | ; CHECK-NEXT: Index: 1 |
| 263 | 263 | ; CHECK-NEXT: Offset: 0x000003C8 |
| 264 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 264 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 265 | 265 | ; CHECK-NEXT: Index: 1 |
| 266 | 266 | ; CHECK-NEXT: Offset: 0x000003D4 |
| 267 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 267 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 268 | 268 | ; CHECK-NEXT: Index: 1 |
| 269 | 269 | ; CHECK-NEXT: Offset: 0x000003E0 |
| 270 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 270 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 271 | 271 | ; CHECK-NEXT: Index: 1 |
| 272 | 272 | ; CHECK-NEXT: Offset: 0x000003EC |
| 273 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 273 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 274 | 274 | ; CHECK-NEXT: Index: 1 |
| 275 | 275 | ; CHECK-NEXT: Offset: 0x000003F8 |
| 276 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 276 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 277 | 277 | ; CHECK-NEXT: Index: 1 |
| 278 | 278 | ; CHECK-NEXT: Offset: 0x00000404 |
| 279 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 279 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 280 | 280 | ; CHECK-NEXT: Index: 1 |
| 281 | 281 | ; CHECK-NEXT: Offset: 0x00000410 |
| 282 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 282 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 283 | 283 | ; CHECK-NEXT: Index: 1 |
| 284 | 284 | ; CHECK-NEXT: Offset: 0x0000041C |
| 285 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 285 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 286 | 286 | ; CHECK-NEXT: Index: 1 |
| 287 | 287 | ; CHECK-NEXT: Offset: 0x00000428 |
| 288 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 288 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 289 | 289 | ; CHECK-NEXT: Index: 1 |
| 290 | 290 | ; CHECK-NEXT: Offset: 0x00000434 |
| 291 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 291 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 292 | 292 | ; CHECK-NEXT: Index: 1 |
| 293 | 293 | ; CHECK-NEXT: Offset: 0x00000440 |
| 294 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 294 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 295 | 295 | ; CHECK-NEXT: Index: 1 |
| 296 | 296 | ; CHECK-NEXT: Offset: 0x0000044C |
| 297 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 297 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 298 | 298 | ; CHECK-NEXT: Index: 1 |
| 299 | 299 | ; CHECK-NEXT: Offset: 0x00000458 |
| 300 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 300 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 301 | 301 | ; CHECK-NEXT: Index: 1 |
| 302 | 302 | ; CHECK-NEXT: Offset: 0x00000464 |
| 303 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 303 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 304 | 304 | ; CHECK-NEXT: Index: 1 |
| 305 | 305 | ; CHECK-NEXT: Offset: 0x00000470 |
| 306 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 306 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 307 | 307 | ; CHECK-NEXT: Index: 1 |
| 308 | 308 | ; CHECK-NEXT: Offset: 0x0000047C |
| 309 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 309 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 310 | 310 | ; CHECK-NEXT: Index: 1 |
| 311 | 311 | ; CHECK-NEXT: Offset: 0x00000488 |
| 312 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 312 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 313 | 313 | ; CHECK-NEXT: Index: 1 |
| 314 | 314 | ; CHECK-NEXT: Offset: 0x00000494 |
| 315 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 315 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 316 | 316 | ; CHECK-NEXT: Index: 1 |
| 317 | 317 | ; CHECK-NEXT: Offset: 0x000004A0 |
| 318 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 318 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 319 | 319 | ; CHECK-NEXT: Index: 1 |
| 320 | 320 | ; CHECK-NEXT: Offset: 0x000004AC |
| 321 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 321 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 322 | 322 | ; CHECK-NEXT: Index: 1 |
| 323 | 323 | ; CHECK-NEXT: Offset: 0x000004B8 |
| 324 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 324 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 325 | 325 | ; CHECK-NEXT: Index: 1 |
| 326 | 326 | ; CHECK-NEXT: Offset: 0x000004C4 |
| 327 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 327 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 328 | 328 | ; CHECK-NEXT: Index: 1 |
| 329 | 329 | ; CHECK-NEXT: Offset: 0x000004D0 |
| 330 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 330 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 331 | 331 | ; CHECK-NEXT: Index: 1 |
| 332 | 332 | ; CHECK-NEXT: Offset: 0x000004DC |
| 333 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 333 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 334 | 334 | ; CHECK-NEXT: Index: 1 |
| 335 | 335 | ; CHECK-NEXT: Offset: 0x000004E8 |
| 336 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 336 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 337 | 337 | ; CHECK-NEXT: Index: 1 |
| 338 | 338 | ; CHECK-NEXT: Offset: 0x000004F4 |
| 339 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 339 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 340 | 340 | ; CHECK-NEXT: Index: 1 |
| 341 | 341 | ; CHECK-NEXT: Offset: 0x00000500 |
| 342 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 342 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 343 | 343 | ; CHECK-NEXT: Index: 1 |
| 344 | 344 | ; CHECK-NEXT: Offset: 0x0000050C |
| 345 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 345 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 346 | 346 | ; CHECK-NEXT: Index: 1 |
| 347 | 347 | ; CHECK-NEXT: Offset: 0x00000518 |
| 348 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 348 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 349 | 349 | ; CHECK-NEXT: Index: 1 |
| 350 | 350 | ; CHECK-NEXT: Offset: 0x00000524 |
| 351 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 351 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 352 | 352 | ; CHECK-NEXT: Index: 1 |
| 353 | 353 | ; CHECK-NEXT: Offset: 0x00000530 |
| 354 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 354 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 355 | 355 | ; CHECK-NEXT: Index: 1 |
| 356 | 356 | ; CHECK-NEXT: Offset: 0x0000053C |
| 357 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 357 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 358 | 358 | ; CHECK-NEXT: Index: 1 |
| 359 | 359 | ; CHECK-NEXT: Offset: 0x00000548 |
| 360 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 360 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 361 | 361 | ; CHECK-NEXT: Index: 1 |
| 362 | 362 | ; CHECK-NEXT: Offset: 0x00000554 |
| 363 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 363 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 364 | 364 | ; CHECK-NEXT: Index: 1 |
| 365 | 365 | ; CHECK-NEXT: Offset: 0x00000560 |
| 366 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 366 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 367 | 367 | ; CHECK-NEXT: Index: 1 |
| 368 | 368 | ; CHECK-NEXT: Offset: 0x0000056C |
| 369 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 369 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 370 | 370 | ; CHECK-NEXT: Index: 1 |
| 371 | 371 | ; CHECK-NEXT: Offset: 0x00000578 |
| 372 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 372 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 373 | 373 | ; CHECK-NEXT: Index: 1 |
| 374 | 374 | ; CHECK-NEXT: Offset: 0x00000584 |
| 375 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 375 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 376 | 376 | ; CHECK-NEXT: Index: 1 |
| 377 | 377 | ; CHECK-NEXT: Offset: 0x00000590 |
| 378 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 378 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 379 | 379 | ; CHECK-NEXT: Index: 1 |
| 380 | 380 | ; CHECK-NEXT: Offset: 0x0000059C |
| 381 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 381 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 382 | 382 | ; CHECK-NEXT: Index: 1 |
| 383 | 383 | ; CHECK-NEXT: Offset: 0x000005A8 |
| 384 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 384 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 385 | 385 | ; CHECK-NEXT: Index: 1 |
| 386 | 386 | ; CHECK-NEXT: Offset: 0x000005B4 |
| 387 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 387 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 388 | 388 | ; CHECK-NEXT: Index: 1 |
| 389 | 389 | ; CHECK-NEXT: Offset: 0x000005C0 |
| 390 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 390 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 391 | 391 | ; CHECK-NEXT: Index: 1 |
| 392 | 392 | ; CHECK-NEXT: Offset: 0x000005CC |
| 393 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 393 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 394 | 394 | ; CHECK-NEXT: Index: 1 |
| 395 | 395 | ; CHECK-NEXT: Offset: 0x000005D8 |
| 396 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 396 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 397 | 397 | ; CHECK-NEXT: Index: 1 |
| 398 | 398 | ; CHECK-NEXT: Offset: 0x000005E4 |
| 399 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 399 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 400 | 400 | ; CHECK-NEXT: Index: 1 |
| 401 | 401 | ; CHECK-NEXT: Offset: 0x000005F0 |
| 402 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 402 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 403 | 403 | ; CHECK-NEXT: Index: 129 |
| 404 | 404 | ; CHECK-NEXT: Offset: 0x000005FC |
| 405 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB | |
| 405 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB | |
| 406 | 406 | ; CHECK-NEXT: Index: 129 |
| 407 | 407 | ; CHECK-NEXT: Offset: 0x00000608 |
| 408 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB | |
| 408 | ; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB | |
| 409 | 409 | ; CHECK-NEXT: Index: 131 |
| 410 | 410 | ; CHECK-NEXT: Offset: 0x00000611 |
| 411 | 411 | ; CHECK-NEXT: Functions: |
| ... | ... | @@ -802,13 +802,13 @@ entry: |
| 802 | 802 | ; CHECK-NEXT: - Type: DATA |
| 803 | 803 | ; CHECK-NEXT: Segments: |
| 804 | 804 | ; CHECK-NEXT: - SectionOffset: 6 |
| 805 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 805 | ; CHECK-NEXT: InitFlags: 0 | |
| 806 | 806 | ; CHECK-NEXT: Offset: |
| 807 | 807 | ; CHECK-NEXT: Opcode: I32_CONST |
| 808 | 808 | ; CHECK-NEXT: Value: 0 |
| 809 | 809 | ; CHECK-NEXT: Content: '01000000' |
| 810 | 810 | ; CHECK-NEXT: - SectionOffset: 15 |
| 811 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 811 | ; CHECK-NEXT: InitFlags: 0 | |
| 812 | 812 | ; CHECK-NEXT: Offset: |
| 813 | 813 | ; CHECK-NEXT: Opcode: I32_CONST |
| 814 | 814 | ; CHECK-NEXT: Value: 4 |
deps/lld/test/wasm/pie.ll created+58| ... | ... | @@ -0,0 +1,58 @@ |
| 1 | ; RUN: llc -relocation-model=pic -filetype=obj %s -o %t.o | |
| 2 | ; RUN: wasm-ld --no-gc-sections --allow-undefined -pie -o %t.wasm %t.o | |
| 3 | ; RUN: obj2yaml %t.wasm | FileCheck %s | |
| 4 | ||
| 5 | target triple = "wasm32-unknown-emscripten" | |
| 6 | ||
| 7 | @data = global i32 2, align 4 | |
| 8 | @data_external = external global i32 | |
| 9 | @indirect_func = local_unnamed_addr global i32 ()* @foo, align 4 | |
| 10 | ||
| 11 | @data_addr = local_unnamed_addr global i32* @data, align 4 | |
| 12 | @data_addr_external = local_unnamed_addr global i32* @data_external, align 4 | |
| 13 | ||
| 14 | define hidden i32 @foo() { | |
| 15 | entry: | |
| 16 | ; To ensure we use __stack_pointer | |
| 17 | %ptr = alloca i32 | |
| 18 | %0 = load i32, i32* @data, align 4 | |
| 19 | %1 = load i32 ()*, i32 ()** @indirect_func, align 4 | |
| 20 | call i32 %1() | |
| 21 | ret i32 %0 | |
| 22 | } | |
| 23 | ||
| 24 | define default i32** @get_data_address() { | |
| 25 | entry: | |
| 26 | ret i32** @data_addr_external | |
| 27 | } | |
| 28 | ||
| 29 | define void @_start() { | |
| 30 | ret void | |
| 31 | } | |
| 32 | ||
| 33 | ; CHECK: - Type: IMPORT | |
| 34 | ; CHECK-NEXT: Imports: | |
| 35 | ; CHECK-NEXT: - Module: env | |
| 36 | ; CHECK-NEXT: Field: __indirect_function_table | |
| 37 | ; CHECK-NEXT: Kind: TABLE | |
| 38 | ; CHECK-NEXT: Table: | |
| 39 | ; CHECK-NEXT: ElemType: FUNCREF | |
| 40 | ; CHECK-NEXT: Limits: | |
| 41 | ; CHECK-NEXT: Initial: 0x00000001 | |
| 42 | ; CHECK-NEXT: - Module: env | |
| 43 | ; CHECK-NEXT: Field: __stack_pointer | |
| 44 | ; CHECK-NEXT: Kind: GLOBAL | |
| 45 | ; CHECK-NEXT: GlobalType: I32 | |
| 46 | ; CHECK-NEXT: GlobalMutable: true | |
| 47 | ; CHECK-NEXT: - Module: env | |
| 48 | ; CHECK-NEXT: Field: __memory_base | |
| 49 | ; CHECK-NEXT: Kind: GLOBAL | |
| 50 | ; CHECK-NEXT: GlobalType: I32 | |
| 51 | ; CHECK-NEXT: GlobalMutable: false | |
| 52 | ; CHECK-NEXT: - Module: env | |
| 53 | ; CHECK-NEXT: Field: __table_base | |
| 54 | ; CHECK-NEXT: Kind: GLOBAL | |
| 55 | ; CHECK-NEXT: GlobalType: I32 | |
| 56 | ; CHECK-NEXT: GlobalMutable: false | |
| 57 | ||
| 58 |
deps/lld/test/wasm/reloc-addend.ll+1-1| ... | ... | @@ -13,7 +13,7 @@ target triple = "wasm32-unknown-unknown" |
| 13 | 13 | |
| 14 | 14 | ; CHECK: - Type: DATA |
| 15 | 15 | ; CHECK-NEXT: Relocations: |
| 16 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32 | |
| 16 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_I32 | |
| 17 | 17 | ; CHECK-NEXT: Index: 0 |
| 18 | 18 | ; CHECK-NEXT: Offset: 0x0000013D |
| 19 | 19 | ; CHECK-NEXT: Addend: 64 |
deps/lld/test/wasm/relocatable.ll+15-15| ... | ... | @@ -79,19 +79,19 @@ entry: |
| 79 | 79 | ; CHECK-NEXT: Functions: [ 4, 1, 2 ] |
| 80 | 80 | ; CHECK-NEXT: - Type: CODE |
| 81 | 81 | ; CHECK-NEXT: Relocations: |
| 82 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB | |
| 82 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB | |
| 83 | 83 | ; CHECK-NEXT: Index: 1 |
| 84 | 84 | ; CHECK-NEXT: Offset: 0x00000004 |
| 85 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB | |
| 85 | ; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB | |
| 86 | 86 | ; CHECK-NEXT: Index: 2 |
| 87 | 87 | ; CHECK-NEXT: Offset: 0x0000000A |
| 88 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB | |
| 88 | ; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB | |
| 89 | 89 | ; CHECK-NEXT: Index: 4 |
| 90 | 90 | ; CHECK-NEXT: Offset: 0x00000013 |
| 91 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB | |
| 91 | ; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB | |
| 92 | 92 | ; CHECK-NEXT: Index: 5 |
| 93 | 93 | ; CHECK-NEXT: Offset: 0x0000001A |
| 94 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB | |
| 94 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB | |
| 95 | 95 | ; CHECK-NEXT: Index: 7 |
| 96 | 96 | ; CHECK-NEXT: Offset: 0x00000026 |
| 97 | 97 | ; CHECK-NEXT: Functions: |
| ... | ... | @@ -106,51 +106,51 @@ entry: |
| 106 | 106 | ; CHECK-NEXT: Body: 419C808080000B |
| 107 | 107 | ; CHECK-NEXT: - Type: DATA |
| 108 | 108 | ; CHECK-NEXT: Relocations: |
| 109 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32 | |
| 109 | ; CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_I32 | |
| 110 | 110 | ; CHECK-NEXT: Index: 3 |
| 111 | 111 | ; CHECK-NEXT: Offset: 0x00000012 |
| 112 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32 | |
| 112 | ; CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_I32 | |
| 113 | 113 | ; CHECK-NEXT: Index: 4 |
| 114 | 114 | ; CHECK-NEXT: Offset: 0x0000001B |
| 115 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32 | |
| 115 | ; CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_I32 | |
| 116 | 116 | ; CHECK-NEXT: Index: 5 |
| 117 | 117 | ; CHECK-NEXT: Offset: 0x00000024 |
| 118 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32 | |
| 118 | ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_I32 | |
| 119 | 119 | ; CHECK-NEXT: Index: 12 |
| 120 | 120 | ; CHECK-NEXT: Offset: 0x0000002D |
| 121 | 121 | ; CHECK-NEXT: Segments: |
| 122 | 122 | ; CHECK-NEXT: - SectionOffset: 6 |
| 123 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 123 | ; CHECK-NEXT: InitFlags: 0 | |
| 124 | 124 | ; CHECK-NEXT: Offset: |
| 125 | 125 | ; CHECK-NEXT: Opcode: I32_CONST |
| 126 | 126 | ; CHECK-NEXT: Value: 0 |
| 127 | 127 | ; CHECK-NEXT: Content: 68656C6C6F0A00 |
| 128 | 128 | ; CHECK-NEXT: - SectionOffset: 18 |
| 129 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 129 | ; CHECK-NEXT: InitFlags: 0 | |
| 130 | 130 | ; CHECK-NEXT: Offset: |
| 131 | 131 | ; CHECK-NEXT: Opcode: I32_CONST |
| 132 | 132 | ; CHECK-NEXT: Value: 8 |
| 133 | 133 | ; CHECK-NEXT: Content: '01000000' |
| 134 | 134 | ; CHECK-NEXT: - SectionOffset: 27 |
| 135 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 135 | ; CHECK-NEXT: InitFlags: 0 | |
| 136 | 136 | ; CHECK-NEXT: Offset: |
| 137 | 137 | ; CHECK-NEXT: Opcode: I32_CONST |
| 138 | 138 | ; CHECK-NEXT: Value: 12 |
| 139 | 139 | ; CHECK-NEXT: Content: '02000000' |
| 140 | 140 | ; CHECK-NEXT: - SectionOffset: 36 |
| 141 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 141 | ; CHECK-NEXT: InitFlags: 0 | |
| 142 | 142 | ; CHECK-NEXT: Offset: |
| 143 | 143 | ; CHECK-NEXT: Opcode: I32_CONST |
| 144 | 144 | ; CHECK-NEXT: Value: 16 |
| 145 | 145 | ; CHECK-NEXT: Content: '03000000' |
| 146 | 146 | ; CHECK-NEXT: - SectionOffset: 45 |
| 147 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 147 | ; CHECK-NEXT: InitFlags: 0 | |
| 148 | 148 | ; CHECK-NEXT: Offset: |
| 149 | 149 | ; CHECK-NEXT: Opcode: I32_CONST |
| 150 | 150 | ; CHECK-NEXT: Value: 24 |
| 151 | 151 | ; CHECK-NEXT: Content: '00000000' |
| 152 | 152 | ; CHECK-NEXT: - SectionOffset: 54 |
| 153 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 153 | ; CHECK-NEXT: InitFlags: 0 | |
| 154 | 154 | ; CHECK-NEXT: Offset: |
| 155 | 155 | ; CHECK-NEXT: Opcode: I32_CONST |
| 156 | 156 | ; CHECK-NEXT: Value: 28 |
deps/lld/test/wasm/reproduce.ll created+27| ... | ... | @@ -0,0 +1,27 @@ |
| 1 | ; REQUIRES: shell | |
| 2 | ; RUN: rm -rf %t.dir | |
| 3 | ; RUN: mkdir -p %t.dir | |
| 4 | ; RUN: llc -filetype=obj %s -o %t.dir/foo.o | |
| 5 | ; RUN: wasm-ld --reproduce=%t.dir/repro.tar -o %t.dir/out.wasm %t.dir/foo.o | |
| 6 | ||
| 7 | ; RUN: cd %t.dir | |
| 8 | ; RUN: tar tf repro.tar | FileCheck --check-prefix=TAR %s | |
| 9 | ||
| 10 | ; TAR: repro/response.txt | |
| 11 | ; TAR: repro/version.txt | |
| 12 | ; TAR: repro/{{.*}}/foo.o | |
| 13 | ||
| 14 | ; RUN: tar xf repro.tar | |
| 15 | ; RUN: FileCheck --check-prefix=RSP %s < repro/response.txt | |
| 16 | ||
| 17 | ; RSP: -o {{.*}}out.wasm | |
| 18 | ; RSP: {{.*}}/foo.o | |
| 19 | ||
| 20 | ; RUN: FileCheck %s --check-prefix=VERSION < repro/version.txt | |
| 21 | ; VERSION: LLD | |
| 22 | ||
| 23 | target triple = "wasm32-unknown-unknown" | |
| 24 | ||
| 25 | define void @_start() { | |
| 26 | ret void | |
| 27 | } |
deps/lld/test/wasm/section-symbol-relocs.yaml created+61| ... | ... | @@ -0,0 +1,61 @@ |
| 1 | # RUN: yaml2obj %s -o %t.o | |
| 2 | # RUN: llc -filetype=obj %S/Inputs/custom.ll -o %t2.o | |
| 3 | # RUN: wasm-ld --no-entry -o - %t2.o %t.o | obj2yaml | FileCheck %s | |
| 4 | # RUN: wasm-ld -r --no-entry -o - %t2.o %t.o | obj2yaml | FileCheck %s -check-prefix=RELOC | |
| 5 | ||
| 6 | --- !WASM | |
| 7 | FileHeader: | |
| 8 | Version: 0x00000001 | |
| 9 | Sections: | |
| 10 | - Type: CUSTOM | |
| 11 | Name: green | |
| 12 | Payload: 'AA0000000000000000' | |
| 13 | Relocations: | |
| 14 | - Type: R_WASM_SECTION_OFFSET_I32 | |
| 15 | Index: 0 | |
| 16 | Offset: 0x00000001 | |
| 17 | - Type: R_WASM_SECTION_OFFSET_I32 | |
| 18 | Index: 1 | |
| 19 | Offset: 0x00000005 | |
| 20 | - Type: CUSTOM | |
| 21 | Name: red | |
| 22 | Payload: 'BB0000000000000000' | |
| 23 | - Type: CUSTOM | |
| 24 | Name: linking | |
| 25 | Version: 2 | |
| 26 | SymbolTable: | |
| 27 | - Index: 0 | |
| 28 | Kind: SECTION | |
| 29 | Section: 0 | |
| 30 | Flags: [ BINDING_LOCAL ] | |
| 31 | - Index: 1 | |
| 32 | Kind: SECTION | |
| 33 | Section: 1 | |
| 34 | Flags: [ BINDING_LOCAL ] | |
| 35 | ... | |
| 36 | ||
| 37 | # CHECK: Name: green | |
| 38 | # CHECK-NEXT: Payload: 626172717578AA0600000003000000 | |
| 39 | # CHECK: Name: red | |
| 40 | # CHECK-NEXT: Payload: 666F6FBB0000000000000000 | |
| 41 | ||
| 42 | # RELOC: Relocations: | |
| 43 | # RELOC-NEXT: - Type: R_WASM_SECTION_OFFSET_I32 | |
| 44 | # RELOC-NEXT: Index: 0 | |
| 45 | # RELOC-NEXT: Offset: 0x00000007 | |
| 46 | # RELOC-NEXT: Addend: 6 | |
| 47 | # RELOC-NEXT: - Type: R_WASM_SECTION_OFFSET_I32 | |
| 48 | # RELOC-NEXT: Index: 1 | |
| 49 | # RELOC-NEXT: Offset: 0x0000000B | |
| 50 | # RELOC-NEXT: Addend: 3 | |
| 51 | # RELOC-NEXT: Name: green | |
| 52 | # | |
| 53 | # RELOC: SymbolTable: | |
| 54 | # RELOC-NEXT: - Index: 0 | |
| 55 | # RELOC-NEXT: Kind: SECTION | |
| 56 | # RELOC-NEXT: Flags: [ BINDING_LOCAL ] | |
| 57 | # RELOC-NEXT: Section: 2 | |
| 58 | # RELOC-NEXT: - Index: 1 | |
| 59 | # RELOC-NEXT: Kind: SECTION | |
| 60 | # RELOC-NEXT: Flags: [ BINDING_LOCAL ] | |
| 61 | # RELOC-NEXT: Section: 3 |
deps/lld/test/wasm/shared-memory-no-atomics.yaml created+60| ... | ... | @@ -0,0 +1,60 @@ |
| 1 | # RUN: yaml2obj %s -o %t1.o | |
| 2 | ||
| 3 | # RUN: wasm-ld --no-entry %t1.o -o - | obj2yaml | FileCheck %s --check-prefix NO-SHARED | |
| 4 | ||
| 5 | # RUN: not wasm-ld --no-entry --shared-memory --max-memory=131072 %t1.o -o - 2>&1 | FileCheck %s --check-prefix SHARED | |
| 6 | ||
| 7 | --- !WASM | |
| 8 | FileHeader: | |
| 9 | Version: 0x00000001 | |
| 10 | Sections: | |
| 11 | - Type: IMPORT | |
| 12 | Imports: | |
| 13 | - Module: env | |
| 14 | Field: __linear_memory | |
| 15 | Kind: MEMORY | |
| 16 | Memory: | |
| 17 | Initial: 0x00000001 | |
| 18 | - Module: env | |
| 19 | Field: __indirect_function_table | |
| 20 | Kind: TABLE | |
| 21 | Table: | |
| 22 | ElemType: FUNCREF | |
| 23 | Limits: | |
| 24 | Initial: 0x00000000 | |
| 25 | - Type: DATA | |
| 26 | Segments: | |
| 27 | - SectionOffset: 6 | |
| 28 | InitFlags: 0 | |
| 29 | Offset: | |
| 30 | Opcode: I32_CONST | |
| 31 | Value: 0 | |
| 32 | Content: 68656C6C6F0A00 | |
| 33 | - Type: CUSTOM | |
| 34 | Name: linking | |
| 35 | Version: 2 | |
| 36 | SymbolTable: | |
| 37 | - Index: 0 | |
| 38 | Kind: DATA | |
| 39 | Name: hello_str | |
| 40 | Flags: [ ] | |
| 41 | Segment: 0 | |
| 42 | Size: 7 | |
| 43 | SegmentInfo: | |
| 44 | - Index: 0 | |
| 45 | Name: .rodata.hello_str | |
| 46 | Alignment: 0 | |
| 47 | Flags: [ ] | |
| 48 | - Type: CUSTOM | |
| 49 | Name: target_features | |
| 50 | Features: | |
| 51 | - Prefix: DISALLOWED | |
| 52 | Name: "atomics" | |
| 53 | ... | |
| 54 | ||
| 55 | # NO-SHARED: - Type: MEMORY | |
| 56 | # NO-SHARED-NEXT: Memories: | |
| 57 | # NO-SHARED-NEXT: - Initial: 0x00000002 | |
| 58 | # NO-SHARED-NOT: Maximum: | |
| 59 | ||
| 60 | # SHARED: 'atomics' feature is disallowed by {{.*}}shared-memory-no-atomics.yaml.tmp1.o, so --shared-memory must not be used{{$}} |
deps/lld/test/wasm/shared-memory.yaml created+75| ... | ... | @@ -0,0 +1,75 @@ |
| 1 | # RUN: yaml2obj %s -o %t1.o | |
| 2 | ||
| 3 | # RUN: not wasm-ld --no-entry --shared-memory --active-segments %t1.o -o - 2>&1 | FileCheck %s --check-prefix SHARED-NO-MAX | |
| 4 | ||
| 5 | # RUN: not wasm-ld --no-entry --shared-memory --active-segments --max-memory=100000 %t1.o -o - 2>&1 | FileCheck %s --check-prefix SHARED-UNALIGNED | |
| 6 | ||
| 7 | # RUN: wasm-ld --no-entry --shared-memory --active-segments --max-memory=131072 %t1.o -o - | obj2yaml | FileCheck %s --check-prefix SHARED | |
| 8 | ||
| 9 | # RUN: not wasm-ld --no-entry --features=atomics %t1.o -o - 2>&1 | FileCheck %s --check-prefix ATOMICS-NO-SHARED | |
| 10 | ||
| 11 | # RUN: not wasm-ld --no-entry --features=atomics --shared-memory --active-segments %t1.o -o - 2>&1 | FileCheck %s --check-prefix ATOMICS-NO-MAX | |
| 12 | ||
| 13 | # RUN: not wasm-ld --no-entry --features=atomics --shared-memory --active-segments --max-memory=100000 %t1.o -o - 2>&1 | FileCheck %s --check-prefix ATOMICS-UNALIGNED | |
| 14 | ||
| 15 | # RUN: wasm-ld --no-entry --features=atomics --shared-memory --active-segments --max-memory=131072 %t1.o -o - | obj2yaml | FileCheck %s --check-prefix SHARED | |
| 16 | ||
| 17 | ||
| 18 | --- !WASM | |
| 19 | FileHeader: | |
| 20 | Version: 0x00000001 | |
| 21 | Sections: | |
| 22 | - Type: IMPORT | |
| 23 | Imports: | |
| 24 | - Module: env | |
| 25 | Field: __linear_memory | |
| 26 | Kind: MEMORY | |
| 27 | Memory: | |
| 28 | Initial: 0x00000001 | |
| 29 | - Module: env | |
| 30 | Field: __indirect_function_table | |
| 31 | Kind: TABLE | |
| 32 | Table: | |
| 33 | ElemType: FUNCREF | |
| 34 | Limits: | |
| 35 | Initial: 0x00000000 | |
| 36 | - Type: DATA | |
| 37 | Segments: | |
| 38 | - SectionOffset: 6 | |
| 39 | InitFlags: 0 | |
| 40 | Offset: | |
| 41 | Opcode: I32_CONST | |
| 42 | Value: 0 | |
| 43 | Content: 68656C6C6F0A00 | |
| 44 | - Type: CUSTOM | |
| 45 | Name: linking | |
| 46 | Version: 2 | |
| 47 | SymbolTable: | |
| 48 | - Index: 0 | |
| 49 | Kind: DATA | |
| 50 | Name: hello_str | |
| 51 | Flags: [ ] | |
| 52 | Segment: 0 | |
| 53 | Size: 7 | |
| 54 | SegmentInfo: | |
| 55 | - Index: 0 | |
| 56 | Name: .rodata.hello_str | |
| 57 | Alignment: 0 | |
| 58 | Flags: [ ] | |
| 59 | ... | |
| 60 | ||
| 61 | # SHARED-NO-MAX: maximum memory too small, 66560 bytes needed{{$}} | |
| 62 | ||
| 63 | # SHARED-UNALIGNED: maximum memory must be 65536-byte aligned{{$}} | |
| 64 | ||
| 65 | # SHARED: - Type: MEMORY | |
| 66 | # SHARED-NEXT: Memories: | |
| 67 | # SHARED-NEXT: - Flags: [ HAS_MAX, IS_SHARED ] | |
| 68 | # SHARED-NEXT: Initial: 0x00000002 | |
| 69 | # SHARED-NEXT: Maximum: 0x00000002 | |
| 70 | ||
| 71 | # ATOMICS-NO-SHARED: 'atomics' feature is used, so --shared-memory must be used{{$}} | |
| 72 | ||
| 73 | # ATOMICS-NO-MAX: maximum memory too small, 66560 bytes needed{{$}} | |
| 74 | ||
| 75 | # ATOMICS-UNALIGNED: maximum memory must be 65536-byte aligned{{$}} |
deps/lld/test/wasm/shared-needed.ll created+38| ... | ... | @@ -0,0 +1,38 @@ |
| 1 | ; RUN: llc -filetype=obj %s -o %t.o | |
| 2 | ; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o | |
| 3 | ||
| 4 | ; RUN: wasm-ld -shared -o %t1.so %t.o | |
| 5 | ; RUN: obj2yaml %t1.so | FileCheck %s -check-prefix=SO1 | |
| 6 | ||
| 7 | ; RUN: wasm-ld -shared -o %t2.so %t1.so %t.ret32.o | |
| 8 | ; RUN: obj2yaml %t2.so | FileCheck %s -check-prefix=SO2 | |
| 9 | ||
| 10 | target triple = "wasm32-unknown-unknown" | |
| 11 | ||
| 12 | @data = global i32 2, align 4 | |
| 13 | ||
| 14 | define default void @foo() { | |
| 15 | entry: | |
| 16 | ret void | |
| 17 | } | |
| 18 | ||
| 19 | ; SO1: Sections: | |
| 20 | ; SO1-NEXT: - Type: CUSTOM | |
| 21 | ; SO1-NEXT: Name: dylink | |
| 22 | ; SO1-NEXT: MemorySize: 4 | |
| 23 | ; SO1-NEXT: MemoryAlignment: 2 | |
| 24 | ; SO1-NEXT: TableSize: 0 | |
| 25 | ; SO1-NEXT: TableAlignment: 0 | |
| 26 | ; SO1-NEXT: Needed: [] | |
| 27 | ; SO1-NEXT: - Type: TYPE | |
| 28 | ||
| 29 | ; SO2: Sections: | |
| 30 | ; SO2-NEXT: - Type: CUSTOM | |
| 31 | ; SO2-NEXT: Name: dylink | |
| 32 | ; SO2-NEXT: MemorySize: 0 | |
| 33 | ; SO2-NEXT: MemoryAlignment: 0 | |
| 34 | ; SO2-NEXT: TableSize: 0 | |
| 35 | ; SO2-NEXT: TableAlignment: 0 | |
| 36 | ; SO2-NEXT: Needed: | |
| 37 | ; SO2-NEXT: - shared-needed.ll.tmp1.so | |
| 38 | ; SO2-NEXT: - Type: TYPE |
deps/lld/test/wasm/shared.ll+87-14| ... | ... | @@ -1,44 +1,74 @@ |
| 1 | ; RUN: llc -O0 -filetype=obj %s -o %t.o | |
| 1 | ; RUN: llc -relocation-model=pic -filetype=obj %s -o %t.o | |
| 2 | 2 | ; RUN: wasm-ld -shared -o %t.wasm %t.o |
| 3 | 3 | ; RUN: obj2yaml %t.wasm | FileCheck %s |
| 4 | 4 | |
| 5 | target triple = "wasm32-unknown-unknown" | |
| 5 | target triple = "wasm32-unknown-emscripten" | |
| 6 | 6 | |
| 7 | 7 | @data = hidden global i32 2, align 4 |
| 8 | @indirect_func = local_unnamed_addr global void ()* @foo, align 4 | |
| 8 | @data_external = external global i32 | |
| 9 | @indirect_func = local_unnamed_addr global i32 ()* @foo, align 4 | |
| 9 | 10 | @indirect_func_external = local_unnamed_addr global void ()* @func_external, align 4 |
| 10 | 11 | |
| 11 | define default void @foo() { | |
| 12 | ; Test data relocations | |
| 13 | @data_addr = local_unnamed_addr global i32* @data, align 4 | |
| 14 | ; .. against external symbols | |
| 15 | @data_addr_external = local_unnamed_addr global i32* @data_external, align 4 | |
| 16 | ; .. including addends | |
| 17 | %struct.s = type { i32, i32 } | |
| 18 | @extern_struct = external global %struct.s | |
| 19 | @extern_struct_internal_ptr = local_unnamed_addr global i32* getelementptr inbounds (%struct.s, %struct.s* @extern_struct, i32 0, i32 1), align 4 | |
| 20 | ||
| 21 | define hidden i32 @foo() { | |
| 12 | 22 | entry: |
| 13 | 23 | ; To ensure we use __stack_pointer |
| 14 | 24 | %ptr = alloca i32 |
| 15 | 25 | %0 = load i32, i32* @data, align 4 |
| 16 | %1 = load i32, i32* @data_external, align 4 | |
| 17 | %2 = load void ()*, void ()** @indirect_func, align 4 | |
| 18 | call void %2() | |
| 19 | ret void | |
| 26 | %1 = load i32 ()*, i32 ()** @indirect_func, align 4 | |
| 27 | call i32 %1() | |
| 28 | ret i32 %0 | |
| 20 | 29 | } |
| 21 | 30 | |
| 22 | declare void @func_external() | |
| 31 | define hidden i32* @get_data_address() { | |
| 32 | entry: | |
| 33 | ret i32* @data_external | |
| 34 | } | |
| 23 | 35 | |
| 24 | @data_external = external global i32 | |
| 36 | define hidden i8* @get_func_address() { | |
| 37 | entry: | |
| 38 | ret i8* bitcast (void ()* @func_external to i8*) | |
| 39 | } | |
| 25 | 40 | |
| 41 | define default i8* @get_local_func_address() { | |
| 42 | entry: | |
| 43 | ; Verify that a function which is otherwise not address taken *is* added to | |
| 44 | ; the wasm table with referenced via R_WASM_TABLE_INDEX_REL_SLEB | |
| 45 | ret i8* bitcast (i8* ()* @get_func_address to i8*) | |
| 46 | } | |
| 47 | ||
| 48 | declare void @func_external() | |
| 26 | 49 | |
| 27 | 50 | ; check for dylink section at start |
| 28 | 51 | |
| 29 | 52 | ; CHECK: Sections: |
| 30 | 53 | ; CHECK-NEXT: - Type: CUSTOM |
| 31 | 54 | ; CHECK-NEXT: Name: dylink |
| 32 | ; CHECK-NEXT: MemorySize: 8 | |
| 55 | ; CHECK-NEXT: MemorySize: 24 | |
| 33 | 56 | ; CHECK-NEXT: MemoryAlignment: 2 |
| 34 | 57 | ; CHECK-NEXT: TableSize: 2 |
| 35 | 58 | ; CHECK-NEXT: TableAlignment: 0 |
| 59 | ; CHECK-NEXT: Needed: [] | |
| 60 | ; CHECK-NEXT: - Type: TYPE | |
| 36 | 61 | |
| 37 | 62 | ; check for import of __table_base and __memory_base globals |
| 38 | 63 | |
| 39 | 64 | ; CHECK: - Type: IMPORT |
| 40 | 65 | ; CHECK-NEXT: Imports: |
| 41 | 66 | ; CHECK-NEXT: - Module: env |
| 67 | ; CHECK-NEXT: Field: memory | |
| 68 | ; CHECK-NEXT: Kind: MEMORY | |
| 69 | ; CHECK-NEXT: Memory: | |
| 70 | ; CHECK-NEXT: Initial: 0x0000000 | |
| 71 | ; CHECK-NEXT: - Module: env | |
| 42 | 72 | ; CHECK-NEXT: Field: __indirect_function_table |
| 43 | 73 | ; CHECK-NEXT: Kind: TABLE |
| 44 | 74 | ; CHECK-NEXT: Table: |
| ... | ... | @@ -60,6 +90,37 @@ declare void @func_external() |
| 60 | 90 | ; CHECK-NEXT: Kind: GLOBAL |
| 61 | 91 | ; CHECK-NEXT: GlobalType: I32 |
| 62 | 92 | ; CHECK-NEXT: GlobalMutable: false |
| 93 | ; CHECK-NEXT: - Module: env | |
| 94 | ; CHECK-NEXT: Field: func_external | |
| 95 | ; CHECK-NEXT: Kind: FUNCTION | |
| 96 | ; CHECK-NEXT: SigIndex: 1 | |
| 97 | ; CHECK-NEXT: - Module: GOT.mem | |
| 98 | ; CHECK-NEXT: Field: indirect_func | |
| 99 | ; CHECK-NEXT: Kind: GLOBAL | |
| 100 | ; CHECK-NEXT: GlobalType: I32 | |
| 101 | ; CHECK-NEXT: GlobalMutable: true | |
| 102 | ; CHECK-NEXT: - Module: GOT.func | |
| 103 | ; CHECK-NEXT: Field: func_external | |
| 104 | ; CHECK-NEXT: Kind: GLOBAL | |
| 105 | ; CHECK-NEXT: GlobalType: I32 | |
| 106 | ; CHECK-NEXT: GlobalMutable: true | |
| 107 | ; CHECK-NEXT: - Module: GOT.mem | |
| 108 | ; CHECK-NEXT: Field: data_external | |
| 109 | ; CHECK-NEXT: Kind: GLOBAL | |
| 110 | ; CHECK-NEXT: GlobalType: I32 | |
| 111 | ; CHECK-NEXT: GlobalMutable: true | |
| 112 | ; CHECK-NEXT: - Module: GOT.mem | |
| 113 | ; CHECK-NEXT: Field: extern_struct | |
| 114 | ; CHECK-NEXT: Kind: GLOBAL | |
| 115 | ; CHECK-NEXT: GlobalType: I32 | |
| 116 | ; CHECK-NEXT: GlobalMutable: true | |
| 117 | ; CHECK-NEXT: - Type: FUNCTION | |
| 118 | ||
| 119 | ; CHECK: - Type: EXPORT | |
| 120 | ; CHECK-NEXT: Exports: | |
| 121 | ; CHECK-NEXT: - Name: __wasm_call_ctors | |
| 122 | ; CHECK-NEXT: Kind: FUNCTION | |
| 123 | ; CHECK-NEXT: Index: 1 | |
| 63 | 124 | |
| 64 | 125 | ; check for elem segment initialized with __table_base global as offset |
| 65 | 126 | |
| ... | ... | @@ -68,15 +129,27 @@ declare void @func_external() |
| 68 | 129 | ; CHECK-NEXT: - Offset: |
| 69 | 130 | ; CHECK-NEXT: Opcode: GLOBAL_GET |
| 70 | 131 | ; CHECK-NEXT: Index: 2 |
| 71 | ; CHECK-NEXT: Functions: [ 2, 0 ] | |
| 132 | ; CHECK-NEXT: Functions: [ 4, 3 ] | |
| 133 | ||
| 134 | ; check the generated code in __wasm_call_ctors and __wasm_apply_relocs functions | |
| 135 | ; TODO(sbc): Disassemble and verify instructions. | |
| 136 | ||
| 137 | ; CHECK: - Type: CODE | |
| 138 | ; CHECK-NEXT: Functions: | |
| 139 | ; CHECK-NEXT: - Index: 1 | |
| 140 | ; CHECK-NEXT: Locals: [] | |
| 141 | ; CHECK-NEXT: Body: 10020B | |
| 142 | ; CHECK-NEXT: - Index: 2 | |
| 143 | ; CHECK-NEXT: Locals: [] | |
| 144 | ; CHECK-NEXT: Body: 230141046A230241016A360200230141086A23043602002301410C6A230141006A360200230141106A2305360200230141146A230641046A3602000B | |
| 72 | 145 | |
| 73 | 146 | ; check the data segment initialized with __memory_base global as offset |
| 74 | 147 | |
| 75 | 148 | ; CHECK: - Type: DATA |
| 76 | 149 | ; CHECK-NEXT: Segments: |
| 77 | 150 | ; CHECK-NEXT: - SectionOffset: 6 |
| 78 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 151 | ; CHECK-NEXT: InitFlags: 0 | |
| 79 | 152 | ; CHECK-NEXT: Offset: |
| 80 | 153 | ; CHECK-NEXT: Opcode: GLOBAL_GET |
| 81 | 154 | ; CHECK-NEXT: Index: 1 |
| 82 | ; CHECK-NEXT: Content: '0000000001000000' | |
| 155 | ; CHECK-NEXT: Content: '020000000100000000000000000000000000000000000000' |
deps/lld/test/wasm/signature-mismatch-export.ll created+30| ... | ... | @@ -0,0 +1,30 @@ |
| 1 | ; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o | |
| 2 | ; RUN: llc -filetype=obj %s -o %t.main.o | |
| 3 | ; RUN: wasm-ld --export=ret32 -o %t.wasm %t.main.o %t.ret32.o | |
| 4 | ; RUN: obj2yaml %t.wasm | FileCheck %s | |
| 5 | ||
| 6 | target triple = "wasm32-unknown-unknown" | |
| 7 | ||
| 8 | declare i32 @ret32(i32) | |
| 9 | ||
| 10 | define void @_start() { | |
| 11 | entry: | |
| 12 | %call1 = call i32 @ret32(i32 0) | |
| 13 | ret void | |
| 14 | } | |
| 15 | ||
| 16 | ; CHECK: - Type: EXPORT | |
| 17 | ; CHECK: - Name: ret32 | |
| 18 | ; CHECK-NEXT: Kind: FUNCTION | |
| 19 | ; CHECK-NEXT: Index: 2 | |
| 20 | ||
| 21 | ; CHECK: - Type: CUSTOM | |
| 22 | ; CHECK-NEXT: Name: name | |
| 23 | ; CHECK-NEXT: FunctionNames: | |
| 24 | ; CHECK-NEXT: - Index: 0 | |
| 25 | ; CHECK-NEXT: Name: 'unreachable:ret32' | |
| 26 | ; CHECK-NEXT: - Index: 1 | |
| 27 | ; CHECK-NEXT: Name: _start | |
| 28 | ; CHECK-NEXT: - Index: 2 | |
| 29 | ; CHECK-NEXT: Name: ret32 | |
| 30 | ; CHECK-NEXT: ... |
deps/lld/test/wasm/signature-mismatch-unknown.ll created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | ; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o | |
| 2 | ; RUN: llc -filetype=obj %s -o %t.main.o | |
| 3 | ; RUN: wasm-ld --fatal-warnings -o %t.wasm %t.ret32.o %t.main.o | |
| 4 | ; RUN: wasm-ld --fatal-warnings -o %t.wasm %t.main.o %t.ret32.o | |
| 5 | ||
| 6 | target triple = "wasm32-unknown-unknown" | |
| 7 | ||
| 8 | ; Function declartion with incorrect signature. | |
| 9 | declare dso_local void @ret32() | |
| 10 | ||
| 11 | ; Simply taking the address of the function should *not* generate the | |
| 12 | ; the signature mismatch warning. | |
| 13 | @ptr = dso_local global i8* bitcast (void ()* @ret32 to i8*), align 8 | |
| 14 | ||
| 15 | define hidden void @_start() local_unnamed_addr { | |
| 16 | %addr = load i32 ()*, i32 ()** bitcast (i8** @ptr to i32 ()**), align 8 | |
| 17 | call i32 %addr() | |
| 18 | ret void | |
| 19 | } |
deps/lld/test/wasm/signature-mismatch.ll+39-14| ... | ... | @@ -1,26 +1,51 @@ |
| 1 | 1 | ; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o |
| 2 | ; RUN: llc -filetype=obj %p/Inputs/call-ret32.ll -o %t.call.o | |
| 2 | 3 | ; RUN: llc -filetype=obj %s -o %t.main.o |
| 3 | ; RUN: not wasm-ld --fatal-warnings -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s | |
| 4 | ; Run the test again by with the object files in the other order to verify | |
| 5 | ; the check works when the undefined symbol is resolved by an existing defined | |
| 6 | ; one. | |
| 7 | ; RUN: not wasm-ld --fatal-warnings -o %t.wasm %t.ret32.o %t.main.o 2>&1 | FileCheck %s -check-prefix=REVERSE | |
| 4 | ; RUN: wasm-ld --export=call_ret32 --export=ret32 -o %t.wasm %t.main.o %t.ret32.o %t.call.o 2>&1 | FileCheck %s -check-prefix=WARN | |
| 5 | ; RUN: obj2yaml %t.wasm | FileCheck %s -check-prefix=YAML | |
| 6 | ; RUN: not wasm-ld --fatal-warnings -o %t.wasm %t.main.o %t.ret32.o %t.call.o 2>&1 | FileCheck %s -check-prefix=ERROR | |
| 8 | 7 | |
| 9 | 8 | target triple = "wasm32-unknown-unknown" |
| 10 | 9 | |
| 10 | @ret32_address_main = global i32 (i32, i64, i32)* @ret32, align 4 | |
| 11 | ||
| 11 | 12 | ; Function Attrs: nounwind |
| 12 | define hidden void @_start() local_unnamed_addr #0 { | |
| 13 | define hidden void @_start() local_unnamed_addr { | |
| 13 | 14 | entry: |
| 14 | %call = tail call i32 @ret32(i32 1, i64 2, i32 3) #2 | |
| 15 | %call1 = call i32 @ret32(i32 1, i64 2, i32 3) | |
| 16 | %addr = load i32 (i32, i64, i32)*, i32 (i32, i64, i32)** @ret32_address_main, align 4 | |
| 17 | %call2 = call i32 %addr(i32 1, i64 2, i32 3) | |
| 15 | 18 | ret void |
| 16 | 19 | } |
| 17 | 20 | |
| 18 | declare i32 @ret32(i32, i64, i32) local_unnamed_addr #1 | |
| 21 | declare i32 @ret32(i32, i64, i32) local_unnamed_addr | |
| 22 | ||
| 23 | ; WARN: warning: function signature mismatch: ret32 | |
| 24 | ; WARN-NEXT: >>> defined as (i32, i64, i32) -> i32 in {{.*}}.main.o | |
| 25 | ; WARN-NEXT: >>> defined as (f32) -> i32 in {{.*}}.ret32.o | |
| 26 | ||
| 27 | ; ERROR: error: function signature mismatch: ret32 | |
| 28 | ; ERROR-NEXT: >>> defined as (i32, i64, i32) -> i32 in {{.*}}.main.o | |
| 29 | ; ERROR-NEXT: >>> defined as (f32) -> i32 in {{.*}}.ret32.o | |
| 30 | ||
| 31 | ; YAML: - Type: EXPORT | |
| 32 | ; YAML: - Name: ret32 | |
| 33 | ; YAML-NEXT: Kind: FUNCTION | |
| 34 | ; YAML-NEXT: Index: 2 | |
| 35 | ; YAML-NEXT: - Name: call_ret32 | |
| 36 | ; YAML-NEXT: Kind: FUNCTION | |
| 37 | ; YAML-NEXT: Index: 3 | |
| 19 | 38 | |
| 20 | ; CHECK: error: function signature mismatch: ret32 | |
| 21 | ; CHECK-NEXT: >>> defined as (i32, i64, i32) -> i32 in {{.*}}.main.o | |
| 22 | ; CHECK-NEXT: >>> defined as (f32) -> i32 in {{.*}}.ret32.o | |
| 39 | ; YAML: - Type: CUSTOM | |
| 40 | ; YAML-NEXT: Name: name | |
| 41 | ; YAML-NEXT: FunctionNames: | |
| 42 | ; YAML-NEXT: - Index: 0 | |
| 43 | ; YAML-NEXT: Name: 'unreachable:ret32' | |
| 44 | ; YAML-NEXT: - Index: 1 | |
| 45 | ; YAML-NEXT: Name: _start | |
| 46 | ; YAML-NEXT: - Index: 2 | |
| 47 | ; YAML-NEXT: Name: ret32 | |
| 48 | ; YAML-NEXT: - Index: 3 | |
| 49 | ; YAML-NEXT: Name: call_ret32 | |
| 50 | ; YAML-NEXT: ... | |
| 23 | 51 | |
| 24 | ; REVERSE: error: function signature mismatch: ret32 | |
| 25 | ; REVERSE-NEXT: >>> defined as (f32) -> i32 in {{.*}}.ret32.o | |
| 26 | ; REVERSE-NEXT: >>> defined as (i32, i64, i32) -> i32 in {{.*}}.main.o |
deps/lld/test/wasm/stack-first.test+6-5| ... | ... | @@ -4,8 +4,7 @@ |
| 4 | 4 | ; global should be initialized to 512. |
| 5 | 5 | |
| 6 | 6 | RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.o |
| 7 | ||
| 8 | RUN: wasm-ld -z stack-size=512 --stack-first --allow-undefined -o %t.wasm %t.o | |
| 7 | RUN: wasm-ld -z stack-size=512 --stack-first --export=__data_end --export=__heap_base -o %t.wasm %t.o | |
| 9 | 8 | RUN: obj2yaml %t.wasm | FileCheck %s |
| 10 | 9 | |
| 11 | 10 | CHECK: - Type: GLOBAL |
| ... | ... | @@ -33,10 +32,12 @@ CHECK-NEXT: Exports: |
| 33 | 32 | CHECK-NEXT: - Name: memory |
| 34 | 33 | CHECK-NEXT: Kind: MEMORY |
| 35 | 34 | CHECK-NEXT: Index: 0 |
| 36 | CHECK-NEXT: - Name: __heap_base | |
| 35 | CHECK-NEXT: - Name: __data_end | |
| 37 | 36 | CHECK-NEXT: Kind: GLOBAL |
| 38 | 37 | CHECK-NEXT: Index: 1 |
| 39 | CHECK-NEXT: - Name: __data_end | |
| 38 | CHECK-NEXT: - Name: __heap_base | |
| 40 | 39 | CHECK-NEXT: Kind: GLOBAL |
| 41 | 40 | CHECK-NEXT: Index: 2 |
| 42 | ||
| 41 | CHECK-NEXT: - Name: _start | |
| 42 | CHECK-NEXT: Kind: FUNCTION | |
| 43 | CHECK-NEXT: Index: 0 |
deps/lld/test/wasm/stack-pointer.ll+1-1| ... | ... | @@ -41,7 +41,7 @@ entry: |
| 41 | 41 | ; CHECK-NEXT: - Initial: 0x00000000 |
| 42 | 42 | ; CHECK-NEXT: - Type: CODE |
| 43 | 43 | ; CHECK-NEXT: Relocations: |
| 44 | ; CHECK-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB | |
| 44 | ; CHECK-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB | |
| 45 | 45 | ; CHECK-NEXT: Index: 1 |
| 46 | 46 | ; CHECK-NEXT: Offset: 0x00000004 |
| 47 | 47 | ; CHECK-NEXT: Functions: |
deps/lld/test/wasm/startstop.ll created+53| ... | ... | @@ -0,0 +1,53 @@ |
| 1 | ; RUN: llc -filetype=obj -o %t.o %s | |
| 2 | ; RUN: llc -filetype=obj %p/Inputs/explicit-section.ll -o %t2.o | |
| 3 | ; RUN: wasm-ld --export=get_start --export=get_end --export=foo --export=var1 %t.o %t2.o -o %t.wasm | |
| 4 | ; RUN: obj2yaml %t.wasm | FileCheck %s | |
| 5 | ||
| 6 | target triple = "wasm32-unknown-unknown" | |
| 7 | ||
| 8 | @foo = global i32 3, section "mysection", align 4 | |
| 9 | @bar = global i32 4, section "mysection", align 4 | |
| 10 | ||
| 11 | @__start_mysection = external global i8* | |
| 12 | @__stop_mysection = external global i8* | |
| 13 | ||
| 14 | define i8** @get_start() { | |
| 15 | ret i8** @__start_mysection | |
| 16 | } | |
| 17 | ||
| 18 | define i8** @get_end() { | |
| 19 | ret i8** @__stop_mysection | |
| 20 | } | |
| 21 | ||
| 22 | define void @_start() { | |
| 23 | entry: | |
| 24 | ret void | |
| 25 | } | |
| 26 | ; CHECK: - Type: CODE | |
| 27 | ; CHECK-NEXT: Functions: | |
| 28 | ; CHECK-NEXT: - Index: 0 | |
| 29 | ; CHECK-NEXT: Locals: [] | |
| 30 | ; CHECK-NEXT: Body: 4180888080000B | |
| 31 | ; CHECK-NEXT: - Index: 1 | |
| 32 | ; CHECK-NEXT: Locals: [] | |
| 33 | ; CHECK-NEXT: Body: 4190888080000B | |
| 34 | ; CHECK-NEXT: - Index: 2 | |
| 35 | ; CHECK-NEXT: Locals: [] | |
| 36 | ; CHECK-NEXT: Body: 0B | |
| 37 | ; CHECK-NEXT: - Type: DATA | |
| 38 | ; CHECK-NEXT: Segments: | |
| 39 | ; CHECK-NEXT: - SectionOffset: 7 | |
| 40 | ; CHECK-NEXT: InitFlags: 0 | |
| 41 | ; CHECK-NEXT: Offset: | |
| 42 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 43 | ; CHECK-NEXT: Value: 1024 | |
| 44 | ; CHECK-NEXT: Content: 03000000040000002A0000002B000000 | |
| 45 | ; CHECK-NEXT: - Type: CUSTOM | |
| 46 | ; CHECK-NEXT: Name: name | |
| 47 | ; CHECK-NEXT: FunctionNames: | |
| 48 | ; CHECK-NEXT: - Index: 0 | |
| 49 | ; CHECK-NEXT: Name: get_start | |
| 50 | ; CHECK-NEXT: - Index: 1 | |
| 51 | ; CHECK-NEXT: Name: get_end | |
| 52 | ; CHECK-NEXT: - Index: 2 | |
| 53 | ; CHECK-NEXT: Name: _start |
deps/lld/test/wasm/target-feature-disallowed.yaml created+72| ... | ... | @@ -0,0 +1,72 @@ |
| 1 | # RUN: yaml2obj %s -o %t1.o | |
| 2 | ||
| 3 | # RUN: wasm-ld --no-entry --features=foo,bar,baz -o %t.specified.wasm %t1.o | |
| 4 | # RUN: obj2yaml %t.specified.wasm | FileCheck %s --check-prefix SPECIFIED | |
| 5 | ||
| 6 | # RUN: wasm-ld --no-entry --features=bar,baz,quux -o %t.unspecified.wasm %t1.o | |
| 7 | # RUN: obj2yaml %t.unspecified.wasm | FileCheck %s --check-prefix UNSPECIFIED | |
| 8 | ||
| 9 | # RUN: yaml2obj %S/Inputs/disallow-feature-foo.yaml -o %t.disallowed.o | |
| 10 | # RUN: wasm-ld --no-entry -o - %t1.o %t.disallowed.o | obj2yaml | FileCheck %s --check-prefix DISALLOWED | |
| 11 | ||
| 12 | # RUN: yaml2obj %S/Inputs/no-feature-foo.yaml -o %t.none.o | |
| 13 | # RUN: wasm-ld --no-entry -o - %t1.o %t.none.o | obj2yaml | FileCheck %s --check-prefix NONE | |
| 14 | ||
| 15 | # Check that the following combinations of feature linkage policies | |
| 16 | # give the expected results: | |
| 17 | # | |
| 18 | # DISALLOWED x DISALLOWED => NONE | |
| 19 | # DISALLOWED x NONE => NONE | |
| 20 | ||
| 21 | --- !WASM | |
| 22 | FileHeader: | |
| 23 | Version: 0x00000001 | |
| 24 | Sections: | |
| 25 | - Type: CUSTOM | |
| 26 | Name: linking | |
| 27 | Version: 2 | |
| 28 | - Type: CUSTOM | |
| 29 | Name: target_features | |
| 30 | Features: | |
| 31 | - Prefix: DISALLOWED | |
| 32 | Name: "foo" | |
| 33 | # included so output has target features section | |
| 34 | - Prefix: USED | |
| 35 | Name: "bar" | |
| 36 | ... | |
| 37 | ||
| 38 | # SPECIFIED: - Type: CUSTOM | |
| 39 | # SPECIFIED-NEXT: Name: target_features | |
| 40 | # SPECIFIED-NEXT: Features: | |
| 41 | # SPECIFIED-NEXT: - Prefix: USED | |
| 42 | # SPECIFIED-NEXT: Name: bar | |
| 43 | # SPECIFIED-NEXT: - Prefix: USED | |
| 44 | # SPECIFIED-NEXT: Name: baz | |
| 45 | # SPECIFIED-NEXT: - Prefix: USED | |
| 46 | # SPECIFIED-NEXT: Name: foo | |
| 47 | # SPECIFIED-NEXT: ... | |
| 48 | ||
| 49 | # UNSPECIFIED: - Type: CUSTOM | |
| 50 | # UNSPECIFIED-NEXT: Name: target_features | |
| 51 | # UNSPECIFIED-NEXT: Features: | |
| 52 | # UNSPECIFIED-NEXT: - Prefix: USED | |
| 53 | # UNSPECIFIED-NEXT: Name: bar | |
| 54 | # UNSPECIFIED-NEXT: - Prefix: USED | |
| 55 | # UNSPECIFIED-NEXT: Name: baz | |
| 56 | # UNSPECIFIED-NEXT: - Prefix: USED | |
| 57 | # UNSPECIFIED-NEXT: Name: quux | |
| 58 | # UNSPECIFIED-NEXT: ... | |
| 59 | ||
| 60 | # DISALLOWED: - Type: CUSTOM | |
| 61 | # DISALLOWED-NEXT: Name: target_features | |
| 62 | # DISALLOWED-NEXT: Features: | |
| 63 | # DISALLOWED-NEXT: - Prefix: USED | |
| 64 | # DISALLOWED-NEXT: Name: bar | |
| 65 | # DISALLOWED-NEXT: ... | |
| 66 | ||
| 67 | # NONE: - Type: CUSTOM | |
| 68 | # NONE-NEXT: Name: target_features | |
| 69 | # NONE-NEXT: Features: | |
| 70 | # NONE-NEXT: - Prefix: USED | |
| 71 | # NONE-NEXT: Name: bar | |
| 72 | # NONE-NEXT: ... |
deps/lld/test/wasm/target-feature-none.yaml created+33| ... | ... | @@ -0,0 +1,33 @@ |
| 1 | # RUN: yaml2obj %s -o %t1.o | |
| 2 | ||
| 3 | # RUN: wasm-ld --no-entry -o - %t1.o | obj2yaml | FileCheck %s --check-prefix EMPTY | |
| 4 | ||
| 5 | # RUN: wasm-ld --no-entry --features= -o - %t1.o | obj2yaml | FileCheck %s --check-prefix EMPTY | |
| 6 | ||
| 7 | # RUN: wasm-ld --no-entry --features=foo,bar,baz -o - %t1.o | obj2yaml | FileCheck %s --check-prefix SPECIFIED | |
| 8 | ||
| 9 | --- !WASM | |
| 10 | FileHeader: | |
| 11 | Version: 0x00000001 | |
| 12 | Sections: | |
| 13 | - Type: CUSTOM | |
| 14 | Name: linking | |
| 15 | Version: 2 | |
| 16 | - Type: CUSTOM | |
| 17 | Name: target_features | |
| 18 | Features: [ ] | |
| 19 | ... | |
| 20 | ||
| 21 | # section is not emitted if it would be empty | |
| 22 | # EMPTY-NOT: target_features | |
| 23 | ||
| 24 | # SPECIFIED: - Type: CUSTOM | |
| 25 | # SPECIFIED-NEXT: Name: target_features | |
| 26 | # SPECIFIED-NEXT: Features: | |
| 27 | # SPECIFIED-NEXT: - Prefix: USED | |
| 28 | # SPECIFIED-NEXT: Name: bar | |
| 29 | # SPECIFIED-NEXT: - Prefix: USED | |
| 30 | # SPECIFIED-NEXT: Name: baz | |
| 31 | # SPECIFIED-NEXT: - Prefix: USED | |
| 32 | # SPECIFIED-NEXT: Name: foo | |
| 33 | # SPECIFIED-NEXT: ... |
deps/lld/test/wasm/target-feature-required.yaml created+90| ... | ... | @@ -0,0 +1,90 @@ |
| 1 | # RUN: yaml2obj %s -o %t1.o | |
| 2 | ||
| 3 | # RUN: wasm-ld --no-entry --features=foo,bar,baz -o - %t1.o | obj2yaml | FileCheck %s --check-prefix SPECIFIED | |
| 4 | ||
| 5 | # RUN: not wasm-ld --no-entry --features=bar,baz,quux -o /dev/null %t1.o 2>&1 | FileCheck %s --check-prefix UNSPECIFIED | |
| 6 | ||
| 7 | # RUN: wasm-ld --no-entry --no-check-features --features=bar,baz,quux -o - %t1.o | obj2yaml | FileCheck %s --check-prefix UNSPECIFIED-NOCHECK | |
| 8 | ||
| 9 | # RUN: yaml2obj %S/Inputs/require-feature-foo.yaml -o %t.required.o | |
| 10 | # RUN: wasm-ld --no-entry -o - %t1.o %t.required.o | obj2yaml | FileCheck %s --check-prefix REQUIRED | |
| 11 | ||
| 12 | # RUN: yaml2obj %S/Inputs/disallow-feature-foo.yaml -o %t.disallowed.o | |
| 13 | # RUN: not wasm-ld --no-entry -o /dev/null %t1.o %t.disallowed.o 2>&1 | FileCheck %s --check-prefix DISALLOWED | |
| 14 | ||
| 15 | # RUN: wasm-ld --no-entry --no-check-features -o - %t1.o %t.disallowed.o | obj2yaml | FileCheck %s --check-prefix DISALLOWED-NOCHECK | |
| 16 | ||
| 17 | # RUN: yaml2obj %S/Inputs/no-feature-foo.yaml -o %t.none.o | |
| 18 | # RUN: not wasm-ld --no-entry -o /dev/null %t1.o %t.none.o 2>&1 | FileCheck %s --check-prefix NONE | |
| 19 | ||
| 20 | # RUN: wasm-ld --no-entry --no-check-features -o - %t1.o %t.none.o | obj2yaml | FileCheck %s --check-prefix NONE-NOCHECK | |
| 21 | ||
| 22 | # Check that the following combinations of feature linkage policies | |
| 23 | # give the expected results: | |
| 24 | # | |
| 25 | # REQUIRED x REQUIRED => USED | |
| 26 | # REQUIRED x DISALLOWED => Error | |
| 27 | # REQUIRED x NONE => Error | |
| 28 | ||
| 29 | --- !WASM | |
| 30 | FileHeader: | |
| 31 | Version: 0x00000001 | |
| 32 | Sections: | |
| 33 | - Type: CUSTOM | |
| 34 | Name: linking | |
| 35 | Version: 2 | |
| 36 | - Type: CUSTOM | |
| 37 | Name: target_features | |
| 38 | Features: | |
| 39 | - Prefix: REQUIRED | |
| 40 | Name: "foo" | |
| 41 | ... | |
| 42 | ||
| 43 | # SPECIFIED: - Type: CUSTOM | |
| 44 | # SPECIFIED-NEXT: Name: target_features | |
| 45 | # SPECIFIED-NEXT: Features: | |
| 46 | # SPECIFIED-NEXT: - Prefix: USED | |
| 47 | # SPECIFIED-NEXT: Name: bar | |
| 48 | # SPECIFIED-NEXT: - Prefix: USED | |
| 49 | # SPECIFIED-NEXT: Name: baz | |
| 50 | # SPECIFIED-NEXT: - Prefix: USED | |
| 51 | # SPECIFIED-NEXT: Name: foo | |
| 52 | # SPECIFIED-NEXT: ... | |
| 53 | ||
| 54 | # UNSPECIFIED: Target feature 'foo' used by {{.*}}target-feature-required.yaml.tmp1.o is not allowed.{{$}} | |
| 55 | ||
| 56 | # UNSPECIFIED-NOCHECK: - Type: CUSTOM | |
| 57 | # UNSPECIFIED-NOCHECK-NEXT: Name: target_features | |
| 58 | # UNSPECIFIED-NOCHECK-NEXT: Features: | |
| 59 | # UNSPECIFIED-NOCHECK-NEXT: - Prefix: USED | |
| 60 | # UNSPECIFIED-NOCHECK-NEXT: Name: bar | |
| 61 | # UNSPECIFIED-NOCHECK-NEXT: - Prefix: USED | |
| 62 | # UNSPECIFIED-NOCHECK-NEXT: Name: baz | |
| 63 | # UNSPECIFIED-NOCHECK-NEXT: - Prefix: USED | |
| 64 | # UNSPECIFIED-NOCHECK-NEXT: Name: quux | |
| 65 | # UNSPECIFIED-NOCHECK-NEXT: ... | |
| 66 | ||
| 67 | # REQUIRED: - Type: CUSTOM | |
| 68 | # REQUIRED-NEXT: Name: target_features | |
| 69 | # REQUIRED-NEXT: Features: | |
| 70 | # REQUIRED-NEXT: - Prefix: USED | |
| 71 | # REQUIRED-NEXT: Name: foo | |
| 72 | # REQUIRED-NEXT: ... | |
| 73 | ||
| 74 | # DISALLOWED: Target feature 'foo' used in {{.*}}target-feature-required.yaml.tmp1.o is disallowed by {{.*}}target-feature-required.yaml.tmp.disallowed.o. Use --no-check-features to suppress.{{$}} | |
| 75 | ||
| 76 | # DISALLOWED-NOCHECK: - Type: CUSTOM | |
| 77 | # DISALLOWED-NOCHECK-NEXT: Name: target_features | |
| 78 | # DISALLOWED-NOCHECK-NEXT: Features: | |
| 79 | # DISALLOWED-NOCHECK-NEXT: - Prefix: USED | |
| 80 | # DISALLOWED-NOCHECK-NEXT: Name: foo | |
| 81 | # DISALLOWED-NOCHECK-NEXT: ... | |
| 82 | ||
| 83 | # NONE: Missing target feature 'foo' in {{.*}}target-feature-required.yaml.tmp.none.o, required by {{.*}}target-feature-required.yaml.tmp1.o. Use --no-check-features to suppress.{{$}} | |
| 84 | ||
| 85 | # NONE-NOCHECK: - Type: CUSTOM | |
| 86 | # NONE-NOCHECK-NEXT: Name: target_features | |
| 87 | # NONE-NOCHECK-NEXT: Features: | |
| 88 | # NONE-NOCHECK-NEXT: - Prefix: USED | |
| 89 | # NONE-NOCHECK-NEXT: Name: foo | |
| 90 | # NONE-NOCHECK-NEXT: ... |
deps/lld/test/wasm/target-feature-used.yaml created+97| ... | ... | @@ -0,0 +1,97 @@ |
| 1 | # RUN: yaml2obj %s -o %t1.o | |
| 2 | ||
| 3 | # RUN: wasm-ld --no-entry --features=foo,bar,baz -o - %t1.o | obj2yaml | FileCheck %s --check-prefix SPECIFIED | |
| 4 | ||
| 5 | # RUN: not wasm-ld --no-entry --features=bar,baz,quux -o /dev/null %t1.o 2>&1 | FileCheck %s --check-prefix UNSPECIFIED | |
| 6 | ||
| 7 | # RUN: wasm-ld --no-entry --no-check-features --features=bar,baz,quux -o - %t1.o | obj2yaml | FileCheck %s --check-prefix UNSPECIFIED-NOCHECK | |
| 8 | ||
| 9 | # RUN: yaml2obj %S/Inputs/use-feature-foo.yaml -o %t.used.o | |
| 10 | # RUN: wasm-ld --no-entry -o - %t1.o %t.used.o | obj2yaml | FileCheck %s --check-prefix USED | |
| 11 | ||
| 12 | # RUN: yaml2obj %S/Inputs/require-feature-foo.yaml -o %t.required.o | |
| 13 | # RUN: wasm-ld --no-entry -o - %t1.o %t.required.o | obj2yaml | FileCheck %s --check-prefix REQUIRED | |
| 14 | ||
| 15 | # RUN: yaml2obj %S/Inputs/disallow-feature-foo.yaml -o %t.disallowed.o | |
| 16 | # RUN: not wasm-ld --no-entry -o /dev/null %t1.o %t.disallowed.o 2>&1 | FileCheck %s --check-prefix DISALLOWED | |
| 17 | ||
| 18 | # RUN: wasm-ld --no-entry --no-check-features -o - %t1.o %t.disallowed.o | obj2yaml | FileCheck %s --check-prefix DISALLOWED-NOCHECK | |
| 19 | ||
| 20 | # RUN: yaml2obj %S/Inputs/no-feature-foo.yaml -o %t.none.o | |
| 21 | # RUN: wasm-ld --no-entry -o - %t1.o %t.none.o | obj2yaml | FileCheck %s --check-prefix NONE | |
| 22 | ||
| 23 | # Check that the following combinations of feature linkage policies | |
| 24 | # give the expected results: | |
| 25 | # | |
| 26 | # USED x USED => USED | |
| 27 | # USED x REQUIRED => USED | |
| 28 | # USED x DISALLOWED => Error | |
| 29 | # USED x NONE => USED | |
| 30 | ||
| 31 | --- !WASM | |
| 32 | FileHeader: | |
| 33 | Version: 0x00000001 | |
| 34 | Sections: | |
| 35 | - Type: CUSTOM | |
| 36 | Name: linking | |
| 37 | Version: 2 | |
| 38 | - Type: CUSTOM | |
| 39 | Name: target_features | |
| 40 | Features: | |
| 41 | - Prefix: USED | |
| 42 | Name: "foo" | |
| 43 | ... | |
| 44 | ||
| 45 | # SPECIFIED: - Type: CUSTOM | |
| 46 | # SPECIFIED-NEXT: Name: target_features | |
| 47 | # SPECIFIED-NEXT: Features: | |
| 48 | # SPECIFIED-NEXT: - Prefix: USED | |
| 49 | # SPECIFIED-NEXT: Name: bar | |
| 50 | # SPECIFIED-NEXT: - Prefix: USED | |
| 51 | # SPECIFIED-NEXT: Name: baz | |
| 52 | # SPECIFIED-NEXT: - Prefix: USED | |
| 53 | # SPECIFIED-NEXT: Name: foo | |
| 54 | # SPECIFIED-NEXT: ... | |
| 55 | ||
| 56 | # UNSPECIFIED: Target feature 'foo' used by {{.*}}target-feature-used.yaml.tmp1.o is not allowed.{{$}} | |
| 57 | ||
| 58 | # UNSPECIFIED-NOCHECK: - Type: CUSTOM | |
| 59 | # UNSPECIFIED-NOCHECK-NEXT: Name: target_features | |
| 60 | # UNSPECIFIED-NOCHECK-NEXT: Features: | |
| 61 | # UNSPECIFIED-NOCHECK-NEXT: - Prefix: USED | |
| 62 | # UNSPECIFIED-NOCHECK-NEXT: Name: bar | |
| 63 | # UNSPECIFIED-NOCHECK-NEXT: - Prefix: USED | |
| 64 | # UNSPECIFIED-NOCHECK-NEXT: Name: baz | |
| 65 | # UNSPECIFIED-NOCHECK-NEXT: - Prefix: USED | |
| 66 | # UNSPECIFIED-NOCHECK-NEXT: Name: quux | |
| 67 | # UNSPECIFIED-NOCHECK-NEXT: ... | |
| 68 | ||
| 69 | # USED: - Type: CUSTOM | |
| 70 | # USED-NEXT: Name: target_features | |
| 71 | # USED-NEXT: Features: | |
| 72 | # USED-NEXT: - Prefix: USED | |
| 73 | # USED-NEXT: Name: foo | |
| 74 | # USED-NEXT: ... | |
| 75 | ||
| 76 | # REQUIRED: - Type: CUSTOM | |
| 77 | # REQUIRED-NEXT: Name: target_features | |
| 78 | # REQUIRED-NEXT: Features: | |
| 79 | # REQUIRED-NEXT: - Prefix: USED | |
| 80 | # REQUIRED-NEXT: Name: foo | |
| 81 | # REQUIRED-NEXT: ... | |
| 82 | ||
| 83 | # DISALLOWED: Target feature 'foo' used in {{.*}}target-feature-used.yaml.tmp1.o is disallowed by {{.*}}target-feature-used.yaml.tmp.disallowed.o. Use --no-check-features to suppress.{{$}} | |
| 84 | ||
| 85 | # DISALLOWED-NOCHECK: - Type: CUSTOM | |
| 86 | # DISALLOWED-NOCHECK-NEXT: Name: target_features | |
| 87 | # DISALLOWED-NOCHECK-NEXT: Features: | |
| 88 | # DISALLOWED-NOCHECK-NEXT: - Prefix: USED | |
| 89 | # DISALLOWED-NOCHECK-NEXT: Name: foo | |
| 90 | # DISALLOWED-NOCHECK-NEXT: ... | |
| 91 | ||
| 92 | # NONE: - Type: CUSTOM | |
| 93 | # NONE-NEXT: Name: target_features | |
| 94 | # NONE-NEXT: Features: | |
| 95 | # NONE-NEXT: - Prefix: USED | |
| 96 | # NONE-NEXT: Name: foo | |
| 97 | # NONE-NEXT: ... |
deps/lld/test/wasm/tls.ll created+79| ... | ... | @@ -0,0 +1,79 @@ |
| 1 | ; RUN: llc -mattr=+bulk-memory -filetype=obj %s -o %t.o | |
| 2 | ||
| 3 | target triple = "wasm32-unknown-unknown" | |
| 4 | ||
| 5 | @no_tls = global i32 0, align 4 | |
| 6 | @tls1 = thread_local(localexec) global i32 1, align 4 | |
| 7 | @tls2 = thread_local(localexec) global i32 1, align 4 | |
| 8 | ||
| 9 | define i32* @tls1_addr() { | |
| 10 | ret i32* @tls1 | |
| 11 | } | |
| 12 | ||
| 13 | define i32* @tls2_addr() { | |
| 14 | ret i32* @tls2 | |
| 15 | } | |
| 16 | ||
| 17 | ; RUN: wasm-ld -no-gc-sections --shared-memory --max-memory=131072 --no-entry -o %t.wasm %t.o | |
| 18 | ; RUN: obj2yaml %t.wasm | FileCheck %s | |
| 19 | ||
| 20 | ; RUN: wasm-ld -no-gc-sections --shared-memory --max-memory=131072 --no-merge-data-segments --no-entry -o %t.wasm %t.o | |
| 21 | ; RUN: obj2yaml %t.wasm | FileCheck %s | |
| 22 | ||
| 23 | ; CHECK: - Type: GLOBAL | |
| 24 | ; CHECK-NEXT: Globals: | |
| 25 | ; CHECK-NEXT: - Index: 0 | |
| 26 | ; CHECK-NEXT: Type: I32 | |
| 27 | ; CHECK-NEXT: Mutable: true | |
| 28 | ; CHECK-NEXT: InitExpr: | |
| 29 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 30 | ; CHECK-NEXT: Value: 66576 | |
| 31 | ; CHECK-NEXT: - Index: 1 | |
| 32 | ; CHECK-NEXT: Type: I32 | |
| 33 | ; CHECK-NEXT: Mutable: true | |
| 34 | ; CHECK-NEXT: InitExpr: | |
| 35 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 36 | ; CHECK-NEXT: Value: 0 | |
| 37 | ; CHECK-NEXT: - Index: 2 | |
| 38 | ; CHECK-NEXT: Type: I32 | |
| 39 | ; CHECK-NEXT: Mutable: false | |
| 40 | ; CHECK-NEXT: InitExpr: | |
| 41 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 42 | ; CHECK-NEXT: Value: 8 | |
| 43 | ||
| 44 | ||
| 45 | ; CHECK: - Type: CODE | |
| 46 | ; CHECK-NEXT: Functions: | |
| 47 | ; Skip __wasm_call_ctors and __wasm_init_memory | |
| 48 | ; CHECK: - Index: 2 | |
| 49 | ; CHECK-NEXT: Locals: [] | |
| 50 | ; CHECK-NEXT: Body: 20002401200041004108FC0801000B | |
| 51 | ||
| 52 | ; Expected body of __wasm_init_tls: | |
| 53 | ; local.get 0 | |
| 54 | ; global.set 1 | |
| 55 | ; local.get 0 | |
| 56 | ; i32.const 0 | |
| 57 | ; i32.const 8 | |
| 58 | ; memory.init 1, 0 | |
| 59 | ; end | |
| 60 | ||
| 61 | ; CHECK-NEXT: - Index: 3 | |
| 62 | ; CHECK-NEXT: Locals: [] | |
| 63 | ; CHECK-NEXT: Body: 2381808080004180808080006A0B | |
| 64 | ||
| 65 | ; Expected body of tls1_addr: | |
| 66 | ; global.get 1 | |
| 67 | ; i32.const 0 | |
| 68 | ; i32.add | |
| 69 | ; end | |
| 70 | ||
| 71 | ; CHECK-NEXT: - Index: 4 | |
| 72 | ; CHECK-NEXT: Locals: [] | |
| 73 | ; CHECK-NEXT: Body: 2381808080004184808080006A0B | |
| 74 | ||
| 75 | ; Expected body of tls1_addr: | |
| 76 | ; global.get 1 | |
| 77 | ; i32.const 4 | |
| 78 | ; i32.add | |
| 79 | ; end |
deps/lld/test/wasm/trace-symbol.ll created+28| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | ; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o | |
| 2 | ; RUN: llc -filetype=obj -o %t.start.o %s | |
| 3 | ; RUN: wasm-ld -o %t.wasm %t.start.o %t.ret32.o -y ret32 -y _start | FileCheck %s -check-prefix=BOTH | |
| 4 | ; RUN: wasm-ld -o %t.wasm %t.ret32.o %t.start.o -y ret32 -y _start | FileCheck %s -check-prefix=REVERSED | |
| 5 | ||
| 6 | ; check alias | |
| 7 | ; RUN: wasm-ld -o %t.wasm %t.start.o %t.ret32.o -trace-symbol=_start | FileCheck %s -check-prefixes=JUST-START | |
| 8 | ||
| 9 | target triple = "wasm32-unknown-unknown" | |
| 10 | ||
| 11 | declare i32 @ret32(float %arg) | |
| 12 | ||
| 13 | define void @_start() { | |
| 14 | entry: | |
| 15 | %call1 = call i32 @ret32(float 0.0) | |
| 16 | ret void | |
| 17 | } | |
| 18 | ||
| 19 | ; BOTH: start.o: definition of _start | |
| 20 | ; BOTH-NEXT: start.o: reference to ret32 | |
| 21 | ; BOTH-NEXT: ret32.o: definition of ret32 | |
| 22 | ||
| 23 | ; REVERSED: ret32.o: definition of ret32 | |
| 24 | ; REVERSED-NEXT: start.o: definition of _start | |
| 25 | ; REVERSED-NEXT: start.o: reference to ret32 | |
| 26 | ||
| 27 | ; JUST-START: start.o: definition of _start | |
| 28 | ; JUST-START-NOT: ret32 |
deps/lld/test/wasm/trace.test created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.foo.o | |
| 2 | ||
| 3 | # Check -t | |
| 4 | RUN: wasm-ld %t.foo.o -o %t.t.out.wasm -t 2>&1 | FileCheck %s | |
| 5 | CHECK: {{.*}}.foo.o | |
| 6 | ||
| 7 | # Check --trace alias | |
| 8 | RUN: wasm-ld %t.foo.o -o %t.trace.out.wasm --trace 2>&1 | FileCheck %s |
deps/lld/test/wasm/undefined-data.ll created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | ; RUN: llc -filetype=obj %s -o %t.o | |
| 2 | ; RUN: not wasm-ld -o %t.wasm %t.o 2>&1 | FileCheck %s -check-prefix=UNDEF | |
| 3 | ; RUN: not wasm-ld --allow-undefined -o %t.wasm %t.o 2>&1 | FileCheck %s -check-prefix=UNDEF | |
| 4 | ; RUN: not wasm-ld --shared -o %t.wasm %t.o 2>&1 | FileCheck %s -check-prefix=SHARED | |
| 5 | ||
| 6 | target triple = "wasm32-unknown-unknown" | |
| 7 | ||
| 8 | @data_external = external global i32 | |
| 9 | ||
| 10 | define i32 @_start() { | |
| 11 | entry: | |
| 12 | %0 = load i32, i32* @data_external, align 4 | |
| 13 | ret i32 %0 | |
| 14 | } | |
| 15 | ||
| 16 | ; UNDEF: error: {{.*}}undefined-data.ll.tmp.o: undefined symbol: data_external | |
| 17 | ; SHARED: error: {{.*}}undefined-data.ll.tmp.o: relocation R_WASM_MEMORY_ADDR_LEB cannot be used against symbol data_external; recompile with -fPIC |
deps/lld/test/wasm/undefined-weak-call.ll+7-30| ... | ... | @@ -42,7 +42,7 @@ define i32 @callWeakFuncs() { |
| 42 | 42 | ; CHECK-NEXT: ReturnType: I32 |
| 43 | 43 | ; CHECK-NEXT: ParamTypes: |
| 44 | 44 | ; CHECK-NEXT: - Type: FUNCTION |
| 45 | ; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 1, 2 ] | |
| 45 | ; CHECK-NEXT: FunctionTypes: [ 0, 0, 1, 2 ] | |
| 46 | 46 | ; CHECK-NEXT: - Type: TABLE |
| 47 | 47 | ; CHECK-NEXT: Tables: |
| 48 | 48 | ; CHECK-NEXT: - ElemType: FUNCREF |
| ... | ... | @@ -61,37 +61,19 @@ define i32 @callWeakFuncs() { |
| 61 | 61 | ; CHECK-NEXT: InitExpr: |
| 62 | 62 | ; CHECK-NEXT: Opcode: I32_CONST |
| 63 | 63 | ; CHECK-NEXT: Value: 66560 |
| 64 | ; CHECK-NEXT: - Index: 1 | |
| 65 | ; CHECK-NEXT: Type: I32 | |
| 66 | ; CHECK-NEXT: Mutable: false | |
| 67 | ; CHECK-NEXT: InitExpr: | |
| 68 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 69 | ; CHECK-NEXT: Value: 66560 | |
| 70 | ; CHECK-NEXT: - Index: 2 | |
| 71 | ; CHECK-NEXT: Type: I32 | |
| 72 | ; CHECK-NEXT: Mutable: false | |
| 73 | ; CHECK-NEXT: InitExpr: | |
| 74 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 75 | ; CHECK-NEXT: Value: 1024 | |
| 76 | 64 | ; CHECK-NEXT: - Type: EXPORT |
| 77 | 65 | ; CHECK-NEXT: Exports: |
| 78 | 66 | ; CHECK-NEXT: - Name: memory |
| 79 | 67 | ; CHECK-NEXT: Kind: MEMORY |
| 80 | 68 | ; CHECK-NEXT: Index: 0 |
| 81 | ; CHECK-NEXT: - Name: __heap_base | |
| 82 | ; CHECK-NEXT: Kind: GLOBAL | |
| 83 | ; CHECK-NEXT: Index: 1 | |
| 84 | ; CHECK-NEXT: - Name: __data_end | |
| 85 | ; CHECK-NEXT: Kind: GLOBAL | |
| 86 | ; CHECK-NEXT: Index: 2 | |
| 87 | 69 | ; CHECK-NEXT: - Name: callWeakFuncs |
| 88 | 70 | ; CHECK-NEXT: Kind: FUNCTION |
| 89 | ; CHECK-NEXT: Index: 4 | |
| 71 | ; CHECK-NEXT: Index: 3 | |
| 90 | 72 | ; CHECK-NEXT: - Type: CODE |
| 91 | 73 | ; CHECK-NEXT: Functions: |
| 92 | 74 | ; CHECK-NEXT: - Index: 0 |
| 93 | 75 | ; CHECK-NEXT: Locals: |
| 94 | ; CHECK-NEXT: Body: 0B | |
| 76 | ; CHECK-NEXT: Body: 000B | |
| 95 | 77 | ; CHECK-NEXT: - Index: 1 |
| 96 | 78 | ; CHECK-NEXT: Locals: |
| 97 | 79 | ; CHECK-NEXT: Body: 000B |
| ... | ... | @@ -100,21 +82,16 @@ define i32 @callWeakFuncs() { |
| 100 | 82 | ; CHECK-NEXT: Body: 000B |
| 101 | 83 | ; CHECK-NEXT: - Index: 3 |
| 102 | 84 | ; CHECK-NEXT: Locals: |
| 103 | ; CHECK-NEXT: Body: 000B | |
| 104 | ; CHECK-NEXT: - Index: 4 | |
| 105 | ; CHECK-NEXT: Locals: | |
| 106 | ; CHECK-NEXT: Body: 10818080800010828080800041021083808080004180808080004180808080006A0B | |
| 85 | ; CHECK-NEXT: Body: 10808080800010818080800041021082808080004180808080004180808080006A0B | |
| 107 | 86 | ; CHECK-NEXT: - Type: CUSTOM |
| 108 | 87 | ; CHECK-NEXT: Name: name |
| 109 | 88 | ; CHECK-NEXT: FunctionNames: |
| 110 | 89 | ; CHECK-NEXT: - Index: 0 |
| 111 | ; CHECK-NEXT: Name: __wasm_call_ctors | |
| 90 | ; CHECK-NEXT: Name: 'undefined:weakFunc1' | |
| 112 | 91 | ; CHECK-NEXT: - Index: 1 |
| 113 | ; CHECK-NEXT: Name: undefined function weakFunc1 | |
| 92 | ; CHECK-NEXT: Name: 'undefined:weakFunc2' | |
| 114 | 93 | ; CHECK-NEXT: - Index: 2 |
| 115 | ; CHECK-NEXT: Name: undefined function weakFunc2 | |
| 94 | ; CHECK-NEXT: Name: 'undefined:weakFunc3' | |
| 116 | 95 | ; CHECK-NEXT: - Index: 3 |
| 117 | ; CHECK-NEXT: Name: undefined function weakFunc3 | |
| 118 | ; CHECK-NEXT: - Index: 4 | |
| 119 | 96 | ; CHECK-NEXT: Name: callWeakFuncs |
| 120 | 97 | ; CHECK-NEXT: ... |
deps/lld/test/wasm/undefined.ll+3-2| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | ; RUN: llc -filetype=obj %s -o %t.o |
| 2 | 2 | ; RUN: wasm-ld --allow-undefined -o %t.wasm %t.o |
| 3 | 3 | |
| 4 | ; Fails due to undefined 'foo' | |
| 4 | ; Fails due to undefined 'foo' | |
| 5 | 5 | ; RUN: not wasm-ld --undefined=baz -o %t.wasm %t.o 2>&1 | FileCheck %s |
| 6 | 6 | ; CHECK: error: {{.*}}.o: undefined symbol: foo |
| 7 | 7 | ; CHECK-NOT: undefined symbol: baz |
| ... | ... | @@ -16,7 +16,8 @@ |
| 16 | 16 | target triple = "wasm32-unknown-unknown" |
| 17 | 17 | |
| 18 | 18 | ; Takes the address of the external foo() resulting in undefined external |
| 19 | @bar = hidden local_unnamed_addr global i8* bitcast (i32 ()* @foo to i8*), align 4 | |
| 19 | @bar = global i8* bitcast (i32 ()* @foo to i8*), align 4 | |
| 20 | @llvm.used = appending global [1 x i8**] [i8** @bar], section "llvm.metadata" | |
| 20 | 21 | |
| 21 | 22 | declare i32 @foo() #0 |
| 22 | 23 |
deps/lld/test/wasm/version.ll+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | ; RUN: llc -filetype=obj %s -o %t.o |
| 2 | 2 | ; RUN: wasm-ld -o %t.wasm %t.o |
| 3 | ; RUN: llvm-readobj -file-headers %t.wasm | FileCheck %s | |
| 3 | ; RUN: llvm-readobj --file-headers %t.wasm | FileCheck %s | |
| 4 | 4 | |
| 5 | 5 | target triple = "wasm32-unknown-unknown" |
| 6 | 6 |
deps/lld/test/wasm/visibility-hidden.ll+4-16| ... | ... | @@ -43,21 +43,15 @@ entry: |
| 43 | 43 | ; CHECK-NEXT: - Name: memory |
| 44 | 44 | ; CHECK-NEXT: Kind: MEMORY |
| 45 | 45 | ; CHECK-NEXT: Index: 0 |
| 46 | ; CHECK-NEXT: - Name: __heap_base | |
| 47 | ; CHECK-NEXT: Kind: GLOBAL | |
| 48 | ; CHECK-NEXT: Index: 1 | |
| 49 | ; CHECK-NEXT: - Name: __data_end | |
| 50 | ; CHECK-NEXT: Kind: GLOBAL | |
| 51 | ; CHECK-NEXT: Index: 2 | |
| 52 | 46 | ; CHECK-NEXT: - Name: objectDefault |
| 53 | 47 | ; CHECK-NEXT: Kind: FUNCTION |
| 54 | ; CHECK-NEXT: Index: 2 | |
| 48 | ; CHECK-NEXT: Index: 1 | |
| 55 | 49 | ; CHECK-NEXT: - Name: _start |
| 56 | 50 | ; CHECK-NEXT: Kind: FUNCTION |
| 57 | ; CHECK-NEXT: Index: 3 | |
| 51 | ; CHECK-NEXT: Index: 2 | |
| 58 | 52 | ; CHECK-NEXT: - Name: archiveDefault |
| 59 | 53 | ; CHECK-NEXT: Kind: FUNCTION |
| 60 | ; CHECK-NEXT: Index: 5 | |
| 54 | ; CHECK-NEXT: Index: 4 | |
| 61 | 55 | ; CHECK-NEXT: - Type: |
| 62 | 56 | |
| 63 | 57 | |
| ... | ... | @@ -66,13 +60,7 @@ entry: |
| 66 | 60 | ; NO-DEFAULT-NEXT: - Name: memory |
| 67 | 61 | ; NO-DEFAULT-NEXT: Kind: MEMORY |
| 68 | 62 | ; NO-DEFAULT-NEXT: Index: 0 |
| 69 | ; NO-DEFAULT-NEXT: - Name: __heap_base | |
| 70 | ; NO-DEFAULT-NEXT: Kind: GLOBAL | |
| 71 | ; NO-DEFAULT-NEXT: Index: 1 | |
| 72 | ; NO-DEFAULT-NEXT: - Name: __data_end | |
| 73 | ; NO-DEFAULT-NEXT: Kind: GLOBAL | |
| 74 | ; NO-DEFAULT-NEXT: Index: 2 | |
| 75 | 63 | ; NO-DEFAULT-NEXT: - Name: _start |
| 76 | 64 | ; NO-DEFAULT-NEXT: Kind: FUNCTION |
| 77 | ; NO-DEFAULT-NEXT: Index: 3 | |
| 65 | ; NO-DEFAULT-NEXT: Index: 2 | |
| 78 | 66 | ; NO-DEFAULT-NEXT: - Type: |
deps/lld/test/wasm/weak-alias-overide.ll+25-48| ... | ... | @@ -26,13 +26,13 @@ entry: |
| 26 | 26 | ; CHECK-NEXT: - Type: TYPE |
| 27 | 27 | ; CHECK-NEXT: Signatures: |
| 28 | 28 | ; CHECK-NEXT: - Index: 0 |
| 29 | ; CHECK-NEXT: ReturnType: NORESULT | |
| 29 | ; CHECK-NEXT: ReturnType: I32 | |
| 30 | 30 | ; CHECK-NEXT: ParamTypes: |
| 31 | 31 | ; CHECK-NEXT: - Index: 1 |
| 32 | ; CHECK-NEXT: ReturnType: I32 | |
| 32 | ; CHECK-NEXT: ReturnType: NORESULT | |
| 33 | 33 | ; CHECK-NEXT: ParamTypes: |
| 34 | 34 | ; CHECK-NEXT: - Type: FUNCTION |
| 35 | ; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 1, 1, 1, 1, 1 ] | |
| 35 | ; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 0, 0, 0 ] | |
| 36 | 36 | ; CHECK-NEXT: - Type: TABLE |
| 37 | 37 | ; CHECK-NEXT: Tables: |
| 38 | 38 | ; CHECK-NEXT: - ElemType: FUNCREF |
| ... | ... | @@ -51,103 +51,80 @@ entry: |
| 51 | 51 | ; CHECK-NEXT: InitExpr: |
| 52 | 52 | ; CHECK-NEXT: Opcode: I32_CONST |
| 53 | 53 | ; CHECK-NEXT: Value: 66560 |
| 54 | ; CHECK-NEXT: - Index: 1 | |
| 55 | ; CHECK-NEXT: Type: I32 | |
| 56 | ; CHECK-NEXT: Mutable: false | |
| 57 | ; CHECK-NEXT: InitExpr: | |
| 58 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 59 | ; CHECK-NEXT: Value: 66560 | |
| 60 | ; CHECK-NEXT: - Index: 2 | |
| 61 | ; CHECK-NEXT: Type: I32 | |
| 62 | ; CHECK-NEXT: Mutable: false | |
| 63 | ; CHECK-NEXT: InitExpr: | |
| 64 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 65 | ; CHECK-NEXT: Value: 1024 | |
| 66 | 54 | ; CHECK-NEXT: - Type: EXPORT |
| 67 | 55 | ; CHECK-NEXT: Exports: |
| 68 | 56 | ; CHECK-NEXT: - Name: memory |
| 69 | 57 | ; CHECK-NEXT: Kind: MEMORY |
| 70 | 58 | ; CHECK-NEXT: Index: 0 |
| 71 | ; CHECK-NEXT: - Name: __heap_base | |
| 72 | ; CHECK-NEXT: Kind: GLOBAL | |
| 73 | ; CHECK-NEXT: Index: 1 | |
| 74 | ; CHECK-NEXT: - Name: __data_end | |
| 75 | ; CHECK-NEXT: Kind: GLOBAL | |
| 76 | ; CHECK-NEXT: Index: 2 | |
| 77 | 59 | ; CHECK-NEXT: - Name: alias_fn |
| 78 | 60 | ; CHECK-NEXT: Kind: FUNCTION |
| 79 | ; CHECK-NEXT: Index: 1 | |
| 61 | ; CHECK-NEXT: Index: 0 | |
| 80 | 62 | ; CHECK-NEXT: - Name: _start |
| 81 | 63 | ; CHECK-NEXT: Kind: FUNCTION |
| 82 | ; CHECK-NEXT: Index: 2 | |
| 64 | ; CHECK-NEXT: Index: 1 | |
| 83 | 65 | ; CHECK-NEXT: - Name: direct_fn |
| 84 | 66 | ; CHECK-NEXT: Kind: FUNCTION |
| 85 | ; CHECK-NEXT: Index: 3 | |
| 67 | ; CHECK-NEXT: Index: 2 | |
| 86 | 68 | ; CHECK-NEXT: - Name: call_direct |
| 87 | 69 | ; CHECK-NEXT: Kind: FUNCTION |
| 88 | ; CHECK-NEXT: Index: 4 | |
| 70 | ; CHECK-NEXT: Index: 3 | |
| 89 | 71 | ; CHECK-NEXT: - Name: call_alias |
| 90 | 72 | ; CHECK-NEXT: Kind: FUNCTION |
| 91 | ; CHECK-NEXT: Index: 5 | |
| 73 | ; CHECK-NEXT: Index: 4 | |
| 92 | 74 | ; CHECK-NEXT: - Name: call_alias_ptr |
| 93 | 75 | ; CHECK-NEXT: Kind: FUNCTION |
| 94 | ; CHECK-NEXT: Index: 6 | |
| 76 | ; CHECK-NEXT: Index: 5 | |
| 95 | 77 | ; CHECK-NEXT: - Name: call_direct_ptr |
| 96 | 78 | ; CHECK-NEXT: Kind: FUNCTION |
| 97 | ; CHECK-NEXT: Index: 7 | |
| 79 | ; CHECK-NEXT: Index: 6 | |
| 98 | 80 | ; CHECK-NEXT: - Type: ELEM |
| 99 | 81 | ; CHECK-NEXT: Segments: |
| 100 | 82 | ; CHECK-NEXT: - Offset: |
| 101 | 83 | ; CHECK-NEXT: Opcode: I32_CONST |
| 102 | 84 | ; CHECK-NEXT: Value: 1 |
| 103 | ; CHECK-NEXT: Functions: [ 1, 3 ] | |
| 85 | ; CHECK-NEXT: Functions: [ 0, 2 ] | |
| 104 | 86 | ; CHECK-NEXT: - Type: CODE |
| 105 | 87 | ; CHECK-NEXT: Functions: |
| 106 | 88 | ; CHECK-NEXT: - Index: 0 |
| 107 | 89 | ; CHECK-NEXT: Locals: |
| 108 | ; CHECK-NEXT: Body: 0B | |
| 90 | ; CHECK-NEXT: Body: 41010B | |
| 109 | 91 | ; CHECK-NEXT: - Index: 1 |
| 110 | 92 | ; CHECK-NEXT: Locals: |
| 111 | ; CHECK-NEXT: Body: 41010B | |
| 93 | ; CHECK-NEXT: Body: 1080808080001A0B | |
| 112 | 94 | ; CHECK-NEXT: - Index: 2 |
| 113 | 95 | ; CHECK-NEXT: Locals: |
| 114 | ; CHECK-NEXT: Body: 1081808080001A0B | |
| 96 | ; CHECK-NEXT: Body: 41000B | |
| 115 | 97 | ; CHECK-NEXT: - Index: 3 |
| 116 | 98 | ; CHECK-NEXT: Locals: |
| 117 | ; CHECK-NEXT: Body: 41000B | |
| 99 | ; CHECK-NEXT: Body: 1082808080000B | |
| 118 | 100 | ; CHECK-NEXT: - Index: 4 |
| 119 | 101 | ; CHECK-NEXT: Locals: |
| 120 | ; CHECK-NEXT: Body: 1083808080000B | |
| 102 | ; CHECK-NEXT: Body: 1080808080000B | |
| 121 | 103 | ; CHECK-NEXT: - Index: 5 |
| 122 | 104 | ; CHECK-NEXT: Locals: |
| 123 | ; CHECK-NEXT: Body: 1081808080000B | |
| 124 | ; CHECK-NEXT: - Index: 6 | |
| 125 | ; CHECK-NEXT: Locals: | |
| 126 | 105 | ; CHECK-NEXT: - Type: I32 |
| 127 | 106 | ; CHECK-NEXT: Count: 2 |
| 128 | ; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081081808080002101200041106A24808080800020010B | |
| 129 | ; CHECK-NEXT: - Index: 7 | |
| 107 | ; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081080808080002101200041106A24808080800020010B | |
| 108 | ; CHECK-NEXT: - Index: 6 | |
| 130 | 109 | ; CHECK-NEXT: Locals: |
| 131 | 110 | ; CHECK-NEXT: - Type: I32 |
| 132 | 111 | ; CHECK-NEXT: Count: 2 |
| 133 | ; CHECK-NEXT: Body: 23808080800041106B220024808080800020004182808080003602081083808080002101200041106A24808080800020010B | |
| 112 | ; CHECK-NEXT: Body: 23808080800041106B220024808080800020004182808080003602081082808080002101200041106A24808080800020010B | |
| 134 | 113 | ; CHECK-NEXT: - Type: CUSTOM |
| 135 | 114 | ; CHECK-NEXT: Name: name |
| 136 | 115 | ; CHECK-NEXT: FunctionNames: |
| 137 | 116 | ; CHECK-NEXT: - Index: 0 |
| 138 | ; CHECK-NEXT: Name: __wasm_call_ctors | |
| 139 | ; CHECK-NEXT: - Index: 1 | |
| 140 | 117 | ; CHECK-NEXT: Name: alias_fn |
| 141 | ; CHECK-NEXT: - Index: 2 | |
| 118 | ; CHECK-NEXT: - Index: 1 | |
| 142 | 119 | ; CHECK-NEXT: Name: _start |
| 143 | ; CHECK-NEXT: - Index: 3 | |
| 120 | ; CHECK-NEXT: - Index: 2 | |
| 144 | 121 | ; CHECK-NEXT: Name: direct_fn |
| 145 | ; CHECK-NEXT: - Index: 4 | |
| 122 | ; CHECK-NEXT: - Index: 3 | |
| 146 | 123 | ; CHECK-NEXT: Name: call_direct |
| 147 | ; CHECK-NEXT: - Index: 5 | |
| 124 | ; CHECK-NEXT: - Index: 4 | |
| 148 | 125 | ; CHECK-NEXT: Name: call_alias |
| 149 | ; CHECK-NEXT: - Index: 6 | |
| 126 | ; CHECK-NEXT: - Index: 5 | |
| 150 | 127 | ; CHECK-NEXT: Name: call_alias_ptr |
| 151 | ; CHECK-NEXT: - Index: 7 | |
| 128 | ; CHECK-NEXT: - Index: 6 | |
| 152 | 129 | ; CHECK-NEXT: Name: call_direct_ptr |
| 153 | 130 | ; CHECK-NEXT: ... |
deps/lld/test/wasm/weak-alias.ll+34-57| ... | ... | @@ -29,7 +29,7 @@ entry: |
| 29 | 29 | ; CHECK-NEXT: ReturnType: I32 |
| 30 | 30 | ; CHECK-NEXT: ParamTypes: |
| 31 | 31 | ; CHECK-NEXT: - Type: FUNCTION |
| 32 | ; CHECK-NEXT: FunctionTypes: [ 0, 0, 1, 1, 1, 1, 1 ] | |
| 32 | ; CHECK-NEXT: FunctionTypes: [ 0, 1, 1, 1, 1, 1 ] | |
| 33 | 33 | ; CHECK-NEXT: - Type: TABLE |
| 34 | 34 | ; CHECK-NEXT: Tables: |
| 35 | 35 | ; CHECK-NEXT: - ElemType: FUNCREF |
| ... | ... | @@ -48,99 +48,76 @@ entry: |
| 48 | 48 | ; CHECK-NEXT: InitExpr: |
| 49 | 49 | ; CHECK-NEXT: Opcode: I32_CONST |
| 50 | 50 | ; CHECK-NEXT: Value: 66560 |
| 51 | ; CHECK-NEXT: - Index: 1 | |
| 52 | ; CHECK-NEXT: Type: I32 | |
| 53 | ; CHECK-NEXT: Mutable: false | |
| 54 | ; CHECK-NEXT: InitExpr: | |
| 55 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 56 | ; CHECK-NEXT: Value: 66560 | |
| 57 | ; CHECK-NEXT: - Index: 2 | |
| 58 | ; CHECK-NEXT: Type: I32 | |
| 59 | ; CHECK-NEXT: Mutable: false | |
| 60 | ; CHECK-NEXT: InitExpr: | |
| 61 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 62 | ; CHECK-NEXT: Value: 1024 | |
| 63 | 51 | ; CHECK-NEXT: - Type: EXPORT |
| 64 | 52 | ; CHECK-NEXT: Exports: |
| 65 | 53 | ; CHECK-NEXT: - Name: memory |
| 66 | 54 | ; CHECK-NEXT: Kind: MEMORY |
| 67 | 55 | ; CHECK-NEXT: Index: 0 |
| 68 | ; CHECK-NEXT: - Name: __heap_base | |
| 69 | ; CHECK-NEXT: Kind: GLOBAL | |
| 70 | ; CHECK-NEXT: Index: 1 | |
| 71 | ; CHECK-NEXT: - Name: __data_end | |
| 72 | ; CHECK-NEXT: Kind: GLOBAL | |
| 73 | ; CHECK-NEXT: Index: 2 | |
| 74 | 56 | ; CHECK-NEXT: - Name: _start |
| 75 | 57 | ; CHECK-NEXT: Kind: FUNCTION |
| 76 | ; CHECK-NEXT: Index: 1 | |
| 58 | ; CHECK-NEXT: Index: 0 | |
| 77 | 59 | ; CHECK-NEXT: - Name: alias_fn |
| 78 | 60 | ; CHECK-NEXT: Kind: FUNCTION |
| 79 | ; CHECK-NEXT: Index: 2 | |
| 61 | ; CHECK-NEXT: Index: 1 | |
| 80 | 62 | ; CHECK-NEXT: - Name: direct_fn |
| 81 | 63 | ; CHECK-NEXT: Kind: FUNCTION |
| 82 | ; CHECK-NEXT: Index: 2 | |
| 64 | ; CHECK-NEXT: Index: 1 | |
| 83 | 65 | ; CHECK-NEXT: - Name: call_direct |
| 84 | 66 | ; CHECK-NEXT: Kind: FUNCTION |
| 85 | ; CHECK-NEXT: Index: 3 | |
| 67 | ; CHECK-NEXT: Index: 2 | |
| 86 | 68 | ; CHECK-NEXT: - Name: call_alias |
| 87 | 69 | ; CHECK-NEXT: Kind: FUNCTION |
| 88 | ; CHECK-NEXT: Index: 4 | |
| 70 | ; CHECK-NEXT: Index: 3 | |
| 89 | 71 | ; CHECK-NEXT: - Name: call_alias_ptr |
| 90 | 72 | ; CHECK-NEXT: Kind: FUNCTION |
| 91 | ; CHECK-NEXT: Index: 5 | |
| 73 | ; CHECK-NEXT: Index: 4 | |
| 92 | 74 | ; CHECK-NEXT: - Name: call_direct_ptr |
| 93 | 75 | ; CHECK-NEXT: Kind: FUNCTION |
| 94 | ; CHECK-NEXT: Index: 6 | |
| 76 | ; CHECK-NEXT: Index: 5 | |
| 95 | 77 | ; CHECK-NEXT: - Type: ELEM |
| 96 | 78 | ; CHECK-NEXT: Segments: |
| 97 | 79 | ; CHECK-NEXT: - Offset: |
| 98 | 80 | ; CHECK-NEXT: Opcode: I32_CONST |
| 99 | 81 | ; CHECK-NEXT: Value: 1 |
| 100 | ; CHECK-NEXT: Functions: [ 2 ] | |
| 82 | ; CHECK-NEXT: Functions: [ 1 ] | |
| 101 | 83 | ; CHECK-NEXT: - Type: CODE |
| 102 | 84 | ; CHECK-NEXT: Functions: |
| 103 | 85 | ; CHECK-NEXT: - Index: 0 |
| 104 | 86 | ; CHECK-NEXT: Locals: |
| 105 | ; CHECK-NEXT: Body: 0B | |
| 87 | ; CHECK-NEXT: Body: 1081808080001A0B | |
| 106 | 88 | ; CHECK-NEXT: - Index: 1 |
| 107 | 89 | ; CHECK-NEXT: Locals: |
| 108 | ; CHECK-NEXT: Body: 1082808080001A0B | |
| 90 | ; CHECK-NEXT: Body: 41000B | |
| 109 | 91 | ; CHECK-NEXT: - Index: 2 |
| 110 | 92 | ; CHECK-NEXT: Locals: |
| 111 | ; CHECK-NEXT: Body: 41000B | |
| 93 | ; CHECK-NEXT: Body: 1081808080000B | |
| 112 | 94 | ; CHECK-NEXT: - Index: 3 |
| 113 | 95 | ; CHECK-NEXT: Locals: |
| 114 | ; CHECK-NEXT: Body: 1082808080000B | |
| 96 | ; CHECK-NEXT: Body: 1081808080000B | |
| 115 | 97 | ; CHECK-NEXT: - Index: 4 |
| 116 | 98 | ; CHECK-NEXT: Locals: |
| 117 | ; CHECK-NEXT: Body: 1082808080000B | |
| 118 | ; CHECK-NEXT: - Index: 5 | |
| 119 | ; CHECK-NEXT: Locals: | |
| 120 | 99 | ; CHECK-NEXT: - Type: I32 |
| 121 | 100 | ; CHECK-NEXT: Count: 2 |
| 122 | ; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081082808080002101200041106A24808080800020010B | |
| 123 | ; CHECK-NEXT: - Index: 6 | |
| 101 | ; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081081808080002101200041106A24808080800020010B | |
| 102 | ; CHECK-NEXT: - Index: 5 | |
| 124 | 103 | ; CHECK-NEXT: Locals: |
| 125 | 104 | ; CHECK-NEXT: - Type: I32 |
| 126 | 105 | ; CHECK-NEXT: Count: 2 |
| 127 | ; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081082808080002101200041106A24808080800020010B | |
| 106 | ; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081081808080002101200041106A24808080800020010B | |
| 128 | 107 | ; CHECK-NEXT: - Type: CUSTOM |
| 129 | 108 | ; CHECK-NEXT: Name: name |
| 130 | 109 | ; CHECK-NEXT: FunctionNames: |
| 131 | 110 | ; CHECK-NEXT: - Index: 0 |
| 132 | ; CHECK-NEXT: Name: __wasm_call_ctors | |
| 133 | ; CHECK-NEXT: - Index: 1 | |
| 134 | 111 | ; CHECK-NEXT: Name: _start |
| 135 | ; CHECK-NEXT: - Index: 2 | |
| 112 | ; CHECK-NEXT: - Index: 1 | |
| 136 | 113 | ; CHECK-NEXT: Name: direct_fn |
| 137 | ; CHECK-NEXT: - Index: 3 | |
| 114 | ; CHECK-NEXT: - Index: 2 | |
| 138 | 115 | ; CHECK-NEXT: Name: call_direct |
| 139 | ; CHECK-NEXT: - Index: 4 | |
| 116 | ; CHECK-NEXT: - Index: 3 | |
| 140 | 117 | ; CHECK-NEXT: Name: call_alias |
| 141 | ; CHECK-NEXT: - Index: 5 | |
| 118 | ; CHECK-NEXT: - Index: 4 | |
| 142 | 119 | ; CHECK-NEXT: Name: call_alias_ptr |
| 143 | ; CHECK-NEXT: - Index: 6 | |
| 120 | ; CHECK-NEXT: - Index: 5 | |
| 144 | 121 | ; CHECK-NEXT: Name: call_direct_ptr |
| 145 | 122 | ; CHECK-NEXT: ... |
| 146 | 123 | |
| ... | ... | @@ -186,43 +163,43 @@ entry: |
| 186 | 163 | ; RELOC-NEXT: Functions: [ 1 ] |
| 187 | 164 | ; RELOC-NEXT: - Type: CODE |
| 188 | 165 | ; RELOC-NEXT: Relocations: |
| 189 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB | |
| 166 | ; RELOC-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB | |
| 190 | 167 | ; RELOC-NEXT: Index: 1 |
| 191 | 168 | ; RELOC-NEXT: Offset: 0x00000004 |
| 192 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB | |
| 169 | ; RELOC-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB | |
| 193 | 170 | ; RELOC-NEXT: Index: 2 |
| 194 | 171 | ; RELOC-NEXT: Offset: 0x00000013 |
| 195 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB | |
| 172 | ; RELOC-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB | |
| 196 | 173 | ; RELOC-NEXT: Index: 1 |
| 197 | 174 | ; RELOC-NEXT: Offset: 0x0000001C |
| 198 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB | |
| 175 | ; RELOC-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB | |
| 199 | 176 | ; RELOC-NEXT: Index: 6 |
| 200 | 177 | ; RELOC-NEXT: Offset: 0x00000027 |
| 201 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB | |
| 178 | ; RELOC-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB | |
| 202 | 179 | ; RELOC-NEXT: Index: 6 |
| 203 | 180 | ; RELOC-NEXT: Offset: 0x00000032 |
| 204 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB | |
| 181 | ; RELOC-NEXT: - Type: R_WASM_TABLE_INDEX_SLEB | |
| 205 | 182 | ; RELOC-NEXT: Index: 1 |
| 206 | 183 | ; RELOC-NEXT: Offset: 0x0000003A |
| 207 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB | |
| 184 | ; RELOC-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB | |
| 208 | 185 | ; RELOC-NEXT: Index: 1 |
| 209 | 186 | ; RELOC-NEXT: Offset: 0x00000043 |
| 210 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB | |
| 187 | ; RELOC-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB | |
| 211 | 188 | ; RELOC-NEXT: Index: 6 |
| 212 | 189 | ; RELOC-NEXT: Offset: 0x00000050 |
| 213 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB | |
| 190 | ; RELOC-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB | |
| 214 | 191 | ; RELOC-NEXT: Index: 6 |
| 215 | 192 | ; RELOC-NEXT: Offset: 0x0000005D |
| 216 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB | |
| 193 | ; RELOC-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB | |
| 217 | 194 | ; RELOC-NEXT: Index: 6 |
| 218 | 195 | ; RELOC-NEXT: Offset: 0x00000068 |
| 219 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB | |
| 196 | ; RELOC-NEXT: - Type: R_WASM_TABLE_INDEX_SLEB | |
| 220 | 197 | ; RELOC-NEXT: Index: 2 |
| 221 | 198 | ; RELOC-NEXT: Offset: 0x00000070 |
| 222 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB | |
| 199 | ; RELOC-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB | |
| 223 | 200 | ; RELOC-NEXT: Index: 2 |
| 224 | 201 | ; RELOC-NEXT: Offset: 0x00000079 |
| 225 | ; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB | |
| 202 | ; RELOC-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB | |
| 226 | 203 | ; RELOC-NEXT: Index: 6 |
| 227 | 204 | ; RELOC-NEXT: Offset: 0x00000086 |
| 228 | 205 | ; RELOC-NEXT: Functions: |
deps/lld/test/wasm/weak-symbols.ll+14-37| ... | ... | @@ -29,7 +29,7 @@ entry: |
| 29 | 29 | ; CHECK-NEXT: ReturnType: I32 |
| 30 | 30 | ; CHECK-NEXT: ParamTypes: |
| 31 | 31 | ; CHECK-NEXT: - Type: FUNCTION |
| 32 | ; CHECK-NEXT: FunctionTypes: [ 0, 0, 1, 1, 1 ] | |
| 32 | ; CHECK-NEXT: FunctionTypes: [ 0, 1, 1, 1 ] | |
| 33 | 33 | ; CHECK-NEXT: - Type: TABLE |
| 34 | 34 | ; CHECK-NEXT: Tables: |
| 35 | 35 | ; CHECK-NEXT: - ElemType: FUNCREF |
| ... | ... | @@ -53,72 +53,51 @@ entry: |
| 53 | 53 | ; CHECK-NEXT: Mutable: false |
| 54 | 54 | ; CHECK-NEXT: InitExpr: |
| 55 | 55 | ; CHECK-NEXT: Opcode: I32_CONST |
| 56 | ; CHECK-NEXT: Value: 66576 | |
| 57 | ; CHECK-NEXT: - Index: 2 | |
| 58 | ; CHECK-NEXT: Type: I32 | |
| 59 | ; CHECK-NEXT: Mutable: false | |
| 60 | ; CHECK-NEXT: InitExpr: | |
| 61 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 62 | ; CHECK-NEXT: Value: 1028 | |
| 63 | ; CHECK-NEXT: - Index: 3 | |
| 64 | ; CHECK-NEXT: Type: I32 | |
| 65 | ; CHECK-NEXT: Mutable: false | |
| 66 | ; CHECK-NEXT: InitExpr: | |
| 67 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 68 | 56 | ; CHECK-NEXT: Value: 1024 |
| 69 | 57 | ; CHECK-NEXT: - Type: EXPORT |
| 70 | 58 | ; CHECK-NEXT: Exports: |
| 71 | 59 | ; CHECK-NEXT: - Name: memory |
| 72 | 60 | ; CHECK-NEXT: Kind: MEMORY |
| 73 | 61 | ; CHECK-NEXT: Index: 0 |
| 74 | ; CHECK-NEXT: - Name: __heap_base | |
| 75 | ; CHECK-NEXT: Kind: GLOBAL | |
| 76 | ; CHECK-NEXT: Index: 1 | |
| 77 | ; CHECK-NEXT: - Name: __data_end | |
| 78 | ; CHECK-NEXT: Kind: GLOBAL | |
| 79 | ; CHECK-NEXT: Index: 2 | |
| 80 | 62 | ; CHECK-NEXT: - Name: _start |
| 81 | 63 | ; CHECK-NEXT: Kind: FUNCTION |
| 82 | ; CHECK-NEXT: Index: 1 | |
| 64 | ; CHECK-NEXT: Index: 0 | |
| 83 | 65 | ; CHECK-NEXT: - Name: weakFn |
| 84 | 66 | ; CHECK-NEXT: Kind: FUNCTION |
| 85 | ; CHECK-NEXT: Index: 2 | |
| 67 | ; CHECK-NEXT: Index: 1 | |
| 86 | 68 | ; CHECK-NEXT: - Name: exportWeak1 |
| 87 | 69 | ; CHECK-NEXT: Kind: FUNCTION |
| 88 | ; CHECK-NEXT: Index: 3 | |
| 70 | ; CHECK-NEXT: Index: 2 | |
| 89 | 71 | ; CHECK-NEXT: - Name: weakGlobal |
| 90 | 72 | ; CHECK-NEXT: Kind: GLOBAL |
| 91 | ; CHECK-NEXT: Index: 3 | |
| 73 | ; CHECK-NEXT: Index: 1 | |
| 92 | 74 | ; CHECK-NEXT: - Name: exportWeak2 |
| 93 | 75 | ; CHECK-NEXT: Kind: FUNCTION |
| 94 | ; CHECK-NEXT: Index: 4 | |
| 76 | ; CHECK-NEXT: Index: 3 | |
| 95 | 77 | ; CHECK-NEXT: - Type: ELEM |
| 96 | 78 | ; CHECK-NEXT: Segments: |
| 97 | 79 | ; CHECK-NEXT: - Offset: |
| 98 | 80 | ; CHECK-NEXT: Opcode: I32_CONST |
| 99 | 81 | ; CHECK-NEXT: Value: 1 |
| 100 | ; CHECK-NEXT: Functions: [ 2 ] | |
| 82 | ; CHECK-NEXT: Functions: [ 1 ] | |
| 101 | 83 | ; CHECK-NEXT: - Type: CODE |
| 102 | 84 | ; CHECK-NEXT: Functions: |
| 103 | 85 | ; CHECK-NEXT: - Index: 0 |
| 104 | 86 | ; CHECK-NEXT: Locals: |
| 105 | ; CHECK-NEXT: Body: 0B | |
| 87 | ; CHECK-NEXT: Body: 1081808080001A0B | |
| 106 | 88 | ; CHECK-NEXT: - Index: 1 |
| 107 | 89 | ; CHECK-NEXT: Locals: |
| 108 | ; CHECK-NEXT: Body: 1082808080001A0B | |
| 109 | ; CHECK-NEXT: - Index: 2 | |
| 110 | ; CHECK-NEXT: Locals: | |
| 111 | 90 | ; CHECK-NEXT: Body: 41010B |
| 112 | ; CHECK-NEXT: - Index: 3 | |
| 91 | ; CHECK-NEXT: - Index: 2 | |
| 113 | 92 | ; CHECK-NEXT: Locals: |
| 114 | 93 | ; CHECK-NEXT: Body: 4181808080000B |
| 115 | ; CHECK-NEXT: - Index: 4 | |
| 94 | ; CHECK-NEXT: - Index: 3 | |
| 116 | 95 | ; CHECK-NEXT: Locals: |
| 117 | 96 | ; CHECK-NEXT: Body: 4181808080000B |
| 118 | 97 | ; CHECK-NEXT: - Type: DATA |
| 119 | 98 | ; CHECK-NEXT: Segments: |
| 120 | 99 | ; CHECK-NEXT: - SectionOffset: 7 |
| 121 | ; CHECK-NEXT: MemoryIndex: 0 | |
| 100 | ; CHECK-NEXT: InitFlags: 0 | |
| 122 | 101 | ; CHECK-NEXT: Offset: |
| 123 | 102 | ; CHECK-NEXT: Opcode: I32_CONST |
| 124 | 103 | ; CHECK-NEXT: Value: 1024 |
| ... | ... | @@ -127,13 +106,11 @@ entry: |
| 127 | 106 | ; CHECK-NEXT: Name: name |
| 128 | 107 | ; CHECK-NEXT: FunctionNames: |
| 129 | 108 | ; CHECK-NEXT: - Index: 0 |
| 130 | ; CHECK-NEXT: Name: __wasm_call_ctors | |
| 131 | ; CHECK-NEXT: - Index: 1 | |
| 132 | 109 | ; CHECK-NEXT: Name: _start |
| 133 | ; CHECK-NEXT: - Index: 2 | |
| 110 | ; CHECK-NEXT: - Index: 1 | |
| 134 | 111 | ; CHECK-NEXT: Name: weakFn |
| 135 | ; CHECK-NEXT: - Index: 3 | |
| 112 | ; CHECK-NEXT: - Index: 2 | |
| 136 | 113 | ; CHECK-NEXT: Name: exportWeak1 |
| 137 | ; CHECK-NEXT: - Index: 4 | |
| 114 | ; CHECK-NEXT: - Index: 3 | |
| 138 | 115 | ; CHECK-NEXT: Name: exportWeak2 |
| 139 | 116 | ; CHECK-NEXT: ... |
deps/lld/test/wasm/weak-undefined.ll+6-27| ... | ... | @@ -34,13 +34,13 @@ entry: |
| 34 | 34 | ; CHECK-NEXT: - Type: TYPE |
| 35 | 35 | ; CHECK-NEXT: Signatures: |
| 36 | 36 | ; CHECK-NEXT: - Index: 0 |
| 37 | ; CHECK-NEXT: ReturnType: NORESULT | |
| 37 | ; CHECK-NEXT: ReturnType: I32 | |
| 38 | 38 | ; CHECK-NEXT: ParamTypes: |
| 39 | 39 | ; CHECK-NEXT: - Index: 1 |
| 40 | ; CHECK-NEXT: ReturnType: I32 | |
| 40 | ; CHECK-NEXT: ReturnType: NORESULT | |
| 41 | 41 | ; CHECK-NEXT: ParamTypes: |
| 42 | 42 | ; CHECK-NEXT: - Type: FUNCTION |
| 43 | ; CHECK-NEXT: FunctionTypes: [ 0, 1, 1, 0 ] | |
| 43 | ; CHECK-NEXT: FunctionTypes: [ 0, 0, 1 ] | |
| 44 | 44 | ; CHECK-NEXT: - Type: TABLE |
| 45 | 45 | ; CHECK-NEXT: Tables: |
| 46 | 46 | ; CHECK-NEXT: - ElemType: FUNCREF |
| ... | ... | @@ -59,44 +59,23 @@ entry: |
| 59 | 59 | ; CHECK-NEXT: InitExpr: |
| 60 | 60 | ; CHECK-NEXT: Opcode: I32_CONST |
| 61 | 61 | ; CHECK-NEXT: Value: 66560 |
| 62 | ; CHECK-NEXT: - Index: 1 | |
| 63 | ; CHECK-NEXT: Type: I32 | |
| 64 | ; CHECK-NEXT: Mutable: false | |
| 65 | ; CHECK-NEXT: InitExpr: | |
| 66 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 67 | ; CHECK-NEXT: Value: 66560 | |
| 68 | ; CHECK-NEXT: - Index: 2 | |
| 69 | ; CHECK-NEXT: Type: I32 | |
| 70 | ; CHECK-NEXT: Mutable: false | |
| 71 | ; CHECK-NEXT: InitExpr: | |
| 72 | ; CHECK-NEXT: Opcode: I32_CONST | |
| 73 | ; CHECK-NEXT: Value: 1024 | |
| 74 | 62 | ; CHECK-NEXT: - Type: EXPORT |
| 75 | 63 | ; CHECK-NEXT: Exports: |
| 76 | 64 | ; CHECK-NEXT: - Name: memory |
| 77 | 65 | ; CHECK-NEXT: Kind: MEMORY |
| 78 | 66 | ; CHECK-NEXT: Index: 0 |
| 79 | ; CHECK-NEXT: - Name: __heap_base | |
| 80 | ; CHECK-NEXT: Kind: GLOBAL | |
| 81 | ; CHECK-NEXT: Index: 1 | |
| 82 | ; CHECK-NEXT: - Name: __data_end | |
| 83 | ; CHECK-NEXT: Kind: GLOBAL | |
| 84 | ; CHECK-NEXT: Index: 2 | |
| 85 | 67 | ; CHECK-NEXT: - Name: _start |
| 86 | 68 | ; CHECK-NEXT: Kind: FUNCTION |
| 87 | ; CHECK-NEXT: Index: 3 | |
| 69 | ; CHECK-NEXT: Index: 2 | |
| 88 | 70 | ; CHECK-NEXT: - Type: CODE |
| 89 | 71 | ; CHECK-NEXT: Functions: |
| 90 | 72 | ; CHECK-NEXT: - Index: 0 |
| 91 | 73 | ; CHECK-NEXT: Locals: |
| 92 | ; CHECK-NEXT: Body: 0B | |
| 74 | ; CHECK-NEXT: Body: 4180808080000B | |
| 93 | 75 | ; CHECK-NEXT: - Index: 1 |
| 94 | 76 | ; CHECK-NEXT: Locals: |
| 95 | 77 | ; CHECK-NEXT: Body: 4180808080000B |
| 96 | 78 | ; CHECK-NEXT: - Index: 2 |
| 97 | 79 | ; CHECK-NEXT: Locals: |
| 98 | ; CHECK-NEXT: Body: 4180808080000B | |
| 99 | ; CHECK-NEXT: - Index: 3 | |
| 100 | ; CHECK-NEXT: Locals: | |
| 101 | ; CHECK-NEXT: Body: 1082808080001A1081808080001A0B | |
| 80 | ; CHECK-NEXT: Body: 1081808080001A1080808080001A0B | |
| 102 | 81 | ; CHECK-NEXT: ... |
deps/lld/test/wasm/wrap.ll created+40| ... | ... | @@ -0,0 +1,40 @@ |
| 1 | ; RUN: llc -filetype=obj %s -o %t.o | |
| 2 | ; RUN: wasm-ld -wrap nosuchsym -wrap foo -o %t.wasm %t.o | |
| 3 | ; RUN: wasm-ld -emit-relocs -wrap foo -o %t.wasm %t.o | |
| 4 | ; RUN: obj2yaml %t.wasm | FileCheck %s | |
| 5 | ||
| 6 | target triple = "wasm32-unknown-unknown" | |
| 7 | ||
| 8 | define i32 @foo() { | |
| 9 | ret i32 1 | |
| 10 | } | |
| 11 | ||
| 12 | define void @_start() { | |
| 13 | entry: | |
| 14 | call i32 @foo() | |
| 15 | ret void | |
| 16 | } | |
| 17 | ||
| 18 | declare i32 @__real_foo() | |
| 19 | ||
| 20 | define i32 @__wrap_foo() { | |
| 21 | %rtn = call i32 @__real_foo() | |
| 22 | ret i32 %rtn | |
| 23 | } | |
| 24 | ||
| 25 | ; CHECK: - Type: CODE | |
| 26 | ; CHECK-NEXT: Relocations: | |
| 27 | ; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB | |
| 28 | ; CHECK-NEXT: Index: 2 | |
| 29 | ; CHECK-NEXT: Offset: 0x00000009 | |
| 30 | ; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB | |
| 31 | ; CHECK-NEXT: Index: 0 | |
| 32 | ; CHECK-NEXT: Offset: 0x00000013 | |
| 33 | ||
| 34 | ; CHECK: FunctionNames: | |
| 35 | ; CHECK-NEXT: - Index: 0 | |
| 36 | ; CHECK-NEXT: Name: foo | |
| 37 | ; CHECK-NEXT: - Index: 1 | |
| 38 | ; CHECK-NEXT: Name: _start | |
| 39 | ; CHECK-NEXT: - Index: 2 | |
| 40 | ; CHECK-NEXT: Name: __wrap_foo |
deps/lld/tools/lld/CMakeLists.txt+1| ... | ... | @@ -8,6 +8,7 @@ add_lld_tool(lld |
| 8 | 8 | |
| 9 | 9 | target_link_libraries(lld |
| 10 | 10 | PRIVATE |
| 11 | lldCommon | |
| 11 | 12 | lldCOFF |
| 12 | 13 | lldDriver |
| 13 | 14 | lldELF |
deps/lld/tools/lld/lld.cpp+64-43| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- tools/lld/lld.cpp - Linker Driver Dispatcher -----------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -27,9 +26,13 @@ |
| 27 | 26 | //===----------------------------------------------------------------------===// |
| 28 | 27 | |
| 29 | 28 | #include "lld/Common/Driver.h" |
| 29 | #include "lld/Common/Memory.h" | |
| 30 | 30 | #include "llvm/ADT/STLExtras.h" |
| 31 | #include "llvm/ADT/SmallVector.h" | |
| 31 | 32 | #include "llvm/ADT/StringSwitch.h" |
| 33 | #include "llvm/ADT/Triple.h" | |
| 32 | 34 | #include "llvm/ADT/Twine.h" |
| 35 | #include "llvm/Support/CommandLine.h" | |
| 33 | 36 | #include "llvm/Support/InitLLVM.h" |
| 34 | 37 | #include "llvm/Support/Path.h" |
| 35 | 38 | #include <cstdlib> |
| ... | ... | @@ -46,13 +49,13 @@ enum Flavor { |
| 46 | 49 | Wasm, // -flavor wasm |
| 47 | 50 | }; |
| 48 | 51 | |
| 49 | LLVM_ATTRIBUTE_NORETURN static void die(const Twine &S) { | |
| 50 | errs() << S << "\n"; | |
| 52 | LLVM_ATTRIBUTE_NORETURN static void die(const Twine &s) { | |
| 53 | errs() << s << "\n"; | |
| 51 | 54 | exit(1); |
| 52 | 55 | } |
| 53 | 56 | |
| 54 | static Flavor getFlavor(StringRef S) { | |
| 55 | return StringSwitch<Flavor>(S) | |
| 57 | static Flavor getFlavor(StringRef s) { | |
| 58 | return StringSwitch<Flavor>(s) | |
| 56 | 59 | .CasesLower("ld", "ld.lld", "gnu", Gnu) |
| 57 | 60 | .CasesLower("wasm", "ld-wasm", Wasm) |
| 58 | 61 | .CaseLower("link", WinLink) |
| ... | ... | @@ -60,55 +63,73 @@ static Flavor getFlavor(StringRef S) { |
| 60 | 63 | .Default(Invalid); |
| 61 | 64 | } |
| 62 | 65 | |
| 63 | static bool isPETarget(const std::vector<const char *> &V) { | |
| 64 | for (auto It = V.begin(); It + 1 != V.end(); ++It) { | |
| 65 | if (StringRef(*It) != "-m") | |
| 66 | static cl::TokenizerCallback getDefaultQuotingStyle() { | |
| 67 | if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32) | |
| 68 | return cl::TokenizeWindowsCommandLine; | |
| 69 | return cl::TokenizeGNUCommandLine; | |
| 70 | } | |
| 71 | ||
| 72 | static bool isPETargetName(StringRef s) { | |
| 73 | return s == "i386pe" || s == "i386pep" || s == "thumb2pe" || s == "arm64pe"; | |
| 74 | } | |
| 75 | ||
| 76 | static bool isPETarget(std::vector<const char *> &v) { | |
| 77 | for (auto it = v.begin(); it + 1 != v.end(); ++it) { | |
| 78 | if (StringRef(*it) != "-m") | |
| 79 | continue; | |
| 80 | return isPETargetName(*(it + 1)); | |
| 81 | } | |
| 82 | // Expand response files (arguments in the form of @<filename>) | |
| 83 | // to allow detecting the -m argument from arguments in them. | |
| 84 | SmallVector<const char *, 256> expandedArgs(v.data(), v.data() + v.size()); | |
| 85 | cl::ExpandResponseFiles(saver, getDefaultQuotingStyle(), expandedArgs); | |
| 86 | for (auto it = expandedArgs.begin(); it + 1 != expandedArgs.end(); ++it) { | |
| 87 | if (StringRef(*it) != "-m") | |
| 66 | 88 | continue; |
| 67 | StringRef S = *(It + 1); | |
| 68 | return S == "i386pe" || S == "i386pep" || S == "thumb2pe" || S == "arm64pe"; | |
| 89 | return isPETargetName(*(it + 1)); | |
| 69 | 90 | } |
| 70 | 91 | return false; |
| 71 | 92 | } |
| 72 | 93 | |
| 73 | static Flavor parseProgname(StringRef Progname) { | |
| 94 | static Flavor parseProgname(StringRef progname) { | |
| 74 | 95 | #if __APPLE__ |
| 75 | 96 | // Use Darwin driver for "ld" on Darwin. |
| 76 | if (Progname == "ld") | |
| 97 | if (progname == "ld") | |
| 77 | 98 | return Darwin; |
| 78 | 99 | #endif |
| 79 | 100 | |
| 80 | 101 | #if LLVM_ON_UNIX |
| 81 | 102 | // Use GNU driver for "ld" on other Unix-like system. |
| 82 | if (Progname == "ld") | |
| 103 | if (progname == "ld") | |
| 83 | 104 | return Gnu; |
| 84 | 105 | #endif |
| 85 | 106 | |
| 86 | 107 | // Progname may be something like "lld-gnu". Parse it. |
| 87 | SmallVector<StringRef, 3> V; | |
| 88 | Progname.split(V, "-"); | |
| 89 | for (StringRef S : V) | |
| 90 | if (Flavor F = getFlavor(S)) | |
| 91 | return F; | |
| 108 | SmallVector<StringRef, 3> v; | |
| 109 | progname.split(v, "-"); | |
| 110 | for (StringRef s : v) | |
| 111 | if (Flavor f = getFlavor(s)) | |
| 112 | return f; | |
| 92 | 113 | return Invalid; |
| 93 | 114 | } |
| 94 | 115 | |
| 95 | static Flavor parseFlavor(std::vector<const char *> &V) { | |
| 116 | static Flavor parseFlavor(std::vector<const char *> &v) { | |
| 96 | 117 | // Parse -flavor option. |
| 97 | if (V.size() > 1 && V[1] == StringRef("-flavor")) { | |
| 98 | if (V.size() <= 2) | |
| 118 | if (v.size() > 1 && v[1] == StringRef("-flavor")) { | |
| 119 | if (v.size() <= 2) | |
| 99 | 120 | die("missing arg value for '-flavor'"); |
| 100 | Flavor F = getFlavor(V[2]); | |
| 101 | if (F == Invalid) | |
| 102 | die("Unknown flavor: " + StringRef(V[2])); | |
| 103 | V.erase(V.begin() + 1, V.begin() + 3); | |
| 104 | return F; | |
| 121 | Flavor f = getFlavor(v[2]); | |
| 122 | if (f == Invalid) | |
| 123 | die("Unknown flavor: " + StringRef(v[2])); | |
| 124 | v.erase(v.begin() + 1, v.begin() + 3); | |
| 125 | return f; | |
| 105 | 126 | } |
| 106 | 127 | |
| 107 | 128 | // Deduct the flavor from argv[0]. |
| 108 | StringRef Arg0 = path::filename(V[0]); | |
| 109 | if (Arg0.endswith_lower(".exe")) | |
| 110 | Arg0 = Arg0.drop_back(4); | |
| 111 | return parseProgname(Arg0); | |
| 129 | StringRef arg0 = path::filename(v[0]); | |
| 130 | if (arg0.endswith_lower(".exe")) | |
| 131 | arg0 = arg0.drop_back(4); | |
| 132 | return parseProgname(arg0); | |
| 112 | 133 | } |
| 113 | 134 | |
| 114 | 135 | // If this function returns true, lld calls _exit() so that it quickly |
| ... | ... | @@ -121,21 +142,21 @@ static bool canExitEarly() { return StringRef(getenv("LLD_IN_TEST")) != "1"; } |
| 121 | 142 | |
| 122 | 143 | /// Universal linker main(). This linker emulates the gnu, darwin, or |
| 123 | 144 | /// windows linker based on the argv[0] or -flavor option. |
| 124 | int main(int Argc, const char **Argv) { | |
| 125 | InitLLVM X(Argc, Argv); | |
| 145 | int main(int argc, const char **argv) { | |
| 146 | InitLLVM x(argc, argv); | |
| 126 | 147 | |
| 127 | std::vector<const char *> Args(Argv, Argv + Argc); | |
| 128 | switch (parseFlavor(Args)) { | |
| 148 | std::vector<const char *> args(argv, argv + argc); | |
| 149 | switch (parseFlavor(args)) { | |
| 129 | 150 | case Gnu: |
| 130 | if (isPETarget(Args)) | |
| 131 | return !mingw::link(Args); | |
| 132 | return !elf::link(Args, canExitEarly()); | |
| 151 | if (isPETarget(args)) | |
| 152 | return !mingw::link(args); | |
| 153 | return !elf::link(args, canExitEarly()); | |
| 133 | 154 | case WinLink: |
| 134 | return !coff::link(Args, canExitEarly()); | |
| 155 | return !coff::link(args, canExitEarly()); | |
| 135 | 156 | case Darwin: |
| 136 | return !mach_o::link(Args, canExitEarly()); | |
| 157 | return !mach_o::link(args, canExitEarly()); | |
| 137 | 158 | case Wasm: |
| 138 | return !wasm::link(Args, canExitEarly()); | |
| 159 | return !wasm::link(args, canExitEarly()); | |
| 139 | 160 | default: |
| 140 | 161 | die("lld is a generic driver.\n" |
| 141 | 162 | "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld" |
deps/lld/unittests/DriverTests/DarwinLdDriverTest.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lld/unittest/DarwinLdDriverTest.cpp --------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | /// |
deps/lld/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lld/unittest/MachOTests/MachONormalizedFileBinaryReaderTests.cpp ---===// |
| 2 | 2 | // |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lld/unittest/MachOTests/MachONormalizedFileBinaryWriterTests.cpp ---===// |
| 2 | 2 | // |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lld/unittest/MachOTests/MachONormalizedFileToAtomsTests.cpp --------===// |
| 2 | 2 | // |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- lld/unittest/MachOTests/MachONormalizedFileYAMLTests.cpp -----------===// |
| 2 | 2 | // |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/utils/benchmark.py+12-8| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | #!/usr/bin/env python |
| 2 | 2 | # |
| 3 | # The LLVM Compiler Infrastructure | |
| 4 | # | |
| 5 | # This file is distributed under the University of Illinois Open Source | |
| 6 | # License. See LICENSE.TXT for details. | |
| 3 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | # See https://llvm.org/LICENSE.txt for license information. | |
| 5 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | # |
| 8 | 7 | # ==------------------------------------------------------------------------==# |
| 9 | 8 | |
| ... | ... | @@ -14,8 +13,13 @@ import subprocess |
| 14 | 13 | import json |
| 15 | 14 | import datetime |
| 16 | 15 | import argparse |
| 17 | import urllib | |
| 18 | import urllib2 | |
| 16 | try: | |
| 17 | from urllib.parse import urlencode | |
| 18 | from urllib.request import urlopen, Request | |
| 19 | except ImportError: | |
| 20 | from urllib import urlencode | |
| 21 | from urllib2 import urlopen, Request | |
| 22 | ||
| 19 | 23 | |
| 20 | 24 | parser = argparse.ArgumentParser() |
| 21 | 25 | parser.add_argument('benchmark_directory') |
| ... | ... | @@ -127,8 +131,8 @@ def buildLntJson(benchmarks): |
| 127 | 131 | return json.dumps(ret, sort_keys=True, indent=4) |
| 128 | 132 | |
| 129 | 133 | def submitToServer(data): |
| 130 | data2 = urllib.urlencode({ 'input_data' : data }).encode('ascii') | |
| 131 | urllib2.urlopen(urllib2.Request(args.url, data2)) | |
| 134 | data2 = urlencode({ 'input_data' : data }).encode('ascii') | |
| 135 | urlopen(Request(args.url, data2)) | |
| 132 | 136 | |
| 133 | 137 | os.chdir(args.benchmark_directory) |
| 134 | 138 | data = buildLntJson(getBenchmarks()) |
deps/lld/wasm/CMakeLists.txt+3-1| ... | ... | @@ -13,8 +13,10 @@ add_lld_library(lldWasm |
| 13 | 13 | LTO.cpp |
| 14 | 14 | MarkLive.cpp |
| 15 | 15 | OutputSections.cpp |
| 16 | Relocations.cpp | |
| 16 | 17 | SymbolTable.cpp |
| 17 | 18 | Symbols.cpp |
| 19 | SyntheticSections.cpp | |
| 18 | 20 | Writer.cpp |
| 19 | 21 | WriterUtils.cpp |
| 20 | 22 | |
| ... | ... | @@ -35,4 +37,4 @@ add_lld_library(lldWasm |
| 35 | 37 | DEPENDS |
| 36 | 38 | WasmOptionsTableGen |
| 37 | 39 | ${tablegen_deps} |
| 38 | ) | |
| \ No newline at end of file | ||
| 40 | ) |
deps/lld/wasm/Config.h+53-40| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Config.h -------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -18,49 +17,63 @@ |
| 18 | 17 | namespace lld { |
| 19 | 18 | namespace wasm { |
| 20 | 19 | |
| 20 | // This struct contains the global configuration for the linker. | |
| 21 | // Most fields are direct mapping from the command line options | |
| 22 | // and such fields have the same name as the corresponding options. | |
| 23 | // Most fields are initialized by the driver. | |
| 21 | 24 | struct Configuration { |
| 22 | bool AllowUndefined; | |
| 23 | bool CompressRelocations; | |
| 24 | bool Demangle; | |
| 25 | bool DisableVerify; | |
| 26 | bool ExportAll; | |
| 27 | bool ExportDynamic; | |
| 28 | bool ExportTable; | |
| 29 | bool GcSections; | |
| 30 | bool ImportMemory; | |
| 31 | bool SharedMemory; | |
| 32 | bool ImportTable; | |
| 33 | bool MergeDataSegments; | |
| 34 | bool Pie; | |
| 35 | bool PrintGcSections; | |
| 36 | bool Relocatable; | |
| 37 | bool SaveTemps; | |
| 38 | bool Shared; | |
| 39 | bool StripAll; | |
| 40 | bool StripDebug; | |
| 41 | bool StackFirst; | |
| 42 | uint32_t GlobalBase; | |
| 43 | uint32_t InitialMemory; | |
| 44 | uint32_t MaxMemory; | |
| 45 | uint32_t ZStackSize; | |
| 46 | unsigned LTOPartitions; | |
| 47 | unsigned LTOO; | |
| 48 | unsigned Optimize; | |
| 49 | unsigned ThinLTOJobs; | |
| 50 | llvm::StringRef Entry; | |
| 51 | llvm::StringRef OutputFile; | |
| 52 | llvm::StringRef ThinLTOCacheDir; | |
| 25 | bool allowUndefined; | |
| 26 | bool checkFeatures; | |
| 27 | bool compressRelocations; | |
| 28 | bool demangle; | |
| 29 | bool disableVerify; | |
| 30 | bool emitRelocs; | |
| 31 | bool exportAll; | |
| 32 | bool exportDynamic; | |
| 33 | bool exportTable; | |
| 34 | bool gcSections; | |
| 35 | bool importMemory; | |
| 36 | bool sharedMemory; | |
| 37 | bool passiveSegments; | |
| 38 | bool importTable; | |
| 39 | bool mergeDataSegments; | |
| 40 | bool pie; | |
| 41 | bool printGcSections; | |
| 42 | bool relocatable; | |
| 43 | bool saveTemps; | |
| 44 | bool shared; | |
| 45 | bool stripAll; | |
| 46 | bool stripDebug; | |
| 47 | bool stackFirst; | |
| 48 | bool trace; | |
| 49 | uint32_t globalBase; | |
| 50 | uint32_t initialMemory; | |
| 51 | uint32_t maxMemory; | |
| 52 | uint32_t zStackSize; | |
| 53 | unsigned ltoPartitions; | |
| 54 | unsigned ltoo; | |
| 55 | unsigned optimize; | |
| 56 | unsigned thinLTOJobs; | |
| 57 | ||
| 58 | llvm::StringRef entry; | |
| 59 | llvm::StringRef outputFile; | |
| 60 | llvm::StringRef thinLTOCacheDir; | |
| 61 | ||
| 62 | llvm::StringSet<> allowUndefinedSymbols; | |
| 63 | llvm::StringSet<> exportedSymbols; | |
| 64 | std::vector<llvm::StringRef> searchPaths; | |
| 65 | llvm::CachePruningPolicy thinLTOCachePolicy; | |
| 66 | llvm::Optional<std::vector<std::string>> features; | |
| 53 | 67 | |
| 54 | llvm::StringSet<> AllowUndefinedSymbols; | |
| 55 | std::vector<llvm::StringRef> SearchPaths; | |
| 56 | llvm::CachePruningPolicy ThinLTOCachePolicy; | |
| 68 | // The following config options do not directly correspond to any | |
| 69 | // particualr command line options. | |
| 57 | 70 | |
| 58 | 71 | // True if we are creating position-independent code. |
| 59 | bool Pic; | |
| 72 | bool isPic; | |
| 60 | 73 | }; |
| 61 | 74 | |
| 62 | 75 | // The only instance of Configuration struct. |
| 63 | extern Configuration *Config; | |
| 76 | extern Configuration *config; | |
| 64 | 77 | |
| 65 | 78 | } // namespace wasm |
| 66 | 79 | } // namespace lld |
deps/lld/wasm/Driver.cpp+498-325| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Driver.cpp ---------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -17,15 +16,18 @@ |
| 17 | 16 | #include "lld/Common/Args.h" |
| 18 | 17 | #include "lld/Common/ErrorHandler.h" |
| 19 | 18 | #include "lld/Common/Memory.h" |
| 19 | #include "lld/Common/Reproduce.h" | |
| 20 | 20 | #include "lld/Common/Strings.h" |
| 21 | 21 | #include "lld/Common/Threads.h" |
| 22 | 22 | #include "lld/Common/Version.h" |
| 23 | 23 | #include "llvm/ADT/Twine.h" |
| 24 | 24 | #include "llvm/Object/Wasm.h" |
| 25 | #include "llvm/Option/Arg.h" | |
| 25 | 26 | #include "llvm/Option/ArgList.h" |
| 26 | 27 | #include "llvm/Support/CommandLine.h" |
| 27 | 28 | #include "llvm/Support/Path.h" |
| 28 | 29 | #include "llvm/Support/Process.h" |
| 30 | #include "llvm/Support/TarWriter.h" | |
| 29 | 31 | #include "llvm/Support/TargetSelect.h" |
| 30 | 32 | |
| 31 | 33 | #define DEBUG_TYPE "lld" |
| ... | ... | @@ -38,7 +40,7 @@ using namespace llvm::wasm; |
| 38 | 40 | using namespace lld; |
| 39 | 41 | using namespace lld::wasm; |
| 40 | 42 | |
| 41 | Configuration *lld::wasm::Config; | |
| 43 | Configuration *lld::wasm::config; | |
| 42 | 44 | |
| 43 | 45 | namespace { |
| 44 | 46 | |
| ... | ... | @@ -63,39 +65,39 @@ static void initLLVM() { |
| 63 | 65 | |
| 64 | 66 | class LinkerDriver { |
| 65 | 67 | public: |
| 66 | void link(ArrayRef<const char *> ArgsArr); | |
| 68 | void link(ArrayRef<const char *> argsArr); | |
| 67 | 69 | |
| 68 | 70 | private: |
| 69 | void createFiles(opt::InputArgList &Args); | |
| 70 | void addFile(StringRef Path); | |
| 71 | void addLibrary(StringRef Name); | |
| 71 | void createFiles(opt::InputArgList &args); | |
| 72 | void addFile(StringRef path); | |
| 73 | void addLibrary(StringRef name); | |
| 72 | 74 | |
| 73 | 75 | // True if we are in --whole-archive and --no-whole-archive. |
| 74 | bool InWholeArchive = false; | |
| 76 | bool inWholeArchive = false; | |
| 75 | 77 | |
| 76 | std::vector<InputFile *> Files; | |
| 78 | std::vector<InputFile *> files; | |
| 77 | 79 | }; |
| 78 | 80 | } // anonymous namespace |
| 79 | 81 | |
| 80 | bool lld::wasm::link(ArrayRef<const char *> Args, bool CanExitEarly, | |
| 81 | raw_ostream &Error) { | |
| 82 | errorHandler().LogName = args::getFilenameWithoutExe(Args[0]); | |
| 83 | errorHandler().ErrorOS = &Error; | |
| 84 | errorHandler().ColorDiagnostics = Error.has_colors(); | |
| 85 | errorHandler().ErrorLimitExceededMsg = | |
| 82 | bool lld::wasm::link(ArrayRef<const char *> args, bool canExitEarly, | |
| 83 | raw_ostream &error) { | |
| 84 | errorHandler().logName = args::getFilenameWithoutExe(args[0]); | |
| 85 | errorHandler().errorOS = &error; | |
| 86 | errorHandler().colorDiagnostics = error.has_colors(); | |
| 87 | errorHandler().errorLimitExceededMsg = | |
| 86 | 88 | "too many errors emitted, stopping now (use " |
| 87 | 89 | "-error-limit=0 to see all errors)"; |
| 88 | 90 | |
| 89 | Config = make<Configuration>(); | |
| 90 | Symtab = make<SymbolTable>(); | |
| 91 | config = make<Configuration>(); | |
| 92 | symtab = make<SymbolTable>(); | |
| 91 | 93 | |
| 92 | 94 | initLLVM(); |
| 93 | LinkerDriver().link(Args); | |
| 95 | LinkerDriver().link(args); | |
| 94 | 96 | |
| 95 | 97 | // Exit immediately if we don't need to return to the caller. |
| 96 | 98 | // This saves time because the overhead of calling destructors |
| 97 | 99 | // for all globally-allocated objects is not negligible. |
| 98 | if (CanExitEarly) | |
| 100 | if (canExitEarly) | |
| 99 | 101 | exitLld(errorCount() ? 1 : 0); |
| 100 | 102 | |
| 101 | 103 | freeArena(); |
| ... | ... | @@ -108,7 +110,7 @@ bool lld::wasm::link(ArrayRef<const char *> Args, bool CanExitEarly, |
| 108 | 110 | #undef PREFIX |
| 109 | 111 | |
| 110 | 112 | // Create table mapping all options defined in Options.td |
| 111 | static const opt::OptTable::Info OptInfo[] = { | |
| 113 | static const opt::OptTable::Info optInfo[] = { | |
| 112 | 114 | #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ |
| 113 | 115 | {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ |
| 114 | 116 | X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, |
| ... | ... | @@ -119,57 +121,57 @@ static const opt::OptTable::Info OptInfo[] = { |
| 119 | 121 | namespace { |
| 120 | 122 | class WasmOptTable : public llvm::opt::OptTable { |
| 121 | 123 | public: |
| 122 | WasmOptTable() : OptTable(OptInfo) {} | |
| 123 | opt::InputArgList parse(ArrayRef<const char *> Argv); | |
| 124 | WasmOptTable() : OptTable(optInfo) {} | |
| 125 | opt::InputArgList parse(ArrayRef<const char *> argv); | |
| 124 | 126 | }; |
| 125 | 127 | } // namespace |
| 126 | 128 | |
| 127 | 129 | // Set color diagnostics according to -color-diagnostics={auto,always,never} |
| 128 | 130 | // or -no-color-diagnostics flags. |
| 129 | static void handleColorDiagnostics(opt::InputArgList &Args) { | |
| 130 | auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, | |
| 131 | static void handleColorDiagnostics(opt::InputArgList &args) { | |
| 132 | auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, | |
| 131 | 133 | OPT_no_color_diagnostics); |
| 132 | if (!Arg) | |
| 134 | if (!arg) | |
| 133 | 135 | return; |
| 134 | if (Arg->getOption().getID() == OPT_color_diagnostics) { | |
| 135 | errorHandler().ColorDiagnostics = true; | |
| 136 | } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) { | |
| 137 | errorHandler().ColorDiagnostics = false; | |
| 136 | if (arg->getOption().getID() == OPT_color_diagnostics) { | |
| 137 | errorHandler().colorDiagnostics = true; | |
| 138 | } else if (arg->getOption().getID() == OPT_no_color_diagnostics) { | |
| 139 | errorHandler().colorDiagnostics = false; | |
| 138 | 140 | } else { |
| 139 | StringRef S = Arg->getValue(); | |
| 140 | if (S == "always") | |
| 141 | errorHandler().ColorDiagnostics = true; | |
| 142 | else if (S == "never") | |
| 143 | errorHandler().ColorDiagnostics = false; | |
| 144 | else if (S != "auto") | |
| 145 | error("unknown option: --color-diagnostics=" + S); | |
| 141 | StringRef s = arg->getValue(); | |
| 142 | if (s == "always") | |
| 143 | errorHandler().colorDiagnostics = true; | |
| 144 | else if (s == "never") | |
| 145 | errorHandler().colorDiagnostics = false; | |
| 146 | else if (s != "auto") | |
| 147 | error("unknown option: --color-diagnostics=" + s); | |
| 146 | 148 | } |
| 147 | 149 | } |
| 148 | 150 | |
| 149 | 151 | // Find a file by concatenating given paths. |
| 150 | static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) { | |
| 151 | SmallString<128> S; | |
| 152 | path::append(S, Path1, Path2); | |
| 153 | if (fs::exists(S)) | |
| 154 | return S.str().str(); | |
| 152 | static Optional<std::string> findFile(StringRef path1, const Twine &path2) { | |
| 153 | SmallString<128> s; | |
| 154 | path::append(s, path1, path2); | |
| 155 | if (fs::exists(s)) | |
| 156 | return s.str().str(); | |
| 155 | 157 | return None; |
| 156 | 158 | } |
| 157 | 159 | |
| 158 | opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> Argv) { | |
| 159 | SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size()); | |
| 160 | opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> argv) { | |
| 161 | SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size()); | |
| 160 | 162 | |
| 161 | unsigned MissingIndex; | |
| 162 | unsigned MissingCount; | |
| 163 | unsigned missingIndex; | |
| 164 | unsigned missingCount; | |
| 163 | 165 | |
| 164 | 166 | // Expand response files (arguments in the form of @<filename>) |
| 165 | cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Vec); | |
| 167 | cl::ExpandResponseFiles(saver, cl::TokenizeGNUCommandLine, vec); | |
| 166 | 168 | |
| 167 | opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount); | |
| 169 | opt::InputArgList args = this->ParseArgs(vec, missingIndex, missingCount); | |
| 168 | 170 | |
| 169 | handleColorDiagnostics(Args); | |
| 170 | for (auto *Arg : Args.filtered(OPT_UNKNOWN)) | |
| 171 | error("unknown argument: " + Arg->getSpelling()); | |
| 172 | return Args; | |
| 171 | handleColorDiagnostics(args); | |
| 172 | for (auto *arg : args.filtered(OPT_UNKNOWN)) | |
| 173 | error("unknown argument: " + arg->getAsString(args)); | |
| 174 | return args; | |
| 173 | 175 | } |
| 174 | 176 | |
| 175 | 177 | // Currently we allow a ".imports" to live alongside a library. This can |
| ... | ... | @@ -179,149 +181,188 @@ opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> Argv) { |
| 179 | 181 | // In the long run this information would be better stored as a symbol |
| 180 | 182 | // attribute/flag in the object file itself. |
| 181 | 183 | // See: https://github.com/WebAssembly/tool-conventions/issues/35 |
| 182 | static void readImportFile(StringRef Filename) { | |
| 183 | if (Optional<MemoryBufferRef> Buf = readFile(Filename)) | |
| 184 | for (StringRef Sym : args::getLines(*Buf)) | |
| 185 | Config->AllowUndefinedSymbols.insert(Sym); | |
| 184 | static void readImportFile(StringRef filename) { | |
| 185 | if (Optional<MemoryBufferRef> buf = readFile(filename)) | |
| 186 | for (StringRef sym : args::getLines(*buf)) | |
| 187 | config->allowUndefinedSymbols.insert(sym); | |
| 186 | 188 | } |
| 187 | 189 | |
| 188 | 190 | // Returns slices of MB by parsing MB as an archive file. |
| 189 | 191 | // Each slice consists of a member file in the archive. |
| 190 | std::vector<MemoryBufferRef> static getArchiveMembers(MemoryBufferRef MB) { | |
| 191 | std::unique_ptr<Archive> File = | |
| 192 | CHECK(Archive::create(MB), | |
| 193 | MB.getBufferIdentifier() + ": failed to parse archive"); | |
| 194 | ||
| 195 | std::vector<MemoryBufferRef> V; | |
| 196 | Error Err = Error::success(); | |
| 197 | for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) { | |
| 198 | Archive::Child C = | |
| 199 | CHECK(COrErr, MB.getBufferIdentifier() + | |
| 192 | std::vector<MemoryBufferRef> static getArchiveMembers(MemoryBufferRef mb) { | |
| 193 | std::unique_ptr<Archive> file = | |
| 194 | CHECK(Archive::create(mb), | |
| 195 | mb.getBufferIdentifier() + ": failed to parse archive"); | |
| 196 | ||
| 197 | std::vector<MemoryBufferRef> v; | |
| 198 | Error err = Error::success(); | |
| 199 | for (const ErrorOr<Archive::Child> &cOrErr : file->children(err)) { | |
| 200 | Archive::Child c = | |
| 201 | CHECK(cOrErr, mb.getBufferIdentifier() + | |
| 200 | 202 | ": could not get the child of the archive"); |
| 201 | MemoryBufferRef MBRef = | |
| 202 | CHECK(C.getMemoryBufferRef(), | |
| 203 | MB.getBufferIdentifier() + | |
| 203 | MemoryBufferRef mbref = | |
| 204 | CHECK(c.getMemoryBufferRef(), | |
| 205 | mb.getBufferIdentifier() + | |
| 204 | 206 | ": could not get the buffer for a child of the archive"); |
| 205 | V.push_back(MBRef); | |
| 207 | v.push_back(mbref); | |
| 206 | 208 | } |
| 207 | if (Err) | |
| 208 | fatal(MB.getBufferIdentifier() + | |
| 209 | ": Archive::children failed: " + toString(std::move(Err))); | |
| 209 | if (err) | |
| 210 | fatal(mb.getBufferIdentifier() + | |
| 211 | ": Archive::children failed: " + toString(std::move(err))); | |
| 210 | 212 | |
| 211 | 213 | // Take ownership of memory buffers created for members of thin archives. |
| 212 | for (std::unique_ptr<MemoryBuffer> &MB : File->takeThinBuffers()) | |
| 213 | make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); | |
| 214 | for (std::unique_ptr<MemoryBuffer> &mb : file->takeThinBuffers()) | |
| 215 | make<std::unique_ptr<MemoryBuffer>>(std::move(mb)); | |
| 214 | 216 | |
| 215 | return V; | |
| 217 | return v; | |
| 216 | 218 | } |
| 217 | 219 | |
| 218 | void LinkerDriver::addFile(StringRef Path) { | |
| 219 | Optional<MemoryBufferRef> Buffer = readFile(Path); | |
| 220 | if (!Buffer.hasValue()) | |
| 220 | void LinkerDriver::addFile(StringRef path) { | |
| 221 | Optional<MemoryBufferRef> buffer = readFile(path); | |
| 222 | if (!buffer.hasValue()) | |
| 221 | 223 | return; |
| 222 | MemoryBufferRef MBRef = *Buffer; | |
| 224 | MemoryBufferRef mbref = *buffer; | |
| 223 | 225 | |
| 224 | switch (identify_magic(MBRef.getBuffer())) { | |
| 226 | switch (identify_magic(mbref.getBuffer())) { | |
| 225 | 227 | case file_magic::archive: { |
| 228 | SmallString<128> importFile = path; | |
| 229 | path::replace_extension(importFile, ".imports"); | |
| 230 | if (fs::exists(importFile)) | |
| 231 | readImportFile(importFile.str()); | |
| 232 | ||
| 226 | 233 | // Handle -whole-archive. |
| 227 | if (InWholeArchive) { | |
| 228 | for (MemoryBufferRef &M : getArchiveMembers(MBRef)) | |
| 229 | Files.push_back(createObjectFile(M)); | |
| 234 | if (inWholeArchive) { | |
| 235 | for (MemoryBufferRef &m : getArchiveMembers(mbref)) | |
| 236 | files.push_back(createObjectFile(m, path)); | |
| 230 | 237 | return; |
| 231 | 238 | } |
| 232 | 239 | |
| 233 | SmallString<128> ImportFile = Path; | |
| 234 | path::replace_extension(ImportFile, ".imports"); | |
| 235 | if (fs::exists(ImportFile)) | |
| 236 | readImportFile(ImportFile.str()); | |
| 240 | std::unique_ptr<Archive> file = | |
| 241 | CHECK(Archive::create(mbref), path + ": failed to parse archive"); | |
| 242 | ||
| 243 | if (!file->isEmpty() && !file->hasSymbolTable()) { | |
| 244 | error(mbref.getBufferIdentifier() + | |
| 245 | ": archive has no index; run ranlib to add one"); | |
| 246 | } | |
| 237 | 247 | |
| 238 | Files.push_back(make<ArchiveFile>(MBRef)); | |
| 248 | files.push_back(make<ArchiveFile>(mbref)); | |
| 239 | 249 | return; |
| 240 | 250 | } |
| 241 | 251 | case file_magic::bitcode: |
| 242 | 252 | case file_magic::wasm_object: |
| 243 | Files.push_back(createObjectFile(MBRef)); | |
| 253 | files.push_back(createObjectFile(mbref)); | |
| 244 | 254 | break; |
| 245 | 255 | default: |
| 246 | error("unknown file type: " + MBRef.getBufferIdentifier()); | |
| 256 | error("unknown file type: " + mbref.getBufferIdentifier()); | |
| 247 | 257 | } |
| 248 | 258 | } |
| 249 | 259 | |
| 250 | 260 | // Add a given library by searching it from input search paths. |
| 251 | void LinkerDriver::addLibrary(StringRef Name) { | |
| 252 | for (StringRef Dir : Config->SearchPaths) { | |
| 253 | if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a")) { | |
| 254 | addFile(*S); | |
| 261 | void LinkerDriver::addLibrary(StringRef name) { | |
| 262 | for (StringRef dir : config->searchPaths) { | |
| 263 | if (Optional<std::string> s = findFile(dir, "lib" + name + ".a")) { | |
| 264 | addFile(*s); | |
| 255 | 265 | return; |
| 256 | 266 | } |
| 257 | 267 | } |
| 258 | 268 | |
| 259 | error("unable to find library -l" + Name); | |
| 269 | error("unable to find library -l" + name); | |
| 260 | 270 | } |
| 261 | 271 | |
| 262 | void LinkerDriver::createFiles(opt::InputArgList &Args) { | |
| 263 | for (auto *Arg : Args) { | |
| 264 | switch (Arg->getOption().getUnaliasedOption().getID()) { | |
| 272 | void LinkerDriver::createFiles(opt::InputArgList &args) { | |
| 273 | for (auto *arg : args) { | |
| 274 | switch (arg->getOption().getID()) { | |
| 265 | 275 | case OPT_l: |
| 266 | addLibrary(Arg->getValue()); | |
| 276 | addLibrary(arg->getValue()); | |
| 267 | 277 | break; |
| 268 | 278 | case OPT_INPUT: |
| 269 | addFile(Arg->getValue()); | |
| 279 | addFile(arg->getValue()); | |
| 270 | 280 | break; |
| 271 | 281 | case OPT_whole_archive: |
| 272 | InWholeArchive = true; | |
| 282 | inWholeArchive = true; | |
| 273 | 283 | break; |
| 274 | 284 | case OPT_no_whole_archive: |
| 275 | InWholeArchive = false; | |
| 285 | inWholeArchive = false; | |
| 276 | 286 | break; |
| 277 | 287 | } |
| 278 | 288 | } |
| 279 | 289 | } |
| 280 | 290 | |
| 281 | static StringRef getEntry(opt::InputArgList &Args, StringRef Default) { | |
| 282 | auto *Arg = Args.getLastArg(OPT_entry, OPT_no_entry); | |
| 283 | if (!Arg) | |
| 284 | return Default; | |
| 285 | if (Arg->getOption().getID() == OPT_no_entry) | |
| 291 | static StringRef getEntry(opt::InputArgList &args) { | |
| 292 | auto *arg = args.getLastArg(OPT_entry, OPT_no_entry); | |
| 293 | if (!arg) { | |
| 294 | if (args.hasArg(OPT_relocatable)) | |
| 295 | return ""; | |
| 296 | if (args.hasArg(OPT_shared)) | |
| 297 | return "__wasm_call_ctors"; | |
| 298 | return "_start"; | |
| 299 | } | |
| 300 | if (arg->getOption().getID() == OPT_no_entry) | |
| 286 | 301 | return ""; |
| 287 | return Arg->getValue(); | |
| 302 | return arg->getValue(); | |
| 288 | 303 | } |
| 289 | 304 | |
| 290 | static const uint8_t UnreachableFn[] = { | |
| 291 | 0x03 /* ULEB length */, 0x00 /* ULEB num locals */, | |
| 292 | 0x00 /* opcode unreachable */, 0x0b /* opcode end */ | |
| 293 | }; | |
| 294 | ||
| 295 | // For weak undefined functions, there may be "call" instructions that reference | |
| 296 | // the symbol. In this case, we need to synthesise a dummy/stub function that | |
| 297 | // will abort at runtime, so that relocations can still provided an operand to | |
| 298 | // the call instruction that passes Wasm validation. | |
| 299 | static void handleWeakUndefines() { | |
| 300 | for (Symbol *Sym : Symtab->getSymbols()) { | |
| 301 | if (!Sym->isUndefined() || !Sym->isWeak()) | |
| 302 | continue; | |
| 303 | auto *FuncSym = dyn_cast<FunctionSymbol>(Sym); | |
| 304 | if (!FuncSym) | |
| 305 | continue; | |
| 306 | ||
| 307 | // It is possible for undefined functions not to have a signature (eg. if | |
| 308 | // added via "--undefined"), but weak undefined ones do have a signature. | |
| 309 | assert(FuncSym->Signature); | |
| 310 | const WasmSignature &Sig = *FuncSym->Signature; | |
| 311 | ||
| 312 | // Add a synthetic dummy for weak undefined functions. These dummies will | |
| 313 | // be GC'd if not used as the target of any "call" instructions. | |
| 314 | std::string SymName = toString(*Sym); | |
| 315 | StringRef DebugName = Saver.save("undefined function " + SymName); | |
| 316 | auto *Func = make<SyntheticFunction>(Sig, Sym->getName(), DebugName); | |
| 317 | Func->setBody(UnreachableFn); | |
| 318 | // Ensure it compares equal to the null pointer, and so that table relocs | |
| 319 | // don't pull in the stub body (only call-operand relocs should do that). | |
| 320 | Func->setTableIndex(0); | |
| 321 | Symtab->SyntheticFunctions.emplace_back(Func); | |
| 322 | // Hide our dummy to prevent export. | |
| 323 | uint32_t Flags = WASM_SYMBOL_VISIBILITY_HIDDEN; | |
| 324 | replaceSymbol<DefinedFunction>(Sym, Sym->getName(), Flags, nullptr, Func); | |
| 305 | // Initializes Config members by the command line options. | |
| 306 | static void readConfigs(opt::InputArgList &args) { | |
| 307 | config->allowUndefined = args.hasArg(OPT_allow_undefined); | |
| 308 | config->checkFeatures = | |
| 309 | args.hasFlag(OPT_check_features, OPT_no_check_features, true); | |
| 310 | config->compressRelocations = args.hasArg(OPT_compress_relocations); | |
| 311 | config->demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true); | |
| 312 | config->disableVerify = args.hasArg(OPT_disable_verify); | |
| 313 | config->emitRelocs = args.hasArg(OPT_emit_relocs); | |
| 314 | config->entry = getEntry(args); | |
| 315 | config->exportAll = args.hasArg(OPT_export_all); | |
| 316 | config->exportDynamic = args.hasFlag(OPT_export_dynamic, | |
| 317 | OPT_no_export_dynamic, false); | |
| 318 | config->exportTable = args.hasArg(OPT_export_table); | |
| 319 | errorHandler().fatalWarnings = | |
| 320 | args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); | |
| 321 | config->importMemory = args.hasArg(OPT_import_memory); | |
| 322 | config->sharedMemory = args.hasArg(OPT_shared_memory); | |
| 323 | config->passiveSegments = args.hasFlag( | |
| 324 | OPT_passive_segments, OPT_active_segments, config->sharedMemory); | |
| 325 | config->importTable = args.hasArg(OPT_import_table); | |
| 326 | config->ltoo = args::getInteger(args, OPT_lto_O, 2); | |
| 327 | config->ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1); | |
| 328 | config->optimize = args::getInteger(args, OPT_O, 0); | |
| 329 | config->outputFile = args.getLastArgValue(OPT_o); | |
| 330 | config->relocatable = args.hasArg(OPT_relocatable); | |
| 331 | config->gcSections = | |
| 332 | args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !config->relocatable); | |
| 333 | config->mergeDataSegments = | |
| 334 | args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments, | |
| 335 | !config->relocatable); | |
| 336 | config->pie = args.hasFlag(OPT_pie, OPT_no_pie, false); | |
| 337 | config->printGcSections = | |
| 338 | args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false); | |
| 339 | config->saveTemps = args.hasArg(OPT_save_temps); | |
| 340 | config->searchPaths = args::getStrings(args, OPT_L); | |
| 341 | config->shared = args.hasArg(OPT_shared); | |
| 342 | config->stripAll = args.hasArg(OPT_strip_all); | |
| 343 | config->stripDebug = args.hasArg(OPT_strip_debug); | |
| 344 | config->stackFirst = args.hasArg(OPT_stack_first); | |
| 345 | config->trace = args.hasArg(OPT_trace); | |
| 346 | config->thinLTOCacheDir = args.getLastArgValue(OPT_thinlto_cache_dir); | |
| 347 | config->thinLTOCachePolicy = CHECK( | |
| 348 | parseCachePruningPolicy(args.getLastArgValue(OPT_thinlto_cache_policy)), | |
| 349 | "--thinlto-cache-policy: invalid cache policy"); | |
| 350 | config->thinLTOJobs = args::getInteger(args, OPT_thinlto_jobs, -1u); | |
| 351 | errorHandler().verbose = args.hasArg(OPT_verbose); | |
| 352 | LLVM_DEBUG(errorHandler().verbose = true); | |
| 353 | threadsEnabled = args.hasFlag(OPT_threads, OPT_no_threads, true); | |
| 354 | ||
| 355 | config->initialMemory = args::getInteger(args, OPT_initial_memory, 0); | |
| 356 | config->globalBase = args::getInteger(args, OPT_global_base, 1024); | |
| 357 | config->maxMemory = args::getInteger(args, OPT_max_memory, 0); | |
| 358 | config->zStackSize = | |
| 359 | args::getZOptionValue(args, OPT_z, "stack-size", WasmPageSize); | |
| 360 | ||
| 361 | if (auto *arg = args.getLastArg(OPT_features)) { | |
| 362 | config->features = | |
| 363 | llvm::Optional<std::vector<std::string>>(std::vector<std::string>()); | |
| 364 | for (StringRef s : arg->getValues()) | |
| 365 | config->features->push_back(s); | |
| 325 | 366 | } |
| 326 | 367 | } |
| 327 | 368 | |
| ... | ... | @@ -329,286 +370,418 @@ static void handleWeakUndefines() { |
| 329 | 370 | // command line options, but computed based on other Config values. |
| 330 | 371 | // This function initialize such members. See Config.h for the details |
| 331 | 372 | // of these values. |
| 332 | static void setConfigs(opt::InputArgList &Args) { | |
| 333 | Config->AllowUndefined = Args.hasArg(OPT_allow_undefined); | |
| 334 | Config->CompressRelocations = Args.hasArg(OPT_compress_relocations); | |
| 335 | Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true); | |
| 336 | Config->DisableVerify = Args.hasArg(OPT_disable_verify); | |
| 337 | Config->Entry = getEntry(Args, Args.hasArg(OPT_relocatable) ? "" : "_start"); | |
| 338 | Config->ExportAll = Args.hasArg(OPT_export_all); | |
| 339 | Config->ExportDynamic = Args.hasFlag(OPT_export_dynamic, | |
| 340 | OPT_no_export_dynamic, false); | |
| 341 | Config->ExportTable = Args.hasArg(OPT_export_table); | |
| 342 | errorHandler().FatalWarnings = | |
| 343 | Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); | |
| 344 | Config->ImportMemory = Args.hasArg(OPT_import_memory); | |
| 345 | Config->SharedMemory = Args.hasArg(OPT_shared_memory); | |
| 346 | Config->ImportTable = Args.hasArg(OPT_import_table); | |
| 347 | Config->LTOO = args::getInteger(Args, OPT_lto_O, 2); | |
| 348 | Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1); | |
| 349 | Config->Optimize = args::getInteger(Args, OPT_O, 0); | |
| 350 | Config->OutputFile = Args.getLastArgValue(OPT_o); | |
| 351 | Config->Relocatable = Args.hasArg(OPT_relocatable); | |
| 352 | Config->GcSections = | |
| 353 | Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !Config->Relocatable); | |
| 354 | Config->MergeDataSegments = | |
| 355 | Args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments, | |
| 356 | !Config->Relocatable); | |
| 357 | Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false); | |
| 358 | Config->PrintGcSections = | |
| 359 | Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false); | |
| 360 | Config->SaveTemps = Args.hasArg(OPT_save_temps); | |
| 361 | Config->SearchPaths = args::getStrings(Args, OPT_L); | |
| 362 | Config->Shared = Args.hasArg(OPT_shared); | |
| 363 | Config->StripAll = Args.hasArg(OPT_strip_all); | |
| 364 | Config->StripDebug = Args.hasArg(OPT_strip_debug); | |
| 365 | Config->StackFirst = Args.hasArg(OPT_stack_first); | |
| 366 | Config->ThinLTOCacheDir = Args.getLastArgValue(OPT_thinlto_cache_dir); | |
| 367 | Config->ThinLTOCachePolicy = CHECK( | |
| 368 | parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)), | |
| 369 | "--thinlto-cache-policy: invalid cache policy"); | |
| 370 | Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u); | |
| 371 | errorHandler().Verbose = Args.hasArg(OPT_verbose); | |
| 372 | ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); | |
| 373 | ||
| 374 | Config->InitialMemory = args::getInteger(Args, OPT_initial_memory, 0); | |
| 375 | Config->GlobalBase = args::getInteger(Args, OPT_global_base, 1024); | |
| 376 | Config->MaxMemory = args::getInteger(Args, OPT_max_memory, 0); | |
| 377 | Config->ZStackSize = | |
| 378 | args::getZOptionValue(Args, OPT_z, "stack-size", WasmPageSize); | |
| 373 | static void setConfigs() { | |
| 374 | config->isPic = config->pie || config->shared; | |
| 375 | ||
| 376 | if (config->isPic) { | |
| 377 | if (config->exportTable) | |
| 378 | error("-shared/-pie is incompatible with --export-table"); | |
| 379 | config->importTable = true; | |
| 380 | } | |
| 381 | ||
| 382 | if (config->shared) { | |
| 383 | config->importMemory = true; | |
| 384 | config->exportDynamic = true; | |
| 385 | config->allowUndefined = true; | |
| 386 | } | |
| 379 | 387 | } |
| 380 | 388 | |
| 381 | 389 | // Some command line options or some combinations of them are not allowed. |
| 382 | 390 | // This function checks for such errors. |
| 383 | static void checkOptions(opt::InputArgList &Args) { | |
| 384 | if (!Config->StripDebug && !Config->StripAll && Config->CompressRelocations) | |
| 391 | static void checkOptions(opt::InputArgList &args) { | |
| 392 | if (!config->stripDebug && !config->stripAll && config->compressRelocations) | |
| 385 | 393 | error("--compress-relocations is incompatible with output debug" |
| 386 | 394 | " information. Please pass --strip-debug or --strip-all"); |
| 387 | 395 | |
| 388 | if (Config->LTOO > 3) | |
| 389 | error("invalid optimization level for LTO: " + Twine(Config->LTOO)); | |
| 390 | if (Config->LTOPartitions == 0) | |
| 396 | if (config->ltoo > 3) | |
| 397 | error("invalid optimization level for LTO: " + Twine(config->ltoo)); | |
| 398 | if (config->ltoPartitions == 0) | |
| 391 | 399 | error("--lto-partitions: number of threads must be > 0"); |
| 392 | if (Config->ThinLTOJobs == 0) | |
| 400 | if (config->thinLTOJobs == 0) | |
| 393 | 401 | error("--thinlto-jobs: number of threads must be > 0"); |
| 394 | 402 | |
| 395 | if (Config->Pie && Config->Shared) | |
| 403 | if (config->pie && config->shared) | |
| 396 | 404 | error("-shared and -pie may not be used together"); |
| 397 | 405 | |
| 398 | if (Config->OutputFile.empty()) | |
| 406 | if (config->outputFile.empty()) | |
| 399 | 407 | error("no output file specified"); |
| 400 | 408 | |
| 401 | if (Config->ImportTable && Config->ExportTable) | |
| 409 | if (config->importTable && config->exportTable) | |
| 402 | 410 | error("--import-table and --export-table may not be used together"); |
| 403 | 411 | |
| 404 | if (Config->Relocatable) { | |
| 405 | if (!Config->Entry.empty()) | |
| 412 | if (config->relocatable) { | |
| 413 | if (!config->entry.empty()) | |
| 406 | 414 | error("entry point specified for relocatable output file"); |
| 407 | if (Config->GcSections) | |
| 415 | if (config->gcSections) | |
| 408 | 416 | error("-r and --gc-sections may not be used together"); |
| 409 | if (Config->CompressRelocations) | |
| 417 | if (config->compressRelocations) | |
| 410 | 418 | error("-r -and --compress-relocations may not be used together"); |
| 411 | if (Args.hasArg(OPT_undefined)) | |
| 419 | if (args.hasArg(OPT_undefined)) | |
| 412 | 420 | error("-r -and --undefined may not be used together"); |
| 413 | if (Config->Pie) | |
| 421 | if (config->pie) | |
| 414 | 422 | error("-r and -pie may not be used together"); |
| 415 | 423 | } |
| 416 | 424 | } |
| 417 | 425 | |
| 418 | 426 | // Force Sym to be entered in the output. Used for -u or equivalent. |
| 419 | static Symbol *handleUndefined(StringRef Name) { | |
| 420 | Symbol *Sym = Symtab->find(Name); | |
| 421 | if (!Sym) | |
| 427 | static Symbol *handleUndefined(StringRef name) { | |
| 428 | Symbol *sym = symtab->find(name); | |
| 429 | if (!sym) | |
| 422 | 430 | return nullptr; |
| 423 | 431 | |
| 424 | 432 | // Since symbol S may not be used inside the program, LTO may |
| 425 | 433 | // eliminate it. Mark the symbol as "used" to prevent it. |
| 426 | Sym->IsUsedInRegularObj = true; | |
| 434 | sym->isUsedInRegularObj = true; | |
| 427 | 435 | |
| 428 | if (auto *LazySym = dyn_cast<LazySymbol>(Sym)) | |
| 429 | LazySym->fetch(); | |
| 436 | if (auto *lazySym = dyn_cast<LazySymbol>(sym)) | |
| 437 | lazySym->fetch(); | |
| 430 | 438 | |
| 431 | return Sym; | |
| 439 | return sym; | |
| 432 | 440 | } |
| 433 | 441 | |
| 434 | 442 | static UndefinedGlobal * |
| 435 | createUndefinedGlobal(StringRef Name, llvm::wasm::WasmGlobalType *Type) { | |
| 436 | auto *Sym = | |
| 437 | cast<UndefinedGlobal>(Symtab->addUndefinedGlobal(Name, Name, | |
| 438 | DefaultModule, 0, | |
| 439 | nullptr, Type)); | |
| 440 | Config->AllowUndefinedSymbols.insert(Sym->getName()); | |
| 441 | Sym->IsUsedInRegularObj = true; | |
| 442 | return Sym; | |
| 443 | createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) { | |
| 444 | auto *sym = | |
| 445 | cast<UndefinedGlobal>(symtab->addUndefinedGlobal(name, name, | |
| 446 | defaultModule, 0, | |
| 447 | nullptr, type)); | |
| 448 | config->allowUndefinedSymbols.insert(sym->getName()); | |
| 449 | sym->isUsedInRegularObj = true; | |
| 450 | return sym; | |
| 443 | 451 | } |
| 444 | 452 | |
| 445 | 453 | // Create ABI-defined synthetic symbols |
| 446 | 454 | static void createSyntheticSymbols() { |
| 447 | static WasmSignature NullSignature = {{}, {}}; | |
| 448 | static llvm::wasm::WasmGlobalType GlobalTypeI32 = {WASM_TYPE_I32, false}; | |
| 449 | static llvm::wasm::WasmGlobalType MutableGlobalTypeI32 = {WASM_TYPE_I32, | |
| 455 | static WasmSignature nullSignature = {{}, {}}; | |
| 456 | static WasmSignature i32ArgSignature = {{}, {ValType::I32}}; | |
| 457 | static llvm::wasm::WasmGlobalType globalTypeI32 = {WASM_TYPE_I32, false}; | |
| 458 | static llvm::wasm::WasmGlobalType mutableGlobalTypeI32 = {WASM_TYPE_I32, | |
| 450 | 459 | true}; |
| 451 | 460 | |
| 452 | if (!Config->Relocatable) | |
| 453 | WasmSym::CallCtors = Symtab->addSyntheticFunction( | |
| 461 | if (!config->relocatable) { | |
| 462 | WasmSym::callCtors = symtab->addSyntheticFunction( | |
| 454 | 463 | "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN, |
| 455 | make<SyntheticFunction>(NullSignature, "__wasm_call_ctors")); | |
| 464 | make<SyntheticFunction>(nullSignature, "__wasm_call_ctors")); | |
| 465 | ||
| 466 | if (config->passiveSegments) { | |
| 467 | // Passive segments are used to avoid memory being reinitialized on each | |
| 468 | // thread's instantiation. These passive segments are initialized and | |
| 469 | // dropped in __wasm_init_memory, which is the first function called from | |
| 470 | // __wasm_call_ctors. | |
| 471 | WasmSym::initMemory = symtab->addSyntheticFunction( | |
| 472 | "__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN, | |
| 473 | make<SyntheticFunction>(nullSignature, "__wasm_init_memory")); | |
| 474 | } | |
| 456 | 475 | |
| 457 | // The __stack_pointer is imported in the shared library case, and exported | |
| 458 | // in the non-shared (executable) case. | |
| 459 | if (Config->Shared) { | |
| 460 | WasmSym::StackPointer = | |
| 461 | createUndefinedGlobal("__stack_pointer", &MutableGlobalTypeI32); | |
| 462 | } else { | |
| 463 | llvm::wasm::WasmGlobal Global; | |
| 464 | Global.Type = {WASM_TYPE_I32, true}; | |
| 465 | Global.InitExpr.Value.Int32 = 0; | |
| 466 | Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST; | |
| 467 | Global.SymbolName = "__stack_pointer"; | |
| 468 | auto *StackPointer = make<InputGlobal>(Global, nullptr); | |
| 469 | StackPointer->Live = true; | |
| 470 | // For non-PIC code | |
| 471 | // TODO(sbc): Remove WASM_SYMBOL_VISIBILITY_HIDDEN when the mutable global | |
| 472 | // spec proposal is implemented in all major browsers. | |
| 473 | // See: https://github.com/WebAssembly/mutable-global | |
| 474 | WasmSym::StackPointer = Symtab->addSyntheticGlobal( | |
| 475 | "__stack_pointer", WASM_SYMBOL_VISIBILITY_HIDDEN, StackPointer); | |
| 476 | WasmSym::HeapBase = Symtab->addSyntheticDataSymbol("__heap_base", 0); | |
| 477 | WasmSym::DataEnd = Symtab->addSyntheticDataSymbol("__data_end", 0); | |
| 478 | ||
| 479 | // These two synthetic symbols exist purely for the embedder so we always | |
| 480 | // want to export them. | |
| 481 | WasmSym::HeapBase->ForceExport = true; | |
| 482 | WasmSym::DataEnd->ForceExport = true; | |
| 476 | if (config->isPic) { | |
| 477 | // For PIC code we create a synthetic function __wasm_apply_relocs which | |
| 478 | // is called from __wasm_call_ctors before the user-level constructors. | |
| 479 | WasmSym::applyRelocs = symtab->addSyntheticFunction( | |
| 480 | "__wasm_apply_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN, | |
| 481 | make<SyntheticFunction>(nullSignature, "__wasm_apply_relocs")); | |
| 482 | } | |
| 483 | 483 | } |
| 484 | 484 | |
| 485 | if (Config->Pic) { | |
| 485 | if (!config->shared) | |
| 486 | WasmSym::dataEnd = symtab->addOptionalDataSymbol("__data_end"); | |
| 487 | ||
| 488 | if (config->isPic) { | |
| 489 | WasmSym::stackPointer = | |
| 490 | createUndefinedGlobal("__stack_pointer", &mutableGlobalTypeI32); | |
| 486 | 491 | // For PIC code, we import two global variables (__memory_base and |
| 487 | 492 | // __table_base) from the environment and use these as the offset at |
| 488 | 493 | // which to load our static data and function table. |
| 489 | 494 | // See: |
| 490 | 495 | // https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md |
| 491 | WasmSym::MemoryBase = | |
| 492 | createUndefinedGlobal("__memory_base", &GlobalTypeI32); | |
| 493 | WasmSym::TableBase = createUndefinedGlobal("__table_base", &GlobalTypeI32); | |
| 494 | WasmSym::MemoryBase->markLive(); | |
| 495 | WasmSym::TableBase->markLive(); | |
| 496 | WasmSym::memoryBase = | |
| 497 | createUndefinedGlobal("__memory_base", &globalTypeI32); | |
| 498 | WasmSym::tableBase = createUndefinedGlobal("__table_base", &globalTypeI32); | |
| 499 | WasmSym::memoryBase->markLive(); | |
| 500 | WasmSym::tableBase->markLive(); | |
| 501 | } else { | |
| 502 | llvm::wasm::WasmGlobal global; | |
| 503 | global.Type = {WASM_TYPE_I32, true}; | |
| 504 | global.InitExpr.Value.Int32 = 0; | |
| 505 | global.InitExpr.Opcode = WASM_OPCODE_I32_CONST; | |
| 506 | global.SymbolName = "__stack_pointer"; | |
| 507 | auto *stackPointer = make<InputGlobal>(global, nullptr); | |
| 508 | stackPointer->live = true; | |
| 509 | // For non-PIC code | |
| 510 | // TODO(sbc): Remove WASM_SYMBOL_VISIBILITY_HIDDEN when the mutable global | |
| 511 | // spec proposal is implemented in all major browsers. | |
| 512 | // See: https://github.com/WebAssembly/mutable-global | |
| 513 | WasmSym::stackPointer = symtab->addSyntheticGlobal( | |
| 514 | "__stack_pointer", WASM_SYMBOL_VISIBILITY_HIDDEN, stackPointer); | |
| 515 | WasmSym::globalBase = symtab->addOptionalDataSymbol("__global_base"); | |
| 516 | WasmSym::heapBase = symtab->addOptionalDataSymbol("__heap_base"); | |
| 496 | 517 | } |
| 497 | 518 | |
| 498 | WasmSym::DsoHandle = Symtab->addSyntheticDataSymbol( | |
| 519 | if (config->sharedMemory && !config->shared) { | |
| 520 | llvm::wasm::WasmGlobal tlsBaseGlobal; | |
| 521 | tlsBaseGlobal.Type = {WASM_TYPE_I32, true}; | |
| 522 | tlsBaseGlobal.InitExpr.Value.Int32 = 0; | |
| 523 | tlsBaseGlobal.InitExpr.Opcode = WASM_OPCODE_I32_CONST; | |
| 524 | tlsBaseGlobal.SymbolName = "__tls_base"; | |
| 525 | WasmSym::tlsBase = | |
| 526 | symtab->addSyntheticGlobal("__tls_base", WASM_SYMBOL_VISIBILITY_HIDDEN, | |
| 527 | make<InputGlobal>(tlsBaseGlobal, nullptr)); | |
| 528 | ||
| 529 | llvm::wasm::WasmGlobal tlsSizeGlobal; | |
| 530 | tlsSizeGlobal.Type = {WASM_TYPE_I32, false}; | |
| 531 | tlsSizeGlobal.InitExpr.Value.Int32 = 0; | |
| 532 | tlsSizeGlobal.InitExpr.Opcode = WASM_OPCODE_I32_CONST; | |
| 533 | tlsSizeGlobal.SymbolName = "__tls_size"; | |
| 534 | WasmSym::tlsSize = | |
| 535 | symtab->addSyntheticGlobal("__tls_size", WASM_SYMBOL_VISIBILITY_HIDDEN, | |
| 536 | make<InputGlobal>(tlsSizeGlobal, nullptr)); | |
| 537 | ||
| 538 | WasmSym::initTLS = symtab->addSyntheticFunction( | |
| 539 | "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN, | |
| 540 | make<SyntheticFunction>(i32ArgSignature, "__wasm_init_tls")); | |
| 541 | } | |
| 542 | ||
| 543 | WasmSym::dsoHandle = symtab->addSyntheticDataSymbol( | |
| 499 | 544 | "__dso_handle", WASM_SYMBOL_VISIBILITY_HIDDEN); |
| 500 | 545 | } |
| 501 | 546 | |
| 502 | void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { | |
| 503 | WasmOptTable Parser; | |
| 504 | opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); | |
| 547 | // Reconstructs command line arguments so that so that you can re-run | |
| 548 | // the same command with the same inputs. This is for --reproduce. | |
| 549 | static std::string createResponseFile(const opt::InputArgList &args) { | |
| 550 | SmallString<0> data; | |
| 551 | raw_svector_ostream os(data); | |
| 552 | ||
| 553 | // Copy the command line to the output while rewriting paths. | |
| 554 | for (auto *arg : args) { | |
| 555 | switch (arg->getOption().getID()) { | |
| 556 | case OPT_reproduce: | |
| 557 | break; | |
| 558 | case OPT_INPUT: | |
| 559 | os << quote(relativeToRoot(arg->getValue())) << "\n"; | |
| 560 | break; | |
| 561 | case OPT_o: | |
| 562 | // If -o path contains directories, "lld @response.txt" will likely | |
| 563 | // fail because the archive we are creating doesn't contain empty | |
| 564 | // directories for the output path (-o doesn't create directories). | |
| 565 | // Strip directories to prevent the issue. | |
| 566 | os << "-o " << quote(sys::path::filename(arg->getValue())) << "\n"; | |
| 567 | break; | |
| 568 | default: | |
| 569 | os << toString(*arg) << "\n"; | |
| 570 | } | |
| 571 | } | |
| 572 | return data.str(); | |
| 573 | } | |
| 574 | ||
| 575 | // The --wrap option is a feature to rename symbols so that you can write | |
| 576 | // wrappers for existing functions. If you pass `-wrap=foo`, all | |
| 577 | // occurrences of symbol `foo` are resolved to `wrap_foo` (so, you are | |
| 578 | // expected to write `wrap_foo` function as a wrapper). The original | |
| 579 | // symbol becomes accessible as `real_foo`, so you can call that from your | |
| 580 | // wrapper. | |
| 581 | // | |
| 582 | // This data structure is instantiated for each -wrap option. | |
| 583 | struct WrappedSymbol { | |
| 584 | Symbol *sym; | |
| 585 | Symbol *real; | |
| 586 | Symbol *wrap; | |
| 587 | }; | |
| 588 | ||
| 589 | static Symbol *addUndefined(StringRef name) { | |
| 590 | return symtab->addUndefinedFunction(name, "", "", 0, nullptr, nullptr, false); | |
| 591 | } | |
| 592 | ||
| 593 | // Handles -wrap option. | |
| 594 | // | |
| 595 | // This function instantiates wrapper symbols. At this point, they seem | |
| 596 | // like they are not being used at all, so we explicitly set some flags so | |
| 597 | // that LTO won't eliminate them. | |
| 598 | static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) { | |
| 599 | std::vector<WrappedSymbol> v; | |
| 600 | DenseSet<StringRef> seen; | |
| 601 | ||
| 602 | for (auto *arg : args.filtered(OPT_wrap)) { | |
| 603 | StringRef name = arg->getValue(); | |
| 604 | if (!seen.insert(name).second) | |
| 605 | continue; | |
| 606 | ||
| 607 | Symbol *sym = symtab->find(name); | |
| 608 | if (!sym) | |
| 609 | continue; | |
| 610 | ||
| 611 | Symbol *real = addUndefined(saver.save("__real_" + name)); | |
| 612 | Symbol *wrap = addUndefined(saver.save("__wrap_" + name)); | |
| 613 | v.push_back({sym, real, wrap}); | |
| 614 | ||
| 615 | // We want to tell LTO not to inline symbols to be overwritten | |
| 616 | // because LTO doesn't know the final symbol contents after renaming. | |
| 617 | real->canInline = false; | |
| 618 | sym->canInline = false; | |
| 619 | ||
| 620 | // Tell LTO not to eliminate these symbols. | |
| 621 | sym->isUsedInRegularObj = true; | |
| 622 | wrap->isUsedInRegularObj = true; | |
| 623 | real->isUsedInRegularObj = false; | |
| 624 | } | |
| 625 | return v; | |
| 626 | } | |
| 627 | ||
| 628 | // Do renaming for -wrap by updating pointers to symbols. | |
| 629 | // | |
| 630 | // When this function is executed, only InputFiles and symbol table | |
| 631 | // contain pointers to symbol objects. We visit them to replace pointers, | |
| 632 | // so that wrapped symbols are swapped as instructed by the command line. | |
| 633 | static void wrapSymbols(ArrayRef<WrappedSymbol> wrapped) { | |
| 634 | DenseMap<Symbol *, Symbol *> map; | |
| 635 | for (const WrappedSymbol &w : wrapped) { | |
| 636 | map[w.sym] = w.wrap; | |
| 637 | map[w.real] = w.sym; | |
| 638 | } | |
| 639 | ||
| 640 | // Update pointers in input files. | |
| 641 | parallelForEach(symtab->objectFiles, [&](InputFile *file) { | |
| 642 | MutableArrayRef<Symbol *> syms = file->getMutableSymbols(); | |
| 643 | for (size_t i = 0, e = syms.size(); i != e; ++i) | |
| 644 | if (Symbol *s = map.lookup(syms[i])) | |
| 645 | syms[i] = s; | |
| 646 | }); | |
| 647 | ||
| 648 | // Update pointers in the symbol table. | |
| 649 | for (const WrappedSymbol &w : wrapped) | |
| 650 | symtab->wrap(w.sym, w.real, w.wrap); | |
| 651 | } | |
| 652 | ||
| 653 | void LinkerDriver::link(ArrayRef<const char *> argsArr) { | |
| 654 | WasmOptTable parser; | |
| 655 | opt::InputArgList args = parser.parse(argsArr.slice(1)); | |
| 505 | 656 | |
| 506 | 657 | // Handle --help |
| 507 | if (Args.hasArg(OPT_help)) { | |
| 508 | Parser.PrintHelp(outs(), | |
| 509 | (std::string(ArgsArr[0]) + " [options] file...").c_str(), | |
| 658 | if (args.hasArg(OPT_help)) { | |
| 659 | parser.PrintHelp(outs(), | |
| 660 | (std::string(argsArr[0]) + " [options] file...").c_str(), | |
| 510 | 661 | "LLVM Linker", false); |
| 511 | 662 | return; |
| 512 | 663 | } |
| 513 | 664 | |
| 514 | 665 | // Handle --version |
| 515 | if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v)) { | |
| 666 | if (args.hasArg(OPT_version) || args.hasArg(OPT_v)) { | |
| 516 | 667 | outs() << getLLDVersion() << "\n"; |
| 517 | 668 | return; |
| 518 | 669 | } |
| 519 | 670 | |
| 671 | // Handle --reproduce | |
| 672 | if (auto *arg = args.getLastArg(OPT_reproduce)) { | |
| 673 | StringRef path = arg->getValue(); | |
| 674 | Expected<std::unique_ptr<TarWriter>> errOrWriter = | |
| 675 | TarWriter::create(path, path::stem(path)); | |
| 676 | if (errOrWriter) { | |
| 677 | tar = std::move(*errOrWriter); | |
| 678 | tar->append("response.txt", createResponseFile(args)); | |
| 679 | tar->append("version.txt", getLLDVersion() + "\n"); | |
| 680 | } else { | |
| 681 | error("--reproduce: " + toString(errOrWriter.takeError())); | |
| 682 | } | |
| 683 | } | |
| 684 | ||
| 520 | 685 | // Parse and evaluate -mllvm options. |
| 521 | std::vector<const char *> V; | |
| 522 | V.push_back("wasm-ld (LLVM option parsing)"); | |
| 523 | for (auto *Arg : Args.filtered(OPT_mllvm)) | |
| 524 | V.push_back(Arg->getValue()); | |
| 525 | cl::ParseCommandLineOptions(V.size(), V.data()); | |
| 686 | std::vector<const char *> v; | |
| 687 | v.push_back("wasm-ld (LLVM option parsing)"); | |
| 688 | for (auto *arg : args.filtered(OPT_mllvm)) | |
| 689 | v.push_back(arg->getValue()); | |
| 690 | cl::ParseCommandLineOptions(v.size(), v.data()); | |
| 526 | 691 | |
| 527 | errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20); | |
| 692 | errorHandler().errorLimit = args::getInteger(args, OPT_error_limit, 20); | |
| 528 | 693 | |
| 529 | setConfigs(Args); | |
| 530 | checkOptions(Args); | |
| 694 | readConfigs(args); | |
| 695 | setConfigs(); | |
| 696 | checkOptions(args); | |
| 531 | 697 | |
| 532 | if (auto *Arg = Args.getLastArg(OPT_allow_undefined_file)) | |
| 533 | readImportFile(Arg->getValue()); | |
| 698 | if (auto *arg = args.getLastArg(OPT_allow_undefined_file)) | |
| 699 | readImportFile(arg->getValue()); | |
| 534 | 700 | |
| 535 | if (!Args.hasArg(OPT_INPUT)) { | |
| 701 | if (!args.hasArg(OPT_INPUT)) { | |
| 536 | 702 | error("no input files"); |
| 537 | 703 | return; |
| 538 | 704 | } |
| 539 | 705 | |
| 540 | Config->Pic = Config->Pie || Config->Shared; | |
| 541 | ||
| 542 | if (Config->Pic) { | |
| 543 | if (Config->ExportTable) | |
| 544 | error("-shared/-pie is incompatible with --export-table"); | |
| 545 | Config->ImportTable = true; | |
| 546 | } | |
| 706 | // Handle --trace-symbol. | |
| 707 | for (auto *arg : args.filtered(OPT_trace_symbol)) | |
| 708 | symtab->trace(arg->getValue()); | |
| 547 | 709 | |
| 548 | if (Config->Shared) { | |
| 549 | Config->ExportDynamic = true; | |
| 550 | Config->AllowUndefined = true; | |
| 551 | } | |
| 710 | for (auto *arg : args.filtered(OPT_export)) | |
| 711 | config->exportedSymbols.insert(arg->getValue()); | |
| 552 | 712 | |
| 553 | if (!Config->Relocatable) | |
| 713 | if (!config->relocatable) | |
| 554 | 714 | createSyntheticSymbols(); |
| 555 | 715 | |
| 556 | createFiles(Args); | |
| 716 | createFiles(args); | |
| 557 | 717 | if (errorCount()) |
| 558 | 718 | return; |
| 559 | 719 | |
| 560 | 720 | // Add all files to the symbol table. This will add almost all |
| 561 | 721 | // symbols that we need to the symbol table. |
| 562 | for (InputFile *F : Files) | |
| 563 | Symtab->addFile(F); | |
| 722 | for (InputFile *f : files) | |
| 723 | symtab->addFile(f); | |
| 564 | 724 | if (errorCount()) |
| 565 | 725 | return; |
| 566 | 726 | |
| 567 | 727 | // Handle the `--undefined <sym>` options. |
| 568 | for (auto *Arg : Args.filtered(OPT_undefined)) | |
| 569 | handleUndefined(Arg->getValue()); | |
| 728 | for (auto *arg : args.filtered(OPT_undefined)) | |
| 729 | handleUndefined(arg->getValue()); | |
| 570 | 730 | |
| 571 | 731 | // Handle the `--export <sym>` options |
| 572 | 732 | // This works like --undefined but also exports the symbol if its found |
| 573 | for (auto *Arg : Args.filtered(OPT_export)) { | |
| 574 | Symbol *Sym = handleUndefined(Arg->getValue()); | |
| 575 | if (Sym && Sym->isDefined()) | |
| 576 | Sym->ForceExport = true; | |
| 577 | else if (!Config->AllowUndefined) | |
| 578 | error(Twine("symbol exported via --export not found: ") + | |
| 579 | Arg->getValue()); | |
| 580 | } | |
| 581 | ||
| 582 | Symbol *EntrySym = nullptr; | |
| 583 | if (!Config->Relocatable) { | |
| 584 | // Add synthetic dummies for weak undefined functions. | |
| 585 | handleWeakUndefines(); | |
| 586 | ||
| 587 | if (!Config->Shared && !Config->Entry.empty()) { | |
| 588 | EntrySym = handleUndefined(Config->Entry); | |
| 589 | if (EntrySym && EntrySym->isDefined()) | |
| 590 | EntrySym->ForceExport = true; | |
| 591 | else | |
| 592 | error("entry symbol not defined (pass --no-entry to supress): " + | |
| 593 | Config->Entry); | |
| 594 | } | |
| 595 | ||
| 596 | // Make sure we have resolved all symbols. | |
| 597 | if (!Config->AllowUndefined) | |
| 598 | Symtab->reportRemainingUndefines(); | |
| 733 | for (auto *arg : args.filtered(OPT_export)) | |
| 734 | handleUndefined(arg->getValue()); | |
| 735 | ||
| 736 | Symbol *entrySym = nullptr; | |
| 737 | if (!config->relocatable && !config->entry.empty()) { | |
| 738 | entrySym = handleUndefined(config->entry); | |
| 739 | if (entrySym && entrySym->isDefined()) | |
| 740 | entrySym->forceExport = true; | |
| 741 | else | |
| 742 | error("entry symbol not defined (pass --no-entry to supress): " + | |
| 743 | config->entry); | |
| 599 | 744 | } |
| 600 | 745 | |
| 601 | 746 | if (errorCount()) |
| 602 | 747 | return; |
| 603 | 748 | |
| 749 | // Create wrapped symbols for -wrap option. | |
| 750 | std::vector<WrappedSymbol> wrapped = addWrappedSymbols(args); | |
| 751 | ||
| 604 | 752 | // Do link-time optimization if given files are LLVM bitcode files. |
| 605 | 753 | // This compiles bitcode files into real object files. |
| 606 | Symtab->addCombinedLTOObject(); | |
| 754 | symtab->addCombinedLTOObject(); | |
| 607 | 755 | if (errorCount()) |
| 608 | 756 | return; |
| 609 | 757 | |
| 610 | if (EntrySym) | |
| 611 | EntrySym->setHidden(false); | |
| 758 | // Resolve any variant symbols that were created due to signature | |
| 759 | // mismatchs. | |
| 760 | symtab->handleSymbolVariants(); | |
| 761 | if (errorCount()) | |
| 762 | return; | |
| 763 | ||
| 764 | // Apply symbol renames for -wrap. | |
| 765 | if (!wrapped.empty()) | |
| 766 | wrapSymbols(wrapped); | |
| 767 | ||
| 768 | for (auto *arg : args.filtered(OPT_export)) { | |
| 769 | Symbol *sym = symtab->find(arg->getValue()); | |
| 770 | if (sym && sym->isDefined()) | |
| 771 | sym->forceExport = true; | |
| 772 | else if (!config->allowUndefined) | |
| 773 | error(Twine("symbol exported via --export not found: ") + | |
| 774 | arg->getValue()); | |
| 775 | } | |
| 776 | ||
| 777 | if (!config->relocatable) { | |
| 778 | // Add synthetic dummies for weak undefined functions. Must happen | |
| 779 | // after LTO otherwise functions may not yet have signatures. | |
| 780 | symtab->handleWeakUndefines(); | |
| 781 | } | |
| 782 | ||
| 783 | if (entrySym) | |
| 784 | entrySym->setHidden(false); | |
| 612 | 785 | |
| 613 | 786 | if (errorCount()) |
| 614 | 787 | return; |
deps/lld/wasm/InputChunks.cpp+214-158| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- InputChunks.cpp ----------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -23,8 +22,8 @@ using namespace llvm::support::endian; |
| 23 | 22 | using namespace lld; |
| 24 | 23 | using namespace lld::wasm; |
| 25 | 24 | |
| 26 | static StringRef reloctTypeToString(uint8_t RelocType) { | |
| 27 | switch (RelocType) { | |
| 25 | StringRef lld::relocTypeToString(uint8_t relocType) { | |
| 26 | switch (relocType) { | |
| 28 | 27 | #define WASM_RELOC(NAME, REL) \ |
| 29 | 28 | case REL: \ |
| 30 | 29 | return #NAME; |
| ... | ... | @@ -34,62 +33,67 @@ static StringRef reloctTypeToString(uint8_t RelocType) { |
| 34 | 33 | llvm_unreachable("unknown reloc type"); |
| 35 | 34 | } |
| 36 | 35 | |
| 37 | std::string lld::toString(const InputChunk *C) { | |
| 38 | return (toString(C->File) + ":(" + C->getName() + ")").str(); | |
| 36 | std::string lld::toString(const InputChunk *c) { | |
| 37 | return (toString(c->file) + ":(" + c->getName() + ")").str(); | |
| 39 | 38 | } |
| 40 | 39 | |
| 41 | 40 | StringRef InputChunk::getComdatName() const { |
| 42 | uint32_t Index = getComdat(); | |
| 43 | if (Index == UINT32_MAX) | |
| 41 | uint32_t index = getComdat(); | |
| 42 | if (index == UINT32_MAX) | |
| 44 | 43 | return StringRef(); |
| 45 | return File->getWasmObj()->linkingData().Comdats[Index]; | |
| 44 | return file->getWasmObj()->linkingData().Comdats[index]; | |
| 46 | 45 | } |
| 47 | 46 | |
| 48 | 47 | void InputChunk::verifyRelocTargets() const { |
| 49 | for (const WasmRelocation &Rel : Relocations) { | |
| 50 | uint32_t ExistingValue; | |
| 51 | unsigned BytesRead = 0; | |
| 52 | uint32_t Offset = Rel.Offset - getInputSectionOffset(); | |
| 53 | const uint8_t *Loc = data().data() + Offset; | |
| 54 | switch (Rel.Type) { | |
| 55 | case R_WEBASSEMBLY_TYPE_INDEX_LEB: | |
| 56 | case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: | |
| 57 | case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: | |
| 58 | case R_WEBASSEMBLY_EVENT_INDEX_LEB: | |
| 59 | case R_WEBASSEMBLY_MEMORY_ADDR_LEB: | |
| 60 | ExistingValue = decodeULEB128(Loc, &BytesRead); | |
| 48 | for (const WasmRelocation &rel : relocations) { | |
| 49 | uint32_t existingValue; | |
| 50 | unsigned bytesRead = 0; | |
| 51 | uint32_t offset = rel.Offset - getInputSectionOffset(); | |
| 52 | const uint8_t *loc = data().data() + offset; | |
| 53 | switch (rel.Type) { | |
| 54 | case R_WASM_TYPE_INDEX_LEB: | |
| 55 | case R_WASM_FUNCTION_INDEX_LEB: | |
| 56 | case R_WASM_GLOBAL_INDEX_LEB: | |
| 57 | case R_WASM_EVENT_INDEX_LEB: | |
| 58 | case R_WASM_MEMORY_ADDR_LEB: | |
| 59 | existingValue = decodeULEB128(loc, &bytesRead); | |
| 61 | 60 | break; |
| 62 | case R_WEBASSEMBLY_TABLE_INDEX_SLEB: | |
| 63 | case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: | |
| 64 | ExistingValue = static_cast<uint32_t>(decodeSLEB128(Loc, &BytesRead)); | |
| 61 | case R_WASM_TABLE_INDEX_SLEB: | |
| 62 | case R_WASM_TABLE_INDEX_REL_SLEB: | |
| 63 | case R_WASM_MEMORY_ADDR_SLEB: | |
| 64 | case R_WASM_MEMORY_ADDR_REL_SLEB: | |
| 65 | existingValue = static_cast<uint32_t>(decodeSLEB128(loc, &bytesRead)); | |
| 65 | 66 | break; |
| 66 | case R_WEBASSEMBLY_TABLE_INDEX_I32: | |
| 67 | case R_WEBASSEMBLY_MEMORY_ADDR_I32: | |
| 68 | case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: | |
| 69 | case R_WEBASSEMBLY_SECTION_OFFSET_I32: | |
| 70 | ExistingValue = static_cast<uint32_t>(read32le(Loc)); | |
| 67 | case R_WASM_TABLE_INDEX_I32: | |
| 68 | case R_WASM_MEMORY_ADDR_I32: | |
| 69 | case R_WASM_FUNCTION_OFFSET_I32: | |
| 70 | case R_WASM_SECTION_OFFSET_I32: | |
| 71 | existingValue = static_cast<uint32_t>(read32le(loc)); | |
| 71 | 72 | break; |
| 72 | 73 | default: |
| 73 | 74 | llvm_unreachable("unknown relocation type"); |
| 74 | 75 | } |
| 75 | 76 | |
| 76 | if (BytesRead && BytesRead != 5) | |
| 77 | if (bytesRead && bytesRead != 5) | |
| 77 | 78 | warn("expected LEB at relocation site be 5-byte padded"); |
| 78 | uint32_t ExpectedValue = File->calcExpectedValue(Rel); | |
| 79 | if (ExpectedValue != ExistingValue) | |
| 80 | warn("unexpected existing value for " + reloctTypeToString(Rel.Type) + | |
| 81 | ": existing=" + Twine(ExistingValue) + | |
| 82 | " expected=" + Twine(ExpectedValue)); | |
| 79 | ||
| 80 | if (rel.Type != R_WASM_GLOBAL_INDEX_LEB) { | |
| 81 | uint32_t expectedValue = file->calcExpectedValue(rel); | |
| 82 | if (expectedValue != existingValue) | |
| 83 | warn("unexpected existing value for " + relocTypeToString(rel.Type) + | |
| 84 | ": existing=" + Twine(existingValue) + | |
| 85 | " expected=" + Twine(expectedValue)); | |
| 86 | } | |
| 83 | 87 | } |
| 84 | 88 | } |
| 85 | 89 | |
| 86 | 90 | // Copy this input chunk to an mmap'ed output file and apply relocations. |
| 87 | void InputChunk::writeTo(uint8_t *Buf) const { | |
| 91 | void InputChunk::writeTo(uint8_t *buf) const { | |
| 88 | 92 | // Copy contents |
| 89 | memcpy(Buf + OutputOffset, data().data(), data().size()); | |
| 93 | memcpy(buf + outputOffset, data().data(), data().size()); | |
| 90 | 94 | |
| 91 | 95 | // Apply relocations |
| 92 | if (Relocations.empty()) | |
| 96 | if (relocations.empty()) | |
| 93 | 97 | return; |
| 94 | 98 | |
| 95 | 99 | #ifndef NDEBUG |
| ... | ... | @@ -97,34 +101,38 @@ void InputChunk::writeTo(uint8_t *Buf) const { |
| 97 | 101 | #endif |
| 98 | 102 | |
| 99 | 103 | LLVM_DEBUG(dbgs() << "applying relocations: " << getName() |
| 100 | << " count=" << Relocations.size() << "\n"); | |
| 101 | int32_t Off = OutputOffset - getInputSectionOffset(); | |
| 102 | ||
| 103 | for (const WasmRelocation &Rel : Relocations) { | |
| 104 | uint8_t *Loc = Buf + Rel.Offset + Off; | |
| 105 | uint32_t Value = File->calcNewValue(Rel); | |
| 106 | LLVM_DEBUG(dbgs() << "apply reloc: type=" << reloctTypeToString(Rel.Type) | |
| 107 | << " addend=" << Rel.Addend << " index=" << Rel.Index | |
| 108 | << " value=" << Value << " offset=" << Rel.Offset | |
| 104 | << " count=" << relocations.size() << "\n"); | |
| 105 | int32_t off = outputOffset - getInputSectionOffset(); | |
| 106 | ||
| 107 | for (const WasmRelocation &rel : relocations) { | |
| 108 | uint8_t *loc = buf + rel.Offset + off; | |
| 109 | uint32_t value = file->calcNewValue(rel); | |
| 110 | LLVM_DEBUG(dbgs() << "apply reloc: type=" << relocTypeToString(rel.Type)); | |
| 111 | if (rel.Type != R_WASM_TYPE_INDEX_LEB) | |
| 112 | LLVM_DEBUG(dbgs() << " sym=" << file->getSymbols()[rel.Index]->getName()); | |
| 113 | LLVM_DEBUG(dbgs() << " addend=" << rel.Addend << " index=" << rel.Index | |
| 114 | << " value=" << value << " offset=" << rel.Offset | |
| 109 | 115 | << "\n"); |
| 110 | 116 | |
| 111 | switch (Rel.Type) { | |
| 112 | case R_WEBASSEMBLY_TYPE_INDEX_LEB: | |
| 113 | case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: | |
| 114 | case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: | |
| 115 | case R_WEBASSEMBLY_EVENT_INDEX_LEB: | |
| 116 | case R_WEBASSEMBLY_MEMORY_ADDR_LEB: | |
| 117 | encodeULEB128(Value, Loc, 5); | |
| 117 | switch (rel.Type) { | |
| 118 | case R_WASM_TYPE_INDEX_LEB: | |
| 119 | case R_WASM_FUNCTION_INDEX_LEB: | |
| 120 | case R_WASM_GLOBAL_INDEX_LEB: | |
| 121 | case R_WASM_EVENT_INDEX_LEB: | |
| 122 | case R_WASM_MEMORY_ADDR_LEB: | |
| 123 | encodeULEB128(value, loc, 5); | |
| 118 | 124 | break; |
| 119 | case R_WEBASSEMBLY_TABLE_INDEX_SLEB: | |
| 120 | case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: | |
| 121 | encodeSLEB128(static_cast<int32_t>(Value), Loc, 5); | |
| 125 | case R_WASM_TABLE_INDEX_SLEB: | |
| 126 | case R_WASM_TABLE_INDEX_REL_SLEB: | |
| 127 | case R_WASM_MEMORY_ADDR_SLEB: | |
| 128 | case R_WASM_MEMORY_ADDR_REL_SLEB: | |
| 129 | encodeSLEB128(static_cast<int32_t>(value), loc, 5); | |
| 122 | 130 | break; |
| 123 | case R_WEBASSEMBLY_TABLE_INDEX_I32: | |
| 124 | case R_WEBASSEMBLY_MEMORY_ADDR_I32: | |
| 125 | case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: | |
| 126 | case R_WEBASSEMBLY_SECTION_OFFSET_I32: | |
| 127 | write32le(Loc, Value); | |
| 131 | case R_WASM_TABLE_INDEX_I32: | |
| 132 | case R_WASM_MEMORY_ADDR_I32: | |
| 133 | case R_WASM_FUNCTION_OFFSET_I32: | |
| 134 | case R_WASM_SECTION_OFFSET_I32: | |
| 135 | write32le(loc, value); | |
| 128 | 136 | break; |
| 129 | 137 | default: |
| 130 | 138 | llvm_unreachable("unknown relocation type"); |
| ... | ... | @@ -135,82 +143,75 @@ void InputChunk::writeTo(uint8_t *Buf) const { |
| 135 | 143 | // Copy relocation entries to a given output stream. |
| 136 | 144 | // This function is used only when a user passes "-r". For a regular link, |
| 137 | 145 | // we consume relocations instead of copying them to an output file. |
| 138 | void InputChunk::writeRelocations(raw_ostream &OS) const { | |
| 139 | if (Relocations.empty()) | |
| 146 | void InputChunk::writeRelocations(raw_ostream &os) const { | |
| 147 | if (relocations.empty()) | |
| 140 | 148 | return; |
| 141 | 149 | |
| 142 | int32_t Off = OutputOffset - getInputSectionOffset(); | |
| 143 | LLVM_DEBUG(dbgs() << "writeRelocations: " << File->getName() | |
| 144 | << " offset=" << Twine(Off) << "\n"); | |
| 145 | ||
| 146 | for (const WasmRelocation &Rel : Relocations) { | |
| 147 | writeUleb128(OS, Rel.Type, "reloc type"); | |
| 148 | writeUleb128(OS, Rel.Offset + Off, "reloc offset"); | |
| 149 | writeUleb128(OS, File->calcNewIndex(Rel), "reloc index"); | |
| 150 | ||
| 151 | switch (Rel.Type) { | |
| 152 | case R_WEBASSEMBLY_MEMORY_ADDR_LEB: | |
| 153 | case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: | |
| 154 | case R_WEBASSEMBLY_MEMORY_ADDR_I32: | |
| 155 | case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: | |
| 156 | case R_WEBASSEMBLY_SECTION_OFFSET_I32: | |
| 157 | writeSleb128(OS, File->calcNewAddend(Rel), "reloc addend"); | |
| 158 | break; | |
| 159 | } | |
| 150 | int32_t off = outputOffset - getInputSectionOffset(); | |
| 151 | LLVM_DEBUG(dbgs() << "writeRelocations: " << file->getName() | |
| 152 | << " offset=" << Twine(off) << "\n"); | |
| 153 | ||
| 154 | for (const WasmRelocation &rel : relocations) { | |
| 155 | writeUleb128(os, rel.Type, "reloc type"); | |
| 156 | writeUleb128(os, rel.Offset + off, "reloc offset"); | |
| 157 | writeUleb128(os, file->calcNewIndex(rel), "reloc index"); | |
| 158 | ||
| 159 | if (relocTypeHasAddend(rel.Type)) | |
| 160 | writeSleb128(os, file->calcNewAddend(rel), "reloc addend"); | |
| 160 | 161 | } |
| 161 | 162 | } |
| 162 | 163 | |
| 163 | void InputFunction::setFunctionIndex(uint32_t Index) { | |
| 164 | void InputFunction::setFunctionIndex(uint32_t index) { | |
| 164 | 165 | LLVM_DEBUG(dbgs() << "InputFunction::setFunctionIndex: " << getName() |
| 165 | << " -> " << Index << "\n"); | |
| 166 | << " -> " << index << "\n"); | |
| 166 | 167 | assert(!hasFunctionIndex()); |
| 167 | FunctionIndex = Index; | |
| 168 | functionIndex = index; | |
| 168 | 169 | } |
| 169 | 170 | |
| 170 | void InputFunction::setTableIndex(uint32_t Index) { | |
| 171 | void InputFunction::setTableIndex(uint32_t index) { | |
| 171 | 172 | LLVM_DEBUG(dbgs() << "InputFunction::setTableIndex: " << getName() << " -> " |
| 172 | << Index << "\n"); | |
| 173 | << index << "\n"); | |
| 173 | 174 | assert(!hasTableIndex()); |
| 174 | TableIndex = Index; | |
| 175 | tableIndex = index; | |
| 175 | 176 | } |
| 176 | 177 | |
| 177 | 178 | // Write a relocation value without padding and return the number of bytes |
| 178 | 179 | // witten. |
| 179 | static unsigned writeCompressedReloc(uint8_t *Buf, const WasmRelocation &Rel, | |
| 180 | uint32_t Value) { | |
| 181 | switch (Rel.Type) { | |
| 182 | case R_WEBASSEMBLY_TYPE_INDEX_LEB: | |
| 183 | case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: | |
| 184 | case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: | |
| 185 | case R_WEBASSEMBLY_EVENT_INDEX_LEB: | |
| 186 | case R_WEBASSEMBLY_MEMORY_ADDR_LEB: | |
| 187 | return encodeULEB128(Value, Buf); | |
| 188 | case R_WEBASSEMBLY_TABLE_INDEX_SLEB: | |
| 189 | case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: | |
| 190 | return encodeSLEB128(static_cast<int32_t>(Value), Buf); | |
| 180 | static unsigned writeCompressedReloc(uint8_t *buf, const WasmRelocation &rel, | |
| 181 | uint32_t value) { | |
| 182 | switch (rel.Type) { | |
| 183 | case R_WASM_TYPE_INDEX_LEB: | |
| 184 | case R_WASM_FUNCTION_INDEX_LEB: | |
| 185 | case R_WASM_GLOBAL_INDEX_LEB: | |
| 186 | case R_WASM_EVENT_INDEX_LEB: | |
| 187 | case R_WASM_MEMORY_ADDR_LEB: | |
| 188 | return encodeULEB128(value, buf); | |
| 189 | case R_WASM_TABLE_INDEX_SLEB: | |
| 190 | case R_WASM_MEMORY_ADDR_SLEB: | |
| 191 | return encodeSLEB128(static_cast<int32_t>(value), buf); | |
| 191 | 192 | default: |
| 192 | 193 | llvm_unreachable("unexpected relocation type"); |
| 193 | 194 | } |
| 194 | 195 | } |
| 195 | 196 | |
| 196 | static unsigned getRelocWidthPadded(const WasmRelocation &Rel) { | |
| 197 | switch (Rel.Type) { | |
| 198 | case R_WEBASSEMBLY_TYPE_INDEX_LEB: | |
| 199 | case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: | |
| 200 | case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: | |
| 201 | case R_WEBASSEMBLY_EVENT_INDEX_LEB: | |
| 202 | case R_WEBASSEMBLY_MEMORY_ADDR_LEB: | |
| 203 | case R_WEBASSEMBLY_TABLE_INDEX_SLEB: | |
| 204 | case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: | |
| 197 | static unsigned getRelocWidthPadded(const WasmRelocation &rel) { | |
| 198 | switch (rel.Type) { | |
| 199 | case R_WASM_TYPE_INDEX_LEB: | |
| 200 | case R_WASM_FUNCTION_INDEX_LEB: | |
| 201 | case R_WASM_GLOBAL_INDEX_LEB: | |
| 202 | case R_WASM_EVENT_INDEX_LEB: | |
| 203 | case R_WASM_MEMORY_ADDR_LEB: | |
| 204 | case R_WASM_TABLE_INDEX_SLEB: | |
| 205 | case R_WASM_MEMORY_ADDR_SLEB: | |
| 205 | 206 | return 5; |
| 206 | 207 | default: |
| 207 | 208 | llvm_unreachable("unexpected relocation type"); |
| 208 | 209 | } |
| 209 | 210 | } |
| 210 | 211 | |
| 211 | static unsigned getRelocWidth(const WasmRelocation &Rel, uint32_t Value) { | |
| 212 | uint8_t Buf[5]; | |
| 213 | return writeCompressedReloc(Buf, Rel, Value); | |
| 212 | static unsigned getRelocWidth(const WasmRelocation &rel, uint32_t value) { | |
| 213 | uint8_t buf[5]; | |
| 214 | return writeCompressedReloc(buf, rel, value); | |
| 214 | 215 | } |
| 215 | 216 | |
| 216 | 217 | // Relocations of type LEB and SLEB in the code section are padded to 5 bytes |
| ... | ... | @@ -224,69 +225,124 @@ static unsigned getRelocWidth(const WasmRelocation &Rel, uint32_t Value) { |
| 224 | 225 | // This function only computes the final output size. It must be called |
| 225 | 226 | // before getSize() is used to calculate of layout of the code section. |
| 226 | 227 | void InputFunction::calculateSize() { |
| 227 | if (!File || !Config->CompressRelocations) | |
| 228 | if (!file || !config->compressRelocations) | |
| 228 | 229 | return; |
| 229 | 230 | |
| 230 | 231 | LLVM_DEBUG(dbgs() << "calculateSize: " << getName() << "\n"); |
| 231 | 232 | |
| 232 | const uint8_t *SecStart = File->CodeSection->Content.data(); | |
| 233 | const uint8_t *FuncStart = SecStart + getInputSectionOffset(); | |
| 234 | uint32_t FunctionSizeLength; | |
| 235 | decodeULEB128(FuncStart, &FunctionSizeLength); | |
| 233 | const uint8_t *secStart = file->codeSection->Content.data(); | |
| 234 | const uint8_t *funcStart = secStart + getInputSectionOffset(); | |
| 235 | uint32_t functionSizeLength; | |
| 236 | decodeULEB128(funcStart, &functionSizeLength); | |
| 236 | 237 | |
| 237 | uint32_t Start = getInputSectionOffset(); | |
| 238 | uint32_t End = Start + Function->Size; | |
| 238 | uint32_t start = getInputSectionOffset(); | |
| 239 | uint32_t end = start + function->Size; | |
| 239 | 240 | |
| 240 | uint32_t LastRelocEnd = Start + FunctionSizeLength; | |
| 241 | for (const WasmRelocation &Rel : Relocations) { | |
| 242 | LLVM_DEBUG(dbgs() << " region: " << (Rel.Offset - LastRelocEnd) << "\n"); | |
| 243 | CompressedFuncSize += Rel.Offset - LastRelocEnd; | |
| 244 | CompressedFuncSize += getRelocWidth(Rel, File->calcNewValue(Rel)); | |
| 245 | LastRelocEnd = Rel.Offset + getRelocWidthPadded(Rel); | |
| 241 | uint32_t lastRelocEnd = start + functionSizeLength; | |
| 242 | for (const WasmRelocation &rel : relocations) { | |
| 243 | LLVM_DEBUG(dbgs() << " region: " << (rel.Offset - lastRelocEnd) << "\n"); | |
| 244 | compressedFuncSize += rel.Offset - lastRelocEnd; | |
| 245 | compressedFuncSize += getRelocWidth(rel, file->calcNewValue(rel)); | |
| 246 | lastRelocEnd = rel.Offset + getRelocWidthPadded(rel); | |
| 246 | 247 | } |
| 247 | LLVM_DEBUG(dbgs() << " final region: " << (End - LastRelocEnd) << "\n"); | |
| 248 | CompressedFuncSize += End - LastRelocEnd; | |
| 248 | LLVM_DEBUG(dbgs() << " final region: " << (end - lastRelocEnd) << "\n"); | |
| 249 | compressedFuncSize += end - lastRelocEnd; | |
| 249 | 250 | |
| 250 | 251 | // Now we know how long the resulting function is we can add the encoding |
| 251 | 252 | // of its length |
| 252 | uint8_t Buf[5]; | |
| 253 | CompressedSize = CompressedFuncSize + encodeULEB128(CompressedFuncSize, Buf); | |
| 253 | uint8_t buf[5]; | |
| 254 | compressedSize = compressedFuncSize + encodeULEB128(compressedFuncSize, buf); | |
| 254 | 255 | |
| 255 | LLVM_DEBUG(dbgs() << " calculateSize orig: " << Function->Size << "\n"); | |
| 256 | LLVM_DEBUG(dbgs() << " calculateSize new: " << CompressedSize << "\n"); | |
| 256 | LLVM_DEBUG(dbgs() << " calculateSize orig: " << function->Size << "\n"); | |
| 257 | LLVM_DEBUG(dbgs() << " calculateSize new: " << compressedSize << "\n"); | |
| 257 | 258 | } |
| 258 | 259 | |
| 259 | 260 | // Override the default writeTo method so that we can (optionally) write the |
| 260 | 261 | // compressed version of the function. |
| 261 | void InputFunction::writeTo(uint8_t *Buf) const { | |
| 262 | if (!File || !Config->CompressRelocations) | |
| 263 | return InputChunk::writeTo(Buf); | |
| 262 | void InputFunction::writeTo(uint8_t *buf) const { | |
| 263 | if (!file || !config->compressRelocations) | |
| 264 | return InputChunk::writeTo(buf); | |
| 264 | 265 | |
| 265 | Buf += OutputOffset; | |
| 266 | uint8_t *Orig = Buf; | |
| 267 | (void)Orig; | |
| 266 | buf += outputOffset; | |
| 267 | uint8_t *orig = buf; | |
| 268 | (void)orig; | |
| 268 | 269 | |
| 269 | const uint8_t *SecStart = File->CodeSection->Content.data(); | |
| 270 | const uint8_t *FuncStart = SecStart + getInputSectionOffset(); | |
| 271 | const uint8_t *End = FuncStart + Function->Size; | |
| 272 | uint32_t Count; | |
| 273 | decodeULEB128(FuncStart, &Count); | |
| 274 | FuncStart += Count; | |
| 270 | const uint8_t *secStart = file->codeSection->Content.data(); | |
| 271 | const uint8_t *funcStart = secStart + getInputSectionOffset(); | |
| 272 | const uint8_t *end = funcStart + function->Size; | |
| 273 | uint32_t count; | |
| 274 | decodeULEB128(funcStart, &count); | |
| 275 | funcStart += count; | |
| 275 | 276 | |
| 276 | 277 | LLVM_DEBUG(dbgs() << "write func: " << getName() << "\n"); |
| 277 | Buf += encodeULEB128(CompressedFuncSize, Buf); | |
| 278 | const uint8_t *LastRelocEnd = FuncStart; | |
| 279 | for (const WasmRelocation &Rel : Relocations) { | |
| 280 | unsigned ChunkSize = (SecStart + Rel.Offset) - LastRelocEnd; | |
| 281 | LLVM_DEBUG(dbgs() << " write chunk: " << ChunkSize << "\n"); | |
| 282 | memcpy(Buf, LastRelocEnd, ChunkSize); | |
| 283 | Buf += ChunkSize; | |
| 284 | Buf += writeCompressedReloc(Buf, Rel, File->calcNewValue(Rel)); | |
| 285 | LastRelocEnd = SecStart + Rel.Offset + getRelocWidthPadded(Rel); | |
| 278 | buf += encodeULEB128(compressedFuncSize, buf); | |
| 279 | const uint8_t *lastRelocEnd = funcStart; | |
| 280 | for (const WasmRelocation &rel : relocations) { | |
| 281 | unsigned chunkSize = (secStart + rel.Offset) - lastRelocEnd; | |
| 282 | LLVM_DEBUG(dbgs() << " write chunk: " << chunkSize << "\n"); | |
| 283 | memcpy(buf, lastRelocEnd, chunkSize); | |
| 284 | buf += chunkSize; | |
| 285 | buf += writeCompressedReloc(buf, rel, file->calcNewValue(rel)); | |
| 286 | lastRelocEnd = secStart + rel.Offset + getRelocWidthPadded(rel); | |
| 286 | 287 | } |
| 287 | 288 | |
| 288 | unsigned ChunkSize = End - LastRelocEnd; | |
| 289 | LLVM_DEBUG(dbgs() << " write final chunk: " << ChunkSize << "\n"); | |
| 290 | memcpy(Buf, LastRelocEnd, ChunkSize); | |
| 291 | LLVM_DEBUG(dbgs() << " total: " << (Buf + ChunkSize - Orig) << "\n"); | |
| 289 | unsigned chunkSize = end - lastRelocEnd; | |
| 290 | LLVM_DEBUG(dbgs() << " write final chunk: " << chunkSize << "\n"); | |
| 291 | memcpy(buf, lastRelocEnd, chunkSize); | |
| 292 | LLVM_DEBUG(dbgs() << " total: " << (buf + chunkSize - orig) << "\n"); | |
| 293 | } | |
| 294 | ||
| 295 | // Generate code to apply relocations to the data section at runtime. | |
| 296 | // This is only called when generating shared libaries (PIC) where address are | |
| 297 | // not known at static link time. | |
| 298 | void InputSegment::generateRelocationCode(raw_ostream &os) const { | |
| 299 | LLVM_DEBUG(dbgs() << "generating runtime relocations: " << getName() | |
| 300 | << " count=" << relocations.size() << "\n"); | |
| 301 | ||
| 302 | // TODO(sbc): Encode the relocations in the data section and write a loop | |
| 303 | // here to apply them. | |
| 304 | uint32_t segmentVA = outputSeg->startVA + outputSegmentOffset; | |
| 305 | for (const WasmRelocation &rel : relocations) { | |
| 306 | uint32_t offset = rel.Offset - getInputSectionOffset(); | |
| 307 | uint32_t outputOffset = segmentVA + offset; | |
| 308 | ||
| 309 | LLVM_DEBUG(dbgs() << "gen reloc: type=" << relocTypeToString(rel.Type) | |
| 310 | << " addend=" << rel.Addend << " index=" << rel.Index | |
| 311 | << " output offset=" << outputOffset << "\n"); | |
| 312 | ||
| 313 | // Get __memory_base | |
| 314 | writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); | |
| 315 | writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), "memory_base"); | |
| 316 | ||
| 317 | // Add the offset of the relocation | |
| 318 | writeU8(os, WASM_OPCODE_I32_CONST, "I32_CONST"); | |
| 319 | writeSleb128(os, outputOffset, "offset"); | |
| 320 | writeU8(os, WASM_OPCODE_I32_ADD, "ADD"); | |
| 321 | ||
| 322 | Symbol *sym = file->getSymbol(rel); | |
| 323 | // Now figure out what we want to store | |
| 324 | if (sym->hasGOTIndex()) { | |
| 325 | writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); | |
| 326 | writeUleb128(os, sym->getGOTIndex(), "global index"); | |
| 327 | if (rel.Addend) { | |
| 328 | writeU8(os, WASM_OPCODE_I32_CONST, "CONST"); | |
| 329 | writeSleb128(os, rel.Addend, "addend"); | |
| 330 | writeU8(os, WASM_OPCODE_I32_ADD, "ADD"); | |
| 331 | } | |
| 332 | } else { | |
| 333 | const GlobalSymbol* baseSymbol = WasmSym::memoryBase; | |
| 334 | if (rel.Type == R_WASM_TABLE_INDEX_I32) | |
| 335 | baseSymbol = WasmSym::tableBase; | |
| 336 | writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); | |
| 337 | writeUleb128(os, baseSymbol->getGlobalIndex(), "base"); | |
| 338 | writeU8(os, WASM_OPCODE_I32_CONST, "CONST"); | |
| 339 | writeSleb128(os, file->calcNewValue(rel), "offset"); | |
| 340 | writeU8(os, WASM_OPCODE_I32_ADD, "ADD"); | |
| 341 | } | |
| 342 | ||
| 343 | // Store that value at the virtual address | |
| 344 | writeU8(os, WASM_OPCODE_I32_STORE, "I32_STORE"); | |
| 345 | writeUleb128(os, 2, "align"); | |
| 346 | writeUleb128(os, 0, "offset"); | |
| 347 | } | |
| 292 | 348 | } |
deps/lld/wasm/InputChunks.h+86-77| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- InputChunks.h --------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -32,20 +31,21 @@ namespace wasm { |
| 32 | 31 | |
| 33 | 32 | class ObjFile; |
| 34 | 33 | class OutputSegment; |
| 34 | class OutputSection; | |
| 35 | 35 | |
| 36 | 36 | class InputChunk { |
| 37 | 37 | public: |
| 38 | 38 | enum Kind { DataSegment, Function, SyntheticFunction, Section }; |
| 39 | 39 | |
| 40 | Kind kind() const { return SectionKind; } | |
| 40 | Kind kind() const { return sectionKind; } | |
| 41 | 41 | |
| 42 | 42 | virtual uint32_t getSize() const { return data().size(); } |
| 43 | 43 | virtual uint32_t getInputSize() const { return getSize(); }; |
| 44 | 44 | |
| 45 | virtual void writeTo(uint8_t *SectionStart) const; | |
| 45 | virtual void writeTo(uint8_t *sectionStart) const; | |
| 46 | 46 | |
| 47 | ArrayRef<WasmRelocation> getRelocations() const { return Relocations; } | |
| 48 | void setRelocations(ArrayRef<WasmRelocation> Rs) { Relocations = Rs; } | |
| 47 | ArrayRef<WasmRelocation> getRelocations() const { return relocations; } | |
| 48 | void setRelocations(ArrayRef<WasmRelocation> rs) { relocations = rs; } | |
| 49 | 49 | |
| 50 | 50 | virtual StringRef getName() const = 0; |
| 51 | 51 | virtual StringRef getDebugName() const = 0; |
| ... | ... | @@ -53,20 +53,23 @@ public: |
| 53 | 53 | StringRef getComdatName() const; |
| 54 | 54 | virtual uint32_t getInputSectionOffset() const = 0; |
| 55 | 55 | |
| 56 | size_t NumRelocations() const { return Relocations.size(); } | |
| 57 | void writeRelocations(llvm::raw_ostream &OS) const; | |
| 56 | size_t getNumRelocations() const { return relocations.size(); } | |
| 57 | void writeRelocations(llvm::raw_ostream &os) const; | |
| 58 | 58 | |
| 59 | ObjFile *File; | |
| 60 | int32_t OutputOffset = 0; | |
| 59 | ObjFile *file; | |
| 60 | int32_t outputOffset = 0; | |
| 61 | 61 | |
| 62 | 62 | // Signals that the section is part of the output. The garbage collector, |
| 63 | 63 | // and COMDAT handling can set a sections' Live bit. |
| 64 | 64 | // If GC is disabled, all sections start out as live by default. |
| 65 | unsigned Live : 1; | |
| 65 | unsigned live : 1; | |
| 66 | ||
| 67 | // Signals the chunk was discarded by COMDAT handling. | |
| 68 | unsigned discarded : 1; | |
| 66 | 69 | |
| 67 | 70 | protected: |
| 68 | InputChunk(ObjFile *F, Kind K) | |
| 69 | : File(F), Live(!Config->GcSections), SectionKind(K) {} | |
| 71 | InputChunk(ObjFile *f, Kind k) | |
| 72 | : file(f), live(!config->gcSections), discarded(false), sectionKind(k) {} | |
| 70 | 73 | virtual ~InputChunk() = default; |
| 71 | 74 | virtual ArrayRef<uint8_t> data() const = 0; |
| 72 | 75 | |
| ... | ... | @@ -74,8 +77,8 @@ protected: |
| 74 | 77 | // This is performed only debug builds as an extra sanity check. |
| 75 | 78 | void verifyRelocTargets() const; |
| 76 | 79 | |
| 77 | ArrayRef<WasmRelocation> Relocations; | |
| 78 | Kind SectionKind; | |
| 80 | ArrayRef<WasmRelocation> relocations; | |
| 81 | Kind sectionKind; | |
| 79 | 82 | }; |
| 80 | 83 | |
| 81 | 84 | // Represents a WebAssembly data segment which can be included as part of |
| ... | ... | @@ -88,63 +91,65 @@ protected: |
| 88 | 91 | // each global variable. |
| 89 | 92 | class InputSegment : public InputChunk { |
| 90 | 93 | public: |
| 91 | InputSegment(const WasmSegment &Seg, ObjFile *F) | |
| 92 | : InputChunk(F, InputChunk::DataSegment), Segment(Seg) {} | |
| 94 | InputSegment(const WasmSegment &seg, ObjFile *f) | |
| 95 | : InputChunk(f, InputChunk::DataSegment), segment(seg) {} | |
| 96 | ||
| 97 | static bool classof(const InputChunk *c) { return c->kind() == DataSegment; } | |
| 93 | 98 | |
| 94 | static bool classof(const InputChunk *C) { return C->kind() == DataSegment; } | |
| 99 | void generateRelocationCode(raw_ostream &os) const; | |
| 95 | 100 | |
| 96 | uint32_t getAlignment() const { return Segment.Data.Alignment; } | |
| 97 | StringRef getName() const override { return Segment.Data.Name; } | |
| 101 | uint32_t getAlignment() const { return segment.Data.Alignment; } | |
| 102 | StringRef getName() const override { return segment.Data.Name; } | |
| 98 | 103 | StringRef getDebugName() const override { return StringRef(); } |
| 99 | uint32_t getComdat() const override { return Segment.Data.Comdat; } | |
| 104 | uint32_t getComdat() const override { return segment.Data.Comdat; } | |
| 100 | 105 | uint32_t getInputSectionOffset() const override { |
| 101 | return Segment.SectionOffset; | |
| 106 | return segment.SectionOffset; | |
| 102 | 107 | } |
| 103 | 108 | |
| 104 | const OutputSegment *OutputSeg = nullptr; | |
| 105 | int32_t OutputSegmentOffset = 0; | |
| 109 | const OutputSegment *outputSeg = nullptr; | |
| 110 | int32_t outputSegmentOffset = 0; | |
| 106 | 111 | |
| 107 | 112 | protected: |
| 108 | ArrayRef<uint8_t> data() const override { return Segment.Data.Content; } | |
| 113 | ArrayRef<uint8_t> data() const override { return segment.Data.Content; } | |
| 109 | 114 | |
| 110 | const WasmSegment &Segment; | |
| 115 | const WasmSegment &segment; | |
| 111 | 116 | }; |
| 112 | 117 | |
| 113 | 118 | // Represents a single wasm function within and input file. These are |
| 114 | 119 | // combined to create the final output CODE section. |
| 115 | 120 | class InputFunction : public InputChunk { |
| 116 | 121 | public: |
| 117 | InputFunction(const WasmSignature &S, const WasmFunction *Func, ObjFile *F) | |
| 118 | : InputChunk(F, InputChunk::Function), Signature(S), Function(Func) {} | |
| 122 | InputFunction(const WasmSignature &s, const WasmFunction *func, ObjFile *f) | |
| 123 | : InputChunk(f, InputChunk::Function), signature(s), function(func) {} | |
| 119 | 124 | |
| 120 | static bool classof(const InputChunk *C) { | |
| 121 | return C->kind() == InputChunk::Function || | |
| 122 | C->kind() == InputChunk::SyntheticFunction; | |
| 125 | static bool classof(const InputChunk *c) { | |
| 126 | return c->kind() == InputChunk::Function || | |
| 127 | c->kind() == InputChunk::SyntheticFunction; | |
| 123 | 128 | } |
| 124 | 129 | |
| 125 | void writeTo(uint8_t *SectionStart) const override; | |
| 126 | StringRef getName() const override { return Function->SymbolName; } | |
| 127 | StringRef getDebugName() const override { return Function->DebugName; } | |
| 128 | uint32_t getComdat() const override { return Function->Comdat; } | |
| 130 | void writeTo(uint8_t *sectionStart) const override; | |
| 131 | StringRef getName() const override { return function->SymbolName; } | |
| 132 | StringRef getDebugName() const override { return function->DebugName; } | |
| 133 | uint32_t getComdat() const override { return function->Comdat; } | |
| 129 | 134 | uint32_t getFunctionInputOffset() const { return getInputSectionOffset(); } |
| 130 | uint32_t getFunctionCodeOffset() const { return Function->CodeOffset; } | |
| 135 | uint32_t getFunctionCodeOffset() const { return function->CodeOffset; } | |
| 131 | 136 | uint32_t getSize() const override { |
| 132 | if (Config->CompressRelocations && File) { | |
| 133 | assert(CompressedSize); | |
| 134 | return CompressedSize; | |
| 137 | if (config->compressRelocations && file) { | |
| 138 | assert(compressedSize); | |
| 139 | return compressedSize; | |
| 135 | 140 | } |
| 136 | 141 | return data().size(); |
| 137 | 142 | } |
| 138 | uint32_t getInputSize() const override { return Function->Size; } | |
| 139 | uint32_t getFunctionIndex() const { return FunctionIndex.getValue(); } | |
| 140 | bool hasFunctionIndex() const { return FunctionIndex.hasValue(); } | |
| 141 | void setFunctionIndex(uint32_t Index); | |
| 143 | uint32_t getInputSize() const override { return function->Size; } | |
| 144 | uint32_t getFunctionIndex() const { return functionIndex.getValue(); } | |
| 145 | bool hasFunctionIndex() const { return functionIndex.hasValue(); } | |
| 146 | void setFunctionIndex(uint32_t index); | |
| 142 | 147 | uint32_t getInputSectionOffset() const override { |
| 143 | return Function->CodeSectionOffset; | |
| 148 | return function->CodeSectionOffset; | |
| 144 | 149 | } |
| 145 | uint32_t getTableIndex() const { return TableIndex.getValue(); } | |
| 146 | bool hasTableIndex() const { return TableIndex.hasValue(); } | |
| 147 | void setTableIndex(uint32_t Index); | |
| 150 | uint32_t getTableIndex() const { return tableIndex.getValue(); } | |
| 151 | bool hasTableIndex() const { return tableIndex.hasValue(); } | |
| 152 | void setTableIndex(uint32_t index); | |
| 148 | 153 | |
| 149 | 154 | // The size of a given input function can depend on the values of the |
| 150 | 155 | // LEB relocations within it. This finalizeContents method is called after |
| ... | ... | @@ -152,73 +157,77 @@ public: |
| 152 | 157 | // called. |
| 153 | 158 | void calculateSize(); |
| 154 | 159 | |
| 155 | const WasmSignature &Signature; | |
| 160 | const WasmSignature &signature; | |
| 156 | 161 | |
| 157 | 162 | protected: |
| 158 | 163 | ArrayRef<uint8_t> data() const override { |
| 159 | assert(!Config->CompressRelocations); | |
| 160 | return File->CodeSection->Content.slice(getInputSectionOffset(), | |
| 161 | Function->Size); | |
| 164 | assert(!config->compressRelocations); | |
| 165 | return file->codeSection->Content.slice(getInputSectionOffset(), | |
| 166 | function->Size); | |
| 162 | 167 | } |
| 163 | 168 | |
| 164 | const WasmFunction *Function; | |
| 165 | llvm::Optional<uint32_t> FunctionIndex; | |
| 166 | llvm::Optional<uint32_t> TableIndex; | |
| 167 | uint32_t CompressedFuncSize = 0; | |
| 168 | uint32_t CompressedSize = 0; | |
| 169 | const WasmFunction *function; | |
| 170 | llvm::Optional<uint32_t> functionIndex; | |
| 171 | llvm::Optional<uint32_t> tableIndex; | |
| 172 | uint32_t compressedFuncSize = 0; | |
| 173 | uint32_t compressedSize = 0; | |
| 169 | 174 | }; |
| 170 | 175 | |
| 171 | 176 | class SyntheticFunction : public InputFunction { |
| 172 | 177 | public: |
| 173 | SyntheticFunction(const WasmSignature &S, StringRef Name, | |
| 174 | StringRef DebugName = {}) | |
| 175 | : InputFunction(S, nullptr, nullptr), Name(Name), DebugName(DebugName) { | |
| 176 | SectionKind = InputChunk::SyntheticFunction; | |
| 178 | SyntheticFunction(const WasmSignature &s, StringRef name, | |
| 179 | StringRef debugName = {}) | |
| 180 | : InputFunction(s, nullptr, nullptr), name(name), debugName(debugName) { | |
| 181 | sectionKind = InputChunk::SyntheticFunction; | |
| 177 | 182 | } |
| 178 | 183 | |
| 179 | static bool classof(const InputChunk *C) { | |
| 180 | return C->kind() == InputChunk::SyntheticFunction; | |
| 184 | static bool classof(const InputChunk *c) { | |
| 185 | return c->kind() == InputChunk::SyntheticFunction; | |
| 181 | 186 | } |
| 182 | 187 | |
| 183 | StringRef getName() const override { return Name; } | |
| 184 | StringRef getDebugName() const override { return DebugName; } | |
| 188 | StringRef getName() const override { return name; } | |
| 189 | StringRef getDebugName() const override { return debugName; } | |
| 185 | 190 | uint32_t getComdat() const override { return UINT32_MAX; } |
| 186 | 191 | |
| 187 | void setBody(ArrayRef<uint8_t> Body_) { Body = Body_; } | |
| 192 | void setBody(ArrayRef<uint8_t> body_) { body = body_; } | |
| 188 | 193 | |
| 189 | 194 | protected: |
| 190 | ArrayRef<uint8_t> data() const override { return Body; } | |
| 195 | ArrayRef<uint8_t> data() const override { return body; } | |
| 191 | 196 | |
| 192 | StringRef Name; | |
| 193 | StringRef DebugName; | |
| 194 | ArrayRef<uint8_t> Body; | |
| 197 | StringRef name; | |
| 198 | StringRef debugName; | |
| 199 | ArrayRef<uint8_t> body; | |
| 195 | 200 | }; |
| 196 | 201 | |
| 197 | 202 | // Represents a single Wasm Section within an input file. |
| 198 | 203 | class InputSection : public InputChunk { |
| 199 | 204 | public: |
| 200 | InputSection(const WasmSection &S, ObjFile *F) | |
| 201 | : InputChunk(F, InputChunk::Section), Section(S) { | |
| 202 | assert(Section.Type == llvm::wasm::WASM_SEC_CUSTOM); | |
| 205 | InputSection(const WasmSection &s, ObjFile *f) | |
| 206 | : InputChunk(f, InputChunk::Section), section(s) { | |
| 207 | assert(section.Type == llvm::wasm::WASM_SEC_CUSTOM); | |
| 203 | 208 | } |
| 204 | 209 | |
| 205 | StringRef getName() const override { return Section.Name; } | |
| 210 | StringRef getName() const override { return section.Name; } | |
| 206 | 211 | StringRef getDebugName() const override { return StringRef(); } |
| 207 | 212 | uint32_t getComdat() const override { return UINT32_MAX; } |
| 208 | 213 | |
| 214 | OutputSection *outputSec = nullptr; | |
| 215 | ||
| 209 | 216 | protected: |
| 210 | ArrayRef<uint8_t> data() const override { return Section.Content; } | |
| 217 | ArrayRef<uint8_t> data() const override { return section.Content; } | |
| 211 | 218 | |
| 212 | 219 | // Offset within the input section. This is only zero since this chunk |
| 213 | 220 | // type represents an entire input section, not part of one. |
| 214 | 221 | uint32_t getInputSectionOffset() const override { return 0; } |
| 215 | 222 | |
| 216 | const WasmSection &Section; | |
| 223 | const WasmSection &section; | |
| 217 | 224 | }; |
| 218 | 225 | |
| 219 | 226 | } // namespace wasm |
| 220 | 227 | |
| 221 | 228 | std::string toString(const wasm::InputChunk *); |
| 229 | StringRef relocTypeToString(uint8_t relocType); | |
| 230 | ||
| 222 | 231 | } // namespace lld |
| 223 | 232 | |
| 224 | 233 | #endif // LLD_WASM_INPUT_CHUNKS_H |
deps/lld/wasm/InputEvent.h+18-19| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- InputEvent.h ---------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -29,33 +28,33 @@ namespace wasm { |
| 29 | 28 | // form the final EVENTS section. |
| 30 | 29 | class InputEvent { |
| 31 | 30 | public: |
| 32 | InputEvent(const WasmSignature &S, const WasmEvent &E, ObjFile *F) | |
| 33 | : File(F), Event(E), Signature(S), Live(!Config->GcSections) {} | |
| 31 | InputEvent(const WasmSignature &s, const WasmEvent &e, ObjFile *f) | |
| 32 | : file(f), event(e), signature(s), live(!config->gcSections) {} | |
| 34 | 33 | |
| 35 | StringRef getName() const { return Event.SymbolName; } | |
| 36 | const WasmEventType &getType() const { return Event.Type; } | |
| 34 | StringRef getName() const { return event.SymbolName; } | |
| 35 | const WasmEventType &getType() const { return event.Type; } | |
| 37 | 36 | |
| 38 | uint32_t getEventIndex() const { return EventIndex.getValue(); } | |
| 39 | bool hasEventIndex() const { return EventIndex.hasValue(); } | |
| 40 | void setEventIndex(uint32_t Index) { | |
| 37 | uint32_t getEventIndex() const { return eventIndex.getValue(); } | |
| 38 | bool hasEventIndex() const { return eventIndex.hasValue(); } | |
| 39 | void setEventIndex(uint32_t index) { | |
| 41 | 40 | assert(!hasEventIndex()); |
| 42 | EventIndex = Index; | |
| 41 | eventIndex = index; | |
| 43 | 42 | } |
| 44 | 43 | |
| 45 | ObjFile *File; | |
| 46 | WasmEvent Event; | |
| 47 | const WasmSignature &Signature; | |
| 44 | ObjFile *file; | |
| 45 | WasmEvent event; | |
| 46 | const WasmSignature &signature; | |
| 48 | 47 | |
| 49 | bool Live = false; | |
| 48 | bool live = false; | |
| 50 | 49 | |
| 51 | 50 | protected: |
| 52 | llvm::Optional<uint32_t> EventIndex; | |
| 51 | llvm::Optional<uint32_t> eventIndex; | |
| 53 | 52 | }; |
| 54 | 53 | |
| 55 | 54 | } // namespace wasm |
| 56 | 55 | |
| 57 | inline std::string toString(const wasm::InputEvent *E) { | |
| 58 | return (toString(E->File) + ":(" + E->getName() + ")").str(); | |
| 56 | inline std::string toString(const wasm::InputEvent *e) { | |
| 57 | return (toString(e->file) + ":(" + e->getName() + ")").str(); | |
| 59 | 58 | } |
| 60 | 59 | |
| 61 | 60 | } // namespace lld |
deps/lld/wasm/InputFiles.cpp+353-289| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- InputFiles.cpp -----------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -15,8 +14,10 @@ |
| 15 | 14 | #include "SymbolTable.h" |
| 16 | 15 | #include "lld/Common/ErrorHandler.h" |
| 17 | 16 | #include "lld/Common/Memory.h" |
| 17 | #include "lld/Common/Reproduce.h" | |
| 18 | 18 | #include "llvm/Object/Binary.h" |
| 19 | 19 | #include "llvm/Object/Wasm.h" |
| 20 | #include "llvm/Support/TarWriter.h" | |
| 20 | 21 | #include "llvm/Support/raw_ostream.h" |
| 21 | 22 | |
| 22 | 23 | #define DEBUG_TYPE "lld" |
| ... | ... | @@ -28,62 +29,77 @@ using namespace llvm; |
| 28 | 29 | using namespace llvm::object; |
| 29 | 30 | using namespace llvm::wasm; |
| 30 | 31 | |
| 31 | Optional<MemoryBufferRef> lld::wasm::readFile(StringRef Path) { | |
| 32 | log("Loading: " + Path); | |
| 32 | std::unique_ptr<llvm::TarWriter> lld::wasm::tar; | |
| 33 | ||
| 34 | Optional<MemoryBufferRef> lld::wasm::readFile(StringRef path) { | |
| 35 | log("Loading: " + path); | |
| 33 | 36 | |
| 34 | auto MBOrErr = MemoryBuffer::getFile(Path); | |
| 35 | if (auto EC = MBOrErr.getError()) { | |
| 36 | error("cannot open " + Path + ": " + EC.message()); | |
| 37 | auto mbOrErr = MemoryBuffer::getFile(path); | |
| 38 | if (auto ec = mbOrErr.getError()) { | |
| 39 | error("cannot open " + path + ": " + ec.message()); | |
| 37 | 40 | return None; |
| 38 | 41 | } |
| 39 | std::unique_ptr<MemoryBuffer> &MB = *MBOrErr; | |
| 40 | MemoryBufferRef MBRef = MB->getMemBufferRef(); | |
| 41 | make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership | |
| 42 | std::unique_ptr<MemoryBuffer> &mb = *mbOrErr; | |
| 43 | MemoryBufferRef mbref = mb->getMemBufferRef(); | |
| 44 | make<std::unique_ptr<MemoryBuffer>>(std::move(mb)); // take MB ownership | |
| 42 | 45 | |
| 43 | return MBRef; | |
| 46 | if (tar) | |
| 47 | tar->append(relativeToRoot(path), mbref.getBuffer()); | |
| 48 | return mbref; | |
| 44 | 49 | } |
| 45 | 50 | |
| 46 | InputFile *lld::wasm::createObjectFile(MemoryBufferRef MB) { | |
| 47 | file_magic Magic = identify_magic(MB.getBuffer()); | |
| 48 | if (Magic == file_magic::wasm_object) | |
| 49 | return make<ObjFile>(MB); | |
| 51 | InputFile *lld::wasm::createObjectFile(MemoryBufferRef mb, | |
| 52 | StringRef archiveName) { | |
| 53 | file_magic magic = identify_magic(mb.getBuffer()); | |
| 54 | if (magic == file_magic::wasm_object) { | |
| 55 | std::unique_ptr<Binary> bin = | |
| 56 | CHECK(createBinary(mb), mb.getBufferIdentifier()); | |
| 57 | auto *obj = cast<WasmObjectFile>(bin.get()); | |
| 58 | if (obj->isSharedObject()) | |
| 59 | return make<SharedFile>(mb); | |
| 60 | return make<ObjFile>(mb, archiveName); | |
| 61 | } | |
| 50 | 62 | |
| 51 | if (Magic == file_magic::bitcode) | |
| 52 | return make<BitcodeFile>(MB); | |
| 63 | if (magic == file_magic::bitcode) | |
| 64 | return make<BitcodeFile>(mb, archiveName); | |
| 53 | 65 | |
| 54 | fatal("unknown file type: " + MB.getBufferIdentifier()); | |
| 66 | fatal("unknown file type: " + mb.getBufferIdentifier()); | |
| 55 | 67 | } |
| 56 | 68 | |
| 57 | 69 | void ObjFile::dumpInfo() const { |
| 58 | log("info for: " + getName() + | |
| 59 | "\n Symbols : " + Twine(Symbols.size()) + | |
| 60 | "\n Function Imports : " + Twine(WasmObj->getNumImportedFunctions()) + | |
| 61 | "\n Global Imports : " + Twine(WasmObj->getNumImportedGlobals()) + | |
| 62 | "\n Event Imports : " + Twine(WasmObj->getNumImportedEvents())); | |
| 70 | log("info for: " + toString(this) + | |
| 71 | "\n Symbols : " + Twine(symbols.size()) + | |
| 72 | "\n Function Imports : " + Twine(wasmObj->getNumImportedFunctions()) + | |
| 73 | "\n Global Imports : " + Twine(wasmObj->getNumImportedGlobals()) + | |
| 74 | "\n Event Imports : " + Twine(wasmObj->getNumImportedEvents())); | |
| 63 | 75 | } |
| 64 | 76 | |
| 65 | 77 | // Relocations contain either symbol or type indices. This function takes a |
| 66 | 78 | // relocation and returns relocated index (i.e. translates from the input |
| 67 | 79 | // symbol/type space to the output symbol/type space). |
| 68 | uint32_t ObjFile::calcNewIndex(const WasmRelocation &Reloc) const { | |
| 69 | if (Reloc.Type == R_WEBASSEMBLY_TYPE_INDEX_LEB) { | |
| 70 | assert(TypeIsUsed[Reloc.Index]); | |
| 71 | return TypeMap[Reloc.Index]; | |
| 80 | uint32_t ObjFile::calcNewIndex(const WasmRelocation &reloc) const { | |
| 81 | if (reloc.Type == R_WASM_TYPE_INDEX_LEB) { | |
| 82 | assert(typeIsUsed[reloc.Index]); | |
| 83 | return typeMap[reloc.Index]; | |
| 72 | 84 | } |
| 73 | return Symbols[Reloc.Index]->getOutputSymbolIndex(); | |
| 85 | const Symbol *sym = symbols[reloc.Index]; | |
| 86 | if (auto *ss = dyn_cast<SectionSymbol>(sym)) | |
| 87 | sym = ss->getOutputSectionSymbol(); | |
| 88 | return sym->getOutputSymbolIndex(); | |
| 74 | 89 | } |
| 75 | 90 | |
| 76 | 91 | // Relocations can contain addend for combined sections. This function takes a |
| 77 | 92 | // relocation and returns updated addend by offset in the output section. |
| 78 | uint32_t ObjFile::calcNewAddend(const WasmRelocation &Reloc) const { | |
| 79 | switch (Reloc.Type) { | |
| 80 | case R_WEBASSEMBLY_MEMORY_ADDR_LEB: | |
| 81 | case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: | |
| 82 | case R_WEBASSEMBLY_MEMORY_ADDR_I32: | |
| 83 | case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: | |
| 84 | return Reloc.Addend; | |
| 85 | case R_WEBASSEMBLY_SECTION_OFFSET_I32: | |
| 86 | return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend; | |
| 93 | uint32_t ObjFile::calcNewAddend(const WasmRelocation &reloc) const { | |
| 94 | switch (reloc.Type) { | |
| 95 | case R_WASM_MEMORY_ADDR_LEB: | |
| 96 | case R_WASM_MEMORY_ADDR_SLEB: | |
| 97 | case R_WASM_MEMORY_ADDR_REL_SLEB: | |
| 98 | case R_WASM_MEMORY_ADDR_I32: | |
| 99 | case R_WASM_FUNCTION_OFFSET_I32: | |
| 100 | return reloc.Addend; | |
| 101 | case R_WASM_SECTION_OFFSET_I32: | |
| 102 | return getSectionSymbol(reloc.Index)->section->outputOffset + reloc.Addend; | |
| 87 | 103 | default: |
| 88 | 104 | llvm_unreachable("unexpected relocation type"); |
| 89 | 105 | } |
| ... | ... | @@ -92,39 +108,42 @@ uint32_t ObjFile::calcNewAddend(const WasmRelocation &Reloc) const { |
| 92 | 108 | // Calculate the value we expect to find at the relocation location. |
| 93 | 109 | // This is used as a sanity check before applying a relocation to a given |
| 94 | 110 | // location. It is useful for catching bugs in the compiler and linker. |
| 95 | uint32_t ObjFile::calcExpectedValue(const WasmRelocation &Reloc) const { | |
| 96 | switch (Reloc.Type) { | |
| 97 | case R_WEBASSEMBLY_TABLE_INDEX_I32: | |
| 98 | case R_WEBASSEMBLY_TABLE_INDEX_SLEB: { | |
| 99 | const WasmSymbol &Sym = WasmObj->syms()[Reloc.Index]; | |
| 100 | return TableEntries[Sym.Info.ElementIndex]; | |
| 111 | uint32_t ObjFile::calcExpectedValue(const WasmRelocation &reloc) const { | |
| 112 | switch (reloc.Type) { | |
| 113 | case R_WASM_TABLE_INDEX_I32: | |
| 114 | case R_WASM_TABLE_INDEX_SLEB: | |
| 115 | case R_WASM_TABLE_INDEX_REL_SLEB: { | |
| 116 | const WasmSymbol &sym = wasmObj->syms()[reloc.Index]; | |
| 117 | return tableEntries[sym.Info.ElementIndex]; | |
| 101 | 118 | } |
| 102 | case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: | |
| 103 | case R_WEBASSEMBLY_MEMORY_ADDR_I32: | |
| 104 | case R_WEBASSEMBLY_MEMORY_ADDR_LEB: { | |
| 105 | const WasmSymbol &Sym = WasmObj->syms()[Reloc.Index]; | |
| 106 | if (Sym.isUndefined()) | |
| 119 | case R_WASM_MEMORY_ADDR_SLEB: | |
| 120 | case R_WASM_MEMORY_ADDR_I32: | |
| 121 | case R_WASM_MEMORY_ADDR_LEB: | |
| 122 | case R_WASM_MEMORY_ADDR_REL_SLEB: { | |
| 123 | const WasmSymbol &sym = wasmObj->syms()[reloc.Index]; | |
| 124 | if (sym.isUndefined()) | |
| 107 | 125 | return 0; |
| 108 | const WasmSegment &Segment = | |
| 109 | WasmObj->dataSegments()[Sym.Info.DataRef.Segment]; | |
| 110 | return Segment.Data.Offset.Value.Int32 + Sym.Info.DataRef.Offset + | |
| 111 | Reloc.Addend; | |
| 126 | const WasmSegment &segment = | |
| 127 | wasmObj->dataSegments()[sym.Info.DataRef.Segment]; | |
| 128 | return segment.Data.Offset.Value.Int32 + sym.Info.DataRef.Offset + | |
| 129 | reloc.Addend; | |
| 112 | 130 | } |
| 113 | case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: | |
| 114 | if (auto *Sym = dyn_cast<DefinedFunction>(getFunctionSymbol(Reloc.Index))) { | |
| 115 | return Sym->Function->getFunctionInputOffset() + | |
| 116 | Sym->Function->getFunctionCodeOffset() + Reloc.Addend; | |
| 117 | } | |
| 118 | return 0; | |
| 119 | case R_WEBASSEMBLY_SECTION_OFFSET_I32: | |
| 120 | return Reloc.Addend; | |
| 121 | case R_WEBASSEMBLY_TYPE_INDEX_LEB: | |
| 122 | return Reloc.Index; | |
| 123 | case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: | |
| 124 | case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: | |
| 125 | case R_WEBASSEMBLY_EVENT_INDEX_LEB: { | |
| 126 | const WasmSymbol &Sym = WasmObj->syms()[Reloc.Index]; | |
| 127 | return Sym.Info.ElementIndex; | |
| 131 | case R_WASM_FUNCTION_OFFSET_I32: { | |
| 132 | const WasmSymbol &sym = wasmObj->syms()[reloc.Index]; | |
| 133 | InputFunction *f = | |
| 134 | functions[sym.Info.ElementIndex - wasmObj->getNumImportedFunctions()]; | |
| 135 | return f->getFunctionInputOffset() + f->getFunctionCodeOffset() + | |
| 136 | reloc.Addend; | |
| 137 | } | |
| 138 | case R_WASM_SECTION_OFFSET_I32: | |
| 139 | return reloc.Addend; | |
| 140 | case R_WASM_TYPE_INDEX_LEB: | |
| 141 | return reloc.Index; | |
| 142 | case R_WASM_FUNCTION_INDEX_LEB: | |
| 143 | case R_WASM_GLOBAL_INDEX_LEB: | |
| 144 | case R_WASM_EVENT_INDEX_LEB: { | |
| 145 | const WasmSymbol &sym = wasmObj->syms()[reloc.Index]; | |
| 146 | return sym.Info.ElementIndex; | |
| 128 | 147 | } |
| 129 | 148 | default: |
| 130 | 149 | llvm_unreachable("unknown relocation type"); |
| ... | ... | @@ -132,260 +151,299 @@ uint32_t ObjFile::calcExpectedValue(const WasmRelocation &Reloc) const { |
| 132 | 151 | } |
| 133 | 152 | |
| 134 | 153 | // Translate from the relocation's index into the final linked output value. |
| 135 | uint32_t ObjFile::calcNewValue(const WasmRelocation &Reloc) const { | |
| 136 | switch (Reloc.Type) { | |
| 137 | case R_WEBASSEMBLY_TABLE_INDEX_I32: | |
| 138 | case R_WEBASSEMBLY_TABLE_INDEX_SLEB: | |
| 139 | return getFunctionSymbol(Reloc.Index)->getTableIndex(); | |
| 140 | case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: | |
| 141 | case R_WEBASSEMBLY_MEMORY_ADDR_I32: | |
| 142 | case R_WEBASSEMBLY_MEMORY_ADDR_LEB: | |
| 143 | if (auto *Sym = dyn_cast<DefinedData>(getDataSymbol(Reloc.Index))) | |
| 144 | if (Sym->isLive()) | |
| 145 | return Sym->getVirtualAddress() + Reloc.Addend; | |
| 146 | return 0; | |
| 147 | case R_WEBASSEMBLY_TYPE_INDEX_LEB: | |
| 148 | return TypeMap[Reloc.Index]; | |
| 149 | case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: | |
| 150 | return getFunctionSymbol(Reloc.Index)->getFunctionIndex(); | |
| 151 | case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: | |
| 152 | return getGlobalSymbol(Reloc.Index)->getGlobalIndex(); | |
| 153 | case R_WEBASSEMBLY_EVENT_INDEX_LEB: | |
| 154 | return getEventSymbol(Reloc.Index)->getEventIndex(); | |
| 155 | case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: | |
| 156 | if (auto *Sym = dyn_cast<DefinedFunction>(getFunctionSymbol(Reloc.Index))) { | |
| 157 | if (Sym->isLive()) | |
| 158 | return Sym->Function->OutputOffset + | |
| 159 | Sym->Function->getFunctionCodeOffset() + Reloc.Addend; | |
| 160 | } | |
| 161 | return 0; | |
| 162 | case R_WEBASSEMBLY_SECTION_OFFSET_I32: | |
| 163 | return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend; | |
| 154 | uint32_t ObjFile::calcNewValue(const WasmRelocation &reloc) const { | |
| 155 | const Symbol* sym = nullptr; | |
| 156 | if (reloc.Type != R_WASM_TYPE_INDEX_LEB) { | |
| 157 | sym = symbols[reloc.Index]; | |
| 158 | ||
| 159 | // We can end up with relocations against non-live symbols. For example | |
| 160 | // in debug sections. | |
| 161 | if ((isa<FunctionSymbol>(sym) || isa<DataSymbol>(sym)) && !sym->isLive()) | |
| 162 | return 0; | |
| 163 | } | |
| 164 | ||
| 165 | switch (reloc.Type) { | |
| 166 | case R_WASM_TABLE_INDEX_I32: | |
| 167 | case R_WASM_TABLE_INDEX_SLEB: | |
| 168 | case R_WASM_TABLE_INDEX_REL_SLEB: | |
| 169 | if (config->isPic && !getFunctionSymbol(reloc.Index)->hasTableIndex()) | |
| 170 | return 0; | |
| 171 | return getFunctionSymbol(reloc.Index)->getTableIndex(); | |
| 172 | case R_WASM_MEMORY_ADDR_SLEB: | |
| 173 | case R_WASM_MEMORY_ADDR_I32: | |
| 174 | case R_WASM_MEMORY_ADDR_LEB: | |
| 175 | case R_WASM_MEMORY_ADDR_REL_SLEB: | |
| 176 | if (isa<UndefinedData>(sym)) | |
| 177 | return 0; | |
| 178 | return cast<DefinedData>(sym)->getVirtualAddress() + reloc.Addend; | |
| 179 | case R_WASM_TYPE_INDEX_LEB: | |
| 180 | return typeMap[reloc.Index]; | |
| 181 | case R_WASM_FUNCTION_INDEX_LEB: | |
| 182 | return getFunctionSymbol(reloc.Index)->getFunctionIndex(); | |
| 183 | case R_WASM_GLOBAL_INDEX_LEB: | |
| 184 | if (auto gs = dyn_cast<GlobalSymbol>(sym)) | |
| 185 | return gs->getGlobalIndex(); | |
| 186 | return sym->getGOTIndex(); | |
| 187 | case R_WASM_EVENT_INDEX_LEB: | |
| 188 | return getEventSymbol(reloc.Index)->getEventIndex(); | |
| 189 | case R_WASM_FUNCTION_OFFSET_I32: { | |
| 190 | auto *f = cast<DefinedFunction>(sym); | |
| 191 | return f->function->outputOffset + f->function->getFunctionCodeOffset() + | |
| 192 | reloc.Addend; | |
| 193 | } | |
| 194 | case R_WASM_SECTION_OFFSET_I32: | |
| 195 | return getSectionSymbol(reloc.Index)->section->outputOffset + reloc.Addend; | |
| 164 | 196 | default: |
| 165 | 197 | llvm_unreachable("unknown relocation type"); |
| 166 | 198 | } |
| 167 | 199 | } |
| 168 | 200 | |
| 169 | 201 | template <class T> |
| 170 | static void setRelocs(const std::vector<T *> &Chunks, | |
| 171 | const WasmSection *Section) { | |
| 172 | if (!Section) | |
| 202 | static void setRelocs(const std::vector<T *> &chunks, | |
| 203 | const WasmSection *section) { | |
| 204 | if (!section) | |
| 173 | 205 | return; |
| 174 | 206 | |
| 175 | ArrayRef<WasmRelocation> Relocs = Section->Relocations; | |
| 176 | assert(std::is_sorted(Relocs.begin(), Relocs.end(), | |
| 177 | [](const WasmRelocation &R1, const WasmRelocation &R2) { | |
| 178 | return R1.Offset < R2.Offset; | |
| 207 | ArrayRef<WasmRelocation> relocs = section->Relocations; | |
| 208 | assert(std::is_sorted(relocs.begin(), relocs.end(), | |
| 209 | [](const WasmRelocation &r1, const WasmRelocation &r2) { | |
| 210 | return r1.Offset < r2.Offset; | |
| 179 | 211 | })); |
| 180 | 212 | assert(std::is_sorted( |
| 181 | Chunks.begin(), Chunks.end(), [](InputChunk *C1, InputChunk *C2) { | |
| 182 | return C1->getInputSectionOffset() < C2->getInputSectionOffset(); | |
| 213 | chunks.begin(), chunks.end(), [](InputChunk *c1, InputChunk *c2) { | |
| 214 | return c1->getInputSectionOffset() < c2->getInputSectionOffset(); | |
| 183 | 215 | })); |
| 184 | 216 | |
| 185 | auto RelocsNext = Relocs.begin(); | |
| 186 | auto RelocsEnd = Relocs.end(); | |
| 187 | auto RelocLess = [](const WasmRelocation &R, uint32_t Val) { | |
| 188 | return R.Offset < Val; | |
| 217 | auto relocsNext = relocs.begin(); | |
| 218 | auto relocsEnd = relocs.end(); | |
| 219 | auto relocLess = [](const WasmRelocation &r, uint32_t val) { | |
| 220 | return r.Offset < val; | |
| 189 | 221 | }; |
| 190 | for (InputChunk *C : Chunks) { | |
| 191 | auto RelocsStart = std::lower_bound(RelocsNext, RelocsEnd, | |
| 192 | C->getInputSectionOffset(), RelocLess); | |
| 193 | RelocsNext = std::lower_bound( | |
| 194 | RelocsStart, RelocsEnd, C->getInputSectionOffset() + C->getInputSize(), | |
| 195 | RelocLess); | |
| 196 | C->setRelocations(ArrayRef<WasmRelocation>(RelocsStart, RelocsNext)); | |
| 222 | for (InputChunk *c : chunks) { | |
| 223 | auto relocsStart = std::lower_bound(relocsNext, relocsEnd, | |
| 224 | c->getInputSectionOffset(), relocLess); | |
| 225 | relocsNext = std::lower_bound( | |
| 226 | relocsStart, relocsEnd, c->getInputSectionOffset() + c->getInputSize(), | |
| 227 | relocLess); | |
| 228 | c->setRelocations(ArrayRef<WasmRelocation>(relocsStart, relocsNext)); | |
| 197 | 229 | } |
| 198 | 230 | } |
| 199 | 231 | |
| 200 | void ObjFile::parse() { | |
| 232 | void ObjFile::parse(bool ignoreComdats) { | |
| 201 | 233 | // Parse a memory buffer as a wasm file. |
| 202 | 234 | LLVM_DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n"); |
| 203 | std::unique_ptr<Binary> Bin = CHECK(createBinary(MB), toString(this)); | |
| 235 | std::unique_ptr<Binary> bin = CHECK(createBinary(mb), toString(this)); | |
| 204 | 236 | |
| 205 | auto *Obj = dyn_cast<WasmObjectFile>(Bin.get()); | |
| 206 | if (!Obj) | |
| 237 | auto *obj = dyn_cast<WasmObjectFile>(bin.get()); | |
| 238 | if (!obj) | |
| 207 | 239 | fatal(toString(this) + ": not a wasm file"); |
| 208 | if (!Obj->isRelocatableObject()) | |
| 240 | if (!obj->isRelocatableObject()) | |
| 209 | 241 | fatal(toString(this) + ": not a relocatable wasm file"); |
| 210 | 242 | |
| 211 | Bin.release(); | |
| 212 | WasmObj.reset(Obj); | |
| 243 | bin.release(); | |
| 244 | wasmObj.reset(obj); | |
| 213 | 245 | |
| 214 | 246 | // Build up a map of function indices to table indices for use when |
| 215 | 247 | // verifying the existing table index relocations |
| 216 | uint32_t TotalFunctions = | |
| 217 | WasmObj->getNumImportedFunctions() + WasmObj->functions().size(); | |
| 218 | TableEntries.resize(TotalFunctions); | |
| 219 | for (const WasmElemSegment &Seg : WasmObj->elements()) { | |
| 220 | if (Seg.Offset.Opcode != WASM_OPCODE_I32_CONST) | |
| 248 | uint32_t totalFunctions = | |
| 249 | wasmObj->getNumImportedFunctions() + wasmObj->functions().size(); | |
| 250 | tableEntries.resize(totalFunctions); | |
| 251 | for (const WasmElemSegment &seg : wasmObj->elements()) { | |
| 252 | if (seg.Offset.Opcode != WASM_OPCODE_I32_CONST) | |
| 221 | 253 | fatal(toString(this) + ": invalid table elements"); |
| 222 | uint32_t Offset = Seg.Offset.Value.Int32; | |
| 223 | for (uint32_t Index = 0; Index < Seg.Functions.size(); Index++) { | |
| 254 | uint32_t offset = seg.Offset.Value.Int32; | |
| 255 | for (uint32_t index = 0; index < seg.Functions.size(); index++) { | |
| 224 | 256 | |
| 225 | uint32_t FunctionIndex = Seg.Functions[Index]; | |
| 226 | TableEntries[FunctionIndex] = Offset + Index; | |
| 257 | uint32_t functionIndex = seg.Functions[index]; | |
| 258 | tableEntries[functionIndex] = offset + index; | |
| 227 | 259 | } |
| 228 | 260 | } |
| 229 | 261 | |
| 230 | // Find the code and data sections. Wasm objects can have at most one code | |
| 231 | // and one data section. | |
| 232 | uint32_t SectionIndex = 0; | |
| 233 | for (const SectionRef &Sec : WasmObj->sections()) { | |
| 234 | const WasmSection &Section = WasmObj->getWasmSection(Sec); | |
| 235 | if (Section.Type == WASM_SEC_CODE) { | |
| 236 | CodeSection = &Section; | |
| 237 | } else if (Section.Type == WASM_SEC_DATA) { | |
| 238 | DataSection = &Section; | |
| 239 | } else if (Section.Type == WASM_SEC_CUSTOM) { | |
| 240 | CustomSections.emplace_back(make<InputSection>(Section, this)); | |
| 241 | CustomSections.back()->setRelocations(Section.Relocations); | |
| 242 | CustomSectionsByIndex[SectionIndex] = CustomSections.back(); | |
| 262 | uint32_t sectionIndex = 0; | |
| 263 | ||
| 264 | // Bool for each symbol, true if called directly. This allows us to implement | |
| 265 | // a weaker form of signature checking where undefined functions that are not | |
| 266 | // called directly (i.e. only address taken) don't have to match the defined | |
| 267 | // function's signature. We cannot do this for directly called functions | |
| 268 | // because those signatures are checked at validation times. | |
| 269 | // See https://bugs.llvm.org/show_bug.cgi?id=40412 | |
| 270 | std::vector<bool> isCalledDirectly(wasmObj->getNumberOfSymbols(), false); | |
| 271 | for (const SectionRef &sec : wasmObj->sections()) { | |
| 272 | const WasmSection &section = wasmObj->getWasmSection(sec); | |
| 273 | // Wasm objects can have at most one code and one data section. | |
| 274 | if (section.Type == WASM_SEC_CODE) { | |
| 275 | assert(!codeSection); | |
| 276 | codeSection = &section; | |
| 277 | } else if (section.Type == WASM_SEC_DATA) { | |
| 278 | assert(!dataSection); | |
| 279 | dataSection = &section; | |
| 280 | } else if (section.Type == WASM_SEC_CUSTOM) { | |
| 281 | customSections.emplace_back(make<InputSection>(section, this)); | |
| 282 | customSections.back()->setRelocations(section.Relocations); | |
| 283 | customSectionsByIndex[sectionIndex] = customSections.back(); | |
| 243 | 284 | } |
| 244 | SectionIndex++; | |
| 285 | sectionIndex++; | |
| 286 | // Scans relocations to dermine determine if a function symbol is called | |
| 287 | // directly | |
| 288 | for (const WasmRelocation &reloc : section.Relocations) | |
| 289 | if (reloc.Type == R_WASM_FUNCTION_INDEX_LEB) | |
| 290 | isCalledDirectly[reloc.Index] = true; | |
| 245 | 291 | } |
| 246 | 292 | |
| 247 | TypeMap.resize(getWasmObj()->types().size()); | |
| 248 | TypeIsUsed.resize(getWasmObj()->types().size(), false); | |
| 293 | typeMap.resize(getWasmObj()->types().size()); | |
| 294 | typeIsUsed.resize(getWasmObj()->types().size(), false); | |
| 249 | 295 | |
| 250 | ArrayRef<StringRef> Comdats = WasmObj->linkingData().Comdats; | |
| 251 | UsedComdats.resize(Comdats.size()); | |
| 252 | for (unsigned I = 0; I < Comdats.size(); ++I) | |
| 253 | UsedComdats[I] = Symtab->addComdat(Comdats[I]); | |
| 296 | ArrayRef<StringRef> comdats = wasmObj->linkingData().Comdats; | |
| 297 | for (StringRef comdat : comdats) { | |
| 298 | bool isNew = ignoreComdats || symtab->addComdat(comdat); | |
| 299 | keptComdats.push_back(isNew); | |
| 300 | } | |
| 254 | 301 | |
| 255 | 302 | // Populate `Segments`. |
| 256 | for (const WasmSegment &S : WasmObj->dataSegments()) | |
| 257 | Segments.emplace_back(make<InputSegment>(S, this)); | |
| 258 | setRelocs(Segments, DataSection); | |
| 303 | for (const WasmSegment &s : wasmObj->dataSegments()) { | |
| 304 | auto* seg = make<InputSegment>(s, this); | |
| 305 | seg->discarded = isExcludedByComdat(seg); | |
| 306 | segments.emplace_back(seg); | |
| 307 | } | |
| 308 | setRelocs(segments, dataSection); | |
| 259 | 309 | |
| 260 | 310 | // Populate `Functions`. |
| 261 | ArrayRef<WasmFunction> Funcs = WasmObj->functions(); | |
| 262 | ArrayRef<uint32_t> FuncTypes = WasmObj->functionTypes(); | |
| 263 | ArrayRef<WasmSignature> Types = WasmObj->types(); | |
| 264 | Functions.reserve(Funcs.size()); | |
| 265 | ||
| 266 | for (size_t I = 0, E = Funcs.size(); I != E; ++I) | |
| 267 | Functions.emplace_back( | |
| 268 | make<InputFunction>(Types[FuncTypes[I]], &Funcs[I], this)); | |
| 269 | setRelocs(Functions, CodeSection); | |
| 311 | ArrayRef<WasmFunction> funcs = wasmObj->functions(); | |
| 312 | ArrayRef<uint32_t> funcTypes = wasmObj->functionTypes(); | |
| 313 | ArrayRef<WasmSignature> types = wasmObj->types(); | |
| 314 | functions.reserve(funcs.size()); | |
| 315 | ||
| 316 | for (size_t i = 0, e = funcs.size(); i != e; ++i) { | |
| 317 | auto* func = make<InputFunction>(types[funcTypes[i]], &funcs[i], this); | |
| 318 | func->discarded = isExcludedByComdat(func); | |
| 319 | functions.emplace_back(func); | |
| 320 | } | |
| 321 | setRelocs(functions, codeSection); | |
| 270 | 322 | |
| 271 | 323 | // Populate `Globals`. |
| 272 | for (const WasmGlobal &G : WasmObj->globals()) | |
| 273 | Globals.emplace_back(make<InputGlobal>(G, this)); | |
| 324 | for (const WasmGlobal &g : wasmObj->globals()) | |
| 325 | globals.emplace_back(make<InputGlobal>(g, this)); | |
| 274 | 326 | |
| 275 | 327 | // Populate `Events`. |
| 276 | for (const WasmEvent &E : WasmObj->events()) | |
| 277 | Events.emplace_back(make<InputEvent>(Types[E.Type.SigIndex], E, this)); | |
| 278 | ||
| 279 | // Populate `Symbols` based on the WasmSymbols in the object. | |
| 280 | Symbols.reserve(WasmObj->getNumberOfSymbols()); | |
| 281 | for (const SymbolRef &Sym : WasmObj->symbols()) { | |
| 282 | const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym.getRawDataRefImpl()); | |
| 283 | if (Symbol *Sym = createDefined(WasmSym)) | |
| 284 | Symbols.push_back(Sym); | |
| 285 | else | |
| 286 | Symbols.push_back(createUndefined(WasmSym)); | |
| 328 | for (const WasmEvent &e : wasmObj->events()) | |
| 329 | events.emplace_back(make<InputEvent>(types[e.Type.SigIndex], e, this)); | |
| 330 | ||
| 331 | // Populate `Symbols` based on the symbols in the object. | |
| 332 | symbols.reserve(wasmObj->getNumberOfSymbols()); | |
| 333 | for (const SymbolRef &sym : wasmObj->symbols()) { | |
| 334 | const WasmSymbol &wasmSym = wasmObj->getWasmSymbol(sym.getRawDataRefImpl()); | |
| 335 | if (wasmSym.isDefined()) { | |
| 336 | // createDefined may fail if the symbol is comdat excluded in which case | |
| 337 | // we fall back to creating an undefined symbol | |
| 338 | if (Symbol *d = createDefined(wasmSym)) { | |
| 339 | symbols.push_back(d); | |
| 340 | continue; | |
| 341 | } | |
| 342 | } | |
| 343 | size_t idx = symbols.size(); | |
| 344 | symbols.push_back(createUndefined(wasmSym, isCalledDirectly[idx])); | |
| 287 | 345 | } |
| 288 | 346 | } |
| 289 | 347 | |
| 290 | bool ObjFile::isExcludedByComdat(InputChunk *Chunk) const { | |
| 291 | uint32_t C = Chunk->getComdat(); | |
| 292 | if (C == UINT32_MAX) | |
| 348 | bool ObjFile::isExcludedByComdat(InputChunk *chunk) const { | |
| 349 | uint32_t c = chunk->getComdat(); | |
| 350 | if (c == UINT32_MAX) | |
| 293 | 351 | return false; |
| 294 | return !UsedComdats[C]; | |
| 352 | return !keptComdats[c]; | |
| 295 | 353 | } |
| 296 | 354 | |
| 297 | FunctionSymbol *ObjFile::getFunctionSymbol(uint32_t Index) const { | |
| 298 | return cast<FunctionSymbol>(Symbols[Index]); | |
| 355 | FunctionSymbol *ObjFile::getFunctionSymbol(uint32_t index) const { | |
| 356 | return cast<FunctionSymbol>(symbols[index]); | |
| 299 | 357 | } |
| 300 | 358 | |
| 301 | GlobalSymbol *ObjFile::getGlobalSymbol(uint32_t Index) const { | |
| 302 | return cast<GlobalSymbol>(Symbols[Index]); | |
| 359 | GlobalSymbol *ObjFile::getGlobalSymbol(uint32_t index) const { | |
| 360 | return cast<GlobalSymbol>(symbols[index]); | |
| 303 | 361 | } |
| 304 | 362 | |
| 305 | EventSymbol *ObjFile::getEventSymbol(uint32_t Index) const { | |
| 306 | return cast<EventSymbol>(Symbols[Index]); | |
| 363 | EventSymbol *ObjFile::getEventSymbol(uint32_t index) const { | |
| 364 | return cast<EventSymbol>(symbols[index]); | |
| 307 | 365 | } |
| 308 | 366 | |
| 309 | SectionSymbol *ObjFile::getSectionSymbol(uint32_t Index) const { | |
| 310 | return cast<SectionSymbol>(Symbols[Index]); | |
| 367 | SectionSymbol *ObjFile::getSectionSymbol(uint32_t index) const { | |
| 368 | return cast<SectionSymbol>(symbols[index]); | |
| 311 | 369 | } |
| 312 | 370 | |
| 313 | DataSymbol *ObjFile::getDataSymbol(uint32_t Index) const { | |
| 314 | return cast<DataSymbol>(Symbols[Index]); | |
| 371 | DataSymbol *ObjFile::getDataSymbol(uint32_t index) const { | |
| 372 | return cast<DataSymbol>(symbols[index]); | |
| 315 | 373 | } |
| 316 | 374 | |
| 317 | Symbol *ObjFile::createDefined(const WasmSymbol &Sym) { | |
| 318 | if (!Sym.isDefined()) | |
| 319 | return nullptr; | |
| 320 | ||
| 321 | StringRef Name = Sym.Info.Name; | |
| 322 | uint32_t Flags = Sym.Info.Flags; | |
| 375 | Symbol *ObjFile::createDefined(const WasmSymbol &sym) { | |
| 376 | StringRef name = sym.Info.Name; | |
| 377 | uint32_t flags = sym.Info.Flags; | |
| 323 | 378 | |
| 324 | switch (Sym.Info.Kind) { | |
| 379 | switch (sym.Info.Kind) { | |
| 325 | 380 | case WASM_SYMBOL_TYPE_FUNCTION: { |
| 326 | InputFunction *Func = | |
| 327 | Functions[Sym.Info.ElementIndex - WasmObj->getNumImportedFunctions()]; | |
| 328 | if (isExcludedByComdat(Func)) { | |
| 329 | Func->Live = false; | |
| 381 | InputFunction *func = | |
| 382 | functions[sym.Info.ElementIndex - wasmObj->getNumImportedFunctions()]; | |
| 383 | if (sym.isBindingLocal()) | |
| 384 | return make<DefinedFunction>(name, flags, this, func); | |
| 385 | if (func->discarded) | |
| 330 | 386 | return nullptr; |
| 331 | } | |
| 332 | ||
| 333 | if (Sym.isBindingLocal()) | |
| 334 | return make<DefinedFunction>(Name, Flags, this, Func); | |
| 335 | return Symtab->addDefinedFunction(Name, Flags, this, Func); | |
| 387 | return symtab->addDefinedFunction(name, flags, this, func); | |
| 336 | 388 | } |
| 337 | 389 | case WASM_SYMBOL_TYPE_DATA: { |
| 338 | InputSegment *Seg = Segments[Sym.Info.DataRef.Segment]; | |
| 339 | if (isExcludedByComdat(Seg)) { | |
| 340 | Seg->Live = false; | |
| 390 | InputSegment *seg = segments[sym.Info.DataRef.Segment]; | |
| 391 | uint32_t offset = sym.Info.DataRef.Offset; | |
| 392 | uint32_t size = sym.Info.DataRef.Size; | |
| 393 | if (sym.isBindingLocal()) | |
| 394 | return make<DefinedData>(name, flags, this, seg, offset, size); | |
| 395 | if (seg->discarded) | |
| 341 | 396 | return nullptr; |
| 342 | } | |
| 343 | ||
| 344 | uint32_t Offset = Sym.Info.DataRef.Offset; | |
| 345 | uint32_t Size = Sym.Info.DataRef.Size; | |
| 346 | ||
| 347 | if (Sym.isBindingLocal()) | |
| 348 | return make<DefinedData>(Name, Flags, this, Seg, Offset, Size); | |
| 349 | return Symtab->addDefinedData(Name, Flags, this, Seg, Offset, Size); | |
| 397 | return symtab->addDefinedData(name, flags, this, seg, offset, size); | |
| 350 | 398 | } |
| 351 | 399 | case WASM_SYMBOL_TYPE_GLOBAL: { |
| 352 | InputGlobal *Global = | |
| 353 | Globals[Sym.Info.ElementIndex - WasmObj->getNumImportedGlobals()]; | |
| 354 | if (Sym.isBindingLocal()) | |
| 355 | return make<DefinedGlobal>(Name, Flags, this, Global); | |
| 356 | return Symtab->addDefinedGlobal(Name, Flags, this, Global); | |
| 400 | InputGlobal *global = | |
| 401 | globals[sym.Info.ElementIndex - wasmObj->getNumImportedGlobals()]; | |
| 402 | if (sym.isBindingLocal()) | |
| 403 | return make<DefinedGlobal>(name, flags, this, global); | |
| 404 | return symtab->addDefinedGlobal(name, flags, this, global); | |
| 357 | 405 | } |
| 358 | 406 | case WASM_SYMBOL_TYPE_SECTION: { |
| 359 | InputSection *Section = CustomSectionsByIndex[Sym.Info.ElementIndex]; | |
| 360 | assert(Sym.isBindingLocal()); | |
| 361 | return make<SectionSymbol>(Name, Flags, Section, this); | |
| 407 | InputSection *section = customSectionsByIndex[sym.Info.ElementIndex]; | |
| 408 | assert(sym.isBindingLocal()); | |
| 409 | return make<SectionSymbol>(flags, section, this); | |
| 362 | 410 | } |
| 363 | 411 | case WASM_SYMBOL_TYPE_EVENT: { |
| 364 | InputEvent *Event = | |
| 365 | Events[Sym.Info.ElementIndex - WasmObj->getNumImportedEvents()]; | |
| 366 | if (Sym.isBindingLocal()) | |
| 367 | return make<DefinedEvent>(Name, Flags, this, Event); | |
| 368 | return Symtab->addDefinedEvent(Name, Flags, this, Event); | |
| 412 | InputEvent *event = | |
| 413 | events[sym.Info.ElementIndex - wasmObj->getNumImportedEvents()]; | |
| 414 | if (sym.isBindingLocal()) | |
| 415 | return make<DefinedEvent>(name, flags, this, event); | |
| 416 | return symtab->addDefinedEvent(name, flags, this, event); | |
| 369 | 417 | } |
| 370 | 418 | } |
| 371 | 419 | llvm_unreachable("unknown symbol kind"); |
| 372 | 420 | } |
| 373 | 421 | |
| 374 | Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) { | |
| 375 | StringRef Name = Sym.Info.Name; | |
| 376 | uint32_t Flags = Sym.Info.Flags; | |
| 422 | Symbol *ObjFile::createUndefined(const WasmSymbol &sym, bool isCalledDirectly) { | |
| 423 | StringRef name = sym.Info.Name; | |
| 424 | uint32_t flags = sym.Info.Flags; | |
| 377 | 425 | |
| 378 | switch (Sym.Info.Kind) { | |
| 426 | switch (sym.Info.Kind) { | |
| 379 | 427 | case WASM_SYMBOL_TYPE_FUNCTION: |
| 380 | return Symtab->addUndefinedFunction(Name, Sym.Info.ImportName, | |
| 381 | Sym.Info.ImportModule, Flags, this, | |
| 382 | Sym.Signature); | |
| 428 | if (sym.isBindingLocal()) | |
| 429 | return make<UndefinedFunction>(name, sym.Info.ImportName, | |
| 430 | sym.Info.ImportModule, flags, this, | |
| 431 | sym.Signature, isCalledDirectly); | |
| 432 | return symtab->addUndefinedFunction(name, sym.Info.ImportName, | |
| 433 | sym.Info.ImportModule, flags, this, | |
| 434 | sym.Signature, isCalledDirectly); | |
| 383 | 435 | case WASM_SYMBOL_TYPE_DATA: |
| 384 | return Symtab->addUndefinedData(Name, Flags, this); | |
| 436 | if (sym.isBindingLocal()) | |
| 437 | return make<UndefinedData>(name, flags, this); | |
| 438 | return symtab->addUndefinedData(name, flags, this); | |
| 385 | 439 | case WASM_SYMBOL_TYPE_GLOBAL: |
| 386 | return Symtab->addUndefinedGlobal(Name, Sym.Info.ImportName, | |
| 387 | Sym.Info.ImportModule, Flags, this, | |
| 388 | Sym.GlobalType); | |
| 440 | if (sym.isBindingLocal()) | |
| 441 | return make<UndefinedGlobal>(name, sym.Info.ImportName, | |
| 442 | sym.Info.ImportModule, flags, this, | |
| 443 | sym.GlobalType); | |
| 444 | return symtab->addUndefinedGlobal(name, sym.Info.ImportName, | |
| 445 | sym.Info.ImportModule, flags, this, | |
| 446 | sym.GlobalType); | |
| 389 | 447 | case WASM_SYMBOL_TYPE_SECTION: |
| 390 | 448 | llvm_unreachable("section symbols cannot be undefined"); |
| 391 | 449 | } |
| ... | ... | @@ -395,42 +453,41 @@ Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) { |
| 395 | 453 | void ArchiveFile::parse() { |
| 396 | 454 | // Parse a MemoryBufferRef as an archive file. |
| 397 | 455 | LLVM_DEBUG(dbgs() << "Parsing library: " << toString(this) << "\n"); |
| 398 | File = CHECK(Archive::create(MB), toString(this)); | |
| 456 | file = CHECK(Archive::create(mb), toString(this)); | |
| 399 | 457 | |
| 400 | 458 | // Read the symbol table to construct Lazy symbols. |
| 401 | int Count = 0; | |
| 402 | for (const Archive::Symbol &Sym : File->symbols()) { | |
| 403 | Symtab->addLazy(this, &Sym); | |
| 404 | ++Count; | |
| 459 | int count = 0; | |
| 460 | for (const Archive::Symbol &sym : file->symbols()) { | |
| 461 | symtab->addLazy(this, &sym); | |
| 462 | ++count; | |
| 405 | 463 | } |
| 406 | LLVM_DEBUG(dbgs() << "Read " << Count << " symbols\n"); | |
| 464 | LLVM_DEBUG(dbgs() << "Read " << count << " symbols\n"); | |
| 407 | 465 | } |
| 408 | 466 | |
| 409 | void ArchiveFile::addMember(const Archive::Symbol *Sym) { | |
| 410 | const Archive::Child &C = | |
| 411 | CHECK(Sym->getMember(), | |
| 412 | "could not get the member for symbol " + Sym->getName()); | |
| 467 | void ArchiveFile::addMember(const Archive::Symbol *sym) { | |
| 468 | const Archive::Child &c = | |
| 469 | CHECK(sym->getMember(), | |
| 470 | "could not get the member for symbol " + sym->getName()); | |
| 413 | 471 | |
| 414 | 472 | // Don't try to load the same member twice (this can happen when members |
| 415 | 473 | // mutually reference each other). |
| 416 | if (!Seen.insert(C.getChildOffset()).second) | |
| 474 | if (!seen.insert(c.getChildOffset()).second) | |
| 417 | 475 | return; |
| 418 | 476 | |
| 419 | LLVM_DEBUG(dbgs() << "loading lazy: " << Sym->getName() << "\n"); | |
| 477 | LLVM_DEBUG(dbgs() << "loading lazy: " << sym->getName() << "\n"); | |
| 420 | 478 | LLVM_DEBUG(dbgs() << "from archive: " << toString(this) << "\n"); |
| 421 | 479 | |
| 422 | MemoryBufferRef MB = | |
| 423 | CHECK(C.getMemoryBufferRef(), | |
| 480 | MemoryBufferRef mb = | |
| 481 | CHECK(c.getMemoryBufferRef(), | |
| 424 | 482 | "could not get the buffer for the member defining symbol " + |
| 425 | Sym->getName()); | |
| 483 | sym->getName()); | |
| 426 | 484 | |
| 427 | InputFile *Obj = createObjectFile(MB); | |
| 428 | Obj->ArchiveName = getName(); | |
| 429 | Symtab->addFile(Obj); | |
| 485 | InputFile *obj = createObjectFile(mb, getName()); | |
| 486 | symtab->addFile(obj); | |
| 430 | 487 | } |
| 431 | 488 | |
| 432 | static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) { | |
| 433 | switch (GvVisibility) { | |
| 489 | static uint8_t mapVisibility(GlobalValue::VisibilityTypes gvVisibility) { | |
| 490 | switch (gvVisibility) { | |
| 434 | 491 | case GlobalValue::DefaultVisibility: |
| 435 | 492 | return WASM_SYMBOL_VISIBILITY_DEFAULT; |
| 436 | 493 | case GlobalValue::HiddenVisibility: |
| ... | ... | @@ -440,45 +497,52 @@ static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) { |
| 440 | 497 | llvm_unreachable("unknown visibility"); |
| 441 | 498 | } |
| 442 | 499 | |
| 443 | static Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &ObjSym, | |
| 444 | BitcodeFile &F) { | |
| 445 | StringRef Name = Saver.save(ObjSym.getName()); | |
| 500 | static Symbol *createBitcodeSymbol(const std::vector<bool> &keptComdats, | |
| 501 | const lto::InputFile::Symbol &objSym, | |
| 502 | BitcodeFile &f) { | |
| 503 | StringRef name = saver.save(objSym.getName()); | |
| 504 | ||
| 505 | uint32_t flags = objSym.isWeak() ? WASM_SYMBOL_BINDING_WEAK : 0; | |
| 506 | flags |= mapVisibility(objSym.getVisibility()); | |
| 446 | 507 | |
| 447 | uint32_t Flags = ObjSym.isWeak() ? WASM_SYMBOL_BINDING_WEAK : 0; | |
| 448 | Flags |= mapVisibility(ObjSym.getVisibility()); | |
| 508 | int c = objSym.getComdatIndex(); | |
| 509 | bool excludedByComdat = c != -1 && !keptComdats[c]; | |
| 449 | 510 | |
| 450 | if (ObjSym.isUndefined()) { | |
| 451 | if (ObjSym.isExecutable()) | |
| 452 | return Symtab->addUndefinedFunction(Name, Name, DefaultModule, Flags, &F, | |
| 453 | nullptr); | |
| 454 | return Symtab->addUndefinedData(Name, Flags, &F); | |
| 511 | if (objSym.isUndefined() || excludedByComdat) { | |
| 512 | if (objSym.isExecutable()) | |
| 513 | return symtab->addUndefinedFunction(name, name, defaultModule, flags, &f, | |
| 514 | nullptr, true); | |
| 515 | return symtab->addUndefinedData(name, flags, &f); | |
| 455 | 516 | } |
| 456 | 517 | |
| 457 | if (ObjSym.isExecutable()) | |
| 458 | return Symtab->addDefinedFunction(Name, Flags, &F, nullptr); | |
| 459 | return Symtab->addDefinedData(Name, Flags, &F, nullptr, 0, 0); | |
| 518 | if (objSym.isExecutable()) | |
| 519 | return symtab->addDefinedFunction(name, flags, &f, nullptr); | |
| 520 | return symtab->addDefinedData(name, flags, &f, nullptr, 0, 0); | |
| 460 | 521 | } |
| 461 | 522 | |
| 462 | 523 | void BitcodeFile::parse() { |
| 463 | Obj = check(lto::InputFile::create(MemoryBufferRef( | |
| 464 | MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier())))); | |
| 465 | Triple T(Obj->getTargetTriple()); | |
| 466 | if (T.getArch() != Triple::wasm32) { | |
| 467 | error(toString(MB.getBufferIdentifier()) + ": machine type must be wasm32"); | |
| 524 | obj = check(lto::InputFile::create(MemoryBufferRef( | |
| 525 | mb.getBuffer(), saver.save(archiveName + mb.getBufferIdentifier())))); | |
| 526 | Triple t(obj->getTargetTriple()); | |
| 527 | if (t.getArch() != Triple::wasm32) { | |
| 528 | error(toString(mb.getBufferIdentifier()) + ": machine type must be wasm32"); | |
| 468 | 529 | return; |
| 469 | 530 | } |
| 531 | std::vector<bool> keptComdats; | |
| 532 | for (StringRef s : obj->getComdatTable()) | |
| 533 | keptComdats.push_back(symtab->addComdat(s)); | |
| 470 | 534 | |
| 471 | for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) | |
| 472 | Symbols.push_back(createBitcodeSymbol(ObjSym, *this)); | |
| 535 | for (const lto::InputFile::Symbol &objSym : obj->symbols()) | |
| 536 | symbols.push_back(createBitcodeSymbol(keptComdats, objSym, *this)); | |
| 473 | 537 | } |
| 474 | 538 | |
| 475 | 539 | // Returns a string in the format of "foo.o" or "foo.a(bar.o)". |
| 476 | std::string lld::toString(const wasm::InputFile *File) { | |
| 477 | if (!File) | |
| 540 | std::string lld::toString(const wasm::InputFile *file) { | |
| 541 | if (!file) | |
| 478 | 542 | return "<internal>"; |
| 479 | 543 | |
| 480 | if (File->ArchiveName.empty()) | |
| 481 | return File->getName(); | |
| 544 | if (file->archiveName.empty()) | |
| 545 | return file->getName(); | |
| 482 | 546 | |
| 483 | return (File->ArchiveName + "(" + File->getName() + ")").str(); | |
| 547 | return (file->archiveName + "(" + file->getName() + ")").str(); | |
| 484 | 548 | } |
deps/lld/wasm/InputFiles.h+85-61| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- InputFiles.h ---------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -20,6 +19,10 @@ |
| 20 | 19 | #include "llvm/Support/MemoryBuffer.h" |
| 21 | 20 | #include <vector> |
| 22 | 21 | |
| 22 | namespace llvm { | |
| 23 | class TarWriter; | |
| 24 | } | |
| 25 | ||
| 23 | 26 | namespace lld { |
| 24 | 27 | namespace wasm { |
| 25 | 28 | |
| ... | ... | @@ -30,10 +33,15 @@ class InputGlobal; |
| 30 | 33 | class InputEvent; |
| 31 | 34 | class InputSection; |
| 32 | 35 | |
| 36 | // If --reproduce option is given, all input files are written | |
| 37 | // to this tar archive. | |
| 38 | extern std::unique_ptr<llvm::TarWriter> tar; | |
| 39 | ||
| 33 | 40 | class InputFile { |
| 34 | 41 | public: |
| 35 | 42 | enum Kind { |
| 36 | 43 | ObjectKind, |
| 44 | SharedKind, | |
| 37 | 45 | ArchiveKind, |
| 38 | 46 | BitcodeKind, |
| 39 | 47 | }; |
| ... | ... | @@ -41,113 +49,129 @@ public: |
| 41 | 49 | virtual ~InputFile() {} |
| 42 | 50 | |
| 43 | 51 | // Returns the filename. |
| 44 | StringRef getName() const { return MB.getBufferIdentifier(); } | |
| 52 | StringRef getName() const { return mb.getBufferIdentifier(); } | |
| 45 | 53 | |
| 46 | // Reads a file (the constructor doesn't do that). | |
| 47 | virtual void parse() = 0; | |
| 48 | ||
| 49 | Kind kind() const { return FileKind; } | |
| 54 | Kind kind() const { return fileKind; } | |
| 50 | 55 | |
| 51 | 56 | // An archive file name if this file is created from an archive. |
| 52 | StringRef ArchiveName; | |
| 57 | StringRef archiveName; | |
| 58 | ||
| 59 | ArrayRef<Symbol *> getSymbols() const { return symbols; } | |
| 53 | 60 | |
| 54 | ArrayRef<Symbol *> getSymbols() const { return Symbols; } | |
| 61 | MutableArrayRef<Symbol *> getMutableSymbols() { return symbols; } | |
| 55 | 62 | |
| 56 | 63 | protected: |
| 57 | InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} | |
| 58 | MemoryBufferRef MB; | |
| 64 | InputFile(Kind k, MemoryBufferRef m) : mb(m), fileKind(k) {} | |
| 65 | MemoryBufferRef mb; | |
| 59 | 66 | |
| 60 | 67 | // List of all symbols referenced or defined by this file. |
| 61 | std::vector<Symbol *> Symbols; | |
| 68 | std::vector<Symbol *> symbols; | |
| 62 | 69 | |
| 63 | 70 | private: |
| 64 | const Kind FileKind; | |
| 71 | const Kind fileKind; | |
| 65 | 72 | }; |
| 66 | 73 | |
| 67 | 74 | // .a file (ar archive) |
| 68 | 75 | class ArchiveFile : public InputFile { |
| 69 | 76 | public: |
| 70 | explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} | |
| 71 | static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } | |
| 77 | explicit ArchiveFile(MemoryBufferRef m) : InputFile(ArchiveKind, m) {} | |
| 78 | static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; } | |
| 72 | 79 | |
| 73 | void addMember(const llvm::object::Archive::Symbol *Sym); | |
| 80 | void addMember(const llvm::object::Archive::Symbol *sym); | |
| 74 | 81 | |
| 75 | void parse() override; | |
| 82 | void parse(); | |
| 76 | 83 | |
| 77 | 84 | private: |
| 78 | std::unique_ptr<llvm::object::Archive> File; | |
| 79 | llvm::DenseSet<uint64_t> Seen; | |
| 85 | std::unique_ptr<llvm::object::Archive> file; | |
| 86 | llvm::DenseSet<uint64_t> seen; | |
| 80 | 87 | }; |
| 81 | 88 | |
| 82 | 89 | // .o file (wasm object file) |
| 83 | 90 | class ObjFile : public InputFile { |
| 84 | 91 | public: |
| 85 | explicit ObjFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {} | |
| 86 | static bool classof(const InputFile *F) { return F->kind() == ObjectKind; } | |
| 92 | explicit ObjFile(MemoryBufferRef m, StringRef archiveName) | |
| 93 | : InputFile(ObjectKind, m) { | |
| 94 | this->archiveName = archiveName; | |
| 95 | } | |
| 96 | static bool classof(const InputFile *f) { return f->kind() == ObjectKind; } | |
| 87 | 97 | |
| 88 | void parse() override; | |
| 98 | void parse(bool ignoreComdats = false); | |
| 89 | 99 | |
| 90 | 100 | // Returns the underlying wasm file. |
| 91 | const WasmObjectFile *getWasmObj() const { return WasmObj.get(); } | |
| 101 | const WasmObjectFile *getWasmObj() const { return wasmObj.get(); } | |
| 92 | 102 | |
| 93 | 103 | void dumpInfo() const; |
| 94 | 104 | |
| 95 | uint32_t calcNewIndex(const WasmRelocation &Reloc) const; | |
| 96 | uint32_t calcNewValue(const WasmRelocation &Reloc) const; | |
| 97 | uint32_t calcNewAddend(const WasmRelocation &Reloc) const; | |
| 98 | uint32_t calcExpectedValue(const WasmRelocation &Reloc) const; | |
| 105 | uint32_t calcNewIndex(const WasmRelocation &reloc) const; | |
| 106 | uint32_t calcNewValue(const WasmRelocation &reloc) const; | |
| 107 | uint32_t calcNewAddend(const WasmRelocation &reloc) const; | |
| 108 | uint32_t calcExpectedValue(const WasmRelocation &reloc) const; | |
| 109 | Symbol *getSymbol(const WasmRelocation &reloc) const { | |
| 110 | return symbols[reloc.Index]; | |
| 111 | }; | |
| 99 | 112 | |
| 100 | const WasmSection *CodeSection = nullptr; | |
| 101 | const WasmSection *DataSection = nullptr; | |
| 113 | const WasmSection *codeSection = nullptr; | |
| 114 | const WasmSection *dataSection = nullptr; | |
| 102 | 115 | |
| 103 | 116 | // Maps input type indices to output type indices |
| 104 | std::vector<uint32_t> TypeMap; | |
| 105 | std::vector<bool> TypeIsUsed; | |
| 117 | std::vector<uint32_t> typeMap; | |
| 118 | std::vector<bool> typeIsUsed; | |
| 106 | 119 | // Maps function indices to table indices |
| 107 | std::vector<uint32_t> TableEntries; | |
| 108 | std::vector<bool> UsedComdats; | |
| 109 | std::vector<InputSegment *> Segments; | |
| 110 | std::vector<InputFunction *> Functions; | |
| 111 | std::vector<InputGlobal *> Globals; | |
| 112 | std::vector<InputEvent *> Events; | |
| 113 | std::vector<InputSection *> CustomSections; | |
| 114 | llvm::DenseMap<uint32_t, InputSection *> CustomSectionsByIndex; | |
| 115 | ||
| 116 | Symbol *getSymbol(uint32_t Index) const { return Symbols[Index]; } | |
| 117 | FunctionSymbol *getFunctionSymbol(uint32_t Index) const; | |
| 118 | DataSymbol *getDataSymbol(uint32_t Index) const; | |
| 119 | GlobalSymbol *getGlobalSymbol(uint32_t Index) const; | |
| 120 | SectionSymbol *getSectionSymbol(uint32_t Index) const; | |
| 121 | EventSymbol *getEventSymbol(uint32_t Index) const; | |
| 120 | std::vector<uint32_t> tableEntries; | |
| 121 | std::vector<bool> keptComdats; | |
| 122 | std::vector<InputSegment *> segments; | |
| 123 | std::vector<InputFunction *> functions; | |
| 124 | std::vector<InputGlobal *> globals; | |
| 125 | std::vector<InputEvent *> events; | |
| 126 | std::vector<InputSection *> customSections; | |
| 127 | llvm::DenseMap<uint32_t, InputSection *> customSectionsByIndex; | |
| 128 | ||
| 129 | Symbol *getSymbol(uint32_t index) const { return symbols[index]; } | |
| 130 | FunctionSymbol *getFunctionSymbol(uint32_t index) const; | |
| 131 | DataSymbol *getDataSymbol(uint32_t index) const; | |
| 132 | GlobalSymbol *getGlobalSymbol(uint32_t index) const; | |
| 133 | SectionSymbol *getSectionSymbol(uint32_t index) const; | |
| 134 | EventSymbol *getEventSymbol(uint32_t index) const; | |
| 122 | 135 | |
| 123 | 136 | private: |
| 124 | Symbol *createDefined(const WasmSymbol &Sym); | |
| 125 | Symbol *createUndefined(const WasmSymbol &Sym); | |
| 137 | Symbol *createDefined(const WasmSymbol &sym); | |
| 138 | Symbol *createUndefined(const WasmSymbol &sym, bool isCalledDirectly); | |
| 126 | 139 | |
| 127 | bool isExcludedByComdat(InputChunk *Chunk) const; | |
| 140 | bool isExcludedByComdat(InputChunk *chunk) const; | |
| 128 | 141 | |
| 129 | std::unique_ptr<WasmObjectFile> WasmObj; | |
| 142 | std::unique_ptr<WasmObjectFile> wasmObj; | |
| 130 | 143 | }; |
| 131 | 144 | |
| 132 | class BitcodeFile : public InputFile { | |
| 145 | // .so file. | |
| 146 | class SharedFile : public InputFile { | |
| 133 | 147 | public: |
| 134 | explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {} | |
| 135 | static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } | |
| 148 | explicit SharedFile(MemoryBufferRef m) : InputFile(SharedKind, m) {} | |
| 149 | static bool classof(const InputFile *f) { return f->kind() == SharedKind; } | |
| 150 | }; | |
| 136 | 151 | |
| 137 | void parse() override; | |
| 138 | std::unique_ptr<llvm::lto::InputFile> Obj; | |
| 152 | // .bc file | |
| 153 | class BitcodeFile : public InputFile { | |
| 154 | public: | |
| 155 | explicit BitcodeFile(MemoryBufferRef m, StringRef archiveName) | |
| 156 | : InputFile(BitcodeKind, m) { | |
| 157 | this->archiveName = archiveName; | |
| 158 | } | |
| 159 | static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; } | |
| 160 | ||
| 161 | void parse(); | |
| 162 | std::unique_ptr<llvm::lto::InputFile> obj; | |
| 139 | 163 | }; |
| 140 | 164 | |
| 141 | 165 | // Will report a fatal() error if the input buffer is not a valid bitcode |
| 142 | // or was object file. | |
| 143 | InputFile *createObjectFile(MemoryBufferRef MB); | |
| 166 | // or wasm object file. | |
| 167 | InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName = ""); | |
| 144 | 168 | |
| 145 | 169 | // Opens a given file. |
| 146 | llvm::Optional<MemoryBufferRef> readFile(StringRef Path); | |
| 170 | llvm::Optional<MemoryBufferRef> readFile(StringRef path); | |
| 147 | 171 | |
| 148 | 172 | } // namespace wasm |
| 149 | 173 | |
| 150 | std::string toString(const wasm::InputFile *File); | |
| 174 | std::string toString(const wasm::InputFile *file); | |
| 151 | 175 | |
| 152 | 176 | } // namespace lld |
| 153 | 177 |
deps/lld/wasm/InputGlobal.h+17-18| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- InputGlobal.h --------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -23,32 +22,32 @@ namespace wasm { |
| 23 | 22 | // combined to form the final GLOBALS section. |
| 24 | 23 | class InputGlobal { |
| 25 | 24 | public: |
| 26 | InputGlobal(const WasmGlobal &G, ObjFile *F) | |
| 27 | : File(F), Global(G), Live(!Config->GcSections) {} | |
| 25 | InputGlobal(const WasmGlobal &g, ObjFile *f) | |
| 26 | : file(f), global(g), live(!config->gcSections) {} | |
| 28 | 27 | |
| 29 | StringRef getName() const { return Global.SymbolName; } | |
| 30 | const WasmGlobalType &getType() const { return Global.Type; } | |
| 28 | StringRef getName() const { return global.SymbolName; } | |
| 29 | const WasmGlobalType &getType() const { return global.Type; } | |
| 31 | 30 | |
| 32 | uint32_t getGlobalIndex() const { return GlobalIndex.getValue(); } | |
| 33 | bool hasGlobalIndex() const { return GlobalIndex.hasValue(); } | |
| 34 | void setGlobalIndex(uint32_t Index) { | |
| 31 | uint32_t getGlobalIndex() const { return globalIndex.getValue(); } | |
| 32 | bool hasGlobalIndex() const { return globalIndex.hasValue(); } | |
| 33 | void setGlobalIndex(uint32_t index) { | |
| 35 | 34 | assert(!hasGlobalIndex()); |
| 36 | GlobalIndex = Index; | |
| 35 | globalIndex = index; | |
| 37 | 36 | } |
| 38 | 37 | |
| 39 | ObjFile *File; | |
| 40 | WasmGlobal Global; | |
| 38 | ObjFile *file; | |
| 39 | WasmGlobal global; | |
| 41 | 40 | |
| 42 | bool Live = false; | |
| 41 | bool live = false; | |
| 43 | 42 | |
| 44 | 43 | protected: |
| 45 | llvm::Optional<uint32_t> GlobalIndex; | |
| 44 | llvm::Optional<uint32_t> globalIndex; | |
| 46 | 45 | }; |
| 47 | 46 | |
| 48 | 47 | } // namespace wasm |
| 49 | 48 | |
| 50 | inline std::string toString(const wasm::InputGlobal *G) { | |
| 51 | return (toString(G->File) + ":(" + G->getName() + ")").str(); | |
| 49 | inline std::string toString(const wasm::InputGlobal *g) { | |
| 50 | return (toString(g->file) + ":(" + g->getName() + ")").str(); | |
| 52 | 51 | } |
| 53 | 52 | |
| 54 | 53 | } // namespace lld |
deps/lld/wasm/LTO.cpp+82-79| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- LTO.cpp ------------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -11,6 +10,7 @@ |
| 11 | 10 | #include "Config.h" |
| 12 | 11 | #include "InputFiles.h" |
| 13 | 12 | #include "Symbols.h" |
| 13 | #include "lld/Common/Args.h" | |
| 14 | 14 | #include "lld/Common/ErrorHandler.h" |
| 15 | 15 | #include "lld/Common/Strings.h" |
| 16 | 16 | #include "lld/Common/TargetOptionsCommandFlags.h" |
| ... | ... | @@ -40,124 +40,127 @@ using namespace lld; |
| 40 | 40 | using namespace lld::wasm; |
| 41 | 41 | |
| 42 | 42 | static std::unique_ptr<lto::LTO> createLTO() { |
| 43 | lto::Config C; | |
| 44 | C.Options = InitTargetOptionsFromCodeGenFlags(); | |
| 43 | lto::Config c; | |
| 44 | c.Options = initTargetOptionsFromCodeGenFlags(); | |
| 45 | 45 | |
| 46 | 46 | // Always emit a section per function/data with LTO. |
| 47 | C.Options.FunctionSections = true; | |
| 48 | C.Options.DataSections = true; | |
| 49 | ||
| 50 | // Wasm currently only supports ThreadModel::Single | |
| 51 | C.Options.ThreadModel = ThreadModel::Single; | |
| 52 | ||
| 53 | C.DisableVerify = Config->DisableVerify; | |
| 54 | C.DiagHandler = diagnosticHandler; | |
| 55 | C.OptLevel = Config->LTOO; | |
| 56 | C.MAttrs = GetMAttrs(); | |
| 57 | ||
| 58 | if (Config->Relocatable) | |
| 59 | C.RelocModel = None; | |
| 60 | else if (Config->Pic) | |
| 61 | C.RelocModel = Reloc::PIC_; | |
| 47 | c.Options.FunctionSections = true; | |
| 48 | c.Options.DataSections = true; | |
| 49 | ||
| 50 | c.DisableVerify = config->disableVerify; | |
| 51 | c.DiagHandler = diagnosticHandler; | |
| 52 | c.OptLevel = config->ltoo; | |
| 53 | c.MAttrs = getMAttrs(); | |
| 54 | c.CGOptLevel = args::getCGOptLevel(config->ltoo); | |
| 55 | ||
| 56 | if (config->relocatable) | |
| 57 | c.RelocModel = None; | |
| 58 | else if (config->isPic) | |
| 59 | c.RelocModel = Reloc::PIC_; | |
| 62 | 60 | else |
| 63 | C.RelocModel = Reloc::Static; | |
| 61 | c.RelocModel = Reloc::Static; | |
| 64 | 62 | |
| 65 | if (Config->SaveTemps) | |
| 66 | checkError(C.addSaveTemps(Config->OutputFile.str() + ".", | |
| 63 | if (config->saveTemps) | |
| 64 | checkError(c.addSaveTemps(config->outputFile.str() + ".", | |
| 67 | 65 | /*UseInputModulePath*/ true)); |
| 68 | 66 | |
| 69 | lto::ThinBackend Backend; | |
| 70 | if (Config->ThinLTOJobs != -1U) | |
| 71 | Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs); | |
| 72 | return llvm::make_unique<lto::LTO>(std::move(C), Backend, | |
| 73 | Config->LTOPartitions); | |
| 67 | lto::ThinBackend backend; | |
| 68 | if (config->thinLTOJobs != -1U) | |
| 69 | backend = lto::createInProcessThinBackend(config->thinLTOJobs); | |
| 70 | return llvm::make_unique<lto::LTO>(std::move(c), backend, | |
| 71 | config->ltoPartitions); | |
| 74 | 72 | } |
| 75 | 73 | |
| 76 | BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {} | |
| 74 | BitcodeCompiler::BitcodeCompiler() : ltoObj(createLTO()) {} | |
| 77 | 75 | |
| 78 | 76 | BitcodeCompiler::~BitcodeCompiler() = default; |
| 79 | 77 | |
| 80 | static void undefine(Symbol *S) { | |
| 81 | if (auto F = dyn_cast<DefinedFunction>(S)) | |
| 82 | replaceSymbol<UndefinedFunction>(F, F->getName(), F->getName(), | |
| 83 | DefaultModule, 0, | |
| 84 | F->getFile(), F->Signature); | |
| 85 | else if (isa<DefinedData>(S)) | |
| 86 | replaceSymbol<UndefinedData>(S, S->getName(), 0, S->getFile()); | |
| 78 | static void undefine(Symbol *s) { | |
| 79 | if (auto f = dyn_cast<DefinedFunction>(s)) | |
| 80 | replaceSymbol<UndefinedFunction>(f, f->getName(), f->getName(), | |
| 81 | defaultModule, 0, | |
| 82 | f->getFile(), f->signature); | |
| 83 | else if (isa<DefinedData>(s)) | |
| 84 | replaceSymbol<UndefinedData>(s, s->getName(), 0, s->getFile()); | |
| 87 | 85 | else |
| 88 | 86 | llvm_unreachable("unexpected symbol kind"); |
| 89 | 87 | } |
| 90 | 88 | |
| 91 | void BitcodeCompiler::add(BitcodeFile &F) { | |
| 92 | lto::InputFile &Obj = *F.Obj; | |
| 93 | unsigned SymNum = 0; | |
| 94 | ArrayRef<Symbol *> Syms = F.getSymbols(); | |
| 95 | std::vector<lto::SymbolResolution> Resols(Syms.size()); | |
| 89 | void BitcodeCompiler::add(BitcodeFile &f) { | |
| 90 | lto::InputFile &obj = *f.obj; | |
| 91 | unsigned symNum = 0; | |
| 92 | ArrayRef<Symbol *> syms = f.getSymbols(); | |
| 93 | std::vector<lto::SymbolResolution> resols(syms.size()); | |
| 96 | 94 | |
| 97 | 95 | // Provide a resolution to the LTO API for each symbol. |
| 98 | for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) { | |
| 99 | Symbol *Sym = Syms[SymNum]; | |
| 100 | lto::SymbolResolution &R = Resols[SymNum]; | |
| 101 | ++SymNum; | |
| 96 | for (const lto::InputFile::Symbol &objSym : obj.symbols()) { | |
| 97 | Symbol *sym = syms[symNum]; | |
| 98 | lto::SymbolResolution &r = resols[symNum]; | |
| 99 | ++symNum; | |
| 102 | 100 | |
| 103 | 101 | // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile |
| 104 | 102 | // reports two symbols for module ASM defined. Without this check, lld |
| 105 | 103 | // flags an undefined in IR with a definition in ASM as prevailing. |
| 106 | 104 | // Once IRObjectFile is fixed to report only one symbol this hack can |
| 107 | 105 | // be removed. |
| 108 | R.Prevailing = !ObjSym.isUndefined() && Sym->getFile() == &F; | |
| 109 | R.VisibleToRegularObj = Config->Relocatable || Sym->IsUsedInRegularObj || | |
| 110 | (R.Prevailing && Sym->isExported()); | |
| 111 | if (R.Prevailing) | |
| 112 | undefine(Sym); | |
| 106 | r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f; | |
| 107 | r.VisibleToRegularObj = config->relocatable || sym->isUsedInRegularObj || | |
| 108 | (r.Prevailing && sym->isExported()); | |
| 109 | if (r.Prevailing) | |
| 110 | undefine(sym); | |
| 111 | ||
| 112 | // We tell LTO to not apply interprocedural optimization for wrapped | |
| 113 | // (with --wrap) symbols because otherwise LTO would inline them while | |
| 114 | // their values are still not final. | |
| 115 | r.LinkerRedefined = !sym->canInline; | |
| 113 | 116 | } |
| 114 | checkError(LTOObj->add(std::move(F.Obj), Resols)); | |
| 117 | checkError(ltoObj->add(std::move(f.obj), resols)); | |
| 115 | 118 | } |
| 116 | 119 | |
| 117 | 120 | // Merge all the bitcode files we have seen, codegen the result |
| 118 | 121 | // and return the resulting objects. |
| 119 | 122 | std::vector<StringRef> BitcodeCompiler::compile() { |
| 120 | unsigned MaxTasks = LTOObj->getMaxTasks(); | |
| 121 | Buf.resize(MaxTasks); | |
| 122 | Files.resize(MaxTasks); | |
| 123 | unsigned maxTasks = ltoObj->getMaxTasks(); | |
| 124 | buf.resize(maxTasks); | |
| 125 | files.resize(maxTasks); | |
| 123 | 126 | |
| 124 | 127 | // The --thinlto-cache-dir option specifies the path to a directory in which |
| 125 | 128 | // to cache native object files for ThinLTO incremental builds. If a path was |
| 126 | 129 | // specified, configure LTO to use it as the cache directory. |
| 127 | lto::NativeObjectCache Cache; | |
| 128 | if (!Config->ThinLTOCacheDir.empty()) | |
| 129 | Cache = check( | |
| 130 | lto::localCache(Config->ThinLTOCacheDir, | |
| 131 | [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) { | |
| 132 | Files[Task] = std::move(MB); | |
| 130 | lto::NativeObjectCache cache; | |
| 131 | if (!config->thinLTOCacheDir.empty()) | |
| 132 | cache = check( | |
| 133 | lto::localCache(config->thinLTOCacheDir, | |
| 134 | [&](size_t task, std::unique_ptr<MemoryBuffer> mb) { | |
| 135 | files[task] = std::move(mb); | |
| 133 | 136 | })); |
| 134 | 137 | |
| 135 | checkError(LTOObj->run( | |
| 136 | [&](size_t Task) { | |
| 138 | checkError(ltoObj->run( | |
| 139 | [&](size_t task) { | |
| 137 | 140 | return llvm::make_unique<lto::NativeObjectStream>( |
| 138 | llvm::make_unique<raw_svector_ostream>(Buf[Task])); | |
| 141 | llvm::make_unique<raw_svector_ostream>(buf[task])); | |
| 139 | 142 | }, |
| 140 | Cache)); | |
| 143 | cache)); | |
| 141 | 144 | |
| 142 | if (!Config->ThinLTOCacheDir.empty()) | |
| 143 | pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy); | |
| 145 | if (!config->thinLTOCacheDir.empty()) | |
| 146 | pruneCache(config->thinLTOCacheDir, config->thinLTOCachePolicy); | |
| 144 | 147 | |
| 145 | std::vector<StringRef> Ret; | |
| 146 | for (unsigned I = 0; I != MaxTasks; ++I) { | |
| 147 | if (Buf[I].empty()) | |
| 148 | std::vector<StringRef> ret; | |
| 149 | for (unsigned i = 0; i != maxTasks; ++i) { | |
| 150 | if (buf[i].empty()) | |
| 148 | 151 | continue; |
| 149 | if (Config->SaveTemps) { | |
| 150 | if (I == 0) | |
| 151 | saveBuffer(Buf[I], Config->OutputFile + ".lto.o"); | |
| 152 | if (config->saveTemps) { | |
| 153 | if (i == 0) | |
| 154 | saveBuffer(buf[i], config->outputFile + ".lto.o"); | |
| 152 | 155 | else |
| 153 | saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.o"); | |
| 156 | saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.o"); | |
| 154 | 157 | } |
| 155 | Ret.emplace_back(Buf[I].data(), Buf[I].size()); | |
| 158 | ret.emplace_back(buf[i].data(), buf[i].size()); | |
| 156 | 159 | } |
| 157 | 160 | |
| 158 | for (std::unique_ptr<MemoryBuffer> &File : Files) | |
| 159 | if (File) | |
| 160 | Ret.push_back(File->getBuffer()); | |
| 161 | for (std::unique_ptr<MemoryBuffer> &file : files) | |
| 162 | if (file) | |
| 163 | ret.push_back(file->getBuffer()); | |
| 161 | 164 | |
| 162 | return Ret; | |
| 165 | return ret; | |
| 163 | 166 | } |
deps/lld/wasm/LTO.h+7-8| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- LTO.h ----------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -44,13 +43,13 @@ public: |
| 44 | 43 | BitcodeCompiler(); |
| 45 | 44 | ~BitcodeCompiler(); |
| 46 | 45 | |
| 47 | void add(BitcodeFile &F); | |
| 46 | void add(BitcodeFile &f); | |
| 48 | 47 | std::vector<StringRef> compile(); |
| 49 | 48 | |
| 50 | 49 | private: |
| 51 | std::unique_ptr<llvm::lto::LTO> LTOObj; | |
| 52 | std::vector<SmallString<0>> Buf; | |
| 53 | std::vector<std::unique_ptr<MemoryBuffer>> Files; | |
| 50 | std::unique_ptr<llvm::lto::LTO> ltoObj; | |
| 51 | std::vector<SmallString<0>> buf; | |
| 52 | std::vector<std::unique_ptr<MemoryBuffer>> files; | |
| 54 | 53 | }; |
| 55 | 54 | } // namespace wasm |
| 56 | 55 | } // namespace lld |
deps/lld/wasm/MarkLive.cpp+75-56| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- MarkLive.cpp -------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | // |
| ... | ... | @@ -33,48 +32,68 @@ using namespace llvm; |
| 33 | 32 | using namespace llvm::wasm; |
| 34 | 33 | |
| 35 | 34 | void lld::wasm::markLive() { |
| 36 | if (!Config->GcSections) | |
| 35 | if (!config->gcSections) | |
| 37 | 36 | return; |
| 38 | 37 | |
| 39 | 38 | LLVM_DEBUG(dbgs() << "markLive\n"); |
| 40 | SmallVector<InputChunk *, 256> Q; | |
| 39 | SmallVector<InputChunk *, 256> q; | |
| 41 | 40 | |
| 42 | auto Enqueue = [&](Symbol *Sym) { | |
| 43 | if (!Sym || Sym->isLive()) | |
| 41 | std::function<void(Symbol*)> enqueue = [&](Symbol *sym) { | |
| 42 | if (!sym || sym->isLive()) | |
| 44 | 43 | return; |
| 45 | LLVM_DEBUG(dbgs() << "markLive: " << Sym->getName() << "\n"); | |
| 46 | Sym->markLive(); | |
| 47 | if (InputChunk *Chunk = Sym->getChunk()) | |
| 48 | Q.push_back(Chunk); | |
| 44 | LLVM_DEBUG(dbgs() << "markLive: " << sym->getName() << "\n"); | |
| 45 | sym->markLive(); | |
| 46 | if (InputChunk *chunk = sym->getChunk()) | |
| 47 | q.push_back(chunk); | |
| 48 | ||
| 49 | // The ctor functions are all referenced by the synthetic callCtors | |
| 50 | // function. However, this function does not contain relocations so we | |
| 51 | // have to manually mark the ctors as live if callCtors itself is live. | |
| 52 | if (sym == WasmSym::callCtors) { | |
| 53 | if (config->passiveSegments) | |
| 54 | enqueue(WasmSym::initMemory); | |
| 55 | if (config->isPic) | |
| 56 | enqueue(WasmSym::applyRelocs); | |
| 57 | for (const ObjFile *obj : symtab->objectFiles) { | |
| 58 | const WasmLinkingData &l = obj->getWasmObj()->linkingData(); | |
| 59 | for (const WasmInitFunc &f : l.InitFunctions) { | |
| 60 | auto* initSym = obj->getFunctionSymbol(f.Symbol); | |
| 61 | if (!initSym->isDiscarded()) | |
| 62 | enqueue(initSym); | |
| 63 | } | |
| 64 | } | |
| 65 | } | |
| 49 | 66 | }; |
| 50 | 67 | |
| 51 | 68 | // Add GC root symbols. |
| 52 | if (!Config->Entry.empty()) | |
| 53 | Enqueue(Symtab->find(Config->Entry)); | |
| 54 | Enqueue(WasmSym::CallCtors); | |
| 69 | if (!config->entry.empty()) | |
| 70 | enqueue(symtab->find(config->entry)); | |
| 55 | 71 | |
| 56 | 72 | // We need to preserve any exported symbol |
| 57 | for (Symbol *Sym : Symtab->getSymbols()) | |
| 58 | if (Sym->isExported()) | |
| 59 | Enqueue(Sym); | |
| 60 | ||
| 61 | // The ctor functions are all used in the synthetic __wasm_call_ctors | |
| 62 | // function, but since this function is created in-place it doesn't contain | |
| 63 | // relocations which mean we have to manually mark the ctors. | |
| 64 | for (const ObjFile *Obj : Symtab->ObjectFiles) { | |
| 65 | const WasmLinkingData &L = Obj->getWasmObj()->linkingData(); | |
| 66 | for (const WasmInitFunc &F : L.InitFunctions) | |
| 67 | Enqueue(Obj->getFunctionSymbol(F.Symbol)); | |
| 73 | for (Symbol *sym : symtab->getSymbols()) | |
| 74 | if (sym->isExported()) | |
| 75 | enqueue(sym); | |
| 76 | ||
| 77 | // For relocatable output, we need to preserve all the ctor functions | |
| 78 | if (config->relocatable) { | |
| 79 | for (const ObjFile *obj : symtab->objectFiles) { | |
| 80 | const WasmLinkingData &l = obj->getWasmObj()->linkingData(); | |
| 81 | for (const WasmInitFunc &f : l.InitFunctions) | |
| 82 | enqueue(obj->getFunctionSymbol(f.Symbol)); | |
| 83 | } | |
| 68 | 84 | } |
| 69 | 85 | |
| 86 | if (config->isPic) | |
| 87 | enqueue(WasmSym::callCtors); | |
| 88 | ||
| 70 | 89 | // Follow relocations to mark all reachable chunks. |
| 71 | while (!Q.empty()) { | |
| 72 | InputChunk *C = Q.pop_back_val(); | |
| 90 | while (!q.empty()) { | |
| 91 | InputChunk *c = q.pop_back_val(); | |
| 73 | 92 | |
| 74 | for (const WasmRelocation Reloc : C->getRelocations()) { | |
| 75 | if (Reloc.Type == R_WEBASSEMBLY_TYPE_INDEX_LEB) | |
| 93 | for (const WasmRelocation reloc : c->getRelocations()) { | |
| 94 | if (reloc.Type == R_WASM_TYPE_INDEX_LEB) | |
| 76 | 95 | continue; |
| 77 | Symbol *Sym = C->File->getSymbol(Reloc.Index); | |
| 96 | Symbol *sym = c->file->getSymbol(reloc.Index); | |
| 78 | 97 | |
| 79 | 98 | // If the function has been assigned the special index zero in the table, |
| 80 | 99 | // the relocation doesn't pull in the function body, since the function |
| ... | ... | @@ -83,38 +102,38 @@ void lld::wasm::markLive() { |
| 83 | 102 | // zero is only reachable via "call", not via "call_indirect". The stub |
| 84 | 103 | // functions used for weak-undefined symbols have this behaviour (compare |
| 85 | 104 | // equal to null pointer, only reachable via direct call). |
| 86 | if (Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_SLEB || | |
| 87 | Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_I32) { | |
| 88 | auto *FuncSym = cast<FunctionSymbol>(Sym); | |
| 89 | if (FuncSym->hasTableIndex() && FuncSym->getTableIndex() == 0) | |
| 105 | if (reloc.Type == R_WASM_TABLE_INDEX_SLEB || | |
| 106 | reloc.Type == R_WASM_TABLE_INDEX_I32) { | |
| 107 | auto *funcSym = cast<FunctionSymbol>(sym); | |
| 108 | if (funcSym->hasTableIndex() && funcSym->getTableIndex() == 0) | |
| 90 | 109 | continue; |
| 91 | 110 | } |
| 92 | 111 | |
| 93 | Enqueue(Sym); | |
| 112 | enqueue(sym); | |
| 94 | 113 | } |
| 95 | 114 | } |
| 96 | 115 | |
| 97 | 116 | // Report garbage-collected sections. |
| 98 | if (Config->PrintGcSections) { | |
| 99 | for (const ObjFile *Obj : Symtab->ObjectFiles) { | |
| 100 | for (InputChunk *C : Obj->Functions) | |
| 101 | if (!C->Live) | |
| 102 | message("removing unused section " + toString(C)); | |
| 103 | for (InputChunk *C : Obj->Segments) | |
| 104 | if (!C->Live) | |
| 105 | message("removing unused section " + toString(C)); | |
| 106 | for (InputGlobal *G : Obj->Globals) | |
| 107 | if (!G->Live) | |
| 108 | message("removing unused section " + toString(G)); | |
| 109 | for (InputEvent *E : Obj->Events) | |
| 110 | if (!E->Live) | |
| 111 | message("removing unused section " + toString(E)); | |
| 117 | if (config->printGcSections) { | |
| 118 | for (const ObjFile *obj : symtab->objectFiles) { | |
| 119 | for (InputChunk *c : obj->functions) | |
| 120 | if (!c->live) | |
| 121 | message("removing unused section " + toString(c)); | |
| 122 | for (InputChunk *c : obj->segments) | |
| 123 | if (!c->live) | |
| 124 | message("removing unused section " + toString(c)); | |
| 125 | for (InputGlobal *g : obj->globals) | |
| 126 | if (!g->live) | |
| 127 | message("removing unused section " + toString(g)); | |
| 128 | for (InputEvent *e : obj->events) | |
| 129 | if (!e->live) | |
| 130 | message("removing unused section " + toString(e)); | |
| 112 | 131 | } |
| 113 | for (InputChunk *C : Symtab->SyntheticFunctions) | |
| 114 | if (!C->Live) | |
| 115 | message("removing unused section " + toString(C)); | |
| 116 | for (InputGlobal *G : Symtab->SyntheticGlobals) | |
| 117 | if (!G->Live) | |
| 118 | message("removing unused section " + toString(G)); | |
| 132 | for (InputChunk *c : symtab->syntheticFunctions) | |
| 133 | if (!c->live) | |
| 134 | message("removing unused section " + toString(c)); | |
| 135 | for (InputGlobal *g : symtab->syntheticGlobals) | |
| 136 | if (!g->live) | |
| 137 | message("removing unused section " + toString(g)); | |
| 119 | 138 | } |
| 120 | 139 | } |
deps/lld/wasm/MarkLive.h+3-4| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- MarkLive.h -----------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 |
deps/lld/wasm/Options.td+26| ... | ... | @@ -31,6 +31,8 @@ defm demangle: B<"demangle", |
| 31 | 31 | "Demangle symbol names", |
| 32 | 32 | "Do not demangle symbol names">; |
| 33 | 33 | |
| 34 | def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">; | |
| 35 | ||
| 34 | 36 | defm export_dynamic: B<"export-dynamic", |
| 35 | 37 | "Put symbols in the dynamic symbol table", |
| 36 | 38 | "Do not put symbols in the dynamic symbol table (default)">; |
| ... | ... | @@ -85,6 +87,8 @@ defm print_gc_sections: B<"print-gc-sections", |
| 85 | 87 | |
| 86 | 88 | def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">; |
| 87 | 89 | |
| 90 | defm reproduce: Eq<"reproduce", "Dump linker invocation and input files for debugging">; | |
| 91 | ||
| 88 | 92 | def shared: F<"shared">, HelpText<"Build a shared object">; |
| 89 | 93 | |
| 90 | 94 | def strip_all: F<"strip-all">, HelpText<"Strip all symbols">; |
| ... | ... | @@ -93,6 +97,10 @@ def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">; |
| 93 | 97 | |
| 94 | 98 | def threads: F<"threads">, HelpText<"Run the linker multi-threaded">; |
| 95 | 99 | |
| 100 | def trace: F<"trace">, HelpText<"Print the names of the input files">; | |
| 101 | ||
| 102 | defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">; | |
| 103 | ||
| 96 | 104 | defm undefined: Eq<"undefined", "Force undefined symbol during linking">; |
| 97 | 105 | |
| 98 | 106 | def v: Flag<["-"], "v">, HelpText<"Display the version number">; |
| ... | ... | @@ -104,6 +112,9 @@ def version: F<"version">, HelpText<"Display the version number and exit">; |
| 104 | 112 | def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">, |
| 105 | 113 | HelpText<"Linker option extensions">; |
| 106 | 114 | |
| 115 | defm wrap: Eq<"wrap", "Use wrapper functions for symbol">, | |
| 116 | MetaVarName<"<symbol>=<symbol>">; | |
| 117 | ||
| 107 | 118 | // The follow flags are unique to wasm |
| 108 | 119 | |
| 109 | 120 | def allow_undefined: F<"allow-undefined">, |
| ... | ... | @@ -132,6 +143,12 @@ def import_memory: F<"import-memory">, |
| 132 | 143 | def shared_memory: F<"shared-memory">, |
| 133 | 144 | HelpText<"Use shared linear memory">; |
| 134 | 145 | |
| 146 | def active_segments: F<"active-segments">, | |
| 147 | HelpText<"Force segments to be active (default with unshared memory)">; | |
| 148 | ||
| 149 | def passive_segments: F<"passive-segments">, | |
| 150 | HelpText<"Force segments to be passive (default with shared memory)">; | |
| 151 | ||
| 135 | 152 | def import_table: F<"import-table">, |
| 136 | 153 | HelpText<"Import function table from the environment">; |
| 137 | 154 | |
| ... | ... | @@ -151,6 +168,13 @@ defm whole_archive: B<"whole-archive", |
| 151 | 168 | "Force load of all members in a static library", |
| 152 | 169 | "Do not force load of all members in a static library (default)">; |
| 153 | 170 | |
| 171 | defm check_features: B<"check-features", | |
| 172 | "Check feature compatibility of linked objects (default)", | |
| 173 | "Ignore feature compatibility of linked objects">; | |
| 174 | ||
| 175 | def features: CommaJoined<["--", "-"], "features=">, | |
| 176 | HelpText<"Comma-separated used features, inferred from input objects by default.">; | |
| 177 | ||
| 154 | 178 | // Aliases |
| 155 | 179 | def: JoinedOrSeparate<["-"], "e">, Alias<entry>; |
| 156 | 180 | def: J<"entry=">, Alias<entry>; |
| ... | ... | @@ -160,6 +184,8 @@ def: Flag<["-"], "m">, Alias<max_memory>; |
| 160 | 184 | def: Flag<["-"], "r">, Alias<relocatable>; |
| 161 | 185 | def: Flag<["-"], "s">, Alias<strip_all>, HelpText<"Alias for --strip-all">; |
| 162 | 186 | def: Flag<["-"], "S">, Alias<strip_debug>, HelpText<"Alias for --strip-debug">; |
| 187 | def: Flag<["-"], "t">, Alias<trace>, HelpText<"Alias for --trace">; | |
| 188 | def: JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>, HelpText<"Alias for --trace-symbol">; | |
| 163 | 189 | def: JoinedOrSeparate<["-"], "u">, Alias<undefined>; |
| 164 | 190 | |
| 165 | 191 | // LTO-related options. |
deps/lld/wasm/OutputSections.cpp+136-135| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- OutputSections.cpp -------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -24,8 +23,8 @@ using namespace llvm::wasm; |
| 24 | 23 | using namespace lld; |
| 25 | 24 | using namespace lld::wasm; |
| 26 | 25 | |
| 27 | static StringRef sectionTypeToString(uint32_t SectionType) { | |
| 28 | switch (SectionType) { | |
| 26 | static StringRef sectionTypeToString(uint32_t sectionType) { | |
| 27 | switch (sectionType) { | |
| 29 | 28 | case WASM_SEC_CUSTOM: |
| 30 | 29 | return "CUSTOM"; |
| 31 | 30 | case WASM_SEC_TYPE: |
| ... | ... | @@ -52,198 +51,200 @@ static StringRef sectionTypeToString(uint32_t SectionType) { |
| 52 | 51 | return "CODE"; |
| 53 | 52 | case WASM_SEC_DATA: |
| 54 | 53 | return "DATA"; |
| 54 | case WASM_SEC_DATACOUNT: | |
| 55 | return "DATACOUNT"; | |
| 55 | 56 | default: |
| 56 | 57 | fatal("invalid section type"); |
| 57 | 58 | } |
| 58 | 59 | } |
| 59 | 60 | |
| 60 | 61 | // Returns a string, e.g. "FUNCTION(.text)". |
| 61 | std::string lld::toString(const OutputSection &Sec) { | |
| 62 | if (!Sec.Name.empty()) | |
| 63 | return (Sec.getSectionName() + "(" + Sec.Name + ")").str(); | |
| 64 | return Sec.getSectionName(); | |
| 62 | std::string lld::toString(const OutputSection &sec) { | |
| 63 | if (!sec.name.empty()) | |
| 64 | return (sec.getSectionName() + "(" + sec.name + ")").str(); | |
| 65 | return sec.getSectionName(); | |
| 65 | 66 | } |
| 66 | 67 | |
| 67 | 68 | StringRef OutputSection::getSectionName() const { |
| 68 | return sectionTypeToString(Type); | |
| 69 | return sectionTypeToString(type); | |
| 69 | 70 | } |
| 70 | 71 | |
| 71 | void OutputSection::createHeader(size_t BodySize) { | |
| 72 | raw_string_ostream OS(Header); | |
| 73 | debugWrite(OS.tell(), "section type [" + getSectionName() + "]"); | |
| 74 | encodeULEB128(Type, OS); | |
| 75 | writeUleb128(OS, BodySize, "section size"); | |
| 76 | OS.flush(); | |
| 77 | log("createHeader: " + toString(*this) + " body=" + Twine(BodySize) + | |
| 72 | void OutputSection::createHeader(size_t bodySize) { | |
| 73 | raw_string_ostream os(header); | |
| 74 | debugWrite(os.tell(), "section type [" + getSectionName() + "]"); | |
| 75 | encodeULEB128(type, os); | |
| 76 | writeUleb128(os, bodySize, "section size"); | |
| 77 | os.flush(); | |
| 78 | log("createHeader: " + toString(*this) + " body=" + Twine(bodySize) + | |
| 78 | 79 | " total=" + Twine(getSize())); |
| 79 | 80 | } |
| 80 | 81 | |
| 81 | CodeSection::CodeSection(ArrayRef<InputFunction *> Functions) | |
| 82 | : OutputSection(WASM_SEC_CODE), Functions(Functions) { | |
| 83 | assert(Functions.size() > 0); | |
| 84 | ||
| 85 | raw_string_ostream OS(CodeSectionHeader); | |
| 86 | writeUleb128(OS, Functions.size(), "function count"); | |
| 87 | OS.flush(); | |
| 88 | BodySize = CodeSectionHeader.size(); | |
| 82 | void CodeSection::finalizeContents() { | |
| 83 | raw_string_ostream os(codeSectionHeader); | |
| 84 | writeUleb128(os, functions.size(), "function count"); | |
| 85 | os.flush(); | |
| 86 | bodySize = codeSectionHeader.size(); | |
| 89 | 87 | |
| 90 | for (InputFunction *Func : Functions) { | |
| 91 | Func->OutputOffset = BodySize; | |
| 92 | Func->calculateSize(); | |
| 93 | BodySize += Func->getSize(); | |
| 88 | for (InputFunction *func : functions) { | |
| 89 | func->outputOffset = bodySize; | |
| 90 | func->calculateSize(); | |
| 91 | bodySize += func->getSize(); | |
| 94 | 92 | } |
| 95 | 93 | |
| 96 | createHeader(BodySize); | |
| 94 | createHeader(bodySize); | |
| 97 | 95 | } |
| 98 | 96 | |
| 99 | void CodeSection::writeTo(uint8_t *Buf) { | |
| 97 | void CodeSection::writeTo(uint8_t *buf) { | |
| 100 | 98 | log("writing " + toString(*this)); |
| 101 | 99 | log(" size=" + Twine(getSize())); |
| 102 | log(" headersize=" + Twine(Header.size())); | |
| 103 | log(" codeheadersize=" + Twine(CodeSectionHeader.size())); | |
| 104 | Buf += Offset; | |
| 100 | log(" headersize=" + Twine(header.size())); | |
| 101 | log(" codeheadersize=" + Twine(codeSectionHeader.size())); | |
| 102 | buf += offset; | |
| 105 | 103 | |
| 106 | 104 | // Write section header |
| 107 | memcpy(Buf, Header.data(), Header.size()); | |
| 108 | Buf += Header.size(); | |
| 105 | memcpy(buf, header.data(), header.size()); | |
| 106 | buf += header.size(); | |
| 109 | 107 | |
| 110 | 108 | // Write code section headers |
| 111 | memcpy(Buf, CodeSectionHeader.data(), CodeSectionHeader.size()); | |
| 109 | memcpy(buf, codeSectionHeader.data(), codeSectionHeader.size()); | |
| 112 | 110 | |
| 113 | 111 | // Write code section bodies |
| 114 | for (const InputChunk *Chunk : Functions) | |
| 115 | Chunk->writeTo(Buf); | |
| 116 | } | |
| 117 | ||
| 118 | uint32_t CodeSection::numRelocations() const { | |
| 119 | uint32_t Count = 0; | |
| 120 | for (const InputChunk *Func : Functions) | |
| 121 | Count += Func->NumRelocations(); | |
| 122 | return Count; | |
| 123 | } | |
| 124 | ||
| 125 | void CodeSection::writeRelocations(raw_ostream &OS) const { | |
| 126 | for (const InputChunk *C : Functions) | |
| 127 | C->writeRelocations(OS); | |
| 128 | } | |
| 129 | ||
| 130 | DataSection::DataSection(ArrayRef<OutputSegment *> Segments) | |
| 131 | : OutputSection(WASM_SEC_DATA), Segments(Segments) { | |
| 132 | raw_string_ostream OS(DataSectionHeader); | |
| 133 | ||
| 134 | writeUleb128(OS, Segments.size(), "data segment count"); | |
| 135 | OS.flush(); | |
| 136 | BodySize = DataSectionHeader.size(); | |
| 137 | ||
| 138 | for (OutputSegment *Segment : Segments) { | |
| 139 | raw_string_ostream OS(Segment->Header); | |
| 140 | writeUleb128(OS, 0, "memory index"); | |
| 141 | WasmInitExpr InitExpr; | |
| 142 | if (Config->Pic) { | |
| 143 | assert(Segments.size() <= 1 && | |
| 144 | "Currenly only a single data segment is supported in PIC mode"); | |
| 145 | InitExpr.Opcode = WASM_OPCODE_GLOBAL_GET; | |
| 146 | InitExpr.Value.Global = WasmSym::MemoryBase->getGlobalIndex(); | |
| 147 | } else { | |
| 148 | InitExpr.Opcode = WASM_OPCODE_I32_CONST; | |
| 149 | InitExpr.Value.Int32 = Segment->StartVA; | |
| 112 | for (const InputChunk *chunk : functions) | |
| 113 | chunk->writeTo(buf); | |
| 114 | } | |
| 115 | ||
| 116 | uint32_t CodeSection::getNumRelocations() const { | |
| 117 | uint32_t count = 0; | |
| 118 | for (const InputChunk *func : functions) | |
| 119 | count += func->getNumRelocations(); | |
| 120 | return count; | |
| 121 | } | |
| 122 | ||
| 123 | void CodeSection::writeRelocations(raw_ostream &os) const { | |
| 124 | for (const InputChunk *c : functions) | |
| 125 | c->writeRelocations(os); | |
| 126 | } | |
| 127 | ||
| 128 | void DataSection::finalizeContents() { | |
| 129 | raw_string_ostream os(dataSectionHeader); | |
| 130 | ||
| 131 | writeUleb128(os, segments.size(), "data segment count"); | |
| 132 | os.flush(); | |
| 133 | bodySize = dataSectionHeader.size(); | |
| 134 | ||
| 135 | assert((!config->isPic || segments.size() <= 1) && | |
| 136 | "Currenly only a single data segment is supported in PIC mode"); | |
| 137 | ||
| 138 | for (OutputSegment *segment : segments) { | |
| 139 | raw_string_ostream os(segment->header); | |
| 140 | writeUleb128(os, segment->initFlags, "init flags"); | |
| 141 | if (segment->initFlags & WASM_SEGMENT_HAS_MEMINDEX) | |
| 142 | writeUleb128(os, 0, "memory index"); | |
| 143 | if ((segment->initFlags & WASM_SEGMENT_IS_PASSIVE) == 0) { | |
| 144 | WasmInitExpr initExpr; | |
| 145 | if (config->isPic) { | |
| 146 | initExpr.Opcode = WASM_OPCODE_GLOBAL_GET; | |
| 147 | initExpr.Value.Global = WasmSym::memoryBase->getGlobalIndex(); | |
| 148 | } else { | |
| 149 | initExpr.Opcode = WASM_OPCODE_I32_CONST; | |
| 150 | initExpr.Value.Int32 = segment->startVA; | |
| 151 | } | |
| 152 | writeInitExpr(os, initExpr); | |
| 150 | 153 | } |
| 151 | writeInitExpr(OS, InitExpr); | |
| 152 | writeUleb128(OS, Segment->Size, "segment size"); | |
| 153 | OS.flush(); | |
| 154 | writeUleb128(os, segment->size, "segment size"); | |
| 155 | os.flush(); | |
| 154 | 156 | |
| 155 | Segment->SectionOffset = BodySize; | |
| 156 | BodySize += Segment->Header.size() + Segment->Size; | |
| 157 | log("Data segment: size=" + Twine(Segment->Size)); | |
| 157 | segment->sectionOffset = bodySize; | |
| 158 | bodySize += segment->header.size() + segment->size; | |
| 159 | log("Data segment: size=" + Twine(segment->size) + ", startVA=" + | |
| 160 | Twine::utohexstr(segment->startVA) + ", name=" + segment->name); | |
| 158 | 161 | |
| 159 | for (InputSegment *InputSeg : Segment->InputSegments) | |
| 160 | InputSeg->OutputOffset = Segment->SectionOffset + Segment->Header.size() + | |
| 161 | InputSeg->OutputSegmentOffset; | |
| 162 | for (InputSegment *inputSeg : segment->inputSegments) | |
| 163 | inputSeg->outputOffset = segment->sectionOffset + segment->header.size() + | |
| 164 | inputSeg->outputSegmentOffset; | |
| 162 | 165 | } |
| 163 | 166 | |
| 164 | createHeader(BodySize); | |
| 167 | createHeader(bodySize); | |
| 165 | 168 | } |
| 166 | 169 | |
| 167 | void DataSection::writeTo(uint8_t *Buf) { | |
| 170 | void DataSection::writeTo(uint8_t *buf) { | |
| 168 | 171 | log("writing " + toString(*this) + " size=" + Twine(getSize()) + |
| 169 | " body=" + Twine(BodySize)); | |
| 170 | Buf += Offset; | |
| 172 | " body=" + Twine(bodySize)); | |
| 173 | buf += offset; | |
| 171 | 174 | |
| 172 | 175 | // Write section header |
| 173 | memcpy(Buf, Header.data(), Header.size()); | |
| 174 | Buf += Header.size(); | |
| 176 | memcpy(buf, header.data(), header.size()); | |
| 177 | buf += header.size(); | |
| 175 | 178 | |
| 176 | 179 | // Write data section headers |
| 177 | memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size()); | |
| 180 | memcpy(buf, dataSectionHeader.data(), dataSectionHeader.size()); | |
| 178 | 181 | |
| 179 | for (const OutputSegment *Segment : Segments) { | |
| 182 | for (const OutputSegment *segment : segments) { | |
| 180 | 183 | // Write data segment header |
| 181 | uint8_t *SegStart = Buf + Segment->SectionOffset; | |
| 182 | memcpy(SegStart, Segment->Header.data(), Segment->Header.size()); | |
| 184 | uint8_t *segStart = buf + segment->sectionOffset; | |
| 185 | memcpy(segStart, segment->header.data(), segment->header.size()); | |
| 183 | 186 | |
| 184 | 187 | // Write segment data payload |
| 185 | for (const InputChunk *Chunk : Segment->InputSegments) | |
| 186 | Chunk->writeTo(Buf); | |
| 188 | for (const InputChunk *chunk : segment->inputSegments) | |
| 189 | chunk->writeTo(buf); | |
| 187 | 190 | } |
| 188 | 191 | } |
| 189 | 192 | |
| 190 | uint32_t DataSection::numRelocations() const { | |
| 191 | uint32_t Count = 0; | |
| 192 | for (const OutputSegment *Seg : Segments) | |
| 193 | for (const InputChunk *InputSeg : Seg->InputSegments) | |
| 194 | Count += InputSeg->NumRelocations(); | |
| 195 | return Count; | |
| 193 | uint32_t DataSection::getNumRelocations() const { | |
| 194 | uint32_t count = 0; | |
| 195 | for (const OutputSegment *seg : segments) | |
| 196 | for (const InputChunk *inputSeg : seg->inputSegments) | |
| 197 | count += inputSeg->getNumRelocations(); | |
| 198 | return count; | |
| 196 | 199 | } |
| 197 | 200 | |
| 198 | void DataSection::writeRelocations(raw_ostream &OS) const { | |
| 199 | for (const OutputSegment *Seg : Segments) | |
| 200 | for (const InputChunk *C : Seg->InputSegments) | |
| 201 | C->writeRelocations(OS); | |
| 201 | void DataSection::writeRelocations(raw_ostream &os) const { | |
| 202 | for (const OutputSegment *seg : segments) | |
| 203 | for (const InputChunk *c : seg->inputSegments) | |
| 204 | c->writeRelocations(os); | |
| 202 | 205 | } |
| 203 | 206 | |
| 204 | CustomSection::CustomSection(std::string Name, | |
| 205 | ArrayRef<InputSection *> InputSections) | |
| 206 | : OutputSection(WASM_SEC_CUSTOM, Name), PayloadSize(0), | |
| 207 | InputSections(InputSections) { | |
| 208 | raw_string_ostream OS(NameData); | |
| 209 | encodeULEB128(Name.size(), OS); | |
| 210 | OS << Name; | |
| 211 | OS.flush(); | |
| 207 | void CustomSection::finalizeContents() { | |
| 208 | raw_string_ostream os(nameData); | |
| 209 | encodeULEB128(name.size(), os); | |
| 210 | os << name; | |
| 211 | os.flush(); | |
| 212 | 212 | |
| 213 | for (InputSection *Section : InputSections) { | |
| 214 | Section->OutputOffset = PayloadSize; | |
| 215 | PayloadSize += Section->getSize(); | |
| 213 | for (InputSection *section : inputSections) { | |
| 214 | section->outputOffset = payloadSize; | |
| 215 | section->outputSec = this; | |
| 216 | payloadSize += section->getSize(); | |
| 216 | 217 | } |
| 217 | 218 | |
| 218 | createHeader(PayloadSize + NameData.size()); | |
| 219 | createHeader(payloadSize + nameData.size()); | |
| 219 | 220 | } |
| 220 | 221 | |
| 221 | void CustomSection::writeTo(uint8_t *Buf) { | |
| 222 | void CustomSection::writeTo(uint8_t *buf) { | |
| 222 | 223 | log("writing " + toString(*this) + " size=" + Twine(getSize()) + |
| 223 | " chunks=" + Twine(InputSections.size())); | |
| 224 | " chunks=" + Twine(inputSections.size())); | |
| 224 | 225 | |
| 225 | assert(Offset); | |
| 226 | Buf += Offset; | |
| 226 | assert(offset); | |
| 227 | buf += offset; | |
| 227 | 228 | |
| 228 | 229 | // Write section header |
| 229 | memcpy(Buf, Header.data(), Header.size()); | |
| 230 | Buf += Header.size(); | |
| 231 | memcpy(Buf, NameData.data(), NameData.size()); | |
| 232 | Buf += NameData.size(); | |
| 230 | memcpy(buf, header.data(), header.size()); | |
| 231 | buf += header.size(); | |
| 232 | memcpy(buf, nameData.data(), nameData.size()); | |
| 233 | buf += nameData.size(); | |
| 233 | 234 | |
| 234 | 235 | // Write custom sections payload |
| 235 | for (const InputSection *Section : InputSections) | |
| 236 | Section->writeTo(Buf); | |
| 236 | for (const InputSection *section : inputSections) | |
| 237 | section->writeTo(buf); | |
| 237 | 238 | } |
| 238 | 239 | |
| 239 | uint32_t CustomSection::numRelocations() const { | |
| 240 | uint32_t Count = 0; | |
| 241 | for (const InputSection *InputSect : InputSections) | |
| 242 | Count += InputSect->NumRelocations(); | |
| 243 | return Count; | |
| 240 | uint32_t CustomSection::getNumRelocations() const { | |
| 241 | uint32_t count = 0; | |
| 242 | for (const InputSection *inputSect : inputSections) | |
| 243 | count += inputSect->getNumRelocations(); | |
| 244 | return count; | |
| 244 | 245 | } |
| 245 | 246 | |
| 246 | void CustomSection::writeRelocations(raw_ostream &OS) const { | |
| 247 | for (const InputSection *S : InputSections) | |
| 248 | S->writeRelocations(OS); | |
| 247 | void CustomSection::writeRelocations(raw_ostream &os) const { | |
| 248 | for (const InputSection *s : inputSections) | |
| 249 | s->writeRelocations(os); | |
| 249 | 250 | } |
deps/lld/wasm/OutputSections.h+56-73| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- OutputSections.h -----------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -21,7 +20,7 @@ namespace lld { |
| 21 | 20 | namespace wasm { |
| 22 | 21 | class OutputSection; |
| 23 | 22 | } |
| 24 | std::string toString(const wasm::OutputSection &Section); | |
| 23 | std::string toString(const wasm::OutputSection &section); | |
| 25 | 24 | |
| 26 | 25 | namespace wasm { |
| 27 | 26 | |
| ... | ... | @@ -29,86 +28,67 @@ class OutputSegment; |
| 29 | 28 | |
| 30 | 29 | class OutputSection { |
| 31 | 30 | public: |
| 32 | OutputSection(uint32_t Type, std::string Name = "") | |
| 33 | : Type(Type), Name(Name) {} | |
| 31 | OutputSection(uint32_t type, std::string name = "") | |
| 32 | : type(type), name(name) {} | |
| 34 | 33 | virtual ~OutputSection() = default; |
| 35 | 34 | |
| 36 | 35 | StringRef getSectionName() const; |
| 37 | void setOffset(size_t NewOffset) { | |
| 38 | log("setOffset: " + toString(*this) + ": " + Twine(NewOffset)); | |
| 39 | Offset = NewOffset; | |
| 36 | void setOffset(size_t newOffset) { | |
| 37 | log("setOffset: " + toString(*this) + ": " + Twine(newOffset)); | |
| 38 | offset = newOffset; | |
| 40 | 39 | } |
| 41 | void createHeader(size_t BodySize); | |
| 40 | void createHeader(size_t bodySize); | |
| 41 | virtual bool isNeeded() const { return true; } | |
| 42 | 42 | virtual size_t getSize() const = 0; |
| 43 | virtual void writeTo(uint8_t *Buf) = 0; | |
| 44 | virtual void finalizeContents() {} | |
| 45 | virtual uint32_t numRelocations() const { return 0; } | |
| 46 | virtual void writeRelocations(raw_ostream &OS) const {} | |
| 47 | ||
| 48 | std::string Header; | |
| 49 | uint32_t Type; | |
| 50 | std::string Name; | |
| 51 | ||
| 52 | protected: | |
| 53 | size_t Offset = 0; | |
| 54 | }; | |
| 55 | ||
| 56 | class SyntheticSection : public OutputSection { | |
| 57 | public: | |
| 58 | SyntheticSection(uint32_t Type, std::string Name = "") | |
| 59 | : OutputSection(Type, Name), BodyOutputStream(Body) { | |
| 60 | if (!Name.empty()) | |
| 61 | writeStr(BodyOutputStream, Name, "section name"); | |
| 62 | } | |
| 43 | virtual void writeTo(uint8_t *buf) = 0; | |
| 44 | virtual void finalizeContents() = 0; | |
| 45 | virtual uint32_t getNumRelocations() const { return 0; } | |
| 46 | virtual void writeRelocations(raw_ostream &os) const {} | |
| 63 | 47 | |
| 64 | void writeTo(uint8_t *Buf) override { | |
| 65 | assert(Offset); | |
| 66 | log("writing " + toString(*this)); | |
| 67 | memcpy(Buf + Offset, Header.data(), Header.size()); | |
| 68 | memcpy(Buf + Offset + Header.size(), Body.data(), Body.size()); | |
| 69 | } | |
| 70 | ||
| 71 | size_t getSize() const override { return Header.size() + Body.size(); } | |
| 72 | ||
| 73 | void finalizeContents() override { | |
| 74 | BodyOutputStream.flush(); | |
| 75 | createHeader(Body.size()); | |
| 76 | } | |
| 77 | ||
| 78 | raw_ostream &getStream() { return BodyOutputStream; } | |
| 79 | ||
| 80 | std::string Body; | |
| 48 | std::string header; | |
| 49 | uint32_t type; | |
| 50 | uint32_t sectionIndex = UINT32_MAX; | |
| 51 | std::string name; | |
| 52 | OutputSectionSymbol *sectionSym = nullptr; | |
| 81 | 53 | |
| 82 | 54 | protected: |
| 83 | llvm::raw_string_ostream BodyOutputStream; | |
| 55 | size_t offset = 0; | |
| 84 | 56 | }; |
| 85 | 57 | |
| 86 | 58 | class CodeSection : public OutputSection { |
| 87 | 59 | public: |
| 88 | explicit CodeSection(ArrayRef<InputFunction *> Functions); | |
| 89 | size_t getSize() const override { return Header.size() + BodySize; } | |
| 90 | void writeTo(uint8_t *Buf) override; | |
| 91 | uint32_t numRelocations() const override; | |
| 92 | void writeRelocations(raw_ostream &OS) const override; | |
| 60 | explicit CodeSection(ArrayRef<InputFunction *> functions) | |
| 61 | : OutputSection(llvm::wasm::WASM_SEC_CODE), functions(functions) {} | |
| 62 | ||
| 63 | size_t getSize() const override { return header.size() + bodySize; } | |
| 64 | void writeTo(uint8_t *buf) override; | |
| 65 | uint32_t getNumRelocations() const override; | |
| 66 | void writeRelocations(raw_ostream &os) const override; | |
| 67 | bool isNeeded() const override { return functions.size() > 0; } | |
| 68 | void finalizeContents() override; | |
| 93 | 69 | |
| 94 | 70 | protected: |
| 95 | ArrayRef<InputFunction *> Functions; | |
| 96 | std::string CodeSectionHeader; | |
| 97 | size_t BodySize = 0; | |
| 71 | ArrayRef<InputFunction *> functions; | |
| 72 | std::string codeSectionHeader; | |
| 73 | size_t bodySize = 0; | |
| 98 | 74 | }; |
| 99 | 75 | |
| 100 | 76 | class DataSection : public OutputSection { |
| 101 | 77 | public: |
| 102 | explicit DataSection(ArrayRef<OutputSegment *> Segments); | |
| 103 | size_t getSize() const override { return Header.size() + BodySize; } | |
| 104 | void writeTo(uint8_t *Buf) override; | |
| 105 | uint32_t numRelocations() const override; | |
| 106 | void writeRelocations(raw_ostream &OS) const override; | |
| 78 | explicit DataSection(ArrayRef<OutputSegment *> segments) | |
| 79 | : OutputSection(llvm::wasm::WASM_SEC_DATA), segments(segments) {} | |
| 80 | ||
| 81 | size_t getSize() const override { return header.size() + bodySize; } | |
| 82 | void writeTo(uint8_t *buf) override; | |
| 83 | uint32_t getNumRelocations() const override; | |
| 84 | void writeRelocations(raw_ostream &os) const override; | |
| 85 | bool isNeeded() const override { return segments.size() > 0; } | |
| 86 | void finalizeContents() override; | |
| 107 | 87 | |
| 108 | 88 | protected: |
| 109 | ArrayRef<OutputSegment *> Segments; | |
| 110 | std::string DataSectionHeader; | |
| 111 | size_t BodySize = 0; | |
| 89 | ArrayRef<OutputSegment *> segments; | |
| 90 | std::string dataSectionHeader; | |
| 91 | size_t bodySize = 0; | |
| 112 | 92 | }; |
| 113 | 93 | |
| 114 | 94 | // Represents a custom section in the output file. Wasm custom sections are |
| ... | ... | @@ -120,18 +100,21 @@ protected: |
| 120 | 100 | // separately and are instead synthesized by the linker. |
| 121 | 101 | class CustomSection : public OutputSection { |
| 122 | 102 | public: |
| 123 | CustomSection(std::string Name, ArrayRef<InputSection *> InputSections); | |
| 103 | CustomSection(std::string name, ArrayRef<InputSection *> inputSections) | |
| 104 | : OutputSection(llvm::wasm::WASM_SEC_CUSTOM, name), | |
| 105 | inputSections(inputSections) {} | |
| 124 | 106 | size_t getSize() const override { |
| 125 | return Header.size() + NameData.size() + PayloadSize; | |
| 107 | return header.size() + nameData.size() + payloadSize; | |
| 126 | 108 | } |
| 127 | void writeTo(uint8_t *Buf) override; | |
| 128 | uint32_t numRelocations() const override; | |
| 129 | void writeRelocations(raw_ostream &OS) const override; | |
| 109 | void writeTo(uint8_t *buf) override; | |
| 110 | uint32_t getNumRelocations() const override; | |
| 111 | void writeRelocations(raw_ostream &os) const override; | |
| 112 | void finalizeContents() override; | |
| 130 | 113 | |
| 131 | 114 | protected: |
| 132 | size_t PayloadSize; | |
| 133 | ArrayRef<InputSection *> InputSections; | |
| 134 | std::string NameData; | |
| 115 | size_t payloadSize = 0; | |
| 116 | ArrayRef<InputSection *> inputSections; | |
| 117 | std::string nameData; | |
| 135 | 118 | }; |
| 136 | 119 | |
| 137 | 120 | } // namespace wasm |
deps/lld/wasm/OutputSegment.h+21-21| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- OutputSegment.h ------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -21,29 +20,30 @@ class InputSegment; |
| 21 | 20 | |
| 22 | 21 | class OutputSegment { |
| 23 | 22 | public: |
| 24 | OutputSegment(StringRef N, uint32_t Index) : Name(N), Index(Index) {} | |
| 25 | ||
| 26 | void addInputSegment(InputSegment *InSeg) { | |
| 27 | Alignment = std::max(Alignment, InSeg->getAlignment()); | |
| 28 | InputSegments.push_back(InSeg); | |
| 29 | Size = llvm::alignTo(Size, 1 << InSeg->getAlignment()); | |
| 30 | InSeg->OutputSeg = this; | |
| 31 | InSeg->OutputSegmentOffset = Size; | |
| 32 | Size += InSeg->getSize(); | |
| 23 | OutputSegment(StringRef n, uint32_t index) : name(n), index(index) {} | |
| 24 | ||
| 25 | void addInputSegment(InputSegment *inSeg) { | |
| 26 | alignment = std::max(alignment, inSeg->getAlignment()); | |
| 27 | inputSegments.push_back(inSeg); | |
| 28 | size = llvm::alignTo(size, 1ULL << inSeg->getAlignment()); | |
| 29 | inSeg->outputSeg = this; | |
| 30 | inSeg->outputSegmentOffset = size; | |
| 31 | size += inSeg->getSize(); | |
| 33 | 32 | } |
| 34 | 33 | |
| 35 | StringRef Name; | |
| 36 | const uint32_t Index; | |
| 37 | uint32_t SectionOffset = 0; | |
| 38 | uint32_t Alignment = 0; | |
| 39 | uint32_t StartVA = 0; | |
| 40 | std::vector<InputSegment *> InputSegments; | |
| 34 | StringRef name; | |
| 35 | const uint32_t index; | |
| 36 | uint32_t initFlags = 0; | |
| 37 | uint32_t sectionOffset = 0; | |
| 38 | uint32_t alignment = 0; | |
| 39 | uint32_t startVA = 0; | |
| 40 | std::vector<InputSegment *> inputSegments; | |
| 41 | 41 | |
| 42 | 42 | // Sum of the size of the all the input segments |
| 43 | uint32_t Size = 0; | |
| 43 | uint32_t size = 0; | |
| 44 | 44 | |
| 45 | 45 | // Segment header |
| 46 | std::string Header; | |
| 46 | std::string header; | |
| 47 | 47 | }; |
| 48 | 48 | |
| 49 | 49 | } // namespace wasm |
deps/lld/wasm/Relocations.cpp created+101| ... | ... | @@ -0,0 +1,101 @@ |
| 1 | //===- Relocations.cpp ----------------------------------------------------===// | |
| 2 | // | |
| 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 | |
| 6 | // | |
| 7 | //===----------------------------------------------------------------------===// | |
| 8 | ||
| 9 | #include "Relocations.h" | |
| 10 | ||
| 11 | #include "InputChunks.h" | |
| 12 | #include "SyntheticSections.h" | |
| 13 | ||
| 14 | using namespace llvm; | |
| 15 | using namespace llvm::wasm; | |
| 16 | ||
| 17 | using namespace lld; | |
| 18 | using namespace lld::wasm; | |
| 19 | ||
| 20 | static bool requiresGOTAccess(const Symbol *sym) { | |
| 21 | return config->isPic && !sym->isHidden() && !sym->isLocal(); | |
| 22 | } | |
| 23 | ||
| 24 | static bool allowUndefined(const Symbol* sym) { | |
| 25 | // Historically --allow-undefined doesn't work for data symbols since we don't | |
| 26 | // have any way to represent these as imports in the final binary. The idea | |
| 27 | // behind allowing undefined symbols is to allow importing these symbols from | |
| 28 | // the embedder and we can't do this for data symbols (at least not without | |
| 29 | // compiling with -fPIC) | |
| 30 | if (isa<DataSymbol>(sym)) | |
| 31 | return false; | |
| 32 | return (config->allowUndefined || | |
| 33 | config->allowUndefinedSymbols.count(sym->getName()) != 0); | |
| 34 | } | |
| 35 | ||
| 36 | static void reportUndefined(const Symbol* sym) { | |
| 37 | assert(sym->isUndefined()); | |
| 38 | assert(!sym->isWeak()); | |
| 39 | if (!allowUndefined(sym)) | |
| 40 | error(toString(sym->getFile()) + ": undefined symbol: " + toString(*sym)); | |
| 41 | } | |
| 42 | ||
| 43 | void lld::wasm::scanRelocations(InputChunk *chunk) { | |
| 44 | if (!chunk->live) | |
| 45 | return; | |
| 46 | ObjFile *file = chunk->file; | |
| 47 | ArrayRef<WasmSignature> types = file->getWasmObj()->types(); | |
| 48 | for (const WasmRelocation &reloc : chunk->getRelocations()) { | |
| 49 | if (reloc.Type == R_WASM_TYPE_INDEX_LEB) { | |
| 50 | // Mark target type as live | |
| 51 | file->typeMap[reloc.Index] = | |
| 52 | out.typeSec->registerType(types[reloc.Index]); | |
| 53 | file->typeIsUsed[reloc.Index] = true; | |
| 54 | continue; | |
| 55 | } | |
| 56 | ||
| 57 | // Other relocation types all have a corresponding symbol | |
| 58 | Symbol *sym = file->getSymbols()[reloc.Index]; | |
| 59 | ||
| 60 | switch (reloc.Type) { | |
| 61 | case R_WASM_TABLE_INDEX_I32: | |
| 62 | case R_WASM_TABLE_INDEX_SLEB: | |
| 63 | case R_WASM_TABLE_INDEX_REL_SLEB: | |
| 64 | if (requiresGOTAccess(sym)) | |
| 65 | break; | |
| 66 | out.elemSec->addEntry(cast<FunctionSymbol>(sym)); | |
| 67 | break; | |
| 68 | case R_WASM_GLOBAL_INDEX_LEB: | |
| 69 | if (!isa<GlobalSymbol>(sym)) | |
| 70 | out.importSec->addGOTEntry(sym); | |
| 71 | break; | |
| 72 | } | |
| 73 | ||
| 74 | if (config->isPic) { | |
| 75 | switch (reloc.Type) { | |
| 76 | case R_WASM_TABLE_INDEX_SLEB: | |
| 77 | case R_WASM_MEMORY_ADDR_SLEB: | |
| 78 | case R_WASM_MEMORY_ADDR_LEB: | |
| 79 | // Certain relocation types can't be used when building PIC output, | |
| 80 | // since they would require absolute symbol addresses at link time. | |
| 81 | error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) + | |
| 82 | " cannot be used against symbol " + toString(*sym) + | |
| 83 | "; recompile with -fPIC"); | |
| 84 | break; | |
| 85 | case R_WASM_TABLE_INDEX_I32: | |
| 86 | case R_WASM_MEMORY_ADDR_I32: | |
| 87 | // These relocation types are only present in the data section and | |
| 88 | // will be converted into code by `generateRelocationCode`. This code | |
| 89 | // requires the symbols to have GOT entires. | |
| 90 | if (requiresGOTAccess(sym)) | |
| 91 | out.importSec->addGOTEntry(sym); | |
| 92 | break; | |
| 93 | } | |
| 94 | } else { | |
| 95 | // Report undefined symbols | |
| 96 | if (sym->isUndefined() && !config->relocatable && !sym->isWeak()) | |
| 97 | reportUndefined(sym); | |
| 98 | } | |
| 99 | ||
| 100 | } | |
| 101 | } |
deps/lld/wasm/Relocations.h created+22| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | //===- Relocations.h -------------------------------------------*- C++ -*-===// | |
| 2 | // | |
| 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 | |
| 6 | // | |
| 7 | //===----------------------------------------------------------------------===// | |
| 8 | ||
| 9 | #ifndef LLD_WASM_RELOCATIONS_H | |
| 10 | #define LLD_WASM_RELOCATIONS_H | |
| 11 | ||
| 12 | namespace lld { | |
| 13 | namespace wasm { | |
| 14 | ||
| 15 | class InputChunk; | |
| 16 | ||
| 17 | void scanRelocations(InputChunk *chunk); | |
| 18 | ||
| 19 | } // namespace wasm | |
| 20 | } // namespace lld | |
| 21 | ||
| 22 | #endif |
deps/lld/wasm/SymbolTable.cpp+541-255| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- SymbolTable.cpp ----------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -25,17 +24,37 @@ using namespace llvm::object; |
| 25 | 24 | using namespace lld; |
| 26 | 25 | using namespace lld::wasm; |
| 27 | 26 | |
| 28 | SymbolTable *lld::wasm::Symtab; | |
| 27 | SymbolTable *lld::wasm::symtab; | |
| 29 | 28 | |
| 30 | void SymbolTable::addFile(InputFile *File) { | |
| 31 | log("Processing: " + toString(File)); | |
| 32 | File->parse(); | |
| 29 | void SymbolTable::addFile(InputFile *file) { | |
| 30 | log("Processing: " + toString(file)); | |
| 31 | ||
| 32 | // .a file | |
| 33 | if (auto *f = dyn_cast<ArchiveFile>(file)) { | |
| 34 | f->parse(); | |
| 35 | return; | |
| 36 | } | |
| 37 | ||
| 38 | // .so file | |
| 39 | if (auto *f = dyn_cast<SharedFile>(file)) { | |
| 40 | sharedFiles.push_back(f); | |
| 41 | return; | |
| 42 | } | |
| 43 | ||
| 44 | if (config->trace) | |
| 45 | message(toString(file)); | |
| 33 | 46 | |
| 34 | 47 | // LLVM bitcode file |
| 35 | if (auto *F = dyn_cast<BitcodeFile>(File)) | |
| 36 | BitcodeFiles.push_back(F); | |
| 37 | else if (auto *F = dyn_cast<ObjFile>(File)) | |
| 38 | ObjectFiles.push_back(F); | |
| 48 | if (auto *f = dyn_cast<BitcodeFile>(file)) { | |
| 49 | f->parse(); | |
| 50 | bitcodeFiles.push_back(f); | |
| 51 | return; | |
| 52 | } | |
| 53 | ||
| 54 | // Regular object file | |
| 55 | auto *f = cast<ObjFile>(file); | |
| 56 | f->parse(false); | |
| 57 | objectFiles.push_back(f); | |
| 39 | 58 | } |
| 40 | 59 | |
| 41 | 60 | // This function is where all the optimizations of link-time |
| ... | ... | @@ -46,353 +65,620 @@ void SymbolTable::addFile(InputFile *File) { |
| 46 | 65 | // Because all bitcode files that the program consists of are passed |
| 47 | 66 | // to the compiler at once, it can do whole-program optimization. |
| 48 | 67 | void SymbolTable::addCombinedLTOObject() { |
| 49 | if (BitcodeFiles.empty()) | |
| 68 | if (bitcodeFiles.empty()) | |
| 50 | 69 | return; |
| 51 | 70 | |
| 52 | 71 | // Compile bitcode files and replace bitcode symbols. |
| 53 | LTO.reset(new BitcodeCompiler); | |
| 54 | for (BitcodeFile *F : BitcodeFiles) | |
| 55 | LTO->add(*F); | |
| 56 | ||
| 57 | for (StringRef Filename : LTO->compile()) { | |
| 58 | auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp")); | |
| 59 | Obj->parse(); | |
| 60 | ObjectFiles.push_back(Obj); | |
| 72 | lto.reset(new BitcodeCompiler); | |
| 73 | for (BitcodeFile *f : bitcodeFiles) | |
| 74 | lto->add(*f); | |
| 75 | ||
| 76 | for (StringRef filename : lto->compile()) { | |
| 77 | auto *obj = make<ObjFile>(MemoryBufferRef(filename, "lto.tmp"), ""); | |
| 78 | obj->parse(true); | |
| 79 | objectFiles.push_back(obj); | |
| 61 | 80 | } |
| 62 | 81 | } |
| 63 | 82 | |
| 64 | void SymbolTable::reportRemainingUndefines() { | |
| 65 | for (Symbol *Sym : SymVector) { | |
| 66 | if (!Sym->isUndefined() || Sym->isWeak()) | |
| 67 | continue; | |
| 68 | if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0) | |
| 69 | continue; | |
| 70 | if (!Sym->IsUsedInRegularObj) | |
| 71 | continue; | |
| 72 | error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym)); | |
| 73 | } | |
| 83 | Symbol *SymbolTable::find(StringRef name) { | |
| 84 | auto it = symMap.find(CachedHashStringRef(name)); | |
| 85 | if (it == symMap.end() || it->second == -1) | |
| 86 | return nullptr; | |
| 87 | return symVector[it->second]; | |
| 74 | 88 | } |
| 75 | 89 | |
| 76 | Symbol *SymbolTable::find(StringRef Name) { | |
| 77 | return SymMap.lookup(CachedHashStringRef(Name)); | |
| 90 | void SymbolTable::replace(StringRef name, Symbol* sym) { | |
| 91 | auto it = symMap.find(CachedHashStringRef(name)); | |
| 92 | symVector[it->second] = sym; | |
| 78 | 93 | } |
| 79 | 94 | |
| 80 | std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, InputFile *File) { | |
| 81 | bool Inserted = false; | |
| 82 | Symbol *&Sym = SymMap[CachedHashStringRef(Name)]; | |
| 83 | if (!Sym) { | |
| 84 | Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); | |
| 85 | Sym->IsUsedInRegularObj = false; | |
| 86 | SymVector.emplace_back(Sym); | |
| 87 | Inserted = true; | |
| 95 | std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) { | |
| 96 | bool trace = false; | |
| 97 | auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()}); | |
| 98 | int &symIndex = p.first->second; | |
| 99 | bool isNew = p.second; | |
| 100 | if (symIndex == -1) { | |
| 101 | symIndex = symVector.size(); | |
| 102 | trace = true; | |
| 103 | isNew = true; | |
| 88 | 104 | } |
| 89 | if (!File || File->kind() == InputFile::ObjectKind) | |
| 90 | Sym->IsUsedInRegularObj = true; | |
| 91 | return {Sym, Inserted}; | |
| 92 | } | |
| 93 | 105 | |
| 94 | static void reportTypeError(const Symbol *Existing, const InputFile *File, | |
| 95 | llvm::wasm::WasmSymbolType Type) { | |
| 96 | error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " + | |
| 97 | toString(Existing->getWasmType()) + " in " + | |
| 98 | toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) + | |
| 99 | " in " + toString(File)); | |
| 106 | if (!isNew) | |
| 107 | return {symVector[symIndex], false}; | |
| 108 | ||
| 109 | Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); | |
| 110 | sym->isUsedInRegularObj = false; | |
| 111 | sym->canInline = true; | |
| 112 | sym->traced = trace; | |
| 113 | symVector.emplace_back(sym); | |
| 114 | return {sym, true}; | |
| 100 | 115 | } |
| 101 | 116 | |
| 102 | // Check the type of new symbol matches that of the symbol is replacing. | |
| 103 | // For functions this can also involve verifying that the signatures match. | |
| 104 | static void checkFunctionType(Symbol *Existing, const InputFile *File, | |
| 105 | const WasmSignature *NewSig) { | |
| 106 | auto ExistingFunction = dyn_cast<FunctionSymbol>(Existing); | |
| 107 | if (!ExistingFunction) { | |
| 108 | reportTypeError(Existing, File, WASM_SYMBOL_TYPE_FUNCTION); | |
| 109 | return; | |
| 110 | } | |
| 117 | std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, | |
| 118 | const InputFile *file) { | |
| 119 | Symbol *s; | |
| 120 | bool wasInserted; | |
| 121 | std::tie(s, wasInserted) = insertName(name); | |
| 111 | 122 | |
| 112 | if (!NewSig) | |
| 113 | return; | |
| 123 | if (!file || file->kind() == InputFile::ObjectKind) | |
| 124 | s->isUsedInRegularObj = true; | |
| 114 | 125 | |
| 115 | const WasmSignature *OldSig = ExistingFunction->Signature; | |
| 116 | if (!OldSig) { | |
| 117 | ExistingFunction->Signature = NewSig; | |
| 118 | return; | |
| 119 | } | |
| 126 | return {s, wasInserted}; | |
| 127 | } | |
| 120 | 128 | |
| 121 | if (*NewSig != *OldSig) | |
| 122 | warn("function signature mismatch: " + Existing->getName() + | |
| 123 | "\n>>> defined as " + toString(*OldSig) + " in " + | |
| 124 | toString(Existing->getFile()) + "\n>>> defined as " + | |
| 125 | toString(*NewSig) + " in " + toString(File)); | |
| 129 | static void reportTypeError(const Symbol *existing, const InputFile *file, | |
| 130 | llvm::wasm::WasmSymbolType type) { | |
| 131 | error("symbol type mismatch: " + toString(*existing) + "\n>>> defined as " + | |
| 132 | toString(existing->getWasmType()) + " in " + | |
| 133 | toString(existing->getFile()) + "\n>>> defined as " + toString(type) + | |
| 134 | " in " + toString(file)); | |
| 126 | 135 | } |
| 127 | 136 | |
| 128 | static void checkGlobalType(const Symbol *Existing, const InputFile *File, | |
| 129 | const WasmGlobalType *NewType) { | |
| 130 | if (!isa<GlobalSymbol>(Existing)) { | |
| 131 | reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL); | |
| 137 | // Check the type of new symbol matches that of the symbol is replacing. | |
| 138 | // Returns true if the function types match, false is there is a singature | |
| 139 | // mismatch. | |
| 140 | static bool signatureMatches(FunctionSymbol *existing, | |
| 141 | const WasmSignature *newSig) { | |
| 142 | const WasmSignature *oldSig = existing->signature; | |
| 143 | ||
| 144 | // If either function is missing a signature (this happend for bitcode | |
| 145 | // symbols) then assume they match. Any mismatch will be reported later | |
| 146 | // when the LTO objects are added. | |
| 147 | if (!newSig || !oldSig) | |
| 148 | return true; | |
| 149 | ||
| 150 | return *newSig == *oldSig; | |
| 151 | } | |
| 152 | ||
| 153 | static void checkGlobalType(const Symbol *existing, const InputFile *file, | |
| 154 | const WasmGlobalType *newType) { | |
| 155 | if (!isa<GlobalSymbol>(existing)) { | |
| 156 | reportTypeError(existing, file, WASM_SYMBOL_TYPE_GLOBAL); | |
| 132 | 157 | return; |
| 133 | 158 | } |
| 134 | 159 | |
| 135 | const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType(); | |
| 136 | if (*NewType != *OldType) { | |
| 137 | error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " + | |
| 138 | toString(*OldType) + " in " + toString(Existing->getFile()) + | |
| 139 | "\n>>> defined as " + toString(*NewType) + " in " + toString(File)); | |
| 160 | const WasmGlobalType *oldType = cast<GlobalSymbol>(existing)->getGlobalType(); | |
| 161 | if (*newType != *oldType) { | |
| 162 | error("Global type mismatch: " + existing->getName() + "\n>>> defined as " + | |
| 163 | toString(*oldType) + " in " + toString(existing->getFile()) + | |
| 164 | "\n>>> defined as " + toString(*newType) + " in " + toString(file)); | |
| 140 | 165 | } |
| 141 | 166 | } |
| 142 | 167 | |
| 143 | static void checkEventType(const Symbol *Existing, const InputFile *File, | |
| 144 | const WasmEventType *NewType, | |
| 145 | const WasmSignature *NewSig) { | |
| 146 | auto ExistingEvent = dyn_cast<EventSymbol>(Existing); | |
| 147 | if (!isa<EventSymbol>(Existing)) { | |
| 148 | reportTypeError(Existing, File, WASM_SYMBOL_TYPE_EVENT); | |
| 168 | static void checkEventType(const Symbol *existing, const InputFile *file, | |
| 169 | const WasmEventType *newType, | |
| 170 | const WasmSignature *newSig) { | |
| 171 | auto existingEvent = dyn_cast<EventSymbol>(existing); | |
| 172 | if (!isa<EventSymbol>(existing)) { | |
| 173 | reportTypeError(existing, file, WASM_SYMBOL_TYPE_EVENT); | |
| 149 | 174 | return; |
| 150 | 175 | } |
| 151 | 176 | |
| 152 | const WasmEventType *OldType = cast<EventSymbol>(Existing)->getEventType(); | |
| 153 | const WasmSignature *OldSig = ExistingEvent->Signature; | |
| 154 | if (NewType->Attribute != OldType->Attribute) | |
| 155 | error("Event type mismatch: " + Existing->getName() + "\n>>> defined as " + | |
| 156 | toString(*OldType) + " in " + toString(Existing->getFile()) + | |
| 157 | "\n>>> defined as " + toString(*NewType) + " in " + toString(File)); | |
| 158 | if (*NewSig != *OldSig) | |
| 159 | warn("Event signature mismatch: " + Existing->getName() + | |
| 160 | "\n>>> defined as " + toString(*OldSig) + " in " + | |
| 161 | toString(Existing->getFile()) + "\n>>> defined as " + | |
| 162 | toString(*NewSig) + " in " + toString(File)); | |
| 177 | const WasmEventType *oldType = cast<EventSymbol>(existing)->getEventType(); | |
| 178 | const WasmSignature *oldSig = existingEvent->signature; | |
| 179 | if (newType->Attribute != oldType->Attribute) | |
| 180 | error("Event type mismatch: " + existing->getName() + "\n>>> defined as " + | |
| 181 | toString(*oldType) + " in " + toString(existing->getFile()) + | |
| 182 | "\n>>> defined as " + toString(*newType) + " in " + toString(file)); | |
| 183 | if (*newSig != *oldSig) | |
| 184 | warn("Event signature mismatch: " + existing->getName() + | |
| 185 | "\n>>> defined as " + toString(*oldSig) + " in " + | |
| 186 | toString(existing->getFile()) + "\n>>> defined as " + | |
| 187 | toString(*newSig) + " in " + toString(file)); | |
| 188 | } | |
| 189 | ||
| 190 | static void checkDataType(const Symbol *existing, const InputFile *file) { | |
| 191 | if (!isa<DataSymbol>(existing)) | |
| 192 | reportTypeError(existing, file, WASM_SYMBOL_TYPE_DATA); | |
| 163 | 193 | } |
| 164 | 194 | |
| 165 | static void checkDataType(const Symbol *Existing, const InputFile *File) { | |
| 166 | if (!isa<DataSymbol>(Existing)) | |
| 167 | reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA); | |
| 195 | DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name, | |
| 196 | uint32_t flags, | |
| 197 | InputFunction *function) { | |
| 198 | LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << name << "\n"); | |
| 199 | assert(!find(name)); | |
| 200 | syntheticFunctions.emplace_back(function); | |
| 201 | return replaceSymbol<DefinedFunction>(insertName(name).first, name, | |
| 202 | flags, nullptr, function); | |
| 168 | 203 | } |
| 169 | 204 | |
| 170 | DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name, | |
| 171 | uint32_t Flags, | |
| 172 | InputFunction *Function) { | |
| 173 | LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n"); | |
| 174 | assert(!find(Name)); | |
| 175 | SyntheticFunctions.emplace_back(Function); | |
| 176 | return replaceSymbol<DefinedFunction>(insert(Name, nullptr).first, Name, | |
| 177 | Flags, nullptr, Function); | |
| 205 | // Adds an optional, linker generated, data symbols. The symbol will only be | |
| 206 | // added if there is an undefine reference to it, or if it is explictly exported | |
| 207 | // via the --export flag. Otherwise we don't add the symbol and return nullptr. | |
| 208 | DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name, uint32_t value, | |
| 209 | uint32_t flags) { | |
| 210 | Symbol *s = find(name); | |
| 211 | if (!s && (config->exportAll || config->exportedSymbols.count(name) != 0)) | |
| 212 | s = insertName(name).first; | |
| 213 | else if (!s || s->isDefined()) | |
| 214 | return nullptr; | |
| 215 | LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << name << "\n"); | |
| 216 | auto *rtn = replaceSymbol<DefinedData>(s, name, flags); | |
| 217 | rtn->setVirtualAddress(value); | |
| 218 | rtn->referenced = true; | |
| 219 | return rtn; | |
| 178 | 220 | } |
| 179 | 221 | |
| 180 | DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name, | |
| 181 | uint32_t Flags) { | |
| 182 | LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n"); | |
| 183 | assert(!find(Name)); | |
| 184 | return replaceSymbol<DefinedData>(insert(Name, nullptr).first, Name, Flags); | |
| 222 | DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name, | |
| 223 | uint32_t flags) { | |
| 224 | LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n"); | |
| 225 | assert(!find(name)); | |
| 226 | return replaceSymbol<DefinedData>(insertName(name).first, name, flags); | |
| 185 | 227 | } |
| 186 | 228 | |
| 187 | DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags, | |
| 188 | InputGlobal *Global) { | |
| 189 | LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global | |
| 229 | DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags, | |
| 230 | InputGlobal *global) { | |
| 231 | LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << name << " -> " << global | |
| 190 | 232 | << "\n"); |
| 191 | assert(!find(Name)); | |
| 192 | SyntheticGlobals.emplace_back(Global); | |
| 193 | return replaceSymbol<DefinedGlobal>(insert(Name, nullptr).first, Name, Flags, | |
| 194 | nullptr, Global); | |
| 233 | assert(!find(name)); | |
| 234 | syntheticGlobals.emplace_back(global); | |
| 235 | return replaceSymbol<DefinedGlobal>(insertName(name).first, name, flags, | |
| 236 | nullptr, global); | |
| 195 | 237 | } |
| 196 | 238 | |
| 197 | static bool shouldReplace(const Symbol *Existing, InputFile *NewFile, | |
| 198 | uint32_t NewFlags) { | |
| 239 | static bool shouldReplace(const Symbol *existing, InputFile *newFile, | |
| 240 | uint32_t newFlags) { | |
| 199 | 241 | // If existing symbol is undefined, replace it. |
| 200 | if (!Existing->isDefined()) { | |
| 242 | if (!existing->isDefined()) { | |
| 201 | 243 | LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: " |
| 202 | << Existing->getName() << "\n"); | |
| 244 | << existing->getName() << "\n"); | |
| 203 | 245 | return true; |
| 204 | 246 | } |
| 205 | 247 | |
| 206 | 248 | // Now we have two defined symbols. If the new one is weak, we can ignore it. |
| 207 | if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { | |
| 249 | if ((newFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { | |
| 208 | 250 | LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n"); |
| 209 | 251 | return false; |
| 210 | 252 | } |
| 211 | 253 | |
| 212 | 254 | // If the existing symbol is weak, we should replace it. |
| 213 | if (Existing->isWeak()) { | |
| 255 | if (existing->isWeak()) { | |
| 214 | 256 | LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n"); |
| 215 | 257 | return true; |
| 216 | 258 | } |
| 217 | 259 | |
| 218 | 260 | // Neither symbol is week. They conflict. |
| 219 | error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " + | |
| 220 | toString(Existing->getFile()) + "\n>>> defined in " + | |
| 221 | toString(NewFile)); | |
| 261 | error("duplicate symbol: " + toString(*existing) + "\n>>> defined in " + | |
| 262 | toString(existing->getFile()) + "\n>>> defined in " + | |
| 263 | toString(newFile)); | |
| 222 | 264 | return true; |
| 223 | 265 | } |
| 224 | 266 | |
| 225 | Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags, | |
| 226 | InputFile *File, | |
| 227 | InputFunction *Function) { | |
| 228 | LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " [" | |
| 229 | << (Function ? toString(Function->Signature) : "none") | |
| 267 | Symbol *SymbolTable::addDefinedFunction(StringRef name, uint32_t flags, | |
| 268 | InputFile *file, | |
| 269 | InputFunction *function) { | |
| 270 | LLVM_DEBUG(dbgs() << "addDefinedFunction: " << name << " [" | |
| 271 | << (function ? toString(function->signature) : "none") | |
| 230 | 272 | << "]\n"); |
| 231 | Symbol *S; | |
| 232 | bool WasInserted; | |
| 233 | std::tie(S, WasInserted) = insert(Name, File); | |
| 273 | Symbol *s; | |
| 274 | bool wasInserted; | |
| 275 | std::tie(s, wasInserted) = insert(name, file); | |
| 234 | 276 | |
| 235 | if (WasInserted || S->isLazy()) { | |
| 236 | replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function); | |
| 237 | return S; | |
| 277 | auto replaceSym = [&](Symbol *sym) { | |
| 278 | // If the new defined function doesn't have signture (i.e. bitcode | |
| 279 | // functions) but the old symbol does, then preserve the old signature | |
| 280 | const WasmSignature *oldSig = s->getSignature(); | |
| 281 | auto* newSym = replaceSymbol<DefinedFunction>(sym, name, flags, file, function); | |
| 282 | if (!newSym->signature) | |
| 283 | newSym->signature = oldSig; | |
| 284 | }; | |
| 285 | ||
| 286 | if (wasInserted || s->isLazy()) { | |
| 287 | replaceSym(s); | |
| 288 | return s; | |
| 238 | 289 | } |
| 239 | 290 | |
| 240 | if (Function) | |
| 241 | checkFunctionType(S, File, &Function->Signature); | |
| 291 | auto existingFunction = dyn_cast<FunctionSymbol>(s); | |
| 292 | if (!existingFunction) { | |
| 293 | reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); | |
| 294 | return s; | |
| 295 | } | |
| 242 | 296 | |
| 243 | if (shouldReplace(S, File, Flags)) { | |
| 244 | // If the new defined function doesn't have signture (i.e. bitcode | |
| 245 | // functions) but the old symbols does then preserve the old signature | |
| 246 | const WasmSignature *OldSig = nullptr; | |
| 247 | if (auto* F = dyn_cast<FunctionSymbol>(S)) | |
| 248 | OldSig = F->Signature; | |
| 249 | auto NewSym = replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function); | |
| 250 | if (!NewSym->Signature) | |
| 251 | NewSym->Signature = OldSig; | |
| 297 | bool checkSig = true; | |
| 298 | if (auto ud = dyn_cast<UndefinedFunction>(existingFunction)) | |
| 299 | checkSig = ud->isCalledDirectly; | |
| 300 | ||
| 301 | if (checkSig && function && !signatureMatches(existingFunction, &function->signature)) { | |
| 302 | Symbol* variant; | |
| 303 | if (getFunctionVariant(s, &function->signature, file, &variant)) | |
| 304 | // New variant, always replace | |
| 305 | replaceSym(variant); | |
| 306 | else if (shouldReplace(s, file, flags)) | |
| 307 | // Variant already exists, replace it after checking shouldReplace | |
| 308 | replaceSym(variant); | |
| 309 | ||
| 310 | // This variant we found take the place in the symbol table as the primary | |
| 311 | // variant. | |
| 312 | replace(name, variant); | |
| 313 | return variant; | |
| 252 | 314 | } |
| 253 | return S; | |
| 315 | ||
| 316 | // Existing function with matching signature. | |
| 317 | if (shouldReplace(s, file, flags)) | |
| 318 | replaceSym(s); | |
| 319 | ||
| 320 | return s; | |
| 254 | 321 | } |
| 255 | 322 | |
| 256 | Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags, | |
| 257 | InputFile *File, InputSegment *Segment, | |
| 258 | uint32_t Address, uint32_t Size) { | |
| 259 | LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address | |
| 323 | Symbol *SymbolTable::addDefinedData(StringRef name, uint32_t flags, | |
| 324 | InputFile *file, InputSegment *segment, | |
| 325 | uint32_t address, uint32_t size) { | |
| 326 | LLVM_DEBUG(dbgs() << "addDefinedData:" << name << " addr:" << address | |
| 260 | 327 | << "\n"); |
| 261 | Symbol *S; | |
| 262 | bool WasInserted; | |
| 263 | std::tie(S, WasInserted) = insert(Name, File); | |
| 328 | Symbol *s; | |
| 329 | bool wasInserted; | |
| 330 | std::tie(s, wasInserted) = insert(name, file); | |
| 331 | ||
| 332 | auto replaceSym = [&]() { | |
| 333 | replaceSymbol<DefinedData>(s, name, flags, file, segment, address, size); | |
| 334 | }; | |
| 264 | 335 | |
| 265 | if (WasInserted || S->isLazy()) { | |
| 266 | replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size); | |
| 267 | return S; | |
| 336 | if (wasInserted || s->isLazy()) { | |
| 337 | replaceSym(); | |
| 338 | return s; | |
| 268 | 339 | } |
| 269 | 340 | |
| 270 | checkDataType(S, File); | |
| 341 | checkDataType(s, file); | |
| 271 | 342 | |
| 272 | if (shouldReplace(S, File, Flags)) | |
| 273 | replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size); | |
| 274 | return S; | |
| 343 | if (shouldReplace(s, file, flags)) | |
| 344 | replaceSym(); | |
| 345 | return s; | |
| 275 | 346 | } |
| 276 | 347 | |
| 277 | Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags, | |
| 278 | InputFile *File, InputGlobal *Global) { | |
| 279 | LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n"); | |
| 348 | Symbol *SymbolTable::addDefinedGlobal(StringRef name, uint32_t flags, | |
| 349 | InputFile *file, InputGlobal *global) { | |
| 350 | LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << name << "\n"); | |
| 280 | 351 | |
| 281 | Symbol *S; | |
| 282 | bool WasInserted; | |
| 283 | std::tie(S, WasInserted) = insert(Name, File); | |
| 352 | Symbol *s; | |
| 353 | bool wasInserted; | |
| 354 | std::tie(s, wasInserted) = insert(name, file); | |
| 284 | 355 | |
| 285 | if (WasInserted || S->isLazy()) { | |
| 286 | replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global); | |
| 287 | return S; | |
| 356 | auto replaceSym = [&]() { | |
| 357 | replaceSymbol<DefinedGlobal>(s, name, flags, file, global); | |
| 358 | }; | |
| 359 | ||
| 360 | if (wasInserted || s->isLazy()) { | |
| 361 | replaceSym(); | |
| 362 | return s; | |
| 288 | 363 | } |
| 289 | 364 | |
| 290 | checkGlobalType(S, File, &Global->getType()); | |
| 365 | checkGlobalType(s, file, &global->getType()); | |
| 291 | 366 | |
| 292 | if (shouldReplace(S, File, Flags)) | |
| 293 | replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global); | |
| 294 | return S; | |
| 367 | if (shouldReplace(s, file, flags)) | |
| 368 | replaceSym(); | |
| 369 | return s; | |
| 295 | 370 | } |
| 296 | 371 | |
| 297 | Symbol *SymbolTable::addDefinedEvent(StringRef Name, uint32_t Flags, | |
| 298 | InputFile *File, InputEvent *Event) { | |
| 299 | LLVM_DEBUG(dbgs() << "addDefinedEvent:" << Name << "\n"); | |
| 372 | Symbol *SymbolTable::addDefinedEvent(StringRef name, uint32_t flags, | |
| 373 | InputFile *file, InputEvent *event) { | |
| 374 | LLVM_DEBUG(dbgs() << "addDefinedEvent:" << name << "\n"); | |
| 375 | ||
| 376 | Symbol *s; | |
| 377 | bool wasInserted; | |
| 378 | std::tie(s, wasInserted) = insert(name, file); | |
| 300 | 379 | |
| 301 | Symbol *S; | |
| 302 | bool WasInserted; | |
| 303 | std::tie(S, WasInserted) = insert(Name, File); | |
| 380 | auto replaceSym = [&]() { | |
| 381 | replaceSymbol<DefinedEvent>(s, name, flags, file, event); | |
| 382 | }; | |
| 304 | 383 | |
| 305 | if (WasInserted || S->isLazy()) { | |
| 306 | replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event); | |
| 307 | return S; | |
| 384 | if (wasInserted || s->isLazy()) { | |
| 385 | replaceSym(); | |
| 386 | return s; | |
| 308 | 387 | } |
| 309 | 388 | |
| 310 | checkEventType(S, File, &Event->getType(), &Event->Signature); | |
| 389 | checkEventType(s, file, &event->getType(), &event->signature); | |
| 311 | 390 | |
| 312 | if (shouldReplace(S, File, Flags)) | |
| 313 | replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event); | |
| 314 | return S; | |
| 391 | if (shouldReplace(s, file, flags)) | |
| 392 | replaceSym(); | |
| 393 | return s; | |
| 315 | 394 | } |
| 316 | 395 | |
| 317 | Symbol *SymbolTable::addUndefinedFunction(StringRef Name, StringRef ImportName, | |
| 318 | StringRef ImportModule, | |
| 319 | uint32_t Flags, InputFile *File, | |
| 320 | const WasmSignature *Sig) { | |
| 321 | LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name << | |
| 322 | " [" << (Sig ? toString(*Sig) : "none") << "]\n"); | |
| 396 | Symbol *SymbolTable::addUndefinedFunction(StringRef name, StringRef importName, | |
| 397 | StringRef importModule, | |
| 398 | uint32_t flags, InputFile *file, | |
| 399 | const WasmSignature *sig, | |
| 400 | bool isCalledDirectly) { | |
| 401 | LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << name << " [" | |
| 402 | << (sig ? toString(*sig) : "none") | |
| 403 | << "] IsCalledDirectly:" << isCalledDirectly << "\n"); | |
| 404 | ||
| 405 | Symbol *s; | |
| 406 | bool wasInserted; | |
| 407 | std::tie(s, wasInserted) = insert(name, file); | |
| 408 | if (s->traced) | |
| 409 | printTraceSymbolUndefined(name, file); | |
| 410 | ||
| 411 | auto replaceSym = [&]() { | |
| 412 | replaceSymbol<UndefinedFunction>(s, name, importName, importModule, flags, | |
| 413 | file, sig, isCalledDirectly); | |
| 414 | }; | |
| 415 | ||
| 416 | if (wasInserted) | |
| 417 | replaceSym(); | |
| 418 | else if (auto *lazy = dyn_cast<LazySymbol>(s)) | |
| 419 | lazy->fetch(); | |
| 420 | else { | |
| 421 | auto existingFunction = dyn_cast<FunctionSymbol>(s); | |
| 422 | if (!existingFunction) { | |
| 423 | reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); | |
| 424 | return s; | |
| 425 | } | |
| 426 | if (!existingFunction->signature && sig) | |
| 427 | existingFunction->signature = sig; | |
| 428 | if (isCalledDirectly && !signatureMatches(existingFunction, sig)) | |
| 429 | if (getFunctionVariant(s, sig, file, &s)) | |
| 430 | replaceSym(); | |
| 431 | } | |
| 323 | 432 | |
| 324 | Symbol *S; | |
| 325 | bool WasInserted; | |
| 326 | std::tie(S, WasInserted) = insert(Name, File); | |
| 433 | return s; | |
| 434 | } | |
| 327 | 435 | |
| 328 | if (WasInserted) | |
| 329 | replaceSymbol<UndefinedFunction>(S, Name, ImportName, ImportModule, Flags, | |
| 330 | File, Sig); | |
| 331 | else if (auto *Lazy = dyn_cast<LazySymbol>(S)) | |
| 332 | Lazy->fetch(); | |
| 333 | else | |
| 334 | checkFunctionType(S, File, Sig); | |
| 436 | Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags, | |
| 437 | InputFile *file) { | |
| 438 | LLVM_DEBUG(dbgs() << "addUndefinedData: " << name << "\n"); | |
| 439 | ||
| 440 | Symbol *s; | |
| 441 | bool wasInserted; | |
| 442 | std::tie(s, wasInserted) = insert(name, file); | |
| 443 | if (s->traced) | |
| 444 | printTraceSymbolUndefined(name, file); | |
| 445 | ||
| 446 | if (wasInserted) | |
| 447 | replaceSymbol<UndefinedData>(s, name, flags, file); | |
| 448 | else if (auto *lazy = dyn_cast<LazySymbol>(s)) | |
| 449 | lazy->fetch(); | |
| 450 | else if (s->isDefined()) | |
| 451 | checkDataType(s, file); | |
| 452 | return s; | |
| 453 | } | |
| 335 | 454 | |
| 336 | return S; | |
| 455 | Symbol *SymbolTable::addUndefinedGlobal(StringRef name, StringRef importName, | |
| 456 | StringRef importModule, uint32_t flags, | |
| 457 | InputFile *file, | |
| 458 | const WasmGlobalType *type) { | |
| 459 | LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << name << "\n"); | |
| 460 | ||
| 461 | Symbol *s; | |
| 462 | bool wasInserted; | |
| 463 | std::tie(s, wasInserted) = insert(name, file); | |
| 464 | if (s->traced) | |
| 465 | printTraceSymbolUndefined(name, file); | |
| 466 | ||
| 467 | if (wasInserted) | |
| 468 | replaceSymbol<UndefinedGlobal>(s, name, importName, importModule, flags, | |
| 469 | file, type); | |
| 470 | else if (auto *lazy = dyn_cast<LazySymbol>(s)) | |
| 471 | lazy->fetch(); | |
| 472 | else if (s->isDefined()) | |
| 473 | checkGlobalType(s, file, type); | |
| 474 | return s; | |
| 337 | 475 | } |
| 338 | 476 | |
| 339 | Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags, | |
| 340 | InputFile *File) { | |
| 341 | LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n"); | |
| 477 | void SymbolTable::addLazy(ArchiveFile *file, const Archive::Symbol *sym) { | |
| 478 | LLVM_DEBUG(dbgs() << "addLazy: " << sym->getName() << "\n"); | |
| 479 | StringRef name = sym->getName(); | |
| 342 | 480 | |
| 343 | Symbol *S; | |
| 344 | bool WasInserted; | |
| 345 | std::tie(S, WasInserted) = insert(Name, File); | |
| 481 | Symbol *s; | |
| 482 | bool wasInserted; | |
| 483 | std::tie(s, wasInserted) = insertName(name); | |
| 346 | 484 | |
| 347 | if (WasInserted) | |
| 348 | replaceSymbol<UndefinedData>(S, Name, Flags, File); | |
| 349 | else if (auto *Lazy = dyn_cast<LazySymbol>(S)) | |
| 350 | Lazy->fetch(); | |
| 351 | else if (S->isDefined()) | |
| 352 | checkDataType(S, File); | |
| 353 | return S; | |
| 354 | } | |
| 485 | if (wasInserted) { | |
| 486 | replaceSymbol<LazySymbol>(s, name, 0, file, *sym); | |
| 487 | return; | |
| 488 | } | |
| 355 | 489 | |
| 356 | Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, StringRef ImportName, | |
| 357 | StringRef ImportModule, uint32_t Flags, | |
| 358 | InputFile *File, | |
| 359 | const WasmGlobalType *Type) { | |
| 360 | LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n"); | |
| 490 | if (!s->isUndefined()) | |
| 491 | return; | |
| 361 | 492 | |
| 362 | Symbol *S; | |
| 363 | bool WasInserted; | |
| 364 | std::tie(S, WasInserted) = insert(Name, File); | |
| 493 | // The existing symbol is undefined, load a new one from the archive, | |
| 494 | // unless the the existing symbol is weak in which case replace the undefined | |
| 495 | // symbols with a LazySymbol. | |
| 496 | if (s->isWeak()) { | |
| 497 | const WasmSignature *oldSig = nullptr; | |
| 498 | // In the case of an UndefinedFunction we need to preserve the expected | |
| 499 | // signature. | |
| 500 | if (auto *f = dyn_cast<UndefinedFunction>(s)) | |
| 501 | oldSig = f->signature; | |
| 502 | LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n"); | |
| 503 | auto newSym = replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK, | |
| 504 | file, *sym); | |
| 505 | newSym->signature = oldSig; | |
| 506 | return; | |
| 507 | } | |
| 365 | 508 | |
| 366 | if (WasInserted) | |
| 367 | replaceSymbol<UndefinedGlobal>(S, Name, ImportName, ImportModule, Flags, | |
| 368 | File, Type); | |
| 369 | else if (auto *Lazy = dyn_cast<LazySymbol>(S)) | |
| 370 | Lazy->fetch(); | |
| 371 | else if (S->isDefined()) | |
| 372 | checkGlobalType(S, File, Type); | |
| 373 | return S; | |
| 509 | LLVM_DEBUG(dbgs() << "replacing existing undefined\n"); | |
| 510 | file->addMember(sym); | |
| 374 | 511 | } |
| 375 | 512 | |
| 376 | void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) { | |
| 377 | LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n"); | |
| 378 | StringRef Name = Sym->getName(); | |
| 513 | bool SymbolTable::addComdat(StringRef name) { | |
| 514 | return comdatGroups.insert(CachedHashStringRef(name)).second; | |
| 515 | } | |
| 379 | 516 | |
| 380 | Symbol *S; | |
| 381 | bool WasInserted; | |
| 382 | std::tie(S, WasInserted) = insert(Name, nullptr); | |
| 517 | // The new signature doesn't match. Create a variant to the symbol with the | |
| 518 | // signature encoded in the name and return that instead. These symbols are | |
| 519 | // then unified later in handleSymbolVariants. | |
| 520 | bool SymbolTable::getFunctionVariant(Symbol* sym, const WasmSignature *sig, | |
| 521 | const InputFile *file, Symbol **out) { | |
| 522 | LLVM_DEBUG(dbgs() << "getFunctionVariant: " << sym->getName() << " -> " | |
| 523 | << " " << toString(*sig) << "\n"); | |
| 524 | Symbol *variant = nullptr; | |
| 525 | ||
| 526 | // Linear search through symbol variants. Should never be more than two | |
| 527 | // or three entries here. | |
| 528 | auto &variants = symVariants[CachedHashStringRef(sym->getName())]; | |
| 529 | if (variants.empty()) | |
| 530 | variants.push_back(sym); | |
| 531 | ||
| 532 | for (Symbol* v : variants) { | |
| 533 | if (*v->getSignature() == *sig) { | |
| 534 | variant = v; | |
| 535 | break; | |
| 536 | } | |
| 537 | } | |
| 383 | 538 | |
| 384 | if (WasInserted) { | |
| 385 | replaceSymbol<LazySymbol>(S, Name, File, *Sym); | |
| 386 | return; | |
| 539 | bool wasAdded = !variant; | |
| 540 | if (wasAdded) { | |
| 541 | // Create a new variant; | |
| 542 | LLVM_DEBUG(dbgs() << "added new variant\n"); | |
| 543 | variant = reinterpret_cast<Symbol *>(make<SymbolUnion>()); | |
| 544 | variants.push_back(variant); | |
| 545 | } else { | |
| 546 | LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*variant) << "\n"); | |
| 547 | assert(*variant->getSignature() == *sig); | |
| 387 | 548 | } |
| 388 | 549 | |
| 389 | // If there is an existing undefined symbol, load a new one from the archive. | |
| 390 | if (S->isUndefined()) { | |
| 391 | LLVM_DEBUG(dbgs() << "replacing existing undefined\n"); | |
| 392 | File->addMember(Sym); | |
| 550 | *out = variant; | |
| 551 | return wasAdded; | |
| 552 | } | |
| 553 | ||
| 554 | // Set a flag for --trace-symbol so that we can print out a log message | |
| 555 | // if a new symbol with the same name is inserted into the symbol table. | |
| 556 | void SymbolTable::trace(StringRef name) { | |
| 557 | symMap.insert({CachedHashStringRef(name), -1}); | |
| 558 | } | |
| 559 | ||
| 560 | void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) { | |
| 561 | // Swap symbols as instructed by -wrap. | |
| 562 | int &origIdx = symMap[CachedHashStringRef(sym->getName())]; | |
| 563 | int &realIdx= symMap[CachedHashStringRef(real->getName())]; | |
| 564 | int &wrapIdx = symMap[CachedHashStringRef(wrap->getName())]; | |
| 565 | LLVM_DEBUG(dbgs() << "wrap: " << sym->getName() << "\n"); | |
| 566 | ||
| 567 | // Anyone looking up __real symbols should get the original | |
| 568 | realIdx = origIdx; | |
| 569 | // Anyone looking up the original should get the __wrap symbol | |
| 570 | origIdx = wrapIdx; | |
| 571 | } | |
| 572 | ||
| 573 | static const uint8_t unreachableFn[] = { | |
| 574 | 0x03 /* ULEB length */, 0x00 /* ULEB num locals */, | |
| 575 | 0x00 /* opcode unreachable */, 0x0b /* opcode end */ | |
| 576 | }; | |
| 577 | ||
| 578 | // Replace the given symbol body with an unreachable function. | |
| 579 | // This is used by handleWeakUndefines in order to generate a callable | |
| 580 | // equivalent of an undefined function and also handleSymbolVariants for | |
| 581 | // undefined functions that don't match the signature of the definition. | |
| 582 | InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym, | |
| 583 | const WasmSignature &sig, | |
| 584 | StringRef debugName) { | |
| 585 | auto *func = make<SyntheticFunction>(sig, sym->getName(), debugName); | |
| 586 | func->setBody(unreachableFn); | |
| 587 | syntheticFunctions.emplace_back(func); | |
| 588 | replaceSymbol<DefinedFunction>(sym, sym->getName(), sym->getFlags(), nullptr, | |
| 589 | func); | |
| 590 | return func; | |
| 591 | } | |
| 592 | ||
| 593 | // For weak undefined functions, there may be "call" instructions that reference | |
| 594 | // the symbol. In this case, we need to synthesise a dummy/stub function that | |
| 595 | // will abort at runtime, so that relocations can still provided an operand to | |
| 596 | // the call instruction that passes Wasm validation. | |
| 597 | void SymbolTable::handleWeakUndefines() { | |
| 598 | for (Symbol *sym : getSymbols()) { | |
| 599 | if (!sym->isUndefWeak()) | |
| 600 | continue; | |
| 601 | ||
| 602 | const WasmSignature *sig = sym->getSignature(); | |
| 603 | if (!sig) { | |
| 604 | // It is possible for undefined functions not to have a signature (eg. if | |
| 605 | // added via "--undefined"), but weak undefined ones do have a signature. | |
| 606 | // Lazy symbols may not be functions and therefore Sig can still be null | |
| 607 | // in some circumstantce. | |
| 608 | assert(!isa<FunctionSymbol>(sym)); | |
| 609 | continue; | |
| 610 | } | |
| 611 | ||
| 612 | // Add a synthetic dummy for weak undefined functions. These dummies will | |
| 613 | // be GC'd if not used as the target of any "call" instructions. | |
| 614 | StringRef debugName = saver.save("undefined:" + toString(*sym)); | |
| 615 | InputFunction* func = replaceWithUnreachable(sym, *sig, debugName); | |
| 616 | // Ensure it compares equal to the null pointer, and so that table relocs | |
| 617 | // don't pull in the stub body (only call-operand relocs should do that). | |
| 618 | func->setTableIndex(0); | |
| 619 | // Hide our dummy to prevent export. | |
| 620 | sym->setHidden(true); | |
| 393 | 621 | } |
| 394 | 622 | } |
| 395 | 623 | |
| 396 | bool SymbolTable::addComdat(StringRef Name) { | |
| 397 | return Comdats.insert(CachedHashStringRef(Name)).second; | |
| 624 | static void reportFunctionSignatureMismatch(StringRef symName, | |
| 625 | FunctionSymbol *a, | |
| 626 | FunctionSymbol *b, bool isError) { | |
| 627 | std::string msg = ("function signature mismatch: " + symName + | |
| 628 | "\n>>> defined as " + toString(*a->signature) + " in " + | |
| 629 | toString(a->getFile()) + "\n>>> defined as " + | |
| 630 | toString(*b->signature) + " in " + toString(b->getFile())) | |
| 631 | .str(); | |
| 632 | if (isError) | |
| 633 | error(msg); | |
| 634 | else | |
| 635 | warn(msg); | |
| 636 | } | |
| 637 | ||
| 638 | // Remove any variant symbols that were created due to function signature | |
| 639 | // mismatches. | |
| 640 | void SymbolTable::handleSymbolVariants() { | |
| 641 | for (auto pair : symVariants) { | |
| 642 | // Push the initial symbol onto the list of variants. | |
| 643 | StringRef symName = pair.first.val(); | |
| 644 | std::vector<Symbol *> &variants = pair.second; | |
| 645 | ||
| 646 | #ifndef NDEBUG | |
| 647 | LLVM_DEBUG(dbgs() << "symbol with (" << variants.size() | |
| 648 | << ") variants: " << symName << "\n"); | |
| 649 | for (auto *s: variants) { | |
| 650 | auto *f = cast<FunctionSymbol>(s); | |
| 651 | LLVM_DEBUG(dbgs() << " variant: " + f->getName() << " " | |
| 652 | << toString(*f->signature) << "\n"); | |
| 653 | } | |
| 654 | #endif | |
| 655 | ||
| 656 | // Find the one definition. | |
| 657 | DefinedFunction *defined = nullptr; | |
| 658 | for (auto *symbol : variants) { | |
| 659 | if (auto f = dyn_cast<DefinedFunction>(symbol)) { | |
| 660 | defined = f; | |
| 661 | break; | |
| 662 | } | |
| 663 | } | |
| 664 | ||
| 665 | // If there are no definitions, and the undefined symbols disagree on | |
| 666 | // the signature, there is not we can do since we don't know which one | |
| 667 | // to use as the signature on the import. | |
| 668 | if (!defined) { | |
| 669 | reportFunctionSignatureMismatch(symName, | |
| 670 | cast<FunctionSymbol>(variants[0]), | |
| 671 | cast<FunctionSymbol>(variants[1]), true); | |
| 672 | return; | |
| 673 | } | |
| 674 | ||
| 675 | for (auto *symbol : variants) { | |
| 676 | if (symbol != defined) { | |
| 677 | auto *f = cast<FunctionSymbol>(symbol); | |
| 678 | reportFunctionSignatureMismatch(symName, f, defined, false); | |
| 679 | StringRef debugName = saver.save("unreachable:" + toString(*f)); | |
| 680 | replaceWithUnreachable(f, *f->signature, debugName); | |
| 681 | } | |
| 682 | } | |
| 683 | } | |
| 398 | 684 | } |
deps/lld/wasm/SymbolTable.h+69-41| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- SymbolTable.h --------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -36,60 +35,89 @@ class InputSegment; |
| 36 | 35 | // There is one add* function per symbol type. |
| 37 | 36 | class SymbolTable { |
| 38 | 37 | public: |
| 39 | void addFile(InputFile *File); | |
| 38 | void wrap(Symbol *sym, Symbol *real, Symbol *wrap); | |
| 39 | ||
| 40 | void addFile(InputFile *file); | |
| 41 | ||
| 40 | 42 | void addCombinedLTOObject(); |
| 41 | 43 | |
| 42 | std::vector<ObjFile *> ObjectFiles; | |
| 43 | std::vector<BitcodeFile *> BitcodeFiles; | |
| 44 | std::vector<InputFunction *> SyntheticFunctions; | |
| 45 | std::vector<InputGlobal *> SyntheticGlobals; | |
| 44 | ArrayRef<Symbol *> getSymbols() const { return symVector; } | |
| 45 | ||
| 46 | Symbol *find(StringRef name); | |
| 46 | 47 | |
| 47 | void reportRemainingUndefines(); | |
| 48 | void replace(StringRef name, Symbol* sym); | |
| 48 | 49 | |
| 49 | ArrayRef<Symbol *> getSymbols() const { return SymVector; } | |
| 50 | Symbol *find(StringRef Name); | |
| 50 | void trace(StringRef name); | |
| 51 | 51 | |
| 52 | Symbol *addDefinedFunction(StringRef Name, uint32_t Flags, InputFile *File, | |
| 53 | InputFunction *Function); | |
| 54 | Symbol *addDefinedData(StringRef Name, uint32_t Flags, InputFile *File, | |
| 55 | InputSegment *Segment, uint32_t Address, | |
| 56 | uint32_t Size); | |
| 57 | Symbol *addDefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File, | |
| 58 | InputGlobal *G); | |
| 59 | Symbol *addDefinedEvent(StringRef Name, uint32_t Flags, InputFile *File, | |
| 60 | InputEvent *E); | |
| 52 | Symbol *addDefinedFunction(StringRef name, uint32_t flags, InputFile *file, | |
| 53 | InputFunction *function); | |
| 54 | Symbol *addDefinedData(StringRef name, uint32_t flags, InputFile *file, | |
| 55 | InputSegment *segment, uint32_t address, | |
| 56 | uint32_t size); | |
| 57 | Symbol *addDefinedGlobal(StringRef name, uint32_t flags, InputFile *file, | |
| 58 | InputGlobal *g); | |
| 59 | Symbol *addDefinedEvent(StringRef name, uint32_t flags, InputFile *file, | |
| 60 | InputEvent *e); | |
| 61 | 61 | |
| 62 | Symbol *addUndefinedFunction(StringRef Name, StringRef ImportName, | |
| 63 | StringRef ImportModule, uint32_t Flags, | |
| 64 | InputFile *File, const WasmSignature *Signature); | |
| 65 | Symbol *addUndefinedData(StringRef Name, uint32_t Flags, InputFile *File); | |
| 66 | Symbol *addUndefinedGlobal(StringRef Name, StringRef ImportName, | |
| 67 | StringRef ImportModule, uint32_t Flags, | |
| 68 | InputFile *File, const WasmGlobalType *Type); | |
| 62 | Symbol *addUndefinedFunction(StringRef name, StringRef importName, | |
| 63 | StringRef importModule, uint32_t flags, | |
| 64 | InputFile *file, const WasmSignature *signature, | |
| 65 | bool isCalledDirectly); | |
| 66 | Symbol *addUndefinedData(StringRef name, uint32_t flags, InputFile *file); | |
| 67 | Symbol *addUndefinedGlobal(StringRef name, StringRef importName, | |
| 68 | StringRef importModule, uint32_t flags, | |
| 69 | InputFile *file, const WasmGlobalType *type); | |
| 69 | 70 | |
| 70 | void addLazy(ArchiveFile *F, const llvm::object::Archive::Symbol *Sym); | |
| 71 | void addLazy(ArchiveFile *f, const llvm::object::Archive::Symbol *sym); | |
| 71 | 72 | |
| 72 | bool addComdat(StringRef Name); | |
| 73 | bool addComdat(StringRef name); | |
| 73 | 74 | |
| 74 | DefinedData *addSyntheticDataSymbol(StringRef Name, uint32_t Flags); | |
| 75 | DefinedGlobal *addSyntheticGlobal(StringRef Name, uint32_t Flags, | |
| 76 | InputGlobal *Global); | |
| 77 | DefinedFunction *addSyntheticFunction(StringRef Name, uint32_t Flags, | |
| 78 | InputFunction *Function); | |
| 75 | DefinedData *addSyntheticDataSymbol(StringRef name, uint32_t flags); | |
| 76 | DefinedGlobal *addSyntheticGlobal(StringRef name, uint32_t flags, | |
| 77 | InputGlobal *global); | |
| 78 | DefinedFunction *addSyntheticFunction(StringRef name, uint32_t flags, | |
| 79 | InputFunction *function); | |
| 80 | DefinedData *addOptionalDataSymbol(StringRef name, uint32_t value = 0, | |
| 81 | uint32_t flags = 0); | |
| 82 | ||
| 83 | void handleSymbolVariants(); | |
| 84 | void handleWeakUndefines(); | |
| 85 | ||
| 86 | std::vector<ObjFile *> objectFiles; | |
| 87 | std::vector<SharedFile *> sharedFiles; | |
| 88 | std::vector<BitcodeFile *> bitcodeFiles; | |
| 89 | std::vector<InputFunction *> syntheticFunctions; | |
| 90 | std::vector<InputGlobal *> syntheticGlobals; | |
| 79 | 91 | |
| 80 | 92 | private: |
| 81 | std::pair<Symbol *, bool> insert(StringRef Name, InputFile *File); | |
| 93 | std::pair<Symbol *, bool> insert(StringRef name, const InputFile *file); | |
| 94 | std::pair<Symbol *, bool> insertName(StringRef name); | |
| 95 | ||
| 96 | bool getFunctionVariant(Symbol* sym, const WasmSignature *sig, | |
| 97 | const InputFile *file, Symbol **out); | |
| 98 | InputFunction *replaceWithUnreachable(Symbol *sym, const WasmSignature &sig, | |
| 99 | StringRef debugName); | |
| 100 | ||
| 101 | // Maps symbol names to index into the symVector. -1 means that symbols | |
| 102 | // is to not yet in the vector but it should have tracing enabled if it is | |
| 103 | // ever added. | |
| 104 | llvm::DenseMap<llvm::CachedHashStringRef, int> symMap; | |
| 105 | std::vector<Symbol *> symVector; | |
| 82 | 106 | |
| 83 | llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> SymMap; | |
| 84 | std::vector<Symbol *> SymVector; | |
| 107 | // For certain symbols types, e.g. function symbols, we allow for muliple | |
| 108 | // variants of the same symbol with different signatures. | |
| 109 | llvm::DenseMap<llvm::CachedHashStringRef, std::vector<Symbol *>> symVariants; | |
| 85 | 110 | |
| 86 | llvm::DenseSet<llvm::CachedHashStringRef> Comdats; | |
| 111 | // Comdat groups define "link once" sections. If two comdat groups have the | |
| 112 | // same name, only one of them is linked, and the other is ignored. This set | |
| 113 | // is used to uniquify them. | |
| 114 | llvm::DenseSet<llvm::CachedHashStringRef> comdatGroups; | |
| 87 | 115 | |
| 88 | 116 | // For LTO. |
| 89 | std::unique_ptr<BitcodeCompiler> LTO; | |
| 117 | std::unique_ptr<BitcodeCompiler> lto; | |
| 90 | 118 | }; |
| 91 | 119 | |
| 92 | extern SymbolTable *Symtab; | |
| 120 | extern SymbolTable *symtab; | |
| 93 | 121 | |
| 94 | 122 | } // namespace wasm |
| 95 | 123 | } // namespace lld |
deps/lld/wasm/Symbols.cpp+193-140| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Symbols.cpp --------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -13,6 +12,7 @@ |
| 13 | 12 | #include "InputEvent.h" |
| 14 | 13 | #include "InputFiles.h" |
| 15 | 14 | #include "InputGlobal.h" |
| 15 | #include "OutputSections.h" | |
| 16 | 16 | #include "OutputSegment.h" |
| 17 | 17 | #include "lld/Common/ErrorHandler.h" |
| 18 | 18 | #include "lld/Common/Strings.h" |
| ... | ... | @@ -24,13 +24,19 @@ using namespace llvm::wasm; |
| 24 | 24 | using namespace lld; |
| 25 | 25 | using namespace lld::wasm; |
| 26 | 26 | |
| 27 | DefinedFunction *WasmSym::CallCtors; | |
| 28 | DefinedData *WasmSym::DsoHandle; | |
| 29 | DefinedData *WasmSym::DataEnd; | |
| 30 | DefinedData *WasmSym::HeapBase; | |
| 31 | GlobalSymbol *WasmSym::StackPointer; | |
| 32 | UndefinedGlobal *WasmSym::TableBase; | |
| 33 | UndefinedGlobal *WasmSym::MemoryBase; | |
| 27 | DefinedFunction *WasmSym::callCtors; | |
| 28 | DefinedFunction *WasmSym::initMemory; | |
| 29 | DefinedFunction *WasmSym::applyRelocs; | |
| 30 | DefinedFunction *WasmSym::initTLS; | |
| 31 | DefinedData *WasmSym::dsoHandle; | |
| 32 | DefinedData *WasmSym::dataEnd; | |
| 33 | DefinedData *WasmSym::globalBase; | |
| 34 | DefinedData *WasmSym::heapBase; | |
| 35 | GlobalSymbol *WasmSym::stackPointer; | |
| 36 | GlobalSymbol *WasmSym::tlsBase; | |
| 37 | GlobalSymbol *WasmSym::tlsSize; | |
| 38 | UndefinedGlobal *WasmSym::tableBase; | |
| 39 | UndefinedGlobal *WasmSym::memoryBase; | |
| 34 | 40 | |
| 35 | 41 | WasmSymbolType Symbol::getWasmType() const { |
| 36 | 42 | if (isa<FunctionSymbol>(this)) |
| ... | ... | @@ -41,238 +47,260 @@ WasmSymbolType Symbol::getWasmType() const { |
| 41 | 47 | return WASM_SYMBOL_TYPE_GLOBAL; |
| 42 | 48 | if (isa<EventSymbol>(this)) |
| 43 | 49 | return WASM_SYMBOL_TYPE_EVENT; |
| 44 | if (isa<SectionSymbol>(this)) | |
| 50 | if (isa<SectionSymbol>(this) || isa<OutputSectionSymbol>(this)) | |
| 45 | 51 | return WASM_SYMBOL_TYPE_SECTION; |
| 46 | 52 | llvm_unreachable("invalid symbol kind"); |
| 47 | 53 | } |
| 48 | 54 | |
| 55 | const WasmSignature *Symbol::getSignature() const { | |
| 56 | if (auto* f = dyn_cast<FunctionSymbol>(this)) | |
| 57 | return f->signature; | |
| 58 | if (auto *l = dyn_cast<LazySymbol>(this)) | |
| 59 | return l->signature; | |
| 60 | return nullptr; | |
| 61 | } | |
| 62 | ||
| 49 | 63 | InputChunk *Symbol::getChunk() const { |
| 50 | if (auto *F = dyn_cast<DefinedFunction>(this)) | |
| 51 | return F->Function; | |
| 52 | if (auto *D = dyn_cast<DefinedData>(this)) | |
| 53 | return D->Segment; | |
| 64 | if (auto *f = dyn_cast<DefinedFunction>(this)) | |
| 65 | return f->function; | |
| 66 | if (auto *d = dyn_cast<DefinedData>(this)) | |
| 67 | return d->segment; | |
| 54 | 68 | return nullptr; |
| 55 | 69 | } |
| 56 | 70 | |
| 71 | bool Symbol::isDiscarded() const { | |
| 72 | if (InputChunk *c = getChunk()) | |
| 73 | return c->discarded; | |
| 74 | return false; | |
| 75 | } | |
| 76 | ||
| 57 | 77 | bool Symbol::isLive() const { |
| 58 | if (auto *G = dyn_cast<DefinedGlobal>(this)) | |
| 59 | return G->Global->Live; | |
| 60 | if (auto *E = dyn_cast<DefinedEvent>(this)) | |
| 61 | return E->Event->Live; | |
| 62 | if (InputChunk *C = getChunk()) | |
| 63 | return C->Live; | |
| 64 | return Referenced; | |
| 78 | if (auto *g = dyn_cast<DefinedGlobal>(this)) | |
| 79 | return g->global->live; | |
| 80 | if (auto *e = dyn_cast<DefinedEvent>(this)) | |
| 81 | return e->event->live; | |
| 82 | if (InputChunk *c = getChunk()) | |
| 83 | return c->live; | |
| 84 | return referenced; | |
| 65 | 85 | } |
| 66 | 86 | |
| 67 | 87 | void Symbol::markLive() { |
| 68 | if (auto *G = dyn_cast<DefinedGlobal>(this)) | |
| 69 | G->Global->Live = true; | |
| 70 | if (auto *E = dyn_cast<DefinedEvent>(this)) | |
| 71 | E->Event->Live = true; | |
| 72 | if (InputChunk *C = getChunk()) | |
| 73 | C->Live = true; | |
| 74 | Referenced = true; | |
| 88 | assert(!isDiscarded()); | |
| 89 | if (auto *g = dyn_cast<DefinedGlobal>(this)) | |
| 90 | g->global->live = true; | |
| 91 | if (auto *e = dyn_cast<DefinedEvent>(this)) | |
| 92 | e->event->live = true; | |
| 93 | if (InputChunk *c = getChunk()) | |
| 94 | c->live = true; | |
| 95 | referenced = true; | |
| 75 | 96 | } |
| 76 | 97 | |
| 77 | 98 | uint32_t Symbol::getOutputSymbolIndex() const { |
| 78 | assert(OutputSymbolIndex != INVALID_INDEX); | |
| 79 | return OutputSymbolIndex; | |
| 99 | assert(outputSymbolIndex != INVALID_INDEX); | |
| 100 | return outputSymbolIndex; | |
| 80 | 101 | } |
| 81 | 102 | |
| 82 | void Symbol::setOutputSymbolIndex(uint32_t Index) { | |
| 83 | LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << Name << " -> " << Index | |
| 103 | void Symbol::setOutputSymbolIndex(uint32_t index) { | |
| 104 | LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name << " -> " << index | |
| 84 | 105 | << "\n"); |
| 85 | assert(OutputSymbolIndex == INVALID_INDEX); | |
| 86 | OutputSymbolIndex = Index; | |
| 106 | assert(outputSymbolIndex == INVALID_INDEX); | |
| 107 | outputSymbolIndex = index; | |
| 108 | } | |
| 109 | ||
| 110 | void Symbol::setGOTIndex(uint32_t index) { | |
| 111 | LLVM_DEBUG(dbgs() << "setGOTIndex " << name << " -> " << index << "\n"); | |
| 112 | assert(gotIndex == INVALID_INDEX); | |
| 113 | // Any symbol that is assigned a GOT entry must be exported othewise the | |
| 114 | // dynamic linker won't be able create the entry that contains it. | |
| 115 | forceExport = true; | |
| 116 | gotIndex = index; | |
| 87 | 117 | } |
| 88 | 118 | |
| 89 | 119 | bool Symbol::isWeak() const { |
| 90 | return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK; | |
| 120 | return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK; | |
| 91 | 121 | } |
| 92 | 122 | |
| 93 | 123 | bool Symbol::isLocal() const { |
| 94 | return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL; | |
| 124 | return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL; | |
| 95 | 125 | } |
| 96 | 126 | |
| 97 | 127 | bool Symbol::isHidden() const { |
| 98 | return (Flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN; | |
| 128 | return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN; | |
| 99 | 129 | } |
| 100 | 130 | |
| 101 | void Symbol::setHidden(bool IsHidden) { | |
| 102 | LLVM_DEBUG(dbgs() << "setHidden: " << Name << " -> " << IsHidden << "\n"); | |
| 103 | Flags &= ~WASM_SYMBOL_VISIBILITY_MASK; | |
| 104 | if (IsHidden) | |
| 105 | Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN; | |
| 131 | void Symbol::setHidden(bool isHidden) { | |
| 132 | LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n"); | |
| 133 | flags &= ~WASM_SYMBOL_VISIBILITY_MASK; | |
| 134 | if (isHidden) | |
| 135 | flags |= WASM_SYMBOL_VISIBILITY_HIDDEN; | |
| 106 | 136 | else |
| 107 | Flags |= WASM_SYMBOL_VISIBILITY_DEFAULT; | |
| 137 | flags |= WASM_SYMBOL_VISIBILITY_DEFAULT; | |
| 108 | 138 | } |
| 109 | 139 | |
| 110 | 140 | bool Symbol::isExported() const { |
| 111 | 141 | if (!isDefined() || isLocal()) |
| 112 | 142 | return false; |
| 113 | 143 | |
| 114 | if (ForceExport || Config->ExportAll) | |
| 144 | if (forceExport || config->exportAll) | |
| 115 | 145 | return true; |
| 116 | 146 | |
| 117 | if (Config->ExportDynamic && !isHidden()) | |
| 147 | if (config->exportDynamic && !isHidden()) | |
| 118 | 148 | return true; |
| 119 | 149 | |
| 120 | return false; | |
| 150 | return flags & WASM_SYMBOL_EXPORTED; | |
| 121 | 151 | } |
| 122 | 152 | |
| 123 | 153 | uint32_t FunctionSymbol::getFunctionIndex() const { |
| 124 | if (auto *F = dyn_cast<DefinedFunction>(this)) | |
| 125 | return F->Function->getFunctionIndex(); | |
| 126 | assert(FunctionIndex != INVALID_INDEX); | |
| 127 | return FunctionIndex; | |
| 154 | if (auto *f = dyn_cast<DefinedFunction>(this)) | |
| 155 | return f->function->getFunctionIndex(); | |
| 156 | assert(functionIndex != INVALID_INDEX); | |
| 157 | return functionIndex; | |
| 128 | 158 | } |
| 129 | 159 | |
| 130 | void FunctionSymbol::setFunctionIndex(uint32_t Index) { | |
| 131 | LLVM_DEBUG(dbgs() << "setFunctionIndex " << Name << " -> " << Index << "\n"); | |
| 132 | assert(FunctionIndex == INVALID_INDEX); | |
| 133 | FunctionIndex = Index; | |
| 160 | void FunctionSymbol::setFunctionIndex(uint32_t index) { | |
| 161 | LLVM_DEBUG(dbgs() << "setFunctionIndex " << name << " -> " << index << "\n"); | |
| 162 | assert(functionIndex == INVALID_INDEX); | |
| 163 | functionIndex = index; | |
| 134 | 164 | } |
| 135 | 165 | |
| 136 | 166 | bool FunctionSymbol::hasFunctionIndex() const { |
| 137 | if (auto *F = dyn_cast<DefinedFunction>(this)) | |
| 138 | return F->Function->hasFunctionIndex(); | |
| 139 | return FunctionIndex != INVALID_INDEX; | |
| 167 | if (auto *f = dyn_cast<DefinedFunction>(this)) | |
| 168 | return f->function->hasFunctionIndex(); | |
| 169 | return functionIndex != INVALID_INDEX; | |
| 140 | 170 | } |
| 141 | 171 | |
| 142 | 172 | uint32_t FunctionSymbol::getTableIndex() const { |
| 143 | if (auto *F = dyn_cast<DefinedFunction>(this)) | |
| 144 | return F->Function->getTableIndex(); | |
| 145 | assert(TableIndex != INVALID_INDEX); | |
| 146 | return TableIndex; | |
| 173 | if (auto *f = dyn_cast<DefinedFunction>(this)) | |
| 174 | return f->function->getTableIndex(); | |
| 175 | assert(tableIndex != INVALID_INDEX); | |
| 176 | return tableIndex; | |
| 147 | 177 | } |
| 148 | 178 | |
| 149 | 179 | bool FunctionSymbol::hasTableIndex() const { |
| 150 | if (auto *F = dyn_cast<DefinedFunction>(this)) | |
| 151 | return F->Function->hasTableIndex(); | |
| 152 | return TableIndex != INVALID_INDEX; | |
| 180 | if (auto *f = dyn_cast<DefinedFunction>(this)) | |
| 181 | return f->function->hasTableIndex(); | |
| 182 | return tableIndex != INVALID_INDEX; | |
| 153 | 183 | } |
| 154 | 184 | |
| 155 | void FunctionSymbol::setTableIndex(uint32_t Index) { | |
| 185 | void FunctionSymbol::setTableIndex(uint32_t index) { | |
| 156 | 186 | // For imports, we set the table index here on the Symbol; for defined |
| 157 | 187 | // functions we set the index on the InputFunction so that we don't export |
| 158 | 188 | // the same thing twice (keeps the table size down). |
| 159 | if (auto *F = dyn_cast<DefinedFunction>(this)) { | |
| 160 | F->Function->setTableIndex(Index); | |
| 189 | if (auto *f = dyn_cast<DefinedFunction>(this)) { | |
| 190 | f->function->setTableIndex(index); | |
| 161 | 191 | return; |
| 162 | 192 | } |
| 163 | LLVM_DEBUG(dbgs() << "setTableIndex " << Name << " -> " << Index << "\n"); | |
| 164 | assert(TableIndex == INVALID_INDEX); | |
| 165 | TableIndex = Index; | |
| 193 | LLVM_DEBUG(dbgs() << "setTableIndex " << name << " -> " << index << "\n"); | |
| 194 | assert(tableIndex == INVALID_INDEX); | |
| 195 | tableIndex = index; | |
| 166 | 196 | } |
| 167 | 197 | |
| 168 | DefinedFunction::DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F, | |
| 169 | InputFunction *Function) | |
| 170 | : FunctionSymbol(Name, DefinedFunctionKind, Flags, F, | |
| 171 | Function ? &Function->Signature : nullptr), | |
| 172 | Function(Function) {} | |
| 198 | DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f, | |
| 199 | InputFunction *function) | |
| 200 | : FunctionSymbol(name, DefinedFunctionKind, flags, f, | |
| 201 | function ? &function->signature : nullptr), | |
| 202 | function(function) {} | |
| 173 | 203 | |
| 174 | 204 | uint32_t DefinedData::getVirtualAddress() const { |
| 175 | 205 | LLVM_DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n"); |
| 176 | if (Segment) | |
| 177 | return Segment->OutputSeg->StartVA + Segment->OutputSegmentOffset + Offset; | |
| 178 | return Offset; | |
| 206 | if (segment) { | |
| 207 | // For thread local data, the symbol location is relative to the start of | |
| 208 | // the .tdata section, since they are used as offsets from __tls_base. | |
| 209 | // Hence, we do not add in segment->outputSeg->startVA. | |
| 210 | if (segment->outputSeg->name == ".tdata") | |
| 211 | return segment->outputSegmentOffset + offset; | |
| 212 | return segment->outputSeg->startVA + segment->outputSegmentOffset + offset; | |
| 213 | } | |
| 214 | return offset; | |
| 179 | 215 | } |
| 180 | 216 | |
| 181 | void DefinedData::setVirtualAddress(uint32_t Value) { | |
| 182 | LLVM_DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n"); | |
| 183 | assert(!Segment); | |
| 184 | Offset = Value; | |
| 217 | void DefinedData::setVirtualAddress(uint32_t value) { | |
| 218 | LLVM_DEBUG(dbgs() << "setVirtualAddress " << name << " -> " << value << "\n"); | |
| 219 | assert(!segment); | |
| 220 | offset = value; | |
| 185 | 221 | } |
| 186 | 222 | |
| 187 | 223 | uint32_t DefinedData::getOutputSegmentOffset() const { |
| 188 | 224 | LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n"); |
| 189 | return Segment->OutputSegmentOffset + Offset; | |
| 225 | return segment->outputSegmentOffset + offset; | |
| 190 | 226 | } |
| 191 | 227 | |
| 192 | 228 | uint32_t DefinedData::getOutputSegmentIndex() const { |
| 193 | 229 | LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n"); |
| 194 | return Segment->OutputSeg->Index; | |
| 230 | return segment->outputSeg->index; | |
| 195 | 231 | } |
| 196 | 232 | |
| 197 | 233 | uint32_t GlobalSymbol::getGlobalIndex() const { |
| 198 | if (auto *F = dyn_cast<DefinedGlobal>(this)) | |
| 199 | return F->Global->getGlobalIndex(); | |
| 200 | assert(GlobalIndex != INVALID_INDEX); | |
| 201 | return GlobalIndex; | |
| 234 | if (auto *f = dyn_cast<DefinedGlobal>(this)) | |
| 235 | return f->global->getGlobalIndex(); | |
| 236 | assert(globalIndex != INVALID_INDEX); | |
| 237 | return globalIndex; | |
| 202 | 238 | } |
| 203 | 239 | |
| 204 | void GlobalSymbol::setGlobalIndex(uint32_t Index) { | |
| 205 | LLVM_DEBUG(dbgs() << "setGlobalIndex " << Name << " -> " << Index << "\n"); | |
| 206 | assert(GlobalIndex == INVALID_INDEX); | |
| 207 | GlobalIndex = Index; | |
| 240 | void GlobalSymbol::setGlobalIndex(uint32_t index) { | |
| 241 | LLVM_DEBUG(dbgs() << "setGlobalIndex " << name << " -> " << index << "\n"); | |
| 242 | assert(globalIndex == INVALID_INDEX); | |
| 243 | globalIndex = index; | |
| 208 | 244 | } |
| 209 | 245 | |
| 210 | 246 | bool GlobalSymbol::hasGlobalIndex() const { |
| 211 | if (auto *F = dyn_cast<DefinedGlobal>(this)) | |
| 212 | return F->Global->hasGlobalIndex(); | |
| 213 | return GlobalIndex != INVALID_INDEX; | |
| 247 | if (auto *f = dyn_cast<DefinedGlobal>(this)) | |
| 248 | return f->global->hasGlobalIndex(); | |
| 249 | return globalIndex != INVALID_INDEX; | |
| 214 | 250 | } |
| 215 | 251 | |
| 216 | DefinedGlobal::DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File, | |
| 217 | InputGlobal *Global) | |
| 218 | : GlobalSymbol(Name, DefinedGlobalKind, Flags, File, | |
| 219 | Global ? &Global->getType() : nullptr), | |
| 220 | Global(Global) {} | |
| 252 | DefinedGlobal::DefinedGlobal(StringRef name, uint32_t flags, InputFile *file, | |
| 253 | InputGlobal *global) | |
| 254 | : GlobalSymbol(name, DefinedGlobalKind, flags, file, | |
| 255 | global ? &global->getType() : nullptr), | |
| 256 | global(global) {} | |
| 221 | 257 | |
| 222 | 258 | uint32_t EventSymbol::getEventIndex() const { |
| 223 | if (auto *F = dyn_cast<DefinedEvent>(this)) | |
| 224 | return F->Event->getEventIndex(); | |
| 225 | assert(EventIndex != INVALID_INDEX); | |
| 226 | return EventIndex; | |
| 259 | if (auto *f = dyn_cast<DefinedEvent>(this)) | |
| 260 | return f->event->getEventIndex(); | |
| 261 | assert(eventIndex != INVALID_INDEX); | |
| 262 | return eventIndex; | |
| 227 | 263 | } |
| 228 | 264 | |
| 229 | void EventSymbol::setEventIndex(uint32_t Index) { | |
| 230 | LLVM_DEBUG(dbgs() << "setEventIndex " << Name << " -> " << Index << "\n"); | |
| 231 | assert(EventIndex == INVALID_INDEX); | |
| 232 | EventIndex = Index; | |
| 265 | void EventSymbol::setEventIndex(uint32_t index) { | |
| 266 | LLVM_DEBUG(dbgs() << "setEventIndex " << name << " -> " << index << "\n"); | |
| 267 | assert(eventIndex == INVALID_INDEX); | |
| 268 | eventIndex = index; | |
| 233 | 269 | } |
| 234 | 270 | |
| 235 | 271 | bool EventSymbol::hasEventIndex() const { |
| 236 | if (auto *F = dyn_cast<DefinedEvent>(this)) | |
| 237 | return F->Event->hasEventIndex(); | |
| 238 | return EventIndex != INVALID_INDEX; | |
| 272 | if (auto *f = dyn_cast<DefinedEvent>(this)) | |
| 273 | return f->event->hasEventIndex(); | |
| 274 | return eventIndex != INVALID_INDEX; | |
| 239 | 275 | } |
| 240 | 276 | |
| 241 | DefinedEvent::DefinedEvent(StringRef Name, uint32_t Flags, InputFile *File, | |
| 242 | InputEvent *Event) | |
| 243 | : EventSymbol(Name, DefinedEventKind, Flags, File, | |
| 244 | Event ? &Event->getType() : nullptr, | |
| 245 | Event ? &Event->Signature : nullptr), | |
| 246 | Event(Event) {} | |
| 247 | ||
| 248 | uint32_t SectionSymbol::getOutputSectionIndex() const { | |
| 249 | LLVM_DEBUG(dbgs() << "getOutputSectionIndex: " << getName() << "\n"); | |
| 250 | assert(OutputSectionIndex != INVALID_INDEX); | |
| 251 | return OutputSectionIndex; | |
| 252 | } | |
| 277 | DefinedEvent::DefinedEvent(StringRef name, uint32_t flags, InputFile *file, | |
| 278 | InputEvent *event) | |
| 279 | : EventSymbol(name, DefinedEventKind, flags, file, | |
| 280 | event ? &event->getType() : nullptr, | |
| 281 | event ? &event->signature : nullptr), | |
| 282 | event(event) {} | |
| 253 | 283 | |
| 254 | void SectionSymbol::setOutputSectionIndex(uint32_t Index) { | |
| 255 | LLVM_DEBUG(dbgs() << "setOutputSectionIndex: " << getName() << " -> " << Index | |
| 256 | << "\n"); | |
| 257 | assert(Index != INVALID_INDEX); | |
| 258 | OutputSectionIndex = Index; | |
| 284 | const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const { | |
| 285 | assert(section->outputSec && section->outputSec->sectionSym); | |
| 286 | return section->outputSec->sectionSym; | |
| 259 | 287 | } |
| 260 | 288 | |
| 261 | void LazySymbol::fetch() { cast<ArchiveFile>(File)->addMember(&ArchiveSymbol); } | |
| 289 | void LazySymbol::fetch() { cast<ArchiveFile>(file)->addMember(&archiveSymbol); } | |
| 262 | 290 | |
| 263 | std::string lld::toString(const wasm::Symbol &Sym) { | |
| 264 | return lld::maybeDemangleSymbol(Sym.getName()); | |
| 291 | std::string lld::toString(const wasm::Symbol &sym) { | |
| 292 | return lld::maybeDemangleSymbol(sym.getName()); | |
| 265 | 293 | } |
| 266 | 294 | |
| 267 | std::string lld::maybeDemangleSymbol(StringRef Name) { | |
| 268 | if (Config->Demangle) | |
| 269 | if (Optional<std::string> S = demangleItanium(Name)) | |
| 270 | return *S; | |
| 271 | return Name; | |
| 295 | std::string lld::maybeDemangleSymbol(StringRef name) { | |
| 296 | if (config->demangle) | |
| 297 | if (Optional<std::string> s = demangleItanium(name)) | |
| 298 | return *s; | |
| 299 | return name; | |
| 272 | 300 | } |
| 273 | 301 | |
| 274 | std::string lld::toString(wasm::Symbol::Kind Kind) { | |
| 275 | switch (Kind) { | |
| 302 | std::string lld::toString(wasm::Symbol::Kind kind) { | |
| 303 | switch (kind) { | |
| 276 | 304 | case wasm::Symbol::DefinedFunctionKind: |
| 277 | 305 | return "DefinedFunction"; |
| 278 | 306 | case wasm::Symbol::DefinedDataKind: |
| ... | ... | @@ -291,6 +319,31 @@ std::string lld::toString(wasm::Symbol::Kind Kind) { |
| 291 | 319 | return "LazyKind"; |
| 292 | 320 | case wasm::Symbol::SectionKind: |
| 293 | 321 | return "SectionKind"; |
| 322 | case wasm::Symbol::OutputSectionKind: | |
| 323 | return "OutputSectionKind"; | |
| 294 | 324 | } |
| 295 | 325 | llvm_unreachable("invalid symbol kind"); |
| 296 | 326 | } |
| 327 | ||
| 328 | ||
| 329 | void lld::wasm::printTraceSymbolUndefined(StringRef name, const InputFile* file) { | |
| 330 | message(toString(file) + ": reference to " + name); | |
| 331 | } | |
| 332 | ||
| 333 | // Print out a log message for --trace-symbol. | |
| 334 | void lld::wasm::printTraceSymbol(Symbol *sym) { | |
| 335 | // Undefined symbols are traced via printTraceSymbolUndefined | |
| 336 | if (sym->isUndefined()) | |
| 337 | return; | |
| 338 | ||
| 339 | std::string s; | |
| 340 | if (sym->isLazy()) | |
| 341 | s = ": lazy definition of "; | |
| 342 | else | |
| 343 | s = ": definition of "; | |
| 344 | ||
| 345 | message(toString(sym->getFile()) + s + sym->getName()); | |
| 346 | } | |
| 347 | ||
| 348 | const char *lld::wasm::defaultModule = "env"; | |
| 349 | const char *lld::wasm::functionTableName = "__indirect_function_table"; |
deps/lld/wasm/Symbols.h+273-155| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Symbols.h ------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -18,6 +17,14 @@ |
| 18 | 17 | namespace lld { |
| 19 | 18 | namespace wasm { |
| 20 | 19 | |
| 20 | // Shared string constants | |
| 21 | ||
| 22 | // The default module name to use for symbol imports. | |
| 23 | extern const char *defaultModule; | |
| 24 | ||
| 25 | // The name under which to import or export the wasm table. | |
| 26 | extern const char *functionTableName; | |
| 27 | ||
| 21 | 28 | using llvm::wasm::WasmSymbolType; |
| 22 | 29 | |
| 23 | 30 | class InputFile; |
| ... | ... | @@ -27,48 +34,58 @@ class InputFunction; |
| 27 | 34 | class InputGlobal; |
| 28 | 35 | class InputEvent; |
| 29 | 36 | class InputSection; |
| 37 | class OutputSection; | |
| 30 | 38 | |
| 31 | 39 | #define INVALID_INDEX UINT32_MAX |
| 32 | 40 | |
| 33 | 41 | // The base class for real symbol classes. |
| 34 | 42 | class Symbol { |
| 35 | 43 | public: |
| 36 | enum Kind { | |
| 44 | enum Kind : uint8_t { | |
| 37 | 45 | DefinedFunctionKind, |
| 38 | 46 | DefinedDataKind, |
| 39 | 47 | DefinedGlobalKind, |
| 40 | 48 | DefinedEventKind, |
| 41 | 49 | SectionKind, |
| 50 | OutputSectionKind, | |
| 42 | 51 | UndefinedFunctionKind, |
| 43 | 52 | UndefinedDataKind, |
| 44 | 53 | UndefinedGlobalKind, |
| 45 | 54 | LazyKind, |
| 46 | 55 | }; |
| 47 | 56 | |
| 48 | Kind kind() const { return SymbolKind; } | |
| 57 | Kind kind() const { return symbolKind; } | |
| 49 | 58 | |
| 50 | bool isDefined() const { | |
| 51 | return SymbolKind == DefinedFunctionKind || SymbolKind == DefinedDataKind || | |
| 52 | SymbolKind == DefinedGlobalKind || SymbolKind == DefinedEventKind || | |
| 53 | SymbolKind == SectionKind; | |
| 54 | } | |
| 59 | bool isDefined() const { return !isLazy() && !isUndefined(); } | |
| 55 | 60 | |
| 56 | 61 | bool isUndefined() const { |
| 57 | return SymbolKind == UndefinedFunctionKind || | |
| 58 | SymbolKind == UndefinedDataKind || SymbolKind == UndefinedGlobalKind; | |
| 62 | return symbolKind == UndefinedFunctionKind || | |
| 63 | symbolKind == UndefinedDataKind || symbolKind == UndefinedGlobalKind; | |
| 59 | 64 | } |
| 60 | 65 | |
| 61 | bool isLazy() const { return SymbolKind == LazyKind; } | |
| 66 | bool isLazy() const { return symbolKind == LazyKind; } | |
| 62 | 67 | |
| 63 | 68 | bool isLocal() const; |
| 64 | 69 | bool isWeak() const; |
| 65 | 70 | bool isHidden() const; |
| 66 | 71 | |
| 72 | // Returns true if this symbol exists in a discarded (due to COMDAT) section | |
| 73 | bool isDiscarded() const; | |
| 74 | ||
| 75 | // True if this is an undefined weak symbol. This only works once | |
| 76 | // all input files have been added. | |
| 77 | bool isUndefWeak() const { | |
| 78 | // See comment on lazy symbols for details. | |
| 79 | return isWeak() && (isUndefined() || isLazy()); | |
| 80 | } | |
| 81 | ||
| 67 | 82 | // Returns the symbol name. |
| 68 | StringRef getName() const { return Name; } | |
| 83 | StringRef getName() const { return name; } | |
| 69 | 84 | |
| 70 | 85 | // Returns the file from which this symbol was created. |
| 71 | InputFile *getFile() const { return File; } | |
| 86 | InputFile *getFile() const { return file; } | |
| 87 | ||
| 88 | uint32_t getFlags() const { return flags; } | |
| 72 | 89 | |
| 73 | 90 | InputChunk *getChunk() const; |
| 74 | 91 | |
| ... | ... | @@ -80,205 +97,249 @@ public: |
| 80 | 97 | // final image. |
| 81 | 98 | void markLive(); |
| 82 | 99 | |
| 83 | void setHidden(bool IsHidden); | |
| 100 | void setHidden(bool isHidden); | |
| 84 | 101 | |
| 85 | 102 | // Get/set the index in the output symbol table. This is only used for |
| 86 | 103 | // relocatable output. |
| 87 | 104 | uint32_t getOutputSymbolIndex() const; |
| 88 | void setOutputSymbolIndex(uint32_t Index); | |
| 105 | void setOutputSymbolIndex(uint32_t index); | |
| 89 | 106 | |
| 90 | 107 | WasmSymbolType getWasmType() const; |
| 91 | 108 | bool isExported() const; |
| 92 | 109 | |
| 93 | // True if this symbol was referenced by a regular (non-bitcode) object. | |
| 94 | unsigned IsUsedInRegularObj : 1; | |
| 95 | unsigned ForceExport : 1; | |
| 110 | const WasmSignature* getSignature() const; | |
| 111 | ||
| 112 | bool isInGOT() const { return gotIndex != INVALID_INDEX; } | |
| 113 | ||
| 114 | uint32_t getGOTIndex() const { | |
| 115 | assert(gotIndex != INVALID_INDEX); | |
| 116 | return gotIndex; | |
| 117 | } | |
| 118 | ||
| 119 | void setGOTIndex(uint32_t index); | |
| 120 | bool hasGOTIndex() const { return gotIndex != INVALID_INDEX; } | |
| 96 | 121 | |
| 97 | 122 | protected: |
| 98 | Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F) | |
| 99 | : IsUsedInRegularObj(false), ForceExport(false), Name(Name), | |
| 100 | SymbolKind(K), Flags(Flags), File(F), Referenced(!Config->GcSections) {} | |
| 101 | ||
| 102 | StringRef Name; | |
| 103 | Kind SymbolKind; | |
| 104 | uint32_t Flags; | |
| 105 | InputFile *File; | |
| 106 | uint32_t OutputSymbolIndex = INVALID_INDEX; | |
| 107 | bool Referenced; | |
| 123 | Symbol(StringRef name, Kind k, uint32_t flags, InputFile *f) | |
| 124 | : name(name), file(f), flags(flags), symbolKind(k), | |
| 125 | referenced(!config->gcSections), isUsedInRegularObj(false), | |
| 126 | forceExport(false), canInline(false), traced(false) {} | |
| 127 | ||
| 128 | StringRef name; | |
| 129 | InputFile *file; | |
| 130 | uint32_t flags; | |
| 131 | uint32_t outputSymbolIndex = INVALID_INDEX; | |
| 132 | uint32_t gotIndex = INVALID_INDEX; | |
| 133 | Kind symbolKind; | |
| 134 | ||
| 135 | public: | |
| 136 | bool referenced : 1; | |
| 137 | ||
| 138 | // True if the symbol was used for linking and thus need to be added to the | |
| 139 | // output file's symbol table. This is true for all symbols except for | |
| 140 | // unreferenced DSO symbols, lazy (archive) symbols, and bitcode symbols that | |
| 141 | // are unreferenced except by other bitcode objects. | |
| 142 | bool isUsedInRegularObj : 1; | |
| 143 | ||
| 144 | // True if ths symbol is explicity marked for export (i.e. via the -e/--export | |
| 145 | // command line flag) | |
| 146 | bool forceExport : 1; | |
| 147 | ||
| 148 | // False if LTO shouldn't inline whatever this symbol points to. If a symbol | |
| 149 | // is overwritten after LTO, LTO shouldn't inline the symbol because it | |
| 150 | // doesn't know the final contents of the symbol. | |
| 151 | bool canInline : 1; | |
| 152 | ||
| 153 | // True if this symbol is specified by --trace-symbol option. | |
| 154 | bool traced : 1; | |
| 108 | 155 | }; |
| 109 | 156 | |
| 110 | 157 | class FunctionSymbol : public Symbol { |
| 111 | 158 | public: |
| 112 | static bool classof(const Symbol *S) { | |
| 113 | return S->kind() == DefinedFunctionKind || | |
| 114 | S->kind() == UndefinedFunctionKind; | |
| 159 | static bool classof(const Symbol *s) { | |
| 160 | return s->kind() == DefinedFunctionKind || | |
| 161 | s->kind() == UndefinedFunctionKind; | |
| 115 | 162 | } |
| 116 | 163 | |
| 117 | 164 | // Get/set the table index |
| 118 | void setTableIndex(uint32_t Index); | |
| 165 | void setTableIndex(uint32_t index); | |
| 119 | 166 | uint32_t getTableIndex() const; |
| 120 | 167 | bool hasTableIndex() const; |
| 121 | 168 | |
| 122 | 169 | // Get/set the function index |
| 123 | 170 | uint32_t getFunctionIndex() const; |
| 124 | void setFunctionIndex(uint32_t Index); | |
| 171 | void setFunctionIndex(uint32_t index); | |
| 125 | 172 | bool hasFunctionIndex() const; |
| 126 | 173 | |
| 127 | const WasmSignature *Signature; | |
| 174 | const WasmSignature *signature; | |
| 128 | 175 | |
| 129 | 176 | protected: |
| 130 | FunctionSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F, | |
| 131 | const WasmSignature *Sig) | |
| 132 | : Symbol(Name, K, Flags, F), Signature(Sig) {} | |
| 177 | FunctionSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f, | |
| 178 | const WasmSignature *sig) | |
| 179 | : Symbol(name, k, flags, f), signature(sig) {} | |
| 133 | 180 | |
| 134 | uint32_t TableIndex = INVALID_INDEX; | |
| 135 | uint32_t FunctionIndex = INVALID_INDEX; | |
| 181 | uint32_t tableIndex = INVALID_INDEX; | |
| 182 | uint32_t functionIndex = INVALID_INDEX; | |
| 136 | 183 | }; |
| 137 | 184 | |
| 138 | 185 | class DefinedFunction : public FunctionSymbol { |
| 139 | 186 | public: |
| 140 | DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F, | |
| 141 | InputFunction *Function); | |
| 187 | DefinedFunction(StringRef name, uint32_t flags, InputFile *f, | |
| 188 | InputFunction *function); | |
| 142 | 189 | |
| 143 | static bool classof(const Symbol *S) { | |
| 144 | return S->kind() == DefinedFunctionKind; | |
| 190 | static bool classof(const Symbol *s) { | |
| 191 | return s->kind() == DefinedFunctionKind; | |
| 145 | 192 | } |
| 146 | 193 | |
| 147 | InputFunction *Function; | |
| 194 | InputFunction *function; | |
| 148 | 195 | }; |
| 149 | 196 | |
| 150 | 197 | class UndefinedFunction : public FunctionSymbol { |
| 151 | 198 | public: |
| 152 | UndefinedFunction(StringRef Name, StringRef ImportName, | |
| 153 | StringRef ImportModule, uint32_t Flags, | |
| 154 | InputFile *File = nullptr, | |
| 155 | const WasmSignature *Type = nullptr) | |
| 156 | : FunctionSymbol(Name, UndefinedFunctionKind, Flags, File, Type), | |
| 157 | ImportName(ImportName), ImportModule(ImportModule) {} | |
| 158 | ||
| 159 | static bool classof(const Symbol *S) { | |
| 160 | return S->kind() == UndefinedFunctionKind; | |
| 199 | UndefinedFunction(StringRef name, StringRef importName, | |
| 200 | StringRef importModule, uint32_t flags, | |
| 201 | InputFile *file = nullptr, | |
| 202 | const WasmSignature *type = nullptr, | |
| 203 | bool isCalledDirectly = true) | |
| 204 | : FunctionSymbol(name, UndefinedFunctionKind, flags, file, type), | |
| 205 | importName(importName), importModule(importModule), isCalledDirectly(isCalledDirectly) {} | |
| 206 | ||
| 207 | static bool classof(const Symbol *s) { | |
| 208 | return s->kind() == UndefinedFunctionKind; | |
| 161 | 209 | } |
| 162 | 210 | |
| 163 | StringRef ImportName; | |
| 164 | StringRef ImportModule; | |
| 211 | StringRef importName; | |
| 212 | StringRef importModule; | |
| 213 | bool isCalledDirectly; | |
| 165 | 214 | }; |
| 166 | 215 | |
| 167 | class SectionSymbol : public Symbol { | |
| 216 | // Section symbols for output sections are different from those for input | |
| 217 | // section. These are generated by the linker and point the OutputSection | |
| 218 | // rather than an InputSection. | |
| 219 | class OutputSectionSymbol : public Symbol { | |
| 168 | 220 | public: |
| 169 | static bool classof(const Symbol *S) { return S->kind() == SectionKind; } | |
| 221 | OutputSectionSymbol(const OutputSection *s) | |
| 222 | : Symbol("", OutputSectionKind, llvm::wasm::WASM_SYMBOL_BINDING_LOCAL, | |
| 223 | nullptr), | |
| 224 | section(s) {} | |
| 170 | 225 | |
| 171 | SectionSymbol(StringRef Name, uint32_t Flags, const InputSection *S, | |
| 172 | InputFile *F = nullptr) | |
| 173 | : Symbol(Name, SectionKind, Flags, F), Section(S) {} | |
| 226 | static bool classof(const Symbol *s) { | |
| 227 | return s->kind() == OutputSectionKind; | |
| 228 | } | |
| 174 | 229 | |
| 175 | const InputSection *Section; | |
| 230 | const OutputSection *section; | |
| 231 | }; | |
| 176 | 232 | |
| 177 | uint32_t getOutputSectionIndex() const; | |
| 178 | void setOutputSectionIndex(uint32_t Index); | |
| 233 | class SectionSymbol : public Symbol { | |
| 234 | public: | |
| 235 | SectionSymbol(uint32_t flags, const InputSection *s, InputFile *f = nullptr) | |
| 236 | : Symbol("", SectionKind, flags, f), section(s) {} | |
| 179 | 237 | |
| 180 | protected: | |
| 181 | uint32_t OutputSectionIndex = INVALID_INDEX; | |
| 238 | static bool classof(const Symbol *s) { return s->kind() == SectionKind; } | |
| 239 | ||
| 240 | const OutputSectionSymbol *getOutputSectionSymbol() const; | |
| 241 | ||
| 242 | const InputSection *section; | |
| 182 | 243 | }; |
| 183 | 244 | |
| 184 | 245 | class DataSymbol : public Symbol { |
| 185 | 246 | public: |
| 186 | static bool classof(const Symbol *S) { | |
| 187 | return S->kind() == DefinedDataKind || S->kind() == UndefinedDataKind; | |
| 247 | static bool classof(const Symbol *s) { | |
| 248 | return s->kind() == DefinedDataKind || s->kind() == UndefinedDataKind; | |
| 188 | 249 | } |
| 189 | 250 | |
| 190 | 251 | protected: |
| 191 | DataSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F) | |
| 192 | : Symbol(Name, K, Flags, F) {} | |
| 252 | DataSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f) | |
| 253 | : Symbol(name, k, flags, f) {} | |
| 193 | 254 | }; |
| 194 | 255 | |
| 195 | 256 | class DefinedData : public DataSymbol { |
| 196 | 257 | public: |
| 197 | 258 | // Constructor for regular data symbols originating from input files. |
| 198 | DefinedData(StringRef Name, uint32_t Flags, InputFile *F, | |
| 199 | InputSegment *Segment, uint32_t Offset, uint32_t Size) | |
| 200 | : DataSymbol(Name, DefinedDataKind, Flags, F), Segment(Segment), | |
| 201 | Offset(Offset), Size(Size) {} | |
| 259 | DefinedData(StringRef name, uint32_t flags, InputFile *f, | |
| 260 | InputSegment *segment, uint32_t offset, uint32_t size) | |
| 261 | : DataSymbol(name, DefinedDataKind, flags, f), segment(segment), | |
| 262 | offset(offset), size(size) {} | |
| 202 | 263 | |
| 203 | 264 | // Constructor for linker synthetic data symbols. |
| 204 | DefinedData(StringRef Name, uint32_t Flags) | |
| 205 | : DataSymbol(Name, DefinedDataKind, Flags, nullptr) {} | |
| 265 | DefinedData(StringRef name, uint32_t flags) | |
| 266 | : DataSymbol(name, DefinedDataKind, flags, nullptr) {} | |
| 206 | 267 | |
| 207 | static bool classof(const Symbol *S) { return S->kind() == DefinedDataKind; } | |
| 268 | static bool classof(const Symbol *s) { return s->kind() == DefinedDataKind; } | |
| 208 | 269 | |
| 209 | 270 | // Returns the output virtual address of a defined data symbol. |
| 210 | 271 | uint32_t getVirtualAddress() const; |
| 211 | void setVirtualAddress(uint32_t VA); | |
| 272 | void setVirtualAddress(uint32_t va); | |
| 212 | 273 | |
| 213 | 274 | // Returns the offset of a defined data symbol within its OutputSegment. |
| 214 | 275 | uint32_t getOutputSegmentOffset() const; |
| 215 | 276 | uint32_t getOutputSegmentIndex() const; |
| 216 | uint32_t getSize() const { return Size; } | |
| 277 | uint32_t getSize() const { return size; } | |
| 217 | 278 | |
| 218 | InputSegment *Segment = nullptr; | |
| 279 | InputSegment *segment = nullptr; | |
| 219 | 280 | |
| 220 | 281 | protected: |
| 221 | uint32_t Offset = 0; | |
| 222 | uint32_t Size = 0; | |
| 282 | uint32_t offset = 0; | |
| 283 | uint32_t size = 0; | |
| 223 | 284 | }; |
| 224 | 285 | |
| 225 | 286 | class UndefinedData : public DataSymbol { |
| 226 | 287 | public: |
| 227 | UndefinedData(StringRef Name, uint32_t Flags, InputFile *File = nullptr) | |
| 228 | : DataSymbol(Name, UndefinedDataKind, Flags, File) {} | |
| 229 | static bool classof(const Symbol *S) { | |
| 230 | return S->kind() == UndefinedDataKind; | |
| 288 | UndefinedData(StringRef name, uint32_t flags, InputFile *file = nullptr) | |
| 289 | : DataSymbol(name, UndefinedDataKind, flags, file) {} | |
| 290 | static bool classof(const Symbol *s) { | |
| 291 | return s->kind() == UndefinedDataKind; | |
| 231 | 292 | } |
| 232 | 293 | }; |
| 233 | 294 | |
| 234 | 295 | class GlobalSymbol : public Symbol { |
| 235 | 296 | public: |
| 236 | static bool classof(const Symbol *S) { | |
| 237 | return S->kind() == DefinedGlobalKind || S->kind() == UndefinedGlobalKind; | |
| 297 | static bool classof(const Symbol *s) { | |
| 298 | return s->kind() == DefinedGlobalKind || s->kind() == UndefinedGlobalKind; | |
| 238 | 299 | } |
| 239 | 300 | |
| 240 | const WasmGlobalType *getGlobalType() const { return GlobalType; } | |
| 301 | const WasmGlobalType *getGlobalType() const { return globalType; } | |
| 241 | 302 | |
| 242 | 303 | // Get/set the global index |
| 243 | 304 | uint32_t getGlobalIndex() const; |
| 244 | void setGlobalIndex(uint32_t Index); | |
| 305 | void setGlobalIndex(uint32_t index); | |
| 245 | 306 | bool hasGlobalIndex() const; |
| 246 | 307 | |
| 247 | 308 | protected: |
| 248 | GlobalSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F, | |
| 249 | const WasmGlobalType *GlobalType) | |
| 250 | : Symbol(Name, K, Flags, F), GlobalType(GlobalType) {} | |
| 309 | GlobalSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f, | |
| 310 | const WasmGlobalType *globalType) | |
| 311 | : Symbol(name, k, flags, f), globalType(globalType) {} | |
| 251 | 312 | |
| 252 | const WasmGlobalType *GlobalType; | |
| 253 | uint32_t GlobalIndex = INVALID_INDEX; | |
| 313 | const WasmGlobalType *globalType; | |
| 314 | uint32_t globalIndex = INVALID_INDEX; | |
| 254 | 315 | }; |
| 255 | 316 | |
| 256 | 317 | class DefinedGlobal : public GlobalSymbol { |
| 257 | 318 | public: |
| 258 | DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File, | |
| 259 | InputGlobal *Global); | |
| 319 | DefinedGlobal(StringRef name, uint32_t flags, InputFile *file, | |
| 320 | InputGlobal *global); | |
| 260 | 321 | |
| 261 | static bool classof(const Symbol *S) { | |
| 262 | return S->kind() == DefinedGlobalKind; | |
| 322 | static bool classof(const Symbol *s) { | |
| 323 | return s->kind() == DefinedGlobalKind; | |
| 263 | 324 | } |
| 264 | 325 | |
| 265 | InputGlobal *Global; | |
| 326 | InputGlobal *global; | |
| 266 | 327 | }; |
| 267 | 328 | |
| 268 | 329 | class UndefinedGlobal : public GlobalSymbol { |
| 269 | 330 | public: |
| 270 | UndefinedGlobal(StringRef Name, StringRef ImportName, StringRef ImportModule, | |
| 271 | uint32_t Flags, InputFile *File = nullptr, | |
| 272 | const WasmGlobalType *Type = nullptr) | |
| 273 | : GlobalSymbol(Name, UndefinedGlobalKind, Flags, File, Type), | |
| 274 | ImportName(ImportName), ImportModule(ImportModule) {} | |
| 275 | ||
| 276 | static bool classof(const Symbol *S) { | |
| 277 | return S->kind() == UndefinedGlobalKind; | |
| 331 | UndefinedGlobal(StringRef name, StringRef importName, StringRef importModule, | |
| 332 | uint32_t flags, InputFile *file = nullptr, | |
| 333 | const WasmGlobalType *type = nullptr) | |
| 334 | : GlobalSymbol(name, UndefinedGlobalKind, flags, file, type), | |
| 335 | importName(importName), importModule(importModule) {} | |
| 336 | ||
| 337 | static bool classof(const Symbol *s) { | |
| 338 | return s->kind() == UndefinedGlobalKind; | |
| 278 | 339 | } |
| 279 | 340 | |
| 280 | StringRef ImportName; | |
| 281 | StringRef ImportModule; | |
| 341 | StringRef importName; | |
| 342 | StringRef importModule; | |
| 282 | 343 | }; |
| 283 | 344 | |
| 284 | 345 | // Wasm events are features that suspend the current execution and transfer the |
| ... | ... | @@ -295,100 +356,149 @@ public: |
| 295 | 356 | // are used, and has name '__cpp_exception' for linking. |
| 296 | 357 | class EventSymbol : public Symbol { |
| 297 | 358 | public: |
| 298 | static bool classof(const Symbol *S) { return S->kind() == DefinedEventKind; } | |
| 359 | static bool classof(const Symbol *s) { return s->kind() == DefinedEventKind; } | |
| 299 | 360 | |
| 300 | const WasmEventType *getEventType() const { return EventType; } | |
| 361 | const WasmEventType *getEventType() const { return eventType; } | |
| 301 | 362 | |
| 302 | 363 | // Get/set the event index |
| 303 | 364 | uint32_t getEventIndex() const; |
| 304 | void setEventIndex(uint32_t Index); | |
| 365 | void setEventIndex(uint32_t index); | |
| 305 | 366 | bool hasEventIndex() const; |
| 306 | 367 | |
| 307 | const WasmSignature *Signature; | |
| 368 | const WasmSignature *signature; | |
| 308 | 369 | |
| 309 | 370 | protected: |
| 310 | EventSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F, | |
| 311 | const WasmEventType *EventType, const WasmSignature *Sig) | |
| 312 | : Symbol(Name, K, Flags, F), Signature(Sig), EventType(EventType) {} | |
| 371 | EventSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f, | |
| 372 | const WasmEventType *eventType, const WasmSignature *sig) | |
| 373 | : Symbol(name, k, flags, f), signature(sig), eventType(eventType) {} | |
| 313 | 374 | |
| 314 | const WasmEventType *EventType; | |
| 315 | uint32_t EventIndex = INVALID_INDEX; | |
| 375 | const WasmEventType *eventType; | |
| 376 | uint32_t eventIndex = INVALID_INDEX; | |
| 316 | 377 | }; |
| 317 | 378 | |
| 318 | 379 | class DefinedEvent : public EventSymbol { |
| 319 | 380 | public: |
| 320 | DefinedEvent(StringRef Name, uint32_t Flags, InputFile *File, | |
| 321 | InputEvent *Event); | |
| 381 | DefinedEvent(StringRef name, uint32_t flags, InputFile *file, | |
| 382 | InputEvent *event); | |
| 322 | 383 | |
| 323 | static bool classof(const Symbol *S) { return S->kind() == DefinedEventKind; } | |
| 384 | static bool classof(const Symbol *s) { return s->kind() == DefinedEventKind; } | |
| 324 | 385 | |
| 325 | InputEvent *Event; | |
| 386 | InputEvent *event; | |
| 326 | 387 | }; |
| 327 | 388 | |
| 389 | // LazySymbol represents a symbol that is not yet in the link, but we know where | |
| 390 | // to find it if needed. If the resolver finds both Undefined and Lazy for the | |
| 391 | // same name, it will ask the Lazy to load a file. | |
| 392 | // | |
| 393 | // A special complication is the handling of weak undefined symbols. They should | |
| 394 | // not load a file, but we have to remember we have seen both the weak undefined | |
| 395 | // and the lazy. We represent that with a lazy symbol with a weak binding. This | |
| 396 | // means that code looking for undefined symbols normally also has to take lazy | |
| 397 | // symbols into consideration. | |
| 328 | 398 | class LazySymbol : public Symbol { |
| 329 | 399 | public: |
| 330 | LazySymbol(StringRef Name, InputFile *File, | |
| 331 | const llvm::object::Archive::Symbol &Sym) | |
| 332 | : Symbol(Name, LazyKind, 0, File), ArchiveSymbol(Sym) {} | |
| 400 | LazySymbol(StringRef name, uint32_t flags, InputFile *file, | |
| 401 | const llvm::object::Archive::Symbol &sym) | |
| 402 | : Symbol(name, LazyKind, flags, file), archiveSymbol(sym) {} | |
| 333 | 403 | |
| 334 | static bool classof(const Symbol *S) { return S->kind() == LazyKind; } | |
| 404 | static bool classof(const Symbol *s) { return s->kind() == LazyKind; } | |
| 335 | 405 | void fetch(); |
| 336 | 406 | |
| 407 | // Lazy symbols can have a signature because they can replace an | |
| 408 | // UndefinedFunction which which case we need to be able to preserve the | |
| 409 | // signture. | |
| 410 | // TODO(sbc): This repetition of the signature field is inelegant. Revisit | |
| 411 | // the use of class hierarchy to represent symbol taxonomy. | |
| 412 | const WasmSignature *signature = nullptr; | |
| 413 | ||
| 337 | 414 | private: |
| 338 | llvm::object::Archive::Symbol ArchiveSymbol; | |
| 415 | llvm::object::Archive::Symbol archiveSymbol; | |
| 339 | 416 | }; |
| 340 | 417 | |
| 341 | 418 | // linker-generated symbols |
| 342 | 419 | struct WasmSym { |
| 420 | // __global_base | |
| 421 | // Symbol marking the start of the global section. | |
| 422 | static DefinedData *globalBase; | |
| 423 | ||
| 343 | 424 | // __stack_pointer |
| 344 | 425 | // Global that holds the address of the top of the explicit value stack in |
| 345 | 426 | // linear memory. |
| 346 | static GlobalSymbol *StackPointer; | |
| 427 | static GlobalSymbol *stackPointer; | |
| 428 | ||
| 429 | // __tls_base | |
| 430 | // Global that holds the address of the base of the current thread's | |
| 431 | // TLS block. | |
| 432 | static GlobalSymbol *tlsBase; | |
| 433 | ||
| 434 | // __tls_size | |
| 435 | // Symbol whose value is the size of the TLS block. | |
| 436 | static GlobalSymbol *tlsSize; | |
| 347 | 437 | |
| 348 | 438 | // __data_end |
| 349 | 439 | // Symbol marking the end of the data and bss. |
| 350 | static DefinedData *DataEnd; | |
| 440 | static DefinedData *dataEnd; | |
| 351 | 441 | |
| 352 | 442 | // __heap_base |
| 353 | 443 | // Symbol marking the end of the data, bss and explicit stack. Any linear |
| 354 | 444 | // memory following this address is not used by the linked code and can |
| 355 | 445 | // therefore be used as a backing store for brk()/malloc() implementations. |
| 356 | static DefinedData *HeapBase; | |
| 446 | static DefinedData *heapBase; | |
| 357 | 447 | |
| 358 | 448 | // __wasm_call_ctors |
| 359 | 449 | // Function that directly calls all ctors in priority order. |
| 360 | static DefinedFunction *CallCtors; | |
| 450 | static DefinedFunction *callCtors; | |
| 451 | ||
| 452 | // __wasm_init_memory | |
| 453 | // Function that initializes passive data segments post-instantiation. | |
| 454 | static DefinedFunction *initMemory; | |
| 455 | ||
| 456 | // __wasm_apply_relocs | |
| 457 | // Function that applies relocations to data segment post-instantiation. | |
| 458 | static DefinedFunction *applyRelocs; | |
| 459 | ||
| 460 | // __wasm_init_tls | |
| 461 | // Function that allocates thread-local storage and initializes it. | |
| 462 | static DefinedFunction *initTLS; | |
| 361 | 463 | |
| 362 | 464 | // __dso_handle |
| 363 | 465 | // Symbol used in calls to __cxa_atexit to determine current DLL |
| 364 | static DefinedData *DsoHandle; | |
| 466 | static DefinedData *dsoHandle; | |
| 365 | 467 | |
| 366 | 468 | // __table_base |
| 367 | 469 | // Used in PIC code for offset of indirect function table |
| 368 | static UndefinedGlobal *TableBase; | |
| 470 | static UndefinedGlobal *tableBase; | |
| 369 | 471 | |
| 370 | 472 | // __memory_base |
| 371 | 473 | // Used in PIC code for offset of global data |
| 372 | static UndefinedGlobal *MemoryBase; | |
| 474 | static UndefinedGlobal *memoryBase; | |
| 373 | 475 | }; |
| 374 | 476 | |
| 375 | 477 | // A buffer class that is large enough to hold any Symbol-derived |
| 376 | 478 | // object. We allocate memory using this class and instantiate a symbol |
| 377 | 479 | // using the placement new. |
| 378 | 480 | union SymbolUnion { |
| 379 | alignas(DefinedFunction) char A[sizeof(DefinedFunction)]; | |
| 380 | alignas(DefinedData) char B[sizeof(DefinedData)]; | |
| 381 | alignas(DefinedGlobal) char C[sizeof(DefinedGlobal)]; | |
| 382 | alignas(DefinedEvent) char D[sizeof(DefinedEvent)]; | |
| 383 | alignas(LazySymbol) char E[sizeof(LazySymbol)]; | |
| 384 | alignas(UndefinedFunction) char F[sizeof(UndefinedFunction)]; | |
| 385 | alignas(UndefinedData) char G[sizeof(UndefinedData)]; | |
| 386 | alignas(UndefinedGlobal) char H[sizeof(UndefinedGlobal)]; | |
| 387 | alignas(SectionSymbol) char I[sizeof(SectionSymbol)]; | |
| 481 | alignas(DefinedFunction) char a[sizeof(DefinedFunction)]; | |
| 482 | alignas(DefinedData) char b[sizeof(DefinedData)]; | |
| 483 | alignas(DefinedGlobal) char c[sizeof(DefinedGlobal)]; | |
| 484 | alignas(DefinedEvent) char d[sizeof(DefinedEvent)]; | |
| 485 | alignas(LazySymbol) char e[sizeof(LazySymbol)]; | |
| 486 | alignas(UndefinedFunction) char f[sizeof(UndefinedFunction)]; | |
| 487 | alignas(UndefinedData) char g[sizeof(UndefinedData)]; | |
| 488 | alignas(UndefinedGlobal) char h[sizeof(UndefinedGlobal)]; | |
| 489 | alignas(SectionSymbol) char i[sizeof(SectionSymbol)]; | |
| 388 | 490 | }; |
| 389 | 491 | |
| 492 | // It is important to keep the size of SymbolUnion small for performance and | |
| 493 | // memory usage reasons. 96 bytes is a soft limit based on the size of | |
| 494 | // UndefinedFunction on a 64-bit system. | |
| 495 | static_assert(sizeof(SymbolUnion) <= 96, "SymbolUnion too large"); | |
| 496 | ||
| 497 | void printTraceSymbol(Symbol *sym); | |
| 498 | void printTraceSymbolUndefined(StringRef name, const InputFile* file); | |
| 499 | ||
| 390 | 500 | template <typename T, typename... ArgT> |
| 391 | T *replaceSymbol(Symbol *S, ArgT &&... Arg) { | |
| 501 | T *replaceSymbol(Symbol *s, ArgT &&... arg) { | |
| 392 | 502 | static_assert(std::is_trivially_destructible<T>(), |
| 393 | 503 | "Symbol types must be trivially destructible"); |
| 394 | 504 | static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small"); |
| ... | ... | @@ -397,20 +507,28 @@ T *replaceSymbol(Symbol *S, ArgT &&... Arg) { |
| 397 | 507 | assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr && |
| 398 | 508 | "Not a Symbol"); |
| 399 | 509 | |
| 400 | Symbol SymCopy = *S; | |
| 510 | Symbol symCopy = *s; | |
| 511 | ||
| 512 | T *s2 = new (s) T(std::forward<ArgT>(arg)...); | |
| 513 | s2->isUsedInRegularObj = symCopy.isUsedInRegularObj; | |
| 514 | s2->forceExport = symCopy.forceExport; | |
| 515 | s2->canInline = symCopy.canInline; | |
| 516 | s2->traced = symCopy.traced; | |
| 517 | ||
| 518 | // Print out a log message if --trace-symbol was specified. | |
| 519 | // This is for debugging. | |
| 520 | if (s2->traced) | |
| 521 | printTraceSymbol(s2); | |
| 401 | 522 | |
| 402 | T *S2 = new (S) T(std::forward<ArgT>(Arg)...); | |
| 403 | S2->IsUsedInRegularObj = SymCopy.IsUsedInRegularObj; | |
| 404 | S2->ForceExport = SymCopy.ForceExport; | |
| 405 | return S2; | |
| 523 | return s2; | |
| 406 | 524 | } |
| 407 | 525 | |
| 408 | 526 | } // namespace wasm |
| 409 | 527 | |
| 410 | 528 | // Returns a symbol name for an error message. |
| 411 | std::string toString(const wasm::Symbol &Sym); | |
| 412 | std::string toString(wasm::Symbol::Kind Kind); | |
| 413 | std::string maybeDemangleSymbol(StringRef Name); | |
| 529 | std::string toString(const wasm::Symbol &sym); | |
| 530 | std::string toString(wasm::Symbol::Kind kind); | |
| 531 | std::string maybeDemangleSymbol(StringRef name); | |
| 414 | 532 | |
| 415 | 533 | } // namespace lld |
| 416 | 534 |
deps/lld/wasm/SyntheticSections.cpp created+547| ... | ... | @@ -0,0 +1,547 @@ |
| 1 | //===- SyntheticSections.cpp ----------------------------------------------===// | |
| 2 | // | |
| 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 | |
| 6 | // | |
| 7 | //===----------------------------------------------------------------------===// | |
| 8 | // | |
| 9 | // This file contains linker-synthesized sections. | |
| 10 | // | |
| 11 | //===----------------------------------------------------------------------===// | |
| 12 | ||
| 13 | #include "SyntheticSections.h" | |
| 14 | ||
| 15 | #include "InputChunks.h" | |
| 16 | #include "InputEvent.h" | |
| 17 | #include "InputGlobal.h" | |
| 18 | #include "OutputSegment.h" | |
| 19 | #include "SymbolTable.h" | |
| 20 | #include "llvm/Support/Path.h" | |
| 21 | ||
| 22 | using namespace llvm; | |
| 23 | using namespace llvm::wasm; | |
| 24 | ||
| 25 | using namespace lld; | |
| 26 | using namespace lld::wasm; | |
| 27 | ||
| 28 | OutStruct lld::wasm::out; | |
| 29 | ||
| 30 | namespace { | |
| 31 | ||
| 32 | // Some synthetic sections (e.g. "name" and "linking") have subsections. | |
| 33 | // Just like the synthetic sections themselves these need to be created before | |
| 34 | // they can be written out (since they are preceded by their length). This | |
| 35 | // class is used to create subsections and then write them into the stream | |
| 36 | // of the parent section. | |
| 37 | class SubSection { | |
| 38 | public: | |
| 39 | explicit SubSection(uint32_t type) : type(type) {} | |
| 40 | ||
| 41 | void writeTo(raw_ostream &to) { | |
| 42 | os.flush(); | |
| 43 | writeUleb128(to, type, "subsection type"); | |
| 44 | writeUleb128(to, body.size(), "subsection size"); | |
| 45 | to.write(body.data(), body.size()); | |
| 46 | } | |
| 47 | ||
| 48 | private: | |
| 49 | uint32_t type; | |
| 50 | std::string body; | |
| 51 | ||
| 52 | public: | |
| 53 | raw_string_ostream os{body}; | |
| 54 | }; | |
| 55 | ||
| 56 | } // namespace | |
| 57 | ||
| 58 | void DylinkSection::writeBody() { | |
| 59 | raw_ostream &os = bodyOutputStream; | |
| 60 | ||
| 61 | writeUleb128(os, memSize, "MemSize"); | |
| 62 | writeUleb128(os, memAlign, "MemAlign"); | |
| 63 | writeUleb128(os, out.elemSec->numEntries(), "TableSize"); | |
| 64 | writeUleb128(os, 0, "TableAlign"); | |
| 65 | writeUleb128(os, symtab->sharedFiles.size(), "Needed"); | |
| 66 | for (auto *so : symtab->sharedFiles) | |
| 67 | writeStr(os, llvm::sys::path::filename(so->getName()), "so name"); | |
| 68 | } | |
| 69 | ||
| 70 | uint32_t TypeSection::registerType(const WasmSignature &sig) { | |
| 71 | auto pair = typeIndices.insert(std::make_pair(sig, types.size())); | |
| 72 | if (pair.second) { | |
| 73 | LLVM_DEBUG(llvm::dbgs() << "type " << toString(sig) << "\n"); | |
| 74 | types.push_back(&sig); | |
| 75 | } | |
| 76 | return pair.first->second; | |
| 77 | } | |
| 78 | ||
| 79 | uint32_t TypeSection::lookupType(const WasmSignature &sig) { | |
| 80 | auto it = typeIndices.find(sig); | |
| 81 | if (it == typeIndices.end()) { | |
| 82 | error("type not found: " + toString(sig)); | |
| 83 | return 0; | |
| 84 | } | |
| 85 | return it->second; | |
| 86 | } | |
| 87 | ||
| 88 | void TypeSection::writeBody() { | |
| 89 | writeUleb128(bodyOutputStream, types.size(), "type count"); | |
| 90 | for (const WasmSignature *sig : types) | |
| 91 | writeSig(bodyOutputStream, *sig); | |
| 92 | } | |
| 93 | ||
| 94 | uint32_t ImportSection::getNumImports() const { | |
| 95 | assert(isSealed); | |
| 96 | uint32_t numImports = importedSymbols.size() + gotSymbols.size(); | |
| 97 | if (config->importMemory) | |
| 98 | ++numImports; | |
| 99 | if (config->importTable) | |
| 100 | ++numImports; | |
| 101 | return numImports; | |
| 102 | } | |
| 103 | ||
| 104 | void ImportSection::addGOTEntry(Symbol *sym) { | |
| 105 | assert(!isSealed); | |
| 106 | if (sym->hasGOTIndex()) | |
| 107 | return; | |
| 108 | sym->setGOTIndex(numImportedGlobals++); | |
| 109 | gotSymbols.push_back(sym); | |
| 110 | } | |
| 111 | ||
| 112 | void ImportSection::addImport(Symbol *sym) { | |
| 113 | assert(!isSealed); | |
| 114 | importedSymbols.emplace_back(sym); | |
| 115 | if (auto *f = dyn_cast<FunctionSymbol>(sym)) | |
| 116 | f->setFunctionIndex(numImportedFunctions++); | |
| 117 | else if (auto *g = dyn_cast<GlobalSymbol>(sym)) | |
| 118 | g->setGlobalIndex(numImportedGlobals++); | |
| 119 | else | |
| 120 | cast<EventSymbol>(sym)->setEventIndex(numImportedEvents++); | |
| 121 | } | |
| 122 | ||
| 123 | void ImportSection::writeBody() { | |
| 124 | raw_ostream &os = bodyOutputStream; | |
| 125 | ||
| 126 | writeUleb128(os, getNumImports(), "import count"); | |
| 127 | ||
| 128 | if (config->importMemory) { | |
| 129 | WasmImport import; | |
| 130 | import.Module = defaultModule; | |
| 131 | import.Field = "memory"; | |
| 132 | import.Kind = WASM_EXTERNAL_MEMORY; | |
| 133 | import.Memory.Flags = 0; | |
| 134 | import.Memory.Initial = out.memorySec->numMemoryPages; | |
| 135 | if (out.memorySec->maxMemoryPages != 0 || config->sharedMemory) { | |
| 136 | import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX; | |
| 137 | import.Memory.Maximum = out.memorySec->maxMemoryPages; | |
| 138 | } | |
| 139 | if (config->sharedMemory) | |
| 140 | import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED; | |
| 141 | writeImport(os, import); | |
| 142 | } | |
| 143 | ||
| 144 | if (config->importTable) { | |
| 145 | uint32_t tableSize = out.elemSec->elemOffset + out.elemSec->numEntries(); | |
| 146 | WasmImport import; | |
| 147 | import.Module = defaultModule; | |
| 148 | import.Field = functionTableName; | |
| 149 | import.Kind = WASM_EXTERNAL_TABLE; | |
| 150 | import.Table.ElemType = WASM_TYPE_FUNCREF; | |
| 151 | import.Table.Limits = {0, tableSize, 0}; | |
| 152 | writeImport(os, import); | |
| 153 | } | |
| 154 | ||
| 155 | for (const Symbol *sym : importedSymbols) { | |
| 156 | WasmImport import; | |
| 157 | if (auto *f = dyn_cast<UndefinedFunction>(sym)) { | |
| 158 | import.Field = f->importName; | |
| 159 | import.Module = f->importModule; | |
| 160 | } else if (auto *g = dyn_cast<UndefinedGlobal>(sym)) { | |
| 161 | import.Field = g->importName; | |
| 162 | import.Module = g->importModule; | |
| 163 | } else { | |
| 164 | import.Field = sym->getName(); | |
| 165 | import.Module = defaultModule; | |
| 166 | } | |
| 167 | ||
| 168 | if (auto *functionSym = dyn_cast<FunctionSymbol>(sym)) { | |
| 169 | import.Kind = WASM_EXTERNAL_FUNCTION; | |
| 170 | import.SigIndex = out.typeSec->lookupType(*functionSym->signature); | |
| 171 | } else if (auto *globalSym = dyn_cast<GlobalSymbol>(sym)) { | |
| 172 | import.Kind = WASM_EXTERNAL_GLOBAL; | |
| 173 | import.Global = *globalSym->getGlobalType(); | |
| 174 | } else { | |
| 175 | auto *eventSym = cast<EventSymbol>(sym); | |
| 176 | import.Kind = WASM_EXTERNAL_EVENT; | |
| 177 | import.Event.Attribute = eventSym->getEventType()->Attribute; | |
| 178 | import.Event.SigIndex = out.typeSec->lookupType(*eventSym->signature); | |
| 179 | } | |
| 180 | writeImport(os, import); | |
| 181 | } | |
| 182 | ||
| 183 | for (const Symbol *sym : gotSymbols) { | |
| 184 | WasmImport import; | |
| 185 | import.Kind = WASM_EXTERNAL_GLOBAL; | |
| 186 | import.Global = {WASM_TYPE_I32, true}; | |
| 187 | if (isa<DataSymbol>(sym)) | |
| 188 | import.Module = "GOT.mem"; | |
| 189 | else | |
| 190 | import.Module = "GOT.func"; | |
| 191 | import.Field = sym->getName(); | |
| 192 | writeImport(os, import); | |
| 193 | } | |
| 194 | } | |
| 195 | ||
| 196 | void FunctionSection::writeBody() { | |
| 197 | raw_ostream &os = bodyOutputStream; | |
| 198 | ||
| 199 | writeUleb128(os, inputFunctions.size(), "function count"); | |
| 200 | for (const InputFunction *func : inputFunctions) | |
| 201 | writeUleb128(os, out.typeSec->lookupType(func->signature), "sig index"); | |
| 202 | } | |
| 203 | ||
| 204 | void FunctionSection::addFunction(InputFunction *func) { | |
| 205 | if (!func->live) | |
| 206 | return; | |
| 207 | uint32_t functionIndex = | |
| 208 | out.importSec->getNumImportedFunctions() + inputFunctions.size(); | |
| 209 | inputFunctions.emplace_back(func); | |
| 210 | func->setFunctionIndex(functionIndex); | |
| 211 | } | |
| 212 | ||
| 213 | void TableSection::writeBody() { | |
| 214 | uint32_t tableSize = out.elemSec->elemOffset + out.elemSec->numEntries(); | |
| 215 | ||
| 216 | raw_ostream &os = bodyOutputStream; | |
| 217 | writeUleb128(os, 1, "table count"); | |
| 218 | WasmLimits limits = {WASM_LIMITS_FLAG_HAS_MAX, tableSize, tableSize}; | |
| 219 | writeTableType(os, WasmTable{WASM_TYPE_FUNCREF, limits}); | |
| 220 | } | |
| 221 | ||
| 222 | void MemorySection::writeBody() { | |
| 223 | raw_ostream &os = bodyOutputStream; | |
| 224 | ||
| 225 | bool hasMax = maxMemoryPages != 0 || config->sharedMemory; | |
| 226 | writeUleb128(os, 1, "memory count"); | |
| 227 | unsigned flags = 0; | |
| 228 | if (hasMax) | |
| 229 | flags |= WASM_LIMITS_FLAG_HAS_MAX; | |
| 230 | if (config->sharedMemory) | |
| 231 | flags |= WASM_LIMITS_FLAG_IS_SHARED; | |
| 232 | writeUleb128(os, flags, "memory limits flags"); | |
| 233 | writeUleb128(os, numMemoryPages, "initial pages"); | |
| 234 | if (hasMax) | |
| 235 | writeUleb128(os, maxMemoryPages, "max pages"); | |
| 236 | } | |
| 237 | ||
| 238 | void GlobalSection::writeBody() { | |
| 239 | raw_ostream &os = bodyOutputStream; | |
| 240 | ||
| 241 | writeUleb128(os, numGlobals(), "global count"); | |
| 242 | for (const InputGlobal *g : inputGlobals) | |
| 243 | writeGlobal(os, g->global); | |
| 244 | for (const DefinedData *sym : definedFakeGlobals) { | |
| 245 | WasmGlobal global; | |
| 246 | global.Type = {WASM_TYPE_I32, false}; | |
| 247 | global.InitExpr.Opcode = WASM_OPCODE_I32_CONST; | |
| 248 | global.InitExpr.Value.Int32 = sym->getVirtualAddress(); | |
| 249 | writeGlobal(os, global); | |
| 250 | } | |
| 251 | } | |
| 252 | ||
| 253 | void GlobalSection::addGlobal(InputGlobal *global) { | |
| 254 | if (!global->live) | |
| 255 | return; | |
| 256 | uint32_t globalIndex = | |
| 257 | out.importSec->getNumImportedGlobals() + inputGlobals.size(); | |
| 258 | LLVM_DEBUG(dbgs() << "addGlobal: " << globalIndex << "\n"); | |
| 259 | global->setGlobalIndex(globalIndex); | |
| 260 | out.globalSec->inputGlobals.push_back(global); | |
| 261 | } | |
| 262 | ||
| 263 | void EventSection::writeBody() { | |
| 264 | raw_ostream &os = bodyOutputStream; | |
| 265 | ||
| 266 | writeUleb128(os, inputEvents.size(), "event count"); | |
| 267 | for (InputEvent *e : inputEvents) { | |
| 268 | e->event.Type.SigIndex = out.typeSec->lookupType(e->signature); | |
| 269 | writeEvent(os, e->event); | |
| 270 | } | |
| 271 | } | |
| 272 | ||
| 273 | void EventSection::addEvent(InputEvent *event) { | |
| 274 | if (!event->live) | |
| 275 | return; | |
| 276 | uint32_t eventIndex = | |
| 277 | out.importSec->getNumImportedEvents() + inputEvents.size(); | |
| 278 | LLVM_DEBUG(dbgs() << "addEvent: " << eventIndex << "\n"); | |
| 279 | event->setEventIndex(eventIndex); | |
| 280 | inputEvents.push_back(event); | |
| 281 | } | |
| 282 | ||
| 283 | void ExportSection::writeBody() { | |
| 284 | raw_ostream &os = bodyOutputStream; | |
| 285 | ||
| 286 | writeUleb128(os, exports.size(), "export count"); | |
| 287 | for (const WasmExport &export_ : exports) | |
| 288 | writeExport(os, export_); | |
| 289 | } | |
| 290 | ||
| 291 | void ElemSection::addEntry(FunctionSymbol *sym) { | |
| 292 | if (sym->hasTableIndex()) | |
| 293 | return; | |
| 294 | sym->setTableIndex(elemOffset + indirectFunctions.size()); | |
| 295 | indirectFunctions.emplace_back(sym); | |
| 296 | } | |
| 297 | ||
| 298 | void ElemSection::writeBody() { | |
| 299 | raw_ostream &os = bodyOutputStream; | |
| 300 | ||
| 301 | writeUleb128(os, 1, "segment count"); | |
| 302 | writeUleb128(os, 0, "table index"); | |
| 303 | WasmInitExpr initExpr; | |
| 304 | if (config->isPic) { | |
| 305 | initExpr.Opcode = WASM_OPCODE_GLOBAL_GET; | |
| 306 | initExpr.Value.Global = WasmSym::tableBase->getGlobalIndex(); | |
| 307 | } else { | |
| 308 | initExpr.Opcode = WASM_OPCODE_I32_CONST; | |
| 309 | initExpr.Value.Int32 = elemOffset; | |
| 310 | } | |
| 311 | writeInitExpr(os, initExpr); | |
| 312 | writeUleb128(os, indirectFunctions.size(), "elem count"); | |
| 313 | ||
| 314 | uint32_t tableIndex = elemOffset; | |
| 315 | for (const FunctionSymbol *sym : indirectFunctions) { | |
| 316 | assert(sym->getTableIndex() == tableIndex); | |
| 317 | writeUleb128(os, sym->getFunctionIndex(), "function index"); | |
| 318 | ++tableIndex; | |
| 319 | } | |
| 320 | } | |
| 321 | ||
| 322 | void DataCountSection::writeBody() { | |
| 323 | writeUleb128(bodyOutputStream, numSegments, "data count"); | |
| 324 | } | |
| 325 | ||
| 326 | bool DataCountSection::isNeeded() const { | |
| 327 | return numSegments && config->passiveSegments; | |
| 328 | } | |
| 329 | ||
| 330 | static uint32_t getWasmFlags(const Symbol *sym) { | |
| 331 | uint32_t flags = 0; | |
| 332 | if (sym->isLocal()) | |
| 333 | flags |= WASM_SYMBOL_BINDING_LOCAL; | |
| 334 | if (sym->isWeak()) | |
| 335 | flags |= WASM_SYMBOL_BINDING_WEAK; | |
| 336 | if (sym->isHidden()) | |
| 337 | flags |= WASM_SYMBOL_VISIBILITY_HIDDEN; | |
| 338 | if (sym->isUndefined()) | |
| 339 | flags |= WASM_SYMBOL_UNDEFINED; | |
| 340 | if (auto *f = dyn_cast<UndefinedFunction>(sym)) { | |
| 341 | if (f->getName() != f->importName) | |
| 342 | flags |= WASM_SYMBOL_EXPLICIT_NAME; | |
| 343 | } else if (auto *g = dyn_cast<UndefinedGlobal>(sym)) { | |
| 344 | if (g->getName() != g->importName) | |
| 345 | flags |= WASM_SYMBOL_EXPLICIT_NAME; | |
| 346 | } | |
| 347 | return flags; | |
| 348 | } | |
| 349 | ||
| 350 | void LinkingSection::writeBody() { | |
| 351 | raw_ostream &os = bodyOutputStream; | |
| 352 | ||
| 353 | writeUleb128(os, WasmMetadataVersion, "Version"); | |
| 354 | ||
| 355 | if (!symtabEntries.empty()) { | |
| 356 | SubSection sub(WASM_SYMBOL_TABLE); | |
| 357 | writeUleb128(sub.os, symtabEntries.size(), "num symbols"); | |
| 358 | ||
| 359 | for (const Symbol *sym : symtabEntries) { | |
| 360 | assert(sym->isDefined() || sym->isUndefined()); | |
| 361 | WasmSymbolType kind = sym->getWasmType(); | |
| 362 | uint32_t flags = getWasmFlags(sym); | |
| 363 | ||
| 364 | writeU8(sub.os, kind, "sym kind"); | |
| 365 | writeUleb128(sub.os, flags, "sym flags"); | |
| 366 | ||
| 367 | if (auto *f = dyn_cast<FunctionSymbol>(sym)) { | |
| 368 | writeUleb128(sub.os, f->getFunctionIndex(), "index"); | |
| 369 | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) | |
| 370 | writeStr(sub.os, sym->getName(), "sym name"); | |
| 371 | } else if (auto *g = dyn_cast<GlobalSymbol>(sym)) { | |
| 372 | writeUleb128(sub.os, g->getGlobalIndex(), "index"); | |
| 373 | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) | |
| 374 | writeStr(sub.os, sym->getName(), "sym name"); | |
| 375 | } else if (auto *e = dyn_cast<EventSymbol>(sym)) { | |
| 376 | writeUleb128(sub.os, e->getEventIndex(), "index"); | |
| 377 | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) | |
| 378 | writeStr(sub.os, sym->getName(), "sym name"); | |
| 379 | } else if (isa<DataSymbol>(sym)) { | |
| 380 | writeStr(sub.os, sym->getName(), "sym name"); | |
| 381 | if (auto *dataSym = dyn_cast<DefinedData>(sym)) { | |
| 382 | writeUleb128(sub.os, dataSym->getOutputSegmentIndex(), "index"); | |
| 383 | writeUleb128(sub.os, dataSym->getOutputSegmentOffset(), | |
| 384 | "data offset"); | |
| 385 | writeUleb128(sub.os, dataSym->getSize(), "data size"); | |
| 386 | } | |
| 387 | } else { | |
| 388 | auto *s = cast<OutputSectionSymbol>(sym); | |
| 389 | writeUleb128(sub.os, s->section->sectionIndex, "sym section index"); | |
| 390 | } | |
| 391 | } | |
| 392 | ||
| 393 | sub.writeTo(os); | |
| 394 | } | |
| 395 | ||
| 396 | if (dataSegments.size()) { | |
| 397 | SubSection sub(WASM_SEGMENT_INFO); | |
| 398 | writeUleb128(sub.os, dataSegments.size(), "num data segments"); | |
| 399 | for (const OutputSegment *s : dataSegments) { | |
| 400 | writeStr(sub.os, s->name, "segment name"); | |
| 401 | writeUleb128(sub.os, s->alignment, "alignment"); | |
| 402 | writeUleb128(sub.os, 0, "flags"); | |
| 403 | } | |
| 404 | sub.writeTo(os); | |
| 405 | } | |
| 406 | ||
| 407 | if (!initFunctions.empty()) { | |
| 408 | SubSection sub(WASM_INIT_FUNCS); | |
| 409 | writeUleb128(sub.os, initFunctions.size(), "num init functions"); | |
| 410 | for (const WasmInitEntry &f : initFunctions) { | |
| 411 | writeUleb128(sub.os, f.priority, "priority"); | |
| 412 | writeUleb128(sub.os, f.sym->getOutputSymbolIndex(), "function index"); | |
| 413 | } | |
| 414 | sub.writeTo(os); | |
| 415 | } | |
| 416 | ||
| 417 | struct ComdatEntry { | |
| 418 | unsigned kind; | |
| 419 | uint32_t index; | |
| 420 | }; | |
| 421 | std::map<StringRef, std::vector<ComdatEntry>> comdats; | |
| 422 | ||
| 423 | for (const InputFunction *f : out.functionSec->inputFunctions) { | |
| 424 | StringRef comdat = f->getComdatName(); | |
| 425 | if (!comdat.empty()) | |
| 426 | comdats[comdat].emplace_back( | |
| 427 | ComdatEntry{WASM_COMDAT_FUNCTION, f->getFunctionIndex()}); | |
| 428 | } | |
| 429 | for (uint32_t i = 0; i < dataSegments.size(); ++i) { | |
| 430 | const auto &inputSegments = dataSegments[i]->inputSegments; | |
| 431 | if (inputSegments.empty()) | |
| 432 | continue; | |
| 433 | StringRef comdat = inputSegments[0]->getComdatName(); | |
| 434 | #ifndef NDEBUG | |
| 435 | for (const InputSegment *isec : inputSegments) | |
| 436 | assert(isec->getComdatName() == comdat); | |
| 437 | #endif | |
| 438 | if (!comdat.empty()) | |
| 439 | comdats[comdat].emplace_back(ComdatEntry{WASM_COMDAT_DATA, i}); | |
| 440 | } | |
| 441 | ||
| 442 | if (!comdats.empty()) { | |
| 443 | SubSection sub(WASM_COMDAT_INFO); | |
| 444 | writeUleb128(sub.os, comdats.size(), "num comdats"); | |
| 445 | for (const auto &c : comdats) { | |
| 446 | writeStr(sub.os, c.first, "comdat name"); | |
| 447 | writeUleb128(sub.os, 0, "comdat flags"); // flags for future use | |
| 448 | writeUleb128(sub.os, c.second.size(), "num entries"); | |
| 449 | for (const ComdatEntry &entry : c.second) { | |
| 450 | writeU8(sub.os, entry.kind, "entry kind"); | |
| 451 | writeUleb128(sub.os, entry.index, "entry index"); | |
| 452 | } | |
| 453 | } | |
| 454 | sub.writeTo(os); | |
| 455 | } | |
| 456 | } | |
| 457 | ||
| 458 | void LinkingSection::addToSymtab(Symbol *sym) { | |
| 459 | sym->setOutputSymbolIndex(symtabEntries.size()); | |
| 460 | symtabEntries.emplace_back(sym); | |
| 461 | } | |
| 462 | ||
| 463 | unsigned NameSection::numNames() const { | |
| 464 | unsigned numNames = out.importSec->getNumImportedFunctions(); | |
| 465 | for (const InputFunction *f : out.functionSec->inputFunctions) | |
| 466 | if (!f->getName().empty() || !f->getDebugName().empty()) | |
| 467 | ++numNames; | |
| 468 | ||
| 469 | return numNames; | |
| 470 | } | |
| 471 | ||
| 472 | // Create the custom "name" section containing debug symbol names. | |
| 473 | void NameSection::writeBody() { | |
| 474 | SubSection sub(WASM_NAMES_FUNCTION); | |
| 475 | writeUleb128(sub.os, numNames(), "name count"); | |
| 476 | ||
| 477 | // Names must appear in function index order. As it happens importedSymbols | |
| 478 | // and inputFunctions are numbered in order with imported functions coming | |
| 479 | // first. | |
| 480 | for (const Symbol *s : out.importSec->importedSymbols) { | |
| 481 | if (auto *f = dyn_cast<FunctionSymbol>(s)) { | |
| 482 | writeUleb128(sub.os, f->getFunctionIndex(), "func index"); | |
| 483 | writeStr(sub.os, toString(*s), "symbol name"); | |
| 484 | } | |
| 485 | } | |
| 486 | for (const InputFunction *f : out.functionSec->inputFunctions) { | |
| 487 | if (!f->getName().empty()) { | |
| 488 | writeUleb128(sub.os, f->getFunctionIndex(), "func index"); | |
| 489 | if (!f->getDebugName().empty()) { | |
| 490 | writeStr(sub.os, f->getDebugName(), "symbol name"); | |
| 491 | } else { | |
| 492 | writeStr(sub.os, maybeDemangleSymbol(f->getName()), "symbol name"); | |
| 493 | } | |
| 494 | } | |
| 495 | } | |
| 496 | ||
| 497 | sub.writeTo(bodyOutputStream); | |
| 498 | } | |
| 499 | ||
| 500 | void ProducersSection::addInfo(const WasmProducerInfo &info) { | |
| 501 | for (auto &producers : | |
| 502 | {std::make_pair(&info.Languages, &languages), | |
| 503 | std::make_pair(&info.Tools, &tools), std::make_pair(&info.SDKs, &sDKs)}) | |
| 504 | for (auto &producer : *producers.first) | |
| 505 | if (producers.second->end() == | |
| 506 | llvm::find_if(*producers.second, | |
| 507 | [&](std::pair<std::string, std::string> seen) { | |
| 508 | return seen.first == producer.first; | |
| 509 | })) | |
| 510 | producers.second->push_back(producer); | |
| 511 | } | |
| 512 | ||
| 513 | void ProducersSection::writeBody() { | |
| 514 | auto &os = bodyOutputStream; | |
| 515 | writeUleb128(os, fieldCount(), "field count"); | |
| 516 | for (auto &field : | |
| 517 | {std::make_pair("language", languages), | |
| 518 | std::make_pair("processed-by", tools), std::make_pair("sdk", sDKs)}) { | |
| 519 | if (field.second.empty()) | |
| 520 | continue; | |
| 521 | writeStr(os, field.first, "field name"); | |
| 522 | writeUleb128(os, field.second.size(), "number of entries"); | |
| 523 | for (auto &entry : field.second) { | |
| 524 | writeStr(os, entry.first, "producer name"); | |
| 525 | writeStr(os, entry.second, "producer version"); | |
| 526 | } | |
| 527 | } | |
| 528 | } | |
| 529 | ||
| 530 | void TargetFeaturesSection::writeBody() { | |
| 531 | SmallVector<std::string, 8> emitted(features.begin(), features.end()); | |
| 532 | llvm::sort(emitted); | |
| 533 | auto &os = bodyOutputStream; | |
| 534 | writeUleb128(os, emitted.size(), "feature count"); | |
| 535 | for (auto &feature : emitted) { | |
| 536 | writeU8(os, WASM_FEATURE_PREFIX_USED, "feature used prefix"); | |
| 537 | writeStr(os, feature, "feature name"); | |
| 538 | } | |
| 539 | } | |
| 540 | ||
| 541 | void RelocSection::writeBody() { | |
| 542 | uint32_t count = sec->getNumRelocations(); | |
| 543 | assert(sec->sectionIndex != UINT32_MAX); | |
| 544 | writeUleb128(bodyOutputStream, sec->sectionIndex, "reloc section"); | |
| 545 | writeUleb128(bodyOutputStream, count, "reloc count"); | |
| 546 | sec->writeRelocations(bodyOutputStream); | |
| 547 | } |
deps/lld/wasm/SyntheticSections.h created+339| ... | ... | @@ -0,0 +1,339 @@ |
| 1 | //===- SyntheticSection.h ---------------------------------------*- C++ -*-===// | |
| 2 | // | |
| 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 | |
| 6 | // | |
| 7 | //===----------------------------------------------------------------------===// | |
| 8 | // | |
| 9 | // Synthetic sections represent chunks of linker-created data. If you | |
| 10 | // need to create a chunk of data that to be included in some section | |
| 11 | // in the result, you probably want to create that as a synthetic section. | |
| 12 | // | |
| 13 | //===----------------------------------------------------------------------===// | |
| 14 | ||
| 15 | #ifndef LLD_WASM_SYNTHETIC_SECTIONS_H | |
| 16 | #define LLD_WASM_SYNTHETIC_SECTIONS_H | |
| 17 | ||
| 18 | #include "OutputSections.h" | |
| 19 | ||
| 20 | #include "llvm/ADT/SmallSet.h" | |
| 21 | #include "llvm/ADT/StringMap.h" | |
| 22 | #include "llvm/Object/WasmTraits.h" | |
| 23 | ||
| 24 | #define DEBUG_TYPE "lld" | |
| 25 | ||
| 26 | namespace lld { | |
| 27 | namespace wasm { | |
| 28 | ||
| 29 | // An init entry to be written to either the synthetic init func or the | |
| 30 | // linking metadata. | |
| 31 | struct WasmInitEntry { | |
| 32 | const FunctionSymbol *sym; | |
| 33 | uint32_t priority; | |
| 34 | }; | |
| 35 | ||
| 36 | class SyntheticSection : public OutputSection { | |
| 37 | public: | |
| 38 | SyntheticSection(uint32_t type, std::string name = "") | |
| 39 | : OutputSection(type, name), bodyOutputStream(body) { | |
| 40 | if (!name.empty()) | |
| 41 | writeStr(bodyOutputStream, name, "section name"); | |
| 42 | } | |
| 43 | ||
| 44 | void writeTo(uint8_t *buf) override { | |
| 45 | assert(offset); | |
| 46 | log("writing " + toString(*this)); | |
| 47 | memcpy(buf + offset, header.data(), header.size()); | |
| 48 | memcpy(buf + offset + header.size(), body.data(), body.size()); | |
| 49 | } | |
| 50 | ||
| 51 | size_t getSize() const override { return header.size() + body.size(); } | |
| 52 | ||
| 53 | virtual void writeBody() {} | |
| 54 | ||
| 55 | void finalizeContents() override { | |
| 56 | writeBody(); | |
| 57 | bodyOutputStream.flush(); | |
| 58 | createHeader(body.size()); | |
| 59 | } | |
| 60 | ||
| 61 | raw_ostream &getStream() { return bodyOutputStream; } | |
| 62 | ||
| 63 | std::string body; | |
| 64 | ||
| 65 | protected: | |
| 66 | llvm::raw_string_ostream bodyOutputStream; | |
| 67 | }; | |
| 68 | ||
| 69 | // Create the custom "dylink" section containing information for the dynamic | |
| 70 | // linker. | |
| 71 | // See | |
| 72 | // https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md | |
| 73 | class DylinkSection : public SyntheticSection { | |
| 74 | public: | |
| 75 | DylinkSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "dylink") {} | |
| 76 | bool isNeeded() const override { return config->isPic; } | |
| 77 | void writeBody() override; | |
| 78 | ||
| 79 | uint32_t memAlign = 0; | |
| 80 | uint32_t memSize = 0; | |
| 81 | }; | |
| 82 | ||
| 83 | class TypeSection : public SyntheticSection { | |
| 84 | public: | |
| 85 | TypeSection() : SyntheticSection(llvm::wasm::WASM_SEC_TYPE) {} | |
| 86 | ||
| 87 | bool isNeeded() const override { return types.size() > 0; }; | |
| 88 | void writeBody() override; | |
| 89 | uint32_t registerType(const WasmSignature &sig); | |
| 90 | uint32_t lookupType(const WasmSignature &sig); | |
| 91 | ||
| 92 | protected: | |
| 93 | std::vector<const WasmSignature *> types; | |
| 94 | llvm::DenseMap<WasmSignature, int32_t> typeIndices; | |
| 95 | }; | |
| 96 | ||
| 97 | class ImportSection : public SyntheticSection { | |
| 98 | public: | |
| 99 | ImportSection() : SyntheticSection(llvm::wasm::WASM_SEC_IMPORT) {} | |
| 100 | bool isNeeded() const override { return getNumImports() > 0; } | |
| 101 | void writeBody() override; | |
| 102 | void addImport(Symbol *sym); | |
| 103 | void addGOTEntry(Symbol *sym); | |
| 104 | void seal() { isSealed = true; } | |
| 105 | uint32_t getNumImports() const; | |
| 106 | uint32_t getNumImportedGlobals() const { | |
| 107 | assert(isSealed); | |
| 108 | return numImportedGlobals; | |
| 109 | } | |
| 110 | uint32_t getNumImportedFunctions() const { | |
| 111 | assert(isSealed); | |
| 112 | return numImportedFunctions; | |
| 113 | } | |
| 114 | uint32_t getNumImportedEvents() const { | |
| 115 | assert(isSealed); | |
| 116 | return numImportedEvents; | |
| 117 | } | |
| 118 | ||
| 119 | std::vector<const Symbol *> importedSymbols; | |
| 120 | ||
| 121 | protected: | |
| 122 | bool isSealed = false; | |
| 123 | unsigned numImportedGlobals = 0; | |
| 124 | unsigned numImportedFunctions = 0; | |
| 125 | unsigned numImportedEvents = 0; | |
| 126 | std::vector<const Symbol *> gotSymbols; | |
| 127 | }; | |
| 128 | ||
| 129 | class FunctionSection : public SyntheticSection { | |
| 130 | public: | |
| 131 | FunctionSection() : SyntheticSection(llvm::wasm::WASM_SEC_FUNCTION) {} | |
| 132 | ||
| 133 | bool isNeeded() const override { return inputFunctions.size() > 0; }; | |
| 134 | void writeBody() override; | |
| 135 | void addFunction(InputFunction *func); | |
| 136 | ||
| 137 | std::vector<InputFunction *> inputFunctions; | |
| 138 | ||
| 139 | protected: | |
| 140 | }; | |
| 141 | ||
| 142 | class MemorySection : public SyntheticSection { | |
| 143 | public: | |
| 144 | MemorySection() : SyntheticSection(llvm::wasm::WASM_SEC_MEMORY) {} | |
| 145 | ||
| 146 | bool isNeeded() const override { return !config->importMemory; } | |
| 147 | void writeBody() override; | |
| 148 | ||
| 149 | uint32_t numMemoryPages = 0; | |
| 150 | uint32_t maxMemoryPages = 0; | |
| 151 | }; | |
| 152 | ||
| 153 | class TableSection : public SyntheticSection { | |
| 154 | public: | |
| 155 | TableSection() : SyntheticSection(llvm::wasm::WASM_SEC_TABLE) {} | |
| 156 | ||
| 157 | bool isNeeded() const override { | |
| 158 | // Always output a table section (or table import), even if there are no | |
| 159 | // indirect calls. There are two reasons for this: | |
| 160 | // 1. For executables it is useful to have an empty table slot at 0 | |
| 161 | // which can be filled with a null function call handler. | |
| 162 | // 2. If we don't do this, any program that contains a call_indirect but | |
| 163 | // no address-taken function will fail at validation time since it is | |
| 164 | // a validation error to include a call_indirect instruction if there | |
| 165 | // is not table. | |
| 166 | return !config->importTable; | |
| 167 | } | |
| 168 | ||
| 169 | void writeBody() override; | |
| 170 | }; | |
| 171 | ||
| 172 | class GlobalSection : public SyntheticSection { | |
| 173 | public: | |
| 174 | GlobalSection() : SyntheticSection(llvm::wasm::WASM_SEC_GLOBAL) {} | |
| 175 | uint32_t numGlobals() const { | |
| 176 | return inputGlobals.size() + definedFakeGlobals.size(); | |
| 177 | } | |
| 178 | bool isNeeded() const override { return numGlobals() > 0; } | |
| 179 | void writeBody() override; | |
| 180 | void addGlobal(InputGlobal *global); | |
| 181 | ||
| 182 | std::vector<const DefinedData *> definedFakeGlobals; | |
| 183 | std::vector<InputGlobal *> inputGlobals; | |
| 184 | }; | |
| 185 | ||
| 186 | // The event section contains a list of declared wasm events associated with the | |
| 187 | // module. Currently the only supported event kind is exceptions. A single event | |
| 188 | // entry represents a single event with an event tag. All C++ exceptions are | |
| 189 | // represented by a single event. An event entry in this section contains | |
| 190 | // information on what kind of event it is (e.g. exception) and the type of | |
| 191 | // values contained in a single event object. (In wasm, an event can contain | |
| 192 | // multiple values of primitive types. But for C++ exceptions, we just throw a | |
| 193 | // pointer which is an i32 value (for wasm32 architecture), so the signature of | |
| 194 | // C++ exception is (i32)->(void), because all event types are assumed to have | |
| 195 | // void return type to share WasmSignature with functions.) | |
| 196 | class EventSection : public SyntheticSection { | |
| 197 | public: | |
| 198 | EventSection() : SyntheticSection(llvm::wasm::WASM_SEC_EVENT) {} | |
| 199 | void writeBody() override; | |
| 200 | bool isNeeded() const override { return inputEvents.size() > 0; } | |
| 201 | void addEvent(InputEvent *event); | |
| 202 | ||
| 203 | std::vector<InputEvent *> inputEvents; | |
| 204 | }; | |
| 205 | ||
| 206 | class ExportSection : public SyntheticSection { | |
| 207 | public: | |
| 208 | ExportSection() : SyntheticSection(llvm::wasm::WASM_SEC_EXPORT) {} | |
| 209 | bool isNeeded() const override { return exports.size() > 0; } | |
| 210 | void writeBody() override; | |
| 211 | ||
| 212 | std::vector<llvm::wasm::WasmExport> exports; | |
| 213 | }; | |
| 214 | ||
| 215 | class ElemSection : public SyntheticSection { | |
| 216 | public: | |
| 217 | ElemSection(uint32_t offset) | |
| 218 | : SyntheticSection(llvm::wasm::WASM_SEC_ELEM), elemOffset(offset) {} | |
| 219 | bool isNeeded() const override { return indirectFunctions.size() > 0; }; | |
| 220 | void writeBody() override; | |
| 221 | void addEntry(FunctionSymbol *sym); | |
| 222 | uint32_t numEntries() const { return indirectFunctions.size(); } | |
| 223 | uint32_t elemOffset; | |
| 224 | ||
| 225 | protected: | |
| 226 | std::vector<const FunctionSymbol *> indirectFunctions; | |
| 227 | }; | |
| 228 | ||
| 229 | class DataCountSection : public SyntheticSection { | |
| 230 | public: | |
| 231 | DataCountSection(uint32_t numSegments) | |
| 232 | : SyntheticSection(llvm::wasm::WASM_SEC_DATACOUNT), | |
| 233 | numSegments(numSegments) {} | |
| 234 | bool isNeeded() const override; | |
| 235 | void writeBody() override; | |
| 236 | ||
| 237 | protected: | |
| 238 | uint32_t numSegments; | |
| 239 | }; | |
| 240 | ||
| 241 | // Create the custom "linking" section containing linker metadata. | |
| 242 | // This is only created when relocatable output is requested. | |
| 243 | class LinkingSection : public SyntheticSection { | |
| 244 | public: | |
| 245 | LinkingSection(const std::vector<WasmInitEntry> &initFunctions, | |
| 246 | const std::vector<OutputSegment *> &dataSegments) | |
| 247 | : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "linking"), | |
| 248 | initFunctions(initFunctions), dataSegments(dataSegments) {} | |
| 249 | bool isNeeded() const override { | |
| 250 | return config->relocatable || config->emitRelocs; | |
| 251 | } | |
| 252 | void writeBody() override; | |
| 253 | void addToSymtab(Symbol *sym); | |
| 254 | ||
| 255 | protected: | |
| 256 | std::vector<const Symbol *> symtabEntries; | |
| 257 | llvm::StringMap<uint32_t> sectionSymbolIndices; | |
| 258 | const std::vector<WasmInitEntry> &initFunctions; | |
| 259 | const std::vector<OutputSegment *> &dataSegments; | |
| 260 | }; | |
| 261 | ||
| 262 | // Create the custom "name" section containing debug symbol names. | |
| 263 | class NameSection : public SyntheticSection { | |
| 264 | public: | |
| 265 | NameSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name") {} | |
| 266 | bool isNeeded() const override { | |
| 267 | return !config->stripDebug && !config->stripAll && numNames() > 0; | |
| 268 | } | |
| 269 | void writeBody() override; | |
| 270 | unsigned numNames() const; | |
| 271 | }; | |
| 272 | ||
| 273 | class ProducersSection : public SyntheticSection { | |
| 274 | public: | |
| 275 | ProducersSection() | |
| 276 | : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "producers") {} | |
| 277 | bool isNeeded() const override { | |
| 278 | return !config->stripAll && fieldCount() > 0; | |
| 279 | } | |
| 280 | void writeBody() override; | |
| 281 | void addInfo(const llvm::wasm::WasmProducerInfo &info); | |
| 282 | ||
| 283 | protected: | |
| 284 | int fieldCount() const { | |
| 285 | return int(!languages.empty()) + int(!tools.empty()) + int(!sDKs.empty()); | |
| 286 | } | |
| 287 | SmallVector<std::pair<std::string, std::string>, 8> languages; | |
| 288 | SmallVector<std::pair<std::string, std::string>, 8> tools; | |
| 289 | SmallVector<std::pair<std::string, std::string>, 8> sDKs; | |
| 290 | }; | |
| 291 | ||
| 292 | class TargetFeaturesSection : public SyntheticSection { | |
| 293 | public: | |
| 294 | TargetFeaturesSection() | |
| 295 | : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "target_features") {} | |
| 296 | bool isNeeded() const override { | |
| 297 | return !config->stripAll && features.size() > 0; | |
| 298 | } | |
| 299 | void writeBody() override; | |
| 300 | ||
| 301 | llvm::SmallSet<std::string, 8> features; | |
| 302 | }; | |
| 303 | ||
| 304 | class RelocSection : public SyntheticSection { | |
| 305 | public: | |
| 306 | RelocSection(StringRef name, OutputSection *sec) | |
| 307 | : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, name), sec(sec) {} | |
| 308 | void writeBody() override; | |
| 309 | bool isNeeded() const override { return sec->getNumRelocations() > 0; }; | |
| 310 | ||
| 311 | protected: | |
| 312 | OutputSection *sec; | |
| 313 | }; | |
| 314 | ||
| 315 | // Linker generated output sections | |
| 316 | struct OutStruct { | |
| 317 | DylinkSection *dylinkSec; | |
| 318 | TypeSection *typeSec; | |
| 319 | FunctionSection *functionSec; | |
| 320 | ImportSection *importSec; | |
| 321 | TableSection *tableSec; | |
| 322 | MemorySection *memorySec; | |
| 323 | GlobalSection *globalSec; | |
| 324 | EventSection *eventSec; | |
| 325 | ExportSection *exportSec; | |
| 326 | ElemSection *elemSec; | |
| 327 | DataCountSection *dataCountSec; | |
| 328 | LinkingSection *linkingSec; | |
| 329 | NameSection *nameSec; | |
| 330 | ProducersSection *producersSec; | |
| 331 | TargetFeaturesSection *targetFeaturesSec; | |
| 332 | }; | |
| 333 | ||
| 334 | extern OutStruct out; | |
| 335 | ||
| 336 | } // namespace wasm | |
| 337 | } // namespace lld | |
| 338 | ||
| 339 | #endif |
deps/lld/wasm/Writer.cpp+659-909| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Writer.cpp ---------------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -14,13 +13,17 @@ |
| 14 | 13 | #include "InputGlobal.h" |
| 15 | 14 | #include "OutputSections.h" |
| 16 | 15 | #include "OutputSegment.h" |
| 16 | #include "Relocations.h" | |
| 17 | 17 | #include "SymbolTable.h" |
| 18 | #include "SyntheticSections.h" | |
| 18 | 19 | #include "WriterUtils.h" |
| 19 | 20 | #include "lld/Common/ErrorHandler.h" |
| 20 | 21 | #include "lld/Common/Memory.h" |
| 21 | 22 | #include "lld/Common/Strings.h" |
| 22 | 23 | #include "lld/Common/Threads.h" |
| 23 | 24 | #include "llvm/ADT/DenseSet.h" |
| 25 | #include "llvm/ADT/SmallSet.h" | |
| 26 | #include "llvm/ADT/SmallVector.h" | |
| 24 | 27 | #include "llvm/ADT/StringMap.h" |
| 25 | 28 | #include "llvm/BinaryFormat/Wasm.h" |
| 26 | 29 | #include "llvm/Object/WasmTraits.h" |
| ... | ... | @@ -39,19 +42,10 @@ using namespace llvm::wasm; |
| 39 | 42 | using namespace lld; |
| 40 | 43 | using namespace lld::wasm; |
| 41 | 44 | |
| 42 | static constexpr int StackAlignment = 16; | |
| 43 | static constexpr const char *FunctionTableName = "__indirect_function_table"; | |
| 44 | const char *lld::wasm::DefaultModule = "env"; | |
| 45 | static constexpr int stackAlignment = 16; | |
| 45 | 46 | |
| 46 | 47 | namespace { |
| 47 | 48 | |
| 48 | // An init entry to be written to either the synthetic init func or the | |
| 49 | // linking metadata. | |
| 50 | struct WasmInitEntry { | |
| 51 | const FunctionSymbol *Sym; | |
| 52 | uint32_t Priority; | |
| 53 | }; | |
| 54 | ||
| 55 | 49 | // The writer writes a SymbolTable result to a file. |
| 56 | 50 | class Writer { |
| 57 | 51 | public: |
| ... | ... | @@ -60,613 +54,145 @@ public: |
| 60 | 54 | private: |
| 61 | 55 | void openFile(); |
| 62 | 56 | |
| 63 | uint32_t lookupType(const WasmSignature &Sig); | |
| 64 | uint32_t registerType(const WasmSignature &Sig); | |
| 57 | void createInitMemoryFunction(); | |
| 58 | void createApplyRelocationsFunction(); | |
| 59 | void createCallCtorsFunction(); | |
| 60 | void createInitTLSFunction(); | |
| 65 | 61 | |
| 66 | void createCtorFunction(); | |
| 67 | void calculateInitFunctions(); | |
| 68 | 62 | void assignIndexes(); |
| 63 | void populateSymtab(); | |
| 64 | void populateProducers(); | |
| 65 | void populateTargetFeatures(); | |
| 66 | void calculateInitFunctions(); | |
| 69 | 67 | void calculateImports(); |
| 70 | 68 | void calculateExports(); |
| 71 | 69 | void calculateCustomSections(); |
| 72 | void assignSymtab(); | |
| 73 | 70 | void calculateTypes(); |
| 74 | 71 | void createOutputSegments(); |
| 75 | 72 | void layoutMemory(); |
| 76 | 73 | void createHeader(); |
| 77 | void createSections(); | |
| 78 | SyntheticSection *createSyntheticSection(uint32_t Type, StringRef Name = ""); | |
| 79 | ||
| 80 | // Builtin sections | |
| 81 | void createTypeSection(); | |
| 82 | void createFunctionSection(); | |
| 83 | void createTableSection(); | |
| 84 | void createGlobalSection(); | |
| 85 | void createEventSection(); | |
| 86 | void createExportSection(); | |
| 87 | void createImportSection(); | |
| 88 | void createMemorySection(); | |
| 89 | void createElemSection(); | |
| 90 | void createCodeSection(); | |
| 91 | void createDataSection(); | |
| 74 | ||
| 75 | void addSection(OutputSection *sec); | |
| 76 | ||
| 77 | void addSections(); | |
| 78 | ||
| 92 | 79 | void createCustomSections(); |
| 80 | void createSyntheticSections(); | |
| 81 | void finalizeSections(); | |
| 93 | 82 | |
| 94 | 83 | // Custom sections |
| 95 | void createDylinkSection(); | |
| 96 | 84 | void createRelocSections(); |
| 97 | void createLinkingSection(); | |
| 98 | void createNameSection(); | |
| 99 | 85 | |
| 100 | 86 | void writeHeader(); |
| 101 | 87 | void writeSections(); |
| 102 | 88 | |
| 103 | uint64_t FileSize = 0; | |
| 104 | uint32_t TableBase = 0; | |
| 105 | uint32_t NumMemoryPages = 0; | |
| 106 | uint32_t MaxMemoryPages = 0; | |
| 107 | // Memory size and aligment. Written to the "dylink" section | |
| 108 | // when build with -shared or -pie. | |
| 109 | uint32_t MemAlign = 0; | |
| 110 | uint32_t MemSize = 0; | |
| 111 | ||
| 112 | std::vector<const WasmSignature *> Types; | |
| 113 | DenseMap<WasmSignature, int32_t> TypeIndices; | |
| 114 | std::vector<const Symbol *> ImportedSymbols; | |
| 115 | unsigned NumImportedFunctions = 0; | |
| 116 | unsigned NumImportedGlobals = 0; | |
| 117 | unsigned NumImportedEvents = 0; | |
| 118 | std::vector<WasmExport> Exports; | |
| 119 | std::vector<const DefinedData *> DefinedFakeGlobals; | |
| 120 | std::vector<InputGlobal *> InputGlobals; | |
| 121 | std::vector<InputFunction *> InputFunctions; | |
| 122 | std::vector<InputEvent *> InputEvents; | |
| 123 | std::vector<const FunctionSymbol *> IndirectFunctions; | |
| 124 | std::vector<const Symbol *> SymtabEntries; | |
| 125 | std::vector<WasmInitEntry> InitFunctions; | |
| 126 | ||
| 127 | llvm::StringMap<std::vector<InputSection *>> CustomSectionMapping; | |
| 128 | llvm::StringMap<SectionSymbol *> CustomSectionSymbols; | |
| 89 | uint64_t fileSize = 0; | |
| 90 | uint32_t tableBase = 0; | |
| 91 | ||
| 92 | std::vector<WasmInitEntry> initFunctions; | |
| 93 | llvm::StringMap<std::vector<InputSection *>> customSectionMapping; | |
| 129 | 94 | |
| 130 | 95 | // Elements that are used to construct the final output |
| 131 | std::string Header; | |
| 132 | std::vector<OutputSection *> OutputSections; | |
| 96 | std::string header; | |
| 97 | std::vector<OutputSection *> outputSections; | |
| 133 | 98 | |
| 134 | std::unique_ptr<FileOutputBuffer> Buffer; | |
| 99 | std::unique_ptr<FileOutputBuffer> buffer; | |
| 135 | 100 | |
| 136 | std::vector<OutputSegment *> Segments; | |
| 137 | llvm::SmallDenseMap<StringRef, OutputSegment *> SegmentMap; | |
| 101 | std::vector<OutputSegment *> segments; | |
| 102 | llvm::SmallDenseMap<StringRef, OutputSegment *> segmentMap; | |
| 138 | 103 | }; |
| 139 | 104 | |
| 140 | 105 | } // anonymous namespace |
| 141 | 106 | |
| 142 | void Writer::createImportSection() { | |
| 143 | uint32_t NumImports = ImportedSymbols.size(); | |
| 144 | if (Config->ImportMemory) | |
| 145 | ++NumImports; | |
| 146 | if (Config->ImportTable) | |
| 147 | ++NumImports; | |
| 148 | ||
| 149 | if (NumImports == 0) | |
| 150 | return; | |
| 151 | ||
| 152 | SyntheticSection *Section = createSyntheticSection(WASM_SEC_IMPORT); | |
| 153 | raw_ostream &OS = Section->getStream(); | |
| 154 | ||
| 155 | writeUleb128(OS, NumImports, "import count"); | |
| 156 | ||
| 157 | if (Config->ImportMemory) { | |
| 158 | WasmImport Import; | |
| 159 | Import.Module = DefaultModule; | |
| 160 | Import.Field = "memory"; | |
| 161 | Import.Kind = WASM_EXTERNAL_MEMORY; | |
| 162 | Import.Memory.Flags = 0; | |
| 163 | Import.Memory.Initial = NumMemoryPages; | |
| 164 | if (MaxMemoryPages != 0) { | |
| 165 | Import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX; | |
| 166 | Import.Memory.Maximum = MaxMemoryPages; | |
| 167 | } | |
| 168 | if (Config->SharedMemory) | |
| 169 | Import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED; | |
| 170 | writeImport(OS, Import); | |
| 171 | } | |
| 172 | ||
| 173 | if (Config->ImportTable) { | |
| 174 | uint32_t TableSize = TableBase + IndirectFunctions.size(); | |
| 175 | WasmImport Import; | |
| 176 | Import.Module = DefaultModule; | |
| 177 | Import.Field = FunctionTableName; | |
| 178 | Import.Kind = WASM_EXTERNAL_TABLE; | |
| 179 | Import.Table.ElemType = WASM_TYPE_FUNCREF; | |
| 180 | Import.Table.Limits = {0, TableSize, 0}; | |
| 181 | writeImport(OS, Import); | |
| 182 | } | |
| 183 | ||
| 184 | for (const Symbol *Sym : ImportedSymbols) { | |
| 185 | WasmImport Import; | |
| 186 | if (auto *F = dyn_cast<UndefinedFunction>(Sym)) { | |
| 187 | Import.Field = F->ImportName; | |
| 188 | Import.Module = F->ImportModule; | |
| 189 | } else if (auto *G = dyn_cast<UndefinedGlobal>(Sym)) { | |
| 190 | Import.Field = G->ImportName; | |
| 191 | Import.Module = G->ImportModule; | |
| 192 | } else { | |
| 193 | Import.Field = Sym->getName(); | |
| 194 | Import.Module = DefaultModule; | |
| 195 | } | |
| 196 | ||
| 197 | if (auto *FunctionSym = dyn_cast<FunctionSymbol>(Sym)) { | |
| 198 | Import.Kind = WASM_EXTERNAL_FUNCTION; | |
| 199 | Import.SigIndex = lookupType(*FunctionSym->Signature); | |
| 200 | } else if (auto *GlobalSym = dyn_cast<GlobalSymbol>(Sym)) { | |
| 201 | Import.Kind = WASM_EXTERNAL_GLOBAL; | |
| 202 | Import.Global = *GlobalSym->getGlobalType(); | |
| 203 | } else { | |
| 204 | auto *EventSym = cast<EventSymbol>(Sym); | |
| 205 | Import.Kind = WASM_EXTERNAL_EVENT; | |
| 206 | Import.Event.Attribute = EventSym->getEventType()->Attribute; | |
| 207 | Import.Event.SigIndex = lookupType(*EventSym->Signature); | |
| 208 | } | |
| 209 | writeImport(OS, Import); | |
| 210 | } | |
| 211 | } | |
| 212 | ||
| 213 | void Writer::createTypeSection() { | |
| 214 | SyntheticSection *Section = createSyntheticSection(WASM_SEC_TYPE); | |
| 215 | raw_ostream &OS = Section->getStream(); | |
| 216 | writeUleb128(OS, Types.size(), "type count"); | |
| 217 | for (const WasmSignature *Sig : Types) | |
| 218 | writeSig(OS, *Sig); | |
| 219 | } | |
| 220 | ||
| 221 | void Writer::createFunctionSection() { | |
| 222 | if (InputFunctions.empty()) | |
| 223 | return; | |
| 224 | ||
| 225 | SyntheticSection *Section = createSyntheticSection(WASM_SEC_FUNCTION); | |
| 226 | raw_ostream &OS = Section->getStream(); | |
| 227 | ||
| 228 | writeUleb128(OS, InputFunctions.size(), "function count"); | |
| 229 | for (const InputFunction *Func : InputFunctions) | |
| 230 | writeUleb128(OS, lookupType(Func->Signature), "sig index"); | |
| 231 | } | |
| 232 | ||
| 233 | void Writer::createMemorySection() { | |
| 234 | if (Config->ImportMemory) | |
| 235 | return; | |
| 236 | ||
| 237 | SyntheticSection *Section = createSyntheticSection(WASM_SEC_MEMORY); | |
| 238 | raw_ostream &OS = Section->getStream(); | |
| 239 | ||
| 240 | bool HasMax = MaxMemoryPages != 0; | |
| 241 | writeUleb128(OS, 1, "memory count"); | |
| 242 | unsigned Flags = 0; | |
| 243 | if (HasMax) | |
| 244 | Flags |= WASM_LIMITS_FLAG_HAS_MAX; | |
| 245 | if (Config->SharedMemory) | |
| 246 | Flags |= WASM_LIMITS_FLAG_IS_SHARED; | |
| 247 | writeUleb128(OS, Flags, "memory limits flags"); | |
| 248 | writeUleb128(OS, NumMemoryPages, "initial pages"); | |
| 249 | if (HasMax) | |
| 250 | writeUleb128(OS, MaxMemoryPages, "max pages"); | |
| 251 | } | |
| 252 | ||
| 253 | void Writer::createGlobalSection() { | |
| 254 | unsigned NumGlobals = InputGlobals.size() + DefinedFakeGlobals.size(); | |
| 255 | if (NumGlobals == 0) | |
| 256 | return; | |
| 257 | ||
| 258 | SyntheticSection *Section = createSyntheticSection(WASM_SEC_GLOBAL); | |
| 259 | raw_ostream &OS = Section->getStream(); | |
| 260 | ||
| 261 | writeUleb128(OS, NumGlobals, "global count"); | |
| 262 | for (const InputGlobal *G : InputGlobals) | |
| 263 | writeGlobal(OS, G->Global); | |
| 264 | for (const DefinedData *Sym : DefinedFakeGlobals) { | |
| 265 | WasmGlobal Global; | |
| 266 | Global.Type = {WASM_TYPE_I32, false}; | |
| 267 | Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST; | |
| 268 | Global.InitExpr.Value.Int32 = Sym->getVirtualAddress(); | |
| 269 | writeGlobal(OS, Global); | |
| 270 | } | |
| 271 | } | |
| 272 | ||
| 273 | // The event section contains a list of declared wasm events associated with the | |
| 274 | // module. Currently the only supported event kind is exceptions. A single event | |
| 275 | // entry represents a single event with an event tag. All C++ exceptions are | |
| 276 | // represented by a single event. An event entry in this section contains | |
| 277 | // information on what kind of event it is (e.g. exception) and the type of | |
| 278 | // values contained in a single event object. (In wasm, an event can contain | |
| 279 | // multiple values of primitive types. But for C++ exceptions, we just throw a | |
| 280 | // pointer which is an i32 value (for wasm32 architecture), so the signature of | |
| 281 | // C++ exception is (i32)->(void), because all event types are assumed to have | |
| 282 | // void return type to share WasmSignature with functions.) | |
| 283 | void Writer::createEventSection() { | |
| 284 | unsigned NumEvents = InputEvents.size(); | |
| 285 | if (NumEvents == 0) | |
| 286 | return; | |
| 287 | ||
| 288 | SyntheticSection *Section = createSyntheticSection(WASM_SEC_EVENT); | |
| 289 | raw_ostream &OS = Section->getStream(); | |
| 290 | ||
| 291 | writeUleb128(OS, NumEvents, "event count"); | |
| 292 | for (InputEvent *E : InputEvents) { | |
| 293 | E->Event.Type.SigIndex = lookupType(E->Signature); | |
| 294 | writeEvent(OS, E->Event); | |
| 295 | } | |
| 296 | } | |
| 297 | ||
| 298 | void Writer::createTableSection() { | |
| 299 | if (Config->ImportTable) | |
| 300 | return; | |
| 301 | ||
| 302 | // Always output a table section (or table import), even if there are no | |
| 303 | // indirect calls. There are two reasons for this: | |
| 304 | // 1. For executables it is useful to have an empty table slot at 0 | |
| 305 | // which can be filled with a null function call handler. | |
| 306 | // 2. If we don't do this, any program that contains a call_indirect but | |
| 307 | // no address-taken function will fail at validation time since it is | |
| 308 | // a validation error to include a call_indirect instruction if there | |
| 309 | // is not table. | |
| 310 | uint32_t TableSize = TableBase + IndirectFunctions.size(); | |
| 311 | ||
| 312 | SyntheticSection *Section = createSyntheticSection(WASM_SEC_TABLE); | |
| 313 | raw_ostream &OS = Section->getStream(); | |
| 314 | ||
| 315 | writeUleb128(OS, 1, "table count"); | |
| 316 | WasmLimits Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize}; | |
| 317 | writeTableType(OS, WasmTable{WASM_TYPE_FUNCREF, Limits}); | |
| 318 | } | |
| 319 | ||
| 320 | void Writer::createExportSection() { | |
| 321 | if (!Exports.size()) | |
| 322 | return; | |
| 323 | ||
| 324 | SyntheticSection *Section = createSyntheticSection(WASM_SEC_EXPORT); | |
| 325 | raw_ostream &OS = Section->getStream(); | |
| 326 | ||
| 327 | writeUleb128(OS, Exports.size(), "export count"); | |
| 328 | for (const WasmExport &Export : Exports) | |
| 329 | writeExport(OS, Export); | |
| 330 | } | |
| 331 | ||
| 332 | 107 | void Writer::calculateCustomSections() { |
| 333 | 108 | log("calculateCustomSections"); |
| 334 | bool StripDebug = Config->StripDebug || Config->StripAll; | |
| 335 | for (ObjFile *File : Symtab->ObjectFiles) { | |
| 336 | for (InputSection *Section : File->CustomSections) { | |
| 337 | StringRef Name = Section->getName(); | |
| 109 | bool stripDebug = config->stripDebug || config->stripAll; | |
| 110 | for (ObjFile *file : symtab->objectFiles) { | |
| 111 | for (InputSection *section : file->customSections) { | |
| 112 | StringRef name = section->getName(); | |
| 338 | 113 | // These custom sections are known the linker and synthesized rather than |
| 339 | 114 | // blindly copied |
| 340 | if (Name == "linking" || Name == "name" || Name.startswith("reloc.")) | |
| 115 | if (name == "linking" || name == "name" || name == "producers" || | |
| 116 | name == "target_features" || name.startswith("reloc.")) | |
| 341 | 117 | continue; |
| 342 | 118 | // .. or it is a debug section |
| 343 | if (StripDebug && Name.startswith(".debug_")) | |
| 119 | if (stripDebug && name.startswith(".debug_")) | |
| 344 | 120 | continue; |
| 345 | CustomSectionMapping[Name].push_back(Section); | |
| 121 | customSectionMapping[name].push_back(section); | |
| 346 | 122 | } |
| 347 | 123 | } |
| 348 | 124 | } |
| 349 | 125 | |
| 350 | 126 | void Writer::createCustomSections() { |
| 351 | 127 | log("createCustomSections"); |
| 352 | for (auto &Pair : CustomSectionMapping) { | |
| 353 | StringRef Name = Pair.first(); | |
| 354 | ||
| 355 | auto P = CustomSectionSymbols.find(Name); | |
| 356 | if (P != CustomSectionSymbols.end()) { | |
| 357 | uint32_t SectionIndex = OutputSections.size(); | |
| 358 | P->second->setOutputSectionIndex(SectionIndex); | |
| 128 | for (auto &pair : customSectionMapping) { | |
| 129 | StringRef name = pair.first(); | |
| 130 | LLVM_DEBUG(dbgs() << "createCustomSection: " << name << "\n"); | |
| 131 | ||
| 132 | OutputSection *sec = make<CustomSection>(name, pair.second); | |
| 133 | if (config->relocatable || config->emitRelocs) { | |
| 134 | auto *sym = make<OutputSectionSymbol>(sec); | |
| 135 | out.linkingSec->addToSymtab(sym); | |
| 136 | sec->sectionSym = sym; | |
| 359 | 137 | } |
| 360 | ||
| 361 | LLVM_DEBUG(dbgs() << "createCustomSection: " << Name << "\n"); | |
| 362 | OutputSections.push_back(make<CustomSection>(Name, Pair.second)); | |
| 138 | addSection(sec); | |
| 363 | 139 | } |
| 364 | 140 | } |
| 365 | 141 | |
| 366 | void Writer::createElemSection() { | |
| 367 | if (IndirectFunctions.empty()) | |
| 368 | return; | |
| 369 | ||
| 370 | SyntheticSection *Section = createSyntheticSection(WASM_SEC_ELEM); | |
| 371 | raw_ostream &OS = Section->getStream(); | |
| 372 | ||
| 373 | writeUleb128(OS, 1, "segment count"); | |
| 374 | writeUleb128(OS, 0, "table index"); | |
| 375 | WasmInitExpr InitExpr; | |
| 376 | if (Config->Pic) { | |
| 377 | InitExpr.Opcode = WASM_OPCODE_GLOBAL_GET; | |
| 378 | InitExpr.Value.Global = WasmSym::TableBase->getGlobalIndex(); | |
| 379 | } else { | |
| 380 | InitExpr.Opcode = WASM_OPCODE_I32_CONST; | |
| 381 | InitExpr.Value.Int32 = TableBase; | |
| 382 | } | |
| 383 | writeInitExpr(OS, InitExpr); | |
| 384 | writeUleb128(OS, IndirectFunctions.size(), "elem count"); | |
| 385 | ||
| 386 | uint32_t TableIndex = TableBase; | |
| 387 | for (const FunctionSymbol *Sym : IndirectFunctions) { | |
| 388 | assert(Sym->getTableIndex() == TableIndex); | |
| 389 | writeUleb128(OS, Sym->getFunctionIndex(), "function index"); | |
| 390 | ++TableIndex; | |
| 391 | } | |
| 392 | } | |
| 393 | ||
| 394 | void Writer::createCodeSection() { | |
| 395 | if (InputFunctions.empty()) | |
| 396 | return; | |
| 397 | ||
| 398 | log("createCodeSection"); | |
| 399 | ||
| 400 | auto Section = make<CodeSection>(InputFunctions); | |
| 401 | OutputSections.push_back(Section); | |
| 402 | } | |
| 403 | ||
| 404 | void Writer::createDataSection() { | |
| 405 | if (!Segments.size()) | |
| 406 | return; | |
| 407 | ||
| 408 | log("createDataSection"); | |
| 409 | auto Section = make<DataSection>(Segments); | |
| 410 | OutputSections.push_back(Section); | |
| 411 | } | |
| 412 | ||
| 413 | 142 | // Create relocations sections in the final output. |
| 414 | 143 | // These are only created when relocatable output is requested. |
| 415 | 144 | void Writer::createRelocSections() { |
| 416 | 145 | log("createRelocSections"); |
| 417 | 146 | // Don't use iterator here since we are adding to OutputSection |
| 418 | size_t OrigSize = OutputSections.size(); | |
| 419 | for (size_t I = 0; I < OrigSize; I++) { | |
| 420 | OutputSection *OSec = OutputSections[I]; | |
| 421 | uint32_t Count = OSec->numRelocations(); | |
| 422 | if (!Count) | |
| 147 | size_t origSize = outputSections.size(); | |
| 148 | for (size_t i = 0; i < origSize; i++) { | |
| 149 | LLVM_DEBUG(dbgs() << "check section " << i << "\n"); | |
| 150 | OutputSection *sec = outputSections[i]; | |
| 151 | ||
| 152 | // Count the number of needed sections. | |
| 153 | uint32_t count = sec->getNumRelocations(); | |
| 154 | if (!count) | |
| 423 | 155 | continue; |
| 424 | 156 | |
| 425 | StringRef Name; | |
| 426 | if (OSec->Type == WASM_SEC_DATA) | |
| 427 | Name = "reloc.DATA"; | |
| 428 | else if (OSec->Type == WASM_SEC_CODE) | |
| 429 | Name = "reloc.CODE"; | |
| 430 | else if (OSec->Type == WASM_SEC_CUSTOM) | |
| 431 | Name = Saver.save("reloc." + OSec->Name); | |
| 157 | StringRef name; | |
| 158 | if (sec->type == WASM_SEC_DATA) | |
| 159 | name = "reloc.DATA"; | |
| 160 | else if (sec->type == WASM_SEC_CODE) | |
| 161 | name = "reloc.CODE"; | |
| 162 | else if (sec->type == WASM_SEC_CUSTOM) | |
| 163 | name = saver.save("reloc." + sec->name); | |
| 432 | 164 | else |
| 433 | 165 | llvm_unreachable( |
| 434 | 166 | "relocations only supported for code, data, or custom sections"); |
| 435 | 167 | |
| 436 | SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, Name); | |
| 437 | raw_ostream &OS = Section->getStream(); | |
| 438 | writeUleb128(OS, I, "reloc section"); | |
| 439 | writeUleb128(OS, Count, "reloc count"); | |
| 440 | OSec->writeRelocations(OS); | |
| 441 | } | |
| 442 | } | |
| 443 | ||
| 444 | static uint32_t getWasmFlags(const Symbol *Sym) { | |
| 445 | uint32_t Flags = 0; | |
| 446 | if (Sym->isLocal()) | |
| 447 | Flags |= WASM_SYMBOL_BINDING_LOCAL; | |
| 448 | if (Sym->isWeak()) | |
| 449 | Flags |= WASM_SYMBOL_BINDING_WEAK; | |
| 450 | if (Sym->isHidden()) | |
| 451 | Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN; | |
| 452 | if (Sym->isUndefined()) | |
| 453 | Flags |= WASM_SYMBOL_UNDEFINED; | |
| 454 | if (auto *F = dyn_cast<UndefinedFunction>(Sym)) { | |
| 455 | if (F->getName() != F->ImportName) | |
| 456 | Flags |= WASM_SYMBOL_EXPLICIT_NAME; | |
| 457 | } else if (auto *G = dyn_cast<UndefinedGlobal>(Sym)) { | |
| 458 | if (G->getName() != G->ImportName) | |
| 459 | Flags |= WASM_SYMBOL_EXPLICIT_NAME; | |
| 168 | addSection(make<RelocSection>(name, sec)); | |
| 460 | 169 | } |
| 461 | return Flags; | |
| 462 | 170 | } |
| 463 | 171 | |
| 464 | // Some synthetic sections (e.g. "name" and "linking") have subsections. | |
| 465 | // Just like the synthetic sections themselves these need to be created before | |
| 466 | // they can be written out (since they are preceded by their length). This | |
| 467 | // class is used to create subsections and then write them into the stream | |
| 468 | // of the parent section. | |
| 469 | class SubSection { | |
| 470 | public: | |
| 471 | explicit SubSection(uint32_t Type) : Type(Type) {} | |
| 472 | ||
| 473 | void writeTo(raw_ostream &To) { | |
| 474 | OS.flush(); | |
| 475 | writeUleb128(To, Type, "subsection type"); | |
| 476 | writeUleb128(To, Body.size(), "subsection size"); | |
| 477 | To.write(Body.data(), Body.size()); | |
| 172 | void Writer::populateProducers() { | |
| 173 | for (ObjFile *file : symtab->objectFiles) { | |
| 174 | const WasmProducerInfo &info = file->getWasmObj()->getProducerInfo(); | |
| 175 | out.producersSec->addInfo(info); | |
| 478 | 176 | } |
| 479 | ||
| 480 | private: | |
| 481 | uint32_t Type; | |
| 482 | std::string Body; | |
| 483 | ||
| 484 | public: | |
| 485 | raw_string_ostream OS{Body}; | |
| 486 | }; | |
| 487 | ||
| 488 | // Create the custom "dylink" section containing information for the dynamic | |
| 489 | // linker. | |
| 490 | // See | |
| 491 | // https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md | |
| 492 | void Writer::createDylinkSection() { | |
| 493 | SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, "dylink"); | |
| 494 | raw_ostream &OS = Section->getStream(); | |
| 495 | ||
| 496 | writeUleb128(OS, MemSize, "MemSize"); | |
| 497 | writeUleb128(OS, MemAlign, "MemAlign"); | |
| 498 | writeUleb128(OS, IndirectFunctions.size(), "TableSize"); | |
| 499 | writeUleb128(OS, 0, "TableAlign"); | |
| 500 | writeUleb128(OS, 0, "Needed"); // TODO: Support "needed" shared libraries | |
| 501 | } | |
| 502 | ||
| 503 | // Create the custom "linking" section containing linker metadata. | |
| 504 | // This is only created when relocatable output is requested. | |
| 505 | void Writer::createLinkingSection() { | |
| 506 | SyntheticSection *Section = | |
| 507 | createSyntheticSection(WASM_SEC_CUSTOM, "linking"); | |
| 508 | raw_ostream &OS = Section->getStream(); | |
| 509 | ||
| 510 | writeUleb128(OS, WasmMetadataVersion, "Version"); | |
| 511 | ||
| 512 | if (!SymtabEntries.empty()) { | |
| 513 | SubSection Sub(WASM_SYMBOL_TABLE); | |
| 514 | writeUleb128(Sub.OS, SymtabEntries.size(), "num symbols"); | |
| 515 | ||
| 516 | for (const Symbol *Sym : SymtabEntries) { | |
| 517 | assert(Sym->isDefined() || Sym->isUndefined()); | |
| 518 | WasmSymbolType Kind = Sym->getWasmType(); | |
| 519 | uint32_t Flags = getWasmFlags(Sym); | |
| 520 | ||
| 521 | writeU8(Sub.OS, Kind, "sym kind"); | |
| 522 | writeUleb128(Sub.OS, Flags, "sym flags"); | |
| 523 | ||
| 524 | if (auto *F = dyn_cast<FunctionSymbol>(Sym)) { | |
| 525 | writeUleb128(Sub.OS, F->getFunctionIndex(), "index"); | |
| 526 | if (Sym->isDefined() || | |
| 527 | (Flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) | |
| 528 | writeStr(Sub.OS, Sym->getName(), "sym name"); | |
| 529 | } else if (auto *G = dyn_cast<GlobalSymbol>(Sym)) { | |
| 530 | writeUleb128(Sub.OS, G->getGlobalIndex(), "index"); | |
| 531 | if (Sym->isDefined() || | |
| 532 | (Flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) | |
| 533 | writeStr(Sub.OS, Sym->getName(), "sym name"); | |
| 534 | } else if (auto *E = dyn_cast<EventSymbol>(Sym)) { | |
| 535 | writeUleb128(Sub.OS, E->getEventIndex(), "index"); | |
| 536 | if (Sym->isDefined() || | |
| 537 | (Flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) | |
| 538 | writeStr(Sub.OS, Sym->getName(), "sym name"); | |
| 539 | } else if (isa<DataSymbol>(Sym)) { | |
| 540 | writeStr(Sub.OS, Sym->getName(), "sym name"); | |
| 541 | if (auto *DataSym = dyn_cast<DefinedData>(Sym)) { | |
| 542 | writeUleb128(Sub.OS, DataSym->getOutputSegmentIndex(), "index"); | |
| 543 | writeUleb128(Sub.OS, DataSym->getOutputSegmentOffset(), | |
| 544 | "data offset"); | |
| 545 | writeUleb128(Sub.OS, DataSym->getSize(), "data size"); | |
| 546 | } | |
| 547 | } else { | |
| 548 | auto *S = cast<SectionSymbol>(Sym); | |
| 549 | writeUleb128(Sub.OS, S->getOutputSectionIndex(), "sym section index"); | |
| 550 | } | |
| 551 | } | |
| 552 | ||
| 553 | Sub.writeTo(OS); | |
| 554 | } | |
| 555 | ||
| 556 | if (Segments.size()) { | |
| 557 | SubSection Sub(WASM_SEGMENT_INFO); | |
| 558 | writeUleb128(Sub.OS, Segments.size(), "num data segments"); | |
| 559 | for (const OutputSegment *S : Segments) { | |
| 560 | writeStr(Sub.OS, S->Name, "segment name"); | |
| 561 | writeUleb128(Sub.OS, S->Alignment, "alignment"); | |
| 562 | writeUleb128(Sub.OS, 0, "flags"); | |
| 563 | } | |
| 564 | Sub.writeTo(OS); | |
| 565 | } | |
| 566 | ||
| 567 | if (!InitFunctions.empty()) { | |
| 568 | SubSection Sub(WASM_INIT_FUNCS); | |
| 569 | writeUleb128(Sub.OS, InitFunctions.size(), "num init functions"); | |
| 570 | for (const WasmInitEntry &F : InitFunctions) { | |
| 571 | writeUleb128(Sub.OS, F.Priority, "priority"); | |
| 572 | writeUleb128(Sub.OS, F.Sym->getOutputSymbolIndex(), "function index"); | |
| 573 | } | |
| 574 | Sub.writeTo(OS); | |
| 575 | } | |
| 576 | ||
| 577 | struct ComdatEntry { | |
| 578 | unsigned Kind; | |
| 579 | uint32_t Index; | |
| 580 | }; | |
| 581 | std::map<StringRef, std::vector<ComdatEntry>> Comdats; | |
| 582 | ||
| 583 | for (const InputFunction *F : InputFunctions) { | |
| 584 | StringRef Comdat = F->getComdatName(); | |
| 585 | if (!Comdat.empty()) | |
| 586 | Comdats[Comdat].emplace_back( | |
| 587 | ComdatEntry{WASM_COMDAT_FUNCTION, F->getFunctionIndex()}); | |
| 588 | } | |
| 589 | for (uint32_t I = 0; I < Segments.size(); ++I) { | |
| 590 | const auto &InputSegments = Segments[I]->InputSegments; | |
| 591 | if (InputSegments.empty()) | |
| 592 | continue; | |
| 593 | StringRef Comdat = InputSegments[0]->getComdatName(); | |
| 594 | #ifndef NDEBUG | |
| 595 | for (const InputSegment *IS : InputSegments) | |
| 596 | assert(IS->getComdatName() == Comdat); | |
| 597 | #endif | |
| 598 | if (!Comdat.empty()) | |
| 599 | Comdats[Comdat].emplace_back(ComdatEntry{WASM_COMDAT_DATA, I}); | |
| 600 | } | |
| 601 | ||
| 602 | if (!Comdats.empty()) { | |
| 603 | SubSection Sub(WASM_COMDAT_INFO); | |
| 604 | writeUleb128(Sub.OS, Comdats.size(), "num comdats"); | |
| 605 | for (const auto &C : Comdats) { | |
| 606 | writeStr(Sub.OS, C.first, "comdat name"); | |
| 607 | writeUleb128(Sub.OS, 0, "comdat flags"); // flags for future use | |
| 608 | writeUleb128(Sub.OS, C.second.size(), "num entries"); | |
| 609 | for (const ComdatEntry &Entry : C.second) { | |
| 610 | writeU8(Sub.OS, Entry.Kind, "entry kind"); | |
| 611 | writeUleb128(Sub.OS, Entry.Index, "entry index"); | |
| 612 | } | |
| 613 | } | |
| 614 | Sub.writeTo(OS); | |
| 615 | } | |
| 616 | } | |
| 617 | ||
| 618 | // Create the custom "name" section containing debug symbol names. | |
| 619 | void Writer::createNameSection() { | |
| 620 | unsigned NumNames = NumImportedFunctions; | |
| 621 | for (const InputFunction *F : InputFunctions) | |
| 622 | if (!F->getName().empty() || !F->getDebugName().empty()) | |
| 623 | ++NumNames; | |
| 624 | ||
| 625 | if (NumNames == 0) | |
| 626 | return; | |
| 627 | ||
| 628 | SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, "name"); | |
| 629 | ||
| 630 | SubSection Sub(WASM_NAMES_FUNCTION); | |
| 631 | writeUleb128(Sub.OS, NumNames, "name count"); | |
| 632 | ||
| 633 | // Names must appear in function index order. As it happens ImportedSymbols | |
| 634 | // and InputFunctions are numbered in order with imported functions coming | |
| 635 | // first. | |
| 636 | for (const Symbol *S : ImportedSymbols) { | |
| 637 | if (auto *F = dyn_cast<FunctionSymbol>(S)) { | |
| 638 | writeUleb128(Sub.OS, F->getFunctionIndex(), "func index"); | |
| 639 | writeStr(Sub.OS, toString(*S), "symbol name"); | |
| 640 | } | |
| 641 | } | |
| 642 | for (const InputFunction *F : InputFunctions) { | |
| 643 | if (!F->getName().empty()) { | |
| 644 | writeUleb128(Sub.OS, F->getFunctionIndex(), "func index"); | |
| 645 | if (!F->getDebugName().empty()) { | |
| 646 | writeStr(Sub.OS, F->getDebugName(), "symbol name"); | |
| 647 | } else { | |
| 648 | writeStr(Sub.OS, maybeDemangleSymbol(F->getName()), "symbol name"); | |
| 649 | } | |
| 650 | } | |
| 651 | } | |
| 652 | ||
| 653 | Sub.writeTo(Section->getStream()); | |
| 654 | 177 | } |
| 655 | 178 | |
| 656 | 179 | void Writer::writeHeader() { |
| 657 | memcpy(Buffer->getBufferStart(), Header.data(), Header.size()); | |
| 180 | memcpy(buffer->getBufferStart(), header.data(), header.size()); | |
| 658 | 181 | } |
| 659 | 182 | |
| 660 | 183 | void Writer::writeSections() { |
| 661 | uint8_t *Buf = Buffer->getBufferStart(); | |
| 662 | parallelForEach(OutputSections, [Buf](OutputSection *S) { S->writeTo(Buf); }); | |
| 184 | uint8_t *buf = buffer->getBufferStart(); | |
| 185 | parallelForEach(outputSections, [buf](OutputSection *s) { | |
| 186 | assert(s->isNeeded()); | |
| 187 | s->writeTo(buf); | |
| 188 | }); | |
| 663 | 189 | } |
| 664 | 190 | |
| 665 | 191 | // Fix the memory layout of the output binary. This assigns memory offsets |
| 666 | 192 | // to each of the input data sections as well as the explicit stack region. |
| 667 | 193 | // The default memory layout is as follows, from low to high. |
| 668 | 194 | // |
| 669 | // - initialized data (starting at Config->GlobalBase) | |
| 195 | // - initialized data (starting at Config->globalBase) | |
| 670 | 196 | // - BSS data (not currently implemented in llvm) |
| 671 | 197 | // - explicit stack (Config->ZStackSize) |
| 672 | 198 | // - heap start / unallocated |
| ... | ... | @@ -676,264 +202,349 @@ void Writer::writeSections() { |
| 676 | 202 | // rather than overwriting global data, but also increases code size since all |
| 677 | 203 | // static data loads and stores requires larger offsets. |
| 678 | 204 | void Writer::layoutMemory() { |
| 679 | createOutputSegments(); | |
| 205 | uint32_t memoryPtr = 0; | |
| 680 | 206 | |
| 681 | uint32_t MemoryPtr = 0; | |
| 682 | ||
| 683 | auto PlaceStack = [&]() { | |
| 684 | if (Config->Relocatable || Config->Shared) | |
| 207 | auto placeStack = [&]() { | |
| 208 | if (config->relocatable || config->isPic) | |
| 685 | 209 | return; |
| 686 | MemoryPtr = alignTo(MemoryPtr, StackAlignment); | |
| 687 | if (Config->ZStackSize != alignTo(Config->ZStackSize, StackAlignment)) | |
| 688 | error("stack size must be " + Twine(StackAlignment) + "-byte aligned"); | |
| 689 | log("mem: stack size = " + Twine(Config->ZStackSize)); | |
| 690 | log("mem: stack base = " + Twine(MemoryPtr)); | |
| 691 | MemoryPtr += Config->ZStackSize; | |
| 692 | auto *SP = cast<DefinedGlobal>(WasmSym::StackPointer); | |
| 693 | SP->Global->Global.InitExpr.Value.Int32 = MemoryPtr; | |
| 694 | log("mem: stack top = " + Twine(MemoryPtr)); | |
| 210 | memoryPtr = alignTo(memoryPtr, stackAlignment); | |
| 211 | if (config->zStackSize != alignTo(config->zStackSize, stackAlignment)) | |
| 212 | error("stack size must be " + Twine(stackAlignment) + "-byte aligned"); | |
| 213 | log("mem: stack size = " + Twine(config->zStackSize)); | |
| 214 | log("mem: stack base = " + Twine(memoryPtr)); | |
| 215 | memoryPtr += config->zStackSize; | |
| 216 | auto *sp = cast<DefinedGlobal>(WasmSym::stackPointer); | |
| 217 | sp->global->global.InitExpr.Value.Int32 = memoryPtr; | |
| 218 | log("mem: stack top = " + Twine(memoryPtr)); | |
| 695 | 219 | }; |
| 696 | 220 | |
| 697 | if (Config->StackFirst) { | |
| 698 | PlaceStack(); | |
| 221 | if (config->stackFirst) { | |
| 222 | placeStack(); | |
| 699 | 223 | } else { |
| 700 | MemoryPtr = Config->GlobalBase; | |
| 701 | log("mem: global base = " + Twine(Config->GlobalBase)); | |
| 224 | memoryPtr = config->globalBase; | |
| 225 | log("mem: global base = " + Twine(config->globalBase)); | |
| 702 | 226 | } |
| 703 | 227 | |
| 704 | uint32_t DataStart = MemoryPtr; | |
| 228 | if (WasmSym::globalBase) | |
| 229 | WasmSym::globalBase->setVirtualAddress(config->globalBase); | |
| 230 | ||
| 231 | uint32_t dataStart = memoryPtr; | |
| 705 | 232 | |
| 706 | 233 | // Arbitrarily set __dso_handle handle to point to the start of the data |
| 707 | 234 | // segments. |
| 708 | if (WasmSym::DsoHandle) | |
| 709 | WasmSym::DsoHandle->setVirtualAddress(DataStart); | |
| 710 | ||
| 711 | MemAlign = 0; | |
| 712 | for (OutputSegment *Seg : Segments) { | |
| 713 | MemAlign = std::max(MemAlign, Seg->Alignment); | |
| 714 | MemoryPtr = alignTo(MemoryPtr, 1 << Seg->Alignment); | |
| 715 | Seg->StartVA = MemoryPtr; | |
| 716 | log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", Seg->Name, | |
| 717 | MemoryPtr, Seg->Size, Seg->Alignment)); | |
| 718 | MemoryPtr += Seg->Size; | |
| 235 | if (WasmSym::dsoHandle) | |
| 236 | WasmSym::dsoHandle->setVirtualAddress(dataStart); | |
| 237 | ||
| 238 | out.dylinkSec->memAlign = 0; | |
| 239 | for (OutputSegment *seg : segments) { | |
| 240 | out.dylinkSec->memAlign = std::max(out.dylinkSec->memAlign, seg->alignment); | |
| 241 | memoryPtr = alignTo(memoryPtr, 1ULL << seg->alignment); | |
| 242 | seg->startVA = memoryPtr; | |
| 243 | log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", seg->name, | |
| 244 | memoryPtr, seg->size, seg->alignment)); | |
| 245 | memoryPtr += seg->size; | |
| 246 | ||
| 247 | if (WasmSym::tlsSize && seg->name == ".tdata") { | |
| 248 | auto *tlsSize = cast<DefinedGlobal>(WasmSym::tlsSize); | |
| 249 | tlsSize->global->global.InitExpr.Value.Int32 = seg->size; | |
| 250 | } | |
| 719 | 251 | } |
| 720 | 252 | |
| 721 | 253 | // TODO: Add .bss space here. |
| 722 | if (WasmSym::DataEnd) | |
| 723 | WasmSym::DataEnd->setVirtualAddress(MemoryPtr); | |
| 254 | if (WasmSym::dataEnd) | |
| 255 | WasmSym::dataEnd->setVirtualAddress(memoryPtr); | |
| 724 | 256 | |
| 725 | log("mem: static data = " + Twine(MemoryPtr - DataStart)); | |
| 257 | log("mem: static data = " + Twine(memoryPtr - dataStart)); | |
| 726 | 258 | |
| 727 | if (Config->Shared) { | |
| 728 | MemSize = MemoryPtr; | |
| 259 | if (config->shared) { | |
| 260 | out.dylinkSec->memSize = memoryPtr; | |
| 729 | 261 | return; |
| 730 | 262 | } |
| 731 | 263 | |
| 732 | if (!Config->StackFirst) | |
| 733 | PlaceStack(); | |
| 264 | if (!config->stackFirst) | |
| 265 | placeStack(); | |
| 734 | 266 | |
| 735 | 267 | // Set `__heap_base` to directly follow the end of the stack or global data. |
| 736 | 268 | // The fact that this comes last means that a malloc/brk implementation |
| 737 | 269 | // can grow the heap at runtime. |
| 738 | if (!Config->Relocatable) { | |
| 739 | WasmSym::HeapBase->setVirtualAddress(MemoryPtr); | |
| 740 | log("mem: heap base = " + Twine(MemoryPtr)); | |
| 741 | } | |
| 270 | log("mem: heap base = " + Twine(memoryPtr)); | |
| 271 | if (WasmSym::heapBase) | |
| 272 | WasmSym::heapBase->setVirtualAddress(memoryPtr); | |
| 742 | 273 | |
| 743 | if (Config->InitialMemory != 0) { | |
| 744 | if (Config->InitialMemory != alignTo(Config->InitialMemory, WasmPageSize)) | |
| 274 | if (config->initialMemory != 0) { | |
| 275 | if (config->initialMemory != alignTo(config->initialMemory, WasmPageSize)) | |
| 745 | 276 | error("initial memory must be " + Twine(WasmPageSize) + "-byte aligned"); |
| 746 | if (MemoryPtr > Config->InitialMemory) | |
| 747 | error("initial memory too small, " + Twine(MemoryPtr) + " bytes needed"); | |
| 277 | if (memoryPtr > config->initialMemory) | |
| 278 | error("initial memory too small, " + Twine(memoryPtr) + " bytes needed"); | |
| 748 | 279 | else |
| 749 | MemoryPtr = Config->InitialMemory; | |
| 280 | memoryPtr = config->initialMemory; | |
| 750 | 281 | } |
| 751 | MemSize = MemoryPtr; | |
| 752 | NumMemoryPages = alignTo(MemoryPtr, WasmPageSize) / WasmPageSize; | |
| 753 | log("mem: total pages = " + Twine(NumMemoryPages)); | |
| 282 | out.dylinkSec->memSize = memoryPtr; | |
| 283 | out.memorySec->numMemoryPages = | |
| 284 | alignTo(memoryPtr, WasmPageSize) / WasmPageSize; | |
| 285 | log("mem: total pages = " + Twine(out.memorySec->numMemoryPages)); | |
| 754 | 286 | |
| 755 | if (Config->MaxMemory != 0) { | |
| 756 | if (Config->MaxMemory != alignTo(Config->MaxMemory, WasmPageSize)) | |
| 287 | // Check max if explicitly supplied or required by shared memory | |
| 288 | if (config->maxMemory != 0 || config->sharedMemory) { | |
| 289 | if (config->maxMemory != alignTo(config->maxMemory, WasmPageSize)) | |
| 757 | 290 | error("maximum memory must be " + Twine(WasmPageSize) + "-byte aligned"); |
| 758 | if (MemoryPtr > Config->MaxMemory) | |
| 759 | error("maximum memory too small, " + Twine(MemoryPtr) + " bytes needed"); | |
| 760 | MaxMemoryPages = Config->MaxMemory / WasmPageSize; | |
| 761 | log("mem: max pages = " + Twine(MaxMemoryPages)); | |
| 291 | if (memoryPtr > config->maxMemory) | |
| 292 | error("maximum memory too small, " + Twine(memoryPtr) + " bytes needed"); | |
| 293 | out.memorySec->maxMemoryPages = config->maxMemory / WasmPageSize; | |
| 294 | log("mem: max pages = " + Twine(out.memorySec->maxMemoryPages)); | |
| 762 | 295 | } |
| 763 | 296 | } |
| 764 | 297 | |
| 765 | SyntheticSection *Writer::createSyntheticSection(uint32_t Type, | |
| 766 | StringRef Name) { | |
| 767 | auto Sec = make<SyntheticSection>(Type, Name); | |
| 768 | log("createSection: " + toString(*Sec)); | |
| 769 | OutputSections.push_back(Sec); | |
| 770 | return Sec; | |
| 771 | } | |
| 298 | void Writer::addSection(OutputSection *sec) { | |
| 299 | if (!sec->isNeeded()) | |
| 300 | return; | |
| 301 | log("addSection: " + toString(*sec)); | |
| 302 | sec->sectionIndex = outputSections.size(); | |
| 303 | outputSections.push_back(sec); | |
| 304 | } | |
| 305 | ||
| 306 | // If a section name is valid as a C identifier (which is rare because of | |
| 307 | // the leading '.'), linkers are expected to define __start_<secname> and | |
| 308 | // __stop_<secname> symbols. They are at beginning and end of the section, | |
| 309 | // respectively. This is not requested by the ELF standard, but GNU ld and | |
| 310 | // gold provide the feature, and used by many programs. | |
| 311 | static void addStartStopSymbols(const OutputSegment *seg) { | |
| 312 | StringRef name = seg->name; | |
| 313 | if (!isValidCIdentifier(name)) | |
| 314 | return; | |
| 315 | LLVM_DEBUG(dbgs() << "addStartStopSymbols: " << name << "\n"); | |
| 316 | uint32_t start = seg->startVA; | |
| 317 | uint32_t stop = start + seg->size; | |
| 318 | symtab->addOptionalDataSymbol(saver.save("__start_" + name), start); | |
| 319 | symtab->addOptionalDataSymbol(saver.save("__stop_" + name), stop); | |
| 320 | } | |
| 321 | ||
| 322 | void Writer::addSections() { | |
| 323 | addSection(out.dylinkSec); | |
| 324 | addSection(out.typeSec); | |
| 325 | addSection(out.importSec); | |
| 326 | addSection(out.functionSec); | |
| 327 | addSection(out.tableSec); | |
| 328 | addSection(out.memorySec); | |
| 329 | addSection(out.globalSec); | |
| 330 | addSection(out.eventSec); | |
| 331 | addSection(out.exportSec); | |
| 332 | addSection(out.elemSec); | |
| 333 | addSection(out.dataCountSec); | |
| 334 | ||
| 335 | addSection(make<CodeSection>(out.functionSec->inputFunctions)); | |
| 336 | addSection(make<DataSection>(segments)); | |
| 772 | 337 | |
| 773 | void Writer::createSections() { | |
| 774 | // Known sections | |
| 775 | if (Config->Pic) | |
| 776 | createDylinkSection(); | |
| 777 | createTypeSection(); | |
| 778 | createImportSection(); | |
| 779 | createFunctionSection(); | |
| 780 | createTableSection(); | |
| 781 | createMemorySection(); | |
| 782 | createGlobalSection(); | |
| 783 | createEventSection(); | |
| 784 | createExportSection(); | |
| 785 | createElemSection(); | |
| 786 | createCodeSection(); | |
| 787 | createDataSection(); | |
| 788 | 338 | createCustomSections(); |
| 789 | 339 | |
| 790 | // Custom sections | |
| 791 | if (Config->Relocatable) { | |
| 792 | createLinkingSection(); | |
| 340 | addSection(out.linkingSec); | |
| 341 | if (config->emitRelocs || config->relocatable) { | |
| 793 | 342 | createRelocSections(); |
| 794 | 343 | } |
| 795 | if (!Config->StripDebug && !Config->StripAll) | |
| 796 | createNameSection(); | |
| 797 | 344 | |
| 798 | for (OutputSection *S : OutputSections) { | |
| 799 | S->setOffset(FileSize); | |
| 800 | S->finalizeContents(); | |
| 801 | FileSize += S->getSize(); | |
| 345 | addSection(out.nameSec); | |
| 346 | addSection(out.producersSec); | |
| 347 | addSection(out.targetFeaturesSec); | |
| 348 | } | |
| 349 | ||
| 350 | void Writer::finalizeSections() { | |
| 351 | for (OutputSection *s : outputSections) { | |
| 352 | s->setOffset(fileSize); | |
| 353 | s->finalizeContents(); | |
| 354 | fileSize += s->getSize(); | |
| 355 | } | |
| 356 | } | |
| 357 | ||
| 358 | void Writer::populateTargetFeatures() { | |
| 359 | StringMap<std::string> used; | |
| 360 | StringMap<std::string> required; | |
| 361 | StringMap<std::string> disallowed; | |
| 362 | bool tlsUsed = false; | |
| 363 | ||
| 364 | // Only infer used features if user did not specify features | |
| 365 | bool inferFeatures = !config->features.hasValue(); | |
| 366 | ||
| 367 | if (!inferFeatures) { | |
| 368 | for (auto &feature : config->features.getValue()) | |
| 369 | out.targetFeaturesSec->features.insert(feature); | |
| 370 | // No need to read or check features | |
| 371 | if (!config->checkFeatures) | |
| 372 | return; | |
| 373 | } | |
| 374 | ||
| 375 | // Find the sets of used, required, and disallowed features | |
| 376 | for (ObjFile *file : symtab->objectFiles) { | |
| 377 | StringRef fileName(file->getName()); | |
| 378 | for (auto &feature : file->getWasmObj()->getTargetFeatures()) { | |
| 379 | switch (feature.Prefix) { | |
| 380 | case WASM_FEATURE_PREFIX_USED: | |
| 381 | used.insert({feature.Name, fileName}); | |
| 382 | break; | |
| 383 | case WASM_FEATURE_PREFIX_REQUIRED: | |
| 384 | used.insert({feature.Name, fileName}); | |
| 385 | required.insert({feature.Name, fileName}); | |
| 386 | break; | |
| 387 | case WASM_FEATURE_PREFIX_DISALLOWED: | |
| 388 | disallowed.insert({feature.Name, fileName}); | |
| 389 | break; | |
| 390 | default: | |
| 391 | error("Unrecognized feature policy prefix " + | |
| 392 | std::to_string(feature.Prefix)); | |
| 393 | } | |
| 394 | } | |
| 395 | ||
| 396 | for (InputSegment *segment : file->segments) { | |
| 397 | if (!segment->live) | |
| 398 | continue; | |
| 399 | StringRef name = segment->getName(); | |
| 400 | if (name.startswith(".tdata") || name.startswith(".tbss")) | |
| 401 | tlsUsed = true; | |
| 402 | } | |
| 403 | } | |
| 404 | ||
| 405 | if (inferFeatures) | |
| 406 | out.targetFeaturesSec->features.insert(used.keys().begin(), | |
| 407 | used.keys().end()); | |
| 408 | ||
| 409 | if (out.targetFeaturesSec->features.count("atomics") && | |
| 410 | !config->sharedMemory) { | |
| 411 | if (inferFeatures) | |
| 412 | error(Twine("'atomics' feature is used by ") + used["atomics"] + | |
| 413 | ", so --shared-memory must be used"); | |
| 414 | else | |
| 415 | error("'atomics' feature is used, so --shared-memory must be used"); | |
| 416 | } | |
| 417 | ||
| 418 | if (!config->checkFeatures) | |
| 419 | return; | |
| 420 | ||
| 421 | if (disallowed.count("atomics") && config->sharedMemory) | |
| 422 | error("'atomics' feature is disallowed by " + disallowed["atomics"] + | |
| 423 | ", so --shared-memory must not be used"); | |
| 424 | ||
| 425 | if (!used.count("bulk-memory") && config->passiveSegments) | |
| 426 | error("'bulk-memory' feature must be used in order to emit passive " | |
| 427 | "segments"); | |
| 428 | ||
| 429 | if (!used.count("bulk-memory") && tlsUsed) | |
| 430 | error("'bulk-memory' feature must be used in order to use thread-local " | |
| 431 | "storage"); | |
| 432 | ||
| 433 | // Validate that used features are allowed in output | |
| 434 | if (!inferFeatures) { | |
| 435 | for (auto &feature : used.keys()) { | |
| 436 | if (!out.targetFeaturesSec->features.count(feature)) | |
| 437 | error(Twine("Target feature '") + feature + "' used by " + | |
| 438 | used[feature] + " is not allowed."); | |
| 439 | } | |
| 440 | } | |
| 441 | ||
| 442 | // Validate the required and disallowed constraints for each file | |
| 443 | for (ObjFile *file : symtab->objectFiles) { | |
| 444 | StringRef fileName(file->getName()); | |
| 445 | SmallSet<std::string, 8> objectFeatures; | |
| 446 | for (auto &feature : file->getWasmObj()->getTargetFeatures()) { | |
| 447 | if (feature.Prefix == WASM_FEATURE_PREFIX_DISALLOWED) | |
| 448 | continue; | |
| 449 | objectFeatures.insert(feature.Name); | |
| 450 | if (disallowed.count(feature.Name)) | |
| 451 | error(Twine("Target feature '") + feature.Name + "' used in " + | |
| 452 | fileName + " is disallowed by " + disallowed[feature.Name] + | |
| 453 | ". Use --no-check-features to suppress."); | |
| 454 | } | |
| 455 | for (auto &feature : required.keys()) { | |
| 456 | if (!objectFeatures.count(feature)) | |
| 457 | error(Twine("Missing target feature '") + feature + "' in " + fileName + | |
| 458 | ", required by " + required[feature] + | |
| 459 | ". Use --no-check-features to suppress."); | |
| 460 | } | |
| 802 | 461 | } |
| 803 | 462 | } |
| 804 | 463 | |
| 805 | 464 | void Writer::calculateImports() { |
| 806 | for (Symbol *Sym : Symtab->getSymbols()) { | |
| 807 | if (!Sym->isUndefined()) | |
| 465 | for (Symbol *sym : symtab->getSymbols()) { | |
| 466 | if (!sym->isUndefined()) | |
| 808 | 467 | continue; |
| 809 | if (isa<DataSymbol>(Sym)) | |
| 468 | if (sym->isWeak() && !config->relocatable) | |
| 810 | 469 | continue; |
| 811 | if (Sym->isWeak() && !Config->Relocatable) | |
| 470 | if (!sym->isLive()) | |
| 812 | 471 | continue; |
| 813 | if (!Sym->isLive()) | |
| 472 | if (!sym->isUsedInRegularObj) | |
| 814 | 473 | continue; |
| 815 | if (!Sym->IsUsedInRegularObj) | |
| 474 | // We don't generate imports for data symbols. They however can be imported | |
| 475 | // as GOT entries. | |
| 476 | if (isa<DataSymbol>(sym)) | |
| 816 | 477 | continue; |
| 817 | 478 | |
| 818 | LLVM_DEBUG(dbgs() << "import: " << Sym->getName() << "\n"); | |
| 819 | ImportedSymbols.emplace_back(Sym); | |
| 820 | if (auto *F = dyn_cast<FunctionSymbol>(Sym)) | |
| 821 | F->setFunctionIndex(NumImportedFunctions++); | |
| 822 | else if (auto *G = dyn_cast<GlobalSymbol>(Sym)) | |
| 823 | G->setGlobalIndex(NumImportedGlobals++); | |
| 824 | else | |
| 825 | cast<EventSymbol>(Sym)->setEventIndex(NumImportedEvents++); | |
| 479 | LLVM_DEBUG(dbgs() << "import: " << sym->getName() << "\n"); | |
| 480 | out.importSec->addImport(sym); | |
| 826 | 481 | } |
| 827 | 482 | } |
| 828 | 483 | |
| 829 | 484 | void Writer::calculateExports() { |
| 830 | if (Config->Relocatable) | |
| 485 | if (config->relocatable) | |
| 831 | 486 | return; |
| 832 | 487 | |
| 833 | if (!Config->Relocatable && !Config->ImportMemory) | |
| 834 | Exports.push_back(WasmExport{"memory", WASM_EXTERNAL_MEMORY, 0}); | |
| 488 | if (!config->relocatable && !config->importMemory) | |
| 489 | out.exportSec->exports.push_back( | |
| 490 | WasmExport{"memory", WASM_EXTERNAL_MEMORY, 0}); | |
| 835 | 491 | |
| 836 | if (!Config->Relocatable && Config->ExportTable) | |
| 837 | Exports.push_back(WasmExport{FunctionTableName, WASM_EXTERNAL_TABLE, 0}); | |
| 492 | if (!config->relocatable && config->exportTable) | |
| 493 | out.exportSec->exports.push_back( | |
| 494 | WasmExport{functionTableName, WASM_EXTERNAL_TABLE, 0}); | |
| 838 | 495 | |
| 839 | unsigned FakeGlobalIndex = NumImportedGlobals + InputGlobals.size(); | |
| 496 | unsigned fakeGlobalIndex = out.importSec->getNumImportedGlobals() + | |
| 497 | out.globalSec->inputGlobals.size(); | |
| 840 | 498 | |
| 841 | for (Symbol *Sym : Symtab->getSymbols()) { | |
| 842 | if (!Sym->isExported()) | |
| 499 | for (Symbol *sym : symtab->getSymbols()) { | |
| 500 | if (!sym->isExported()) | |
| 843 | 501 | continue; |
| 844 | if (!Sym->isLive()) | |
| 502 | if (!sym->isLive()) | |
| 845 | 503 | continue; |
| 846 | 504 | |
| 847 | StringRef Name = Sym->getName(); | |
| 848 | WasmExport Export; | |
| 849 | if (auto *F = dyn_cast<DefinedFunction>(Sym)) { | |
| 850 | Export = {Name, WASM_EXTERNAL_FUNCTION, F->getFunctionIndex()}; | |
| 851 | } else if (auto *G = dyn_cast<DefinedGlobal>(Sym)) { | |
| 505 | StringRef name = sym->getName(); | |
| 506 | WasmExport export_; | |
| 507 | if (auto *f = dyn_cast<DefinedFunction>(sym)) { | |
| 508 | export_ = {name, WASM_EXTERNAL_FUNCTION, f->getFunctionIndex()}; | |
| 509 | } else if (auto *g = dyn_cast<DefinedGlobal>(sym)) { | |
| 852 | 510 | // TODO(sbc): Remove this check once to mutable global proposal is |
| 853 | 511 | // implement in all major browsers. |
| 854 | 512 | // See: https://github.com/WebAssembly/mutable-global |
| 855 | if (G->getGlobalType()->Mutable) { | |
| 856 | // Only the __stack_pointer should ever be create as mutable. | |
| 857 | assert(G == WasmSym::StackPointer); | |
| 513 | if (g->getGlobalType()->Mutable) { | |
| 514 | // Only __stack_pointer and __tls_base should ever be create as mutable. | |
| 515 | assert(g == WasmSym::stackPointer || g == WasmSym::tlsBase); | |
| 858 | 516 | continue; |
| 859 | 517 | } |
| 860 | Export = {Name, WASM_EXTERNAL_GLOBAL, G->getGlobalIndex()}; | |
| 861 | } else if (auto *E = dyn_cast<DefinedEvent>(Sym)) { | |
| 862 | Export = {Name, WASM_EXTERNAL_EVENT, E->getEventIndex()}; | |
| 518 | export_ = {name, WASM_EXTERNAL_GLOBAL, g->getGlobalIndex()}; | |
| 519 | } else if (auto *e = dyn_cast<DefinedEvent>(sym)) { | |
| 520 | export_ = {name, WASM_EXTERNAL_EVENT, e->getEventIndex()}; | |
| 863 | 521 | } else { |
| 864 | auto *D = cast<DefinedData>(Sym); | |
| 865 | DefinedFakeGlobals.emplace_back(D); | |
| 866 | Export = {Name, WASM_EXTERNAL_GLOBAL, FakeGlobalIndex++}; | |
| 522 | auto *d = cast<DefinedData>(sym); | |
| 523 | out.globalSec->definedFakeGlobals.emplace_back(d); | |
| 524 | export_ = {name, WASM_EXTERNAL_GLOBAL, fakeGlobalIndex++}; | |
| 867 | 525 | } |
| 868 | 526 | |
| 869 | LLVM_DEBUG(dbgs() << "Export: " << Name << "\n"); | |
| 870 | Exports.push_back(Export); | |
| 527 | LLVM_DEBUG(dbgs() << "Export: " << name << "\n"); | |
| 528 | out.exportSec->exports.push_back(export_); | |
| 871 | 529 | } |
| 872 | 530 | } |
| 873 | 531 | |
| 874 | void Writer::assignSymtab() { | |
| 875 | if (!Config->Relocatable) | |
| 532 | void Writer::populateSymtab() { | |
| 533 | if (!config->relocatable && !config->emitRelocs) | |
| 876 | 534 | return; |
| 877 | 535 | |
| 878 | StringMap<uint32_t> SectionSymbolIndices; | |
| 879 | ||
| 880 | unsigned SymbolIndex = SymtabEntries.size(); | |
| 881 | ||
| 882 | auto AddSymbol = [&](Symbol *Sym) { | |
| 883 | if (auto *S = dyn_cast<SectionSymbol>(Sym)) { | |
| 884 | StringRef Name = S->getName(); | |
| 885 | if (CustomSectionMapping.count(Name) == 0) | |
| 886 | return; | |
| 887 | ||
| 888 | auto SSI = SectionSymbolIndices.find(Name); | |
| 889 | if (SSI != SectionSymbolIndices.end()) { | |
| 890 | Sym->setOutputSymbolIndex(SSI->second); | |
| 891 | return; | |
| 892 | } | |
| 893 | ||
| 894 | SectionSymbolIndices[Name] = SymbolIndex; | |
| 895 | CustomSectionSymbols[Name] = cast<SectionSymbol>(Sym); | |
| 896 | ||
| 897 | Sym->markLive(); | |
| 898 | } | |
| 899 | ||
| 900 | // (Since this is relocatable output, GC is not performed so symbols must | |
| 901 | // be live.) | |
| 902 | assert(Sym->isLive()); | |
| 903 | Sym->setOutputSymbolIndex(SymbolIndex++); | |
| 904 | SymtabEntries.emplace_back(Sym); | |
| 905 | }; | |
| 906 | ||
| 907 | for (Symbol *Sym : Symtab->getSymbols()) | |
| 908 | if (!Sym->isLazy()) | |
| 909 | AddSymbol(Sym); | |
| 536 | for (Symbol *sym : symtab->getSymbols()) | |
| 537 | if (sym->isUsedInRegularObj && sym->isLive()) | |
| 538 | out.linkingSec->addToSymtab(sym); | |
| 910 | 539 | |
| 911 | for (ObjFile *File : Symtab->ObjectFiles) { | |
| 912 | LLVM_DEBUG(dbgs() << "Local symtab entries: " << File->getName() << "\n"); | |
| 913 | for (Symbol *Sym : File->getSymbols()) | |
| 914 | if (Sym->isLocal()) | |
| 915 | AddSymbol(Sym); | |
| 540 | for (ObjFile *file : symtab->objectFiles) { | |
| 541 | LLVM_DEBUG(dbgs() << "Local symtab entries: " << file->getName() << "\n"); | |
| 542 | for (Symbol *sym : file->getSymbols()) | |
| 543 | if (sym->isLocal() && !isa<SectionSymbol>(sym) && sym->isLive()) | |
| 544 | out.linkingSec->addToSymtab(sym); | |
| 916 | 545 | } |
| 917 | 546 | } |
| 918 | 547 | |
| 919 | uint32_t Writer::lookupType(const WasmSignature &Sig) { | |
| 920 | auto It = TypeIndices.find(Sig); | |
| 921 | if (It == TypeIndices.end()) { | |
| 922 | error("type not found: " + toString(Sig)); | |
| 923 | return 0; | |
| 924 | } | |
| 925 | return It->second; | |
| 926 | } | |
| 927 | ||
| 928 | uint32_t Writer::registerType(const WasmSignature &Sig) { | |
| 929 | auto Pair = TypeIndices.insert(std::make_pair(Sig, Types.size())); | |
| 930 | if (Pair.second) { | |
| 931 | LLVM_DEBUG(dbgs() << "type " << toString(Sig) << "\n"); | |
| 932 | Types.push_back(&Sig); | |
| 933 | } | |
| 934 | return Pair.first->second; | |
| 935 | } | |
| 936 | ||
| 937 | 548 | void Writer::calculateTypes() { |
| 938 | 549 | // The output type section is the union of the following sets: |
| 939 | 550 | // 1. Any signature used in the TYPE relocation |
| ... | ... | @@ -942,244 +553,383 @@ void Writer::calculateTypes() { |
| 942 | 553 | // 4. The signatures of all imported events |
| 943 | 554 | // 5. The signatures of all defined events |
| 944 | 555 | |
| 945 | for (ObjFile *File : Symtab->ObjectFiles) { | |
| 946 | ArrayRef<WasmSignature> Types = File->getWasmObj()->types(); | |
| 947 | for (uint32_t I = 0; I < Types.size(); I++) | |
| 948 | if (File->TypeIsUsed[I]) | |
| 949 | File->TypeMap[I] = registerType(Types[I]); | |
| 556 | for (ObjFile *file : symtab->objectFiles) { | |
| 557 | ArrayRef<WasmSignature> types = file->getWasmObj()->types(); | |
| 558 | for (uint32_t i = 0; i < types.size(); i++) | |
| 559 | if (file->typeIsUsed[i]) | |
| 560 | file->typeMap[i] = out.typeSec->registerType(types[i]); | |
| 950 | 561 | } |
| 951 | 562 | |
| 952 | for (const Symbol *Sym : ImportedSymbols) { | |
| 953 | if (auto *F = dyn_cast<FunctionSymbol>(Sym)) | |
| 954 | registerType(*F->Signature); | |
| 955 | else if (auto *E = dyn_cast<EventSymbol>(Sym)) | |
| 956 | registerType(*E->Signature); | |
| 563 | for (const Symbol *sym : out.importSec->importedSymbols) { | |
| 564 | if (auto *f = dyn_cast<FunctionSymbol>(sym)) | |
| 565 | out.typeSec->registerType(*f->signature); | |
| 566 | else if (auto *e = dyn_cast<EventSymbol>(sym)) | |
| 567 | out.typeSec->registerType(*e->signature); | |
| 957 | 568 | } |
| 958 | 569 | |
| 959 | for (const InputFunction *F : InputFunctions) | |
| 960 | registerType(F->Signature); | |
| 570 | for (const InputFunction *f : out.functionSec->inputFunctions) | |
| 571 | out.typeSec->registerType(f->signature); | |
| 961 | 572 | |
| 962 | for (const InputEvent *E : InputEvents) | |
| 963 | registerType(E->Signature); | |
| 573 | for (const InputEvent *e : out.eventSec->inputEvents) | |
| 574 | out.typeSec->registerType(e->signature); | |
| 964 | 575 | } |
| 965 | 576 | |
| 966 | void Writer::assignIndexes() { | |
| 967 | assert(InputFunctions.empty()); | |
| 968 | uint32_t FunctionIndex = NumImportedFunctions; | |
| 969 | auto AddDefinedFunction = [&](InputFunction *Func) { | |
| 970 | if (!Func->Live) | |
| 971 | return; | |
| 972 | InputFunctions.emplace_back(Func); | |
| 973 | Func->setFunctionIndex(FunctionIndex++); | |
| 974 | }; | |
| 975 | ||
| 976 | for (InputFunction *Func : Symtab->SyntheticFunctions) | |
| 977 | AddDefinedFunction(Func); | |
| 978 | ||
| 979 | for (ObjFile *File : Symtab->ObjectFiles) { | |
| 980 | LLVM_DEBUG(dbgs() << "Functions: " << File->getName() << "\n"); | |
| 981 | for (InputFunction *Func : File->Functions) | |
| 982 | AddDefinedFunction(Func); | |
| 577 | static void scanRelocations() { | |
| 578 | for (ObjFile *file : symtab->objectFiles) { | |
| 579 | LLVM_DEBUG(dbgs() << "scanRelocations: " << file->getName() << "\n"); | |
| 580 | for (InputChunk *chunk : file->functions) | |
| 581 | scanRelocations(chunk); | |
| 582 | for (InputChunk *chunk : file->segments) | |
| 583 | scanRelocations(chunk); | |
| 584 | for (auto &p : file->customSections) | |
| 585 | scanRelocations(p); | |
| 983 | 586 | } |
| 587 | } | |
| 984 | 588 | |
| 985 | uint32_t TableIndex = TableBase; | |
| 986 | auto HandleRelocs = [&](InputChunk *Chunk) { | |
| 987 | if (!Chunk->Live) | |
| 988 | return; | |
| 989 | ObjFile *File = Chunk->File; | |
| 990 | ArrayRef<WasmSignature> Types = File->getWasmObj()->types(); | |
| 991 | for (const WasmRelocation &Reloc : Chunk->getRelocations()) { | |
| 992 | if (Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_I32 || | |
| 993 | Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_SLEB) { | |
| 994 | FunctionSymbol *Sym = File->getFunctionSymbol(Reloc.Index); | |
| 995 | if (Sym->hasTableIndex() || !Sym->hasFunctionIndex()) | |
| 996 | continue; | |
| 997 | Sym->setTableIndex(TableIndex++); | |
| 998 | IndirectFunctions.emplace_back(Sym); | |
| 999 | } else if (Reloc.Type == R_WEBASSEMBLY_TYPE_INDEX_LEB) { | |
| 1000 | // Mark target type as live | |
| 1001 | File->TypeMap[Reloc.Index] = registerType(Types[Reloc.Index]); | |
| 1002 | File->TypeIsUsed[Reloc.Index] = true; | |
| 1003 | } | |
| 1004 | } | |
| 1005 | }; | |
| 589 | void Writer::assignIndexes() { | |
| 590 | // Seal the import section, since other index spaces such as function and | |
| 591 | // global are effected by the number of imports. | |
| 592 | out.importSec->seal(); | |
| 1006 | 593 | |
| 1007 | for (ObjFile *File : Symtab->ObjectFiles) { | |
| 1008 | LLVM_DEBUG(dbgs() << "Handle relocs: " << File->getName() << "\n"); | |
| 1009 | for (InputChunk *Chunk : File->Functions) | |
| 1010 | HandleRelocs(Chunk); | |
| 1011 | for (InputChunk *Chunk : File->Segments) | |
| 1012 | HandleRelocs(Chunk); | |
| 1013 | for (auto &P : File->CustomSections) | |
| 1014 | HandleRelocs(P); | |
| 1015 | } | |
| 594 | for (InputFunction *func : symtab->syntheticFunctions) | |
| 595 | out.functionSec->addFunction(func); | |
| 1016 | 596 | |
| 1017 | assert(InputGlobals.empty()); | |
| 1018 | uint32_t GlobalIndex = NumImportedGlobals; | |
| 1019 | auto AddDefinedGlobal = [&](InputGlobal *Global) { | |
| 1020 | if (Global->Live) { | |
| 1021 | LLVM_DEBUG(dbgs() << "AddDefinedGlobal: " << GlobalIndex << "\n"); | |
| 1022 | Global->setGlobalIndex(GlobalIndex++); | |
| 1023 | InputGlobals.push_back(Global); | |
| 1024 | } | |
| 1025 | }; | |
| 597 | for (ObjFile *file : symtab->objectFiles) { | |
| 598 | LLVM_DEBUG(dbgs() << "Functions: " << file->getName() << "\n"); | |
| 599 | for (InputFunction *func : file->functions) | |
| 600 | out.functionSec->addFunction(func); | |
| 601 | } | |
| 1026 | 602 | |
| 1027 | for (InputGlobal *Global : Symtab->SyntheticGlobals) | |
| 1028 | AddDefinedGlobal(Global); | |
| 603 | for (InputGlobal *global : symtab->syntheticGlobals) | |
| 604 | out.globalSec->addGlobal(global); | |
| 1029 | 605 | |
| 1030 | for (ObjFile *File : Symtab->ObjectFiles) { | |
| 1031 | LLVM_DEBUG(dbgs() << "Globals: " << File->getName() << "\n"); | |
| 1032 | for (InputGlobal *Global : File->Globals) | |
| 1033 | AddDefinedGlobal(Global); | |
| 606 | for (ObjFile *file : symtab->objectFiles) { | |
| 607 | LLVM_DEBUG(dbgs() << "Globals: " << file->getName() << "\n"); | |
| 608 | for (InputGlobal *global : file->globals) | |
| 609 | out.globalSec->addGlobal(global); | |
| 1034 | 610 | } |
| 1035 | 611 | |
| 1036 | assert(InputEvents.empty()); | |
| 1037 | uint32_t EventIndex = NumImportedEvents; | |
| 1038 | auto AddDefinedEvent = [&](InputEvent *Event) { | |
| 1039 | if (Event->Live) { | |
| 1040 | LLVM_DEBUG(dbgs() << "AddDefinedEvent: " << EventIndex << "\n"); | |
| 1041 | Event->setEventIndex(EventIndex++); | |
| 1042 | InputEvents.push_back(Event); | |
| 1043 | } | |
| 1044 | }; | |
| 1045 | ||
| 1046 | for (ObjFile *File : Symtab->ObjectFiles) { | |
| 1047 | LLVM_DEBUG(dbgs() << "Events: " << File->getName() << "\n"); | |
| 1048 | for (InputEvent *Event : File->Events) | |
| 1049 | AddDefinedEvent(Event); | |
| 612 | for (ObjFile *file : symtab->objectFiles) { | |
| 613 | LLVM_DEBUG(dbgs() << "Events: " << file->getName() << "\n"); | |
| 614 | for (InputEvent *event : file->events) | |
| 615 | out.eventSec->addEvent(event); | |
| 1050 | 616 | } |
| 1051 | 617 | } |
| 1052 | 618 | |
| 1053 | static StringRef getOutputDataSegmentName(StringRef Name) { | |
| 619 | static StringRef getOutputDataSegmentName(StringRef name) { | |
| 1054 | 620 | // With PIC code we currently only support a single data segment since |
| 1055 | 621 | // we only have a single __memory_base to use as our base address. |
| 1056 | if (Config->Pic) | |
| 1057 | return "data"; | |
| 1058 | if (!Config->MergeDataSegments) | |
| 1059 | return Name; | |
| 1060 | if (Name.startswith(".text.")) | |
| 622 | if (config->isPic) | |
| 623 | return ".data"; | |
| 624 | // We only support one thread-local segment, so we must merge the segments | |
| 625 | // despite --no-merge-data-segments. | |
| 626 | // We also need to merge .tbss into .tdata so they share the same offsets. | |
| 627 | if (name.startswith(".tdata") || name.startswith(".tbss")) | |
| 628 | return ".tdata"; | |
| 629 | if (!config->mergeDataSegments) | |
| 630 | return name; | |
| 631 | if (name.startswith(".text.")) | |
| 1061 | 632 | return ".text"; |
| 1062 | if (Name.startswith(".data.")) | |
| 633 | if (name.startswith(".data.")) | |
| 1063 | 634 | return ".data"; |
| 1064 | if (Name.startswith(".bss.")) | |
| 635 | if (name.startswith(".bss.")) | |
| 1065 | 636 | return ".bss"; |
| 1066 | if (Name.startswith(".rodata.")) | |
| 637 | if (name.startswith(".rodata.")) | |
| 1067 | 638 | return ".rodata"; |
| 1068 | return Name; | |
| 639 | return name; | |
| 1069 | 640 | } |
| 1070 | 641 | |
| 1071 | 642 | void Writer::createOutputSegments() { |
| 1072 | for (ObjFile *File : Symtab->ObjectFiles) { | |
| 1073 | for (InputSegment *Segment : File->Segments) { | |
| 1074 | if (!Segment->Live) | |
| 643 | for (ObjFile *file : symtab->objectFiles) { | |
| 644 | for (InputSegment *segment : file->segments) { | |
| 645 | if (!segment->live) | |
| 1075 | 646 | continue; |
| 1076 | StringRef Name = getOutputDataSegmentName(Segment->getName()); | |
| 1077 | OutputSegment *&S = SegmentMap[Name]; | |
| 1078 | if (S == nullptr) { | |
| 1079 | LLVM_DEBUG(dbgs() << "new segment: " << Name << "\n"); | |
| 1080 | S = make<OutputSegment>(Name, Segments.size()); | |
| 1081 | Segments.push_back(S); | |
| 647 | StringRef name = getOutputDataSegmentName(segment->getName()); | |
| 648 | OutputSegment *&s = segmentMap[name]; | |
| 649 | if (s == nullptr) { | |
| 650 | LLVM_DEBUG(dbgs() << "new segment: " << name << "\n"); | |
| 651 | s = make<OutputSegment>(name, segments.size()); | |
| 652 | if (config->passiveSegments || name == ".tdata") | |
| 653 | s->initFlags = WASM_SEGMENT_IS_PASSIVE; | |
| 654 | segments.push_back(s); | |
| 655 | } | |
| 656 | s->addInputSegment(segment); | |
| 657 | LLVM_DEBUG(dbgs() << "added data: " << name << ": " << s->size << "\n"); | |
| 658 | } | |
| 659 | } | |
| 660 | } | |
| 661 | ||
| 662 | static void createFunction(DefinedFunction *func, StringRef bodyContent) { | |
| 663 | std::string functionBody; | |
| 664 | { | |
| 665 | raw_string_ostream os(functionBody); | |
| 666 | writeUleb128(os, bodyContent.size(), "function size"); | |
| 667 | os << bodyContent; | |
| 668 | } | |
| 669 | ArrayRef<uint8_t> body = arrayRefFromStringRef(saver.save(functionBody)); | |
| 670 | cast<SyntheticFunction>(func->function)->setBody(body); | |
| 671 | } | |
| 672 | ||
| 673 | void Writer::createInitMemoryFunction() { | |
| 674 | LLVM_DEBUG(dbgs() << "createInitMemoryFunction\n"); | |
| 675 | std::string bodyContent; | |
| 676 | { | |
| 677 | raw_string_ostream os(bodyContent); | |
| 678 | writeUleb128(os, 0, "num locals"); | |
| 679 | ||
| 680 | // initialize passive data segments | |
| 681 | for (const OutputSegment *s : segments) { | |
| 682 | if (s->initFlags & WASM_SEGMENT_IS_PASSIVE && s->name != ".tdata") { | |
| 683 | // destination address | |
| 684 | writeU8(os, WASM_OPCODE_I32_CONST, "i32.const"); | |
| 685 | writeSleb128(os, s->startVA, "destination address"); | |
| 686 | // source segment offset | |
| 687 | writeU8(os, WASM_OPCODE_I32_CONST, "i32.const"); | |
| 688 | writeSleb128(os, 0, "segment offset"); | |
| 689 | // memory region size | |
| 690 | writeU8(os, WASM_OPCODE_I32_CONST, "i32.const"); | |
| 691 | writeSleb128(os, s->size, "memory region size"); | |
| 692 | // memory.init instruction | |
| 693 | writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix"); | |
| 694 | writeUleb128(os, WASM_OPCODE_MEMORY_INIT, "MEMORY.INIT"); | |
| 695 | writeUleb128(os, s->index, "segment index immediate"); | |
| 696 | writeU8(os, 0, "memory index immediate"); | |
| 697 | // data.drop instruction | |
| 698 | writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix"); | |
| 699 | writeUleb128(os, WASM_OPCODE_DATA_DROP, "DATA.DROP"); | |
| 700 | writeUleb128(os, s->index, "segment index immediate"); | |
| 1082 | 701 | } |
| 1083 | S->addInputSegment(Segment); | |
| 1084 | LLVM_DEBUG(dbgs() << "added data: " << Name << ": " << S->Size << "\n"); | |
| 1085 | 702 | } |
| 703 | writeU8(os, WASM_OPCODE_END, "END"); | |
| 1086 | 704 | } |
| 705 | ||
| 706 | createFunction(WasmSym::initMemory, bodyContent); | |
| 1087 | 707 | } |
| 1088 | 708 | |
| 1089 | static const int OPCODE_CALL = 0x10; | |
| 1090 | static const int OPCODE_END = 0xb; | |
| 709 | // For -shared (PIC) output, we create create a synthetic function which will | |
| 710 | // apply any relocations to the data segments on startup. This function is | |
| 711 | // called __wasm_apply_relocs and is added at the beginning of __wasm_call_ctors | |
| 712 | // before any of the constructors run. | |
| 713 | void Writer::createApplyRelocationsFunction() { | |
| 714 | LLVM_DEBUG(dbgs() << "createApplyRelocationsFunction\n"); | |
| 715 | // First write the body's contents to a string. | |
| 716 | std::string bodyContent; | |
| 717 | { | |
| 718 | raw_string_ostream os(bodyContent); | |
| 719 | writeUleb128(os, 0, "num locals"); | |
| 720 | for (const OutputSegment *seg : segments) | |
| 721 | for (const InputSegment *inSeg : seg->inputSegments) | |
| 722 | inSeg->generateRelocationCode(os); | |
| 723 | writeU8(os, WASM_OPCODE_END, "END"); | |
| 724 | } | |
| 725 | ||
| 726 | createFunction(WasmSym::applyRelocs, bodyContent); | |
| 727 | } | |
| 1091 | 728 | |
| 1092 | 729 | // Create synthetic "__wasm_call_ctors" function based on ctor functions |
| 1093 | 730 | // in input object. |
| 1094 | void Writer::createCtorFunction() { | |
| 731 | void Writer::createCallCtorsFunction() { | |
| 732 | if (!WasmSym::callCtors->isLive()) | |
| 733 | return; | |
| 734 | ||
| 1095 | 735 | // First write the body's contents to a string. |
| 1096 | std::string BodyContent; | |
| 736 | std::string bodyContent; | |
| 1097 | 737 | { |
| 1098 | raw_string_ostream OS(BodyContent); | |
| 1099 | writeUleb128(OS, 0, "num locals"); | |
| 1100 | for (const WasmInitEntry &F : InitFunctions) { | |
| 1101 | writeU8(OS, OPCODE_CALL, "CALL"); | |
| 1102 | writeUleb128(OS, F.Sym->getFunctionIndex(), "function index"); | |
| 738 | raw_string_ostream os(bodyContent); | |
| 739 | writeUleb128(os, 0, "num locals"); | |
| 740 | ||
| 741 | if (config->passiveSegments) { | |
| 742 | writeU8(os, WASM_OPCODE_CALL, "CALL"); | |
| 743 | writeUleb128(os, WasmSym::initMemory->getFunctionIndex(), | |
| 744 | "function index"); | |
| 745 | } | |
| 746 | ||
| 747 | if (config->isPic) { | |
| 748 | writeU8(os, WASM_OPCODE_CALL, "CALL"); | |
| 749 | writeUleb128(os, WasmSym::applyRelocs->getFunctionIndex(), | |
| 750 | "function index"); | |
| 751 | } | |
| 752 | ||
| 753 | // Call constructors | |
| 754 | for (const WasmInitEntry &f : initFunctions) { | |
| 755 | writeU8(os, WASM_OPCODE_CALL, "CALL"); | |
| 756 | writeUleb128(os, f.sym->getFunctionIndex(), "function index"); | |
| 1103 | 757 | } |
| 1104 | writeU8(OS, OPCODE_END, "END"); | |
| 758 | writeU8(os, WASM_OPCODE_END, "END"); | |
| 1105 | 759 | } |
| 1106 | 760 | |
| 1107 | // Once we know the size of the body we can create the final function body | |
| 1108 | std::string FunctionBody; | |
| 761 | createFunction(WasmSym::callCtors, bodyContent); | |
| 762 | } | |
| 763 | ||
| 764 | void Writer::createInitTLSFunction() { | |
| 765 | if (!WasmSym::initTLS->isLive()) | |
| 766 | return; | |
| 767 | ||
| 768 | std::string bodyContent; | |
| 1109 | 769 | { |
| 1110 | raw_string_ostream OS(FunctionBody); | |
| 1111 | writeUleb128(OS, BodyContent.size(), "function size"); | |
| 1112 | OS << BodyContent; | |
| 770 | raw_string_ostream os(bodyContent); | |
| 771 | ||
| 772 | OutputSegment *tlsSeg = nullptr; | |
| 773 | for (auto *seg : segments) { | |
| 774 | if (seg->name == ".tdata") { | |
| 775 | tlsSeg = seg; | |
| 776 | break; | |
| 777 | } | |
| 778 | } | |
| 779 | ||
| 780 | writeUleb128(os, 0, "num locals"); | |
| 781 | if (tlsSeg) { | |
| 782 | writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); | |
| 783 | writeUleb128(os, 0, "local index"); | |
| 784 | ||
| 785 | writeU8(os, WASM_OPCODE_GLOBAL_SET, "global.set"); | |
| 786 | writeUleb128(os, WasmSym::tlsBase->getGlobalIndex(), "global index"); | |
| 787 | ||
| 788 | writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); | |
| 789 | writeUleb128(os, 0, "local index"); | |
| 790 | ||
| 791 | writeU8(os, WASM_OPCODE_I32_CONST, "i32.const"); | |
| 792 | writeSleb128(os, 0, "segment offset"); | |
| 793 | ||
| 794 | writeU8(os, WASM_OPCODE_I32_CONST, "i32.const"); | |
| 795 | writeSleb128(os, tlsSeg->size, "memory region size"); | |
| 796 | ||
| 797 | writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix"); | |
| 798 | writeUleb128(os, WASM_OPCODE_MEMORY_INIT, "MEMORY.INIT"); | |
| 799 | writeUleb128(os, tlsSeg->index, "segment index immediate"); | |
| 800 | writeU8(os, 0, "memory index immediate"); | |
| 801 | } | |
| 802 | writeU8(os, WASM_OPCODE_END, "end function"); | |
| 1113 | 803 | } |
| 1114 | 804 | |
| 1115 | ArrayRef<uint8_t> Body = arrayRefFromStringRef(Saver.save(FunctionBody)); | |
| 1116 | cast<SyntheticFunction>(WasmSym::CallCtors->Function)->setBody(Body); | |
| 805 | createFunction(WasmSym::initTLS, bodyContent); | |
| 1117 | 806 | } |
| 1118 | 807 | |
| 1119 | 808 | // Populate InitFunctions vector with init functions from all input objects. |
| 1120 | 809 | // This is then used either when creating the output linking section or to |
| 1121 | 810 | // synthesize the "__wasm_call_ctors" function. |
| 1122 | 811 | void Writer::calculateInitFunctions() { |
| 1123 | for (ObjFile *File : Symtab->ObjectFiles) { | |
| 1124 | const WasmLinkingData &L = File->getWasmObj()->linkingData(); | |
| 1125 | for (const WasmInitFunc &F : L.InitFunctions) { | |
| 1126 | FunctionSymbol *Sym = File->getFunctionSymbol(F.Symbol); | |
| 1127 | if (*Sym->Signature != WasmSignature{{}, {}}) | |
| 1128 | error("invalid signature for init func: " + toString(*Sym)); | |
| 1129 | InitFunctions.emplace_back(WasmInitEntry{Sym, F.Priority}); | |
| 812 | if (!config->relocatable && !WasmSym::callCtors->isLive()) | |
| 813 | return; | |
| 814 | ||
| 815 | for (ObjFile *file : symtab->objectFiles) { | |
| 816 | const WasmLinkingData &l = file->getWasmObj()->linkingData(); | |
| 817 | for (const WasmInitFunc &f : l.InitFunctions) { | |
| 818 | FunctionSymbol *sym = file->getFunctionSymbol(f.Symbol); | |
| 819 | // comdat exclusions can cause init functions be discarded. | |
| 820 | if (sym->isDiscarded()) | |
| 821 | continue; | |
| 822 | assert(sym->isLive()); | |
| 823 | if (*sym->signature != WasmSignature{{}, {}}) | |
| 824 | error("invalid signature for init func: " + toString(*sym)); | |
| 825 | LLVM_DEBUG(dbgs() << "initFunctions: " << toString(*sym) << "\n"); | |
| 826 | initFunctions.emplace_back(WasmInitEntry{sym, f.Priority}); | |
| 1130 | 827 | } |
| 1131 | 828 | } |
| 1132 | 829 | |
| 1133 | 830 | // Sort in order of priority (lowest first) so that they are called |
| 1134 | 831 | // in the correct order. |
| 1135 | std::stable_sort(InitFunctions.begin(), InitFunctions.end(), | |
| 1136 | [](const WasmInitEntry &L, const WasmInitEntry &R) { | |
| 1137 | return L.Priority < R.Priority; | |
| 1138 | }); | |
| 832 | llvm::stable_sort(initFunctions, | |
| 833 | [](const WasmInitEntry &l, const WasmInitEntry &r) { | |
| 834 | return l.priority < r.priority; | |
| 835 | }); | |
| 836 | } | |
| 837 | ||
| 838 | void Writer::createSyntheticSections() { | |
| 839 | out.dylinkSec = make<DylinkSection>(); | |
| 840 | out.typeSec = make<TypeSection>(); | |
| 841 | out.importSec = make<ImportSection>(); | |
| 842 | out.functionSec = make<FunctionSection>(); | |
| 843 | out.tableSec = make<TableSection>(); | |
| 844 | out.memorySec = make<MemorySection>(); | |
| 845 | out.globalSec = make<GlobalSection>(); | |
| 846 | out.eventSec = make<EventSection>(); | |
| 847 | out.exportSec = make<ExportSection>(); | |
| 848 | out.elemSec = make<ElemSection>(tableBase); | |
| 849 | out.dataCountSec = make<DataCountSection>(segments.size()); | |
| 850 | out.linkingSec = make<LinkingSection>(initFunctions, segments); | |
| 851 | out.nameSec = make<NameSection>(); | |
| 852 | out.producersSec = make<ProducersSection>(); | |
| 853 | out.targetFeaturesSec = make<TargetFeaturesSection>(); | |
| 1139 | 854 | } |
| 1140 | 855 | |
| 1141 | 856 | void Writer::run() { |
| 1142 | if (Config->Relocatable || Config->Pic) | |
| 1143 | Config->GlobalBase = 0; | |
| 857 | if (config->relocatable || config->isPic) | |
| 858 | config->globalBase = 0; | |
| 1144 | 859 | |
| 1145 | 860 | // For PIC code the table base is assigned dynamically by the loader. |
| 1146 | 861 | // For non-PIC, we start at 1 so that accessing table index 0 always traps. |
| 1147 | if (!Config->Pic) | |
| 1148 | TableBase = 1; | |
| 862 | if (!config->isPic) | |
| 863 | tableBase = 1; | |
| 1149 | 864 | |
| 865 | log("-- createOutputSegments"); | |
| 866 | createOutputSegments(); | |
| 867 | log("-- createSyntheticSections"); | |
| 868 | createSyntheticSections(); | |
| 869 | log("-- populateProducers"); | |
| 870 | populateProducers(); | |
| 871 | log("-- populateTargetFeatures"); | |
| 872 | populateTargetFeatures(); | |
| 1150 | 873 | log("-- calculateImports"); |
| 1151 | 874 | calculateImports(); |
| 875 | log("-- layoutMemory"); | |
| 876 | layoutMemory(); | |
| 877 | ||
| 878 | if (!config->relocatable) { | |
| 879 | // Create linker synthesized __start_SECNAME/__stop_SECNAME symbols | |
| 880 | // This has to be done after memory layout is performed. | |
| 881 | for (const OutputSegment *seg : segments) | |
| 882 | addStartStopSymbols(seg); | |
| 883 | } | |
| 884 | ||
| 885 | log("-- scanRelocations"); | |
| 886 | scanRelocations(); | |
| 1152 | 887 | log("-- assignIndexes"); |
| 1153 | 888 | assignIndexes(); |
| 1154 | 889 | log("-- calculateInitFunctions"); |
| 1155 | 890 | calculateInitFunctions(); |
| 1156 | if (!Config->Relocatable) | |
| 1157 | createCtorFunction(); | |
| 891 | ||
| 892 | if (!config->relocatable) { | |
| 893 | // Create linker synthesized functions | |
| 894 | if (config->passiveSegments) | |
| 895 | createInitMemoryFunction(); | |
| 896 | if (config->isPic) | |
| 897 | createApplyRelocationsFunction(); | |
| 898 | createCallCtorsFunction(); | |
| 899 | } | |
| 900 | ||
| 901 | if (config->sharedMemory && !config->shared) | |
| 902 | createInitTLSFunction(); | |
| 903 | ||
| 904 | if (errorCount()) | |
| 905 | return; | |
| 906 | ||
| 1158 | 907 | log("-- calculateTypes"); |
| 1159 | 908 | calculateTypes(); |
| 1160 | log("-- layoutMemory"); | |
| 1161 | layoutMemory(); | |
| 1162 | 909 | log("-- calculateExports"); |
| 1163 | 910 | calculateExports(); |
| 1164 | 911 | log("-- calculateCustomSections"); |
| 1165 | 912 | calculateCustomSections(); |
| 1166 | log("-- assignSymtab"); | |
| 1167 | assignSymtab(); | |
| 1168 | ||
| 1169 | if (errorHandler().Verbose) { | |
| 1170 | log("Defined Functions: " + Twine(InputFunctions.size())); | |
| 1171 | log("Defined Globals : " + Twine(InputGlobals.size())); | |
| 1172 | log("Defined Events : " + Twine(InputEvents.size())); | |
| 1173 | log("Function Imports : " + Twine(NumImportedFunctions)); | |
| 1174 | log("Global Imports : " + Twine(NumImportedGlobals)); | |
| 1175 | log("Event Imports : " + Twine(NumImportedEvents)); | |
| 1176 | for (ObjFile *File : Symtab->ObjectFiles) | |
| 1177 | File->dumpInfo(); | |
| 913 | log("-- populateSymtab"); | |
| 914 | populateSymtab(); | |
| 915 | log("-- addSections"); | |
| 916 | addSections(); | |
| 917 | ||
| 918 | if (errorHandler().verbose) { | |
| 919 | log("Defined Functions: " + Twine(out.functionSec->inputFunctions.size())); | |
| 920 | log("Defined Globals : " + Twine(out.globalSec->inputGlobals.size())); | |
| 921 | log("Defined Events : " + Twine(out.eventSec->inputEvents.size())); | |
| 922 | log("Function Imports : " + | |
| 923 | Twine(out.importSec->getNumImportedFunctions())); | |
| 924 | log("Global Imports : " + Twine(out.importSec->getNumImportedGlobals())); | |
| 925 | log("Event Imports : " + Twine(out.importSec->getNumImportedEvents())); | |
| 926 | for (ObjFile *file : symtab->objectFiles) | |
| 927 | file->dumpInfo(); | |
| 1178 | 928 | } |
| 1179 | 929 | |
| 1180 | 930 | createHeader(); |
| 1181 | log("-- createSections"); | |
| 1182 | createSections(); | |
| 931 | log("-- finalizeSections"); | |
| 932 | finalizeSections(); | |
| 1183 | 933 | |
| 1184 | 934 | log("-- openFile"); |
| 1185 | 935 | openFile(); |
| ... | ... | @@ -1193,31 +943,31 @@ void Writer::run() { |
| 1193 | 943 | if (errorCount()) |
| 1194 | 944 | return; |
| 1195 | 945 | |
| 1196 | if (Error E = Buffer->commit()) | |
| 1197 | fatal("failed to write the output file: " + toString(std::move(E))); | |
| 946 | if (Error e = buffer->commit()) | |
| 947 | fatal("failed to write the output file: " + toString(std::move(e))); | |
| 1198 | 948 | } |
| 1199 | 949 | |
| 1200 | 950 | // Open a result file. |
| 1201 | 951 | void Writer::openFile() { |
| 1202 | log("writing: " + Config->OutputFile); | |
| 952 | log("writing: " + config->outputFile); | |
| 1203 | 953 | |
| 1204 | Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = | |
| 1205 | FileOutputBuffer::create(Config->OutputFile, FileSize, | |
| 954 | Expected<std::unique_ptr<FileOutputBuffer>> bufferOrErr = | |
| 955 | FileOutputBuffer::create(config->outputFile, fileSize, | |
| 1206 | 956 | FileOutputBuffer::F_executable); |
| 1207 | 957 | |
| 1208 | if (!BufferOrErr) | |
| 1209 | error("failed to open " + Config->OutputFile + ": " + | |
| 1210 | toString(BufferOrErr.takeError())); | |
| 958 | if (!bufferOrErr) | |
| 959 | error("failed to open " + config->outputFile + ": " + | |
| 960 | toString(bufferOrErr.takeError())); | |
| 1211 | 961 | else |
| 1212 | Buffer = std::move(*BufferOrErr); | |
| 962 | buffer = std::move(*bufferOrErr); | |
| 1213 | 963 | } |
| 1214 | 964 | |
| 1215 | 965 | void Writer::createHeader() { |
| 1216 | raw_string_ostream OS(Header); | |
| 1217 | writeBytes(OS, WasmMagic, sizeof(WasmMagic), "wasm magic"); | |
| 1218 | writeU32(OS, WasmVersion, "wasm version"); | |
| 1219 | OS.flush(); | |
| 1220 | FileSize += Header.size(); | |
| 966 | raw_string_ostream os(header); | |
| 967 | writeBytes(os, WasmMagic, sizeof(WasmMagic), "wasm magic"); | |
| 968 | writeU32(os, WasmVersion, "wasm version"); | |
| 969 | os.flush(); | |
| 970 | fileSize += header.size(); | |
| 1221 | 971 | } |
| 1222 | 972 | |
| 1223 | 973 | void lld::wasm::writeResult() { Writer().run(); } |
deps/lld/wasm/Writer.h+3-6| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- Writer.h -------------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -15,8 +14,6 @@ namespace wasm { |
| 15 | 14 | |
| 16 | 15 | void writeResult(); |
| 17 | 16 | |
| 18 | extern const char *DefaultModule; | |
| 19 | ||
| 20 | 17 | } // namespace wasm |
| 21 | 18 | } // namespace lld |
| 22 | 19 |
deps/lld/wasm/WriterUtils.cpp+104-105| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- WriterUtils.cpp ----------------------------------------------------===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -20,159 +19,159 @@ using namespace llvm::wasm; |
| 20 | 19 | |
| 21 | 20 | namespace lld { |
| 22 | 21 | |
| 23 | void wasm::debugWrite(uint64_t Offset, const Twine &Msg) { | |
| 24 | LLVM_DEBUG(dbgs() << format(" | %08lld: ", Offset) << Msg << "\n"); | |
| 22 | void wasm::debugWrite(uint64_t offset, const Twine &msg) { | |
| 23 | LLVM_DEBUG(dbgs() << format(" | %08lld: ", offset) << msg << "\n"); | |
| 25 | 24 | } |
| 26 | 25 | |
| 27 | void wasm::writeUleb128(raw_ostream &OS, uint32_t Number, const Twine &Msg) { | |
| 28 | debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]"); | |
| 29 | encodeULEB128(Number, OS); | |
| 26 | void wasm::writeUleb128(raw_ostream &os, uint32_t number, const Twine &msg) { | |
| 27 | debugWrite(os.tell(), msg + "[" + utohexstr(number) + "]"); | |
| 28 | encodeULEB128(number, os); | |
| 30 | 29 | } |
| 31 | 30 | |
| 32 | void wasm::writeSleb128(raw_ostream &OS, int32_t Number, const Twine &Msg) { | |
| 33 | debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]"); | |
| 34 | encodeSLEB128(Number, OS); | |
| 31 | void wasm::writeSleb128(raw_ostream &os, int32_t number, const Twine &msg) { | |
| 32 | debugWrite(os.tell(), msg + "[" + utohexstr(number) + "]"); | |
| 33 | encodeSLEB128(number, os); | |
| 35 | 34 | } |
| 36 | 35 | |
| 37 | void wasm::writeBytes(raw_ostream &OS, const char *Bytes, size_t Count, | |
| 38 | const Twine &Msg) { | |
| 39 | debugWrite(OS.tell(), Msg + " [data[" + Twine(Count) + "]]"); | |
| 40 | OS.write(Bytes, Count); | |
| 36 | void wasm::writeBytes(raw_ostream &os, const char *bytes, size_t count, | |
| 37 | const Twine &msg) { | |
| 38 | debugWrite(os.tell(), msg + " [data[" + Twine(count) + "]]"); | |
| 39 | os.write(bytes, count); | |
| 41 | 40 | } |
| 42 | 41 | |
| 43 | void wasm::writeStr(raw_ostream &OS, StringRef String, const Twine &Msg) { | |
| 44 | debugWrite(OS.tell(), | |
| 45 | Msg + " [str[" + Twine(String.size()) + "]: " + String + "]"); | |
| 46 | encodeULEB128(String.size(), OS); | |
| 47 | OS.write(String.data(), String.size()); | |
| 42 | void wasm::writeStr(raw_ostream &os, StringRef string, const Twine &msg) { | |
| 43 | debugWrite(os.tell(), | |
| 44 | msg + " [str[" + Twine(string.size()) + "]: " + string + "]"); | |
| 45 | encodeULEB128(string.size(), os); | |
| 46 | os.write(string.data(), string.size()); | |
| 48 | 47 | } |
| 49 | 48 | |
| 50 | void wasm::writeU8(raw_ostream &OS, uint8_t Byte, const Twine &Msg) { | |
| 51 | debugWrite(OS.tell(), Msg + " [0x" + utohexstr(Byte) + "]"); | |
| 52 | OS << Byte; | |
| 49 | void wasm::writeU8(raw_ostream &os, uint8_t byte, const Twine &msg) { | |
| 50 | debugWrite(os.tell(), msg + " [0x" + utohexstr(byte) + "]"); | |
| 51 | os << byte; | |
| 53 | 52 | } |
| 54 | 53 | |
| 55 | void wasm::writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg) { | |
| 56 | debugWrite(OS.tell(), Msg + "[0x" + utohexstr(Number) + "]"); | |
| 57 | support::endian::write(OS, Number, support::little); | |
| 54 | void wasm::writeU32(raw_ostream &os, uint32_t number, const Twine &msg) { | |
| 55 | debugWrite(os.tell(), msg + "[0x" + utohexstr(number) + "]"); | |
| 56 | support::endian::write(os, number, support::little); | |
| 58 | 57 | } |
| 59 | 58 | |
| 60 | void wasm::writeValueType(raw_ostream &OS, ValType Type, const Twine &Msg) { | |
| 61 | writeU8(OS, static_cast<uint8_t>(Type), | |
| 62 | Msg + "[type: " + toString(Type) + "]"); | |
| 59 | void wasm::writeValueType(raw_ostream &os, ValType type, const Twine &msg) { | |
| 60 | writeU8(os, static_cast<uint8_t>(type), | |
| 61 | msg + "[type: " + toString(type) + "]"); | |
| 63 | 62 | } |
| 64 | 63 | |
| 65 | void wasm::writeSig(raw_ostream &OS, const WasmSignature &Sig) { | |
| 66 | writeU8(OS, WASM_TYPE_FUNC, "signature type"); | |
| 67 | writeUleb128(OS, Sig.Params.size(), "param Count"); | |
| 68 | for (ValType ParamType : Sig.Params) { | |
| 69 | writeValueType(OS, ParamType, "param type"); | |
| 64 | void wasm::writeSig(raw_ostream &os, const WasmSignature &sig) { | |
| 65 | writeU8(os, WASM_TYPE_FUNC, "signature type"); | |
| 66 | writeUleb128(os, sig.Params.size(), "param Count"); | |
| 67 | for (ValType paramType : sig.Params) { | |
| 68 | writeValueType(os, paramType, "param type"); | |
| 70 | 69 | } |
| 71 | writeUleb128(OS, Sig.Returns.size(), "result Count"); | |
| 72 | if (Sig.Returns.size()) { | |
| 73 | writeValueType(OS, Sig.Returns[0], "result type"); | |
| 70 | writeUleb128(os, sig.Returns.size(), "result Count"); | |
| 71 | if (sig.Returns.size()) { | |
| 72 | writeValueType(os, sig.Returns[0], "result type"); | |
| 74 | 73 | } |
| 75 | 74 | } |
| 76 | 75 | |
| 77 | void wasm::writeInitExpr(raw_ostream &OS, const WasmInitExpr &InitExpr) { | |
| 78 | writeU8(OS, InitExpr.Opcode, "opcode"); | |
| 79 | switch (InitExpr.Opcode) { | |
| 76 | void wasm::writeInitExpr(raw_ostream &os, const WasmInitExpr &initExpr) { | |
| 77 | writeU8(os, initExpr.Opcode, "opcode"); | |
| 78 | switch (initExpr.Opcode) { | |
| 80 | 79 | case WASM_OPCODE_I32_CONST: |
| 81 | writeSleb128(OS, InitExpr.Value.Int32, "literal (i32)"); | |
| 80 | writeSleb128(os, initExpr.Value.Int32, "literal (i32)"); | |
| 82 | 81 | break; |
| 83 | 82 | case WASM_OPCODE_I64_CONST: |
| 84 | writeSleb128(OS, InitExpr.Value.Int64, "literal (i64)"); | |
| 83 | writeSleb128(os, initExpr.Value.Int64, "literal (i64)"); | |
| 85 | 84 | break; |
| 86 | 85 | case WASM_OPCODE_GLOBAL_GET: |
| 87 | writeUleb128(OS, InitExpr.Value.Global, "literal (global index)"); | |
| 86 | writeUleb128(os, initExpr.Value.Global, "literal (global index)"); | |
| 88 | 87 | break; |
| 89 | 88 | default: |
| 90 | fatal("unknown opcode in init expr: " + Twine(InitExpr.Opcode)); | |
| 89 | fatal("unknown opcode in init expr: " + Twine(initExpr.Opcode)); | |
| 91 | 90 | } |
| 92 | writeU8(OS, WASM_OPCODE_END, "opcode:end"); | |
| 91 | writeU8(os, WASM_OPCODE_END, "opcode:end"); | |
| 93 | 92 | } |
| 94 | 93 | |
| 95 | void wasm::writeLimits(raw_ostream &OS, const WasmLimits &Limits) { | |
| 96 | writeU8(OS, Limits.Flags, "limits flags"); | |
| 97 | writeUleb128(OS, Limits.Initial, "limits initial"); | |
| 98 | if (Limits.Flags & WASM_LIMITS_FLAG_HAS_MAX) | |
| 99 | writeUleb128(OS, Limits.Maximum, "limits max"); | |
| 94 | void wasm::writeLimits(raw_ostream &os, const WasmLimits &limits) { | |
| 95 | writeU8(os, limits.Flags, "limits flags"); | |
| 96 | writeUleb128(os, limits.Initial, "limits initial"); | |
| 97 | if (limits.Flags & WASM_LIMITS_FLAG_HAS_MAX) | |
| 98 | writeUleb128(os, limits.Maximum, "limits max"); | |
| 100 | 99 | } |
| 101 | 100 | |
| 102 | void wasm::writeGlobalType(raw_ostream &OS, const WasmGlobalType &Type) { | |
| 101 | void wasm::writeGlobalType(raw_ostream &os, const WasmGlobalType &type) { | |
| 103 | 102 | // TODO: Update WasmGlobalType to use ValType and remove this cast. |
| 104 | writeValueType(OS, ValType(Type.Type), "global type"); | |
| 105 | writeU8(OS, Type.Mutable, "global mutable"); | |
| 103 | writeValueType(os, ValType(type.Type), "global type"); | |
| 104 | writeU8(os, type.Mutable, "global mutable"); | |
| 106 | 105 | } |
| 107 | 106 | |
| 108 | void wasm::writeGlobal(raw_ostream &OS, const WasmGlobal &Global) { | |
| 109 | writeGlobalType(OS, Global.Type); | |
| 110 | writeInitExpr(OS, Global.InitExpr); | |
| 107 | void wasm::writeGlobal(raw_ostream &os, const WasmGlobal &global) { | |
| 108 | writeGlobalType(os, global.Type); | |
| 109 | writeInitExpr(os, global.InitExpr); | |
| 111 | 110 | } |
| 112 | 111 | |
| 113 | void wasm::writeEventType(raw_ostream &OS, const WasmEventType &Type) { | |
| 114 | writeUleb128(OS, Type.Attribute, "event attribute"); | |
| 115 | writeUleb128(OS, Type.SigIndex, "sig index"); | |
| 112 | void wasm::writeEventType(raw_ostream &os, const WasmEventType &type) { | |
| 113 | writeUleb128(os, type.Attribute, "event attribute"); | |
| 114 | writeUleb128(os, type.SigIndex, "sig index"); | |
| 116 | 115 | } |
| 117 | 116 | |
| 118 | void wasm::writeEvent(raw_ostream &OS, const WasmEvent &Event) { | |
| 119 | writeEventType(OS, Event.Type); | |
| 117 | void wasm::writeEvent(raw_ostream &os, const WasmEvent &event) { | |
| 118 | writeEventType(os, event.Type); | |
| 120 | 119 | } |
| 121 | 120 | |
| 122 | void wasm::writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type) { | |
| 123 | writeU8(OS, WASM_TYPE_FUNCREF, "table type"); | |
| 124 | writeLimits(OS, Type.Limits); | |
| 121 | void wasm::writeTableType(raw_ostream &os, const llvm::wasm::WasmTable &type) { | |
| 122 | writeU8(os, WASM_TYPE_FUNCREF, "table type"); | |
| 123 | writeLimits(os, type.Limits); | |
| 125 | 124 | } |
| 126 | 125 | |
| 127 | void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) { | |
| 128 | writeStr(OS, Import.Module, "import module name"); | |
| 129 | writeStr(OS, Import.Field, "import field name"); | |
| 130 | writeU8(OS, Import.Kind, "import kind"); | |
| 131 | switch (Import.Kind) { | |
| 126 | void wasm::writeImport(raw_ostream &os, const WasmImport &import) { | |
| 127 | writeStr(os, import.Module, "import module name"); | |
| 128 | writeStr(os, import.Field, "import field name"); | |
| 129 | writeU8(os, import.Kind, "import kind"); | |
| 130 | switch (import.Kind) { | |
| 132 | 131 | case WASM_EXTERNAL_FUNCTION: |
| 133 | writeUleb128(OS, Import.SigIndex, "import sig index"); | |
| 132 | writeUleb128(os, import.SigIndex, "import sig index"); | |
| 134 | 133 | break; |
| 135 | 134 | case WASM_EXTERNAL_GLOBAL: |
| 136 | writeGlobalType(OS, Import.Global); | |
| 135 | writeGlobalType(os, import.Global); | |
| 137 | 136 | break; |
| 138 | 137 | case WASM_EXTERNAL_EVENT: |
| 139 | writeEventType(OS, Import.Event); | |
| 138 | writeEventType(os, import.Event); | |
| 140 | 139 | break; |
| 141 | 140 | case WASM_EXTERNAL_MEMORY: |
| 142 | writeLimits(OS, Import.Memory); | |
| 141 | writeLimits(os, import.Memory); | |
| 143 | 142 | break; |
| 144 | 143 | case WASM_EXTERNAL_TABLE: |
| 145 | writeTableType(OS, Import.Table); | |
| 144 | writeTableType(os, import.Table); | |
| 146 | 145 | break; |
| 147 | 146 | default: |
| 148 | fatal("unsupported import type: " + Twine(Import.Kind)); | |
| 147 | fatal("unsupported import type: " + Twine(import.Kind)); | |
| 149 | 148 | } |
| 150 | 149 | } |
| 151 | 150 | |
| 152 | void wasm::writeExport(raw_ostream &OS, const WasmExport &Export) { | |
| 153 | writeStr(OS, Export.Name, "export name"); | |
| 154 | writeU8(OS, Export.Kind, "export kind"); | |
| 155 | switch (Export.Kind) { | |
| 151 | void wasm::writeExport(raw_ostream &os, const WasmExport &export_) { | |
| 152 | writeStr(os, export_.Name, "export name"); | |
| 153 | writeU8(os, export_.Kind, "export kind"); | |
| 154 | switch (export_.Kind) { | |
| 156 | 155 | case WASM_EXTERNAL_FUNCTION: |
| 157 | writeUleb128(OS, Export.Index, "function index"); | |
| 156 | writeUleb128(os, export_.Index, "function index"); | |
| 158 | 157 | break; |
| 159 | 158 | case WASM_EXTERNAL_GLOBAL: |
| 160 | writeUleb128(OS, Export.Index, "global index"); | |
| 159 | writeUleb128(os, export_.Index, "global index"); | |
| 161 | 160 | break; |
| 162 | 161 | case WASM_EXTERNAL_MEMORY: |
| 163 | writeUleb128(OS, Export.Index, "memory index"); | |
| 162 | writeUleb128(os, export_.Index, "memory index"); | |
| 164 | 163 | break; |
| 165 | 164 | case WASM_EXTERNAL_TABLE: |
| 166 | writeUleb128(OS, Export.Index, "table index"); | |
| 165 | writeUleb128(os, export_.Index, "table index"); | |
| 167 | 166 | break; |
| 168 | 167 | default: |
| 169 | fatal("unsupported export type: " + Twine(Export.Kind)); | |
| 168 | fatal("unsupported export type: " + Twine(export_.Kind)); | |
| 170 | 169 | } |
| 171 | 170 | } |
| 172 | 171 | } // namespace lld |
| 173 | 172 | |
| 174 | std::string lld::toString(ValType Type) { | |
| 175 | switch (Type) { | |
| 173 | std::string lld::toString(ValType type) { | |
| 174 | switch (type) { | |
| 176 | 175 | case ValType::I32: |
| 177 | 176 | return "i32"; |
| 178 | 177 | case ValType::I64: |
| ... | ... | @@ -183,34 +182,34 @@ std::string lld::toString(ValType Type) { |
| 183 | 182 | return "f64"; |
| 184 | 183 | case ValType::V128: |
| 185 | 184 | return "v128"; |
| 186 | case ValType::EXCEPT_REF: | |
| 187 | return "except_ref"; | |
| 185 | case ValType::EXNREF: | |
| 186 | return "exnref"; | |
| 188 | 187 | } |
| 189 | 188 | llvm_unreachable("Invalid wasm::ValType"); |
| 190 | 189 | } |
| 191 | 190 | |
| 192 | std::string lld::toString(const WasmSignature &Sig) { | |
| 193 | SmallString<128> S("("); | |
| 194 | for (ValType Type : Sig.Params) { | |
| 195 | if (S.size() != 1) | |
| 196 | S += ", "; | |
| 197 | S += toString(Type); | |
| 191 | std::string lld::toString(const WasmSignature &sig) { | |
| 192 | SmallString<128> s("("); | |
| 193 | for (ValType type : sig.Params) { | |
| 194 | if (s.size() != 1) | |
| 195 | s += ", "; | |
| 196 | s += toString(type); | |
| 198 | 197 | } |
| 199 | S += ") -> "; | |
| 200 | if (Sig.Returns.size() == 0) | |
| 201 | S += "void"; | |
| 198 | s += ") -> "; | |
| 199 | if (sig.Returns.empty()) | |
| 200 | s += "void"; | |
| 202 | 201 | else |
| 203 | S += toString(Sig.Returns[0]); | |
| 204 | return S.str(); | |
| 202 | s += toString(sig.Returns[0]); | |
| 203 | return s.str(); | |
| 205 | 204 | } |
| 206 | 205 | |
| 207 | std::string lld::toString(const WasmGlobalType &Type) { | |
| 208 | return (Type.Mutable ? "var " : "const ") + | |
| 209 | toString(static_cast<ValType>(Type.Type)); | |
| 206 | std::string lld::toString(const WasmGlobalType &type) { | |
| 207 | return (type.Mutable ? "var " : "const ") + | |
| 208 | toString(static_cast<ValType>(type.Type)); | |
| 210 | 209 | } |
| 211 | 210 | |
| 212 | std::string lld::toString(const WasmEventType &Type) { | |
| 213 | if (Type.Attribute == WASM_EVENT_ATTRIBUTE_EXCEPTION) | |
| 211 | std::string lld::toString(const WasmEventType &type) { | |
| 212 | if (type.Attribute == WASM_EVENT_ATTRIBUTE_EXCEPTION) | |
| 214 | 213 | return "exception"; |
| 215 | 214 | return "unknown"; |
| 216 | 215 | } |
deps/lld/wasm/WriterUtils.h+27-28| ... | ... | @@ -1,9 +1,8 @@ |
| 1 | 1 | //===- WriterUtils.h --------------------------------------------*- C++ -*-===// |
| 2 | 2 | // |
| 3 | // The LLVM Linker | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| 7 | 6 | // |
| 8 | 7 | //===----------------------------------------------------------------------===// |
| 9 | 8 | |
| ... | ... | @@ -17,50 +16,50 @@ |
| 17 | 16 | namespace lld { |
| 18 | 17 | namespace wasm { |
| 19 | 18 | |
| 20 | void debugWrite(uint64_t Offset, const Twine &Msg); | |
| 19 | void debugWrite(uint64_t offset, const Twine &msg); | |
| 21 | 20 | |
| 22 | void writeUleb128(raw_ostream &OS, uint32_t Number, const Twine &Msg); | |
| 21 | void writeUleb128(raw_ostream &os, uint32_t number, const Twine &msg); | |
| 23 | 22 | |
| 24 | void writeSleb128(raw_ostream &OS, int32_t Number, const Twine &Msg); | |
| 23 | void writeSleb128(raw_ostream &os, int32_t number, const Twine &msg); | |
| 25 | 24 | |
| 26 | void writeBytes(raw_ostream &OS, const char *Bytes, size_t count, | |
| 27 | const Twine &Msg); | |
| 25 | void writeBytes(raw_ostream &os, const char *bytes, size_t count, | |
| 26 | const Twine &msg); | |
| 28 | 27 | |
| 29 | void writeStr(raw_ostream &OS, StringRef String, const Twine &Msg); | |
| 28 | void writeStr(raw_ostream &os, StringRef string, const Twine &msg); | |
| 30 | 29 | |
| 31 | void writeU8(raw_ostream &OS, uint8_t byte, const Twine &Msg); | |
| 30 | void writeU8(raw_ostream &os, uint8_t byte, const Twine &msg); | |
| 32 | 31 | |
| 33 | void writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg); | |
| 32 | void writeU32(raw_ostream &os, uint32_t number, const Twine &msg); | |
| 34 | 33 | |
| 35 | void writeValueType(raw_ostream &OS, llvm::wasm::ValType Type, | |
| 36 | const Twine &Msg); | |
| 34 | void writeValueType(raw_ostream &os, llvm::wasm::ValType type, | |
| 35 | const Twine &msg); | |
| 37 | 36 | |
| 38 | void writeSig(raw_ostream &OS, const llvm::wasm::WasmSignature &Sig); | |
| 37 | void writeSig(raw_ostream &os, const llvm::wasm::WasmSignature &sig); | |
| 39 | 38 | |
| 40 | void writeInitExpr(raw_ostream &OS, const llvm::wasm::WasmInitExpr &InitExpr); | |
| 39 | void writeInitExpr(raw_ostream &os, const llvm::wasm::WasmInitExpr &initExpr); | |
| 41 | 40 | |
| 42 | void writeLimits(raw_ostream &OS, const llvm::wasm::WasmLimits &Limits); | |
| 41 | void writeLimits(raw_ostream &os, const llvm::wasm::WasmLimits &limits); | |
| 43 | 42 | |
| 44 | void writeGlobalType(raw_ostream &OS, const llvm::wasm::WasmGlobalType &Type); | |
| 43 | void writeGlobalType(raw_ostream &os, const llvm::wasm::WasmGlobalType &type); | |
| 45 | 44 | |
| 46 | void writeGlobal(raw_ostream &OS, const llvm::wasm::WasmGlobal &Global); | |
| 45 | void writeGlobal(raw_ostream &os, const llvm::wasm::WasmGlobal &global); | |
| 47 | 46 | |
| 48 | void writeEventType(raw_ostream &OS, const llvm::wasm::WasmEventType &Type); | |
| 47 | void writeEventType(raw_ostream &os, const llvm::wasm::WasmEventType &type); | |
| 49 | 48 | |
| 50 | void writeEvent(raw_ostream &OS, const llvm::wasm::WasmEvent &Event); | |
| 49 | void writeEvent(raw_ostream &os, const llvm::wasm::WasmEvent &event); | |
| 51 | 50 | |
| 52 | void writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type); | |
| 51 | void writeTableType(raw_ostream &os, const llvm::wasm::WasmTable &type); | |
| 53 | 52 | |
| 54 | void writeImport(raw_ostream &OS, const llvm::wasm::WasmImport &Import); | |
| 53 | void writeImport(raw_ostream &os, const llvm::wasm::WasmImport &import); | |
| 55 | 54 | |
| 56 | void writeExport(raw_ostream &OS, const llvm::wasm::WasmExport &Export); | |
| 55 | void writeExport(raw_ostream &os, const llvm::wasm::WasmExport &export_); | |
| 57 | 56 | |
| 58 | 57 | } // namespace wasm |
| 59 | 58 | |
| 60 | std::string toString(llvm::wasm::ValType Type); | |
| 61 | std::string toString(const llvm::wasm::WasmSignature &Sig); | |
| 62 | std::string toString(const llvm::wasm::WasmGlobalType &Type); | |
| 63 | std::string toString(const llvm::wasm::WasmEventType &Type); | |
| 59 | std::string toString(llvm::wasm::ValType type); | |
| 60 | std::string toString(const llvm::wasm::WasmSignature &sig); | |
| 61 | std::string toString(const llvm::wasm::WasmGlobalType &type); | |
| 62 | std::string toString(const llvm::wasm::WasmEventType &type); | |
| 64 | 63 | |
| 65 | 64 | } // namespace lld |
| 66 | 65 |