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