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