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