1 /* 2 * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.tools.jaotc.binformat; 25 26 import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT; 27 28 import java.io.ByteArrayOutputStream; 29 import java.io.DataOutputStream; 30 import java.io.IOException; 31 import java.util.ArrayList; 32 import java.util.HashMap; 33 import java.util.List; 34 import java.util.Map; 35 36 import jdk.tools.jaotc.binformat.Symbol.Binding; 37 import jdk.tools.jaotc.binformat.Symbol.Kind; 38 import jdk.tools.jaotc.binformat.elf.JELFRelocObject; 39 import jdk.tools.jaotc.binformat.macho.JMachORelocObject; 40 import jdk.tools.jaotc.binformat.pecoff.JPECoffRelocObject; 41 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; 42 43 /** 44 * A format-agnostic container class that holds various components of a binary. 45 * 46 * <p> 47 * This class holds information necessary to create platform-specific binary containers such as 48 * ELFContainer for Linux and Solaris operating systems or MachOContainer for Mac 49 * OS or PEContainer for MS Windows operating systems. 50 * 51 * <p> 52 * Method APIs provided by this class are used to construct and populate platform-independent 53 * contents of a binary as the first step to create a binary representation of code generated by a 54 * compiler backend such as Graal. 55 * 56 * <p> 57 * Methods to record and access code section contents, symbols and relocations are provided. 58 */ 59 public class BinaryContainer implements SymbolTable { 60 61 private final int codeSegmentSize; 62 63 private final int codeEntryAlignment; 64 65 /** 66 * Container holding code bits and any other related information. 67 */ 68 private final CodeContainer codeContainer; 69 70 /** 71 * Container holding external hotspot linkage bits (PLT entries). 72 */ 73 private final CodeContainer extLinkageContainer; 74 75 /** 76 * Container holding global offset data for hotspot linkage. 77 */ 78 private final ByteContainer extLinkageGOTContainer; 79 80 /** 81 * Patched by HotSpot, contains metaspace pointers. 82 */ 83 private final ByteContainer metaspaceGotContainer; 84 85 /** 86 * Patched lazily by hotspot, contains klass/method pointers. 87 */ 88 private final ByteContainer metadataGotContainer; 89 90 /** 91 * BSS container, contains method state array. 92 */ 93 private final ByteContainer methodStateContainer; 94 95 /** 96 * Patched by hotspot, contains java object pointers. 97 */ 98 private final ByteContainer oopGotContainer; 99 100 // Containers holding read-only data 101 private final ReadOnlyDataContainer configContainer; 102 private final ReadOnlyDataContainer metaspaceNamesContainer; 103 private final ReadOnlyDataContainer methodsOffsetsContainer; 104 private final ReadOnlyDataContainer klassesOffsetsContainer; 105 private final ReadOnlyDataContainer klassesDependenciesContainer; 106 private final HeaderContainer headerContainer; 107 private final ReadOnlyDataContainer stubsOffsetsContainer; 108 private final ReadOnlyDataContainer codeSegmentsContainer; 109 110 // This cannot be read only since we need to patch the metadata at runtime.. 111 private final ReadOnlyDataContainer methodMetadataContainer; 112 113 /** 114 * Container containing constant data used by code. 115 */ 116 private final ReadOnlyDataContainer constantDataContainer; 117 118 /** 119 * Map holding the Strings table. 120 */ 121 private final Map<String, Integer> offsetStringTable = new HashMap<>(); 122 123 private final Map<String, Integer> metaspaceNames = new HashMap<>(); 124 125 // List of relocation table entries - (symbolName, relocationInfo) 126 private final Map<String, Symbol> symbolTable = new HashMap<>(); 127 private final Map<Symbol, List<Relocation>> relocationTable = new HashMap<>(); 128 private final Map<Symbol, Relocation> uniqueRelocationTable = new HashMap<>(); 129 130 /** 131 * Mapping of local VM function names to known global symbols generated in the output binary. 132 */ 133 private static final HashMap<String, String> functionNamesToAOTSymbols = new HashMap<>(); 134 135 private static final String[][] map = { 136 //@formatter:off 137 {"CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", "_aot_deopt_blob_unpack"}, 138 {"CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap", "_aot_deopt_blob_uncommon_trap"}, 139 {"CompilerToVM::Data::SharedRuntime_ic_miss_stub", "_aot_ic_miss_stub"}, 140 {"CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub", "_aot_handle_wrong_method_stub"}, 141 {"SharedRuntime::exception_handler_for_return_address", "_aot_exception_handler_for_return_address"}, 142 {"SharedRuntime::register_finalizer", "_aot_register_finalizer"}, 143 {"SharedRuntime::OSR_migration_end", "_aot_OSR_migration_end"}, 144 {"CompilerRuntime::resolve_string_by_symbol", "_aot_resolve_string_by_symbol"}, 145 {"CompilerRuntime::resolve_klass_by_symbol", "_aot_resolve_klass_by_symbol"}, 146 {"CompilerRuntime::resolve_method_by_symbol_and_load_counters","_aot_resolve_method_by_symbol_and_load_counters"}, 147 {"CompilerRuntime::initialize_klass_by_symbol", "_aot_initialize_klass_by_symbol"}, 148 {"CompilerRuntime::invocation_event", "_aot_invocation_event"}, 149 {"CompilerRuntime::backedge_event", "_aot_backedge_event"}, 150 151 {"CompilerToVM::Data::dpow", "_aot_shared_runtime_dpow"}, 152 {"CompilerToVM::Data::dexp", "_aot_shared_runtime_dexp"}, 153 {"CompilerToVM::Data::dcos", "_aot_shared_runtime_dcos"}, 154 {"CompilerToVM::Data::dsin", "_aot_shared_runtime_dsin"}, 155 {"CompilerToVM::Data::dtan", "_aot_shared_runtime_dtan"}, 156 {"CompilerToVM::Data::dlog", "_aot_shared_runtime_dlog"}, 157 {"CompilerToVM::Data::dlog10", "_aot_shared_runtime_dlog10"}, 158 159 {"StubRoutines::_jbyte_arraycopy", "_aot_stub_routines_jbyte_arraycopy"}, 160 {"StubRoutines::_jshort_arraycopy", "_aot_stub_routines_jshort_arraycopy"}, 161 {"StubRoutines::_jint_arraycopy", "_aot_stub_routines_jint_arraycopy"}, 162 {"StubRoutines::_jlong_arraycopy", "_aot_stub_routines_jlong_arraycopy"}, 163 {"StubRoutines::_oop_arraycopy", "_aot_stub_routines_oop_arraycopy"}, 164 {"StubRoutines::_oop_arraycopy_uninit", "_aot_stub_routines_oop_arraycopy_uninit"}, 165 166 {"StubRoutines::_jbyte_disjoint_arraycopy", "_aot_stub_routines_jbyte_disjoint_arraycopy"}, 167 {"StubRoutines::_jshort_disjoint_arraycopy", "_aot_stub_routines_jshort_disjoint_arraycopy"}, 168 {"StubRoutines::_jint_disjoint_arraycopy", "_aot_stub_routines_jint_disjoint_arraycopy"}, 169 {"StubRoutines::_jlong_disjoint_arraycopy", "_aot_stub_routines_jlong_disjoint_arraycopy"}, 170 {"StubRoutines::_oop_disjoint_arraycopy", "_aot_stub_routines_oop_disjoint_arraycopy"}, 171 {"StubRoutines::_oop_disjoint_arraycopy_uninit", "_aot_stub_routines_oop_disjoint_arraycopy_uninit"}, 172 173 {"StubRoutines::_arrayof_jbyte_arraycopy", "_aot_stub_routines_arrayof_jbyte_arraycopy"}, 174 {"StubRoutines::_arrayof_jshort_arraycopy", "_aot_stub_routines_arrayof_jshort_arraycopy"}, 175 {"StubRoutines::_arrayof_jint_arraycopy", "_aot_stub_routines_arrayof_jint_arraycopy"}, 176 {"StubRoutines::_arrayof_jlong_arraycopy", "_aot_stub_routines_arrayof_jlong_arraycopy"}, 177 {"StubRoutines::_arrayof_oop_arraycopy", "_aot_stub_routines_arrayof_oop_arraycopy"}, 178 {"StubRoutines::_arrayof_oop_arraycopy_uninit", "_aot_stub_routines_arrayof_oop_arraycopy_uninit"}, 179 180 {"StubRoutines::_arrayof_jbyte_disjoint_arraycopy", "_aot_stub_routines_arrayof_jbyte_disjoint_arraycopy"}, 181 {"StubRoutines::_arrayof_jshort_disjoint_arraycopy", "_aot_stub_routines_arrayof_jshort_disjoint_arraycopy"}, 182 {"StubRoutines::_arrayof_jint_disjoint_arraycopy", "_aot_stub_routines_arrayof_jint_disjoint_arraycopy"}, 183 {"StubRoutines::_arrayof_jlong_disjoint_arraycopy", "_aot_stub_routines_arrayof_jlong_disjoint_arraycopy"}, 184 {"StubRoutines::_arrayof_oop_disjoint_arraycopy", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy"}, 185 {"StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit"}, 186 187 {"StubRoutines::_checkcast_arraycopy", "_aot_stub_routines_checkcast_arraycopy"}, 188 189 190 191 192 {"StubRoutines::_aescrypt_encryptBlock", "_aot_stub_routines_aescrypt_encryptBlock"}, 193 {"StubRoutines::_aescrypt_decryptBlock", "_aot_stub_routines_aescrypt_decryptBlock"}, 194 {"StubRoutines::_cipherBlockChaining_encryptAESCrypt", "_aot_stub_routines_cipherBlockChaining_encryptAESCrypt"}, 195 {"StubRoutines::_cipherBlockChaining_decryptAESCrypt", "_aot_stub_routines_cipherBlockChaining_decryptAESCrypt"}, 196 {"StubRoutines::_updateBytesCRC32", "_aot_stub_routines_update_bytes_crc32"}, 197 {"StubRoutines::_crc_table_adr", "_aot_stub_routines_crc_table_adr"}, 198 199 {"StubRoutines::_sha1_implCompress", "_aot_stub_routines_sha1_implCompress" }, 200 {"StubRoutines::_sha1_implCompressMB", "_aot_stub_routines_sha1_implCompressMB" }, 201 {"StubRoutines::_sha256_implCompress", "_aot_stub_routines_sha256_implCompress" }, 202 {"StubRoutines::_sha256_implCompressMB", "_aot_stub_routines_sha256_implCompressMB" }, 203 {"StubRoutines::_sha512_implCompress", "_aot_stub_routines_sha512_implCompress" }, 204 {"StubRoutines::_sha512_implCompressMB", "_aot_stub_routines_sha512_implCompressMB" }, 205 {"StubRoutines::_multiplyToLen", "_aot_stub_routines_multiplyToLen" }, 206 207 {"StubRoutines::_counterMode_AESCrypt", "_aot_stub_routines_counterMode_AESCrypt" }, 208 {"StubRoutines::_ghash_processBlocks", "_aot_stub_routines_ghash_processBlocks" }, 209 {"StubRoutines::_crc32c_table_addr", "_aot_stub_routines_crc32c_table_addr" }, 210 {"StubRoutines::_updateBytesCRC32C", "_aot_stub_routines_updateBytesCRC32C" }, 211 {"StubRoutines::_updateBytesAdler32", "_aot_stub_routines_updateBytesAdler32" }, 212 {"StubRoutines::_squareToLen", "_aot_stub_routines_squareToLen" }, 213 {"StubRoutines::_mulAdd", "_aot_stub_routines_mulAdd" }, 214 {"StubRoutines::_montgomeryMultiply", "_aot_stub_routines_montgomeryMultiply" }, 215 {"StubRoutines::_montgomerySquare", "_aot_stub_routines_montgomerySquare" }, 216 {"StubRoutines::_vectorizedMismatch", "_aot_stub_routines_vectorizedMismatch" }, 217 218 {"StubRoutines::_throw_delayed_StackOverflowError_entry", "_aot_stub_routines_throw_delayed_StackOverflowError_entry" }, 219 220 221 {"os::javaTimeMillis", "_aot_os_javaTimeMillis"}, 222 {"os::javaTimeNanos", "_aot_os_javaTimeNanos"}, 223 224 {"JVMCIRuntime::monitorenter", "_aot_jvmci_runtime_monitorenter"}, 225 {"JVMCIRuntime::monitorexit", "_aot_jvmci_runtime_monitorexit"}, 226 {"JVMCIRuntime::log_object", "_aot_jvmci_runtime_log_object"}, 227 {"JVMCIRuntime::log_printf", "_aot_jvmci_runtime_log_printf"}, 228 {"JVMCIRuntime::vm_message", "_aot_jvmci_runtime_vm_message"}, 229 {"JVMCIRuntime::new_instance", "_aot_jvmci_runtime_new_instance"}, 230 {"JVMCIRuntime::log_primitive", "_aot_jvmci_runtime_log_primitive"}, 231 {"JVMCIRuntime::new_multi_array", "_aot_jvmci_runtime_new_multi_array"}, 232 {"JVMCIRuntime::validate_object", "_aot_jvmci_runtime_validate_object"}, 233 {"JVMCIRuntime::dynamic_new_array", "_aot_jvmci_runtime_dynamic_new_array"}, 234 {"JVMCIRuntime::write_barrier_pre", "_aot_jvmci_runtime_write_barrier_pre"}, 235 {"JVMCIRuntime::identity_hash_code", "_aot_jvmci_runtime_identity_hash_code"}, 236 {"JVMCIRuntime::write_barrier_post", "_aot_jvmci_runtime_write_barrier_post"}, 237 {"JVMCIRuntime::dynamic_new_instance", "_aot_jvmci_runtime_dynamic_new_instance"}, 238 {"JVMCIRuntime::thread_is_interrupted", "_aot_jvmci_runtime_thread_is_interrupted"}, 239 {"JVMCIRuntime::exception_handler_for_pc", "_aot_jvmci_runtime_exception_handler_for_pc"}, 240 {"JVMCIRuntime::test_deoptimize_call_int", "_aot_jvmci_runtime_test_deoptimize_call_int"}, 241 242 {"JVMCIRuntime::throw_and_post_jvmti_exception", "_aot_jvmci_runtime_throw_and_post_jvmti_exception"}, 243 {"JVMCIRuntime::throw_klass_external_name_exception", "_aot_jvmci_runtime_throw_klass_external_name_exception"}, 244 {"JVMCIRuntime::throw_class_cast_exception", "_aot_jvmci_runtime_throw_class_cast_exception"}, 245 246 {"JVMCIRuntime::vm_error", "_aot_jvmci_runtime_vm_error"}, 247 {"JVMCIRuntime::new_array", "_aot_jvmci_runtime_new_array"} 248 //@formatter:on 249 }; 250 251 static { 252 for (String[] entry : map) { 253 functionNamesToAOTSymbols.put(entry[0], entry[1]); 254 } 255 } 256 257 /** 258 * Allocates a {@code BinaryContainer} object whose content will be generated in a file with the 259 * prefix {@code prefix}. It also initializes internal code container, symbol table and 260 * relocation tables. 261 */ 262 public BinaryContainer(GraalHotSpotVMConfig config, String jvmVersion) { 263 this.codeSegmentSize = config.codeSegmentSize; 264 this.codeEntryAlignment = config.codeEntryAlignment; 265 266 // read only, code 267 codeContainer = new CodeContainer(".text", this); 268 extLinkageContainer = new CodeContainer(".hs.plt.linkage", this); 269 270 // read only, info 271 configContainer = new ReadOnlyDataContainer(".config", this); 272 metaspaceNamesContainer = new ReadOnlyDataContainer(".meta.names", this); 273 methodsOffsetsContainer = new ReadOnlyDataContainer(".methods.offsets", this); 274 klassesOffsetsContainer = new ReadOnlyDataContainer(".kls.offsets", this); 275 klassesDependenciesContainer = new ReadOnlyDataContainer(".kls.dependencies", this); 276 277 headerContainer = new HeaderContainer(jvmVersion, new ReadOnlyDataContainer(".header", this)); 278 stubsOffsetsContainer = new ReadOnlyDataContainer(".stubs.offsets", this); 279 codeSegmentsContainer = new ReadOnlyDataContainer(".code.segments", this); 280 constantDataContainer = new ReadOnlyDataContainer(".meth.constdata", this); 281 282 // needs relocation patching at load time by the loader 283 methodMetadataContainer = new ReadOnlyDataContainer(".meth.metadata", this); 284 285 // writable sections 286 metaspaceGotContainer = new ByteContainer(".meta.got", this); 287 metadataGotContainer = new ByteContainer(".metadata.got", this); 288 methodStateContainer = new ByteContainer(".meth.state", this); 289 oopGotContainer = new ByteContainer(".oop.got", this); 290 extLinkageGOTContainer = new ByteContainer(".hs.got.linkage", this); 291 292 addGlobalSymbols(); 293 294 recordConfiguration(config); 295 } 296 297 private void recordConfiguration(GraalHotSpotVMConfig config) { 298 // @formatter:off 299 boolean[] booleanFlags = { config.cAssertions, // Debug VM 300 config.useCompressedOops, 301 config.useCompressedClassPointers, 302 config.compactFields, 303 config.useG1GC, 304 config.useCMSGC, 305 config.useTLAB, 306 config.useBiasedLocking, 307 TieredAOT.getValue(), 308 config.enableContended, 309 config.restrictContended, 310 }; 311 312 int[] intFlags = { config.narrowOopShift, 313 config.narrowKlassShift, 314 config.contendedPaddingWidth, 315 config.fieldsAllocationStyle, 316 config.objectAlignment, 317 config.codeSegmentSize, 318 }; 319 // @formatter:on 320 321 byte[] booleanFlagsAsBytes = flagsToByteArray(booleanFlags); 322 int size0 = configContainer.getByteStreamSize(); 323 324 // @formatter:off 325 int computedSize = booleanFlagsAsBytes.length * Byte.BYTES + // size of boolean flags 326 intFlags.length * Integer.BYTES + // size of int flags 327 Integer.BYTES; // size of the "computedSize" 328 329 configContainer.appendInt(computedSize). 330 appendInts(intFlags). 331 appendBytes(booleanFlagsAsBytes); 332 // @formatter:on 333 334 int size = configContainer.getByteStreamSize() - size0; 335 assert size == computedSize; 336 } 337 338 private static byte[] flagsToByteArray(boolean[] flags) { 339 byte[] byteArray = new byte[flags.length]; 340 for (int i = 0; i < flags.length; ++i) { 341 byteArray[i] = boolToByte(flags[i]); 342 } 343 return byteArray; 344 } 345 346 private static byte boolToByte(boolean flag) { 347 return (byte) (flag ? 1 : 0); 348 } 349 350 /** 351 * Free some memory. 352 */ 353 public void freeMemory() { 354 offsetStringTable.clear(); 355 metaspaceNames.clear(); 356 } 357 358 /* 359 * Global symbol names in generated DSO corresponding to VM's symbols. VM needs to look up this 360 * symbol in DSO and link it with VM's corresponding symbol: store VM's symbol address or value 361 * in the named GOT cell. 362 */ 363 364 public String getCardTableAddressSymbolName() { 365 return "_aot_card_table_address"; 366 } 367 368 public String getHeapTopAddressSymbolName() { 369 return "_aot_heap_top_address"; 370 } 371 372 public String getHeapEndAddressSymbolName() { 373 return "_aot_heap_end_address"; 374 } 375 376 public String getCrcTableAddressSymbolName() { 377 return "_aot_stub_routines_crc_table_adr"; 378 } 379 380 public String getPollingPageSymbolName() { 381 return "_aot_polling_page"; 382 } 383 384 public String getResolveStaticEntrySymbolName() { 385 return "_resolve_static_entry"; 386 } 387 388 public String getResolveVirtualEntrySymbolName() { 389 return "_resolve_virtual_entry"; 390 } 391 392 public String getResolveOptVirtualEntrySymbolName() { 393 return "_resolve_opt_virtual_entry"; 394 } 395 396 public String getNarrowKlassBaseAddressSymbolName() { 397 return "_aot_narrow_klass_base_address"; 398 } 399 400 public String getLogOfHeapRegionGrainBytesSymbolName() { 401 return "_aot_log_of_heap_region_grain_bytes"; 402 } 403 404 public String getInlineContiguousAllocationSupportedSymbolName() { 405 return "_aot_inline_contiguous_allocation_supported"; 406 } 407 408 public int getCodeSegmentSize() { 409 return codeSegmentSize; 410 } 411 412 public int getCodeEntryAlignment() { 413 return codeEntryAlignment; 414 } 415 416 /** 417 * Gets the global AOT symbol associated with the function name. 418 * 419 * @param functionName function name 420 * @return AOT symbol for the given function name, or null if there is no mapping. 421 */ 422 public String getAOTSymbolForVMFunctionName(String functionName) { 423 return functionNamesToAOTSymbols.get(functionName); 424 } 425 426 private void addGlobalSymbols() { 427 // Create global symbols for all containers. 428 createContainerSymbol(codeContainer); 429 createContainerSymbol(configContainer); 430 createContainerSymbol(methodsOffsetsContainer); 431 createContainerSymbol(klassesOffsetsContainer); 432 createContainerSymbol(klassesDependenciesContainer); 433 createContainerSymbol(metaspaceGotContainer); 434 createContainerSymbol(metadataGotContainer); 435 createContainerSymbol(methodStateContainer); 436 createContainerSymbol(oopGotContainer); 437 createContainerSymbol(metaspaceNamesContainer); 438 createContainerSymbol(methodMetadataContainer); 439 createContainerSymbol(stubsOffsetsContainer); 440 createContainerSymbol(headerContainer.getContainer()); 441 createContainerSymbol(codeSegmentsContainer); 442 443 createGotSymbol(getResolveStaticEntrySymbolName()); 444 createGotSymbol(getResolveVirtualEntrySymbolName()); 445 createGotSymbol(getResolveOptVirtualEntrySymbolName()); 446 createGotSymbol(getCardTableAddressSymbolName()); 447 createGotSymbol(getHeapTopAddressSymbolName()); 448 createGotSymbol(getHeapEndAddressSymbolName()); 449 createGotSymbol(getNarrowKlassBaseAddressSymbolName()); 450 createGotSymbol(getPollingPageSymbolName()); 451 createGotSymbol(getLogOfHeapRegionGrainBytesSymbolName()); 452 createGotSymbol(getInlineContiguousAllocationSupportedSymbolName()); 453 454 for (HashMap.Entry<String, String> entry : functionNamesToAOTSymbols.entrySet()) { 455 createGotSymbol(entry.getValue()); 456 } 457 } 458 459 /** 460 * Creates a global symbol of the form {@code "JVM" + container name}. 461 * 462 * @param container container to create a symbol for 463 */ 464 private static void createContainerSymbol(ByteContainer container) { 465 container.createSymbol(0, Kind.OBJECT, Binding.GLOBAL, 0, "JVM" + container.getContainerName()); 466 } 467 468 /** 469 * Creates a global GOT symbol of the form {@code "got." + name}. 470 * 471 * @param name name for the GOT symbol 472 */ 473 private void createGotSymbol(String name) { 474 String s = "got." + name; 475 Symbol gotSymbol = extLinkageGOTContainer.createGotSymbol(s); 476 extLinkageGOTContainer.createSymbol(gotSymbol.getOffset(), Kind.OBJECT, Binding.GLOBAL, 8, name); 477 } 478 479 /** 480 * Create a platform-specific binary file representing the content of the 481 * {@code BinaryContainer} object. 482 * 483 * This method is called after creating and performing any necessary changes to the contents of 484 * code stream, symbol tables and relocation tables is completely finalized 485 * 486 * @param outputFileName name of output file 487 * 488 * @throws IOException in case of file creation failure 489 */ 490 public void createBinary(String outputFileName, String aotVersion) throws IOException { 491 String osName = System.getProperty("os.name"); 492 switch (osName) { 493 case "Linux": 494 case "SunOS": 495 JELFRelocObject elfobj = new JELFRelocObject(this, outputFileName, aotVersion); 496 elfobj.createELFRelocObject(relocationTable, symbolTable.values()); 497 break; 498 case "Mac OS X": 499 JMachORelocObject machobj = new JMachORelocObject(this, outputFileName); 500 machobj.createMachORelocObject(relocationTable, symbolTable.values()); 501 break; 502 default: 503 if (osName.startsWith("Windows")) { 504 JPECoffRelocObject pecoffobj = new JPECoffRelocObject(this, outputFileName, aotVersion); 505 pecoffobj.createPECoffRelocObject(relocationTable, symbolTable.values()); 506 break; 507 } 508 else 509 throw new InternalError("Unsupported platform: " + osName); 510 } 511 } 512 513 /** 514 * Add symbol to the symbol table. If the existing symbol is undefined and the specified symbol 515 * is not undefined, replace the existing symbol information with that specified. 516 * 517 * @param symInfo symbol information to be added 518 */ 519 public void addSymbol(Symbol symInfo) { 520 if (symInfo.getName().startsWith("got.") && !(symInfo instanceof GotSymbol)) { 521 throw new InternalError("adding got. without being GotSymbol"); 522 } 523 if (symbolTable.containsKey(symInfo.getName())) { 524 throw new InternalError("Symbol: " + symInfo.getName() + " already exists in SymbolTable"); 525 } else { 526 // System.out.println("# Symbol [" + name + "] [" + symInfo.getValue() + "] [" + 527 // symInfo.getSection().getContainerName() + "] [" + symInfo.getSize() + "]"); 528 symbolTable.put(symInfo.getName(), symInfo); 529 } 530 } 531 532 public boolean addStringOffset(String name, Integer offset) { 533 offsetStringTable.put(name, offset); 534 return true; 535 } 536 537 /** 538 * Add relocation entry for {@code symName}. Multiple relocation entries for a given symbol may 539 * exist. 540 * 541 * @param info relocation information to be added 542 */ 543 public void addRelocation(Relocation info) { 544 // System.out.println("# Relocation [" + symName + "] [" + info.getOffset() + "] [" + 545 // info.getSection().getContainerName() + "] [" + info.getSymbol().getName() + "] [" + 546 // info.getSymbol().getOffset() + " @ " + info.getSymbol().getSection().getContainerName() + 547 // "]"); 548 if (relocationTable.containsKey(info.getSymbol())) { 549 relocationTable.get(info.getSymbol()).add(info); 550 } else if (uniqueRelocationTable.containsKey(info.getSymbol())) { 551 // promote 552 ArrayList<Relocation> list = new ArrayList<>(2); 553 list.add(uniqueRelocationTable.get(info.getSymbol())); 554 list.add(info); 555 relocationTable.put(info.getSymbol(), list); 556 uniqueRelocationTable.remove(info.getSymbol()); 557 } else { 558 uniqueRelocationTable.put(info.getSymbol(), info); 559 } 560 } 561 562 /** 563 * Get symbol with name {@code symName}. 564 * 565 * @param symName name of symbol for which symbol table information is being queried 566 * @return success or failure of insertion operation 567 */ 568 @Override 569 public Symbol getSymbol(String symName) { 570 return symbolTable.get(symName); 571 } 572 573 @Override 574 public Symbol createSymbol(int offset, Kind kind, Binding binding, int size, String name) { 575 if (kind != Kind.NATIVE_FUNCTION) { 576 throw new UnsupportedOperationException("Must be external functions: " + name); 577 } 578 Symbol symbol = new Symbol(offset, kind, binding, null, size, name); 579 addSymbol(symbol); 580 return symbol; 581 } 582 583 /** 584 * Get offset in got section with name {@code symName}. 585 * 586 * @param name for which String table information is being queried 587 * @return success or failure of insertion operation 588 */ 589 public Integer getStringOffset(String name) { 590 return offsetStringTable.get(name); 591 } 592 593 /** 594 * Insert {@code targetCode} to code stream with {@code size} at {@code offset}. 595 * 596 * @param targetCode byte array of native code 597 * @param offset offset at which {@code targetCode} is to be inserted 598 * @param size size of {@code targetCode} 599 */ 600 private static void appendBytes(ByteContainer byteContainer, byte[] targetCode, int offset, int size) { 601 byteContainer.appendBytes(targetCode, offset, size); 602 } 603 604 public void appendCodeBytes(byte[] targetCode, int offset, int size) { 605 appendBytes(codeContainer, targetCode, offset, size); 606 } 607 608 public void appendIntToCode(int value) { 609 codeContainer.appendInt(value); 610 } 611 612 public int appendExtLinkageGotBytes(byte[] bytes, int offset, int size) { 613 int startOffset = extLinkageGOTContainer.getByteStreamSize(); 614 appendBytes(extLinkageGOTContainer, bytes, offset, size); 615 return startOffset; 616 } 617 618 public int appendMetaspaceGotBytes(byte[] bytes, int offset, int size) { 619 int startOffset = metaspaceGotContainer.getByteStreamSize(); 620 appendBytes(metaspaceGotContainer, bytes, offset, size); 621 return startOffset; 622 } 623 624 public void addMetadataGotEntry(int offset) { 625 metadataGotContainer.appendLong(offset); 626 } 627 628 public int addMetaspaceName(String name) { 629 Integer value = metaspaceNames.get(name); 630 if (value != null) { 631 return value.intValue(); 632 } 633 // Get the current length of the stubsNameContainer 634 // align on 8-byte boundary 635 int nameOffset = alignUp(metaspaceNamesContainer, 8); 636 637 try { 638 // Add the name of the symbol to the .stubs.names section 639 // Modify them to sequence of utf8 strings with length: 640 // "<u2_size>Ljava/lang/ThreadGroup;<u2_size>addUnstarted<u2_size>()V" 641 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 642 DataOutputStream out = new DataOutputStream(bout); 643 int len = name.length(); 644 if (name.startsWith("Stub")) { // Stub 645 out.writeUTF(name); 646 } else { // Method or Klass 647 int parenthesesIndex = name.lastIndexOf('(', len - 1); 648 if (parenthesesIndex > 0) { // Method name 649 int dotIndex = name.lastIndexOf('.', parenthesesIndex - 1); 650 assert dotIndex > 0 : "method's full name should have '.' : " + name; 651 String klassName = name.substring(0, dotIndex); 652 out.writeUTF(klassName); 653 String methodName = name.substring(dotIndex + 1, parenthesesIndex); 654 out.writeUTF(methodName); 655 String signature = name.substring(parenthesesIndex, len); 656 out.writeUTF(signature); 657 } else { 658 out.writeUTF(name); // Klass 659 } 660 } 661 out.writeShort(0); // Terminate by 0. 662 byte[] b = bout.toByteArray(); 663 metaspaceNamesContainer.appendBytes(b, 0, b.length); 664 665 metaspaceNames.put(name, nameOffset); 666 return nameOffset; 667 } catch (IOException e) { 668 throw new InternalError("Failed to append bytes to stubs sections", e); 669 } 670 } 671 672 /** 673 * Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to 674 * patch. 675 * 676 * @param oopName name of the oop symbol 677 */ 678 public Integer addOopSymbol(String oopName) { 679 Integer oopGotOffset = getStringOffset(oopName); 680 if (oopGotOffset != null) { 681 return oopGotOffset; 682 } 683 return newOopSymbol(oopName); 684 } 685 686 private Integer newOopSymbol(String oopName) { 687 // Reference to String resolution (ldc). 688 int offset = oopGotContainer.getByteStreamSize(); 689 String gotName = "got.ldc." + offset; 690 Symbol relocationSymbol = oopGotContainer.createGotSymbol(gotName); 691 692 if (offset != relocationSymbol.getOffset()) { 693 throw new InternalError("offset must equal! (" + offset + " vs " + relocationSymbol.getOffset()); 694 } 695 696 addStringOffset(oopName, relocationSymbol.getOffset()); 697 return relocationSymbol.getOffset(); 698 } 699 700 public int addMetaspaceSymbol(String metaspaceName) { 701 String gotName = "got." + metaspaceName; 702 Symbol relocationSymbol = getGotSymbol(gotName); 703 int metaspaceOffset = -1; 704 if (relocationSymbol == null) { 705 // Add slots when asked in the .metaspace.got section: 706 metaspaceGotContainer.createGotSymbol(gotName); 707 } 708 return metaspaceOffset; 709 } 710 711 public Symbol getGotSymbol(String name) { 712 assert name.startsWith("got."); 713 return symbolTable.get(name); 714 } 715 716 /** 717 * Add metaspace symbol by as follows. - Adding the symbol name to the metaspace.names section - 718 * Add the offset of the name in metaspace.names to metaspace.offsets - Extend the metaspace.got 719 * section with another slot for the VM to patch 720 * 721 * @param metaspaceName name of the metaspace symbol 722 * @return the got offset in the metaspace.got of the metaspace symbol 723 */ 724 public int addTwoSlotMetaspaceSymbol(String metaspaceName) { 725 String gotName = "got." + metaspaceName; 726 Symbol previous = getGotSymbol(gotName); 727 assert previous == null : "should be called only once for: " + metaspaceName; 728 // Add slots when asked in the .metaspace.got section: 729 // First slot 730 String gotInitName = "got.init." + metaspaceName; 731 GotSymbol slot1Symbol = metaspaceGotContainer.createGotSymbol(gotInitName); 732 GotSymbol slot2Symbol = metaspaceGotContainer.createGotSymbol(gotName); 733 734 slot1Symbol.getIndex(); // check alignment and ignore result 735 // Get the index (offset/8) to the got in the .metaspace.got section 736 return slot2Symbol.getIndex(); 737 } 738 739 public int addMethodsCount(int count, ReadOnlyDataContainer container) { 740 return appendInt(count, container); 741 } 742 743 private static int appendInt(int count, ReadOnlyDataContainer container) { 744 int offset = container.getByteStreamSize(); 745 container.appendInt(count); 746 return offset; 747 } 748 749 /** 750 * Add constant data as follows. - Adding the data to the meth.constdata section 751 * 752 * @param data 753 * @param alignment 754 * @return the offset in the meth.constdata of the data 755 */ 756 public int addConstantData(byte[] data, int alignment) { 757 // Get the current length of the metaspaceNameContainer 758 int constantDataOffset = alignUp(constantDataContainer, alignment); 759 constantDataContainer.appendBytes(data, 0, data.length); 760 alignUp(constantDataContainer, alignment); // Post alignment 761 return constantDataOffset; 762 } 763 764 public int alignUp(ByteContainer container, int alignment) { 765 if (Integer.bitCount(alignment) != 1) { 766 throw new IllegalArgumentException("Must be a power of 2"); 767 } 768 int offset = container.getByteStreamSize(); 769 int aligned = (offset + (alignment - 1)) & -alignment; 770 if (aligned < offset || (aligned & (alignment - 1)) != 0) { 771 throw new RuntimeException("Error aligning: " + offset + " -> " + aligned); 772 } 773 if (aligned != offset) { 774 int nullArraySz = aligned - offset; 775 byte[] nullArray = new byte[nullArraySz]; 776 container.appendBytes(nullArray, 0, nullArraySz); 777 offset = aligned; 778 } 779 return offset; 780 } 781 782 public void addCodeSegments(int start, int end) { 783 assert (start % codeSegmentSize) == 0 : "not aligned code"; 784 int currentOffset = codeSegmentsContainer.getByteStreamSize(); 785 int offset = start / codeSegmentSize; 786 int emptySize = offset - currentOffset; 787 // add empty segments if needed 788 if (emptySize > 0) { 789 byte[] emptyArray = new byte[emptySize]; 790 for (int i = 0; i < emptySize; i++) { 791 emptyArray[i] = (byte) 0xff; 792 } 793 appendBytes(codeSegmentsContainer, emptyArray, 0, emptySize); 794 } 795 int alignedEnd = (end + (codeSegmentSize - 1)) & -codeSegmentSize; 796 int segmentsCount = (alignedEnd / codeSegmentSize) - offset; 797 byte[] segments = new byte[segmentsCount]; 798 int idx = 0; 799 for (int i = 0; i < segmentsCount; i++) { 800 segments[i] = (byte) idx; 801 idx = (idx == 0xfe) ? 1 : (idx + 1); 802 } 803 appendBytes(codeSegmentsContainer, segments, 0, segmentsCount); 804 } 805 806 public CodeContainer getExtLinkageContainer() { 807 return extLinkageContainer; 808 } 809 810 public ByteContainer getExtLinkageGOTContainer() { 811 return extLinkageGOTContainer; 812 } 813 814 public ByteContainer getMethodMetadataContainer() { 815 return methodMetadataContainer; 816 } 817 818 public ReadOnlyDataContainer getMetaspaceNamesContainer() { 819 return metaspaceNamesContainer; 820 } 821 822 public ReadOnlyDataContainer getMethodsOffsetsContainer() { 823 return methodsOffsetsContainer; 824 } 825 826 public ReadOnlyDataContainer getKlassesOffsetsContainer() { 827 return klassesOffsetsContainer; 828 } 829 830 public ReadOnlyDataContainer getKlassesDependenciesContainer() { 831 return klassesDependenciesContainer; 832 } 833 834 public ReadOnlyDataContainer getStubsOffsetsContainer() { 835 return stubsOffsetsContainer; 836 } 837 838 public ReadOnlyDataContainer getCodeSegmentsContainer() { 839 return codeSegmentsContainer; 840 } 841 842 public ReadOnlyDataContainer getConstantDataContainer() { 843 return constantDataContainer; 844 } 845 846 public ByteContainer getMetaspaceGotContainer() { 847 return metaspaceGotContainer; 848 } 849 850 public ByteContainer getMetadataGotContainer() { 851 return metadataGotContainer; 852 } 853 854 public ByteContainer getMethodStateContainer() { 855 return methodStateContainer; 856 } 857 858 public ByteContainer getOopGotContainer() { 859 return oopGotContainer; 860 } 861 862 public CodeContainer getCodeContainer() { 863 return codeContainer; 864 } 865 866 public ReadOnlyDataContainer getConfigContainer() { 867 return configContainer; 868 } 869 870 public Map<Symbol, Relocation> getUniqueRelocationTable() { 871 return uniqueRelocationTable; 872 } 873 874 public HeaderContainer getHeaderContainer() { 875 return headerContainer; 876 } 877 878 }